FlowStacks icon indicating copy to clipboard operation
FlowStacks copied to clipboard

SwiftUI's native dismiss environment value does not work from fullscreen modal with navigation

Open CorbinMontague opened this issue 1 year ago • 4 comments

There is a bug where attempting to use SwiftUI's native dismiss environment value does not work from a fullscreen modal presented with navigation: foo.presentCover(Screen.modalView, withNavigation: true). This bug is present in both the 0.8.1 and 0.8.2 versions (I haven't checked any other versions). Workaround is to use FlowPathNavigator or a reference to the FlowPath associated with the FlowStack because FlowStacks dismiss APIs still work as expected. See code example below:

import Foundation
import FlowStacks
import SwiftUI

public enum Screen {
    case modalView
}
extension Screen: Identifiable, Hashable {
    public var id: String {
        return String(reflecting: self)
    }
    
    public func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
    
    public static func == (lhs: Screen, rhs: Screen) -> Bool {
        lhs.id == rhs.id
    }
}

struct ScreenViewBuilder {
    static func view(for screen: Screen) -> some View {
        switch screen {
        case .modalView:
            return ModalView()
        }
    }
}

struct ContentView: View {
    
    @State var path = FlowPath()
    var body: some View {
        FlowStack($path, withNavigation: true) {
            makeRootView()
                .flowDestination(for: Screen.self) { screen in
                    ScreenViewBuilder.view(for: screen)
                }
        }
    }
    
    @ViewBuilder private func makeRootView() -> some View {
        Button("Present ModalView with navigation") {
            path.presentCover(Screen.modalView, withNavigation: true)
        }
    }
}

struct ModalView: View {
    @Environment(\.dismiss) private var dismiss
    @EnvironmentObject var navigator: FlowPathNavigator
    
    var body: some View {
        Text("Modal View")
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    Button("Native Dismiss") {
                        dismiss() // does not work
                    }
                }
                
                ToolbarItem(placement: .topBarTrailing) {
                    Button("FlowStacks Dismiss") {
                        navigator.dismiss() // works
                        // navigator.goBack() // works
                    }
                }
            }
    }
}

CorbinMontague avatar Oct 07 '24 14:10 CorbinMontague

Thanks for raising this issue @CorbinMontague ! To update you, I can reproduce the bug, but I'm not yet sure why it's happening.

johnpatrickmorgan avatar Oct 10 '24 15:10 johnpatrickmorgan

@johnpatrickmorgan It looks like the issue is tied to the content being wrapped in a NavigationView vs a NavigationStack, because if I change UseNavigationStackPolicyKey's defaultValue to be UseNavigationStackPolicy.whenAvailable instead of UseNavigationStackPolicy.never, I notice that EmbedModifier wraps the content inside a NavigationStack instead of a NavigationView, and this issue does not reproduce. So for some reason Apple's native DismissAction seems to work with NavigationStack, but not NavigationView in this case.

In View+UseNavigationStack.swift I see a comment about how func useNavigationStack() is not ready to be exposed publicly yet due to issues. Could you elaborate on what those issues are since I'm wanting to use UseNavigationStackPolicy.whenAvailable to fix this DismissAction issue?

CorbinMontague avatar Oct 23 '24 15:10 CorbinMontague

hmm I'm seeing some kind of hang when using UseNavigationStackPolicy.whenAvailable and attempting to push additional views from within my modal so I assume I'm starting to hit some of those "issues" referred to in the comment I mentioned given I did not have that issue with UseNavigationStackPolicy.never.

CorbinMontague avatar Oct 23 '24 15:10 CorbinMontague

hmm I'm seeing some kind of hang when using UseNavigationStackPolicy.whenAvailable and attempting to push additional views from within my modal so I assume I'm starting to hit some of those "issues" referred to in the comment I mentioned given I did not have that issue with UseNavigationStackPolicy.never.

Hi @CorbinMontague , yes that is indeed the issue that was holding me back from making that API public. Navigation seems to trigger an infinite loop currently.

johnpatrickmorgan avatar Oct 24 '24 22:10 johnpatrickmorgan