Skip to content

Commit b04aba5

Browse files
authored
[#488] PushNotificationListViewModel 생성 및 생명주기를 개선한다 (#500)
* docs: 메인 탭 요청 트리거 플로우 추가 * docs: 배경 삭제 * docs: 사각형 크기 조정 * fix: PushNotification 데이터 fetch 시점을 탭 선택 상태 기준으로 변경 * feat: PushNotificationListViewCoordinator 구현 * refactor: MainViewCoordinator에서 PushNotificationViewModel 제거 * refactor: PushNotificationListViewCoordinator 적용
1 parent 2a483d1 commit b04aba5

7 files changed

Lines changed: 177 additions & 44 deletions

File tree

Application/DevLogPresentation/Sources/Main/MainView.swift

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ struct MainView: View {
1414
@State private var coordinator: MainViewCoordinator
1515
@State private var homeViewCoordinator: HomeViewCoordinator
1616
@State private var todayViewCoordinator: TodayViewCoordinator
17+
@State private var pushNotificationListViewCoordinator: PushNotificationListViewCoordinator
1718
@State private var profileViewCoordinator: ProfileViewCoordinator
1819
@Binding var selectedTab: MainTab?
1920

@@ -24,6 +25,9 @@ struct MainView: View {
2425
self._coordinator = State(initialValue: MainViewCoordinator(container: container))
2526
self._homeViewCoordinator = State(initialValue: HomeViewCoordinator(container: container))
2627
self._todayViewCoordinator = State(initialValue: TodayViewCoordinator(container: container))
28+
self._pushNotificationListViewCoordinator = State(
29+
initialValue: PushNotificationListViewCoordinator(container: container)
30+
)
2731
self._profileViewCoordinator = State(initialValue: ProfileViewCoordinator(container: container))
2832
self._selectedTab = selectedTab
2933
}
@@ -48,6 +52,8 @@ struct MainView: View {
4852
homeViewCoordinator.fetchData()
4953
} else if newValue == .today {
5054
todayViewCoordinator.fetchData()
55+
} else if newValue == .notification {
56+
pushNotificationListViewCoordinator.fetchData()
5157
} else if newValue == .profile {
5258
profileViewCoordinator.fetchData()
5359
}
@@ -124,17 +130,15 @@ struct MainView: View {
124130
mainSidebar
125131
} content: {
126132
PushNotificationListView(
127-
viewModel: coordinator.pushNotificationListViewModel,
128-
todoIdToPresent: todoIdToPresent,
133+
coordinator: pushNotificationListViewCoordinator,
129134
isCompactLayout: isCompactLayout
130135
)
131136
} detail: {
132137
Group {
133-
if let todoId = coordinator.todoIdToPresent?.id {
138+
if let todoId = pushNotificationListViewCoordinator.todoIdToPresent?.id {
134139
TodoDetailView(
135-
viewModel: coordinator.todoDetailViewModel(
136-
todoId: todoId,
137-
showEditButton: false
140+
viewModel: pushNotificationListViewCoordinator.makeTodoDetailViewModel(
141+
todoId: todoId
138142
)
139143
)
140144
.id(todoId)
@@ -324,8 +328,7 @@ struct MainView: View {
324328

325329
private var notificationView: some View {
326330
PushNotificationListView(
327-
viewModel: coordinator.pushNotificationListViewModel,
328-
todoIdToPresent: todoIdToPresent,
331+
coordinator: pushNotificationListViewCoordinator,
329332
isCompactLayout: isCompactLayout
330333
)
331334
}
@@ -358,13 +361,6 @@ private extension MainView {
358361
)
359362
}
360363

361-
var todoIdToPresent: Binding<TodoIdItem?> {
362-
Binding(
363-
get: { coordinator.todoIdToPresent },
364-
set: { coordinator.todoIdToPresent = $0 }
365-
)
366-
}
367-
368364
var homeNavigationPath: Binding<[HomeRoute]> {
369365
Binding(
370366
get: { homeViewCoordinator.router.path },

Application/DevLogPresentation/Sources/Main/MainViewCoordinator.swift

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ import DevLogDomain
1313
@Observable
1414
final class MainViewCoordinator {
1515
let mainViewModel: MainViewModel
16-
let pushNotificationListViewModel: PushNotificationListViewModel
17-
var todoIdToPresent: TodoIdItem?
1816
private let diContainer: DIContainer
1917
@ObservationIgnored
2018
private var todoListViewModel: TodoListViewModel?
@@ -27,14 +25,6 @@ final class MainViewCoordinator {
2725
trackAnalyticsEventUseCase: container.resolve(TrackAnalyticsEventUseCase.self),
2826
unreadPushCountUseCase: container.resolve(ObserveUnreadPushCountUseCase.self)
2927
)
30-
self.pushNotificationListViewModel = PushNotificationListViewModel(
31-
fetchUseCase: container.resolve(FetchPushNotificationsUseCase.self),
32-
deleteUseCase: container.resolve(DeletePushNotificationUseCase.self),
33-
undoDeleteUseCase: container.resolve(UndoDeletePushNotificationUseCase.self),
34-
toggleReadUseCase: container.resolve(TogglePushNotificationReadUseCase.self),
35-
fetchQueryUseCase: container.resolve(FetchPushNotificationQueryUseCase.self),
36-
updateQueryUseCase: container.resolve(UpdatePushNotificationQueryUseCase.self)
37-
)
3828
}
3929

4030
func todoListViewModel(category: TodoCategory) -> TodoListViewModel {

Application/DevLogPresentation/Sources/PushNotification/PushNotificationListView.swift

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,17 @@ import DevLogDomain
1111

1212
struct PushNotificationListView: View {
1313
@Environment(\.colorScheme) private var colorScheme
14-
@Environment(\.diContainer) private var container: DIContainer
1514
@ScaledMetric(relativeTo: .body) private var headerHeight = 41
1615
@ScaledMetric(relativeTo: .largeTitle) private var labelWidth = 34
17-
@State var viewModel: PushNotificationListViewModel
1816
@State private var headerOffset: CGFloat = 0
1917
@State private var isScrollTrackingEnabled = false
20-
@Binding var todoIdToPresent: TodoIdItem?
18+
let coordinator: PushNotificationListViewCoordinator
2119
let isCompactLayout: Bool
2220

21+
private var viewModel: PushNotificationListViewModel {
22+
coordinator.viewModel
23+
}
24+
2325
var body: some View {
2426
NavigationStack {
2527
notificationList
@@ -29,7 +31,6 @@ struct PushNotificationListView: View {
2931
headerOffset = max(0, -offset)
3032
}
3133
.safeAreaInset(edge: .top) { safeAreaHeader }
32-
.onAppear { viewModel.send(.fetchNotifications) }
3334
.refreshable { viewModel.send(.fetchNotifications) }
3435
.navigationTitle(String(localized: "nav_push_notifications"))
3536
.listStyle(.plain)
@@ -58,21 +59,15 @@ struct PushNotificationListView: View {
5859
.lineLimit(3)
5960
}
6061
.sheet(item: Binding(
61-
get: { isCompactLayout ? todoIdToPresent : nil },
62+
get: { isCompactLayout ? coordinator.todoIdToPresent : nil },
6263
set: { item in
6364
if item == nil {
6465
selectNotification(nil)
6566
}
6667
}
6768
)) { item in
6869
NavigationStack {
69-
TodoDetailView(viewModel: TodoDetailViewModel(
70-
fetchTodoUseCase: container.resolve(FetchTodoByIdUseCase.self),
71-
fetchReferenceItemsUseCase: container.resolve(FetchReferenceItemsUseCase.self),
72-
upsertUseCase: container.resolve(UpsertTodoUseCase.self),
73-
todoId: item.id,
74-
showEditButton: false
75-
))
70+
TodoDetailView(viewModel: coordinator.makeTodoDetailViewModel(todoId: item.id))
7671
.id(item.id)
7772
.toolbar {
7873
ToolbarLeadingButton {
@@ -389,6 +384,6 @@ struct PushNotificationListView: View {
389384

390385
private func selectNotification(_ notificationId: String?) {
391386
viewModel.send(.selectNotification(notificationId))
392-
todoIdToPresent = viewModel.state.selectedTodoId
387+
coordinator.todoIdToPresent = viewModel.state.selectedTodoId
393388
}
394389
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//
2+
// PushNotificationListViewCoordinator.swift
3+
// DevLogPresentation
4+
//
5+
// Created by opfic on 5/29/26.
6+
//
7+
8+
import Foundation
9+
import DevLogCore
10+
import DevLogDomain
11+
12+
@MainActor
13+
@Observable
14+
final class PushNotificationListViewCoordinator {
15+
let viewModel: PushNotificationListViewModel
16+
var todoIdToPresent: TodoIdItem?
17+
private let diContainer: DIContainer
18+
@ObservationIgnored
19+
private var todoDetailViewModel: TodoDetailViewModel?
20+
21+
init(container: DIContainer) {
22+
self.diContainer = container
23+
self.viewModel = PushNotificationListViewModel(
24+
fetchUseCase: container.resolve(FetchPushNotificationsUseCase.self),
25+
deleteUseCase: container.resolve(DeletePushNotificationUseCase.self),
26+
undoDeleteUseCase: container.resolve(UndoDeletePushNotificationUseCase.self),
27+
toggleReadUseCase: container.resolve(TogglePushNotificationReadUseCase.self),
28+
fetchQueryUseCase: container.resolve(FetchPushNotificationQueryUseCase.self),
29+
updateQueryUseCase: container.resolve(UpdatePushNotificationQueryUseCase.self)
30+
)
31+
}
32+
33+
func fetchData() {
34+
viewModel.send(.fetchNotifications)
35+
}
36+
37+
func makeTodoDetailViewModel(todoId: String) -> TodoDetailViewModel {
38+
if let todoDetailViewModel,
39+
todoDetailViewModel.todoId == todoId,
40+
!todoDetailViewModel.showEditButton {
41+
return todoDetailViewModel
42+
}
43+
44+
let todoDetailViewModel = TodoDetailViewModel(
45+
fetchTodoUseCase: diContainer.resolve(FetchTodoByIdUseCase.self),
46+
fetchReferenceItemsUseCase: diContainer.resolve(FetchReferenceItemsUseCase.self),
47+
upsertUseCase: diContainer.resolve(UpsertTodoUseCase.self),
48+
todoId: todoId,
49+
showEditButton: false
50+
)
51+
self.todoDetailViewModel = todoDetailViewModel
52+
return todoDetailViewModel
53+
}
54+
}

docs/App.png

24.9 KB
Loading

0 commit comments

Comments
 (0)