diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b9166cc0e..a4312f084 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,7 +28,7 @@ jobs: arguments: build -Dsplit_targets macos-build: name: Build on macOS - runs-on: macos-11 + runs-on: macos-latest steps: - name: Checkout uses: actions/checkout@v3 diff --git a/decompose/build.gradle.kts b/decompose/build.gradle.kts index 9b3838c50..5b92f687f 100644 --- a/decompose/build.gradle.kts +++ b/decompose/build.gradle.kts @@ -27,18 +27,18 @@ kotlin { setupSourceSets { val android by bundle() val nonAndroid by bundle() - val native by bundle() val nonNative by bundle() val darwin by bundle() + val itvos by bundle() val js by bundle() val nonJs by bundle() - (nonAndroid + native + nonNative + nonJs) dependsOn common + (nonAndroid + darwin + nonNative + nonJs) dependsOn common (allSet - android) dependsOn nonAndroid (allSet - nativeSet) dependsOn nonNative (allSet - js) dependsOn nonJs - (nativeSet + darwin) dependsOn native - darwinSet dependsOn darwin + (iosSet + tvosSet) dependsOn itvos + (darwinSet - iosSet - tvosSet + itvos) dependsOn darwin all { languageSettings { diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Relay.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Relay.kt index ec0f41fe7..ffd3e5404 100644 --- a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Relay.kt +++ b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Relay.kt @@ -6,10 +6,6 @@ internal class Relay( private val isMainThreadCheckEnabled: Boolean = false, ) { - init { - ensureNeverFrozen() - } - private val lock = Lock() private val queue = ArrayDeque() private var isDraining = false diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Utils.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Utils.kt index cec8ed846..c63206ebd 100644 --- a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Utils.kt +++ b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/Utils.kt @@ -9,6 +9,4 @@ fun Any.hashString(): String = internal expect val KClass<*>.uniqueName: String? -internal expect fun Any.ensureNeverFrozen() - internal val Lifecycle.isDestroyed: Boolean get() = state == Lifecycle.State.DESTROYED diff --git a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/value/MutableValueBuilder.kt b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/value/MutableValueBuilder.kt index 7e2f0dad5..622db28b5 100644 --- a/decompose/src/commonMain/kotlin/com/arkivanov/decompose/value/MutableValueBuilder.kt +++ b/decompose/src/commonMain/kotlin/com/arkivanov/decompose/value/MutableValueBuilder.kt @@ -1,7 +1,6 @@ package com.arkivanov.decompose.value import com.arkivanov.decompose.Lock -import com.arkivanov.decompose.ensureNeverFrozen import com.arkivanov.decompose.synchronized /** @@ -12,10 +11,6 @@ fun MutableValue(initialValue: T): MutableValue = MutableValueImpl( private class MutableValueImpl(initialValue: T) : MutableValue() { - init { - ensureNeverFrozen() - } - private val lock = Lock() private var _value: T = initialValue private var isEmitting = false diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/backhandler/TestBackDispatcher.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/backhandler/TestBackDispatcher.kt index 1133cd042..1587dc9fb 100644 --- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/backhandler/TestBackDispatcher.kt +++ b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/backhandler/TestBackDispatcher.kt @@ -1,15 +1,10 @@ package com.arkivanov.decompose.backhandler -import com.arkivanov.decompose.ensureNeverFrozen import com.arkivanov.essenty.backhandler.BackCallback import com.arkivanov.essenty.backhandler.BackDispatcher internal class TestBackDispatcher : BackDispatcher { - init { - ensureNeverFrozen() - } - private var set = emptySet() val size: Int get() = set.size diff --git a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/backhandler/TestChildBackHandler.kt b/decompose/src/commonTest/kotlin/com/arkivanov/decompose/backhandler/TestChildBackHandler.kt deleted file mode 100644 index 3015bc12e..000000000 --- a/decompose/src/commonTest/kotlin/com/arkivanov/decompose/backhandler/TestChildBackHandler.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.arkivanov.decompose.backhandler - -import com.arkivanov.decompose.ensureNeverFrozen -import com.arkivanov.essenty.backhandler.BackCallback - -class TestChildBackHandler( - var isStarted: Boolean = false, - override var isEnabled: Boolean = false, -) : ChildBackHandler { - - init { - ensureNeverFrozen() - } - - override fun start() { - check(!isStarted) - isStarted = true - } - - override fun stop() { - check(isStarted) - isStarted = false - } - - override fun register(callback: BackCallback) { - TODO("Not yet implemented") - } - - override fun unregister(callback: BackCallback) { - TODO("Not yet implemented") - } -} diff --git a/decompose/src/itvosMain/kotlin/com/arkivanov/decompose/lifecycle/ApplicationLifecycle.kt b/decompose/src/itvosMain/kotlin/com/arkivanov/decompose/lifecycle/ApplicationLifecycle.kt new file mode 100644 index 000000000..0217e3c57 --- /dev/null +++ b/decompose/src/itvosMain/kotlin/com/arkivanov/decompose/lifecycle/ApplicationLifecycle.kt @@ -0,0 +1,84 @@ +package com.arkivanov.decompose.lifecycle + +import com.arkivanov.decompose.ExperimentalDecomposeApi +import com.arkivanov.essenty.lifecycle.Lifecycle +import com.arkivanov.essenty.lifecycle.LifecycleRegistry +import com.arkivanov.essenty.lifecycle.destroy +import com.arkivanov.essenty.lifecycle.pause +import com.arkivanov.essenty.lifecycle.resume +import com.arkivanov.essenty.lifecycle.start +import com.arkivanov.essenty.lifecycle.stop +import kotlinx.cinterop.BetaInteropApi +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.ObjCAction +import platform.Foundation.NSNotificationCenter +import platform.Foundation.NSNotificationName +import platform.Foundation.NSSelectorFromString +import platform.UIKit.UIApplicationDidBecomeActiveNotification +import platform.UIKit.UIApplicationDidEnterBackgroundNotification +import platform.UIKit.UIApplicationWillEnterForegroundNotification +import platform.UIKit.UIApplicationWillResignActiveNotification +import platform.UIKit.UIApplicationWillTerminateNotification + +/** + * An implementation of [Lifecycle] that follows the [UIApplication][platform.UIKit.UIApplication] lifecycle notifications. + */ +@ExperimentalDecomposeApi +class ApplicationLifecycle private constructor( + private val lifecycle: LifecycleRegistry, +) : Lifecycle by lifecycle { + + constructor() : this(lifecycle = LifecycleRegistry()) + + init { + addObserver(name = UIApplicationWillEnterForegroundNotification, selectorName = "willEnterForeground") + addObserver(name = UIApplicationDidBecomeActiveNotification, selectorName = "didBecomeActive") + addObserver(name = UIApplicationWillResignActiveNotification, selectorName = "willResignActive") + addObserver(name = UIApplicationDidEnterBackgroundNotification, selectorName = "didEnterBackground") + addObserver(name = UIApplicationWillTerminateNotification, selectorName = "willTerminate") + } + + @OptIn(ExperimentalForeignApi::class) + private fun addObserver(name: NSNotificationName, selectorName: String) { + NSNotificationCenter.defaultCenter.addObserver( + name = name, + `object` = null, + observer = this, + selector = NSSelectorFromString(selectorName), + ) + } + + @Suppress("unused") + @OptIn(BetaInteropApi::class) + @ObjCAction + fun willEnterForeground() { + lifecycle.start() + } + + @Suppress("unused") + @OptIn(BetaInteropApi::class) + @ObjCAction + fun didBecomeActive() { + lifecycle.resume() + } + + @Suppress("unused") + @OptIn(BetaInteropApi::class) + @ObjCAction + fun willResignActive() { + lifecycle.pause() + } + + @Suppress("unused") + @OptIn(BetaInteropApi::class) + @ObjCAction + fun didEnterBackground() { + lifecycle.stop() + } + + @OptIn(BetaInteropApi::class) + @ObjCAction + fun willTerminate() { + lifecycle.destroy() + } +} diff --git a/decompose/src/nativeMain/kotlin/com/arkivanov/decompose/Utils.kt b/decompose/src/nativeMain/kotlin/com/arkivanov/decompose/Utils.kt deleted file mode 100644 index e413ee3d2..000000000 --- a/decompose/src/nativeMain/kotlin/com/arkivanov/decompose/Utils.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.arkivanov.decompose - -import kotlin.native.concurrent.ensureNeverFrozen as ensureNeverFrozenNative - -internal actual fun Any.ensureNeverFrozen() { - ensureNeverFrozenNative() -} diff --git a/decompose/src/nonNativeMain/kotlin/com/arkivanov/decompose/Utils.kt b/decompose/src/nonNativeMain/kotlin/com/arkivanov/decompose/Utils.kt deleted file mode 100644 index b06b4b90b..000000000 --- a/decompose/src/nonNativeMain/kotlin/com/arkivanov/decompose/Utils.kt +++ /dev/null @@ -1,9 +0,0 @@ -@file:JvmName("UtilsJvm") - -package com.arkivanov.decompose - -import kotlin.jvm.JvmName - -internal actual fun Any.ensureNeverFrozen() { - // no-op -} diff --git a/deps.versions.toml b/deps.versions.toml index 843de56b3..a9e3e7c96 100644 --- a/deps.versions.toml +++ b/deps.versions.toml @@ -1,18 +1,18 @@ [versions] decompose = "2.2.0-compose-experimental-alpha04" -kotlin = "1.9.10" -essenty = "1.3.0-alpha03" -parcelizeDarwin = "0.2.2" +kotlin = "1.9.20" +essenty = "1.3.0-alpha04" +parcelizeDarwin = "0.2.3" reaktive = "1.2.3" junit = "4.13.2" -jetbrainsCompose = "1.5.1" +jetbrainsCompose = "1.5.10" jetbrainsKotlinWrappers = "1.0.0-pre.608" jetbrainsKotlinxCoroutines = "1.6.4" jetbrainsKotlinxSerialization = "1.6.0" jetbrainsBinaryCompatibilityValidator = "0.13.2" jetpackCompose = "1.5.0" -jetpackComposeCompiler = "1.5.3" +jetpackComposeCompiler = "1.5.4" androidGradle = "8.0.2" androidMaterial = "1.6.1" androidPlay = "1.10.3" diff --git a/extensions-compose-jetbrains/api/android/extensions-compose-jetbrains.api b/extensions-compose-jetbrains/api/android/extensions-compose-jetbrains.api index dee65b61c..26ca4566c 100644 --- a/extensions-compose-jetbrains/api/android/extensions-compose-jetbrains.api +++ b/extensions-compose-jetbrains/api/android/extensions-compose-jetbrains.api @@ -30,11 +30,17 @@ public final class com/arkivanov/decompose/extensions/compose/jetbrains/pages/Pa public final class com/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation$Default : com/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation { public static final field $stable I public static final field INSTANCE Lcom/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation$Default; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; } public final class com/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation$Disabled : com/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation { public static final field $stable I public static final field INSTANCE Lcom/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation$Disabled; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; } public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/ChildrenKt { diff --git a/extensions-compose-jetbrains/api/jvm/extensions-compose-jetbrains.api b/extensions-compose-jetbrains/api/jvm/extensions-compose-jetbrains.api index 140987c0b..a519761cf 100644 --- a/extensions-compose-jetbrains/api/jvm/extensions-compose-jetbrains.api +++ b/extensions-compose-jetbrains/api/jvm/extensions-compose-jetbrains.api @@ -42,11 +42,17 @@ public final class com/arkivanov/decompose/extensions/compose/jetbrains/pages/Pa public final class com/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation$Default : com/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation { public static final field $stable I public static final field INSTANCE Lcom/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation$Default; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; } public final class com/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation$Disabled : com/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation { public static final field $stable I public static final field INSTANCE Lcom/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation$Disabled; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; } public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/ChildrenKt { diff --git a/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation.kt b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation.kt index 1d20c1aa2..9aba9b04c 100644 --- a/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation.kt +++ b/extensions-compose-jetbrains/src/commonMain/kotlin/com/arkivanov/decompose/extensions/compose/jetbrains/pages/PagesScrollAnimation.kt @@ -8,7 +8,7 @@ import com.arkivanov.decompose.ExperimentalDecomposeApi @ExperimentalDecomposeApi sealed interface PagesScrollAnimation { - object Disabled : PagesScrollAnimation - object Default : PagesScrollAnimation + data object Disabled : PagesScrollAnimation + data object Default : PagesScrollAnimation class Custom(val spec: AnimationSpec) : PagesScrollAnimation } diff --git a/gradle.properties b/gradle.properties index 040c63887..cd97a4bb4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,7 +7,7 @@ org.gradle.parallel=true org.gradle.caching=true systemProp.org.gradle.internal.publish.checksums.insecure=true kotlin.mpp.androidSourceSetLayoutVersion=2 -org.jetbrains.compose.experimental.uikit.enabled=true +kotlin.mpp.applyDefaultHierarchyTemplate=false org.jetbrains.compose.experimental.macos.enabled=true org.jetbrains.compose.experimental.jscanvas.enabled=true diff --git a/sample/app-darwin-compose/.gitignore b/sample/app-darwin-compose/.gitignore deleted file mode 100644 index 42afabfd2..000000000 --- a/sample/app-darwin-compose/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/sample/app-darwin-compose/build.gradle.kts b/sample/app-darwin-compose/build.gradle.kts deleted file mode 100644 index 661a93efa..000000000 --- a/sample/app-darwin-compose/build.gradle.kts +++ /dev/null @@ -1,87 +0,0 @@ -import com.arkivanov.gradle.bundle -import com.arkivanov.gradle.dependsOn -import com.arkivanov.gradle.setupMultiplatform -import com.arkivanov.gradle.setupSourceSets -import org.jetbrains.compose.experimental.dsl.IOSDevices -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget - -plugins { - id("kotlin-multiplatform") - id("org.jetbrains.compose") - id("com.arkivanov.gradle.setup") -} - -setupMultiplatform { - listOf(iosX64("uikitX64"), iosArm64("uikitArm64")).forEach { - it.binaries { - executable { - entryPoint = "com.arkivanov.sample.app.main" - freeCompilerArgs += listOf( - "-linker-option", "-framework", "-linker-option", "Metal", - "-linker-option", "-framework", "-linker-option", "CoreText", - "-linker-option", "-framework", "-linker-option", "CoreGraphics" - ) - } - } - } -} - -kotlin { - setupSourceSets { - val uikit by bundle() - - uikit dependsOn common - iosSet dependsOn uikit - - common.main.dependencies { - implementation(project(":decompose")) - implementation(project(":extensions-compose-jetbrains")) - implementation(project(":sample:shared:shared")) - implementation(project(":sample:shared:compose")) - implementation(compose.runtime) - implementation(compose.foundation) - implementation(compose.material) - } - } -} - -kotlin.targets.withType { - binaries.all { - binaryOptions["memoryModel"] = "experimental" - binaryOptions["freezing"] = "disabled" - } -} - -compose.experimental { - uikit.application { - bundleIdPrefix = "com.arkivanov.decompose.sample" - projectName = "DecomposeSample" - - deployConfigurations { - simulator("IPhone12Pro") { - // Usage: ./gradlew iosDeployIPhone12ProDebug - device = IOSDevices.IPHONE_12_PRO - } - - /* - * Usage: ./gradlew iosDeployDeviceDebug - * - * If your are getting "A valid provisioning profile for this executable was not found" error, - * see: https://developer.apple.com/forums/thread/128121?answerId=403323022#403323022 - */ - connectedDevice("Device") { - // Uncomment and fill with your Team ID - // teamId = "" - } - } - } -} - -kotlin { - targets.withType { - binaries.all { - // TODO: the current compose binary surprises LLVM, so disable checks for now. - freeCompilerArgs += "-Xdisable-phases=VerifyBitcode" - } - } -} diff --git a/sample/app-darwin-compose/src/uikitMain/kotlin/com/arkivanov/sample/app/Main.kt b/sample/app-darwin-compose/src/uikitMain/kotlin/com/arkivanov/sample/app/Main.kt deleted file mode 100644 index c41ee873f..000000000 --- a/sample/app-darwin-compose/src/uikitMain/kotlin/com/arkivanov/sample/app/Main.kt +++ /dev/null @@ -1,108 +0,0 @@ -@file:OptIn(ExperimentalForeignApi::class, BetaInteropApi::class) - -package com.arkivanov.sample.app - -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.ComposeUIViewController -import com.arkivanov.decompose.DefaultComponentContext -import com.arkivanov.decompose.extensions.compose.jetbrains.PredictiveBackGestureIcon -import com.arkivanov.decompose.extensions.compose.jetbrains.PredictiveBackGestureOverlay -import com.arkivanov.essenty.backhandler.BackDispatcher -import com.arkivanov.essenty.lifecycle.LifecycleRegistry -import com.arkivanov.essenty.lifecycle.destroy -import com.arkivanov.essenty.lifecycle.resume -import com.arkivanov.essenty.lifecycle.stop -import com.arkivanov.sample.shared.dynamicfeatures.dynamicfeature.DefaultFeatureInstaller -import com.arkivanov.sample.shared.root.DefaultRootComponent -import com.arkivanov.sample.shared.root.RootContent -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 platform.Foundation.NSStringFromClass -import platform.UIKit.UIApplication -import platform.UIKit.UIApplicationDelegateProtocol -import platform.UIKit.UIApplicationDelegateProtocolMeta -import platform.UIKit.UIApplicationMain -import platform.UIKit.UIResponder -import platform.UIKit.UIResponderMeta -import platform.UIKit.UIScreen -import platform.UIKit.UIWindow - -fun main() { - val args = emptyArray() - memScoped { - val argc = args.size + 1 - val argv = (arrayOf("skikoApp") + args).map { it.cstr.ptr }.toCValues() - autoreleasepool { - UIApplicationMain(argc, argv, null, NSStringFromClass(SkikoAppDelegate)) - } - } -} - -class SkikoAppDelegate @OverrideInit constructor() : UIResponder(), UIApplicationDelegateProtocol { - companion object : UIResponderMeta(), UIApplicationDelegateProtocolMeta - - private val backDispatcher = BackDispatcher() - private val lifecycle = LifecycleRegistry() - - private val root = - DefaultRootComponent( - componentContext = DefaultComponentContext(lifecycle = lifecycle, backHandler = backDispatcher), - featureInstaller = DefaultFeatureInstaller, - ) - - private var _window: UIWindow? = null - override fun window() = _window - override fun setWindow(window: UIWindow?) { - _window = window - } - - override fun application(application: UIApplication, didFinishLaunchingWithOptions: Map?): Boolean { - window = UIWindow(frame = UIScreen.mainScreen.bounds) - - window!!.rootViewController = ComposeUIViewController { - Column { - PredictiveBackGestureOverlay( - backDispatcher = backDispatcher, - backIcon = { progress, _ -> - PredictiveBackGestureIcon( - imageVector = Icons.Default.ArrowBack, - progress = progress, - ) - }, - modifier = Modifier.fillMaxSize(), - ) { - RootContent( - component = root, - modifier = Modifier.fillMaxSize(), - ) - } - } - } - window!!.makeKeyAndVisible() - return true - } - - override fun applicationDidBecomeActive(application: UIApplication) { - lifecycle.resume() - } - - override fun applicationWillResignActive(application: UIApplication) { - lifecycle.stop() - - } - - override fun applicationWillTerminate(application: UIApplication) { - lifecycle.destroy() - } -} diff --git a/sample/app-ios-compose/.gitignore b/sample/app-ios-compose/.gitignore new file mode 100644 index 000000000..97d5de824 --- /dev/null +++ b/sample/app-ios-compose/.gitignore @@ -0,0 +1,18 @@ +DerivedData/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ +*.moved-aside +*.xccheckout +*.xcscmblueprint +*.hmap +*.ipa +*.dSYM.zip +*.dSYM +Pods diff --git a/sample/app-ios-compose/app-ios-compose.xcodeproj/project.pbxproj b/sample/app-ios-compose/app-ios-compose.xcodeproj/project.pbxproj new file mode 100644 index 000000000..004d5b419 --- /dev/null +++ b/sample/app-ios-compose/app-ios-compose.xcodeproj/project.pbxproj @@ -0,0 +1,394 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 79DA70E72B06BD3700326407 /* iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79DA70E62B06BD3700326407 /* iOSApp.swift */; }; + 79DA70E92B06BD3700326407 /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79DA70E82B06BD3700326407 /* RootView.swift */; }; + 79DA70EB2B06BD3800326407 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 79DA70EA2B06BD3800326407 /* Assets.xcassets */; }; + 79DA70EF2B06BD3800326407 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 79DA70EE2B06BD3800326407 /* Preview Assets.xcassets */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 79DA70E32B06BD3700326407 /* app-ios-compose.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "app-ios-compose.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 79DA70E62B06BD3700326407 /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = ""; }; + 79DA70E82B06BD3700326407 /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = ""; }; + 79DA70EA2B06BD3800326407 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 79DA70EC2B06BD3800326407 /* app_ios_compose.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = app_ios_compose.entitlements; sourceTree = ""; }; + 79DA70EE2B06BD3800326407 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 79DA70E02B06BD3700326407 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 79DA70DA2B06BD3700326407 = { + isa = PBXGroup; + children = ( + 79DA70E52B06BD3700326407 /* app-ios-compose */, + 79DA70E42B06BD3700326407 /* Products */, + ); + sourceTree = ""; + }; + 79DA70E42B06BD3700326407 /* Products */ = { + isa = PBXGroup; + children = ( + 79DA70E32B06BD3700326407 /* app-ios-compose.app */, + ); + name = Products; + sourceTree = ""; + }; + 79DA70E52B06BD3700326407 /* app-ios-compose */ = { + isa = PBXGroup; + children = ( + 79DA70E62B06BD3700326407 /* iOSApp.swift */, + 79DA70E82B06BD3700326407 /* RootView.swift */, + 79DA70EA2B06BD3800326407 /* Assets.xcassets */, + 79DA70EC2B06BD3800326407 /* app_ios_compose.entitlements */, + 79DA70ED2B06BD3800326407 /* Preview Content */, + ); + path = "app-ios-compose"; + sourceTree = ""; + }; + 79DA70ED2B06BD3800326407 /* Preview Content */ = { + isa = PBXGroup; + children = ( + 79DA70EE2B06BD3800326407 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 79DA70E22B06BD3700326407 /* app-ios-compose */ = { + isa = PBXNativeTarget; + buildConfigurationList = 79DA70F22B06BD3800326407 /* Build configuration list for PBXNativeTarget "app-ios-compose" */; + buildPhases = ( + 79DA70F52B06BE4E00326407 /* ShellScript */, + 79DA70DF2B06BD3700326407 /* Sources */, + 79DA70E02B06BD3700326407 /* Frameworks */, + 79DA70E12B06BD3700326407 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "app-ios-compose"; + productName = "app-ios-compose"; + productReference = 79DA70E32B06BD3700326407 /* app-ios-compose.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 79DA70DB2B06BD3700326407 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1430; + LastUpgradeCheck = 1430; + TargetAttributes = { + 79DA70E22B06BD3700326407 = { + CreatedOnToolsVersion = 14.3.1; + }; + }; + }; + buildConfigurationList = 79DA70DE2B06BD3700326407 /* Build configuration list for PBXProject "app-ios-compose" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 79DA70DA2B06BD3700326407; + productRefGroup = 79DA70E42B06BD3700326407 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 79DA70E22B06BD3700326407 /* app-ios-compose */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 79DA70E12B06BD3700326407 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 79DA70EF2B06BD3800326407 /* Preview Assets.xcassets in Resources */, + 79DA70EB2B06BD3800326407 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 79DA70F52B06BE4E00326407 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "cd \"$SRCROOT/../..\"\n./gradlew :sample:shared:compose:embedAndSignAppleFrameworkForXcode\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 79DA70DF2B06BD3700326407 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 79DA70E92B06BD3700326407 /* RootView.swift in Sources */, + 79DA70E72B06BD3700326407 /* iOSApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 79DA70F02B06BD3800326407 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 79DA70F12B06BD3800326407 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 79DA70F32B06BD3800326407 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = "app-ios-compose/app_ios_compose.entitlements"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"app-ios-compose/Preview Content\""; + ENABLE_PREVIEWS = YES; + FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../shared/compose/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)"; + GENERATE_INFOPLIST_FILE = YES; + "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault; + "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; + "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 13.3; + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + shared, + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.arkivanov.sample.app-ios-compose.app-ios-compose"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 79DA70F42B06BD3800326407 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = "app-ios-compose/app_ios_compose.entitlements"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"app-ios-compose/Preview Content\""; + ENABLE_PREVIEWS = YES; + FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../shared/compose/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)"; + GENERATE_INFOPLIST_FILE = YES; + "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault; + "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; + "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 13.3; + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + shared, + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.arkivanov.sample.app-ios-compose.app-ios-compose"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 79DA70DE2B06BD3700326407 /* Build configuration list for PBXProject "app-ios-compose" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 79DA70F02B06BD3800326407 /* Debug */, + 79DA70F12B06BD3800326407 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 79DA70F22B06BD3800326407 /* Build configuration list for PBXNativeTarget "app-ios-compose" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 79DA70F32B06BD3800326407 /* Debug */, + 79DA70F42B06BD3800326407 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 79DA70DB2B06BD3700326407 /* Project object */; +} diff --git a/sample/app-ios-compose/app-ios-compose.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/sample/app-ios-compose/app-ios-compose.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/sample/app-ios-compose/app-ios-compose.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/sample/app-ios-compose/app-ios-compose.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/sample/app-ios-compose/app-ios-compose.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/sample/app-ios-compose/app-ios-compose.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/sample/app-ios-compose/app-ios-compose.xcodeproj/project.xcworkspace/xcuserdata/arkivanov.xcuserdatad/UserInterfaceState.xcuserstate b/sample/app-ios-compose/app-ios-compose.xcodeproj/project.xcworkspace/xcuserdata/arkivanov.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 000000000..9d0313ba6 Binary files /dev/null and b/sample/app-ios-compose/app-ios-compose.xcodeproj/project.xcworkspace/xcuserdata/arkivanov.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/sample/app-ios-compose/app-ios-compose.xcodeproj/xcuserdata/arkivanov.xcuserdatad/xcschemes/xcschememanagement.plist b/sample/app-ios-compose/app-ios-compose.xcodeproj/xcuserdata/arkivanov.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 000000000..2920fb6ac --- /dev/null +++ b/sample/app-ios-compose/app-ios-compose.xcodeproj/xcuserdata/arkivanov.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + app-ios-compose.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/sample/app-ios-compose/app-ios-compose/Assets.xcassets/AccentColor.colorset/Contents.json b/sample/app-ios-compose/app-ios-compose/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 000000000..eb8789700 --- /dev/null +++ b/sample/app-ios-compose/app-ios-compose/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/sample/app-ios-compose/app-ios-compose/Assets.xcassets/AppIcon.appiconset/Contents.json b/sample/app-ios-compose/app-ios-compose/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..532cd729c --- /dev/null +++ b/sample/app-ios-compose/app-ios-compose/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,63 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/sample/app-ios-compose/app-ios-compose/Assets.xcassets/Contents.json b/sample/app-ios-compose/app-ios-compose/Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/sample/app-ios-compose/app-ios-compose/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/sample/app-ios-compose/app-ios-compose/Preview Content/Preview Assets.xcassets/Contents.json b/sample/app-ios-compose/app-ios-compose/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/sample/app-ios-compose/app-ios-compose/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/sample/app-ios-compose/app-ios-compose/RootView.swift b/sample/app-ios-compose/app-ios-compose/RootView.swift new file mode 100644 index 000000000..8cae907d0 --- /dev/null +++ b/sample/app-ios-compose/app-ios-compose/RootView.swift @@ -0,0 +1,16 @@ +import SwiftUI +import Shared + +struct RootView: UIViewControllerRepresentable { + let root: RootComponent + let backDispatcher: BackDispatcher + + func makeUIViewController(context: Context) -> UIViewController { + let controller = RootViewControllerKt.rootViewController(root: root, backDispatcher: backDispatcher) + controller.overrideUserInterfaceStyle = .light + return controller + } + + func updateUIViewController(_ uiViewController: UIViewController, context: Context) { + } +} diff --git a/sample/app-ios-compose/app-ios-compose/app_ios_compose.entitlements b/sample/app-ios-compose/app-ios-compose/app_ios_compose.entitlements new file mode 100644 index 000000000..f2ef3ae02 --- /dev/null +++ b/sample/app-ios-compose/app-ios-compose/app_ios_compose.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + + diff --git a/sample/app-ios-compose/app-ios-compose/iOSApp.swift b/sample/app-ios-compose/app-ios-compose/iOSApp.swift new file mode 100644 index 000000000..07fe00db0 --- /dev/null +++ b/sample/app-ios-compose/app-ios-compose/iOSApp.swift @@ -0,0 +1,47 @@ +import SwiftUI +import Shared + +@main +struct iOSApp: App { + @UIApplicationDelegateAdaptor(AppDelegate.self) + var appDelegate: AppDelegate + + var body: some Scene { + WindowGroup { + RootView(root: appDelegate.root, backDispatcher: appDelegate.backDispatcher) + .ignoresSafeArea(.all) + } + } +} + +class AppDelegate: NSObject, UIApplicationDelegate { + private var stateKeeper = StateKeeperDispatcherKt.StateKeeperDispatcher(savedState: nil) + var backDispatcher: BackDispatcher = BackDispatcherKt.BackDispatcher() + + lazy var root: RootComponent = DefaultRootComponent( + componentContext: DefaultComponentContext( + lifecycle: ApplicationLifecycle(), + stateKeeper: stateKeeper, + instanceKeeper: nil, + backHandler: backDispatcher + ), + featureInstaller: DefaultFeatureInstaller.shared, + deepLink: DefaultRootComponentDeepLinkNone.shared, + webHistoryController: nil + ) + + func application(_ application: UIApplication, shouldSaveSecureApplicationState coder: NSCoder) -> Bool { + CodingKt.encodeParcelable(coder, value: stateKeeper.save(), key: "savedState") + return true + } + + func application(_ application: UIApplication, shouldRestoreSecureApplicationState coder: NSCoder) -> Bool { + do { + let savedState = try CodingKt.decodeParcelable(coder, key: "savedState") as! ParcelableParcelableContainer + stateKeeper = StateKeeperDispatcherKt.StateKeeperDispatcher(savedState: savedState) + return true + } catch { + return false + } + } +} diff --git a/sample/app-ios/app-ios.xcodeproj/project.pbxproj b/sample/app-ios/app-ios.xcodeproj/project.pbxproj index 73c92b630..87829c77a 100644 --- a/sample/app-ios/app-ios.xcodeproj/project.pbxproj +++ b/sample/app-ios/app-ios.xcodeproj/project.pbxproj @@ -359,6 +359,11 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + shared, + ); PRODUCT_BUNDLE_IDENTIFIER = "com.arkivanov.sample.app-ios"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -388,6 +393,11 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-framework", + shared, + ); PRODUCT_BUNDLE_IDENTIFIER = "com.arkivanov.sample.app-ios"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; diff --git a/sample/app-ios/app-ios/app_iosApp.swift b/sample/app-ios/app-ios/app_iosApp.swift index 5cb7def1a..bd20440a3 100644 --- a/sample/app-ios/app-ios/app_iosApp.swift +++ b/sample/app-ios/app-ios/app_iosApp.swift @@ -13,76 +13,40 @@ struct app_iosApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate: AppDelegate - private var rootHolder: RootHolder { appDelegate.getRootHolder() } - var body: some Scene { WindowGroup { - RootView(rootHolder.root) - .onReceive(NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)) { _ in - LifecycleRegistryExtKt.resume(rootHolder.lifecycle) - } - .onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in - LifecycleRegistryExtKt.pause(rootHolder.lifecycle) - } - .onReceive(NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)) { _ in - LifecycleRegistryExtKt.stop(rootHolder.lifecycle) - } - .onReceive(NotificationCenter.default.publisher(for: UIApplication.willTerminateNotification)) { _ in - LifecycleRegistryExtKt.destroy(rootHolder.lifecycle) - } + RootView(appDelegate.root) } } } class AppDelegate: NSObject, UIApplicationDelegate { - private var rootHolder: RootHolder? - + private var stateKeeper = StateKeeperDispatcherKt.StateKeeperDispatcher(savedState: nil) + + lazy var root: RootComponent = DefaultRootComponent( + componentContext: DefaultComponentContext( + lifecycle: ApplicationLifecycle(), + stateKeeper: stateKeeper, + instanceKeeper: nil, + backHandler: nil + ), + featureInstaller: DefaultFeatureInstaller.shared, + deepLink: DefaultRootComponentDeepLinkNone.shared, + webHistoryController: nil + ) + func application(_ application: UIApplication, shouldSaveSecureApplicationState coder: NSCoder) -> Bool { - let savedState = rootHolder!.stateKeeper.save() - CodingKt.encodeParcelable(coder, value: savedState, key: "savedState") + CodingKt.encodeParcelable(coder, value: stateKeeper.save(), key: "savedState") return true } func application(_ application: UIApplication, shouldRestoreSecureApplicationState coder: NSCoder) -> Bool { do { let savedState = try CodingKt.decodeParcelable(coder, key: "savedState") as! ParcelableParcelableContainer - rootHolder = RootHolder(savedState: savedState) + stateKeeper = StateKeeperDispatcherKt.StateKeeperDispatcher(savedState: savedState) return true } catch { return false } } - - fileprivate func getRootHolder() -> RootHolder { - if (rootHolder == nil) { - rootHolder = RootHolder(savedState: nil) - } - - return rootHolder! - } -} - -private class RootHolder { - let lifecycle: LifecycleRegistry - let stateKeeper: StateKeeperDispatcher - let root: RootComponent - - init(savedState: ParcelableParcelableContainer?) { - lifecycle = LifecycleRegistryKt.LifecycleRegistry() - stateKeeper = StateKeeperDispatcherKt.StateKeeperDispatcher(savedState: savedState) - - root = DefaultRootComponent( - componentContext: DefaultComponentContext( - lifecycle: lifecycle, - stateKeeper: stateKeeper, - instanceKeeper: nil, - backHandler: nil - ), - featureInstaller: DefaultFeatureInstaller.shared, - deepLink: DefaultRootComponentDeepLinkNone.shared, - webHistoryController: nil - ) - - LifecycleRegistryExtKt.create(lifecycle) - } } diff --git a/sample/shared/compose/build.gradle.kts b/sample/shared/compose/build.gradle.kts index 48ee55122..6ee286fa7 100644 --- a/sample/shared/compose/build.gradle.kts +++ b/sample/shared/compose/build.gradle.kts @@ -3,6 +3,8 @@ import com.arkivanov.gradle.dependsOn import com.arkivanov.gradle.iosCompat import com.arkivanov.gradle.setupMultiplatform import com.arkivanov.gradle.setupSourceSets +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget +import org.jetbrains.kotlin.konan.target.Family plugins { id("kotlin-multiplatform") @@ -23,6 +25,28 @@ android { } kotlin { + targets + .filterIsInstance() + .filter { it.konanTarget.family == Family.IOS } + .forEach { + it.binaries { + framework { + baseName = "Shared" // Used by app-ios-compose + export(project(":decompose")) + export(project(":sample:shared:shared")) + + // Optional, only if you need Predictive Back Gesture on Darwin (Apple) targets + export(deps.essenty.backHandler) + + // Optional, only if you need state preservation on Darwin (Apple) targets + export(deps.essenty.stateKeeper) + + // Optional, only if you need state preservation on Darwin (Apple) targets + export(deps.parcelizeDarwin.runtime) + } + } + } + setupSourceSets { val jvm by bundle() val ios by bundle() @@ -31,9 +55,9 @@ kotlin { iosSet dependsOn ios common.main.dependencies { - implementation(project(":decompose")) + api(project(":decompose")) implementation(project(":extensions-compose-jetbrains")) - implementation(project(":sample:shared:shared")) + api(project(":sample:shared:shared")) implementation(project(":sample:shared:dynamic-features:api")) implementation(project(":sample:shared:dynamic-features:compose-api")) implementation(compose.runtime) diff --git a/sample/shared/compose/src/iosMain/kotlin/com/arkivanov/sample/shared/root/RootViewController.kt b/sample/shared/compose/src/iosMain/kotlin/com/arkivanov/sample/shared/root/RootViewController.kt new file mode 100644 index 000000000..d5e9e62a3 --- /dev/null +++ b/sample/shared/compose/src/iosMain/kotlin/com/arkivanov/sample/shared/root/RootViewController.kt @@ -0,0 +1,29 @@ +package com.arkivanov.sample.shared.root + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.ui.Modifier +import androidx.compose.ui.window.ComposeUIViewController +import com.arkivanov.decompose.ExperimentalDecomposeApi +import com.arkivanov.decompose.extensions.compose.jetbrains.PredictiveBackGestureIcon +import com.arkivanov.decompose.extensions.compose.jetbrains.PredictiveBackGestureOverlay +import com.arkivanov.essenty.backhandler.BackDispatcher +import platform.UIKit.UIViewController + +@OptIn(ExperimentalDecomposeApi::class) +fun rootViewController(root: RootComponent, backDispatcher: BackDispatcher): UIViewController = + ComposeUIViewController { + PredictiveBackGestureOverlay( + backDispatcher = backDispatcher, + backIcon = { progress, _ -> + PredictiveBackGestureIcon( + imageVector = Icons.Default.ArrowBack, + progress = progress, + ) + }, + modifier = Modifier.fillMaxSize(), + ) { + RootContent(component = root, modifier = Modifier.fillMaxSize()) + } + } diff --git a/sample/shared/dynamic-features/feature1Impl/build.gradle.kts b/sample/shared/dynamic-features/feature1Impl/build.gradle.kts index 64d7313f5..01aae0335 100644 --- a/sample/shared/dynamic-features/feature1Impl/build.gradle.kts +++ b/sample/shared/dynamic-features/feature1Impl/build.gradle.kts @@ -2,9 +2,6 @@ import com.arkivanov.gradle.bundle import com.arkivanov.gradle.iosCompat import com.arkivanov.gradle.setupMultiplatform import com.arkivanov.gradle.setupSourceSets -import org.jetbrains.compose.ComposeCompilerKotlinSupportPlugin -import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation -import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerPluginSupportPlugin import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType plugins { @@ -58,20 +55,6 @@ kotlin { } } -compose.web.targets() - - -plugins.removeAll { it is ComposeCompilerKotlinSupportPlugin } - -class ComposeNoNativePlugin : KotlinCompilerPluginSupportPlugin by ComposeCompilerKotlinSupportPlugin( - buildEventsListenerRegistry = {}, -) { - override fun isApplicable(kotlinCompilation: KotlinCompilation<*>): Boolean { - return when (kotlinCompilation.target.platformType) { - KotlinPlatformType.native -> false - else -> ComposeCompilerKotlinSupportPlugin(buildEventsListenerRegistry = {}).isApplicable(kotlinCompilation) - } - } +compose { + platformTypes.set(platformTypes.get() - KotlinPlatformType.js - KotlinPlatformType.native) } - -apply() diff --git a/sample/shared/dynamic-features/feature2Impl/build.gradle.kts b/sample/shared/dynamic-features/feature2Impl/build.gradle.kts index 75a128d0c..6ec35b647 100644 --- a/sample/shared/dynamic-features/feature2Impl/build.gradle.kts +++ b/sample/shared/dynamic-features/feature2Impl/build.gradle.kts @@ -2,9 +2,6 @@ import com.arkivanov.gradle.bundle import com.arkivanov.gradle.iosCompat import com.arkivanov.gradle.setupMultiplatform import com.arkivanov.gradle.setupSourceSets -import org.jetbrains.compose.ComposeCompilerKotlinSupportPlugin -import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation -import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerPluginSupportPlugin import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType plugins { @@ -58,19 +55,6 @@ kotlin { } } -compose.web.targets() - -plugins.removeAll { it is ComposeCompilerKotlinSupportPlugin } - -class ComposeNoNativePlugin : KotlinCompilerPluginSupportPlugin by ComposeCompilerKotlinSupportPlugin( - buildEventsListenerRegistry = {}, -) { - override fun isApplicable(kotlinCompilation: KotlinCompilation<*>): Boolean { - return when (kotlinCompilation.target.platformType) { - KotlinPlatformType.native -> false - else -> ComposeCompilerKotlinSupportPlugin(buildEventsListenerRegistry = {}).isApplicable(kotlinCompilation) - } - } +compose { + platformTypes.set(platformTypes.get() - KotlinPlatformType.js - KotlinPlatformType.native) } - -apply() diff --git a/sample/shared/shared/build.gradle.kts b/sample/shared/shared/build.gradle.kts index 8d432938e..0a2bfedd0 100644 --- a/sample/shared/shared/build.gradle.kts +++ b/sample/shared/shared/build.gradle.kts @@ -32,9 +32,8 @@ kotlin { .forEach { it.binaries { framework { - baseName = "Shared" + baseName = "Shared" // Used by app-ios export(project(":decompose")) - export(deps.essenty.lifecycle) // Optional, only if you need state preservation on Darwin (Apple) targets export(deps.essenty.stateKeeper) @@ -62,7 +61,6 @@ kotlin { implementation(deps.reaktive.reaktive) } - common.test.dependencies { implementation(deps.reaktive.reaktiveTesting) } diff --git a/settings.gradle.kts b/settings.gradle.kts index f4a99455c..f3cbe6116 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -15,7 +15,7 @@ pluginManagement { resolutionStrategy { eachPlugin { if (requested.id.toString() == "com.arkivanov.gradle.setup") { - useModule("com.github.arkivanov:gradle-setup-plugin:2571f348ff") + useModule("com.github.arkivanov:gradle-setup-plugin:655aedff78") } } } @@ -37,7 +37,6 @@ if (!startParameter.projectProperties.containsKey("check_publication")) { include(":sample:shared:dynamic-features:feature2Impl") include(":sample:app-android") include(":sample:app-desktop") - include(":sample:app-darwin-compose") include(":sample:app-js-compose") include(":sample:app-js") } else {