Browse Source

Update Decompose to 0.1.1, remove copy-pasted code (#102)

Co-authored-by: Arkadii Ivanov <>
pull/98/head
Arkadii Ivanov 4 years ago committed by GitHub
parent
commit
1b294335a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      examples/todoapp/android/build.gradle.kts
  2. 34
      examples/todoapp/android/src/main/java/example/todo/android/MainActivity.kt
  3. 3
      examples/todoapp/buildSrc/buildSrc/src/main/kotlin/Deps.kt
  4. 2
      examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/ui/TodoEditUi.kt
  5. 8
      examples/todoapp/common/main/src/commonMain/kotlin/example/todo/common/main/ui/TodoMainUi.kt
  6. 1
      examples/todoapp/common/root/build.gradle.kts
  7. 2
      examples/todoapp/common/root/src/commonMain/kotlin/example/todo/common/root/integration/TodoRootImpl.kt
  8. 1
      examples/todoapp/common/utils/build.gradle.kts
  9. 99
      examples/todoapp/common/utils/src/commonMain/kotlin/example/todo/common/utils/RouterStateComposable.kt
  10. 2
      examples/todoapp/common/utils/src/commonMain/kotlin/example/todo/common/utils/StoreExt.kt
  11. 34
      examples/todoapp/common/utils/src/commonMain/kotlin/example/todo/common/utils/ValueComposable.kt
  12. 1
      examples/todoapp/desktop/build.gradle.kts
  13. 22
      examples/todoapp/desktop/src/jvmMain/kotlin/example/todo/desktop/Main.kt

1
examples/todoapp/android/build.gradle.kts

@ -36,4 +36,5 @@ dependencies {
implementation(Deps.ArkIvanov.MVIKotlin.mvikotlinLogging)
implementation(Deps.ArkIvanov.MVIKotlin.mvikotlinTimeTravel)
implementation(Deps.ArkIvanov.Decompose.decompose)
implementation(Deps.ArkIvanov.Decompose.extensionsCompose)
}

34
examples/todoapp/android/src/main/java/example/todo/android/MainActivity.kt

@ -5,11 +5,8 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.ui.platform.setContent
import com.arkivanov.decompose.DefaultComponentContext
import com.arkivanov.decompose.backpressed.toBackPressedDispatched
import com.arkivanov.decompose.instancekeeper.toInstanceKeeper
import com.arkivanov.decompose.lifecycle.asDecomposeLifecycle
import com.arkivanov.decompose.statekeeper.toStateKeeper
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.extensions.compose.jetbrains.rootComponent
import com.arkivanov.mvikotlin.core.store.StoreFactory
import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory
import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
@ -22,27 +19,22 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val todoRoot =
TodoRoot(
componentContext = DefaultComponentContext(
lifecycle = lifecycle.asDecomposeLifecycle(),
stateKeeper = savedStateRegistry.toStateKeeper(),
instanceKeeper = viewModelStore.toInstanceKeeper(),
backPressedDispatcher = onBackPressedDispatcher.toBackPressedDispatched(lifecycle)
),
dependencies = object : TodoRoot.Dependencies {
// You can play with time travel using IDEA plugin: https://arkivanov.github.io/MVIKotlin/time_travel.html
override val storeFactory: StoreFactory = LoggingStoreFactory(TimeTravelStoreFactory(DefaultStoreFactory))
override val database: TodoDatabase = TodoDatabase(TodoDatabaseDriver(this@MainActivity))
}
)
setContent {
ComposeAppTheme {
Surface(color = MaterialTheme.colors.background) {
todoRoot()
rootComponent(::todoRoot).invoke()
}
}
}
}
private fun todoRoot(componentContext: ComponentContext): TodoRoot =
TodoRoot(
componentContext = componentContext,
dependencies = object : TodoRoot.Dependencies {
// You can play with time travel using IDEA plugin: https://arkivanov.github.io/MVIKotlin/time_travel.html
override val storeFactory: StoreFactory = LoggingStoreFactory(TimeTravelStoreFactory(DefaultStoreFactory))
override val database: TodoDatabase = TodoDatabase(TodoDatabaseDriver(this@MainActivity))
}
)
}

3
examples/todoapp/buildSrc/buildSrc/src/main/kotlin/Deps.kt

@ -35,8 +35,9 @@ object Deps {
}
object Decompose {
private const val VERSION = "0.1.0"
private const val VERSION = "0.1.1"
const val decompose = "com.arkivanov.decompose:decompose:$VERSION"
const val extensionsCompose = "com.arkivanov.decompose:extensions-compose-jetbrains:$VERSION"
}
}

2
examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/ui/TodoEditUi.kt

@ -1,6 +1,5 @@
package example.todo.common.edit.ui
import androidx.compose.foundation.Icon
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@ -8,6 +7,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.Checkbox
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Text
import androidx.compose.material.TextField

8
examples/todoapp/common/main/src/commonMain/kotlin/example/todo/common/main/ui/TodoMainUi.kt

@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumnFor
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.Button
import androidx.compose.material.Checkbox
import androidx.compose.material.Divider
import androidx.compose.material.Icon
@ -19,6 +18,7 @@ import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Delete
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@ -147,8 +147,10 @@ private fun TodoInput(
label = { Text(text = "Add a todo") }
)
Button(modifier = Modifier.padding(start = 8.dp), onClick = onAddClicked) {
Text(text = "+")
Spacer(modifier = Modifier.width(8.dp))
IconButton(onClick = onAddClicked) {
Icon(Icons.Default.Add)
}
}
}

1
examples/todoapp/common/root/build.gradle.kts

@ -17,6 +17,7 @@ kotlin {
implementation(project(":common:main"))
implementation(project(":common:edit"))
implementation(Deps.ArkIvanov.Decompose.decompose)
implementation(Deps.ArkIvanov.Decompose.extensionsCompose)
implementation(Deps.Badoo.Reaktive.reaktive)
}
}

2
examples/todoapp/common/root/src/commonMain/kotlin/example/todo/common/root/integration/TodoRootImpl.kt

@ -2,6 +2,7 @@ package example.todo.common.root.integration
import androidx.compose.runtime.Composable
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.extensions.compose.jetbrains.children
import com.arkivanov.decompose.router
import com.arkivanov.decompose.statekeeper.Parcelable
import com.arkivanov.decompose.statekeeper.Parcelize
@ -13,7 +14,6 @@ import example.todo.common.root.TodoRoot.Dependencies
import example.todo.common.utils.Component
import example.todo.common.utils.Consumer
import example.todo.common.utils.Crossfade
import example.todo.common.utils.children
internal class TodoRootImpl(
componentContext: ComponentContext,

1
examples/todoapp/common/utils/build.gradle.kts

@ -10,6 +10,7 @@ kotlin {
implementation(Deps.ArkIvanov.MVIKotlin.mvikotlin)
implementation(Deps.ArkIvanov.MVIKotlin.mvikotlinExtensionsReaktive)
implementation(Deps.ArkIvanov.Decompose.decompose)
implementation(Deps.ArkIvanov.Decompose.extensionsCompose)
}
}
}

99
examples/todoapp/common/utils/src/commonMain/kotlin/example/todo/common/utils/RouterStateComposable.kt

@ -1,99 +0,0 @@
/*
* Copied from Decompose
*/
package example.todo.common.utils
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
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(value) { 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)
}
}
}
observe { 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
}

2
examples/todoapp/common/utils/src/commonMain/kotlin/example/todo/common/utils/StoreExt.kt

@ -13,7 +13,7 @@ import com.badoo.reaktive.observable.subscribe
val <T : Any> Store<*, T, *>.composeState: State<T>
get() {
val composeState = remember(this) { mutableStateOf(state) }
val disposable = states.subscribe(onNext = { composeState.value = it })
val disposable = remember(this) { states.subscribe(onNext = { composeState.value = it }) }
onDispose(disposable::dispose)
return composeState

34
examples/todoapp/common/utils/src/commonMain/kotlin/example/todo/common/utils/ValueComposable.kt

@ -1,34 +0,0 @@
/*
* Copied from Decompose
*/
package example.todo.common.utils
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.onDispose
import androidx.compose.runtime.remember
import com.arkivanov.decompose.value.Value
import com.arkivanov.decompose.value.ValueObserver
@Composable
fun <T : Any> Value<T>.asState(): State<T> {
val composeState = remember(this) { mutableStateOf(value) }
val observer =
remember(this) {
val observer: ValueObserver<T> = { composeState.value = it }
subscribe(observer)
observer
}
onDispose { unsubscribe(observer) }
return composeState
}
@Composable
fun <T : Any> Value<T>.observe(observer: @Composable() (T) -> Unit) {
observer(asState().value)
}

1
examples/todoapp/desktop/build.gradle.kts

@ -19,6 +19,7 @@ kotlin {
implementation(project(":common:database"))
implementation(project(":common:root"))
implementation(Deps.ArkIvanov.Decompose.decompose)
implementation(Deps.ArkIvanov.Decompose.extensionsCompose)
implementation(Deps.ArkIvanov.MVIKotlin.mvikotlin)
implementation(Deps.ArkIvanov.MVIKotlin.mvikotlinMain)
implementation(Deps.Badoo.Reaktive.reaktive)

22
examples/todoapp/desktop/src/jvmMain/kotlin/example/todo/desktop/Main.kt

@ -6,7 +6,8 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.ui.Modifier
import com.arkivanov.decompose.DefaultComponentContext
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.extensions.compose.jetbrains.rootComponent
import com.arkivanov.decompose.lifecycle.LifecycleRegistry
import com.arkivanov.decompose.lifecycle.resume
import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
@ -23,21 +24,22 @@ fun main() {
val lifecycle = LifecycleRegistry()
lifecycle.resume()
val todoRoot = TodoRoot(
componentContext = DefaultComponentContext(lifecycle),
dependencies = object : TodoRoot.Dependencies {
override val storeFactory = DefaultStoreFactory
override val database = TodoDatabase(TodoDatabaseDriver())
}
)
Window("Todo") {
Surface(modifier = Modifier.fillMaxSize()) {
MaterialTheme {
DesktopTheme {
todoRoot()
rootComponent(factory = ::todoRoot).invoke()
}
}
}
}
}
private fun todoRoot(componentContext: ComponentContext): TodoRoot =
TodoRoot(
componentContext = componentContext,
dependencies = object : TodoRoot.Dependencies {
override val storeFactory = DefaultStoreFactory
override val database = TodoDatabase(TodoDatabaseDriver())
}
)

Loading…
Cancel
Save