diff --git a/Modules/AppFeature/Sources/AppFeature.swift b/Modules/AppFeature/Sources/AppFeature.swift index 1a3b0eb91..0e93013fe 100644 --- a/Modules/AppFeature/Sources/AppFeature.swift +++ b/Modules/AppFeature/Sources/AppFeature.swift @@ -91,6 +91,9 @@ public enum AppFeature { return .none case .setSettingsPresented(let isPresented): + guard isPresented != state.isSettingsPresented else { + return .none + } state.isSettingsPresented = isPresented if isPresented && state.settings == nil { state.settings = .init() diff --git a/Modules/AppFeature/Sources/AppView.swift b/Modules/AppFeature/Sources/AppView.swift index 65d837ecb..cd5cf0ce5 100644 --- a/Modules/AppFeature/Sources/AppView.swift +++ b/Modules/AppFeature/Sources/AppView.swift @@ -15,6 +15,8 @@ public struct AppView: View { public typealias ViewStore = Store @StateObject private var store: ViewStore + @State private var path: [AppFeature.State.Destination] = [] + @State private var isSettingsPresented: Bool = false @Environment(\.theme) private var theme @@ -25,7 +27,7 @@ public struct AppView: View { } public var body: some View { - NavigationStack(path: store.binding(\.path, send: { .setPath($0) })) { + NavigationStack(path: $path) { HomeView { store.projection(state: \.home, action: { .home($0) }) } @@ -33,15 +35,38 @@ public struct AppView: View { viewForDestination($0) } } - .sheet(isPresented: store.binding(\.isSettingsPresented, send: { .setSettingsPresented($0) })) { + .sheet(isPresented: $isSettingsPresented) { SettingsView { store.projection(state: \.settings, action: { .settings($0) }) } } + .accentColor(theme.colorAccent) + // Fix Error `Update NavigationAuthority bound path tried to update multiple times per frame` + .onReceive(store.$state) { newValue in + if newValue.path != path { + path = newValue.path + } + if newValue.isSettingsPresented != isSettingsPresented { + isSettingsPresented = newValue.isSettingsPresented + } + } + .onChange(of: path) { _, newValue in + if newValue != store.state.path { + Task { + await store.dispatch(.setPath(newValue)) + } + } + } + .onChange(of: isSettingsPresented) { _, newValue in + if newValue != store.state.isSettingsPresented { + Task { + await store.dispatch(.setSettingsPresented(newValue)) + } + } + } .onReceive(store.dispatchedAction) { event in print(event) } - .accentColor(theme.colorAccent) } @ViewBuilder private func viewForDestination(_ destination: AppFeature.State.Destination) -> some View { diff --git a/Modules/SettingsFeature/Sources/SettingsView.swift b/Modules/SettingsFeature/Sources/SettingsView.swift index 358e24b57..5eddef387 100644 --- a/Modules/SettingsFeature/Sources/SettingsView.swift +++ b/Modules/SettingsFeature/Sources/SettingsView.swift @@ -11,6 +11,7 @@ public struct SettingsView: View { public typealias ViewStore = Store @StateObject private var store: ViewStore + @State private var path: [SettingsFeature.State.Destination] = [] public init(store: @escaping () -> ViewStore) { // SwiftUI ensures that the following initialization uses the @@ -19,7 +20,7 @@ public struct SettingsView: View { } public var body: some View { - NavigationStack(path: store.binding(\.path, send: { .setPath($0) })) { + NavigationStack(path: $path) { SettingsHomeView { store.projection(state: \.home, action: { .home($0) }) } @@ -31,6 +32,19 @@ public struct SettingsView: View { } } .presentationDetents([.large]) + // Fix Error `Update NavigationAuthority bound path tried to update multiple times per frame` + .onReceive(store.$state) { newValue in + if newValue.path != path { + path = newValue.path + } + } + .onChange(of: path) { _, newValue in + if newValue != store.state.path { + Task { + await store.dispatch(.setPath(newValue)) + } + } + } } @ViewBuilder private func viewForDestination(_ destination: SettingsFeature.State.Destination) -> some View {