Bahn-X / swift-composable-navigator

An open source library for building deep-linkable SwiftUI applications with composition, testing and ergonomics in mind
MIT License
581 stars 25 forks source link

Can you go to screen without specifying the previous screen? #66

Open andrewjmeier opened 3 years ago

andrewjmeier commented 3 years ago

Idea

[//]: It feels useful to be able to go to a screen without specifying the previous screen.

Problem description

[//]: One example of this would be a sheet that you want to be able to show from anywhere in the app and if you deep link to that sheet you'd want to just pop it up from whatever previous screen was open.

Apple Music has this behavior with its now playing bar that can pop up a sheet of the current song from anywhere in the app.

Considered solutions

[//]: I've currently hacked around this like this:

guard let screen = dataSource.path.current.last else { return }
navigator.go(to: EpisodeScreen(episode: episode), on: screen.id)
ohitsdaniel commented 3 years ago

Hey @andrewjmeier,

One example of this would be a sheet that you want to be able to show from anywhere in the app

at this point in time, this is not possible. One of the principles applied while building ComposableNavigator was that, at all times, you know 'where you are' which enables you to 'go where you want'. Instead of accessing the last id in the path, you could pass the current screen id into the function that performs the navigation.

struct MyFancyView: View {
   @Environment(\.currentScreenID) var currentScreenID
   @Environment(\.navigator) var navigator

   var body: some View {
      Button("Go to EpisodeScreen") {
          navigator.go(to: EpisodeScreen(episode: episode, on: currentScreenID)

          /// OR

          viewModel.selectedEpisode(episode, on: currentScreenID)
      }
   }
}

and if you deep link to that sheet you'd want to just pop it up from whatever previous screen was open.

This is a good point. Having access to the current path while parsing deeplinks might be useful. We could provide the current path to deeplink parsers OR allow deeplink parsers to define if they want to append to or replace the current path.

I'll think about it. 🤔

andrewjmeier commented 3 years ago

Ah I should have given more context on my first example. This feels a bit like it's a deep link as well since it's outside of ComposableNavigator's Root. I have to set it up this way because I don't want the view to be inside the NavigationView that gets rendered. Because of this I don't have access to the current screen environment variable.

VStack {
    Root(...)
    MyView().onTapGesture {
        guard let screen = dataSource.path.current.last else { return }
        navigator.go(to: EpisodeScreen(episode: episode), on: screen.id)
    }
}
ohitsdaniel commented 3 years ago

So you're basically adding an overlay in which you want to trigger a sheet from any screen?

I think we can solve this by changing the managed navigation state from a linear

--- screen --- screen --- screen

to a tree like

                     ---- screen
--- screen --- branch
                     ---- screen (overlay)

path.

We will have to do this for tabbed / split path builders anyway, so I guess we can address this issue as part of those efforts.