Skip to content

Instantly share code, notes, and snippets.

@arkivanov
Last active August 4, 2023 12:29
Show Gist options
  • Save arkivanov/c19fbc0dac4b5c296cc4a888426fa17e to your computer and use it in GitHub Desktop.
Save arkivanov/c19fbc0dac4b5c296cc4a888426fa17e to your computer and use it in GitHub Desktop.
Compose-like navigation with Decompose
@Composable
fun <T : Parcelable> Navigator(
initialConfiguration: () -> T,
configurationClass: KClass<out T>,
content: @Composable Router<T>.(T) -> Unit
) {
val lifecycle = getLifecycle()
val stateKeeper = getStateKeeper()
val context = remember { DefaultComponentContext(lifecycle = lifecycle, stateKeeper = stateKeeper) }
val router =
remember {
val decomposeRouter =
context.router(
initialConfiguration = initialConfiguration,
configurationClass = configurationClass,
componentFactory = { configuration, _ -> configuration }
)
object : Router<T>, com.arkivanov.decompose.Router<T, T> by decomposeRouter {}
}
val routerState by router.state.asState()
router.content(routerState.activeChild.configuration)
}
@Composable
private fun getLifecycle(): Lifecycle {
val lifecycle = remember { LifecycleRegistry() }
onActive { lifecycle.resume() }
onDispose { lifecycle.destroy() }
return lifecycle
}
@Composable
private fun getStateKeeper(key: String = "state"): StateKeeper {
val savedStateRegistry: UiSavedStateRegistry? = AmbientUiSavedStateRegistry.current
val dispatcher =
remember {
StateKeeperDispatcher(savedStateRegistry?.consumeRestored(key) as ParcelableContainer?)
}
if (savedStateRegistry != null) {
val stateProvider = dispatcher::save
onActive { savedStateRegistry.registerProvider(key, stateProvider) }
onDispose { savedStateRegistry.unregisterProvider(key, stateProvider) }
}
return dispatcher
}
interface Router<in T : Parcelable> {
fun push(configuration: T)
fun pop()
}
@Elblassy
Copy link

Elblassy commented Jan 2, 2021

asState() unresolved , in line 24

@arkivanov
Copy link
Author

asState() unresolved , in line 24

You have to add one of the Compose extension modules: https://github.com/arkivanov/Decompose#setup

@arkivanov
Copy link
Author

Also please note, this is just a draft. Since Decompose is evolving, you may need to adjust the sample.

@Elblassy
Copy link

Elblassy commented Jan 2, 2021

it said "Type 'State<TypeVariable(T)>' has no method 'getValue(Nothing?, KProperty<*>)' and thus it cannot serve as a delegate" , i know that is just a draft but i can't do navigate with documentation you provide to use decompose , can you help me with simple example to navigate between two screen

@Elblassy
Copy link

Elblassy commented Jan 2, 2021

I am using this extension "com.arkivanov.decompose:extensions-compose-jetbrains:0.1.5"

@Elblassy
Copy link

Elblassy commented Jan 2, 2021

it now work i update it to be val routerState = router.state.asState() instead of delegate
update it :)

@arkivanov
Copy link
Author

It is a known issue: https://youtrack.jetbrains.com/issue/KT-39199
You need to manually import getValue extension function:
import com.arkivanov.decompose.extensions.compose.jetbrains.getValue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment