johnpatrickmorgan / FlowStacks

FlowStacks allows you to hoist SwiftUI navigation and presentation state into a Coordinator
MIT License
778 stars 55 forks source link

[iOS 14] View pops back if Router is inside of other #49

Open rigamikhail27 opened 1 year ago

rigamikhail27 commented 1 year ago

Hi everybody and thanks a lot @johnpatrickmorgan for this job! I was looking chance to organise my app code with MVVMc + SwiftUI and draw a conclusion, that FlowStacks is a best solution!

Here is a code example with weird behaviour when put one Router inside other leads to popping instead of pushing and only on iOS <= 14.5. (routes.push(.second) -> pops back to .root(.main) in CoordinatingViewB)

import SwiftUI
import FlowStacks

enum ScreensA {

    case main, bFlow

}

struct CoordinatingViewA: View {

    @State private var routes: Routes<ScreensA> = [.root(.main)]

    var body: some View {
        NavigationView {
            Router($routes) { screen, _ in
                switch screen {
                case .main:
                    Button {
                        routes.push(.bFlow)
                    } label: {
                        Text("push bFlow")
                    }
                    .navigationTitle("Main A")
                case .bFlow:
                    CoordinatingViewB()
                }
            }
            .navigationBarTitleDisplayMode(.inline)
        }
        .navigationViewStyle(.stack)
    }

}

enum ScreensB {

    case main, first, second

}

struct CoordinatingViewB: View {

    @State private var routes: Routes<ScreensB> = [.root(.main)]

    var body: some View {
        Router($routes) { screen, _ in
            switch screen {
            case .main:
                Button {
                    routes.push(.first)
                } label: {
                    Text("push First B")
                }
                .navigationTitle("Main B")
            case .first:
                Button {
                    routes.push(.second)
                } label: {
                    Text("push second B")
                }
                .navigationTitle("First B")
            case .second:
                Text("Finish")
                    .navigationTitle("Second B")
            }
        }
    }
}

struct TestFlowStack_Previews: PreviewProvider {
    static var previews: some View {
        CoordinatingViewA()
    }
}

Of course, I may use it incorrectly, that's why need your experience and waiting for it)

Thanks!

oleh-petrenko commented 1 year ago

Hey! Got the same issue. It'd be nice to fix that. Thanks in advance!

johnpatrickmorgan commented 1 year ago

Thanks @rigamikhail27 for raising this issue and for the clear reproduction. I see the same issue on iOS 14, and you are using the library as intended, so this is definitely something to be fixed. I've done a little investigation but so far I haven't developed any insight, but will keep you posted.

rigamikhail27 commented 1 year ago

@johnpatrickmorgan any idea?)

johnpatrickmorgan commented 1 year ago

Hi @rigamikhail27, sorry I haven't had any breakthrough. I checked older FlowStacks versions and the issue has been present since the inception of the library. I'm afraid it might be the case that FlowStacks' approach to nesting coordinators is not compatible with SwiftUI on iOS 14, at least for push navigation (presentation seems to work as expected).

I'm considering a significant rewrite of the library to bring the API more in line with the new navigation APIs in iOS 16 (point 2 here). I believe that would allow a more robust approach to nesting coordinators. Sorry I can't offer a better solution.

rigamikhail27 commented 1 year ago

Got it, thanks! Current implementation is useful, so I will better up min support version to 15🙂

johnpatrickmorgan commented 1 year ago

Follow-up: here's an early peek at the possible rewrite: #51