Skip to content

Commit fb64f75

Browse files
committed
refactor: TodoDetailViewModel을 TodoDetailFeature로 대체
1 parent 0b0ab8b commit fb64f75

11 files changed

Lines changed: 160 additions & 252 deletions

File tree

Application/DevLogPresentation/Sources/Home/Detail/TodoDetailView.swift

Lines changed: 89 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -6,76 +6,64 @@
66
//
77

88
import SwiftUI
9+
import ComposableArchitecture
910
import DevLogCore
1011
import DevLogDomain
1112

1213
struct TodoDetailView: View {
1314
@Environment(\.diContainer) private var container: DIContainer
1415
@Environment(\.openWindow) private var openWindow
1516
@Environment(\.isiOSAppOnMac) private var isiOSAppOnMac
16-
@State var viewModel: TodoDetailViewModel
17+
@State private var store: StoreOf<TodoDetailFeature>
18+
19+
init(store: StoreOf<TodoDetailFeature>) {
20+
self._store = State(initialValue: store)
21+
}
22+
23+
init(
24+
fetchTodoUseCase: FetchTodoByIdUseCase,
25+
fetchReferenceItemsUseCase: FetchReferenceItemsUseCase,
26+
todoId: String,
27+
showEditButton: Bool = true
28+
) {
29+
self.init(store: Store(
30+
initialState: TodoDetailFeature.State(
31+
todoId: todoId,
32+
showEditButton: showEditButton
33+
)
34+
) {
35+
TodoDetailFeature()
36+
} withDependencies: {
37+
$0.fetchTodoByIdUseCase = fetchTodoUseCase
38+
$0.fetchReferenceItemsUseCase = fetchReferenceItemsUseCase
39+
})
40+
}
1741

1842
var body: some View {
1943
ZStack {
2044
Color(.systemGroupedBackground).ignoresSafeArea()
21-
if let todo = viewModel.state.todo {
45+
if let todo = store.todo {
2246
TodoDetailContentView(
2347
title: todo.title,
2448
content: todo.content,
25-
referenceItems: viewModel.state.referenceItems,
49+
referenceItems: store.referenceItems,
2650
number: todo.number,
27-
onOpenTodoID: { viewModel.send(.setSelectedTodoId(TodoIdItem(id: $0))) }
51+
onOpenTodoID: { store.send(.setSheet(.todo(TodoIdItem(id: $0)))) }
2852
)
29-
} else if viewModel.state.isLoading {
53+
} else if store.isLoading {
3054
LoadingView()
3155
}
3256
}
33-
.onAppear { viewModel.send(.onAppear) }
57+
.onAppear { store.send(.onAppear) }
3458
.navigationBarTitleDisplayMode(.inline)
35-
.sheet(isPresented: Binding(
36-
get: { viewModel.state.showInfo },
37-
set: { viewModel.send(.setShowInfo($0)) }
38-
)) {
39-
sheetContent
40-
}
41-
.sheet(item: Binding(
42-
get: { viewModel.state.selectedTodoId },
43-
set: { viewModel.send(.setSelectedTodoId($0)) }
44-
)) { item in
45-
NavigationStack {
46-
TodoDetailView(viewModel: TodoDetailViewModel(
47-
fetchTodoUseCase: container.resolve(FetchTodoByIdUseCase.self),
48-
fetchReferenceItemsUseCase: container.resolve(FetchReferenceItemsUseCase.self),
49-
todoId: item.id,
50-
showEditButton: false
51-
))
52-
.toolbar {
53-
ToolbarLeadingButton {
54-
viewModel.send(.setSelectedTodoId(nil))
55-
}
56-
}
57-
}
58-
.background(Color(.systemGroupedBackground))
59-
.presentationDragIndicator(.visible)
59+
.alert($store.scope(state: \.alert, action: \.alert))
60+
.sheet(item: $store.scope(state: \.sheet, action: \.sheet)) { sheetStore in
61+
sheetContent(sheetStore)
6062
}
61-
.fullScreenCover(isPresented: Binding(
62-
get: { viewModel.state.showEditor },
63-
set: { viewModel.send(.setShowEditor($0)) }
64-
)) {
65-
if let todo = viewModel.state.todo {
66-
TodoEditorView(
67-
viewModel: TodoEditorViewModel(
68-
todo: todo,
69-
fetchPreferencesUseCase: container.resolve(FetchTodoCategoryPreferencesUseCase.self),
70-
fetchReferenceItemsUseCase: container.resolve(FetchReferenceItemsUseCase.self),
71-
upsertTodoUseCase: container.resolve(UpsertTodoUseCase.self),
72-
onUpdateSuccess: { todo in
73-
viewModel.send(.setShowEditor(false))
74-
viewModel.send(.setTodo(todo))
75-
}
76-
)
77-
)
78-
}
63+
.fullScreenCover(
64+
item: $store.scope(state: \.fullScreenCover, action: \.fullScreenCover)
65+
) { coverStore in
66+
fullScreenCoverContent(coverStore)
7967
}
8068
.toolbar { toolbarContent }
8169
}
@@ -84,12 +72,12 @@ struct TodoDetailView: View {
8472
private var toolbarContent: some ToolbarContent {
8573
ToolbarItem(placement: .topBarTrailing) {
8674
Button {
87-
viewModel.send(.setShowInfo(true))
75+
store.send(.setSheet(.info))
8876
} label: {
8977
Image(systemName: "info.circle")
9078
}
9179
}
92-
if viewModel.showEditButton {
80+
if store.showEditButton {
9381
if #available(iOS 26.0, *) {
9482
ToolbarSpacer(.fixed, placement: .topBarTrailing)
9583
}
@@ -105,22 +93,66 @@ struct TodoDetailView: View {
10593

10694
private func openTodoEditor() {
10795
if isiOSAppOnMac {
108-
guard let todo = viewModel.state.todo else { return }
96+
guard let todo = store.todo else { return }
10997
openWindow(
11098
id: TodoEditorWindowValue.sceneId,
11199
value: TodoEditorWindowValue(todo: todo)
112100
)
113101
} else {
114-
viewModel.send(.setShowEditor(true))
102+
store.send(.setFullScreenCover(.editor))
103+
}
104+
}
105+
106+
@ViewBuilder
107+
private func fullScreenCoverContent(
108+
_ coverStore: Store<TodoDetailFeature.FullScreenCoverState, Never>
109+
) -> some View {
110+
switch coverStore.destination {
111+
case .editor:
112+
if let todo = store.todo {
113+
TodoEditorView(
114+
viewModel: TodoEditorViewModel(
115+
todo: todo,
116+
fetchPreferencesUseCase: container.resolve(FetchTodoCategoryPreferencesUseCase.self),
117+
fetchReferenceItemsUseCase: container.resolve(FetchReferenceItemsUseCase.self),
118+
upsertTodoUseCase: container.resolve(UpsertTodoUseCase.self),
119+
onUpdateSuccess: { todo in
120+
store.send(.setFullScreenCover(nil))
121+
store.send(.setTodo(todo))
122+
}
123+
)
124+
)
125+
}
115126
}
116127
}
117128

118129
@ViewBuilder
119-
private var sheetContent: some View {
120-
if let todo = viewModel.state.todo {
121-
TodoDetailInfoSheetView(todo: todo) {
122-
viewModel.send(.setShowInfo(false))
130+
private func sheetContent(
131+
_ sheetStore: Store<TodoDetailFeature.SheetState, TodoDetailFeature.Action.Sheet>
132+
) -> some View {
133+
switch sheetStore.destination {
134+
case .info:
135+
if let todo = store.todo {
136+
TodoDetailInfoSheetView(todo: todo) {
137+
sheetStore.send(.tapCloseButton)
138+
}
123139
}
140+
case .todo(let item):
141+
NavigationStack {
142+
TodoDetailView(
143+
fetchTodoUseCase: container.resolve(FetchTodoByIdUseCase.self),
144+
fetchReferenceItemsUseCase: container.resolve(FetchReferenceItemsUseCase.self),
145+
todoId: item.id,
146+
showEditButton: false
147+
)
148+
.toolbar {
149+
ToolbarLeadingButton {
150+
sheetStore.send(.tapCloseButton)
151+
}
152+
}
153+
}
154+
.background(Color(.systemGroupedBackground))
155+
.presentationDragIndicator(.visible)
124156
}
125157
}
126158
}

Application/DevLogPresentation/Sources/Home/Detail/TodoDetailViewModel.swift

Lines changed: 0 additions & 143 deletions
This file was deleted.

Application/DevLogPresentation/Sources/Home/Editor/TodoEditorView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ struct TodoEditorView: View {
6161
set: { viewModel.send(.setSelectedTodoId($0)) }
6262
)) { item in
6363
NavigationStack {
64-
TodoDetailView(viewModel: TodoDetailViewModel(
64+
TodoDetailView(
6565
fetchTodoUseCase: container.resolve(FetchTodoByIdUseCase.self),
6666
fetchReferenceItemsUseCase: container.resolve(FetchReferenceItemsUseCase.self),
6767
todoId: item.id,
6868
showEditButton: false
69-
))
69+
)
7070
.toolbar {
7171
ToolbarLeadingButton {
7272
viewModel.send(.setSelectedTodoId(nil))

Application/DevLogPresentation/Sources/Main/MainView.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ struct MainView: View {
232232
)
233233
.id(item.id)
234234
case .todo(let item):
235-
TodoDetailView(viewModel: todoWindowCoordinator.makeDetailViewModel(todoId: item.id))
235+
TodoDetailView(store: todoWindowCoordinator.makeDetailStore(todoId: item.id))
236236
.id(item.id)
237237
case .webPage(let item):
238238
WebView(url: item.url)
@@ -295,7 +295,7 @@ struct MainView: View {
295295
private func todayDestinationView(_ todayRoute: TodayRoute) -> some View {
296296
switch todayRoute {
297297
case .todo(let item):
298-
TodoDetailView(viewModel: todoWindowCoordinator.makeDetailViewModel(todoId: item.id))
298+
TodoDetailView(store: todoWindowCoordinator.makeDetailStore(todoId: item.id))
299299
.id(item.id)
300300
}
301301
}
@@ -311,7 +311,7 @@ struct MainView: View {
311311
private var notificationRegularDetailView: some View {
312312
if let todoId = pushNotificationListViewCoordinator.todoIdToPresent?.id {
313313
TodoDetailView(
314-
viewModel: pushNotificationListViewCoordinator.makeTodoDetailViewModel(
314+
store: pushNotificationListViewCoordinator.makeTodoDetailStore(
315315
todoId: todoId
316316
)
317317
)
@@ -358,7 +358,7 @@ struct MainView: View {
358358
private func profileRegularDestinationView(_ route: ProfileRoute) -> some View {
359359
switch route {
360360
case .activity(let todoId):
361-
TodoDetailView(viewModel: profileViewCoordinator.makeTodoDetailViewModel(todoId: todoId))
361+
TodoDetailView(store: profileViewCoordinator.makeTodoDetailStore(todoId: todoId))
362362
.id(todoId)
363363
case .settings:
364364
SettingsView(viewModel: profileViewCoordinator.settingsViewModel)

0 commit comments

Comments
 (0)