Skip to content

Instantly share code, notes, and snippets.

@amal
Forked from Nek-12/StackNavigator.kt
Created March 12, 2024 16:20
Show Gist options
  • Save amal/211f212e233d9fb6ee81513d8a603ef0 to your computer and use it in GitHub Desktop.
Save amal/211f212e233d9fb6ee81513d8a603ef0 to your computer and use it in GitHub Desktop.
Decompose - Global navigation events with channel
internal class StackComponent(context: ComponentContext): Component {
private val results = Channel<NavResult<*>>(Channel.CONFLATED)
inline fun <reified R> sendResult(result: R) {
val config = stack.active.configuration
// or popWhile - bring desired page to the front
navigation.pop {
results.trySend(NavResult(config, result))
}
}
suspend inline fun <reified D : Configuration, reified R> subscribe(
noinline onResult: suspend (result: R) -> Unit
) = results
.receiveAsFlow()
.filter { it.from is D && it.value is R }
.collectLatest { onResult(it.value as R) }
}
internal data class NavResult<T>(
val from: Component,
val value: T
)
// lambda that takes a lambda as a parameter. First lambda subscribes, parameter lambda handles the result.
// i.e. curry the result function.
typealias ResultReceiver<T> = @Composable ((action: (T) -> Unit) -> Unit)
internal inline fun <reified D : Component, reified R> StackComponent.resultReceiver(): ResultReceiver<R> =
@Composable {
val block by rememberUpdatedState(it)
LaunchedEffect(Unit) { subscribe<D, R>(block) }
}
internal inline fun <reified R> StackComponent.resultNavigator(): (R) -> Unit =
{ sendResult<R>(it) }
// feature module
// declare the screen
@Composable
fun SelectItemScreen(
component: ItemsComponent,
onBack: (Uuid?) -> Unit,
onAddItem: ResultReceiver<Uuid>,
)
// call the screen
SelectItemScreen(
component = component,
onBack = stackComponent.resultNavigator(),
onCreateItem = stackComponent.resultReceiver<CreateItemConfig, _>(),
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment