-
-
Notifications
You must be signed in to change notification settings - Fork 142
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
Add ability to using miscellaneous Navigator #326
base: main
Are you sure you want to change the base?
Conversation
3b3ca42
to
43020f5
Compare
43020f5
to
2fb4f15
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still don't know why this API is required, there is couple examples on the project creating Custom Navigator with Navigator it self as base, for example BottomSheetNavigator.
Also the transitions problem is not a problem, I have tested here and I was able to reproduce all your transitions with targetState
and initialState
. (#302 (comment))
val isPush = navigator.lastAction.isPush() | ||
val isPop = navigator.lastAction.isPop() | ||
// Define any Screen you want transition must be from | ||
val isInvokerTransitionScreen = navigator.lastAction?.invoker == TransitionScreen | ||
val isInvokerFadeScreen = navigator.lastAction?.invoker == FadeScreen | ||
val isInvokerShrinkScreen = navigator.lastAction?.invoker == ShrinkScreen | ||
val isInvokerScaleScreen = navigator.lastAction?.invoker == ScaleScreen | ||
// Define any Screen you want transition must be to | ||
val isTargetTransitionScreen = navigator.lastItem == TransitionScreen | ||
val isTargetFadeScreen = navigator.lastItem == FadeScreen | ||
val isTargetShrinkScreen = navigator.lastItem == ShrinkScreen | ||
val isTargetScaleScreen = navigator.lastItem == ScaleScreen |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val isPush = navigator.lastAction.isPush() | |
val isPop = navigator.lastAction.isPop() | |
// Define any Screen you want transition must be from | |
val isInvokerTransitionScreen = navigator.lastAction?.invoker == TransitionScreen | |
val isInvokerFadeScreen = navigator.lastAction?.invoker == FadeScreen | |
val isInvokerShrinkScreen = navigator.lastAction?.invoker == ShrinkScreen | |
val isInvokerScaleScreen = navigator.lastAction?.invoker == ScaleScreen | |
// Define any Screen you want transition must be to | |
val isTargetTransitionScreen = navigator.lastItem == TransitionScreen | |
val isTargetFadeScreen = navigator.lastItem == FadeScreen | |
val isTargetShrinkScreen = navigator.lastItem == ShrinkScreen | |
val isTargetScaleScreen = navigator.lastItem == ScaleScreen | |
val invoker = this.initialState | |
val target = this.targetState | |
// Define any StackEvent you want transition to be | |
val isPush = navigator.lastEvent == StackEvent.Push | |
val isPop = navigator.lastEvent == StackEvent.Pop | |
// Define any Screen you want transition must be from | |
val isInvokerTransitionScreen = invoker == TransitionScreen | |
val isInvokerFadeScreen = invoker == FadeScreen | |
val isInvokerShrinkScreen = invoker == ShrinkScreen | |
val isInvokerScaleScreen = invoker == ScaleScreen | |
// Define any Screen you want transition must be to | |
val isTargetTransitionScreen = target == TransitionScreen | |
val isTargetFadeScreen = target == FadeScreen | |
val isTargetShrinkScreen = target == ShrinkScreen | |
val isTargetScaleScreen = target == ScaleScreen |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not know about that API. I have checked, works as expected. Thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like if you can open a PR with this transitions examples using the initialState
and targetState
API to we have on our oficial Voyager samples.
Could be also the sample base that we could use to create a new Transition API for Screens and test on it.
The API currently, for creating a custom Navigator is flexible enough, example: public val LocalMyCustomNavigator: ProvidableCompositionLocal<MyCustomNavigator?> =
staticCompositionLocalOf { null }
interface MyCustomScreenType : Screen {
val header: @Composable () -> Header
}
class MyCustomNavigator(
val voyagerNavigator: Navigator
) : Stack<MyCustomScreenType> by navigator as Stack<MyCustomScreenType> {
public val lastItem: MyCustomScreenType by derivedStateOf {
lastItemOrNull ?: error("MyCustomNavigator has no screen")
}
fun yourOwnNavigatorFunctions() {}
}
@Composable
fun MyCustomNavigator(initialScreen: MyCustomScreenType) {
Navigator(initialScreen, ....) { navigator ->
val myCustomNavigator = remember(navigator) { MyCustomNavigator(navigator) }
CompositionLocalProvider(LocalMyCustomNavigator provides myCustomNavigator) {
Scaffold(
topBar = { myCustomNavigator.lastItem.header() }
content = { CurrentScreen() }
)
}
}
} |
Indeed you can create your own Navigator. What do you think could it add more control and flexibility for users ? |
The examples that I shared before does not require to change anything on the navigator, you can accomplish what you want to do it this and also, the issues that this PR fixes, the code snippet that I have shared using TabNavigator, BottomSheetNavigator are pretty simple implementations for "Custom Navigators", they are so simple that you can replicate it pretty easy and customize as far as you want, so, adding de ability to Voyager custom navigators extension have a "custom navigator factory", I don't see much use cases for that and at the sametime, increase alot the complexity of the Core API of the Navigator, and complexity is the main point that the library is trying to move away. |
"targetState & initialState already cover the cases" - its closed. "TabNavigator, BottomSheetNavigator, MyCustomNavigator" - they are focused to add functionality on UI application level. They add some UI features for user experience. Contrary to that "custom navigator factory" - is aiming to add flexibility on business logic level inside " I don't see the uses cases that the currently API does not already have." - let's review some of them.
val appconfig = // get config
val user = // get user
appconfig.setUser(user)
val navigator = if (appconfig.isUserMustGoToFeatureX) {
AnalyticNavigatorCreator(FirebaseAnalytic)
} else {
DefaultNavigatorCreator()
}
summonNavigatorCreator = navigator
Navigator(Screen) {
// transition
} Every
val min5InMilliSeconds = 1000 * 60 * 5L
// There could be originScreen: Screen as a parameter. It will be first Screen after reset.
summonNavigatorCreator = SelfResetNavigatorCreator(min5InMilliSeconds)
Navigator(TransitionScreen) {
TransitionDemo(it)
}
private class SelfResetNavigator @InternalVoyagerApi constructor(
val resetAfter: Long,
...
) : Navigator(screens, key, stateHolder, disposeBehavior, parent, stack) {
private val timeStamp = MutableSharedFlow<Unit>(
extraBufferCapacity = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST
)
private val scope = CoroutineScope(Job() + Dispatchers.Default)
init {
observeTimeStamp()
}
private fun observeTimeStamp() {
scope.launch {
timeStamp.collectLatest {
delay(resetAfter)
if (canPop) {
popAll()
}
}
}
}
override fun push(item: Screen) {
timeStamp.tryEmit(Unit)
stack.push(item)
}
// other functions
}
A added Are there relevant use cases ? What do you think ? |
ISSUES SOLVED: #190
POSSIBLE SOLVED: #265
This is further discussion of #302
We ended with the following statements:
I added possibility to write and change custom
Navigator
with simple ONE line of a code.Navigator
now is abstract class that I leave as it is.Introduced 2 New navigators:
DefaultNavigator
. It is just wrapper aroundNavigator
ExtendedNavigator
. Resolves the issue of screen and action based transition.Marked as
@ExperimentalVoyagerApi
.Implements idea of Add new Stack that requires the caller #302 (comment)
Pros:
Screen
andStackAction
based transition simultaneously byExtendedNavigator
.Cons:
Screen
andStackAction
based transition limited to the LAST SCREEN. You can't take any screen.More examples when and where it wiill come in handy check this: Add new Stack that requires the caller #302 (comment)
Please @DevSrSouza make a glance.