diff --git a/MacApp/Relay/AppFeature.swift b/MacApp/Relay/AppFeature.swift index b1596cb..e6954a1 100644 --- a/MacApp/Relay/AppFeature.swift +++ b/MacApp/Relay/AppFeature.swift @@ -13,12 +13,24 @@ struct AppFeature { @ObservableState struct State: Equatable { enum Route: Equatable { - case welcome + case welcome(WelcomeFeature.State) case main(MainFeature.State) } var route: Route + /// Вспомогательный доступ для Scope/ifLet — ненулевой если маршрут .welcome. + var routeWelcome: WelcomeFeature.State? { + get { + guard case let .welcome(s) = route else { return nil } + return s + } + set { + guard let newValue else { return } + route = .welcome(newValue) + } + } + /// Вспомогательный доступ для Scope/ifLet — ненулевой если маршрут .main. var routeMain: MainFeature.State? { get { @@ -31,7 +43,7 @@ struct AppFeature { } } - init(route: Route = .main(MainFeature.State())) { + init(route: Route = .welcome(WelcomeFeature.State())) { self.route = route } } @@ -40,6 +52,7 @@ struct AppFeature { @CasePathable enum Action { + case welcome(WelcomeFeature.Action) case main(MainFeature.Action) case showWelcome case showMain @@ -53,7 +66,7 @@ struct AppFeature { Reduce { state, action in switch action { case .showWelcome: - state.route = .welcome + state.route = .welcome(WelcomeFeature.State()) return .none case .showMain: @@ -65,10 +78,19 @@ struct AppFeature { state.route = .main(MainFeature.State()) return .send(.main(._openProject(url))) + case let .welcome(.delegate(.projectSelected(url))): + return .send(.openProject(url)) + + case .welcome: + return .none + case .main: return .none } } + .ifLet(\.routeWelcome, action: \.welcome) { + WelcomeFeature() + } .ifLet(\.routeMain, action: \.main) { MainFeature() } diff --git a/MacApp/Relay/AppRootView.swift b/MacApp/Relay/AppRootView.swift index b3ec54d..e87d4de 100644 --- a/MacApp/Relay/AppRootView.swift +++ b/MacApp/Relay/AppRootView.swift @@ -16,7 +16,9 @@ struct AppRootView: View { var body: some View { switch store.route { case .welcome: - WelcomeView(store: store) + if let welcomeStore = store.scope(state: \.routeWelcome, action: \.welcome) { + WelcomeView(store: welcomeStore) + } case .main: MainView(store: store.scope(state: \.routeMain!, action: \.main)) diff --git a/MacApp/Relay/Welcome/WelcomeView.swift b/MacApp/Relay/Welcome/WelcomeView.swift index 2edcf63..2b5f1e5 100644 --- a/MacApp/Relay/Welcome/WelcomeView.swift +++ b/MacApp/Relay/Welcome/WelcomeView.swift @@ -1,6 +1,5 @@ import AppKit import ComposableArchitecture -import SwiftData import SwiftUI // MARK: - WelcomeView @@ -9,16 +8,7 @@ import SwiftUI /// Показывается при запуске если нет открытого проекта. struct WelcomeView: View { - let store: StoreOf - - @Query( - filter: #Predicate { _ in true }, - sort: \ProjectModel.lastOpenedAt, - order: .reverse - ) - private var allProjects: [ProjectModel] - - @Environment(\.modelContext) private var modelContext + @Bindable var store: StoreOf var body: some View { HSplitView { @@ -30,6 +20,9 @@ struct WelcomeView: View { } .frame(minWidth: 700, minHeight: 460) .background(Color(nsColor: .windowBackgroundColor)) + .onAppear { + store.send(.onAppear) + } } // MARK: - Left panel @@ -87,7 +80,7 @@ struct WelcomeView: View { Divider() - if allProjects.isEmpty { + if store.recentProjects.isEmpty { emptyState } else { projectsList @@ -120,17 +113,17 @@ struct WelcomeView: View { // MARK: - Projects list private var projectsList: some View { - ScrollView { - LazyVStack(spacing: 0) { - // Favorites pinned at top - let favorites = allProjects.filter(\.isFavorite) - let recents = allProjects.filter { !$0.isFavorite } + let projects = store.filteredProjects + let favorites = projects.filter(\.isFavorite) + let recents = projects.filter { !$0.isFavorite } + return ScrollView { + LazyVStack(spacing: 0) { if !favorites.isEmpty { sectionHeader("Favorites") - ForEach(favorites, id: \.path) { project in + ForEach(favorites) { project in RecentProjectRow(project: project) { - openRecentProject(project) + openRecent(project) } onToggleFavorite: { toggleFavorite(project) } onDelete: { @@ -144,9 +137,9 @@ struct WelcomeView: View { if !favorites.isEmpty { sectionHeader("Recent") } - ForEach(recents.prefix(20), id: \.path) { project in + ForEach(recents.prefix(20)) { project in RecentProjectRow(project: project) { - openRecentProject(project) + openRecent(project) } onToggleFavorite: { toggleFavorite(project) } onDelete: { @@ -183,28 +176,19 @@ struct WelcomeView: View { panel.prompt = "Open" guard panel.runModal() == .OK, let url = panel.url else { return } - - let repo = ProjectRepository(modelContext: modelContext) - repo.addProject(path: url) - - store.send(.openProject(url)) + store.send(.folderSelected(url)) } - private func openRecentProject(_ project: ProjectModel) { - let url = URL(filePath: project.path) - let repo = ProjectRepository(modelContext: modelContext) - repo.touchProject(path: url) - store.send(.openProject(url)) + private func openRecent(_ project: ProjectInfo) { + store.send(.openRecent(URL(filePath: project.path))) } - private func toggleFavorite(_ project: ProjectModel) { - let repo = ProjectRepository(modelContext: modelContext) - repo.toggleFavorite(path: URL(filePath: project.path)) + private func toggleFavorite(_ project: ProjectInfo) { + store.send(.toggleFavorite(URL(filePath: project.path))) } - private func deleteProject(_ project: ProjectModel) { - let repo = ProjectRepository(modelContext: modelContext) - repo.deleteProject(path: URL(filePath: project.path)) + private func deleteProject(_ project: ProjectInfo) { + store.send(.removeRecent(URL(filePath: project.path))) } } @@ -212,7 +196,7 @@ struct WelcomeView: View { private struct RecentProjectRow: View { - let project: ProjectModel + let project: ProjectInfo let onOpen: () -> Void let onToggleFavorite: () -> Void let onDelete: () -> Void