diff --git a/README.md b/README.md
index 0b609369..5f0237c9 100644
--- a/README.md
+++ b/README.md
@@ -10,9 +10,9 @@
Voyager: Compose on Warp Speed
-A lightweight and pragmatic navigation library built for, and seamlessly integrated with, [Jetpack Compose](https://developer.android.com/jetpack/compose).
+Voyager is a lightweight and complete navigation library built for, and seamlessly integrated with, [Jetpack Compose](https://developer.android.com/jetpack/compose).
-Turn on the Warp Drive and enjoy the trek 🖖
+Create scalable Single-Activity apps powered by a [pragmatic API](https://voyager.adriel.cafe/navigation/fundamentals).
```kotlin
class HomeScreen : Screen {
@@ -35,11 +35,12 @@ class SingleActivity : ComponentActivity() {
}
```
+Turn on the Warp Drive and enjoy the trek 🖖
+
### Documentation
See the [project website](https://voyager.adriel.cafe) for documentation and APIs.
### Features
-- Create scalable Single-Activity apps powered by a [pragmatic API](https://voyager.adriel.cafe/navigation/fundamentals)
- [BottomSheet navigation](https://voyager.adriel.cafe/navigation/bottomsheet-navigation)
- [Tab navigation](https://voyager.adriel.cafe/navigation/tab-navigation) like [Youtube app](https://play.google.com/store/apps/details?id=com.google.android.youtube)
- [Nested navigation](https://voyager.adriel.cafe/navigation/nested-navigation) if you need to manage multiple stacks
@@ -47,7 +48,6 @@ See the [project website](https://voyager.adriel.cafe) for documentation and API
- Type-safe [multi-module navigation](https://voyager.adriel.cafe/navigation/multi-module-navigation)
- State-aware [Stack API](https://voyager.adriel.cafe/stack-api)
- Built-in [transitions](https://voyager.adriel.cafe/transitions)
-- Pluggable [hooks](https://voyager.adriel.cafe/hooks)
- [Lifecycle](https://voyager.adriel.cafe/lifecycle) callbacks
- [Back press](https://voyager.adriel.cafe/back-press) handling
- [Deep linking](https://voyager.adriel.cafe/deep-links) support
@@ -60,6 +60,6 @@ See the [project website](https://voyager.adriel.cafe) for documentation and API
|------------|----------|-------------|
|  |  |  |
-| [Tab nav.](https://github.com/adrielcafe/voyager/tree/main/sample/src/main/java/cafe/adriel/voyager/sample/tabNavigation) | [Multi-module nav.](https://github.com/adrielcafe/voyager/tree/main/sample-multi-module) | [Nested nav.](https://github.com/adrielcafe/voyager/tree/main/sample/src/main/java/cafe/adriel/voyager/sample/nestedNavigation) |
-|------------|----------|-------------|
-|  |  |  |
+| [BottomSheet nav.](https://github.com/adrielcafe/voyager/tree/main/sample/src/main/java/cafe/adriel/voyager/sample/bottomSheetNavigation) | [Tab nav.](https://github.com/adrielcafe/voyager/tree/main/sample/src/main/java/cafe/adriel/voyager/sample/tabNavigation) | [Multi-module nav.](https://github.com/adrielcafe/voyager/tree/main/sample-multi-module) | [Nested nav.](https://github.com/adrielcafe/voyager/tree/main/sample/src/main/java/cafe/adriel/voyager/sample/nestedNavigation) |
+|------------|------------|----------|-------------|
+|  |  |  |  |
diff --git a/gradle.properties b/gradle.properties
index cee740c3..574f7a16 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -5,7 +5,7 @@ kotlin.code.style=official
# Maven
GROUP=cafe.adriel.voyager
-VERSION_NAME=1.0.0-beta08
+VERSION_NAME=1.0.0-beta09
POM_DESCRIPTION=A pragmatic navigation library for Jetpack Compose
POM_INCEPTION_YEAR=2021
diff --git a/sample/src/main/java/cafe/adriel/voyager/sample/App.kt b/sample/src/main/java/cafe/adriel/voyager/sample/App.kt
index a40aadbe..2c936c13 100644
--- a/sample/src/main/java/cafe/adriel/voyager/sample/App.kt
+++ b/sample/src/main/java/cafe/adriel/voyager/sample/App.kt
@@ -2,6 +2,7 @@ package cafe.adriel.voyager.sample
import android.app.Application
import cafe.adriel.voyager.sample.androidNavigation.DetailsViewModel
+import cafe.adriel.voyager.sample.androidNavigation.ListViewModel
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.core.context.startKoin
import org.koin.dsl.module
@@ -13,6 +14,9 @@ class App : Application() {
startKoin {
modules(
module {
+ viewModel {
+ ListViewModel(handle = get())
+ }
viewModel { parameters ->
DetailsViewModel(index = parameters.get())
}
diff --git a/sample/src/main/java/cafe/adriel/voyager/sample/androidNavigation/ListScreen.kt b/sample/src/main/java/cafe/adriel/voyager/sample/androidNavigation/ListScreen.kt
index 5a718c48..7487f8f3 100644
--- a/sample/src/main/java/cafe/adriel/voyager/sample/androidNavigation/ListScreen.kt
+++ b/sample/src/main/java/cafe/adriel/voyager/sample/androidNavigation/ListScreen.kt
@@ -2,6 +2,8 @@ package cafe.adriel.voyager.sample.androidNavigation
import androidx.compose.foundation.clickable
import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.ListItem
import androidx.compose.material.Text
@@ -10,6 +12,7 @@ import androidx.compose.ui.Modifier
import cafe.adriel.voyager.androidx.AndroidScreen
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
+import org.koin.androidx.compose.getStateViewModel
class ListScreen : AndroidScreen() {
@@ -17,11 +20,12 @@ class ListScreen : AndroidScreen() {
@Composable
override fun Content() {
val navigator = LocalNavigator.currentOrThrow
+ val viewModel = getStateViewModel()
LazyColumn {
- items(100) { index ->
+ itemsIndexed(viewModel.items) { index, item ->
ListItem(
- text = { Text(text = "Item $index") },
+ text = { Text(text = item) },
modifier = Modifier.clickable { navigator.push(DetailsScreen(index)) }
)
}
diff --git a/sample/src/main/java/cafe/adriel/voyager/sample/androidNavigation/ListViewModel.kt b/sample/src/main/java/cafe/adriel/voyager/sample/androidNavigation/ListViewModel.kt
new file mode 100644
index 00000000..8891682e
--- /dev/null
+++ b/sample/src/main/java/cafe/adriel/voyager/sample/androidNavigation/ListViewModel.kt
@@ -0,0 +1,15 @@
+package cafe.adriel.voyager.sample.androidNavigation
+
+import androidx.lifecycle.SavedStateHandle
+import androidx.lifecycle.ViewModel
+import java.util.UUID
+
+class ListViewModel(private val handle: SavedStateHandle) : ViewModel() {
+
+ init {
+ handle["items"] = (0..100).map { "Item #$it | ${UUID.randomUUID().toString().substringBefore('-')}" }
+ }
+
+ val items: List
+ get() = handle["items"] ?: error("Items not found")
+}
diff --git a/sample/src/main/java/cafe/adriel/voyager/sample/basicNavigation/BasicNavigationScreen.kt b/sample/src/main/java/cafe/adriel/voyager/sample/basicNavigation/BasicNavigationScreen.kt
index 075c3469..93908f50 100644
--- a/sample/src/main/java/cafe/adriel/voyager/sample/basicNavigation/BasicNavigationScreen.kt
+++ b/sample/src/main/java/cafe/adriel/voyager/sample/basicNavigation/BasicNavigationScreen.kt
@@ -17,7 +17,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
-import cafe.adriel.voyager.core.screen.LifecycleEffect
+import cafe.adriel.voyager.core.lifecycle.LifecycleEffect
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.core.screen.uniqueScreenKey
import cafe.adriel.voyager.navigator.LocalNavigator
diff --git a/sample/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/TabContent.kt b/sample/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/TabContent.kt
index 3ce573b2..654f7dde 100644
--- a/sample/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/TabContent.kt
+++ b/sample/src/main/java/cafe/adriel/voyager/sample/tabNavigation/tabs/TabContent.kt
@@ -12,7 +12,7 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
-import cafe.adriel.voyager.core.screen.LifecycleEffect
+import cafe.adriel.voyager.core.lifecycle.LifecycleEffect
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.tab.LocalTabNavigator
import cafe.adriel.voyager.navigator.tab.Tab
diff --git a/voyager-androidx/src/main/java/cafe/adriel/voyager/androidx/AndroidScreen.kt b/voyager-androidx/src/main/java/cafe/adriel/voyager/androidx/AndroidScreen.kt
index 4f2106b6..1979a9ff 100644
--- a/voyager-androidx/src/main/java/cafe/adriel/voyager/androidx/AndroidScreen.kt
+++ b/voyager-androidx/src/main/java/cafe/adriel/voyager/androidx/AndroidScreen.kt
@@ -1,9 +1,14 @@
package cafe.adriel.voyager.androidx
+import cafe.adriel.voyager.core.lifecycle.ScreenLifecycleOwner
+import cafe.adriel.voyager.core.lifecycle.ScreenLifecycleProvider
import cafe.adriel.voyager.core.screen.Screen
+import cafe.adriel.voyager.core.screen.ScreenKey
import cafe.adriel.voyager.core.screen.uniqueScreenKey
-public abstract class AndroidScreen : Screen, ScreenLifecycleOwner by ScreenLifecycleHolder() {
+public abstract class AndroidScreen : Screen, ScreenLifecycleProvider {
- override val key: String = uniqueScreenKey
+ override val key: ScreenKey = uniqueScreenKey
+
+ override fun getLifecycleOwner(): ScreenLifecycleOwner = ScreenLifecycleHolder.get(key)
}
diff --git a/voyager-androidx/src/main/java/cafe/adriel/voyager/androidx/ScreenLifecycleHolder.kt b/voyager-androidx/src/main/java/cafe/adriel/voyager/androidx/ScreenLifecycleHolder.kt
new file mode 100644
index 00000000..f1c88f14
--- /dev/null
+++ b/voyager-androidx/src/main/java/cafe/adriel/voyager/androidx/ScreenLifecycleHolder.kt
@@ -0,0 +1,77 @@
+package cafe.adriel.voyager.androidx
+
+import android.app.Activity
+import android.content.Context
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalSavedStateRegistryOwner
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.LifecycleRegistry
+import androidx.lifecycle.ViewModelStore
+import androidx.lifecycle.ViewModelStoreOwner
+import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
+import androidx.savedstate.SavedStateRegistry
+import androidx.savedstate.SavedStateRegistryController
+import androidx.savedstate.SavedStateRegistryOwner
+import cafe.adriel.voyager.core.lifecycle.ScreenHooks
+import cafe.adriel.voyager.core.lifecycle.ScreenLifecycleOwner
+import cafe.adriel.voyager.core.screen.ScreenKey
+import java.util.concurrent.ConcurrentHashMap
+
+public class ScreenLifecycleHolder private constructor(
+ private val key: ScreenKey
+) : ScreenLifecycleOwner,
+ LifecycleOwner,
+ ViewModelStoreOwner,
+ SavedStateRegistryOwner {
+
+ private val registry = LifecycleRegistry(this)
+
+ private val store = ViewModelStore()
+
+ private val controller = SavedStateRegistryController.create(this)
+
+ private val Context.canDispose: Boolean
+ get() = (this as? Activity)?.isChangingConfigurations?.not() ?: true
+
+ init {
+ controller.performRestore(null)
+ }
+
+ @Composable
+ override fun getHooks(): ScreenHooks {
+ val context = LocalContext.current
+
+ return ScreenHooks(
+ providers = listOf(
+ LocalViewModelStoreOwner provides this,
+ LocalSavedStateRegistryOwner provides this,
+ ),
+ disposer = {
+ if (context.canDispose) {
+ viewModelStore.clear()
+ remove(key)
+ }
+ }
+ )
+ }
+
+ override fun getLifecycle(): Lifecycle = registry
+
+ override fun getViewModelStore(): ViewModelStore = store
+
+ override fun getSavedStateRegistry(): SavedStateRegistry = controller.savedStateRegistry
+
+ internal companion object {
+
+ private val holders = ConcurrentHashMap()
+
+ internal fun get(key: ScreenKey) =
+ holders.getOrPut(key) { ScreenLifecycleHolder(key) }
+
+ private fun remove(key: ScreenKey) {
+ holders -= key
+ }
+ }
+}
diff --git a/voyager-androidx/src/main/java/cafe/adriel/voyager/androidx/ScreenLifecycleOwner.kt b/voyager-androidx/src/main/java/cafe/adriel/voyager/androidx/ScreenLifecycleOwner.kt
deleted file mode 100644
index 9d2c9115..00000000
--- a/voyager-androidx/src/main/java/cafe/adriel/voyager/androidx/ScreenLifecycleOwner.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package cafe.adriel.voyager.androidx
-
-import androidx.compose.ui.platform.LocalSavedStateRegistryOwner
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.LifecycleRegistry
-import androidx.lifecycle.ViewModelStore
-import androidx.lifecycle.ViewModelStoreOwner
-import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
-import androidx.savedstate.SavedStateRegistry
-import androidx.savedstate.SavedStateRegistryController
-import androidx.savedstate.SavedStateRegistryOwner
-import cafe.adriel.voyager.core.hook.HookableScreen
-import cafe.adriel.voyager.core.hook.ScreenHook
-import cafe.adriel.voyager.core.hook.ScreenHookHandler
-
-public val ScreenLifecycleOwner.screenLifecycleHooks: List
- get() = listOf(
- ScreenHook.OnProvide { LocalViewModelStoreOwner provides this },
- ScreenHook.OnProvide { LocalSavedStateRegistryOwner provides this },
- ScreenHook.OnDispose { viewModelStore.clear() }
- )
-
-public interface ScreenLifecycleOwner : HookableScreen, LifecycleOwner, ViewModelStoreOwner, SavedStateRegistryOwner
-
-public class ScreenLifecycleHolder : ScreenLifecycleOwner, HookableScreen by ScreenHookHandler() {
-
- private val store = ViewModelStore()
-
- private val registry = LifecycleRegistry(this)
-
- private val controller = SavedStateRegistryController.create(this)
-
- init {
- controller.performRestore(null)
- addHooks(screenLifecycleHooks)
- }
-
- override fun getViewModelStore(): ViewModelStore = store
-
- override fun getLifecycle(): Lifecycle = registry
-
- override fun getSavedStateRegistry(): SavedStateRegistry = controller.savedStateRegistry
-}
diff --git a/voyager-core/src/main/java/cafe/adriel/voyager/core/hook/Hookable.kt b/voyager-core/src/main/java/cafe/adriel/voyager/core/hook/Hookable.kt
deleted file mode 100644
index e648d25a..00000000
--- a/voyager-core/src/main/java/cafe/adriel/voyager/core/hook/Hookable.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package cafe.adriel.voyager.core.hook
-
-public inline fun Hookable.addHooks(vararg hooks: T) {
- addHooks(hooks.toList())
-}
-
-public inline fun Hookable.removeHooks(vararg hooks: T) {
- removeHooks(hooks.toList())
-}
-
-public interface Hookable {
-
- public val hooks: List
-
- public fun addHooks(hooks: List)
-
- public fun removeHooks(hooks: List)
-
- public fun clearHooks()
-}
diff --git a/voyager-core/src/main/java/cafe/adriel/voyager/core/hook/ScreenHook.kt b/voyager-core/src/main/java/cafe/adriel/voyager/core/hook/ScreenHook.kt
deleted file mode 100644
index 761c5fbd..00000000
--- a/voyager-core/src/main/java/cafe/adriel/voyager/core/hook/ScreenHook.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package cafe.adriel.voyager.core.hook
-
-import androidx.compose.runtime.ProvidedValue
-import cafe.adriel.voyager.core.screen.Screen
-
-public typealias HookableScreen = Hookable
-
-public val Screen.hooks: ScreenHooks
- get() = when (this) {
- is Hookable<*> -> ScreenHooks(
- providers = hooks.filterIsInstance>(),
- disposers = hooks.filterIsInstance(),
- )
- else -> ScreenHooks()
- }
-
-public fun Screen.clearHooks() {
- if (this is Hookable<*>) {
- clearHooks()
- }
-}
-
-public sealed class ScreenHook {
- public data class OnProvide(val provide: () -> ProvidedValue) : ScreenHook()
- public data class OnDispose(val dispose: () -> Unit) : ScreenHook()
-}
-
-public data class ScreenHooks(
- val providers: List> = emptyList(),
- val disposers: List = emptyList()
-)
-
-public class ScreenHookHandler : HookableScreen {
-
- private val mutableHooks = mutableListOf()
-
- override val hooks: List
- get() = mutableHooks
-
- override fun addHooks(hooks: List) {
- mutableHooks += hooks
- }
-
- override fun removeHooks(hooks: List) {
- mutableHooks -= hooks
- }
-
- override fun clearHooks() {
- mutableHooks.clear()
- }
-}
diff --git a/voyager-core/src/main/java/cafe/adriel/voyager/core/lifecycle/ScreenHooks.kt b/voyager-core/src/main/java/cafe/adriel/voyager/core/lifecycle/ScreenHooks.kt
new file mode 100644
index 00000000..c45a73c9
--- /dev/null
+++ b/voyager-core/src/main/java/cafe/adriel/voyager/core/lifecycle/ScreenHooks.kt
@@ -0,0 +1,13 @@
+package cafe.adriel.voyager.core.lifecycle
+
+import androidx.compose.runtime.ProvidedValue
+
+public data class ScreenHooks(
+ val providers: List> = emptyList(),
+ val disposer: () -> Unit = {}
+) {
+
+ internal companion object {
+ val Empty = ScreenHooks()
+ }
+}
diff --git a/voyager-core/src/main/java/cafe/adriel/voyager/core/lifecycle/ScreenLifecycle.kt b/voyager-core/src/main/java/cafe/adriel/voyager/core/lifecycle/ScreenLifecycle.kt
new file mode 100644
index 00000000..b4311d7c
--- /dev/null
+++ b/voyager-core/src/main/java/cafe/adriel/voyager/core/lifecycle/ScreenLifecycle.kt
@@ -0,0 +1,41 @@
+package cafe.adriel.voyager.core.lifecycle
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.remember
+import cafe.adriel.voyager.core.screen.Screen
+
+@Composable
+public fun Screen.LifecycleEffect(
+ onStarted: () -> Unit = {},
+ onDisposed: () -> Unit = {}
+) {
+ DisposableEffect(key) {
+ onStarted()
+ onDispose(onDisposed)
+ }
+}
+
+@Composable
+public fun rememberScreenLifecycleOwner(
+ screen: Screen
+): ScreenLifecycleOwner =
+ remember(screen.key) {
+ when (screen) {
+ is ScreenLifecycleProvider -> screen.getLifecycleOwner()
+ else -> DefaultScreenLifecycleOwner
+ }
+ }
+
+public interface ScreenLifecycleProvider {
+
+ public fun getLifecycleOwner(): ScreenLifecycleOwner
+}
+
+public interface ScreenLifecycleOwner {
+
+ @Composable
+ public fun getHooks(): ScreenHooks = ScreenHooks.Empty
+}
+
+private object DefaultScreenLifecycleOwner : ScreenLifecycleOwner
diff --git a/voyager-core/src/main/java/cafe/adriel/voyager/core/screen/Screen.kt b/voyager-core/src/main/java/cafe/adriel/voyager/core/screen/Screen.kt
index 4a57e70b..8fe4dd0a 100644
--- a/voyager-core/src/main/java/cafe/adriel/voyager/core/screen/Screen.kt
+++ b/voyager-core/src/main/java/cafe/adriel/voyager/core/screen/Screen.kt
@@ -1,24 +1,12 @@
package cafe.adriel.voyager.core.screen
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
import java.io.Serializable
-@Composable
-public fun Screen.LifecycleEffect(
- onStarted: () -> Unit = {},
- onDisposed: () -> Unit = {}
-) {
- DisposableEffect(key) {
- onStarted()
- onDispose(onDisposed)
- }
-}
-
public interface Screen : Serializable {
- public val key: String
- get() = this::class.qualifiedName ?: error("Default key not found, please provide your own key")
+ public val key: ScreenKey
+ get() = this::class.qualifiedName ?: error("Default ScreenKey not found, please provide your own key")
@Composable
public fun Content()
diff --git a/voyager-core/src/main/java/cafe/adriel/voyager/core/screen/ScreenKey.kt b/voyager-core/src/main/java/cafe/adriel/voyager/core/screen/ScreenKey.kt
index cf7869bf..e1d5e9ac 100644
--- a/voyager-core/src/main/java/cafe/adriel/voyager/core/screen/ScreenKey.kt
+++ b/voyager-core/src/main/java/cafe/adriel/voyager/core/screen/ScreenKey.kt
@@ -2,7 +2,9 @@ package cafe.adriel.voyager.core.screen
import java.util.concurrent.atomic.AtomicInteger
+public typealias ScreenKey = String
+
private val nextScreenKey = AtomicInteger(0)
-public val Screen.uniqueScreenKey: String
+public val Screen.uniqueScreenKey: ScreenKey
get() = "Screen#${nextScreenKey.getAndIncrement()}"
diff --git a/voyager-core/src/main/java/cafe/adriel/voyager/core/stack/SnapshotStateStack.kt b/voyager-core/src/main/java/cafe/adriel/voyager/core/stack/SnapshotStateStack.kt
index 837a424e..7956419c 100644
--- a/voyager-core/src/main/java/cafe/adriel/voyager/core/stack/SnapshotStateStack.kt
+++ b/voyager-core/src/main/java/cafe/adriel/voyager/core/stack/SnapshotStateStack.kt
@@ -156,4 +156,8 @@ public class SnapshotStateStack- (
public override operator fun plusAssign(items: List
- ) {
push(items)
}
+
+ override fun clearEvent() {
+ lastEvent = StackEvent.Idle
+ }
}
diff --git a/voyager-core/src/main/java/cafe/adriel/voyager/core/stack/Stack.kt b/voyager-core/src/main/java/cafe/adriel/voyager/core/stack/Stack.kt
index 295c1a0b..58b249a3 100644
--- a/voyager-core/src/main/java/cafe/adriel/voyager/core/stack/Stack.kt
+++ b/voyager-core/src/main/java/cafe/adriel/voyager/core/stack/Stack.kt
@@ -47,4 +47,6 @@ public interface Stack
- {
public operator fun plusAssign(item: Item)
public operator fun plusAssign(items: List
- )
+
+ public fun clearEvent()
}
diff --git a/voyager-navigator/src/main/java/cafe/adriel/voyager/navigator/Navigator.kt b/voyager-navigator/src/main/java/cafe/adriel/voyager/navigator/Navigator.kt
index 9f27e52e..e9f8ae47 100644
--- a/voyager-navigator/src/main/java/cafe/adriel/voyager/navigator/Navigator.kt
+++ b/voyager-navigator/src/main/java/cafe/adriel/voyager/navigator/Navigator.kt
@@ -7,9 +7,9 @@ import androidx.compose.runtime.ProvidableCompositionLocal
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.saveable.SaveableStateHolder
+import androidx.compose.runtime.setValue
import androidx.compose.runtime.staticCompositionLocalOf
-import cafe.adriel.voyager.core.hook.clearHooks
-import cafe.adriel.voyager.core.hook.hooks
+import cafe.adriel.voyager.core.lifecycle.rememberScreenLifecycleOwner
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.core.stack.Stack
import cafe.adriel.voyager.core.stack.StackEvent
@@ -64,11 +64,12 @@ public fun Navigator(
val navigator = rememberNavigator(screens, LocalNavigator.current)
val currentScreen = navigator.lastItem
- val hooks = currentScreen.hooks
+ val lifecycleOwner = rememberScreenLifecycleOwner(currentScreen)
+ val hooks = lifecycleOwner.getHooks()
CompositionLocalProvider(
LocalNavigator provides navigator,
- *hooks.providers.map { it.provide() }.toTypedArray()
+ *hooks.providers.toTypedArray()
) {
content(navigator)
@@ -77,9 +78,9 @@ public fun Navigator(
DisposableEffect(currentScreen.key) {
onDispose {
if (navigator.lastEvent in disposableEvents) {
+ hooks.disposer()
navigator.stateHolder.removeState(currentScreen.key)
- hooks.disposers.forEach { it.dispose() }
- currentScreen.clearHooks()
+ navigator.clearEvent()
}
}
}
diff --git a/voyager-tab-navigator/src/main/java/cafe/adriel/voyager/navigator/tab/TabNavigator.kt b/voyager-tab-navigator/src/main/java/cafe/adriel/voyager/navigator/tab/TabNavigator.kt
index 42b4738e..d74241a6 100644
--- a/voyager-tab-navigator/src/main/java/cafe/adriel/voyager/navigator/tab/TabNavigator.kt
+++ b/voyager-tab-navigator/src/main/java/cafe/adriel/voyager/navigator/tab/TabNavigator.kt
@@ -9,8 +9,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.SaveableStateHolder
import androidx.compose.runtime.setValue
import androidx.compose.runtime.staticCompositionLocalOf
-import cafe.adriel.voyager.core.hook.clearHooks
-import cafe.adriel.voyager.core.hook.hooks
+import cafe.adriel.voyager.core.lifecycle.rememberScreenLifecycleOwner
import cafe.adriel.voyager.navigator.tab.internal.rememberTabNavigator
public typealias TabNavigatorContent = @Composable (tabNavigator: TabNavigator) -> Unit
@@ -25,19 +24,19 @@ public fun TabNavigator(
) {
val tabNavigator = rememberTabNavigator(tab)
val currentTab = tabNavigator.current
- val hooks = currentTab.hooks
+ val lifecycleOwner = rememberScreenLifecycleOwner(currentTab)
+ val hooks = lifecycleOwner.getHooks()
CompositionLocalProvider(
LocalTabNavigator provides tabNavigator,
- *hooks.providers.map { it.provide() }.toTypedArray()
+ *hooks.providers.toTypedArray()
) {
content(tabNavigator)
}
DisposableEffect(tabNavigator) {
onDispose {
- hooks.disposers.forEach { it.dispose() }
- currentTab.clearHooks()
+ hooks.disposer()
}
}
}