-
Notifications
You must be signed in to change notification settings - Fork 66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Route.root
should probably use .push
instead of .sheet
#10
Comments
.root
should probably use .push
instead of .sheet
Route.root
should probably use .push
instead of .sheet
Hi Federico, thanks for checking out the latest release! I had intially imagined that child coordinators would initialise their routes with a For most purposes it doesn't matter what case the root is, but I set it to I think the best solution is to allow some ambiguity in the Thanks for raising this issue! |
Hi John, many thanks for the prompt response! After thinking about it a little bit more, I must say that I wouldn't mind leaving the responsibility of adding This is similar to what SwiftUI does: if we try to push in a view that is not embedded in a My suggestion would be to remove all the Thank you again! |
Thanks Federico, I agree it would be good to remove the responsibility of embedding within a The latest release combines both |
As a counter-example, the code below now crashes (because of Click to see reproducible examplestruct ContentView: View {
var body: some View {
NavigationView {
FlowCoordinator(onCompletion: {
print("end")
})
}
}
}
enum Screen {
case firstScreen
case secondScreen
case thirdScreen
}
struct FlowCoordinator: View {
@State private var routes: Routes<Screen> = [.push(.firstScreen)]
var onCompletion: () -> Void
var body: some View {
Router($routes) { screen, _ in
switch screen {
case .firstScreen:
FirstScreen(onCompletion: { routes.presentSheet(.secondScreen) })
case .secondScreen:
NavigationView {
SecondScreen(onCompletion: { routes.push(.thirdScreen) })
}
case .thirdScreen:
ThirdScreen(onCompletion: onCompletion)
}
}
}
}
struct FirstScreen: View {
var onCompletion: () -> Void
var body: some View {
Button("go to second", action: onCompletion)
}
}
struct SecondScreen: View {
var onCompletion: () -> Void
var body: some View {
Button("go to third", action: onCompletion)
}
}
struct ThirdScreen: View {
var onCompletion: () -> Void
var body: some View {
Button("complete", action: onCompletion)
}
} In case a flow would require a screen to be presented both within a sheet and within a navigation stack, at that point, I would create two "screen" cases, e.g.: enum Screen {
case ...
case secondScreen
case secondScreenWithNav
} Where Router($routes) { screen, _ in
switch screen {
...
case .secondScreen:
SecondScreen(onCompletion: { routes.push(.thirdScreen) })
case .secondScreenWithNav:
NavigationView {
SecondScreen(onCompletion: { routes.push(.thirdScreen) })
}
} Unless I miss something, I believe this would cover what you mentioned. Please let me know what you think :) |
Thanks for clarifying @zntfdr! Sadly this approach doesn't work, because the FlowStacks/Sources/FlowStacks/Combined/Node.swift Lines 84 to 88 in c000def
It would end up with a hierarchy like: NavigationView {
SecondScreen(onCompletion: { routes.push(.thirdScreen) })
}
.background(
NavigationLink(destination: next, isActive: pushBinding, label: EmptyView.init).hidden()
) rather than: NavigationView {
SecondScreen(onCompletion: { routes.push(.thirdScreen) })
.background(
NavigationLink(destination: next, isActive: pushBinding, label: EmptyView.init).hidden()
)
} Using the FlowStacks/Sources/FlowStacks/Combined/Node.swift Lines 102 to 110 in c000def
So if the assertion failure was disabled, your example would still silently fail to push the third screen. I don't think there's a nice way to avoid the library managing the |
Thank you for clarifying this for me! You're completely right: I now understand what you mean. In this case, what I would do is the following (this works with 0.1.1): See codestruct ContentView: View {
var body: some View {
NavigationView {
FlowCoordinator(onCompletion: {
print("end")
})
}
}
}
enum Screen {
case firstScreen
case sheet
}
struct FlowCoordinator: View {
@State private var routes: Routes<Screen> = [.push(.firstScreen)]
var onCompletion: () -> Void
var body: some View {
Router($routes) { screen, _ in
switch screen {
case .firstScreen:
FirstScreen(onCompletion: { routes.presentSheet(.sheet) })
case .sheet:
NavigationView {
SheetCoordinator(onCompletion: onCompletion)
}
}
}
}
}
enum SheetScreen {
case secondScreen
case thirdScreen
}
struct SheetCoordinator: View {
@State private var routes: Routes<SheetScreen> = [.push(.secondScreen)]
var onCompletion: () -> Void
var body: some View {
Router($routes) { screen, _ in
switch screen {
case .secondScreen:
SecondScreen(onCompletion: { routes.push(.thirdScreen) })
case .thirdScreen:
ThirdScreen(onCompletion: onCompletion)
}
}
}
}
struct FirstScreen: View {
var onCompletion: () -> Void
var body: some View {
Button("go to second", action: onCompletion)
}
}
struct SecondScreen: View {
var onCompletion: () -> Void
var body: some View {
Button("go to third", action: onCompletion)
}
}
struct ThirdScreen: View {
var onCompletion: () -> Void
var body: some View {
Button("complete", action: onCompletion)
}
} Since we're moving to a sheet with its own navigation, it probably makes sense to have another coordinator anyway. Now that I've experimented a little more with the framework, I don't mind having to use Perhaps a disclaimer in the Apologies for the trouble and thank you again! |
Awesome, that approach works well! I'm glad to know the library can still be used in that way. I think the changes in #11 are still correct, so I think I'll merge that and then |
Thank you! 🙌🏻 |
I haven't explored/experimented thoroughly the new 0.1.x release, but I believe I've found an issue.
Click to see reproducible example
The example above will crash as soon as we try to push to the second screen.
Looking at the FlowStacks codebase, I believe the following definition should use/return
push
instead ofsheet
:FlowStacks/Sources/FlowStacks/Combined/Route.swift
Lines 21 to 25 in 6d04318
Otherwise the
canPush
will returnfalse
in the example above, and trigger an assertion.FlowStacks/Sources/FlowStacks/Combined/Array+RouteProtocol.swift
Lines 7 to 18 in 6d04318
Workarounds for the example above:
@State private var routes: Routes<Screen> = [.push(.firstScreen)]
(where I replaced.root(.firstScreen)
with.push(.firstScreen)
)..root(.firstScreen)
with.root(.firstScreen, embedInNavigationView: true)
, however that would not work for child coordinators (and would embed anotherNavigationStack
to the current one).I'm curious to know if there are reasons that I didn't think of behind using
.sheet
for the.root
definition. If there are none and this is indeed a bug, I'm happy to create a PR with the change if needed.Thank you in advance!
The text was updated successfully, but these errors were encountered: