From 8df2eac926c73a5dd0691b61c17094b08ae8deab Mon Sep 17 00:00:00 2001 From: Ilya Evtushenko Date: Sat, 14 Feb 2026 12:39:04 +0100 Subject: [PATCH 1/2] Update project structure and dependencies --- androidApp/build.gradle.kts | 48 ++++++++++ .../src/main}/AndroidManifest.xml | 0 .../com/jetbrains/basicsample/MainActivity.kt | 8 ++ .../drawable-v24/ic_launcher_foreground.xml | 0 .../res/drawable/ic_launcher_background.xml | 0 .../res/mipmap-anydpi-v26/ic_launcher.xml | 0 .../mipmap-anydpi-v26/ic_launcher_round.xml | 0 .../src/main}/res/mipmap-hdpi/ic_launcher.png | Bin .../res/mipmap-hdpi/ic_launcher_round.png | Bin .../src/main}/res/mipmap-mdpi/ic_launcher.png | Bin .../res/mipmap-mdpi/ic_launcher_round.png | Bin .../main}/res/mipmap-xhdpi/ic_launcher.png | Bin .../res/mipmap-xhdpi/ic_launcher_round.png | Bin .../main}/res/mipmap-xxhdpi/ic_launcher.png | Bin .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin .../main}/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin .../src/main}/res/values/strings.xml | 0 build.gradle.kts | 4 +- composeApp/build.gradle.kts | 70 --------------- .../drawable/compose-multiplatform.xml | 36 -------- .../kotlin/com/jetbrains/basicsample/App.kt | 75 ---------------- gradle.properties | 9 +- gradle/libs.versions.toml | 36 ++++---- gradle/wrapper/gradle-wrapper.properties | 2 +- iosApp/iosApp.xcodeproj/project.pbxproj | 6 +- iosApp/iosApp/ContentView.swift | 8 +- settings.gradle.kts | 4 +- shared/build.gradle.kts | 55 +++++++----- .../com/jetbrains/basicsample/androidTest.kt | 0 .../kotlin/com/jetbrains/basicsample/App.kt | 85 ++++++++++++++++++ 31 files changed, 212 insertions(+), 234 deletions(-) create mode 100644 androidApp/build.gradle.kts rename {composeApp/src/androidMain => androidApp/src/main}/AndroidManifest.xml (100%) rename {composeApp/src/androidMain => androidApp/src/main}/kotlin/com/jetbrains/basicsample/MainActivity.kt (73%) rename {composeApp/src/androidMain => androidApp/src/main}/res/drawable-v24/ic_launcher_foreground.xml (100%) rename {composeApp/src/androidMain => androidApp/src/main}/res/drawable/ic_launcher_background.xml (100%) rename {composeApp/src/androidMain => androidApp/src/main}/res/mipmap-anydpi-v26/ic_launcher.xml (100%) rename {composeApp/src/androidMain => androidApp/src/main}/res/mipmap-anydpi-v26/ic_launcher_round.xml (100%) rename {composeApp/src/androidMain => androidApp/src/main}/res/mipmap-hdpi/ic_launcher.png (100%) rename {composeApp/src/androidMain => androidApp/src/main}/res/mipmap-hdpi/ic_launcher_round.png (100%) rename {composeApp/src/androidMain => androidApp/src/main}/res/mipmap-mdpi/ic_launcher.png (100%) rename {composeApp/src/androidMain => androidApp/src/main}/res/mipmap-mdpi/ic_launcher_round.png (100%) rename {composeApp/src/androidMain => androidApp/src/main}/res/mipmap-xhdpi/ic_launcher.png (100%) rename {composeApp/src/androidMain => androidApp/src/main}/res/mipmap-xhdpi/ic_launcher_round.png (100%) rename {composeApp/src/androidMain => androidApp/src/main}/res/mipmap-xxhdpi/ic_launcher.png (100%) rename {composeApp/src/androidMain => androidApp/src/main}/res/mipmap-xxhdpi/ic_launcher_round.png (100%) rename {composeApp/src/androidMain => androidApp/src/main}/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename {composeApp/src/androidMain => androidApp/src/main}/res/mipmap-xxxhdpi/ic_launcher_round.png (100%) rename {composeApp/src/androidMain => androidApp/src/main}/res/values/strings.xml (100%) delete mode 100644 composeApp/build.gradle.kts delete mode 100644 composeApp/src/androidMain/composeResources/drawable/compose-multiplatform.xml delete mode 100644 composeApp/src/androidMain/kotlin/com/jetbrains/basicsample/App.kt rename shared/src/{androidUnitTest => androidHostTest}/kotlin/com/jetbrains/basicsample/androidTest.kt (100%) create mode 100644 shared/src/commonMain/kotlin/com/jetbrains/basicsample/App.kt diff --git a/androidApp/build.gradle.kts b/androidApp/build.gradle.kts new file mode 100644 index 0000000..a6fd94d --- /dev/null +++ b/androidApp/build.gradle.kts @@ -0,0 +1,48 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + alias(libs.plugins.androidApplication) + alias(libs.plugins.composeMultiplatform) + alias(libs.plugins.composeCompiler) +} + +kotlin { + compilerOptions { + jvmTarget = JvmTarget.JVM_11 + } + dependencies { + implementation(projects.shared) + + implementation(libs.androidx.activity.compose) + + implementation(libs.compose.uiToolingPreview) + debugImplementation(libs.compose.uiTooling) + } +} + +android { + namespace = "com.jetbrains.basicsample" + compileSdk = libs.versions.android.compileSdk.get().toInt() + + defaultConfig { + applicationId = "com.jetbrains.basicsample" + minSdk = libs.versions.android.minSdk.get().toInt() + targetSdk = libs.versions.android.targetSdk.get().toInt() + versionCode = 1 + versionName = "1.0" + } + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } + buildTypes { + getByName("release") { + isMinifyEnabled = false + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } +} diff --git a/composeApp/src/androidMain/AndroidManifest.xml b/androidApp/src/main/AndroidManifest.xml similarity index 100% rename from composeApp/src/androidMain/AndroidManifest.xml rename to androidApp/src/main/AndroidManifest.xml diff --git a/composeApp/src/androidMain/kotlin/com/jetbrains/basicsample/MainActivity.kt b/androidApp/src/main/kotlin/com/jetbrains/basicsample/MainActivity.kt similarity index 73% rename from composeApp/src/androidMain/kotlin/com/jetbrains/basicsample/MainActivity.kt rename to androidApp/src/main/kotlin/com/jetbrains/basicsample/MainActivity.kt index 47cf25c..a883b45 100644 --- a/composeApp/src/androidMain/kotlin/com/jetbrains/basicsample/MainActivity.kt +++ b/androidApp/src/main/kotlin/com/jetbrains/basicsample/MainActivity.kt @@ -4,6 +4,8 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -15,3 +17,9 @@ class MainActivity : ComponentActivity() { } } } + +@Preview +@Composable +fun AppAndroidPreview() { + App() +} diff --git a/composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml b/androidApp/src/main/res/drawable-v24/ic_launcher_foreground.xml similarity index 100% rename from composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml rename to androidApp/src/main/res/drawable-v24/ic_launcher_foreground.xml diff --git a/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml b/androidApp/src/main/res/drawable/ic_launcher_background.xml similarity index 100% rename from composeApp/src/androidMain/res/drawable/ic_launcher_background.xml rename to androidApp/src/main/res/drawable/ic_launcher_background.xml diff --git a/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml b/androidApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml similarity index 100% rename from composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml rename to androidApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml diff --git a/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml b/androidApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml similarity index 100% rename from composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml rename to androidApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml diff --git a/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png b/androidApp/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png rename to androidApp/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png b/androidApp/src/main/res/mipmap-hdpi/ic_launcher_round.png similarity index 100% rename from composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png rename to androidApp/src/main/res/mipmap-hdpi/ic_launcher_round.png diff --git a/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png b/androidApp/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png rename to androidApp/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png b/androidApp/src/main/res/mipmap-mdpi/ic_launcher_round.png similarity index 100% rename from composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png rename to androidApp/src/main/res/mipmap-mdpi/ic_launcher_round.png diff --git a/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png b/androidApp/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png rename to androidApp/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png b/androidApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png similarity index 100% rename from composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png rename to androidApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png b/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png rename to androidApp/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png b/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png similarity index 100% rename from composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png rename to androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png b/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png rename to androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png b/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png similarity index 100% rename from composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png rename to androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/composeApp/src/androidMain/res/values/strings.xml b/androidApp/src/main/res/values/strings.xml similarity index 100% rename from composeApp/src/androidMain/res/values/strings.xml rename to androidApp/src/main/res/values/strings.xml diff --git a/build.gradle.kts b/build.gradle.kts index cf780d5..bfa2a18 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,8 +2,8 @@ plugins { // this is necessary to avoid the plugins to be loaded multiple times // in each subproject's classloader alias(libs.plugins.androidApplication) apply false - alias(libs.plugins.androidLibrary) apply false + alias(libs.plugins.androidMultiplatformLibrary) apply false alias(libs.plugins.composeMultiplatform) apply false alias(libs.plugins.composeCompiler) apply false alias(libs.plugins.kotlinMultiplatform) apply false -} \ No newline at end of file +} diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts deleted file mode 100644 index 2fbcb84..0000000 --- a/composeApp/build.gradle.kts +++ /dev/null @@ -1,70 +0,0 @@ -import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi -import org.jetbrains.kotlin.gradle.dsl.JvmTarget - -plugins { - alias(libs.plugins.kotlinMultiplatform) - alias(libs.plugins.androidApplication) - alias(libs.plugins.composeMultiplatform) - alias(libs.plugins.composeCompiler) -} - -kotlin { - androidTarget { - @OptIn(ExperimentalKotlinGradlePluginApi::class) - compilerOptions { - jvmTarget.set(JvmTarget.JVM_11) - } - } - - sourceSets { - androidMain.dependencies { - implementation(compose.preview) - implementation(libs.androidx.activity.compose) - } - commonMain.dependencies { - implementation(compose.runtime) - implementation(compose.foundation) - implementation(compose.material3) - implementation(compose.ui) - implementation(compose.components.resources) - implementation(compose.components.uiToolingPreview) - implementation(libs.androidx.lifecycle.viewmodel) - implementation(libs.androidx.lifecycle.runtimeCompose) - implementation(projects.shared) - } - commonTest.dependencies { - implementation(libs.kotlin.test) - } - } -} - -android { - namespace = "com.jetbrains.basicsample" - compileSdk = libs.versions.android.compileSdk.get().toInt() - - defaultConfig { - applicationId = "com.jetbrains.basicsample" - minSdk = libs.versions.android.minSdk.get().toInt() - targetSdk = libs.versions.android.targetSdk.get().toInt() - versionCode = 1 - versionName = "1.0" - } - packaging { - resources { - excludes += "/META-INF/{AL2.0,LGPL2.1}" - } - } - buildTypes { - getByName("release") { - isMinifyEnabled = false - } - } - compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - } -} - -dependencies { - debugImplementation(compose.uiTooling) -} diff --git a/composeApp/src/androidMain/composeResources/drawable/compose-multiplatform.xml b/composeApp/src/androidMain/composeResources/drawable/compose-multiplatform.xml deleted file mode 100644 index c0bcfb2..0000000 --- a/composeApp/src/androidMain/composeResources/drawable/compose-multiplatform.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/composeApp/src/androidMain/kotlin/com/jetbrains/basicsample/App.kt b/composeApp/src/androidMain/kotlin/com/jetbrains/basicsample/App.kt deleted file mode 100644 index 2eb7750..0000000 --- a/composeApp/src/androidMain/kotlin/com/jetbrains/basicsample/App.kt +++ /dev/null @@ -1,75 +0,0 @@ -package com.jetbrains.basicsample - -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.material3.TextField -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.unit.dp -import org.jetbrains.compose.ui.tooling.preview.Preview - -@Composable -@Preview -fun App() { - MaterialTheme { - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - Column( - horizontalAlignment = Alignment.Start, - ) { - Text(greet(), Modifier.padding(8.dp)) - - var firstNumber by rememberSaveable { mutableStateOf("") } - var secondNumber by rememberSaveable { mutableStateOf("") } - - Row(verticalAlignment = Alignment.CenterVertically) { - TextField( - value = firstNumber, - onValueChange = { firstNumber = it }, - modifier = Modifier.width(100.dp), - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), - ) - Text(text = "+", modifier = Modifier.padding(4.dp)) - TextField( - value = secondNumber, - onValueChange = { secondNumber = it }, - modifier = Modifier.width(100.dp), - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), - ) - - val first = firstNumber.toIntOrNull() - val second = secondNumber.toIntOrNull() - Text( - text = if (first != null && second != null) { - "= ${Calculator.sum(first, second)}" - } else { - "= \uD83E\uDD14" - }, - modifier = Modifier - .width(100.dp) - .padding(4.dp) - ) - } - } - } - } -} - -fun greet(): String { - return Greeting().greeting() -} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 93239c3..4a49d61 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,11 +1,12 @@ +#Kotlin kotlin.code.style=official +kotlin.daemon.jvmargs=-Xmx3072M #Gradle -org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M" +org.gradle.jvmargs=-Xmx4096M -Dfile.encoding=UTF-8 +org.gradle.configuration-cache=true +org.gradle.caching=true #Android android.nonTransitiveRClass=true android.useAndroidX=true - -#Kotlin Multiplatform -kotlin.mpp.enableCInteropCommonization=true \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0e6a192..55d9a5d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,18 +1,18 @@ [versions] -agp = "8.10.0" -android-compileSdk = "35" +agp = "9.0.1" +android-compileSdk = "36" android-minSdk = "24" -android-targetSdk = "35" -androidx-activity = "1.10.1" +android-targetSdk = "36" +androidx-activity = "1.12.4" androidx-appcompat = "1.7.1" -androidx-constraintlayout = "2.2.1" -androidx-core = "1.16.0" -androidx-espresso = "3.6.1" -androidx-lifecycle = "2.9.1" -androidx-testExt = "1.2.1" -composeMultiplatform = "1.8.2" +androidx-core = "1.17.0" +androidx-espresso = "3.7.0" +androidx-lifecycle = "2.9.6" +androidx-testExt = "1.3.0" +composeMultiplatform = "1.10.1" junit = "4.13.2" -kotlin = "2.2.0" +kotlin = "2.3.10" +material3 = "1.10.0-alpha05" [libraries] kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } @@ -22,14 +22,20 @@ androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx androidx-testExt-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-testExt" } androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-espresso" } androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" } -androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "androidx-constraintlayout" } androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" } -androidx-lifecycle-viewmodel = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel", version.ref = "androidx-lifecycle" } +compose-uiTooling = { module = "org.jetbrains.compose.ui:ui-tooling", version.ref = "composeMultiplatform" } +androidx-lifecycle-viewmodelCompose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } androidx-lifecycle-runtimeCompose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidx-lifecycle" } +compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "composeMultiplatform" } +compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "composeMultiplatform" } +compose-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "material3" } +compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "composeMultiplatform" } +compose-components-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "composeMultiplatform" } +compose-uiToolingPreview = { module = "org.jetbrains.compose.ui:ui-tooling-preview", version.ref = "composeMultiplatform" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" } -androidLibrary = { id = "com.android.library", version.ref = "agp" } +androidMultiplatformLibrary = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" } composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "composeMultiplatform" } composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } -kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } \ No newline at end of file +kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37f853b..2e11132 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj index 75401df..03c0a38 100644 --- a/iosApp/iosApp.xcodeproj/project.pbxproj +++ b/iosApp/iosApp.xcodeproj/project.pbxproj @@ -282,7 +282,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "cd \"$SRCROOT/..\"\n./gradlew :shared:embedAndSignAppleFrameworkForXcode\n"; + shellScript = "if [ \"YES\" = \"$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED\" ]; then\n echo \"Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \\\"YES\\\"\"\n exit 0\nfi\ncd \"$SRCROOT/..\"\n./gradlew :shared:embedAndSignAppleFrameworkForXcode\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -461,7 +461,7 @@ OTHER_LDFLAGS = ( "$(inherited)", "-framework", - shared, + Shared, ); PRODUCT_BUNDLE_IDENTIFIER = orgIdentifier.iosApp; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -487,7 +487,7 @@ OTHER_LDFLAGS = ( "$(inherited)", "-framework", - shared, + Shared, ); PRODUCT_BUNDLE_IDENTIFIER = orgIdentifier.iosApp; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/iosApp/iosApp/ContentView.swift b/iosApp/iosApp/ContentView.swift index 92f63ec..ccf5e50 100644 --- a/iosApp/iosApp/ContentView.swift +++ b/iosApp/iosApp/ContentView.swift @@ -5,8 +5,8 @@ struct ContentView: View { let calculator = Calculator.Companion() let greet = Greeting().greeting() - @State private var firstNum: String = "0" - @State private var secondNum: String = "0" + @State private var firstNum: String = "" + @State private var secondNum: String = "" private var sum: String { if let firstNum = Int32(firstNum), let secondNum = Int32(secondNum) { return String(calculator.sum(a: firstNum, b: secondNum)) @@ -22,12 +22,12 @@ struct ContentView: View { TextField("A", text: $firstNum) .keyboardType(.numberPad) .multilineTextAlignment(.center) - .frame(width: 30) + .frame(width: 100) Text("+") TextField("B", text: $secondNum) .keyboardType(.numberPad) .multilineTextAlignment(.center) - .frame(width: 30) + .frame(width: 100) Text("=") Text(sum) } diff --git a/settings.gradle.kts b/settings.gradle.kts index 20eadb9..7ccc537 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,5 +28,5 @@ dependencyResolutionManagement { } } -include(":composeApp") -include(":shared") \ No newline at end of file +include(":androidApp") +include(":shared") diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 7322963..cc55307 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -1,21 +1,14 @@ -import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { alias(libs.plugins.kotlinMultiplatform) - alias(libs.plugins.androidLibrary) + alias(libs.plugins.androidMultiplatformLibrary) + alias(libs.plugins.composeMultiplatform) + alias(libs.plugins.composeCompiler) } kotlin { - androidTarget { - @OptIn(ExperimentalKotlinGradlePluginApi::class) - compilerOptions { - jvmTarget.set(JvmTarget.JVM_11) - } - } - listOf( - iosX64(), iosArm64(), iosSimulatorArm64() ).forEach { iosTarget -> @@ -25,9 +18,35 @@ kotlin { } } + androidLibrary { + namespace = "com.jetbrains.basicsample.shared" + compileSdk = libs.versions.android.compileSdk.get().toInt() + minSdk = libs.versions.android.minSdk.get().toInt() + + compilerOptions { + jvmTarget = JvmTarget.JVM_11 + } + androidResources { + enable = true + } + withHostTest { + isIncludeAndroidResources = true + } + } + sourceSets { + androidMain.dependencies { + implementation(libs.compose.uiToolingPreview) + } commonMain.dependencies { - // put your Multiplatform dependencies here + implementation(libs.compose.runtime) + implementation(libs.compose.foundation) + implementation(libs.compose.material3) + implementation(libs.compose.ui) + implementation(libs.compose.components.resources) + implementation(libs.compose.uiToolingPreview) + implementation(libs.androidx.lifecycle.viewmodelCompose) + implementation(libs.androidx.lifecycle.runtimeCompose) } commonTest.dependencies { implementation(libs.kotlin.test) @@ -35,14 +54,6 @@ kotlin { } } -android { - namespace = "com.jetbrains.basicsample.shared" - compileSdk = libs.versions.android.compileSdk.get().toInt() - compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - } - defaultConfig { - minSdk = libs.versions.android.minSdk.get().toInt() - } -} \ No newline at end of file +dependencies { + androidRuntimeClasspath(libs.compose.uiTooling) +} diff --git a/shared/src/androidUnitTest/kotlin/com/jetbrains/basicsample/androidTest.kt b/shared/src/androidHostTest/kotlin/com/jetbrains/basicsample/androidTest.kt similarity index 100% rename from shared/src/androidUnitTest/kotlin/com/jetbrains/basicsample/androidTest.kt rename to shared/src/androidHostTest/kotlin/com/jetbrains/basicsample/androidTest.kt diff --git a/shared/src/commonMain/kotlin/com/jetbrains/basicsample/App.kt b/shared/src/commonMain/kotlin/com/jetbrains/basicsample/App.kt new file mode 100644 index 0000000..2114ac6 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/jetbrains/basicsample/App.kt @@ -0,0 +1,85 @@ +package com.jetbrains.basicsample + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.text.input.TextFieldLineLimits +import androidx.compose.foundation.text.input.rememberTextFieldState +import androidx.compose.material3.LocalTextStyle +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp + +@Composable +@Preview +fun App() { + MaterialTheme { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Text( + text = greet(), + modifier = Modifier.padding(8.dp) + ) + + val firstNumber = rememberTextFieldState(initialText = "") + val secondNumber = rememberTextFieldState(initialText = "") + + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceEvenly + ) { + TextField( + state = firstNumber, + placeholder = { Text("A") }, + modifier = Modifier.width(100.dp), + lineLimits = TextFieldLineLimits.SingleLine, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + ) + Text(text = "+", modifier = Modifier.padding(4.dp)) + TextField( + state = secondNumber, + placeholder = { Text("B") }, + modifier = Modifier.width(100.dp), + lineLimits = TextFieldLineLimits.SingleLine, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + ) + + val first = firstNumber.text.toString().toIntOrNull() + val second = secondNumber.text.toString().toIntOrNull() + Text( + text = if (first != null && second != null) { + "= ${Calculator.sum(first, second)}" + } else { + "= 🤔" + }, + modifier = Modifier.padding(4.dp) + ) + } + } + } +} + +fun greet(): String { + return Greeting().greeting() +} From ffd3759d74222f4cdb57f18dca26178e8674a5a2 Mon Sep 17 00:00:00 2001 From: Ilya Evtushenko Date: Tue, 17 Feb 2026 13:16:21 +0100 Subject: [PATCH 2/2] Add build action example --- .github/actions/gradle-setup/action.yml | 12 ++++ .github/workflows/build.yml | 80 +++++++++++++++++++++++++ .github/workflows/push.yml | 16 ----- 3 files changed, 92 insertions(+), 16 deletions(-) create mode 100644 .github/actions/gradle-setup/action.yml create mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/push.yml diff --git a/.github/actions/gradle-setup/action.yml b/.github/actions/gradle-setup/action.yml new file mode 100644 index 0000000..cb7d0e3 --- /dev/null +++ b/.github/actions/gradle-setup/action.yml @@ -0,0 +1,12 @@ +name: gradle-setup +description: Setup the Java and Gradle +runs: + using: "composite" + steps: + - name: Setup Java + uses: actions/setup-java@v4.0.0 + with: + java-version: "17" + distribution: "temurin" + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5.0.0 \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..73fc3d0 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,80 @@ +name: Build + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: + +env: + GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx4096M -Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.caching=true" + +jobs: + test: + name: Run Tests + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Gradle setup + uses: ./.github/actions/gradle-setup + + - name: Run unit tests + run: ./gradlew :shared:allTests + + - name: Upload test reports + uses: actions/upload-artifact@v4 + with: + name: test-reports + path: "**/build/reports/tests/" + + build-android: + name: Build Android + runs-on: ubuntu-latest + needs: test + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Gradle setup + uses: ./.github/actions/gradle-setup + + - name: Build Android debug APK + run: ./gradlew :androidApp:assembleDebug + + - name: Upload Android debug APK + uses: actions/upload-artifact@v4 + with: + name: android-apk + path: androidApp/build/outputs/apk/debug/*.apk + + + build-ios: + name: Build iOS simulator app + runs-on: macos-latest + needs: test + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Gradle setup + uses: ./.github/actions/gradle-setup + + - name: Build iOS simulator app + run: | + xcodebuild build \ + -project iosApp/iosApp.xcodeproj \ + -configuration Debug \ + -scheme iosApp \ + -sdk iphonesimulator \ + -arch arm64 \ + -derivedDataPath ./build \ + -verbose + + - name: Upload App Folder + uses: actions/upload-artifact@v4 + with: + name: iphonesimulator-app + path: build/Build/Products/Debug-iphonesimulator/* diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml deleted file mode 100644 index f2fb0e9..0000000 --- a/.github/workflows/push.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: CI - -on: [push] - -jobs: - build: - runs-on: macos-latest - steps: - - uses: actions/checkout@v1 - - name: Setup Java JDK - uses: actions/setup-java@v2.1.0 - with: - distribution: 'adopt' - java-version: '17' - - name: Build the project - run: ./gradlew assemble