Skip to content

Commit

Permalink
rework for precompose setup
Browse files Browse the repository at this point in the history
  • Loading branch information
Tlaster committed Oct 16, 2023
1 parent bc13c2f commit daf7db5
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 81 deletions.
14 changes: 8 additions & 6 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
[versions] # also check project root build.gradle.kts for versions
androidx-animation = "1.5.0"
androidx-foundation = "1.5.0"
androidx-animation = "1.5.3"
androidx-foundation = "1.5.3"
androidx-appcompat = "1.6.1"
androidx-coreKtx = "1.10.1"
androidxActivityVer = "1.7.2"
androidx-coreKtx = "1.12.0"
androidxActivityVer = "1.8.0"
androidGradlePlugin = "8.1.1"
junit = "4.13.2"
junitJupiterEngine = "5.10.0"
junitJupiterApi = "5.10.0"
kotlin = "1.9.10"
kotlinxCoroutinesCore = "1.7.3"
lifecycleRuntimeKtx = "2.6.1"
material = "1.5.0"
lifecycleRuntimeKtx = "2.6.2"
material = "1.5.3"
moleculeRuntime = "1.2.1"
savedstateKtx = "1.2.1"
spotless = "6.22.0"
Expand All @@ -22,9 +22,11 @@ koin-compose = "1.1.0"

[libraries]
androidx-activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "androidxActivityVer" }
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidxActivityVer" }
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
androidx-coreKtx = { module = "androidx.core:core-ktx", version.ref = "androidx-coreKtx" }
androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycleRuntimeKtx" }
androidx-material = { module = "androidx.compose.material:material", version.ref = "material" }
androidx-savedstate-ktx = { module = "androidx.savedstate:savedstate-ktx", version.ref = "savedstateKtx" }
animation = { module = "androidx.compose.animation:animation", version.ref = "androidx-animation" }
Expand Down
16 changes: 15 additions & 1 deletion precompose/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,19 @@ group = "moe.tlaster"
version = rootProject.extra.get("precomposeVersion") as String

kotlin {
targetHierarchy.default()
targetHierarchy.default {
common {
group("nonAndroid") {
withMacosArm64()
withMacosX64()
withIosX64()
withIosArm64()
withIosSimulatorArm64()
withJvm()
withJs()
}
}
}
macosArm64()
macosX64()
iosX64()
Expand Down Expand Up @@ -61,6 +73,8 @@ kotlin {
api(libs.androidx.appcompat)
implementation(libs.androidx.lifecycle.runtime.ktx)
api(libs.androidx.savedstate.ktx)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.activity.compose)
}
}
val androidUnitTest by getting {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package moe.tlaster.precompose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.LocalSaveableStateRegistry
import androidx.compose.ui.Modifier
import androidx.lifecycle.DefaultLifecycleObserver
import moe.tlaster.precompose.lifecycle.Lifecycle
import moe.tlaster.precompose.lifecycle.LocalLifecycleOwner
import moe.tlaster.precompose.lifecycle.PreComposeViewModel
import moe.tlaster.precompose.stateholder.LocalSavedStateHolder
import moe.tlaster.precompose.stateholder.LocalStateHolder
import moe.tlaster.precompose.stateholder.SavedStateHolder
import moe.tlaster.precompose.ui.LocalBackDispatcherOwner

@Composable
actual fun PreComposeApp(
modifier: Modifier,
content: @Composable () -> Unit,
) {
val viewModel = androidx.lifecycle.viewmodel.compose.viewModel<PreComposeViewModel>()

val lifecycle = androidx.compose.ui.platform.LocalLifecycleOwner.current.lifecycle
val onBackPressedDispatcher = checkNotNull(androidx.activity.compose.LocalOnBackPressedDispatcherOwner.current) {
"No OnBackPressedDispatcherOwner was provided via LocalOnBackPressedDispatcherOwner"
}.onBackPressedDispatcher

DisposableEffect(lifecycle) {
val observer = object : DefaultLifecycleObserver {
override fun onCreate(owner: androidx.lifecycle.LifecycleOwner) {
super.onCreate(owner)
onBackPressedDispatcher.addCallback(owner, viewModel.backPressedCallback)
}

override fun onResume(owner: androidx.lifecycle.LifecycleOwner) {
super.onResume(owner)
viewModel.lifecycleRegistry.currentState = Lifecycle.State.Active
}

override fun onPause(owner: androidx.lifecycle.LifecycleOwner) {
super.onPause(owner)
viewModel.lifecycleRegistry.currentState = Lifecycle.State.InActive
}

// override fun onDestroy(owner: androidx.lifecycle.LifecycleOwner) {
// super.onDestroy(owner)
// if (!isChangingConfigurations) {
// viewModel.lifecycleRegistry.currentState = Lifecycle.State.Destroyed
// }
// }
}
lifecycle.addObserver(observer)
onDispose {
lifecycle.removeObserver(observer)
}
}

val state by viewModel.backDispatcher.canHandleBackPress.collectAsState(false)

val saveableStateRegistry = LocalSaveableStateRegistry.current
val savedStateHolder = remember(saveableStateRegistry) {
SavedStateHolder(
"root",
saveableStateRegistry,
)
}

LaunchedEffect(state) {
viewModel.backPressedCallback.isEnabled = state
}
CompositionLocalProvider(
LocalLifecycleOwner provides viewModel,
LocalStateHolder provides viewModel.stateHolder,
LocalBackDispatcherOwner provides viewModel,
LocalSavedStateHolder provides savedStateHolder,
) {
content.invoke()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,16 @@ package moe.tlaster.precompose.lifecycle

import android.view.ViewGroup
import androidx.activity.ComponentActivity
import androidx.activity.viewModels
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionContext
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.LocalSaveableStateRegistry
import androidx.compose.ui.platform.ComposeView
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.findViewTreeLifecycleOwner
import androidx.lifecycle.findViewTreeViewModelStoreOwner
import androidx.lifecycle.setViewTreeLifecycleOwner
import androidx.lifecycle.setViewTreeViewModelStoreOwner
import androidx.savedstate.findViewTreeSavedStateRegistryOwner
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
import moe.tlaster.precompose.stateholder.LocalSavedStateHolder
import moe.tlaster.precompose.stateholder.LocalStateHolder
import moe.tlaster.precompose.stateholder.SavedStateHolder
import moe.tlaster.precompose.ui.LocalBackDispatcherOwner
import moe.tlaster.precompose.PreComposeApp

fun ComponentActivity.setContent(
parent: CompositionContext? = null,
Expand Down Expand Up @@ -71,66 +58,7 @@ private fun ComponentActivity.setOwners() {

@Composable
private fun ComponentActivity.ContentInternal(content: @Composable () -> Unit) {
ProvideAndroidCompositionLocals {
content.invoke()
}
}

@Composable
private fun ComponentActivity.ProvideAndroidCompositionLocals(
content: @Composable () -> Unit,
) {
val viewModel by viewModels<PreComposeViewModel>()

DisposableEffect(lifecycle) {
val observer = object : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
onBackPressedDispatcher.addCallback(owner, viewModel.backPressedCallback)
}

override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
viewModel.lifecycleRegistry.currentState = Lifecycle.State.Active
}

override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)
viewModel.lifecycleRegistry.currentState = Lifecycle.State.InActive
}

override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
if (!isChangingConfigurations) {
viewModel.lifecycleRegistry.currentState = Lifecycle.State.Destroyed
}
}
}
lifecycle.addObserver(observer)
onDispose {
lifecycle.removeObserver(observer)
}
}

val state by viewModel.backDispatcher.canHandleBackPress.collectAsState(false)

val saveableStateRegistry = LocalSaveableStateRegistry.current
val savedStateHolder = remember(saveableStateRegistry) {
SavedStateHolder(
"root",
saveableStateRegistry,
)
}

LaunchedEffect(state) {
viewModel.backPressedCallback.isEnabled = state
}
CompositionLocalProvider(
LocalLifecycleOwner provides viewModel,
LocalStateHolder provides viewModel.stateHolder,
LocalBackDispatcherOwner provides viewModel,
LocalSavedStateHolder provides savedStateHolder,
) {
PreComposeApp {
content.invoke()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,8 @@ internal class PreComposeViewModel :
backDispatcher.onBackPress()
}
}

override fun onCleared() {
lifecycleRegistry.currentState = Lifecycle.State.Destroyed
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package moe.tlaster.precompose

import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier

@Composable
expect fun PreComposeApp(
modifier: Modifier = Modifier,
content: @Composable () -> Unit = {},
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package moe.tlaster.precompose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import moe.tlaster.precompose.lifecycle.LifecycleOwner
import moe.tlaster.precompose.lifecycle.LifecycleRegistry
import moe.tlaster.precompose.lifecycle.LocalLifecycleOwner
import moe.tlaster.precompose.stateholder.LocalStateHolder
import moe.tlaster.precompose.stateholder.StateHolder
import moe.tlaster.precompose.ui.BackDispatcher
import moe.tlaster.precompose.ui.BackDispatcherOwner
import moe.tlaster.precompose.ui.LocalBackDispatcherOwner

@Composable
actual fun PreComposeApp(
modifier: Modifier,
content: @Composable () -> Unit,
) {
val holder = remember {
PreComposeWindowHolder()
}
CompositionLocalProvider(
LocalLifecycleOwner provides holder,
LocalStateHolder provides holder.stateHolder,
LocalBackDispatcherOwner provides holder,
) {
content.invoke()
}
}

class PreComposeWindowHolder : LifecycleOwner, BackDispatcherOwner {
override val lifecycle by lazy {
LifecycleRegistry()
}
val stateHolder by lazy {
StateHolder()
}
override val backDispatcher by lazy {
BackDispatcher()
}
}

0 comments on commit daf7db5

Please sign in to comment.