Arkadii Ivanov
4 years ago
2 changed files with 105 additions and 7 deletions
@ -0,0 +1,100 @@ |
|||||||
|
/* |
||||||
|
* Copied from Decompose |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.arkivanov.decompose.extensions.compose |
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import androidx.compose.runtime.Providers |
||||||
|
import androidx.compose.runtime.onDispose |
||||||
|
import androidx.compose.runtime.remember |
||||||
|
import androidx.compose.runtime.savedinstancestate.UiSavedStateRegistry |
||||||
|
import androidx.compose.runtime.savedinstancestate.UiSavedStateRegistryAmbient |
||||||
|
import com.arkivanov.decompose.RouterState |
||||||
|
import com.arkivanov.decompose.statekeeper.Parcelable |
||||||
|
import com.arkivanov.decompose.value.Value |
||||||
|
import example.todo.common.utils.invoke |
||||||
|
|
||||||
|
private typealias SavedState = Map<String, List<Any?>> |
||||||
|
|
||||||
|
@Composable |
||||||
|
fun <C : Parcelable, T : Any> Value<RouterState<C, T>>.children(render: @Composable() (child: T, configuration: C) -> Unit) { |
||||||
|
val parentRegistry: UiSavedStateRegistry? = UiSavedStateRegistryAmbient.current |
||||||
|
val children = remember { Children<C>() } |
||||||
|
|
||||||
|
if (parentRegistry != null) { |
||||||
|
onDispose { |
||||||
|
children.inactive.entries.forEach { (key, value) -> |
||||||
|
parentRegistry.unregisterProvider(key, value.provider) |
||||||
|
} |
||||||
|
children.active?.also { |
||||||
|
parentRegistry.unregisterProvider(it.key, it.provider) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
invoke { state -> |
||||||
|
val activeChildConfiguration = state.activeChild.configuration |
||||||
|
|
||||||
|
val currentChild: ActiveChild<C>? = children.active |
||||||
|
if ((currentChild != null) && state.backStack.any { it.configuration === currentChild.configuration }) { |
||||||
|
parentRegistry?.unregisterProvider(currentChild.key, currentChild.provider) |
||||||
|
val inactiveChild = InactiveChild(configuration = currentChild.configuration, savedState = currentChild.provider()) |
||||||
|
children.inactive[currentChild.key] = inactiveChild |
||||||
|
parentRegistry?.registerProvider(currentChild.key, inactiveChild.provider) |
||||||
|
} |
||||||
|
|
||||||
|
val activeChildRegistry: UiSavedStateRegistry |
||||||
|
|
||||||
|
if (currentChild?.configuration === activeChildConfiguration) { |
||||||
|
activeChildRegistry = currentChild.registry |
||||||
|
} else { |
||||||
|
val key = activeChildConfiguration.toString() |
||||||
|
|
||||||
|
val savedChild: InactiveChild<C>? = children.inactive.remove(key) |
||||||
|
if (savedChild != null) { |
||||||
|
parentRegistry?.unregisterProvider(key, savedChild.provider) |
||||||
|
} |
||||||
|
@Suppress("UNCHECKED_CAST") |
||||||
|
val savedState: SavedState? = savedChild?.savedState ?: parentRegistry?.consumeRestored(key) as SavedState? |
||||||
|
|
||||||
|
activeChildRegistry = UiSavedStateRegistry(savedState) { true } |
||||||
|
|
||||||
|
val newActiveChild = ActiveChild(configuration = activeChildConfiguration, key = key, registry = activeChildRegistry) |
||||||
|
children.active = newActiveChild |
||||||
|
parentRegistry?.registerProvider(key, newActiveChild.provider) |
||||||
|
} |
||||||
|
|
||||||
|
children.inactive.entries.removeAll { (key, value) -> |
||||||
|
val remove = state.backStack.none { it.configuration === value.configuration } |
||||||
|
if (remove) { |
||||||
|
parentRegistry?.unregisterProvider(key, value.provider) |
||||||
|
} |
||||||
|
remove |
||||||
|
} |
||||||
|
|
||||||
|
Providers(UiSavedStateRegistryAmbient provides activeChildRegistry) { |
||||||
|
render(state.activeChild.component, activeChildConfiguration) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class Children<C : Parcelable> { |
||||||
|
val inactive: MutableMap<String, InactiveChild<C>> = HashMap() |
||||||
|
var active: ActiveChild<C>? = null |
||||||
|
} |
||||||
|
|
||||||
|
private class ActiveChild<out C : Parcelable>( |
||||||
|
val configuration: C, |
||||||
|
val key: String, |
||||||
|
val registry: UiSavedStateRegistry |
||||||
|
) { |
||||||
|
val provider: () -> SavedState = registry::performSave |
||||||
|
} |
||||||
|
|
||||||
|
private class InactiveChild<out C : Parcelable>( |
||||||
|
val configuration: C, |
||||||
|
val savedState: SavedState |
||||||
|
) { |
||||||
|
val provider: () -> SavedState = ::savedState |
||||||
|
} |
Loading…
Reference in new issue