From e30aaf63718dc3a24eecdb8ae15120c2266f3f4f Mon Sep 17 00:00:00 2001 From: Nikita Lipsky Date: Tue, 10 Jan 2023 15:33:31 +0200 Subject: [PATCH] Move chat-mpp to KMM project structure (#2620) --- experimental/examples/chat-mpp/.gitignore | 6 + .../examples/chat-mpp/.run/desktopApp.run.xml | 28 ++ .../.run/iosApp (Android Studio).run.xml | 7 + .../examples/chat-mpp/.run/iosApp.run.xml | 8 + .../examples/chat-mpp/.run/jsApp.run.xml | 28 ++ experimental/examples/chat-mpp/README.md | 37 +- .../chat-mpp/androidApp/build.gradle.kts | 33 ++ .../src/main}/AndroidManifest.xml | 0 .../src/main}/kotlin/MainActivity.kt | 6 +- .../src/main}/res/values/strings.xml | 0 .../examples/chat-mpp/build.gradle.kts | 229 +---------- .../chat-mpp/desktopApp/build.gradle.kts | 22 + .../src/jvmMain/kotlin/Main.kt} | 10 +- .../examples/chat-mpp/gradle.properties | 20 +- .../iosApp/Chat.xcodeproj/project.pbxproj | 380 ++++++++++++++++++ .../iosApp/Configuration/TeamId.xcconfig | 1 + experimental/examples/chat-mpp/iosApp/Podfile | 5 + .../chat-mpp/iosApp/iosApp/Info.plist | 48 +++ .../chat-mpp/iosApp/iosApp/iosApp.swift | 15 + .../examples/chat-mpp/jsApp/build.gradle.kts | 23 ++ .../{ => jsApp}/src/jsMain/kotlin/main.js.kt | 2 +- .../src/jsMain/resources/index.html | 2 +- .../src/jsMain/resources/styles.css | 0 .../examples/chat-mpp/run-configurations.png | Bin 0 -> 21525 bytes .../examples/chat-mpp/settings.gradle.kts | 17 +- .../examples/chat-mpp/shared/build.gradle.kts | 111 +++++ .../src/androidMain/AndroidManifest.xml | 2 + .../androidMain/kotlin/currentTime.android.kt | 0 .../src/androidMain/kotlin/main.android.kt | 4 + .../src/commonMain/kotlin/ChatApp.kt | 2 +- .../src/commonMain/kotlin/Data.kt | 0 .../src/commonMain/kotlin/Messages.kt | 0 .../src/commonMain/kotlin/Reducer.kt | 0 .../src/commonMain/kotlin/SendMessage.kt | 0 .../src/commonMain/kotlin/Store.kt | 0 .../commonMain/kotlin/currentTime.common.kt | 0 .../desktopMain/kotlin/currentTime.desktop.kt | 0 .../src/desktopMain/kotlin/main.desktop.kt | 11 + .../src/iosMain/kotlin/currentTime.ios.kt} | 0 .../shared/src/iosMain/kotlin/main.ios.kt | 8 + .../src/jsMain/kotlin/currentTime.js.kt | 0 .../shared/src/jsMain/kotlin/main.js.kt | 6 + .../src/macosMain/kotlin/currentTime.macos.kt | 0 .../src/macosMain/kotlin/main.macos.kt | 0 .../src/uikitMain/kotlin/main.uikit.kt | 8 - 45 files changed, 809 insertions(+), 270 deletions(-) create mode 100644 experimental/examples/chat-mpp/.run/desktopApp.run.xml create mode 100644 experimental/examples/chat-mpp/.run/iosApp (Android Studio).run.xml create mode 100644 experimental/examples/chat-mpp/.run/iosApp.run.xml create mode 100644 experimental/examples/chat-mpp/.run/jsApp.run.xml create mode 100644 experimental/examples/chat-mpp/androidApp/build.gradle.kts rename experimental/examples/chat-mpp/{src/androidMain => androidApp/src/main}/AndroidManifest.xml (100%) rename experimental/examples/chat-mpp/{src/androidMain => androidApp/src/main}/kotlin/MainActivity.kt (78%) rename experimental/examples/chat-mpp/{src/androidMain => androidApp/src/main}/res/values/strings.xml (100%) create mode 100644 experimental/examples/chat-mpp/desktopApp/build.gradle.kts rename experimental/examples/chat-mpp/{src/desktopMain/kotlin/main.desktop.kt => desktopApp/src/jvmMain/kotlin/Main.kt} (64%) create mode 100644 experimental/examples/chat-mpp/iosApp/Chat.xcodeproj/project.pbxproj create mode 100644 experimental/examples/chat-mpp/iosApp/Configuration/TeamId.xcconfig create mode 100644 experimental/examples/chat-mpp/iosApp/Podfile create mode 100644 experimental/examples/chat-mpp/iosApp/iosApp/Info.plist create mode 100644 experimental/examples/chat-mpp/iosApp/iosApp/iosApp.swift create mode 100644 experimental/examples/chat-mpp/jsApp/build.gradle.kts rename experimental/examples/chat-mpp/{ => jsApp}/src/jsMain/kotlin/main.js.kt (93%) rename experimental/examples/chat-mpp/{ => jsApp}/src/jsMain/resources/index.html (89%) rename experimental/examples/chat-mpp/{ => jsApp}/src/jsMain/resources/styles.css (100%) create mode 100644 experimental/examples/chat-mpp/run-configurations.png create mode 100644 experimental/examples/chat-mpp/shared/build.gradle.kts create mode 100644 experimental/examples/chat-mpp/shared/src/androidMain/AndroidManifest.xml rename experimental/examples/chat-mpp/{ => shared}/src/androidMain/kotlin/currentTime.android.kt (100%) create mode 100644 experimental/examples/chat-mpp/shared/src/androidMain/kotlin/main.android.kt rename experimental/examples/chat-mpp/{ => shared}/src/commonMain/kotlin/ChatApp.kt (98%) rename experimental/examples/chat-mpp/{ => shared}/src/commonMain/kotlin/Data.kt (100%) rename experimental/examples/chat-mpp/{ => shared}/src/commonMain/kotlin/Messages.kt (100%) rename experimental/examples/chat-mpp/{ => shared}/src/commonMain/kotlin/Reducer.kt (100%) rename experimental/examples/chat-mpp/{ => shared}/src/commonMain/kotlin/SendMessage.kt (100%) rename experimental/examples/chat-mpp/{ => shared}/src/commonMain/kotlin/Store.kt (100%) rename experimental/examples/chat-mpp/{ => shared}/src/commonMain/kotlin/currentTime.common.kt (100%) rename experimental/examples/chat-mpp/{ => shared}/src/desktopMain/kotlin/currentTime.desktop.kt (100%) create mode 100644 experimental/examples/chat-mpp/shared/src/desktopMain/kotlin/main.desktop.kt rename experimental/examples/chat-mpp/{src/uikitMain/kotlin/currentTime.uikit.kt => shared/src/iosMain/kotlin/currentTime.ios.kt} (100%) create mode 100644 experimental/examples/chat-mpp/shared/src/iosMain/kotlin/main.ios.kt rename experimental/examples/chat-mpp/{ => shared}/src/jsMain/kotlin/currentTime.js.kt (100%) create mode 100644 experimental/examples/chat-mpp/shared/src/jsMain/kotlin/main.js.kt rename experimental/examples/chat-mpp/{ => shared}/src/macosMain/kotlin/currentTime.macos.kt (100%) rename experimental/examples/chat-mpp/{ => shared}/src/macosMain/kotlin/main.macos.kt (100%) delete mode 100644 experimental/examples/chat-mpp/src/uikitMain/kotlin/main.uikit.kt diff --git a/experimental/examples/chat-mpp/.gitignore b/experimental/examples/chat-mpp/.gitignore index 7921cd4d1c..74989f6092 100644 --- a/experimental/examples/chat-mpp/.gitignore +++ b/experimental/examples/chat-mpp/.gitignore @@ -1,2 +1,8 @@ local.properties .idea +iosApp/Podfile.lock +iosApp/Pods/* +iosApp/Chat.xcworkspace/* +iosApp/Chat.xcodeproj/* +!iosApp/Chat.xcodeproj/project.pbxproj +shared/shared.podspec diff --git a/experimental/examples/chat-mpp/.run/desktopApp.run.xml b/experimental/examples/chat-mpp/.run/desktopApp.run.xml new file mode 100644 index 0000000000..7af7e15f4b --- /dev/null +++ b/experimental/examples/chat-mpp/.run/desktopApp.run.xml @@ -0,0 +1,28 @@ + + + + + + + + true + true + false + + + \ No newline at end of file diff --git a/experimental/examples/chat-mpp/.run/iosApp (Android Studio).run.xml b/experimental/examples/chat-mpp/.run/iosApp (Android Studio).run.xml new file mode 100644 index 0000000000..7db93f44c2 --- /dev/null +++ b/experimental/examples/chat-mpp/.run/iosApp (Android Studio).run.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/experimental/examples/chat-mpp/.run/iosApp.run.xml b/experimental/examples/chat-mpp/.run/iosApp.run.xml new file mode 100644 index 0000000000..52af717eaf --- /dev/null +++ b/experimental/examples/chat-mpp/.run/iosApp.run.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/experimental/examples/chat-mpp/.run/jsApp.run.xml b/experimental/examples/chat-mpp/.run/jsApp.run.xml new file mode 100644 index 0000000000..6135d902e4 --- /dev/null +++ b/experimental/examples/chat-mpp/.run/jsApp.run.xml @@ -0,0 +1,28 @@ + + + + + + + + true + true + false + + + \ No newline at end of file diff --git a/experimental/examples/chat-mpp/README.md b/experimental/examples/chat-mpp/README.md index 5788efda1b..e9318eee36 100644 --- a/experimental/examples/chat-mpp/README.md +++ b/experimental/examples/chat-mpp/README.md @@ -1,23 +1,28 @@ # Chat example app -## Run on Android: -- connect device or emulator -- `./gradlew installDebug` -- open app +Example can run on Android, iOS, desktop or in a browser. -## Run on Desktop jvm - `./gradlew run` +*Prerequisites*: to run on iOS and Android, you should have "Kotlin Multiplatform Mobile" plugin installed either + in Android Studio or in AppCode with [installed CocoaPods](https://kotlinlang.org/docs/native-cocoapods.html). -## Run native on MacOS - `./gradlew runDebugExecutableMacosX64` (Works on Intel processors) -## Run web assembly in browser - `./gradlew jsBrowserDevelopmentRun` +## How to run -## Run on iOS simulator - `./gradlew iosDeployIPhone8Debug` - `./gradlew iosDeployIPadDebug` +Choose a run configuration for an appropriate target in IDE and run it. -## Run on iOS device -- Read about iOS target in [falling-balls-mpp/README.md](../falling-balls-mpp/README.md) -- `./gradlew iosDeployDeviceRelease` +![run-configurations.png](run-configurations.png) + +To run on iOS device, please correct `iosApp/Configuration/TeamId.xcconfig` with your Apple Team ID. +Alternatively, you may setup signing within XCode opening `iosApp/Chat.xcworkspace` and then +using "Signing & Capabilities" tab of `Chat` target. + +Then choose **iosApp** configuration in IDE and run it +(may also be referred as `Chat` in the Run Configurations or `iosApp (Android Studio)` for Android studio). + +## Run on desktop via Gradle + +`./gradlew desktopApp:run` + +## Run JS in browser with WebAssembly Skia via Gradle + +`./gradlew jsApp:jsBrowserDevelopmentRun` diff --git a/experimental/examples/chat-mpp/androidApp/build.gradle.kts b/experimental/examples/chat-mpp/androidApp/build.gradle.kts new file mode 100644 index 0000000000..148f74a370 --- /dev/null +++ b/experimental/examples/chat-mpp/androidApp/build.gradle.kts @@ -0,0 +1,33 @@ +plugins { + kotlin("multiplatform") + id("com.android.application") + id("org.jetbrains.compose") +} + +kotlin { + android() + sourceSets { + val androidMain by getting { + dependencies { + implementation(project(":shared")) + implementation("androidx.appcompat:appcompat:1.5.1") + implementation("androidx.activity:activity-compose:1.6.1") + } + } + } +} + +android { + compileSdk = 33 + defaultConfig { + applicationId = "org.jetbrains.Chat" + minSdk = 24 + targetSdk = 33 + versionCode = 1 + versionName = "1.0" + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } +} \ No newline at end of file diff --git a/experimental/examples/chat-mpp/src/androidMain/AndroidManifest.xml b/experimental/examples/chat-mpp/androidApp/src/main/AndroidManifest.xml similarity index 100% rename from experimental/examples/chat-mpp/src/androidMain/AndroidManifest.xml rename to experimental/examples/chat-mpp/androidApp/src/main/AndroidManifest.xml diff --git a/experimental/examples/chat-mpp/src/androidMain/kotlin/MainActivity.kt b/experimental/examples/chat-mpp/androidApp/src/main/kotlin/MainActivity.kt similarity index 78% rename from experimental/examples/chat-mpp/src/androidMain/kotlin/MainActivity.kt rename to experimental/examples/chat-mpp/androidApp/src/main/kotlin/MainActivity.kt index ba87a23dcf..dc9ecb1aec 100644 --- a/experimental/examples/chat-mpp/src/androidMain/kotlin/MainActivity.kt +++ b/experimental/examples/chat-mpp/androidApp/src/main/kotlin/MainActivity.kt @@ -3,15 +3,13 @@ package org.jetbrains.chat import android.os.Bundle import androidx.activity.compose.setContent import androidx.appcompat.app.AppCompatActivity -import java.io.File -import java.io.FileOutputStream -import ChatApp +import MainView class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { - ChatApp() + MainView() } } } diff --git a/experimental/examples/chat-mpp/src/androidMain/res/values/strings.xml b/experimental/examples/chat-mpp/androidApp/src/main/res/values/strings.xml similarity index 100% rename from experimental/examples/chat-mpp/src/androidMain/res/values/strings.xml rename to experimental/examples/chat-mpp/androidApp/src/main/res/values/strings.xml diff --git a/experimental/examples/chat-mpp/build.gradle.kts b/experimental/examples/chat-mpp/build.gradle.kts index 27c6ada080..0c00883af5 100644 --- a/experimental/examples/chat-mpp/build.gradle.kts +++ b/experimental/examples/chat-mpp/build.gradle.kts @@ -1,217 +1,18 @@ -import org.jetbrains.compose.compose -import org.jetbrains.compose.desktop.application.dsl.TargetFormat -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension -import org.jetbrains.compose.experimental.dsl.IOSDevices - plugins { - id("com.android.application") - kotlin("multiplatform") - id("org.jetbrains.compose") -} - -version = "1.0-SNAPSHOT" - -repositories { - mavenLocal() - google() - mavenCentral() - maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") -} - -kotlin { - android() - jvm("desktop") - js(IR) { - browser() - binaries.executable() - } - macosX64 { - binaries { - executable { - entryPoint = "main" - freeCompilerArgs += listOf( - "-linker-option", "-framework", "-linker-option", "Metal" - ) - } - } - } - macosArm64 { - binaries { - executable { - entryPoint = "main" - freeCompilerArgs += listOf( - "-linker-option", "-framework", "-linker-option", "Metal" - ) - } - } - } - - // Workaround for an issue: - // https://youtrack.jetbrains.com/issue/KT-53561/Invalid-LLVM-module-inlinable-function-call-in-a-function-with-debug-info-must-have-a-dbg-location - // Compose compiler produces nodes without line information sometimes that provokes Kotlin native compiler to report errors. - // TODO: remove workaround when switch to Kotlin 1.8 - val disableKonanVerification = "-Xverify-compiler=false" - - iosX64("uikitX64") { - binaries { - executable() { - entryPoint = "main" - freeCompilerArgs += listOf( - "-linker-option", "-framework", "-linker-option", "Metal", - "-linker-option", "-framework", "-linker-option", "CoreText", - "-linker-option", "-framework", "-linker-option", "CoreGraphics", - disableKonanVerification - ) - } - } - } - iosArm64("uikitArm64") { - binaries { - executable() { - entryPoint = "main" - freeCompilerArgs += listOf( - "-linker-option", "-framework", "-linker-option", "Metal", - "-linker-option", "-framework", "-linker-option", "CoreText", - "-linker-option", "-framework", "-linker-option", "CoreGraphics", - disableKonanVerification - ) - } - } - } - - sourceSets { - val commonMain by getting { - dependencies { - implementation(compose.ui) - implementation(compose.foundation) - implementation(compose.material) - implementation(compose.runtime) - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3") - } - } - - val commonTest by getting { - dependencies { - implementation(kotlin("test-common")) - implementation(kotlin("test-annotations-common")) - } - } - - val androidMain by getting { - dependsOn(commonMain) - kotlin.srcDirs("src/jvmMain/kotlin") - dependencies { - implementation("androidx.appcompat:appcompat:1.5.1") - implementation("androidx.activity:activity-compose:1.5.0") - } - } - - val desktopMain by getting { - dependencies { - implementation(compose.desktop.currentOs) - } - } - - val jsMain by getting { - dependencies { - implementation(compose.web.core) - } - } - - val nativeMain by creating { - dependsOn(commonMain) - } - val macosMain by creating { - dependsOn(nativeMain) - } - val macosX64Main by getting { - dependsOn(macosMain) - } - val macosArm64Main by getting { - dependsOn(macosMain) - } - val uikitMain by creating { - dependsOn(nativeMain) - } - val uikitX64Main by getting { - dependsOn(uikitMain) - } - val uikitArm64Main by getting { - dependsOn(uikitMain) - } - } -} - -compose.desktop { - application { - mainClass = "Main_desktopKt" - } -} - -compose.experimental { - web.application {} - uikit.application { - bundleIdPrefix = "org.jetbrains" - projectName = "Chat" - deployConfigurations { - simulator("IPhone8") { - //Usage: ./gradlew iosDeployIPhone8Debug - device = IOSDevices.IPHONE_8 - } - simulator("IPad") { - //Usage: ./gradlew iosDeployIPadDebug - device = IOSDevices.IPAD_MINI_6th_Gen - } - connectedDevice("Device") { - //First need specify your teamId here, or in local.properties (compose.ios.teamId=***) - //teamId="***" - //Usage: ./gradlew iosDeployDeviceRelease - } - } - } -} - -tasks.withType { - kotlinOptions.jvmTarget = "11" -} - -compose.desktop.nativeApplication { - targets(kotlin.targets.getByName("macosX64")) - distributions { - targetFormats(TargetFormat.Dmg) - packageName = "Chat" - packageVersion = "1.0.0" - } -} - -// a temporary workaround for a bug in jsRun invocation - see https://youtrack.jetbrains.com/issue/KT-48273 -afterEvaluate { - rootProject.extensions.configure { - versions.webpackDevServer.version = "4.0.0" - versions.webpackCli.version = "4.9.0" - nodeVersion = "16.0.0" - } -} - -android { - compileSdk = 32 - - defaultConfig { - minSdk = 26 - targetSdk = 32 - } - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - } - - sourceSets { - named("main") { - manifest.srcFile("src/androidMain/AndroidManifest.xml") - res.srcDirs("src/androidMain/res", "src/commonMain/resources") - } + // this is necessary to avoid the plugins to be loaded multiple times + // in each subproject's classloader + kotlin("jvm") apply false + kotlin("multiplatform") apply false + kotlin("android") apply false + id("com.android.application") apply false + id("com.android.library") apply false + id("org.jetbrains.compose") apply false +} + +allprojects { + repositories { + google() + mavenCentral() + maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") } } diff --git a/experimental/examples/chat-mpp/desktopApp/build.gradle.kts b/experimental/examples/chat-mpp/desktopApp/build.gradle.kts new file mode 100644 index 0000000000..5c28f890f9 --- /dev/null +++ b/experimental/examples/chat-mpp/desktopApp/build.gradle.kts @@ -0,0 +1,22 @@ +plugins { + kotlin("multiplatform") + id("org.jetbrains.compose") +} + +kotlin { + jvm {} + sourceSets { + val jvmMain by getting { + dependencies { + implementation(compose.desktop.currentOs) + implementation(project(":shared")) + } + } + } +} + +compose.desktop { + application { + mainClass = "MainKt" + } +} diff --git a/experimental/examples/chat-mpp/src/desktopMain/kotlin/main.desktop.kt b/experimental/examples/chat-mpp/desktopApp/src/jvmMain/kotlin/Main.kt similarity index 64% rename from experimental/examples/chat-mpp/src/desktopMain/kotlin/main.desktop.kt rename to experimental/examples/chat-mpp/desktopApp/src/jvmMain/kotlin/Main.kt index db2b97a4cb..b65393717e 100644 --- a/experimental/examples/chat-mpp/src/desktopMain/kotlin/main.desktop.kt +++ b/experimental/examples/chat-mpp/desktopApp/src/jvmMain/kotlin/Main.kt @@ -1,5 +1,3 @@ -import androidx.compose.desktop.ui.tooling.preview.Preview -import androidx.compose.runtime.Composable import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import androidx.compose.ui.window.WindowState @@ -10,11 +8,5 @@ fun main() = title = "Chat", state = WindowState(size = DpSize(500.dp, 800.dp)) ) { - ChatApp() + MainView() } - -@Preview -@Composable -fun ChatPreview() { - ChatApp() -} diff --git a/experimental/examples/chat-mpp/gradle.properties b/experimental/examples/chat-mpp/gradle.properties index e6fa271a3c..d589487b61 100644 --- a/experimental/examples/chat-mpp/gradle.properties +++ b/experimental/examples/chat-mpp/gradle.properties @@ -1,17 +1,17 @@ -compose.version=1.3.0-alpha01-dev827 -kotlin.version=1.7.10 -agp.version=7.0.4 -org.gradle.jvmargs=-Xmx3g kotlin.code.style=official +xcodeproj=./iosApp +kotlin.native.cocoapods.generate.wrapper=true +android.useAndroidX=true +org.gradle.jvmargs=-Xmx3g +org.jetbrains.compose.experimental.jscanvas.enabled=true +org.jetbrains.compose.experimental.macos.enabled=true +org.jetbrains.compose.experimental.uikit.enabled=true kotlin.native.cacheKind=none kotlin.native.useEmbeddableCompilerJar=true kotlin.native.enableDependencyPropagation=false kotlin.mpp.enableGranularSourceSetsMetadata=true # Enable kotlin/native experimental memory model kotlin.native.binary.memoryModel=experimental -compose.desktop.verbose=true -android.useAndroidX=true -kotlin.js.webpack.major.version=4 -org.jetbrains.compose.experimental.jscanvas.enabled=true -org.jetbrains.compose.experimental.macos.enabled=true -org.jetbrains.compose.experimental.uikit.enabled=true +kotlin.version=1.7.20 +agp.version=7.1.3 +compose.version=1.2.1 diff --git a/experimental/examples/chat-mpp/iosApp/Chat.xcodeproj/project.pbxproj b/experimental/examples/chat-mpp/iosApp/Chat.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..d25847ef19 --- /dev/null +++ b/experimental/examples/chat-mpp/iosApp/Chat.xcodeproj/project.pbxproj @@ -0,0 +1,380 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 2152FB042600AC8F00CF470E /* iosApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iosApp.swift */; }; + C1FC908188C4E8695729CB06 /* Pods_Chat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DE96E47030356CE6AD9794A /* Pods_Chat.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1EB65E27D2C0F884D0A1A133 /* Pods-Chat.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Chat.debug.xcconfig"; path = "Target Support Files/Pods-Chat/Pods-Chat.debug.xcconfig"; sourceTree = ""; }; + 2152FB032600AC8F00CF470E /* iosApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iosApp.swift; sourceTree = ""; }; + 3D7A606AB0AD7636269BD9D0 /* Pods-Chat.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Chat.release.xcconfig"; path = "Target Support Files/Pods-Chat/Pods-Chat.release.xcconfig"; sourceTree = ""; }; + 7555FF7B242A565900829871 /* Chat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Chat.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 8DE96E47030356CE6AD9794A /* Pods_Chat.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Chat.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + AB3632DC29227652001CCB65 /* TeamId.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = TeamId.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 9964867F0862B4D9FB6ABFC7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C1FC908188C4E8695729CB06 /* Pods_Chat.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 7555FF72242A565900829871 = { + isa = PBXGroup; + children = ( + AB1DB47929225F7C00F7AF9C /* Configuration */, + 7555FF7D242A565900829871 /* iosApp */, + 7555FF7C242A565900829871 /* Products */, + E1DAFBE8E1CFC0878361EF0E /* Pods */, + B62309C7396AD7BF607A63B2 /* Frameworks */, + ); + sourceTree = ""; + }; + 7555FF7C242A565900829871 /* Products */ = { + isa = PBXGroup; + children = ( + 7555FF7B242A565900829871 /* Chat.app */, + ); + name = Products; + sourceTree = ""; + }; + 7555FF7D242A565900829871 /* iosApp */ = { + isa = PBXGroup; + children = ( + 7555FF8C242A565B00829871 /* Info.plist */, + 2152FB032600AC8F00CF470E /* iosApp.swift */, + ); + path = iosApp; + sourceTree = ""; + }; + AB1DB47929225F7C00F7AF9C /* Configuration */ = { + isa = PBXGroup; + children = ( + AB3632DC29227652001CCB65 /* TeamId.xcconfig */, + ); + path = Configuration; + sourceTree = ""; + }; + B62309C7396AD7BF607A63B2 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 8DE96E47030356CE6AD9794A /* Pods_Chat.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + E1DAFBE8E1CFC0878361EF0E /* Pods */ = { + isa = PBXGroup; + children = ( + 1EB65E27D2C0F884D0A1A133 /* Pods-Chat.debug.xcconfig */, + 3D7A606AB0AD7636269BD9D0 /* Pods-Chat.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 7555FF7A242A565900829871 /* Chat */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "Chat" */; + buildPhases = ( + E8D673591E7196AEA2EA10E2 /* [CP] Check Pods Manifest.lock */, + 7555FF77242A565900829871 /* Sources */, + 7555FF79242A565900829871 /* Resources */, + 9964867F0862B4D9FB6ABFC7 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Chat; + productName = iosApp; + productReference = 7555FF7B242A565900829871 /* Chat.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 7555FF73242A565900829871 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1130; + LastUpgradeCheck = 1130; + ORGANIZATIONNAME = org.jetbrains; + TargetAttributes = { + 7555FF7A242A565900829871 = { + CreatedOnToolsVersion = 11.3.1; + }; + }; + }; + buildConfigurationList = 7555FF76242A565900829871 /* Build configuration list for PBXProject "Chat" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 7555FF72242A565900829871; + productRefGroup = 7555FF7C242A565900829871 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 7555FF7A242A565900829871 /* Chat */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 7555FF79242A565900829871 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + E8D673591E7196AEA2EA10E2 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Chat-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 7555FF77242A565900829871 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2152FB042600AC8F00CF470E /* iosApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7555FFA3242A565B00829871 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AB3632DC29227652001CCB65 /* TeamId.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + 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_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 = 14.1; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 7555FFA4242A565B00829871 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AB3632DC29227652001CCB65 /* TeamId.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + 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 = 14.1; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 7555FFA6242A565B00829871 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1EB65E27D2C0F884D0A1A133 /* Pods-Chat.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_ASSET_PATHS = ""; + DEVELOPMENT_TEAM = "${TEAM_ID}"; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = iosApp/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.jetbrains.Chat${TEAM_ID}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 7555FFA7242A565B00829871 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3D7A606AB0AD7636269BD9D0 /* Pods-Chat.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_ASSET_PATHS = ""; + DEVELOPMENT_TEAM = "${TEAM_ID}"; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = iosApp/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 14.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.jetbrains.Chat${TEAM_ID}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7555FF76242A565900829871 /* Build configuration list for PBXProject "Chat" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7555FFA3242A565B00829871 /* Debug */, + 7555FFA4242A565B00829871 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "Chat" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7555FFA6242A565B00829871 /* Debug */, + 7555FFA7242A565B00829871 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 7555FF73242A565900829871 /* Project object */; +} diff --git a/experimental/examples/chat-mpp/iosApp/Configuration/TeamId.xcconfig b/experimental/examples/chat-mpp/iosApp/Configuration/TeamId.xcconfig new file mode 100644 index 0000000000..bf06eb27e9 --- /dev/null +++ b/experimental/examples/chat-mpp/iosApp/Configuration/TeamId.xcconfig @@ -0,0 +1 @@ +TEAM_ID= diff --git a/experimental/examples/chat-mpp/iosApp/Podfile b/experimental/examples/chat-mpp/iosApp/Podfile new file mode 100644 index 0000000000..34ff925f6a --- /dev/null +++ b/experimental/examples/chat-mpp/iosApp/Podfile @@ -0,0 +1,5 @@ +target 'Chat' do + use_frameworks! + platform :ios, '14.1' + pod 'shared', :path => '../shared' +end \ No newline at end of file diff --git a/experimental/examples/chat-mpp/iosApp/iosApp/Info.plist b/experimental/examples/chat-mpp/iosApp/iosApp/Info.plist new file mode 100644 index 0000000000..9a269f5eaa --- /dev/null +++ b/experimental/examples/chat-mpp/iosApp/iosApp/Info.plist @@ -0,0 +1,48 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + + UILaunchScreen + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/experimental/examples/chat-mpp/iosApp/iosApp/iosApp.swift b/experimental/examples/chat-mpp/iosApp/iosApp/iosApp.swift new file mode 100644 index 0000000000..b42016a6fc --- /dev/null +++ b/experimental/examples/chat-mpp/iosApp/iosApp/iosApp.swift @@ -0,0 +1,15 @@ +import UIKit +import shared + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + var window: UIWindow? + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + window = UIWindow(frame: UIScreen.main.bounds) + let mainViewController = Main_iosKt.MainViewController() + window?.rootViewController = mainViewController + window?.makeKeyAndVisible() + return true + } +} diff --git a/experimental/examples/chat-mpp/jsApp/build.gradle.kts b/experimental/examples/chat-mpp/jsApp/build.gradle.kts new file mode 100644 index 0000000000..99f2073a62 --- /dev/null +++ b/experimental/examples/chat-mpp/jsApp/build.gradle.kts @@ -0,0 +1,23 @@ +plugins { + kotlin("multiplatform") + id("org.jetbrains.compose") +} + +kotlin { + js(IR) { + browser() + binaries.executable() + } + sourceSets { + val jsMain by getting { + dependencies { + implementation(project(":shared")) + } + } + } +} + +compose.experimental { + web.application {} +} + diff --git a/experimental/examples/chat-mpp/src/jsMain/kotlin/main.js.kt b/experimental/examples/chat-mpp/jsApp/src/jsMain/kotlin/main.js.kt similarity index 93% rename from experimental/examples/chat-mpp/src/jsMain/kotlin/main.js.kt rename to experimental/examples/chat-mpp/jsApp/src/jsMain/kotlin/main.js.kt index 1fa9d98d97..e9128595e5 100644 --- a/experimental/examples/chat-mpp/src/jsMain/kotlin/main.js.kt +++ b/experimental/examples/chat-mpp/jsApp/src/jsMain/kotlin/main.js.kt @@ -8,7 +8,7 @@ fun main() { onWasmReady { Window("Chat") { Column(modifier = Modifier.fillMaxSize()) { - ChatApp() + MainView() } } } diff --git a/experimental/examples/chat-mpp/src/jsMain/resources/index.html b/experimental/examples/chat-mpp/jsApp/src/jsMain/resources/index.html similarity index 89% rename from experimental/examples/chat-mpp/src/jsMain/resources/index.html rename to experimental/examples/chat-mpp/jsApp/src/jsMain/resources/index.html index 60a68afca1..11dddb763a 100644 --- a/experimental/examples/chat-mpp/src/jsMain/resources/index.html +++ b/experimental/examples/chat-mpp/jsApp/src/jsMain/resources/index.html @@ -10,6 +10,6 @@
- + diff --git a/experimental/examples/chat-mpp/src/jsMain/resources/styles.css b/experimental/examples/chat-mpp/jsApp/src/jsMain/resources/styles.css similarity index 100% rename from experimental/examples/chat-mpp/src/jsMain/resources/styles.css rename to experimental/examples/chat-mpp/jsApp/src/jsMain/resources/styles.css diff --git a/experimental/examples/chat-mpp/run-configurations.png b/experimental/examples/chat-mpp/run-configurations.png new file mode 100644 index 0000000000000000000000000000000000000000..3a904f61c36240ae5ede721c07f09506d7914fbf GIT binary patch literal 21525 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 literal 0 HcmV?d00001 diff --git a/experimental/examples/chat-mpp/settings.gradle.kts b/experimental/examples/chat-mpp/settings.gradle.kts index 3698d56c08..bccac02bc0 100644 --- a/experimental/examples/chat-mpp/settings.gradle.kts +++ b/experimental/examples/chat-mpp/settings.gradle.kts @@ -1,7 +1,5 @@ pluginManagement { repositories { - mavenLocal() - mavenCentral() gradlePluginPortal() maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") google() @@ -9,15 +7,22 @@ pluginManagement { plugins { val kotlinVersion = extra["kotlin.version"] as String + val agpVersion = extra["agp.version"] as String + val composeVersion = extra["compose.version"] as String + + kotlin("jvm").version(kotlinVersion) kotlin("multiplatform").version(kotlinVersion) kotlin("android").version(kotlinVersion) - - val agpVersion = extra["agp.version"] as String + id("com.android.base").version(agpVersion) id("com.android.application").version(agpVersion) - - val composeVersion = extra["compose.version"] as String + id("com.android.library").version(agpVersion) id("org.jetbrains.compose").version(composeVersion) } } rootProject.name = "chat-mpp" + +include(":androidApp") +include(":shared") +include(":desktopApp") +include(":jsApp") diff --git a/experimental/examples/chat-mpp/shared/build.gradle.kts b/experimental/examples/chat-mpp/shared/build.gradle.kts new file mode 100644 index 0000000000..e9c19abb1d --- /dev/null +++ b/experimental/examples/chat-mpp/shared/build.gradle.kts @@ -0,0 +1,111 @@ +plugins { + kotlin("multiplatform") + kotlin("native.cocoapods") + id("com.android.library") + id("org.jetbrains.compose") +} + +version = "1.0-SNAPSHOT" + +kotlin { + android() + + jvm("desktop") + + ios() + iosSimulatorArm64() + + js(IR) { + browser() + } + + macosX64 { + binaries { + executable { + entryPoint = "main" + } + } + } + macosArm64 { + binaries { + executable { + entryPoint = "main" + } + } + } + + cocoapods { + summary = "Shared code for the sample" + homepage = "https://github.com/JetBrains/compose-jb" + ios.deploymentTarget = "14.1" + podfile = project.file("../iosApp/Podfile") + framework { + baseName = "shared" + isStatic = true + } + extraSpecAttributes["resources"] = "['src/commonMain/resources/**', 'src/iosMain/resources/**']" + } + + sourceSets { + val commonMain by getting { + dependencies { + implementation(compose.ui) + implementation(compose.foundation) + implementation(compose.material) + implementation(compose.runtime) + } + } + val commonTest by getting { + dependencies { + implementation(kotlin("test")) + } + } + val androidMain by getting { + dependencies { + implementation("com.google.android.material:material:1.7.0") + } + } + val androidTest by getting { + dependencies { + implementation("junit:junit:4.13.2") + } + } + val iosMain by getting + val iosTest by getting + val iosSimulatorArm64Main by getting { + dependsOn(iosMain) + } + val iosSimulatorArm64Test by getting { + dependsOn(iosTest) + } + + val desktopMain by getting { + dependencies { + implementation(compose.desktop.common) + } + } + + val macosMain by creating { + dependsOn(commonMain) + } + val macosX64Main by getting { + dependsOn(macosMain) + } + val macosArm64Main by getting { + dependsOn(macosMain) + } + } +} + +android { + compileSdk = 33 + sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") + defaultConfig { + minSdk = 24 + targetSdk = 33 + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } +} \ No newline at end of file diff --git a/experimental/examples/chat-mpp/shared/src/androidMain/AndroidManifest.xml b/experimental/examples/chat-mpp/shared/src/androidMain/AndroidManifest.xml new file mode 100644 index 0000000000..45fde946a8 --- /dev/null +++ b/experimental/examples/chat-mpp/shared/src/androidMain/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/experimental/examples/chat-mpp/src/androidMain/kotlin/currentTime.android.kt b/experimental/examples/chat-mpp/shared/src/androidMain/kotlin/currentTime.android.kt similarity index 100% rename from experimental/examples/chat-mpp/src/androidMain/kotlin/currentTime.android.kt rename to experimental/examples/chat-mpp/shared/src/androidMain/kotlin/currentTime.android.kt diff --git a/experimental/examples/chat-mpp/shared/src/androidMain/kotlin/main.android.kt b/experimental/examples/chat-mpp/shared/src/androidMain/kotlin/main.android.kt new file mode 100644 index 0000000000..bef1ebc77c --- /dev/null +++ b/experimental/examples/chat-mpp/shared/src/androidMain/kotlin/main.android.kt @@ -0,0 +1,4 @@ +import androidx.compose.runtime.Composable + +@Composable +fun MainView() = ChatApp() \ No newline at end of file diff --git a/experimental/examples/chat-mpp/src/commonMain/kotlin/ChatApp.kt b/experimental/examples/chat-mpp/shared/src/commonMain/kotlin/ChatApp.kt similarity index 98% rename from experimental/examples/chat-mpp/src/commonMain/kotlin/ChatApp.kt rename to experimental/examples/chat-mpp/shared/src/commonMain/kotlin/ChatApp.kt index bc59e53674..873212b97b 100644 --- a/experimental/examples/chat-mpp/src/commonMain/kotlin/ChatApp.kt +++ b/experimental/examples/chat-mpp/shared/src/commonMain/kotlin/ChatApp.kt @@ -14,7 +14,7 @@ val friendMessages = listOf( ) @Composable -fun ChatApp() { +internal fun ChatApp() { val coroutineScope = rememberCoroutineScope() val store = remember { coroutineScope.createStore() } val state by store.stateFlow.collectAsState() diff --git a/experimental/examples/chat-mpp/src/commonMain/kotlin/Data.kt b/experimental/examples/chat-mpp/shared/src/commonMain/kotlin/Data.kt similarity index 100% rename from experimental/examples/chat-mpp/src/commonMain/kotlin/Data.kt rename to experimental/examples/chat-mpp/shared/src/commonMain/kotlin/Data.kt diff --git a/experimental/examples/chat-mpp/src/commonMain/kotlin/Messages.kt b/experimental/examples/chat-mpp/shared/src/commonMain/kotlin/Messages.kt similarity index 100% rename from experimental/examples/chat-mpp/src/commonMain/kotlin/Messages.kt rename to experimental/examples/chat-mpp/shared/src/commonMain/kotlin/Messages.kt diff --git a/experimental/examples/chat-mpp/src/commonMain/kotlin/Reducer.kt b/experimental/examples/chat-mpp/shared/src/commonMain/kotlin/Reducer.kt similarity index 100% rename from experimental/examples/chat-mpp/src/commonMain/kotlin/Reducer.kt rename to experimental/examples/chat-mpp/shared/src/commonMain/kotlin/Reducer.kt diff --git a/experimental/examples/chat-mpp/src/commonMain/kotlin/SendMessage.kt b/experimental/examples/chat-mpp/shared/src/commonMain/kotlin/SendMessage.kt similarity index 100% rename from experimental/examples/chat-mpp/src/commonMain/kotlin/SendMessage.kt rename to experimental/examples/chat-mpp/shared/src/commonMain/kotlin/SendMessage.kt diff --git a/experimental/examples/chat-mpp/src/commonMain/kotlin/Store.kt b/experimental/examples/chat-mpp/shared/src/commonMain/kotlin/Store.kt similarity index 100% rename from experimental/examples/chat-mpp/src/commonMain/kotlin/Store.kt rename to experimental/examples/chat-mpp/shared/src/commonMain/kotlin/Store.kt diff --git a/experimental/examples/chat-mpp/src/commonMain/kotlin/currentTime.common.kt b/experimental/examples/chat-mpp/shared/src/commonMain/kotlin/currentTime.common.kt similarity index 100% rename from experimental/examples/chat-mpp/src/commonMain/kotlin/currentTime.common.kt rename to experimental/examples/chat-mpp/shared/src/commonMain/kotlin/currentTime.common.kt diff --git a/experimental/examples/chat-mpp/src/desktopMain/kotlin/currentTime.desktop.kt b/experimental/examples/chat-mpp/shared/src/desktopMain/kotlin/currentTime.desktop.kt similarity index 100% rename from experimental/examples/chat-mpp/src/desktopMain/kotlin/currentTime.desktop.kt rename to experimental/examples/chat-mpp/shared/src/desktopMain/kotlin/currentTime.desktop.kt diff --git a/experimental/examples/chat-mpp/shared/src/desktopMain/kotlin/main.desktop.kt b/experimental/examples/chat-mpp/shared/src/desktopMain/kotlin/main.desktop.kt new file mode 100644 index 0000000000..b5f998e2c7 --- /dev/null +++ b/experimental/examples/chat-mpp/shared/src/desktopMain/kotlin/main.desktop.kt @@ -0,0 +1,11 @@ +import androidx.compose.desktop.ui.tooling.preview.Preview +import androidx.compose.runtime.Composable + +@Composable +fun MainView() = ChatApp() + +@Preview +@Composable +fun ChatPreview() { + ChatApp() +} diff --git a/experimental/examples/chat-mpp/src/uikitMain/kotlin/currentTime.uikit.kt b/experimental/examples/chat-mpp/shared/src/iosMain/kotlin/currentTime.ios.kt similarity index 100% rename from experimental/examples/chat-mpp/src/uikitMain/kotlin/currentTime.uikit.kt rename to experimental/examples/chat-mpp/shared/src/iosMain/kotlin/currentTime.ios.kt diff --git a/experimental/examples/chat-mpp/shared/src/iosMain/kotlin/main.ios.kt b/experimental/examples/chat-mpp/shared/src/iosMain/kotlin/main.ios.kt new file mode 100644 index 0000000000..c643166f94 --- /dev/null +++ b/experimental/examples/chat-mpp/shared/src/iosMain/kotlin/main.ios.kt @@ -0,0 +1,8 @@ +import androidx.compose.ui.window.Application +import platform.UIKit.UIViewController + +fun MainViewController(): UIViewController = + Application("Chat") { + ChatApp() + } + diff --git a/experimental/examples/chat-mpp/src/jsMain/kotlin/currentTime.js.kt b/experimental/examples/chat-mpp/shared/src/jsMain/kotlin/currentTime.js.kt similarity index 100% rename from experimental/examples/chat-mpp/src/jsMain/kotlin/currentTime.js.kt rename to experimental/examples/chat-mpp/shared/src/jsMain/kotlin/currentTime.js.kt diff --git a/experimental/examples/chat-mpp/shared/src/jsMain/kotlin/main.js.kt b/experimental/examples/chat-mpp/shared/src/jsMain/kotlin/main.js.kt new file mode 100644 index 0000000000..6ea0df4686 --- /dev/null +++ b/experimental/examples/chat-mpp/shared/src/jsMain/kotlin/main.js.kt @@ -0,0 +1,6 @@ +import androidx.compose.runtime.Composable + +@Composable +fun MainView() = ChatApp() + + diff --git a/experimental/examples/chat-mpp/src/macosMain/kotlin/currentTime.macos.kt b/experimental/examples/chat-mpp/shared/src/macosMain/kotlin/currentTime.macos.kt similarity index 100% rename from experimental/examples/chat-mpp/src/macosMain/kotlin/currentTime.macos.kt rename to experimental/examples/chat-mpp/shared/src/macosMain/kotlin/currentTime.macos.kt diff --git a/experimental/examples/chat-mpp/src/macosMain/kotlin/main.macos.kt b/experimental/examples/chat-mpp/shared/src/macosMain/kotlin/main.macos.kt similarity index 100% rename from experimental/examples/chat-mpp/src/macosMain/kotlin/main.macos.kt rename to experimental/examples/chat-mpp/shared/src/macosMain/kotlin/main.macos.kt diff --git a/experimental/examples/chat-mpp/src/uikitMain/kotlin/main.uikit.kt b/experimental/examples/chat-mpp/src/uikitMain/kotlin/main.uikit.kt deleted file mode 100644 index 100b7b98d2..0000000000 --- a/experimental/examples/chat-mpp/src/uikitMain/kotlin/main.uikit.kt +++ /dev/null @@ -1,8 +0,0 @@ -import androidx.compose.ui.window.Application -import androidx.compose.ui.main.defaultUIKitMain - -fun main() { - defaultUIKitMain("Chat", Application("Chat") { - ChatApp() - }) -}