diff --git a/build.gradle.kts b/build.gradle.kts index fef4f83..c7d87c7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,7 @@ plugins { alias(libs.plugins.kotlin.multiplatform) apply false alias(libs.plugins.kotlin.compose) apply false + alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.android.application) apply false alias(libs.plugins.compose) apply false } \ No newline at end of file diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index d092629..c2a6a75 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -25,6 +25,12 @@ private val gitCommitsCount: Int by lazy { } kotlin { + androidTarget { + @OptIn(ExperimentalKotlinGradlePluginApi::class) + compilerOptions { + jvmTarget.set(JvmTarget.JVM_11) + } + } js { moduleName = "composeApp" browser { @@ -51,12 +57,6 @@ kotlin { } binaries.executable() } - androidTarget { - @OptIn(ExperimentalKotlinGradlePluginApi::class) - compilerOptions { - jvmTarget.set(JvmTarget.JVM_11) - } - } jvm() listOf( iosX64(), diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 388a8ac..2de863c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,11 +3,15 @@ min-sdk = "31" compile-sdk = "35" target-sdk = "35" agp = "8.7.2" + androidx-activity = "1.9.3" androidx-core-splashscreen = "1.0.1" androidx-lifecycle = "2.8.4" +wearCompose = "1.4.0" +composeUiTooling = "1.4.0" google-material = "1.12.0" +google-horologist = "0.6.20" jetbrains-compose = "1.7.1" jetbrains-androidx-navigation-compose = "2.8.0-alpha10" @@ -36,6 +40,7 @@ kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version. kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" } google-material = { module = "com.google.android.material:material", version.ref = "google-material" } +google-horologist-compose-layout = { module = "com.google.android.horologist:horologist-compose-layout", version.ref = "google-horologist" } jetbrains-androidx-navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "jetbrains-androidx-navigation-compose" } jetbrains-androidx-lifecycle-viewmodel-compose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "jetbrains-androidx-lifecycle-viewmodel-compose" } @@ -45,6 +50,10 @@ androidx-activity-compose = { module = "androidx.activity:activity-compose", ver androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "androidx-core-splashscreen" } androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" } androidx-lifecycle-runtime-compose = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidx-lifecycle" } +androidx-wear-compose-foundation = { module = "androidx.wear.compose:compose-foundation", version.ref = "wearCompose" } +androidx-wear-compose-material = { module = "androidx.wear.compose:compose-material", version.ref = "wearCompose" } +androidx-wear-compose-navigation = { module = "androidx.wear.compose:compose-navigation", version.ref = "wearCompose" } +androidx-wear-ui-tooling = { module = "androidx.wear.compose:compose-ui-tooling", version.ref = "composeUiTooling" } coil3-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil3" } coil3-network-ktor = { module = "io.coil-kt.coil3:coil-network-ktor", version.ref = "coil3" } @@ -67,6 +76,7 @@ napier = { module = "io.github.aakira:napier", version.ref = "napier" } kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } android-application = { id = "com.android.application", version.ref = "agp" } compose = { id = "org.jetbrains.compose", version.ref = "jetbrains-compose" } buildkonfig = { id = "com.codingfeline.buildkonfig", version.ref = "buildkonfig" } \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 7ce3f42..571588a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,4 +30,5 @@ dependencyResolutionManagement { } } -include(":composeApp") \ No newline at end of file +include(":composeApp") +include(":wearApp") \ No newline at end of file diff --git a/wearApp/build.gradle.kts b/wearApp/build.gradle.kts new file mode 100644 index 0000000..2b8e3ce --- /dev/null +++ b/wearApp/build.gradle.kts @@ -0,0 +1,67 @@ +@file:OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class) + +import org.apache.commons.io.output.ByteArrayOutputStream +import java.nio.charset.Charset + +plugins { + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.kotlin.compose) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.android.application) + alias(libs.plugins.compose) +} + +private val gitCommitsCount: Int by lazy { + val stdout = ByteArrayOutputStream() + rootProject.exec { + commandLine("git", "rev-list", "--count", "HEAD") + standardOutput = stdout + } + stdout.toString(Charset.defaultCharset()).trim().toInt() +} + +kotlin { + jvmToolchain(21) +} + +android { + namespace = "org.michaelbel.template" + compileSdk = libs.versions.compile.sdk.get().toInt() + + defaultConfig { + applicationId = "org.michaelbel.template" + minSdk = libs.versions.min.sdk.get().toInt() + targetSdk = libs.versions.target.sdk.get().toInt() + versionName = "1.0.0" + versionCode = gitCommitsCount + } + buildFeatures { + compose = true + } +} + +base { + archivesName.set("KmpTemplate-v${android.defaultConfig.versionName}(${android.defaultConfig.versionCode})") +} + +dependencies { + implementation(libs.androidx.core.splashscreen) + implementation(libs.google.material) + implementation(libs.google.horologist.compose.layout) + implementation(libs.androidx.activity.compose) + implementation(libs.androidx.wear.compose.foundation) + implementation(libs.androidx.wear.compose.material) + implementation(libs.androidx.wear.compose.navigation) +} + +tasks.register("printVersionName") { + doLast { + println(android.defaultConfig.versionName) + } +} + +tasks.register("printVersionCode") { + doLast { + println(android.defaultConfig.versionCode.toString()) + } +} \ No newline at end of file diff --git a/wearApp/src/main/AndroidManifest.xml b/wearApp/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c23ae4a --- /dev/null +++ b/wearApp/src/main/AndroidManifest.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/wearApp/src/main/java/org/michaelbel/template/Template.wearos.kt b/wearApp/src/main/java/org/michaelbel/template/Template.wearos.kt new file mode 100644 index 0000000..1367dbe --- /dev/null +++ b/wearApp/src/main/java/org/michaelbel/template/Template.wearos.kt @@ -0,0 +1,4 @@ +package org.michaelbel.template + +val TemplateName: String + get() = "WearOS Template" \ No newline at end of file diff --git a/wearApp/src/main/java/org/michaelbel/template/WearApplication.kt b/wearApp/src/main/java/org/michaelbel/template/WearApplication.kt new file mode 100644 index 0000000..ec22290 --- /dev/null +++ b/wearApp/src/main/java/org/michaelbel/template/WearApplication.kt @@ -0,0 +1,10 @@ +package org.michaelbel.template + +import android.app.Application + +class WearApplication: Application() { + + override fun onCreate() { + super.onCreate() + } +} \ No newline at end of file diff --git a/wearApp/src/main/java/org/michaelbel/template/WearMainActivity.kt b/wearApp/src/main/java/org/michaelbel/template/WearMainActivity.kt new file mode 100644 index 0000000..2ca5a1e --- /dev/null +++ b/wearApp/src/main/java/org/michaelbel/template/WearMainActivity.kt @@ -0,0 +1,105 @@ +@file:OptIn(ExperimentalHorologistApi::class) + +package org.michaelbel.template + +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.compose.runtime.Composable +import androidx.activity.ComponentActivity +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import androidx.navigation.NavHostController +import androidx.wear.compose.material.MaterialTheme +import androidx.wear.compose.material.Text +import androidx.wear.compose.navigation.SwipeDismissableNavHost +import androidx.wear.compose.navigation.composable +import androidx.wear.compose.navigation.rememberSwipeDismissableNavController +import com.google.android.horologist.annotations.ExperimentalHorologistApi +import com.google.android.horologist.compose.layout.AppScaffold +import com.google.android.horologist.compose.layout.ScreenScaffold +import com.google.android.horologist.compose.layout.rememberColumnState + +class WearMainActivity: ComponentActivity() { + + private lateinit var navController: NavHostController + + override fun onCreate(savedInstanceState: Bundle?) { + installSplashScreen() + super.onCreate(savedInstanceState) + setContent { + navController = rememberSwipeDismissableNavController() + WearApp( + navController = navController + ) + } + } +} + +@Composable +fun WearApp( + navController: NavHostController +) { + AppScaffold { + SwipeDismissableNavHost( + navController = navController, + startDestination = Screen.Home.route + ) { + composable( + route = Screen.Home.route + ) { + val scrollState = rememberColumnState() + ScreenScaffold( + modifier = Modifier.fillMaxSize(), + scrollState = scrollState + ) { + + Text( + text = "Home", + modifier = Modifier.fillMaxSize().align(Alignment.Center), + style = MaterialTheme.typography.title1, + textAlign = TextAlign.Center + ) + } + } + composable( + route = Screen.Chat.route + ) { + val scrollState = rememberColumnState() + ScreenScaffold( + scrollState = scrollState + ) { + Text( + text = "Chat", + style = MaterialTheme.typography.title1, + textAlign = TextAlign.Center + ) + } + } + composable( + route = Screen.Settings.route + ) { + val scrollState = rememberColumnState() + ScreenScaffold( + scrollState = scrollState + ) { + Text( + text = "Settings", + style = MaterialTheme.typography.title1, + textAlign = TextAlign.Center + ) + } + } + } + } +} + +sealed class Screen( + val route: String +) { + data object Home: Screen("home") + data object Chat: Screen("chat") + data object Settings: Screen("settings") +} \ No newline at end of file diff --git a/wearApp/src/main/res/drawable-v24/ic_launcher_foreground.xml b/wearApp/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/wearApp/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/wearApp/src/main/res/drawable/branding_image.xml b/wearApp/src/main/res/drawable/branding_image.xml new file mode 100644 index 0000000..61f7b1f --- /dev/null +++ b/wearApp/src/main/res/drawable/branding_image.xml @@ -0,0 +1,9 @@ + + + diff --git a/wearApp/src/main/res/drawable/ic_launcher_background.xml b/wearApp/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..e93e11a --- /dev/null +++ b/wearApp/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/wearApp/src/main/res/drawable/ic_splashscreen.xml b/wearApp/src/main/res/drawable/ic_splashscreen.xml new file mode 100644 index 0000000..9ebcc22 --- /dev/null +++ b/wearApp/src/main/res/drawable/ic_splashscreen.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/wearApp/src/main/res/drawable/ic_splashscreen_branding.xml b/wearApp/src/main/res/drawable/ic_splashscreen_branding.xml new file mode 100644 index 0000000..6cd5122 --- /dev/null +++ b/wearApp/src/main/res/drawable/ic_splashscreen_branding.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/wearApp/src/main/res/drawable/ic_splashscreen_branding_layer_list.xml b/wearApp/src/main/res/drawable/ic_splashscreen_branding_layer_list.xml new file mode 100644 index 0000000..32864d0 --- /dev/null +++ b/wearApp/src/main/res/drawable/ic_splashscreen_branding_layer_list.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/wearApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/wearApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/wearApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/wearApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/wearApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/wearApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/wearApp/src/main/res/mipmap-hdpi/ic_launcher.png b/wearApp/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..a571e60 Binary files /dev/null and b/wearApp/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/wearApp/src/main/res/mipmap-hdpi/ic_launcher_round.png b/wearApp/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..61da551 Binary files /dev/null and b/wearApp/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/wearApp/src/main/res/mipmap-mdpi/ic_launcher.png b/wearApp/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..c41dd28 Binary files /dev/null and b/wearApp/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/wearApp/src/main/res/mipmap-mdpi/ic_launcher_round.png b/wearApp/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..db5080a Binary files /dev/null and b/wearApp/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/wearApp/src/main/res/mipmap-xhdpi/ic_launcher.png b/wearApp/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..6dba46d Binary files /dev/null and b/wearApp/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/wearApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/wearApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..da31a87 Binary files /dev/null and b/wearApp/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/wearApp/src/main/res/mipmap-xxhdpi/ic_launcher.png b/wearApp/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..15ac681 Binary files /dev/null and b/wearApp/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/wearApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/wearApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..b216f2d Binary files /dev/null and b/wearApp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/wearApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/wearApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..f25a419 Binary files /dev/null and b/wearApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/wearApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/wearApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..e96783c Binary files /dev/null and b/wearApp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/wearApp/src/main/res/values-night/colors.xml b/wearApp/src/main/res/values-night/colors.xml new file mode 100644 index 0000000..908cbfb --- /dev/null +++ b/wearApp/src/main/res/values-night/colors.xml @@ -0,0 +1,32 @@ + + + #1C1B1F + #CCC2DC + + #1C1B1F + #F2B8B5 + #8C1D18 + #313033 + #6750A4 + #E6E1E5 + #E6E1E5 + #601410 + #F2B8B5 + #381E72 + #EADDFF + #332D41 + #E8DEF8 + #E6E1E5 + #CAC4D0 + #492532 + #FFD8E4 + #938F99 + #D0BCFF + #4F378B + #CCC2DC + #4A4458 + #1C1B1F + #49454F + #EFB8C8 + #633B48 + \ No newline at end of file diff --git a/wearApp/src/main/res/values-night/themes.xml b/wearApp/src/main/res/values-night/themes.xml new file mode 100644 index 0000000..df629eb --- /dev/null +++ b/wearApp/src/main/res/values-night/themes.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/wearApp/src/main/res/values/colors.xml b/wearApp/src/main/res/values/colors.xml new file mode 100644 index 0000000..169812c --- /dev/null +++ b/wearApp/src/main/res/values/colors.xml @@ -0,0 +1,32 @@ + + + #FFFBFE + #625B71 + + #FFFBFE + #B3261E + #F9DEDC + #F4EFF4 + #D0BCFF + #313033 + #1C1B1F + #FFFFFF + #410E0B + #FFFFFF + #21005D + #FFFFFF + #1D192B + #1C1B1F + #49454F + #FFFFFF + #31111D + #79747E + #6750A4 + #EADDFF + #625B71 + #E8DEF8 + #FFFBFE + #E7E0EC + #7D5260 + #FFD8E4 + \ No newline at end of file diff --git a/wearApp/src/main/res/values/strings.xml b/wearApp/src/main/res/values/strings.xml new file mode 100644 index 0000000..d02d321 --- /dev/null +++ b/wearApp/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + KmpTemplate + \ No newline at end of file diff --git a/wearApp/src/main/res/values/themes.xml b/wearApp/src/main/res/values/themes.xml new file mode 100644 index 0000000..1808cdd --- /dev/null +++ b/wearApp/src/main/res/values/themes.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file