diff --git a/docs/sample.md b/docs/sample.md index 423f8508..e3c2e65b 100644 --- a/docs/sample.md +++ b/docs/sample.md @@ -18,59 +18,61 @@ This sample demonstrates the following features: ```kotlin @Composable fun App() { - val navigator = rememberNavigator() - MaterialTheme { - NavHost( - navigator = navigator, - initialRoute = "/home" - ) { - scene(route = "/home") { - val homeViewModel = viewModel { - HomeViewModel() - } - val name by homeViewModel.name.observeAsState() - Column( - modifier = Modifier.fillMaxSize(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center - ) { - Text( - text = "Greet Me!", - style = MaterialTheme.typography.h6 - ) - Spacer(modifier = Modifier.height(30.dp)) - TextField( - value = name, - maxLines = 1, - label = { Text(text = "Enter your name") }, - onValueChange = { - homeViewModel.setName(it) - } - ) - Spacer(modifier = Modifier.height(30.dp)) - Button( - onClick = { - navigator.navigate(route = "/greeting/$name") - } - ) { - Text(text = "GO!") + PreComposeApp { + val navigator = rememberNavigator() + MaterialTheme { + NavHost( + navigator = navigator, + initialRoute = "/home" + ) { + scene(route = "/home") { + val homeViewModel = viewModel { + HomeViewModel() } - } - } - scene(route = "/greeting/{name}") { backStackEntry -> - backStackEntry.path("name")?.let { name -> + val name by homeViewModel.name.observeAsState() Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Text( - text = name, + text = "Greet Me!", style = MaterialTheme.typography.h6 ) Spacer(modifier = Modifier.height(30.dp)) - Button(onClick = { navigator.goBack() }) { - Text(text = "GO BACK!") + TextField( + value = name, + maxLines = 1, + label = { Text(text = "Enter your name") }, + onValueChange = { + homeViewModel.setName(it) + } + ) + Spacer(modifier = Modifier.height(30.dp)) + Button( + onClick = { + navigator.navigate(route = "/greeting/$name") + } + ) { + Text(text = "GO!") + } + } + } + scene(route = "/greeting/{name}") { backStackEntry -> + backStackEntry.path("name")?.let { name -> + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Text( + text = name, + style = MaterialTheme.typography.h6 + ) + Spacer(modifier = Modifier.height(30.dp)) + Button(onClick = { navigator.goBack() }) { + Text(text = "GO BACK!") + } } } } @@ -93,57 +95,59 @@ class HomeViewModel : ViewModel() { ```kotlin @Composable fun App() { - val navigator = rememberNavigator() - MaterialTheme { - NavHost( - navigator = navigator, - initialRoute = "/home" - ) { - scene(route = "/home") { - val homeViewModel = viewModel { - HomeViewModel() - } - val name by homeViewModel.name.collectAsStateWithLifecycle() - Column( - modifier = Modifier.fillMaxSize(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center - ) { - Text( - text = "Greet Me!", - style = MaterialTheme.typography.h6 - ) - Spacer(modifier = Modifier.height(30.dp)) - TextField( - value = name, - maxLines = 1, - label = { Text(text = "Enter your name") }, - onValueChange = homeViewModel::setName - ) - Spacer(modifier = Modifier.height(30.dp)) - Button( - onClick = { - navigator.navigate(route = "/greeting/$name") - } - ) { - Text(text = "GO!") + PreComposeApp { + val navigator = rememberNavigator() + MaterialTheme { + NavHost( + navigator = navigator, + initialRoute = "/home" + ) { + scene(route = "/home") { + val homeViewModel = viewModel { + HomeViewModel() } - } - } - scene(route = "/greeting/{name}") { backStackEntry -> - backStackEntry.path("name")?.let { name -> + val name by homeViewModel.name.collectAsStateWithLifecycle() Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { Text( - text = name, + text = "Greet Me!", style = MaterialTheme.typography.h6 ) Spacer(modifier = Modifier.height(30.dp)) - Button(onClick = navigator::goBack) { - Text(text = "GO BACK!") + TextField( + value = name, + maxLines = 1, + label = { Text(text = "Enter your name") }, + onValueChange = homeViewModel::setName + ) + Spacer(modifier = Modifier.height(30.dp)) + Button( + onClick = { + navigator.navigate(route = "/greeting/$name") + } + ) { + Text(text = "GO!") + } + } + } + scene(route = "/greeting/{name}") { backStackEntry -> + backStackEntry.path("name")?.let { name -> + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Text( + text = name, + style = MaterialTheme.typography.h6 + ) + Spacer(modifier = Modifier.height(30.dp)) + Button(onClick = navigator::goBack) { + Text(text = "GO BACK!") + } } } } diff --git a/docs/setup.md b/docs/setup.md index 1a3e4408..1a9e2df0 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -17,20 +17,17 @@ api("moe.tlaster:precompose:$precompose_version") // api("moe.tlaster:precompose-koin:$precompose_version") // For Koin intergration ``` -## Android -Change the `androidx.activity.compose.setContent` to `moe.tlaster.precompose.lifecycle.setContent` -## Desktop (JVM) -Change the `Window` to `moe.tlaster.precompose.PreComposeWindow` +## Wrap the `App()` -## iOS -Set the `UIWindow.rootViewController` to `PreComposeApplication` - -## Native macOS -Change the `Window` to `moe.tlaster.precompose.PreComposeWindow` - -## Web (Canvas) -Change the `Window` to `moe.tlaster.precompose.preComposeWindow` +Wrap your App with `PreComposApp` like this: +```Kotlin +fun App() { + PreComposeApp { + // your apps content gose here + } +} +``` ## Done! That's it! Enjoying the PreCompose! Now you can write all your business logic and ui code in `commonMain` diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 49cd685f..a8e14259 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,16 +1,16 @@ [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.20" kotlinxCoroutinesCore = "1.7.3" -lifecycleRuntimeKtx = "2.6.1" +lifecycleRuntimeKtx = "2.6.2" material = "1.5.0" moleculeRuntime = "1.3.0" savedstateKtx = "1.2.1" @@ -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" } diff --git a/precompose-koin/build.gradle.kts b/precompose-koin/build.gradle.kts index 076e60be..6d3e7b18 100644 --- a/precompose-koin/build.gradle.kts +++ b/precompose-koin/build.gradle.kts @@ -12,7 +12,8 @@ group = "moe.tlaster" version = rootProject.extra.get("precomposeVersion") as String kotlin { - targetHierarchy.default { + + applyDefaultHierarchyTemplate { common { group("jvmAndroid") { withAndroidTarget() diff --git a/precompose-molecule/build.gradle.kts b/precompose-molecule/build.gradle.kts index fd3c1d20..3d27d9df 100644 --- a/precompose-molecule/build.gradle.kts +++ b/precompose-molecule/build.gradle.kts @@ -12,6 +12,7 @@ group = "moe.tlaster" version = rootProject.extra.get("precomposeVersion") as String kotlin { + applyDefaultHierarchyTemplate() androidTarget { publishLibraryVariants("release", "debug") } @@ -82,33 +83,18 @@ kotlin { implementation(kotlin("test-js")) } } - val macosMain by creating { + val macosMain by getting { dependsOn(commonMain) dependencies { implementation(compose.foundation) } } - val macosX64Main by getting { - dependsOn(macosMain) - } - val macosArm64Main by getting { - dependsOn(macosMain) - } - val iosMain by creating { + val iosMain by getting { dependsOn(commonMain) dependencies { implementation(compose.foundation) } } - val iosX64Main by getting { - dependsOn(iosMain) - } - val iosArm64Main by getting { - dependsOn(iosMain) - } - val iosSimulatorArm64Main by getting { - dependsOn(iosMain) - } } } diff --git a/precompose-molecule/src/commonMain/kotlin/moe/tlaster/precompose/molecule/Molecule.kt b/precompose-molecule/src/commonMain/kotlin/moe/tlaster/precompose/molecule/Molecule.kt index 9fb40030..8d80d748 100644 --- a/precompose-molecule/src/commonMain/kotlin/moe/tlaster/precompose/molecule/Molecule.kt +++ b/precompose-molecule/src/commonMain/kotlin/moe/tlaster/precompose/molecule/Molecule.kt @@ -33,7 +33,7 @@ private class PresenterHolder( RecompositionMode.ContextClock } private val scope = CoroutineScope(dispatcher) - val state = scope.launchMolecule(clock, body) + val state = scope.launchMolecule(mode = clock, body = body) override fun close() { scope.cancel() diff --git a/precompose-viewmodel/build.gradle.kts b/precompose-viewmodel/build.gradle.kts index 306a4e96..c334d7cf 100644 --- a/precompose-viewmodel/build.gradle.kts +++ b/precompose-viewmodel/build.gradle.kts @@ -12,7 +12,7 @@ group = "moe.tlaster" version = rootProject.extra.get("precomposeVersion") as String kotlin { - targetHierarchy.default { + applyDefaultHierarchyTemplate { common { group("jvmAndroid") { withAndroidTarget() diff --git a/precompose/build.gradle.kts b/precompose/build.gradle.kts index 8e2a4ca1..e5f706db 100644 --- a/precompose/build.gradle.kts +++ b/precompose/build.gradle.kts @@ -12,7 +12,7 @@ group = "moe.tlaster" version = rootProject.extra.get("precomposeVersion") as String kotlin { - targetHierarchy.default() + applyDefaultHierarchyTemplate() macosArm64() macosX64() iosX64() @@ -61,6 +61,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 { diff --git a/precompose/src/androidMain/kotlin/moe/tlaster/precompose/PreComposeApp.android.kt b/precompose/src/androidMain/kotlin/moe/tlaster/precompose/PreComposeApp.android.kt new file mode 100644 index 00000000..0da33b60 --- /dev/null +++ b/precompose/src/androidMain/kotlin/moe/tlaster/precompose/PreComposeApp.android.kt @@ -0,0 +1,82 @@ +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.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( + content: @Composable () -> Unit, +) { + val viewModel = androidx.lifecycle.viewmodel.compose.viewModel() + + 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() + } +} diff --git a/precompose/src/androidMain/kotlin/moe/tlaster/precompose/lifecycle/PreComposeActivity.kt b/precompose/src/androidMain/kotlin/moe/tlaster/precompose/lifecycle/PreComposeActivity.kt index 5aac16cd..4b894dba 100644 --- a/precompose/src/androidMain/kotlin/moe/tlaster/precompose/lifecycle/PreComposeActivity.kt +++ b/precompose/src/androidMain/kotlin/moe/tlaster/precompose/lifecycle/PreComposeActivity.kt @@ -1,141 +1,37 @@ package moe.tlaster.precompose.lifecycle -import android.view.ViewGroup import androidx.activity.ComponentActivity -import androidx.activity.viewModels +import androidx.activity.compose.setContent 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 - -fun ComponentActivity.setContent( +import moe.tlaster.precompose.PreComposeApp + +@Deprecated( + message = """ + Use ComponentActivity directly instead. And make sure wrap your content with PreComposeApp. + PreComposeActivity will be removed in the future release. + For migration guide, please refer to https://github.com/Tlaster/PreCompose/releases/tag/1.5.5 + """, + replaceWith = ReplaceWith("ComponentActivity"), +) +typealias PreComposeActivity = ComponentActivity + +@Deprecated( + message = """ + Use androidx.activity.compose.setContent directly instead. And make sure wrap your content with PreComposeApp. + PreComposeActivity.setContent will be removed in the future release. + For migration guide, please refer to https://github.com/Tlaster/PreCompose/releases/tag/1.5.5 + """, + replaceWith = ReplaceWith("androidx.activity.compose.setContent"), +) +@Suppress("DEPRECATION") +fun PreComposeActivity.setContent( parent: CompositionContext? = null, content: @Composable () -> Unit, ) { - val existingComposeView = - window.decorView.findViewById(android.R.id.content).getChildAt(0) as? ComposeView - - if (existingComposeView != null) { - with(existingComposeView) { - setParentCompositionContext(parent) - setContent { - ContentInternal(content) - } - } - } else { - ComposeView(this).apply { - // Set content and parent **before** setContentView - // to have ComposeView create the composition on attach - setParentCompositionContext(parent) - setContent { - ContentInternal(content) - } - // Set the view tree owners before setting the content view so that the inflation process - // and attach listeners will see them already present - setOwners() - setContentView(this, DefaultActivityContentLayoutParams) - } - } -} - -private fun ComponentActivity.setOwners() { - val decorView = window.decorView - if (decorView.findViewTreeLifecycleOwner() == null) { - decorView.setViewTreeLifecycleOwner(this) - } - if (decorView.findViewTreeViewModelStoreOwner() == null) { - decorView.setViewTreeViewModelStoreOwner(this) - } - if (decorView.findViewTreeSavedStateRegistryOwner() == null) { - decorView.setViewTreeSavedStateRegistryOwner(this) - } -} - -@Composable -private fun ComponentActivity.ContentInternal(content: @Composable () -> Unit) { - ProvideAndroidCompositionLocals { - content.invoke() - } -} - -@Composable -private fun ComponentActivity.ProvideAndroidCompositionLocals( - content: @Composable () -> Unit, -) { - val viewModel by viewModels() - - 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) + setContent(parent) { + PreComposeApp { + content.invoke() } } - - 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() - } } - -private val DefaultActivityContentLayoutParams = ViewGroup.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT, -) diff --git a/precompose/src/androidMain/kotlin/moe/tlaster/precompose/lifecycle/PreComposeViewModel.kt b/precompose/src/androidMain/kotlin/moe/tlaster/precompose/lifecycle/PreComposeViewModel.kt index 3ec26daa..a09025b4 100644 --- a/precompose/src/androidMain/kotlin/moe/tlaster/precompose/lifecycle/PreComposeViewModel.kt +++ b/precompose/src/androidMain/kotlin/moe/tlaster/precompose/lifecycle/PreComposeViewModel.kt @@ -27,4 +27,8 @@ internal class PreComposeViewModel : backDispatcher.onBackPress() } } + + override fun onCleared() { + lifecycleRegistry.currentState = Lifecycle.State.Destroyed + } } diff --git a/precompose/src/commonMain/kotlin/moe/tlaster/precompose/PreComposeApp.kt b/precompose/src/commonMain/kotlin/moe/tlaster/precompose/PreComposeApp.kt new file mode 100644 index 00000000..0a2a3a1d --- /dev/null +++ b/precompose/src/commonMain/kotlin/moe/tlaster/precompose/PreComposeApp.kt @@ -0,0 +1,8 @@ +package moe.tlaster.precompose + +import androidx.compose.runtime.Composable + +@Composable +expect fun PreComposeApp( + content: @Composable () -> Unit = {}, +) diff --git a/precompose/src/iosMain/kotlin/moe/tlaster/precompose/PreComposeApplication.kt b/precompose/src/iosMain/kotlin/moe/tlaster/precompose/PreComposeApplication.kt index a7b084fe..19de622d 100644 --- a/precompose/src/iosMain/kotlin/moe/tlaster/precompose/PreComposeApplication.kt +++ b/precompose/src/iosMain/kotlin/moe/tlaster/precompose/PreComposeApplication.kt @@ -5,6 +5,10 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.remember import androidx.compose.ui.uikit.ComposeUIViewControllerConfiguration import androidx.compose.ui.window.ComposeUIViewController +import kotlinx.cinterop.BetaInteropApi +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.ObjCAction +import moe.tlaster.precompose.lifecycle.Lifecycle import moe.tlaster.precompose.lifecycle.LifecycleOwner import moe.tlaster.precompose.lifecycle.LifecycleRegistry import moe.tlaster.precompose.lifecycle.LocalLifecycleOwner @@ -13,25 +17,43 @@ import moe.tlaster.precompose.stateholder.StateHolder import moe.tlaster.precompose.ui.BackDispatcher import moe.tlaster.precompose.ui.BackDispatcherOwner import moe.tlaster.precompose.ui.LocalBackDispatcherOwner +import platform.Foundation.NSNotification +import platform.Foundation.NSNotificationCenter +import platform.Foundation.NSSelectorFromString +import platform.UIKit.UIApplicationDidEnterBackgroundNotification +import platform.UIKit.UIApplicationWillEnterForegroundNotification +import platform.UIKit.UIApplicationWillTerminateNotification import platform.UIKit.UIViewController @Suppress("FunctionName") +@Deprecated( + message = """ + Use ComposeUIViewController directly instead. And make sure wrap your content with PreComposeApp. + PreComposeApplication will be removed in the future release. + For migration guide, please refer to https://github.com/Tlaster/PreCompose/releases/tag/1.5.5 + """, + replaceWith = ReplaceWith("ComposeUIViewController"), +) fun PreComposeApplication( configure: ComposeUIViewControllerConfiguration.() -> Unit = {}, content: @Composable () -> Unit, ): UIViewController { return ComposeUIViewController(configure) { - val holder = remember { - PreComposeWindowHolder() - } - ProvidePreComposeCompositionLocals( - holder, - ) { + PreComposeApp { content.invoke() } } } +@Composable +actual fun PreComposeApp( + content: @Composable () -> Unit, +) { + ProvidePreComposeCompositionLocals { + content.invoke() + } +} + @Composable fun ProvidePreComposeCompositionLocals( holder: PreComposeWindowHolder = remember { @@ -48,6 +70,7 @@ fun ProvidePreComposeCompositionLocals( } } +@OptIn(ExperimentalForeignApi::class) class PreComposeWindowHolder : LifecycleOwner, BackDispatcherOwner { override val lifecycle by lazy { LifecycleRegistry() @@ -58,4 +81,42 @@ class PreComposeWindowHolder : LifecycleOwner, BackDispatcherOwner { override val backDispatcher by lazy { BackDispatcher() } + init { + NSNotificationCenter.defaultCenter().addObserver( + this, + selector = NSSelectorFromString("appMovedToForeground:"), + name = UIApplicationWillEnterForegroundNotification, + `object` = null, + ) + NSNotificationCenter.defaultCenter().addObserver( + this, + selector = NSSelectorFromString("appMovedToBackground:"), + name = UIApplicationDidEnterBackgroundNotification, + `object` = null, + ) + NSNotificationCenter.defaultCenter().addObserver( + this, + selector = NSSelectorFromString("appWillTerminate:"), + name = UIApplicationWillTerminateNotification, + `object` = null, + ) + } + + @OptIn(BetaInteropApi::class) + @ObjCAction + fun appMovedToForeground(notification: NSNotification) { + lifecycle.currentState = Lifecycle.State.Active + } + + @OptIn(BetaInteropApi::class) + @ObjCAction + fun appMovedToBackground(notification: NSNotification) { + lifecycle.currentState = Lifecycle.State.InActive + } + + @OptIn(BetaInteropApi::class) + @ObjCAction + fun appWillTerminate(notification: NSNotification) { + lifecycle.currentState = Lifecycle.State.Destroyed + } } diff --git a/precompose/src/jsMain/kotlin/moe/tlaster/precompose/PreComposeWindow.kt b/precompose/src/jsMain/kotlin/moe/tlaster/precompose/PreComposeWindow.kt index 8b3fff1b..48c65170 100644 --- a/precompose/src/jsMain/kotlin/moe/tlaster/precompose/PreComposeWindow.kt +++ b/precompose/src/jsMain/kotlin/moe/tlaster/precompose/PreComposeWindow.kt @@ -32,16 +32,22 @@ fun preComposeWindow( requestResize = requestResize, applyDefaultStyles = applyDefaultStyles, content = { - val holder = remember { - PreComposeWindowHolder() - } - ProvidePreComposeCompositionLocals(holder) { - content() + PreComposeApp { + content.invoke() } }, ) } +@Composable +actual fun PreComposeApp( + content: @Composable () -> Unit, +) { + ProvidePreComposeCompositionLocals { + content.invoke() + } +} + @Composable fun ProvidePreComposeCompositionLocals( holder: PreComposeWindowHolder = remember { diff --git a/precompose/src/jvmMain/kotlin/moe/tlaster/precompose/PreComposeWindow.kt b/precompose/src/jvmMain/kotlin/moe/tlaster/precompose/PreComposeWindow.kt index e6247366..167d0ec4 100644 --- a/precompose/src/jvmMain/kotlin/moe/tlaster/precompose/PreComposeWindow.kt +++ b/precompose/src/jvmMain/kotlin/moe/tlaster/precompose/PreComposeWindow.kt @@ -2,16 +2,14 @@ package moe.tlaster.precompose import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.remember -import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.input.key.KeyEvent import androidx.compose.ui.window.FrameWindowScope import androidx.compose.ui.window.Window import androidx.compose.ui.window.WindowState import androidx.compose.ui.window.rememberWindowState -import kotlinx.coroutines.flow.distinctUntilChanged import moe.tlaster.precompose.lifecycle.Lifecycle import moe.tlaster.precompose.lifecycle.LifecycleOwner import moe.tlaster.precompose.lifecycle.LifecycleRegistry @@ -21,7 +19,17 @@ import moe.tlaster.precompose.stateholder.StateHolder import moe.tlaster.precompose.ui.BackDispatcher import moe.tlaster.precompose.ui.BackDispatcherOwner import moe.tlaster.precompose.ui.LocalBackDispatcherOwner +import java.awt.event.WindowAdapter +import java.awt.event.WindowEvent +@Deprecated( + message = """ + Use Window directly instead. And make sure wrap your content with PreComposeApp. + PreComposeWindow will be removed in the future release. + For migration guide, please refer to https://github.com/Tlaster/PreCompose/releases/tag/1.5.5 + """, + replaceWith = ReplaceWith("PreComposeWindow"), +) @Composable fun PreComposeWindow( onCloseRequest: () -> Unit, @@ -39,54 +47,64 @@ fun PreComposeWindow( onKeyEvent: (KeyEvent) -> Boolean = { false }, content: @Composable FrameWindowScope.() -> Unit, ) { - val holder = remember { - PreComposeWindowHolder() - } - LaunchedEffect(Unit) { - snapshotFlow { state.isMinimized } - .distinctUntilChanged() - .collect { - holder.lifecycle.currentState = if (it) { - Lifecycle.State.InActive - } else { - Lifecycle.State.Active - } - } - } - ProvidePreComposeCompositionLocals( - holder, - ) { - Window( - onCloseRequest = { - holder.lifecycle.currentState = Lifecycle.State.Destroyed - onCloseRequest.invoke() - }, - state = state, - visible = visible, - title = title, - icon = icon, - undecorated = undecorated, - transparent = transparent, - resizable = resizable, - enabled = enabled, - focusable = focusable, - alwaysOnTop = alwaysOnTop, - onPreviewKeyEvent = onPreviewKeyEvent, - onKeyEvent = onKeyEvent, - content = { + Window( + onCloseRequest = onCloseRequest, + state = state, + visible = visible, + title = title, + icon = icon, + undecorated = undecorated, + transparent = transparent, + resizable = resizable, + enabled = enabled, + focusable = focusable, + alwaysOnTop = alwaysOnTop, + onPreviewKeyEvent = onPreviewKeyEvent, + onKeyEvent = onKeyEvent, + content = { + PreComposeApp { content.invoke(this) - }, - ) - } + } + }, + ) } +@Suppress("INVISIBLE_MEMBER") @Composable -fun ProvidePreComposeCompositionLocals( - holder: PreComposeWindowHolder = remember { - PreComposeWindowHolder() - }, +actual fun PreComposeApp( content: @Composable () -> Unit, ) { + val holder = remember { + PreComposeWindowHolder() + } + val window = androidx.compose.ui.window.LocalWindow.current + if (window != null) { + val listener = remember { + object : WindowAdapter() { + override fun windowClosing(e: WindowEvent?) { + holder.lifecycle.currentState = Lifecycle.State.Destroyed + } + override fun windowStateChanged(e: WindowEvent?) { + when (e?.newState) { + java.awt.Frame.ICONIFIED -> { + holder.lifecycle.currentState = Lifecycle.State.InActive + } + else -> { + holder.lifecycle.currentState = Lifecycle.State.Active + } + } + } + } + } + DisposableEffect(window) { + window.addWindowListener(listener) + window.addWindowStateListener(listener) + onDispose { + window.removeWindowListener(listener) + window.removeWindowStateListener(listener) + } + } + } CompositionLocalProvider( LocalLifecycleOwner provides holder, LocalStateHolder provides holder.stateHolder, diff --git a/precompose/src/macosMain/kotlin/moe/tlaster/precompose/ComposeWindow.kt b/precompose/src/macosMain/kotlin/moe/tlaster/precompose/ComposeWindow.kt index 4d31c649..fd726b34 100644 --- a/precompose/src/macosMain/kotlin/moe/tlaster/precompose/ComposeWindow.kt +++ b/precompose/src/macosMain/kotlin/moe/tlaster/precompose/ComposeWindow.kt @@ -48,12 +48,13 @@ internal class ComposeWindow( hideTitleBar: Boolean = false, initialTitle: String, private val onCloseRequest: () -> Unit = {}, + private val onMinimizeRequest: () -> Unit = {}, + private val onDeminiaturizeRequest: () -> Unit = {}, ) : NSObject(), NSWindowDelegateProtocol { private val density by lazy { Density( density = nsWindow.backingScaleFactor.toFloat(), - fontScale = 1f, ) } private val macosTextInputService = MacosTextInputService() @@ -184,6 +185,18 @@ internal class ComposeWindow( onCloseRequest.invoke() } + @OptIn(BetaInteropApi::class) + @ObjCAction + override fun windowWillMiniaturize(notification: NSNotification) { + onMinimizeRequest.invoke() + } + + @OptIn(BetaInteropApi::class) + @ObjCAction + override fun windowDidDeminiaturize(notification: NSNotification) { + onDeminiaturizeRequest.invoke() + } + private fun updateLayerSize() { val (w, h) = nsWindow.contentView!!.frame.useContents { size.width to size.height diff --git a/precompose/src/macosMain/kotlin/moe/tlaster/precompose/PreComposeWindow.kt b/precompose/src/macosMain/kotlin/moe/tlaster/precompose/PreComposeWindow.kt index 0e103033..60293b65 100644 --- a/precompose/src/macosMain/kotlin/moe/tlaster/precompose/PreComposeWindow.kt +++ b/precompose/src/macosMain/kotlin/moe/tlaster/precompose/PreComposeWindow.kt @@ -2,6 +2,7 @@ package moe.tlaster.precompose import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.ExperimentalComposeApi import androidx.compose.runtime.remember import moe.tlaster.precompose.lifecycle.LifecycleOwner import moe.tlaster.precompose.lifecycle.LifecycleRegistry @@ -12,10 +13,13 @@ import moe.tlaster.precompose.ui.BackDispatcher import moe.tlaster.precompose.ui.BackDispatcherOwner import moe.tlaster.precompose.ui.LocalBackDispatcherOwner +@ExperimentalComposeApi fun PreComposeWindow( title: String, hideTitleBar: Boolean = false, onCloseRequest: () -> Unit = {}, + onMinimizeRequest: () -> Unit = {}, + onDeminiaturizeRequest: () -> Unit = {}, content: @Composable () -> Unit, ) { // Ugly workaround until Native macOS support window resize and hide title bar. @@ -23,20 +27,26 @@ fun PreComposeWindow( hideTitleBar = hideTitleBar, initialTitle = title, onCloseRequest = onCloseRequest, + onMinimizeRequest = onMinimizeRequest, + onDeminiaturizeRequest = onDeminiaturizeRequest, ).apply { setContent { - val holder = remember { - PreComposeWindowHolder() - } - ProvidePreComposeCompositionLocals( - holder, - ) { + PreComposeApp { content.invoke() } } } } +@Composable +actual fun PreComposeApp( + content: @Composable () -> Unit, +) { + ProvidePreComposeCompositionLocals { + content.invoke() + } +} + @Composable fun ProvidePreComposeCompositionLocals( holder: PreComposeWindowHolder = remember { diff --git a/sample/molecule/build.gradle.kts b/sample/molecule/build.gradle.kts index 10842435..dc75a264 100644 --- a/sample/molecule/build.gradle.kts +++ b/sample/molecule/build.gradle.kts @@ -64,11 +64,11 @@ kotlin { implementation(compose.desktop.currentOs) } } - // val androidMain by getting { - // dependencies { - // implementation("androidx.activity:activity-ktx:${Versions.AndroidX.activity}") - // } - // } + val androidMain by getting { + dependencies { + implementation(libs.androidx.activity.compose) + } + } val darwinMain by creating { dependsOn(commonMain) dependencies { @@ -136,19 +136,19 @@ compose { } } } - experimental { - uikit { - application { - bundleIdPrefix = "moe.tlaster.precompose.sample.molecule" - projectName = "PreComposeMoleculeSample" - deployConfigurations { - simulator("Simulator") { - device = org.jetbrains.compose.experimental.dsl.IOSDevices.IPHONE_13_MINI - } - } - } - } - } + // experimental { + // uikit { + // application { + // bundleIdPrefix = "moe.tlaster.precompose.sample.molecule" + // projectName = "PreComposeMoleculeSample" + // deployConfigurations { + // simulator("Simulator") { + // device = org.jetbrains.compose.experimental.dsl.IOSDevices.IPHONE_13_MINI + // } + // } + // } + // } + // } } android { diff --git a/sample/molecule/src/androidMain/kotlin/moe/tlaster/precompose/molecule/sample/MainActivity.kt b/sample/molecule/src/androidMain/kotlin/moe/tlaster/precompose/molecule/sample/MainActivity.kt index a7efc03b..7d329a83 100644 --- a/sample/molecule/src/androidMain/kotlin/moe/tlaster/precompose/molecule/sample/MainActivity.kt +++ b/sample/molecule/src/androidMain/kotlin/moe/tlaster/precompose/molecule/sample/MainActivity.kt @@ -1,8 +1,8 @@ package moe.tlaster.precompose.molecule.sample import android.os.Bundle +import androidx.activity.compose.setContent import androidx.fragment.app.FragmentActivity -import moe.tlaster.precompose.lifecycle.setContent class MainActivity : FragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { diff --git a/sample/molecule/src/jvmMain/kotlin/moe/tlaster/precompose/molecule/sample/Main.kt b/sample/molecule/src/jvmMain/kotlin/moe/tlaster/precompose/molecule/sample/Main.kt index 5f3ee7dc..64b11fdf 100644 --- a/sample/molecule/src/jvmMain/kotlin/moe/tlaster/precompose/molecule/sample/Main.kt +++ b/sample/molecule/src/jvmMain/kotlin/moe/tlaster/precompose/molecule/sample/Main.kt @@ -1,11 +1,11 @@ package moe.tlaster.precompose.molecule.sample +import androidx.compose.ui.window.Window import androidx.compose.ui.window.application -import moe.tlaster.precompose.PreComposeWindow fun main() { application { - PreComposeWindow( + Window( title = "PreCompose Molecule Sample", onCloseRequest = ::exitApplication, ) { diff --git a/sample/molecule/src/macosMain/kotlin/moe/tlaster/precompose/molecule/sample/Main.kt b/sample/molecule/src/macosMain/kotlin/moe/tlaster/precompose/molecule/sample/Main.kt index 4a794dc1..7853b675 100644 --- a/sample/molecule/src/macosMain/kotlin/moe/tlaster/precompose/molecule/sample/Main.kt +++ b/sample/molecule/src/macosMain/kotlin/moe/tlaster/precompose/molecule/sample/Main.kt @@ -1,10 +1,10 @@ package moe.tlaster.precompose.molecule.sample -import moe.tlaster.precompose.PreComposeWindow +import androidx.compose.ui.window.Window import platform.AppKit.NSApp fun main() { - PreComposeWindow( + Window( "PreCompose Molecule Sample", ) { App() diff --git a/sample/molecule/src/uikitMain/kotlin/moe/tlaster/precompose/molecule/sample/Main.kt b/sample/molecule/src/uikitMain/kotlin/moe/tlaster/precompose/molecule/sample/Main.kt index 3e07237e..25ddb38f 100644 --- a/sample/molecule/src/uikitMain/kotlin/moe/tlaster/precompose/molecule/sample/Main.kt +++ b/sample/molecule/src/uikitMain/kotlin/moe/tlaster/precompose/molecule/sample/Main.kt @@ -1,12 +1,12 @@ package moe.tlaster.precompose.molecule.sample +import androidx.compose.ui.window.ComposeUIViewController import kotlinx.cinterop.BetaInteropApi import kotlinx.cinterop.ExperimentalForeignApi import kotlinx.cinterop.autoreleasepool import kotlinx.cinterop.cstr import kotlinx.cinterop.memScoped import kotlinx.cinterop.toCValues -import moe.tlaster.precompose.PreComposeApplication import platform.Foundation.NSStringFromClass import platform.UIKit.UIApplication import platform.UIKit.UIApplicationDelegateProtocol @@ -39,7 +39,7 @@ class SkikoAppDelegate : UIResponder, UIApplicationDelegateProtocol { @OptIn(ExperimentalForeignApi::class) override fun application(application: UIApplication, didFinishLaunchingWithOptions: Map?): Boolean { window = UIWindow(frame = UIScreen.mainScreen.bounds).apply { - rootViewController = PreComposeApplication { + rootViewController = ComposeUIViewController { App() } makeKeyAndVisible() diff --git a/sample/todo/android/build.gradle.kts b/sample/todo/android/build.gradle.kts index 45530008..e42d5d8c 100644 --- a/sample/todo/android/build.gradle.kts +++ b/sample/todo/android/build.gradle.kts @@ -9,6 +9,7 @@ version = "1.0" dependencies { implementation(project(":sample:todo:common")) + implementation(libs.androidx.activity.compose) } android { diff --git a/sample/todo/android/src/main/java/moe/tlaster/android/MainActivity.kt b/sample/todo/android/src/main/java/moe/tlaster/android/MainActivity.kt index ad70907c..8b20a231 100644 --- a/sample/todo/android/src/main/java/moe/tlaster/android/MainActivity.kt +++ b/sample/todo/android/src/main/java/moe/tlaster/android/MainActivity.kt @@ -2,8 +2,8 @@ package moe.tlaster.android import android.os.Bundle import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent import moe.tlaster.common.App -import moe.tlaster.precompose.lifecycle.setContent class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { diff --git a/sample/todo/common/src/commonMain/kotlin/moe/tlaster/common/App.kt b/sample/todo/common/src/commonMain/kotlin/moe/tlaster/common/App.kt index 456123e5..53518229 100644 --- a/sample/todo/common/src/commonMain/kotlin/moe/tlaster/common/App.kt +++ b/sample/todo/common/src/commonMain/kotlin/moe/tlaster/common/App.kt @@ -14,6 +14,7 @@ import moe.tlaster.common.scene.NoteListScene import moe.tlaster.common.viewmodel.NoteDetailViewModel import moe.tlaster.common.viewmodel.NoteEditViewModel import moe.tlaster.common.viewmodel.NoteListViewModel +import moe.tlaster.precompose.PreComposeApp import moe.tlaster.precompose.navigation.NavHost import moe.tlaster.precompose.navigation.path import moe.tlaster.precompose.navigation.rememberNavigator @@ -25,54 +26,77 @@ import org.koin.dsl.module @OptIn(ExperimentalMaterialApi::class) @Composable fun App() { - KoinApplication( - application = { - modules( - module { - single { FakeRepository() } - factory { (id: Int) -> - NoteDetailViewModel( - id = id, - fakeRepository = get(), + PreComposeApp { + KoinApplication( + application = { + modules( + module { + single { FakeRepository() } + factory { (id: Int) -> + NoteDetailViewModel( + id = id, + fakeRepository = get(), + ) + } + factory { (id: Int?, savedStateHolder: SavedStateHolder) -> + NoteEditViewModel( + id = id, + savedStateHolder = savedStateHolder, + fakeRepository = get(), + ) + } + factory { NoteListViewModel(fakeRepository = get()) } + }, + ) + }, + ) { + val navigator = rememberNavigator() + MaterialTheme { + NavHost( + navigator = navigator, + initialRoute = "/home", + ) { + scene("/home") { + NoteListScene( + onItemClicked = { + navigator.navigate("/detail/${it.id}") + }, + onAddClicked = { + navigator.navigate("/edit") + }, + onEditClicked = { + navigator.navigate("/edit/${it.id}") + }, ) } - factory { (id: Int?, savedStateHolder: SavedStateHolder) -> - NoteEditViewModel( - id = id, - savedStateHolder = savedStateHolder, - fakeRepository = get(), - ) + scene("/detail/{id:[0-9]+}") { backStackEntry -> + backStackEntry.path("id")?.let { + NoteDetailScene( + id = it, + onEdit = { + navigator.navigate("/edit/$it") + }, + onBack = { + navigator.goBack() + }, + ) + } } - factory { NoteListViewModel(fakeRepository = get()) } - }, - ) - }, - ) { - val navigator = rememberNavigator() - MaterialTheme { - NavHost( - navigator = navigator, - initialRoute = "/home", - ) { - scene("/home") { - NoteListScene( - onItemClicked = { - navigator.navigate("/detail/${it.id}") - }, - onAddClicked = { - navigator.navigate("/edit") - }, - onEditClicked = { - navigator.navigate("/edit/${it.id}") - }, - ) - } - scene("/detail/{id:[0-9]+}") { backStackEntry -> - backStackEntry.path("id")?.let { - NoteDetailScene( - id = it, - onEdit = { - navigator.navigate("/edit/$it") + scene( + "/edit/{id:[0-9]+}?", + navTransition = NavTransition( + createTransition = slideInVertically(initialOffsetY = { it }), + destroyTransition = slideOutVertically(targetOffsetY = { it }), + pauseTransition = scaleOut(targetScale = 0.9f), + resumeTransition = scaleIn(initialScale = 0.9f), + exitTargetContentZIndex = 1f, + ), + ) { backStackEntry -> + val id = backStackEntry.path("id") + NoteEditScene( + id = id, + onDone = { + navigator.goBack() }, onBack = { navigator.goBack() @@ -80,27 +104,6 @@ fun App() { ) } } - scene( - "/edit/{id:[0-9]+}?", - navTransition = NavTransition( - createTransition = slideInVertically(initialOffsetY = { it }), - destroyTransition = slideOutVertically(targetOffsetY = { it }), - pauseTransition = scaleOut(targetScale = 0.9f), - resumeTransition = scaleIn(initialScale = 0.9f), - exitTargetContentZIndex = 1f, - ), - ) { backStackEntry -> - val id = backStackEntry.path("id") - NoteEditScene( - id = id, - onDone = { - navigator.goBack() - }, - onBack = { - navigator.goBack() - }, - ) - } } } } diff --git a/sample/todo/desktop/src/jvmMain/kotlin/Main.kt b/sample/todo/desktop/src/jvmMain/kotlin/Main.kt index 6dcefce9..e6e23109 100644 --- a/sample/todo/desktop/src/jvmMain/kotlin/Main.kt +++ b/sample/todo/desktop/src/jvmMain/kotlin/Main.kt @@ -1,13 +1,11 @@ -import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.ui.window.Window import androidx.compose.ui.window.application import moe.tlaster.common.App -import moe.tlaster.precompose.PreComposeWindow -@OptIn(ExperimentalMaterialApi::class) fun main() { application { - PreComposeWindow( + Window( title = "PreCompose Sample", onCloseRequest = { exitApplication() diff --git a/sample/todo/ios/build.gradle.kts b/sample/todo/ios/build.gradle.kts index ebf268a4..671be7b1 100644 --- a/sample/todo/ios/build.gradle.kts +++ b/sample/todo/ios/build.gradle.kts @@ -1,4 +1,4 @@ -import org.jetbrains.compose.compose + import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget import org.jetbrains.kotlin.gradle.tasks.KotlinCompile @@ -38,17 +38,17 @@ kotlin { } } -compose.experimental { - uikit.application { - bundleIdPrefix = "moe.tlaster" - projectName = "PreComposeSample" - deployConfigurations { - simulator("Simulator") { - device = org.jetbrains.compose.experimental.dsl.IOSDevices.IPHONE_13_MINI - } - } - } -} +// compose.experimental { +// uikit.application { +// bundleIdPrefix = "moe.tlaster" +// projectName = "PreComposeSample" +// deployConfigurations { +// simulator("Simulator") { +// device = org.jetbrains.compose.experimental.dsl.IOSDevices.IPHONE_13_MINI +// } +// } +// } +// } tasks.withType { kotlinOptions.jvmTarget = rootProject.extra.get("jvmTarget") as String diff --git a/sample/todo/ios/src/uikitMain/kotlin/Main.uikit.kt b/sample/todo/ios/src/uikitMain/kotlin/Main.uikit.kt index 303618ee..afa4a9b6 100644 --- a/sample/todo/ios/src/uikitMain/kotlin/Main.uikit.kt +++ b/sample/todo/ios/src/uikitMain/kotlin/Main.uikit.kt @@ -1,3 +1,4 @@ + import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -6,6 +7,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.material.MaterialTheme import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.ComposeUIViewController import kotlinx.cinterop.BetaInteropApi import kotlinx.cinterop.ExperimentalForeignApi import kotlinx.cinterop.autoreleasepool @@ -13,7 +15,6 @@ import kotlinx.cinterop.cstr import kotlinx.cinterop.memScoped import kotlinx.cinterop.toCValues import moe.tlaster.common.App -import moe.tlaster.precompose.PreComposeApplication import platform.Foundation.NSStringFromClass import platform.UIKit.UIApplication import platform.UIKit.UIApplicationDelegateProtocol @@ -52,7 +53,7 @@ class SkikoAppDelegate : UIResponder, UIApplicationDelegateProtocol { @OptIn(ExperimentalForeignApi::class) override fun application(application: UIApplication, didFinishLaunchingWithOptions: Map?): Boolean { window = UIWindow(frame = UIScreen.mainScreen.bounds).apply { - rootViewController = PreComposeApplication { + rootViewController = ComposeUIViewController { Column { Spacer( modifier = Modifier diff --git a/sample/todo/js/src/jsMain/kotlin/Main.kt b/sample/todo/js/src/jsMain/kotlin/Main.kt index fa276745..96d4ee20 100644 --- a/sample/todo/js/src/jsMain/kotlin/Main.kt +++ b/sample/todo/js/src/jsMain/kotlin/Main.kt @@ -1,11 +1,13 @@ +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.window.CanvasBasedWindow import moe.tlaster.common.App -import moe.tlaster.precompose.preComposeWindow import org.jetbrains.skiko.wasm.onWasmReady +@OptIn(ExperimentalComposeUiApi::class) fun main() { onWasmReady { - preComposeWindow( + CanvasBasedWindow( title = "Sample", ) { App()