diff --git a/Application/DevLogPresentation/Sources/Main/MainView.swift b/Application/DevLogPresentation/Sources/Main/MainView.swift index 59b2442b..4ba0d939 100644 --- a/Application/DevLogPresentation/Sources/Main/MainView.swift +++ b/Application/DevLogPresentation/Sources/Main/MainView.swift @@ -14,6 +14,7 @@ struct MainView: View { @State private var coordinator: MainViewCoordinator @State private var homeViewCoordinator: HomeViewCoordinator @State private var todayViewCoordinator: TodayViewCoordinator + @State private var pushNotificationListViewCoordinator: PushNotificationListViewCoordinator @State private var profileViewCoordinator: ProfileViewCoordinator @Binding var selectedTab: MainTab? @@ -24,6 +25,9 @@ struct MainView: View { self._coordinator = State(initialValue: MainViewCoordinator(container: container)) self._homeViewCoordinator = State(initialValue: HomeViewCoordinator(container: container)) self._todayViewCoordinator = State(initialValue: TodayViewCoordinator(container: container)) + self._pushNotificationListViewCoordinator = State( + initialValue: PushNotificationListViewCoordinator(container: container) + ) self._profileViewCoordinator = State(initialValue: ProfileViewCoordinator(container: container)) self._selectedTab = selectedTab } @@ -48,6 +52,8 @@ struct MainView: View { homeViewCoordinator.fetchData() } else if newValue == .today { todayViewCoordinator.fetchData() + } else if newValue == .notification { + pushNotificationListViewCoordinator.fetchData() } else if newValue == .profile { profileViewCoordinator.fetchData() } @@ -124,17 +130,15 @@ struct MainView: View { mainSidebar } content: { PushNotificationListView( - viewModel: coordinator.pushNotificationListViewModel, - todoIdToPresent: todoIdToPresent, + coordinator: pushNotificationListViewCoordinator, isCompactLayout: isCompactLayout ) } detail: { Group { - if let todoId = coordinator.todoIdToPresent?.id { + if let todoId = pushNotificationListViewCoordinator.todoIdToPresent?.id { TodoDetailView( - viewModel: coordinator.todoDetailViewModel( - todoId: todoId, - showEditButton: false + viewModel: pushNotificationListViewCoordinator.makeTodoDetailViewModel( + todoId: todoId ) ) .id(todoId) @@ -324,8 +328,7 @@ struct MainView: View { private var notificationView: some View { PushNotificationListView( - viewModel: coordinator.pushNotificationListViewModel, - todoIdToPresent: todoIdToPresent, + coordinator: pushNotificationListViewCoordinator, isCompactLayout: isCompactLayout ) } @@ -358,13 +361,6 @@ private extension MainView { ) } - var todoIdToPresent: Binding { - Binding( - get: { coordinator.todoIdToPresent }, - set: { coordinator.todoIdToPresent = $0 } - ) - } - var homeNavigationPath: Binding<[HomeRoute]> { Binding( get: { homeViewCoordinator.router.path }, diff --git a/Application/DevLogPresentation/Sources/Main/MainViewCoordinator.swift b/Application/DevLogPresentation/Sources/Main/MainViewCoordinator.swift index 493b069e..1546d7d7 100644 --- a/Application/DevLogPresentation/Sources/Main/MainViewCoordinator.swift +++ b/Application/DevLogPresentation/Sources/Main/MainViewCoordinator.swift @@ -13,8 +13,6 @@ import DevLogDomain @Observable final class MainViewCoordinator { let mainViewModel: MainViewModel - let pushNotificationListViewModel: PushNotificationListViewModel - var todoIdToPresent: TodoIdItem? private let diContainer: DIContainer @ObservationIgnored private var todoListViewModel: TodoListViewModel? @@ -27,14 +25,6 @@ final class MainViewCoordinator { trackAnalyticsEventUseCase: container.resolve(TrackAnalyticsEventUseCase.self), unreadPushCountUseCase: container.resolve(ObserveUnreadPushCountUseCase.self) ) - self.pushNotificationListViewModel = PushNotificationListViewModel( - fetchUseCase: container.resolve(FetchPushNotificationsUseCase.self), - deleteUseCase: container.resolve(DeletePushNotificationUseCase.self), - undoDeleteUseCase: container.resolve(UndoDeletePushNotificationUseCase.self), - toggleReadUseCase: container.resolve(TogglePushNotificationReadUseCase.self), - fetchQueryUseCase: container.resolve(FetchPushNotificationQueryUseCase.self), - updateQueryUseCase: container.resolve(UpdatePushNotificationQueryUseCase.self) - ) } func todoListViewModel(category: TodoCategory) -> TodoListViewModel { diff --git a/Application/DevLogPresentation/Sources/PushNotification/PushNotificationListView.swift b/Application/DevLogPresentation/Sources/PushNotification/PushNotificationListView.swift index 0c239f4c..a33d41d9 100644 --- a/Application/DevLogPresentation/Sources/PushNotification/PushNotificationListView.swift +++ b/Application/DevLogPresentation/Sources/PushNotification/PushNotificationListView.swift @@ -11,15 +11,17 @@ import DevLogDomain struct PushNotificationListView: View { @Environment(\.colorScheme) private var colorScheme - @Environment(\.diContainer) private var container: DIContainer @ScaledMetric(relativeTo: .body) private var headerHeight = 41 @ScaledMetric(relativeTo: .largeTitle) private var labelWidth = 34 - @State var viewModel: PushNotificationListViewModel @State private var headerOffset: CGFloat = 0 @State private var isScrollTrackingEnabled = false - @Binding var todoIdToPresent: TodoIdItem? + let coordinator: PushNotificationListViewCoordinator let isCompactLayout: Bool + private var viewModel: PushNotificationListViewModel { + coordinator.viewModel + } + var body: some View { NavigationStack { notificationList @@ -29,7 +31,6 @@ struct PushNotificationListView: View { headerOffset = max(0, -offset) } .safeAreaInset(edge: .top) { safeAreaHeader } - .onAppear { viewModel.send(.fetchNotifications) } .refreshable { viewModel.send(.fetchNotifications) } .navigationTitle(String(localized: "nav_push_notifications")) .listStyle(.plain) @@ -58,7 +59,7 @@ struct PushNotificationListView: View { .lineLimit(3) } .sheet(item: Binding( - get: { isCompactLayout ? todoIdToPresent : nil }, + get: { isCompactLayout ? coordinator.todoIdToPresent : nil }, set: { item in if item == nil { selectNotification(nil) @@ -66,13 +67,7 @@ struct PushNotificationListView: View { } )) { item in NavigationStack { - TodoDetailView(viewModel: TodoDetailViewModel( - fetchTodoUseCase: container.resolve(FetchTodoByIdUseCase.self), - fetchReferenceItemsUseCase: container.resolve(FetchReferenceItemsUseCase.self), - upsertUseCase: container.resolve(UpsertTodoUseCase.self), - todoId: item.id, - showEditButton: false - )) + TodoDetailView(viewModel: coordinator.makeTodoDetailViewModel(todoId: item.id)) .id(item.id) .toolbar { ToolbarLeadingButton { @@ -389,6 +384,6 @@ struct PushNotificationListView: View { private func selectNotification(_ notificationId: String?) { viewModel.send(.selectNotification(notificationId)) - todoIdToPresent = viewModel.state.selectedTodoId + coordinator.todoIdToPresent = viewModel.state.selectedTodoId } } diff --git a/Application/DevLogPresentation/Sources/PushNotification/PushNotificationListViewCoordinator.swift b/Application/DevLogPresentation/Sources/PushNotification/PushNotificationListViewCoordinator.swift new file mode 100644 index 00000000..fe8f9b85 --- /dev/null +++ b/Application/DevLogPresentation/Sources/PushNotification/PushNotificationListViewCoordinator.swift @@ -0,0 +1,54 @@ +// +// PushNotificationListViewCoordinator.swift +// DevLogPresentation +// +// Created by opfic on 5/29/26. +// + +import Foundation +import DevLogCore +import DevLogDomain + +@MainActor +@Observable +final class PushNotificationListViewCoordinator { + let viewModel: PushNotificationListViewModel + var todoIdToPresent: TodoIdItem? + private let diContainer: DIContainer + @ObservationIgnored + private var todoDetailViewModel: TodoDetailViewModel? + + init(container: DIContainer) { + self.diContainer = container + self.viewModel = PushNotificationListViewModel( + fetchUseCase: container.resolve(FetchPushNotificationsUseCase.self), + deleteUseCase: container.resolve(DeletePushNotificationUseCase.self), + undoDeleteUseCase: container.resolve(UndoDeletePushNotificationUseCase.self), + toggleReadUseCase: container.resolve(TogglePushNotificationReadUseCase.self), + fetchQueryUseCase: container.resolve(FetchPushNotificationQueryUseCase.self), + updateQueryUseCase: container.resolve(UpdatePushNotificationQueryUseCase.self) + ) + } + + func fetchData() { + viewModel.send(.fetchNotifications) + } + + func makeTodoDetailViewModel(todoId: String) -> TodoDetailViewModel { + if let todoDetailViewModel, + todoDetailViewModel.todoId == todoId, + !todoDetailViewModel.showEditButton { + return todoDetailViewModel + } + + let todoDetailViewModel = TodoDetailViewModel( + fetchTodoUseCase: diContainer.resolve(FetchTodoByIdUseCase.self), + fetchReferenceItemsUseCase: diContainer.resolve(FetchReferenceItemsUseCase.self), + upsertUseCase: diContainer.resolve(UpsertTodoUseCase.self), + todoId: todoId, + showEditButton: false + ) + self.todoDetailViewModel = todoDetailViewModel + return todoDetailViewModel + } +} diff --git a/docs/App.png b/docs/App.png index 028191c5..1980a0a2 100644 Binary files a/docs/App.png and b/docs/App.png differ diff --git a/docs/DevLog.drawio b/docs/DevLog.drawio index 2bed4e6e..ee88c1db 100644 --- a/docs/DevLog.drawio +++ b/docs/DevLog.drawio @@ -1,4 +1,4 @@ - + @@ -103,7 +103,7 @@ - + @@ -292,7 +292,7 @@ - + @@ -382,6 +382,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -468,7 +566,7 @@ - + @@ -648,7 +746,7 @@ - + @@ -695,7 +793,7 @@ - + diff --git a/docs/Widget.png b/docs/Widget.png index a79a3c4a..6f60328d 100644 Binary files a/docs/Widget.png and b/docs/Widget.png differ