From ccf1004110d3c5ec0f5889d0edfab571e577b147 Mon Sep 17 00:00:00 2001 From: ErrorErrorError <16653389+ErrorErrorError@users.noreply.github.com> Date: Wed, 27 Dec 2023 01:01:11 -0600 Subject: [PATCH] fix: search now works due to navstack not properly deeply linking --- .../Features/Search/SearchFeature+View.swift | 2 +- Sources/Shared/Styling/NavStack.swift | 103 ++++++++++++------ 2 files changed, 69 insertions(+), 36 deletions(-) diff --git a/Sources/Features/Search/SearchFeature+View.swift b/Sources/Features/Search/SearchFeature+View.swift index 93bb049..be42526 100644 --- a/Sources/Features/Search/SearchFeature+View.swift +++ b/Sources/Features/Search/SearchFeature+View.swift @@ -209,7 +209,7 @@ extension SearchFeature.View { Image(systemName: "chevron.up.chevron.down") .font(.footnote.weight(.semibold)) } - .foregroundColor(selectedOptions.isEmpty ? nil : .white) + .foregroundColor(selectedOptions.isEmpty ? theme.textColor : .white) .lineLimit(1) .font(.footnote) .padding(.horizontal, 12) diff --git a/Sources/Shared/Styling/NavStack.swift b/Sources/Shared/Styling/NavStack.swift index d60b421..517f477 100644 --- a/Sources/Shared/Styling/NavStack.swift +++ b/Sources/Shared/Styling/NavStack.swift @@ -9,14 +9,11 @@ @_spi(Presentation) import ComposableArchitecture import Foundation +import FoundationHelpers import OrderedCollections import SwiftUI import ViewComponents -extension Animation { - public static var navStackTransion: Animation { .timingCurve(0.31, 0.47, 0.31, 1, duration: 0.4) } -} - // MARK: - NavStack public struct NavStack: View { @@ -50,42 +47,30 @@ public struct NavStack: } else { #if os(iOS) NavigationView { - ZStack { - root() - .themeable() - - Group { + root() + .themeable() + .background { WithViewStore(store, observe: \.ids, removeDuplicates: areOrderedSetsDuplicates) { viewStore in - ForEach(viewStore.state, id: \.self) { id in - NavigationLink( - isActive: .init( - get: { viewStore.state.contains(id) }, - set: { isActive, transaction in - if !isActive, viewStore.state.contains(id) { - viewStore.send(.popFrom(id: id), transaction: transaction) - } - } + // Simulate "drilling down" for iOS 15 + DrilledView(set: viewStore.state, index: viewStore.startIndex) { id, transaction in + if viewStore.state.contains(id) { + viewStore.send(.popFrom(id: id), transaction: transaction) + } + } destination: { id in + IfLetStore( + store.scope( + state: returningLastNonNilValue { $0[id: id] }, + action: { .element(id: id, action: $0 as Action) } ) - ) { - IfLetStore( - store.scope( - state: returningLastNonNilValue { $0[id: id] }, - action: { .element(id: id, action: $0 as Action) } - ) - ) { store in - destination(store) - .themeable() - } - } label: { - EmptyView() + ) { store in + destination(store) + .themeable() } - .isDetailLink(false) - .hidden() } + .hidden() } + .hidden() } - .hidden() - } } .navigationViewStyle(.stack) #elseif os(macOS) @@ -119,6 +104,54 @@ public struct NavStack: } } +@MainActor +private struct DrilledView: View { + typealias Elements = OrderedSet + let set: Elements + let index: Elements.Index + let popped: (Elements.Element, Transaction) -> Void + let destination: (Elements.Element) -> Destination + + var id: Elements.Element? { + if set.startIndex <= index && index < set.endIndex { + set[index] + } else { + nil + } + } + + @MainActor + var body: some View { + NavigationLink( + isActive: .init( + get: { id.flatMap(set.contains) ?? false }, + set: { isActive, transaction in + if let id, !isActive { + popped(id, transaction) + } + } + ) + ) { + if let id { + destination(id) + .background( + Self( + set: set, + index: set.index(after: index), + popped: popped, + destination: destination + ) + .hidden() + ) + } + } label: { + EmptyView() + } + .isDetailLink(false) + .hidden() + } +} + extension NavStack { public init( _ store: Store, StackAction>, @@ -158,7 +191,7 @@ extension View { @ViewBuilder destination: @escaping (_ store: Store) -> some View ) -> some View { presentation(store: store) { `self`, $item, destinationContent in - if #available(iOS 16.0, macOS 13.0, *) { + if #available(iOS 18.0, macOS 13.0, *) { self.navigationDestination(isPresented: $item.isPresent()) { destinationContent(destination) .themeable()