From bb79a8a2a443eeaa7a2bf457d74ef6b7aac5fde6 Mon Sep 17 00:00:00 2001 From: stslex Date: Fri, 24 Nov 2023 07:49:29 +0300 Subject: [PATCH 1/4] remove unused modules --- composeApp/build.gradle.kts | 1 - core/core/build.gradle.kts | 8 +---- core/ui/build.gradle.kts | 6 ---- feature/home/build.gradle.kts | 6 ---- .../com/stslex/feature/home/HomeScreen.kt | 15 ++++---- .../resources/compose-multiplatform.xml | 36 ------------------- gradle/libs.versions.toml | 8 ++--- server/build.gradle.kts | 21 ----------- .../kotlin/com/stslex/wizard/Application.kt | 22 ------------ server/src/main/resources/logback.xml | 12 ------- settings.gradle.kts | 2 -- shared/build.gradle.kts | 34 ------------------ .../androidMain/kotlin/Platform.android.kt | 7 ---- shared/src/commonMain/kotlin/Constants.kt | 1 - shared/src/commonMain/kotlin/Greeting.kt | 7 ---- shared/src/commonMain/kotlin/Platform.kt | 5 --- shared/src/iosMain/kotlin/Platform.ios.kt | 7 ---- shared/src/jvmMain/kotlin/Platform.jvm.kt | 5 --- 18 files changed, 11 insertions(+), 192 deletions(-) delete mode 100644 feature/home/src/commonMain/resources/compose-multiplatform.xml delete mode 100644 server/build.gradle.kts delete mode 100644 server/src/main/kotlin/com/stslex/wizard/Application.kt delete mode 100644 server/src/main/resources/logback.xml delete mode 100644 shared/build.gradle.kts delete mode 100644 shared/src/androidMain/kotlin/Platform.android.kt delete mode 100644 shared/src/commonMain/kotlin/Constants.kt delete mode 100644 shared/src/commonMain/kotlin/Greeting.kt delete mode 100644 shared/src/commonMain/kotlin/Platform.kt delete mode 100644 shared/src/iosMain/kotlin/Platform.ios.kt delete mode 100644 shared/src/jvmMain/kotlin/Platform.jvm.kt diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 7e74ae51..c29fb014 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -45,7 +45,6 @@ kotlin { implementation(project(":core:ui")) implementation(project(":feature:home")) - implementation(projects.shared) implementation(compose.runtime) implementation(compose.foundation) implementation(compose.material) diff --git a/core/core/build.gradle.kts b/core/core/build.gradle.kts index aef9daf8..f0bfa61d 100644 --- a/core/core/build.gradle.kts +++ b/core/core/build.gradle.kts @@ -14,7 +14,7 @@ kotlin { } jvm("desktop") - + listOf( iosX64(), iosArm64(), @@ -27,20 +27,14 @@ kotlin { } sourceSets { - val desktopMain by getting - commonMain.dependencies { implementation(libs.kermit) - implementation(projects.shared) implementation(compose.runtime) implementation(compose.foundation) } commonTest.dependencies { implementation(libs.kotlin.test) } - desktopMain.dependencies { - implementation(compose.desktop.currentOs) - } } } diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index 184ee588..c4d71f5b 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -29,12 +29,9 @@ kotlin { } sourceSets { - val desktopMain by getting - commonMain.dependencies { implementation(project(":core:core")) - implementation(projects.shared) implementation(compose.runtime) implementation(compose.foundation) implementation(compose.material) @@ -44,9 +41,6 @@ kotlin { commonTest.dependencies { implementation(libs.kotlin.test) } - desktopMain.dependencies { - implementation(compose.desktop.currentOs) - } } } diff --git a/feature/home/build.gradle.kts b/feature/home/build.gradle.kts index f2be90b6..976105fa 100644 --- a/feature/home/build.gradle.kts +++ b/feature/home/build.gradle.kts @@ -29,13 +29,10 @@ kotlin { } sourceSets { - val desktopMain by getting - commonMain.dependencies { implementation(project(":core:core")) implementation(project(":core:ui")) - implementation(projects.shared) implementation(compose.runtime) implementation(compose.foundation) implementation(compose.material) @@ -45,9 +42,6 @@ kotlin { commonTest.dependencies { implementation(libs.kotlin.test) } - desktopMain.dependencies { - implementation(compose.desktop.currentOs) - } } } diff --git a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/HomeScreen.kt b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/HomeScreen.kt index c38fc7b6..52be83bb 100644 --- a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/HomeScreen.kt +++ b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/HomeScreen.kt @@ -1,16 +1,17 @@ package com.stslex.feature.home -import Greeting import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material.Button +import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Home import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue @@ -20,7 +21,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.ExperimentalResourceApi -import org.jetbrains.compose.resources.painterResource @OptIn(ExperimentalResourceApi::class) @Composable @@ -33,7 +33,7 @@ fun HomeScreen( .background(MaterialTheme.colors.background) ) { val defaultGreetState = "Hello World!" - val clickedGreetState = "Compose: ${Greeting().greet()}" + val clickedGreetState = "Compose: Greeting" var isClicked by remember { mutableStateOf(false) } val greetingText by remember { derivedStateOf { @@ -56,9 +56,10 @@ fun HomeScreen( Text(greetingText) } AnimatedVisibility(isClicked) { - Image( - painterResource("compose-multiplatform.xml"), - null + Icon( + imageVector = Icons.Default.Home, + contentDescription = null, + tint = MaterialTheme.colors.primary ) } } diff --git a/feature/home/src/commonMain/resources/compose-multiplatform.xml b/feature/home/src/commonMain/resources/compose-multiplatform.xml deleted file mode 100644 index d7bf7955..00000000 --- a/feature/home/src/commonMain/resources/compose-multiplatform.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 33eb1987..bfc43670 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,5 @@ [versions] kermit = "2.0.2" -ktor = "2.3.6" logback = "1.4.11" compose = "1.5.4" compose-plugin = "1.5.10" @@ -24,10 +23,6 @@ kermit = { module = "co.touchlab:kermit", version.ref = "kermit" } kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } junit = { group = "junit", name = "junit", version.ref = "junit" } -logback = { module = "ch.qos.logback:logback-classic", version.ref = "logback" } -ktor-server-core = { module = "io.ktor:ktor-server-core-jvm", version.ref = "ktor" } -ktor-server-netty = { module = "io.ktor:ktor-server-netty-jvm", version.ref = "ktor" } -ktor-server-tests = { module = "io.ktor:ktor-server-tests-jvm", version.ref = "ktor" } compose-ui = { module = "androidx.compose.ui:ui", version.ref = "compose" } compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" } compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" } @@ -41,9 +36,10 @@ androidx-material = { group = "com.google.android.material", name = "material", androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout" } androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" } +#todo check if this is needed +logback = { module = "ch.qos.logback:logback-classic", version.ref = "logback" } [plugins] kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } -ktor = { id = "io.ktor.plugin", version.ref = "ktor" } jetbrainsCompose = { id = "org.jetbrains.compose", version.ref = "compose-plugin" } androidApplication = { id = "com.android.application", version.ref = "agp" } androidLibrary = { id = "com.android.library", version.ref = "agp" } diff --git a/server/build.gradle.kts b/server/build.gradle.kts deleted file mode 100644 index 1453aaed..00000000 --- a/server/build.gradle.kts +++ /dev/null @@ -1,21 +0,0 @@ -plugins { - alias(libs.plugins.kotlinJvm) - alias(libs.plugins.ktor) - application -} - -group = "com.stslex.wizard" -version = "1.0.0" -application { - mainClass.set("com.stslex.wizard.ApplicationKt") - applicationDefaultJvmArgs = listOf("-Dio.ktor.development=${extra["development"] ?: "false"}") -} - -dependencies { - implementation(projects.shared) - implementation(libs.logback) - implementation(libs.ktor.server.core) - implementation(libs.ktor.server.netty) - testImplementation(libs.ktor.server.tests) - testImplementation(libs.kotlin.test.junit) -} \ No newline at end of file diff --git a/server/src/main/kotlin/com/stslex/wizard/Application.kt b/server/src/main/kotlin/com/stslex/wizard/Application.kt deleted file mode 100644 index 21ce3989..00000000 --- a/server/src/main/kotlin/com/stslex/wizard/Application.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.stslex.wizard - -import Greeting -import SERVER_PORT -import io.ktor.server.application.* -import io.ktor.server.engine.* -import io.ktor.server.netty.* -import io.ktor.server.response.* -import io.ktor.server.routing.* - -fun main() { - embeddedServer(Netty, port = SERVER_PORT, host = "0.0.0.0", module = Application::module) - .start(wait = true) -} - -fun Application.module() { - routing { - get("/") { - call.respondText("Ktor: ${Greeting().greet()}") - } - } -} diff --git a/server/src/main/resources/logback.xml b/server/src/main/resources/logback.xml deleted file mode 100644 index bdbb64ec..00000000 --- a/server/src/main/resources/logback.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - diff --git a/settings.gradle.kts b/settings.gradle.kts index 239c3fa5..d52ab9c3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -18,8 +18,6 @@ dependencyResolutionManagement { } } -include(":server") -include(":shared") include(":composeApp") include(":core:core") include(":core:ui") diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts deleted file mode 100644 index 75231443..00000000 --- a/shared/build.gradle.kts +++ /dev/null @@ -1,34 +0,0 @@ -plugins { - alias(libs.plugins.kotlinMultiplatform) - alias(libs.plugins.androidLibrary) -} - -kotlin { - iosX64() - iosArm64() - iosSimulatorArm64() - - androidTarget { - compilations.all { - kotlinOptions { - jvmTarget = "1.8" - } - } - } - - jvm() - - sourceSets { - commonMain.dependencies { - // put your Multiplatform dependencies here - } - } -} - -android { - namespace = "com.stslex.wizard.shared" - compileSdk = libs.versions.android.compileSdk.get().toInt() - defaultConfig { - minSdk = libs.versions.android.minSdk.get().toInt() - } -} diff --git a/shared/src/androidMain/kotlin/Platform.android.kt b/shared/src/androidMain/kotlin/Platform.android.kt deleted file mode 100644 index 4f3ea051..00000000 --- a/shared/src/androidMain/kotlin/Platform.android.kt +++ /dev/null @@ -1,7 +0,0 @@ -import android.os.Build - -class AndroidPlatform : Platform { - override val name: String = "Android ${Build.VERSION.SDK_INT}" -} - -actual fun getPlatform(): Platform = AndroidPlatform() \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/Constants.kt b/shared/src/commonMain/kotlin/Constants.kt deleted file mode 100644 index e88a3e6c..00000000 --- a/shared/src/commonMain/kotlin/Constants.kt +++ /dev/null @@ -1 +0,0 @@ -const val SERVER_PORT = 8080 diff --git a/shared/src/commonMain/kotlin/Greeting.kt b/shared/src/commonMain/kotlin/Greeting.kt deleted file mode 100644 index 887d8350..00000000 --- a/shared/src/commonMain/kotlin/Greeting.kt +++ /dev/null @@ -1,7 +0,0 @@ -class Greeting { - private val platform = getPlatform() - - fun greet(): String { - return "Hello, ${platform.name}!" - } -} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/Platform.kt b/shared/src/commonMain/kotlin/Platform.kt deleted file mode 100644 index 87ca3fff..00000000 --- a/shared/src/commonMain/kotlin/Platform.kt +++ /dev/null @@ -1,5 +0,0 @@ -interface Platform { - val name: String -} - -expect fun getPlatform(): Platform \ No newline at end of file diff --git a/shared/src/iosMain/kotlin/Platform.ios.kt b/shared/src/iosMain/kotlin/Platform.ios.kt deleted file mode 100644 index 5cef987c..00000000 --- a/shared/src/iosMain/kotlin/Platform.ios.kt +++ /dev/null @@ -1,7 +0,0 @@ -import platform.UIKit.UIDevice - -class IOSPlatform: Platform { - override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion -} - -actual fun getPlatform(): Platform = IOSPlatform() \ No newline at end of file diff --git a/shared/src/jvmMain/kotlin/Platform.jvm.kt b/shared/src/jvmMain/kotlin/Platform.jvm.kt deleted file mode 100644 index f5e7e494..00000000 --- a/shared/src/jvmMain/kotlin/Platform.jvm.kt +++ /dev/null @@ -1,5 +0,0 @@ -class JVMPlatform: Platform { - override val name: String = "Java ${System.getProperty("java.version")}" -} - -actual fun getPlatform(): Platform = JVMPlatform() \ No newline at end of file From 0c076ee896dd585e3b863c7fb8cbc17fb9088515 Mon Sep 17 00:00:00 2001 From: stslex Date: Sat, 25 Nov 2023 12:56:28 +0300 Subject: [PATCH 2/4] material Theme 3 --- composeApp/build.gradle.kts | 15 ++++----------- composeApp/src/commonMain/kotlin/InitialApp.kt | 13 ++++++++++++- .../src/commonMain/kotlin/NavigationHost.kt | 6 ++++++ core/ui/build.gradle.kts | 7 ++++--- .../kotlin/com/stslex/core/ui/theme/AppTheme.kt | 12 ++++++------ feature/home/build.gradle.kts | 8 -------- .../kotlin/com/stslex/feature/home/HomeScreen.kt | 14 ++++++-------- 7 files changed, 38 insertions(+), 37 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/NavigationHost.kt diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index c29fb014..0c215c7c 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -1,5 +1,4 @@ import org.jetbrains.compose.desktop.application.dsl.TargetFormat -import org.jetbrains.compose.ExperimentalComposeLibrary plugins { alias(libs.plugins.kotlinMultiplatform) @@ -15,9 +14,9 @@ kotlin { } } } - + jvm("desktop") - + listOf( iosX64(), iosArm64(), @@ -28,10 +27,10 @@ kotlin { isStatic = true } } - + sourceSets { val desktopMain by getting - + androidMain.dependencies { implementation(libs.compose.ui) implementation(libs.compose.ui.tooling.preview) @@ -44,12 +43,6 @@ kotlin { implementation(project(":core:core")) implementation(project(":core:ui")) implementation(project(":feature:home")) - - implementation(compose.runtime) - implementation(compose.foundation) - implementation(compose.material) - @OptIn(ExperimentalComposeLibrary::class) - implementation(compose.components.resources) } } } diff --git a/composeApp/src/commonMain/kotlin/InitialApp.kt b/composeApp/src/commonMain/kotlin/InitialApp.kt index 272a6384..af1775b5 100644 --- a/composeApp/src/commonMain/kotlin/InitialApp.kt +++ b/composeApp/src/commonMain/kotlin/InitialApp.kt @@ -1,7 +1,18 @@ +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import com.stslex.feature.home.HomeScreen @Composable fun InitialApp() { - HomeScreen() + Scaffold( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.background) + ) { paddingValues -> + HomeScreen() + } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/NavigationHost.kt b/composeApp/src/commonMain/kotlin/NavigationHost.kt new file mode 100644 index 00000000..bba4e72e --- /dev/null +++ b/composeApp/src/commonMain/kotlin/NavigationHost.kt @@ -0,0 +1,6 @@ +import androidx.compose.runtime.Composable + +@Composable +fun NavigationHost() { + +} \ No newline at end of file diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index c4d71f5b..3c9c439c 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -32,11 +32,12 @@ kotlin { commonMain.dependencies { implementation(project(":core:core")) - implementation(compose.runtime) - implementation(compose.foundation) + api(compose.runtime) + api(compose.foundation) implementation(compose.material) + api(compose.material3) @OptIn(ExperimentalComposeLibrary::class) - implementation(compose.components.resources) + api(compose.components.resources) } commonTest.dependencies { implementation(libs.kotlin.test) diff --git a/core/ui/src/commonMain/kotlin/com/stslex/core/ui/theme/AppTheme.kt b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/theme/AppTheme.kt index b316513b..cf78e314 100644 --- a/core/ui/src/commonMain/kotlin/com/stslex/core/ui/theme/AppTheme.kt +++ b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/theme/AppTheme.kt @@ -1,9 +1,9 @@ package com.stslex.core.ui.theme import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.material.MaterialTheme -import androidx.compose.material.darkColors -import androidx.compose.material.lightColors +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable @Composable @@ -12,12 +12,12 @@ fun AppTheme( content: @Composable () -> Unit, ) { val colors = if (isDarkTheme) { - darkColors() + darkColorScheme() } else { - lightColors() + lightColorScheme() } MaterialTheme( - colors = colors, + colorScheme = colors, content = content ) } \ No newline at end of file diff --git a/feature/home/build.gradle.kts b/feature/home/build.gradle.kts index 976105fa..5536ea80 100644 --- a/feature/home/build.gradle.kts +++ b/feature/home/build.gradle.kts @@ -1,5 +1,3 @@ -import org.jetbrains.compose.ExperimentalComposeLibrary - plugins { alias(libs.plugins.kotlinMultiplatform) alias(libs.plugins.androidLibrary) @@ -32,12 +30,6 @@ kotlin { commonMain.dependencies { implementation(project(":core:core")) implementation(project(":core:ui")) - - implementation(compose.runtime) - implementation(compose.foundation) - implementation(compose.material) - @OptIn(ExperimentalComposeLibrary::class) - implementation(compose.components.resources) } commonTest.dependencies { implementation(libs.kotlin.test) diff --git a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/HomeScreen.kt b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/HomeScreen.kt index 52be83bb..4b59f325 100644 --- a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/HomeScreen.kt +++ b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/HomeScreen.kt @@ -6,12 +6,12 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material.Button -import androidx.compose.material.Icon -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Home +import androidx.compose.material3.Button +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue @@ -20,9 +20,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.ExperimentalResourceApi -@OptIn(ExperimentalResourceApi::class) @Composable fun HomeScreen( modifier: Modifier = Modifier @@ -30,7 +28,7 @@ fun HomeScreen( Box( modifier = modifier .fillMaxSize() - .background(MaterialTheme.colors.background) + .background(MaterialTheme.colorScheme.background) ) { val defaultGreetState = "Hello World!" val clickedGreetState = "Compose: Greeting" @@ -59,7 +57,7 @@ fun HomeScreen( Icon( imageVector = Icons.Default.Home, contentDescription = null, - tint = MaterialTheme.colors.primary + tint = MaterialTheme.colorScheme.primary ) } } From 325c6c716a841fc7fd145e8b9675986177cd8e09 Mon Sep 17 00:00:00 2001 From: stslex Date: Sat, 25 Nov 2023 13:54:47 +0300 Subject: [PATCH 3/4] init koin and ViewModel --- composeApp/build.gradle.kts | 6 +---- composeApp/src/commonMain/kotlin/App.kt | 23 +++++++++++++++++-- .../src/commonMain/kotlin/InitialApp.kt | 4 +++- core/core/build.gradle.kts | 2 ++ core/ui/build.gradle.kts | 13 +++++++++++ .../stslex/core/ui/base/ViewModel.android.kt | 22 ++++++++++++++++++ .../com/stslex/core/ui/base/ViewModel.kt | 17 ++++++++++++++ .../stslex/core/ui/base/ViewModel.desktop.kt | 19 +++++++++++++++ .../com/stslex/core/ui/base/ViewModel.ios.kt | 19 +++++++++++++++ .../com/stslex/feature/home/HomeScreen.kt | 5 +++- .../com/stslex/feature/home/di/HomeModule.kt | 9 ++++++++ .../feature/home/domain/HomeInteractor.kt | 12 ++++++++++ gradle/libs.versions.toml | 17 +++++++++++++- iosApp/iosApp.xcodeproj/project.pbxproj | 10 ++++---- 14 files changed, 163 insertions(+), 15 deletions(-) create mode 100644 core/ui/src/androidMain/kotlin/com/stslex/core/ui/base/ViewModel.android.kt create mode 100644 core/ui/src/commonMain/kotlin/com/stslex/core/ui/base/ViewModel.kt create mode 100644 core/ui/src/desktopMain/kotlin/com/stslex/core/ui/base/ViewModel.desktop.kt create mode 100644 core/ui/src/iosMain/kotlin/com/stslex/core/ui/base/ViewModel.ios.kt create mode 100644 feature/home/src/commonMain/kotlin/com/stslex/feature/home/di/HomeModule.kt create mode 100644 feature/home/src/commonMain/kotlin/com/stslex/feature/home/domain/HomeInteractor.kt diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 0c215c7c..b62b5c30 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -31,14 +31,10 @@ kotlin { sourceSets { val desktopMain by getting - androidMain.dependencies { - implementation(libs.compose.ui) - implementation(libs.compose.ui.tooling.preview) - implementation(libs.androidx.activity.compose) - } desktopMain.dependencies { implementation(compose.desktop.currentOs) } + commonMain.dependencies { implementation(project(":core:core")) implementation(project(":core:ui")) diff --git a/composeApp/src/commonMain/kotlin/App.kt b/composeApp/src/commonMain/kotlin/App.kt index aa8a6b2b..171faa4c 100644 --- a/composeApp/src/commonMain/kotlin/App.kt +++ b/composeApp/src/commonMain/kotlin/App.kt @@ -1,9 +1,28 @@ import androidx.compose.runtime.Composable import com.stslex.core.ui.theme.AppTheme +import com.stslex.feature.home.di.homeModule +import org.koin.compose.KoinApplication +import org.koin.dsl.KoinAppDeclaration @Composable fun App() { - AppTheme { - InitialApp() + SetupKoin { + AppTheme { + InitialApp() + } } } + +@Composable +fun SetupKoin( + content: @Composable () -> Unit +) { + KoinApplication( + application = setupModules(), + content = content + ) +} + +private fun setupModules(): KoinAppDeclaration = { + modules(listOf(homeModule)) +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/InitialApp.kt b/composeApp/src/commonMain/kotlin/InitialApp.kt index af1775b5..ddb688d9 100644 --- a/composeApp/src/commonMain/kotlin/InitialApp.kt +++ b/composeApp/src/commonMain/kotlin/InitialApp.kt @@ -5,6 +5,8 @@ import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.stslex.feature.home.HomeScreen +import com.stslex.feature.home.di.homeModule +import org.koin.core.context.startKoin @Composable fun InitialApp() { @@ -15,4 +17,4 @@ fun InitialApp() { ) { paddingValues -> HomeScreen() } -} \ No newline at end of file +} diff --git a/core/core/build.gradle.kts b/core/core/build.gradle.kts index f0bfa61d..e8279ccf 100644 --- a/core/core/build.gradle.kts +++ b/core/core/build.gradle.kts @@ -31,6 +31,8 @@ kotlin { implementation(libs.kermit) implementation(compose.runtime) implementation(compose.foundation) + api(libs.koin.core) + api(libs.koin.compose) } commonTest.dependencies { implementation(libs.kotlin.test) diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index 3c9c439c..2c316960 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -29,6 +29,12 @@ kotlin { } sourceSets { + val desktopMain by getting + + desktopMain.dependencies { + implementation(compose.desktop.currentOs) + } + commonMain.dependencies { implementation(project(":core:core")) @@ -38,10 +44,17 @@ kotlin { api(compose.material3) @OptIn(ExperimentalComposeLibrary::class) api(compose.components.resources) + api(libs.bundles.voyager) } commonTest.dependencies { implementation(libs.kotlin.test) } + androidMain.dependencies { + api(libs.compose.ui) + api(libs.compose.ui.tooling.preview) + api(libs.androidx.activity.compose) + api(libs.koin.android) + } } } diff --git a/core/ui/src/androidMain/kotlin/com/stslex/core/ui/base/ViewModel.android.kt b/core/ui/src/androidMain/kotlin/com/stslex/core/ui/base/ViewModel.android.kt new file mode 100644 index 00000000..410667d9 --- /dev/null +++ b/core/ui/src/androidMain/kotlin/com/stslex/core/ui/base/ViewModel.android.kt @@ -0,0 +1,22 @@ +package com.stslex.core.ui.base + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.CoroutineScope +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.core.definition.Definition +import org.koin.core.definition.KoinDefinition +import org.koin.core.module.Module +import org.koin.core.qualifier.Qualifier +import com.stslex.core.ui.base.ViewModel as VM + +actual class ViewModel : ViewModel() { + + actual val scope: CoroutineScope + get() = viewModelScope +} + +actual inline fun Module.viewModelDefinition( + qualifier: Qualifier?, + noinline definition: Definition, +): KoinDefinition = viewModel(qualifier = qualifier, definition = definition) \ No newline at end of file diff --git a/core/ui/src/commonMain/kotlin/com/stslex/core/ui/base/ViewModel.kt b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/base/ViewModel.kt new file mode 100644 index 00000000..0de7d456 --- /dev/null +++ b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/base/ViewModel.kt @@ -0,0 +1,17 @@ +package com.stslex.core.ui.base + +import kotlinx.coroutines.CoroutineScope +import org.koin.core.definition.Definition +import org.koin.core.definition.KoinDefinition +import org.koin.core.module.Module +import org.koin.core.qualifier.Qualifier + +expect class ViewModel { + + val scope: CoroutineScope +} + +expect inline fun Module.viewModelDefinition( + qualifier: Qualifier? = null, + noinline definition: Definition +): KoinDefinition \ No newline at end of file diff --git a/core/ui/src/desktopMain/kotlin/com/stslex/core/ui/base/ViewModel.desktop.kt b/core/ui/src/desktopMain/kotlin/com/stslex/core/ui/base/ViewModel.desktop.kt new file mode 100644 index 00000000..dbd433d3 --- /dev/null +++ b/core/ui/src/desktopMain/kotlin/com/stslex/core/ui/base/ViewModel.desktop.kt @@ -0,0 +1,19 @@ +package com.stslex.core.ui.base + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import org.koin.core.definition.Definition +import org.koin.core.definition.KoinDefinition +import org.koin.core.module.Module +import org.koin.core.qualifier.Qualifier + +actual class ViewModel { + + actual val scope: CoroutineScope + get() = CoroutineScope(Dispatchers.Default) +} + +actual inline fun Module.viewModelDefinition( + qualifier: Qualifier?, + noinline definition: Definition, +): KoinDefinition = factory(qualifier = qualifier, definition = definition) \ No newline at end of file diff --git a/core/ui/src/iosMain/kotlin/com/stslex/core/ui/base/ViewModel.ios.kt b/core/ui/src/iosMain/kotlin/com/stslex/core/ui/base/ViewModel.ios.kt new file mode 100644 index 00000000..dbd433d3 --- /dev/null +++ b/core/ui/src/iosMain/kotlin/com/stslex/core/ui/base/ViewModel.ios.kt @@ -0,0 +1,19 @@ +package com.stslex.core.ui.base + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import org.koin.core.definition.Definition +import org.koin.core.definition.KoinDefinition +import org.koin.core.module.Module +import org.koin.core.qualifier.Qualifier + +actual class ViewModel { + + actual val scope: CoroutineScope + get() = CoroutineScope(Dispatchers.Default) +} + +actual inline fun Module.viewModelDefinition( + qualifier: Qualifier?, + noinline definition: Definition, +): KoinDefinition = factory(qualifier = qualifier, definition = definition) \ No newline at end of file diff --git a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/HomeScreen.kt b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/HomeScreen.kt index 4b59f325..63a3171d 100644 --- a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/HomeScreen.kt +++ b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/HomeScreen.kt @@ -20,18 +20,21 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import com.stslex.feature.home.domain.HomeInteractor +import org.koin.compose.koinInject @Composable fun HomeScreen( modifier: Modifier = Modifier ) { + val interactor = koinInject() Box( modifier = modifier .fillMaxSize() .background(MaterialTheme.colorScheme.background) ) { val defaultGreetState = "Hello World!" - val clickedGreetState = "Compose: Greeting" + val clickedGreetState = "Compose: ${interactor.greet}" var isClicked by remember { mutableStateOf(false) } val greetingText by remember { derivedStateOf { diff --git a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/di/HomeModule.kt b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/di/HomeModule.kt new file mode 100644 index 00000000..70aeb59e --- /dev/null +++ b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/di/HomeModule.kt @@ -0,0 +1,9 @@ +package com.stslex.feature.home.di + +import com.stslex.feature.home.domain.HomeInteractor +import com.stslex.feature.home.domain.HomeInteractorImpl +import org.koin.dsl.module + +val homeModule = module { + single { HomeInteractorImpl() } +} \ No newline at end of file diff --git a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/domain/HomeInteractor.kt b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/domain/HomeInteractor.kt new file mode 100644 index 00000000..583a480e --- /dev/null +++ b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/domain/HomeInteractor.kt @@ -0,0 +1,12 @@ +package com.stslex.feature.home.domain + +interface HomeInteractor { + + val greet: String +} + +class HomeInteractorImpl : HomeInteractor { + + override val greet: String + get() = "hello world greet" +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bfc43670..051ebfdb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,6 +18,10 @@ androidx-espresso-core = "3.5.1" kotlin = "1.9.20" junit = "4.13.2" +koin = "3.4.3" +koin-compose = "1.0.4" +voyagerVersion = "1.0.0-rc10" + [libraries] kermit = { module = "co.touchlab:kermit", version.ref = "kermit" } kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } @@ -36,6 +40,14 @@ androidx-material = { group = "com.google.android.material", name = "material", androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout" } androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" } +#TODO add for tests +#koin-test = { module = "io.insert-koin:koin-test", version.ref = "koin" } +koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" } +koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" } +koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin-compose"} + +voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyagerVersion" } +voyager-koin = { module = "cafe.adriel.voyager:voyager-koin", version.ref = "voyagerVersion" } #todo check if this is needed logback = { module = "ch.qos.logback:logback-classic", version.ref = "logback" } [plugins] @@ -43,4 +55,7 @@ kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } jetbrainsCompose = { id = "org.jetbrains.compose", version.ref = "compose-plugin" } androidApplication = { id = "com.android.application", version.ref = "agp" } androidLibrary = { id = "com.android.library", version.ref = "agp" } -kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } \ No newline at end of file +kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } + +[bundles] +voyager = ["voyager-navigator", "voyager-koin"] \ No newline at end of file diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj index 66c59c01..a1914a22 100644 --- a/iosApp/iosApp.xcodeproj/project.pbxproj +++ b/iosApp/iosApp.xcodeproj/project.pbxproj @@ -17,7 +17,7 @@ 058557BA273AAA24004C7B11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = ""; }; - 7555FF7B242A565900829871 /* .app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = .app; sourceTree = BUILT_PRODUCTS_DIR; }; + 7555FF7B242A565900829871 /* Wizard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Wizard.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7555FF82242A565900829871 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; AB3632DC29227652001CCB65 /* Config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = ""; }; @@ -52,7 +52,7 @@ 7555FF7C242A565900829871 /* Products */ = { isa = PBXGroup; children = ( - 7555FF7B242A565900829871 /* .app */, + 7555FF7B242A565900829871 /* Wizard.app */, ); name = Products; sourceTree = ""; @@ -94,7 +94,7 @@ ); name = iosApp; productName = iosApp; - productReference = 7555FF7B242A565900829871 /* .app */; + productReference = 7555FF7B242A565900829871 /* Wizard.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -301,7 +301,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; - DEVELOPMENT_TEAM = "${TEAM_ID}"; + DEVELOPMENT_TEAM = U26KC3ZYKX; ENABLE_PREVIEWS = YES; FRAMEWORK_SEARCH_PATHS = ( "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", @@ -332,7 +332,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; - DEVELOPMENT_TEAM = "${TEAM_ID}"; + DEVELOPMENT_TEAM = U26KC3ZYKX; ENABLE_PREVIEWS = YES; FRAMEWORK_SEARCH_PATHS = ( "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", From b18d407fc269e8ade8d3b61fb80ccb78d935729d Mon Sep 17 00:00:00 2001 From: stslex Date: Sat, 25 Nov 2023 16:06:01 +0300 Subject: [PATCH 4/4] Initial setup for Navigation and Store --- composeApp/src/commonMain/kotlin/App.kt | 10 ++++- .../src/commonMain/kotlin/AppNavigatorImpl.kt | 19 +++++++++ .../src/commonMain/kotlin/InitialApp.kt | 20 ++++++--- .../src/commonMain/kotlin/NavigationHost.kt | 6 --- .../src/commonMain/kotlin/di/appModule.kt | 13 ++++++ .../kotlin/com/stslex/core/core/CoreModule.kt | 8 ++++ core/ui/build.gradle.kts | 1 + .../stslex/core/ui/base/ViewModel.android.kt | 9 +++- .../com/stslex/core/ui/base/ViewModel.kt | 23 ++++++++++- .../com/stslex/core/ui/mvi/BaseStore.kt | 7 ++-- .../stslex/core/ui/navigation/AppNavigator.kt | 6 +++ .../stslex/core/ui/navigation/AppScreen.kt | 8 ++++ .../com/stslex/core/ui/navigation/Router.kt | 3 +- .../stslex/core/ui/base/ViewModel.desktop.kt | 9 +++- .../com/stslex/core/ui/base/ViewModel.ios.kt | 9 +++- .../com/stslex/feature/home/di/HomeModule.kt | 13 ++++-- .../feature/home/domain/HomeInteractor.kt | 12 ------ .../home/navigation/HomeScreenRouter.kt | 19 +++++++++ .../feature/home/{ => ui}/HomeScreen.kt | 41 +++++++++++++++---- .../stslex/feature/home/ui/SecondScreen.kt | 15 +++++++ .../feature/home/ui/store/HomeScreenStore.kt | 24 +++++++++++ .../home/ui/store/HomeScreenStoreComponent.kt | 27 ++++++++++++ gradle/libs.versions.toml | 1 + 23 files changed, 253 insertions(+), 50 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/AppNavigatorImpl.kt delete mode 100644 composeApp/src/commonMain/kotlin/NavigationHost.kt create mode 100644 composeApp/src/commonMain/kotlin/di/appModule.kt create mode 100644 core/core/src/commonMain/kotlin/com/stslex/core/core/CoreModule.kt create mode 100644 core/ui/src/commonMain/kotlin/com/stslex/core/ui/navigation/AppNavigator.kt create mode 100644 core/ui/src/commonMain/kotlin/com/stslex/core/ui/navigation/AppScreen.kt delete mode 100644 feature/home/src/commonMain/kotlin/com/stslex/feature/home/domain/HomeInteractor.kt create mode 100644 feature/home/src/commonMain/kotlin/com/stslex/feature/home/navigation/HomeScreenRouter.kt rename feature/home/src/commonMain/kotlin/com/stslex/feature/home/{ => ui}/HomeScreen.kt (65%) create mode 100644 feature/home/src/commonMain/kotlin/com/stslex/feature/home/ui/SecondScreen.kt create mode 100644 feature/home/src/commonMain/kotlin/com/stslex/feature/home/ui/store/HomeScreenStore.kt create mode 100644 feature/home/src/commonMain/kotlin/com/stslex/feature/home/ui/store/HomeScreenStoreComponent.kt diff --git a/composeApp/src/commonMain/kotlin/App.kt b/composeApp/src/commonMain/kotlin/App.kt index 171faa4c..f7e3dac5 100644 --- a/composeApp/src/commonMain/kotlin/App.kt +++ b/composeApp/src/commonMain/kotlin/App.kt @@ -1,6 +1,8 @@ import androidx.compose.runtime.Composable +import com.stslex.core.core.coreModule import com.stslex.core.ui.theme.AppTheme import com.stslex.feature.home.di.homeModule +import di.appModule import org.koin.compose.KoinApplication import org.koin.dsl.KoinAppDeclaration @@ -24,5 +26,11 @@ fun SetupKoin( } private fun setupModules(): KoinAppDeclaration = { - modules(listOf(homeModule)) + modules( + listOf( + appModule, + coreModule, + homeModule, + ) + ) } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/AppNavigatorImpl.kt b/composeApp/src/commonMain/kotlin/AppNavigatorImpl.kt new file mode 100644 index 00000000..874caf38 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/AppNavigatorImpl.kt @@ -0,0 +1,19 @@ +import cafe.adriel.voyager.navigator.Navigator +import com.stslex.core.ui.navigation.AppNavigator +import com.stslex.core.ui.navigation.AppScreen +import com.stslex.feature.home.ui.HomeScreen +import com.stslex.feature.home.ui.SecondScreen + +class AppNavigatorImpl( + private val navigator: Lazy +) : AppNavigator { + + override fun navigate( + screen: AppScreen + ) { + when (screen) { + AppScreen.Home -> navigator.value.push(HomeScreen) + is AppScreen.SecondScreen -> navigator.value.push(SecondScreen(screen.text)) + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/InitialApp.kt b/composeApp/src/commonMain/kotlin/InitialApp.kt index ddb688d9..a0095c69 100644 --- a/composeApp/src/commonMain/kotlin/InitialApp.kt +++ b/composeApp/src/commonMain/kotlin/InitialApp.kt @@ -1,20 +1,28 @@ import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import com.stslex.feature.home.HomeScreen -import com.stslex.feature.home.di.homeModule -import org.koin.core.context.startKoin +import cafe.adriel.voyager.navigator.Navigator +import com.stslex.feature.home.ui.HomeScreen @Composable -fun InitialApp() { +fun InitialApp( + modifier: Modifier = Modifier +) { Scaffold( - modifier = Modifier + modifier = modifier .fillMaxSize() .background(MaterialTheme.colorScheme.background) ) { paddingValues -> - HomeScreen() + Box( + modifier = Modifier.fillMaxSize() + .padding(paddingValues) + ) { + Navigator(HomeScreen) + } } } diff --git a/composeApp/src/commonMain/kotlin/NavigationHost.kt b/composeApp/src/commonMain/kotlin/NavigationHost.kt deleted file mode 100644 index bba4e72e..00000000 --- a/composeApp/src/commonMain/kotlin/NavigationHost.kt +++ /dev/null @@ -1,6 +0,0 @@ -import androidx.compose.runtime.Composable - -@Composable -fun NavigationHost() { - -} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/di/appModule.kt b/composeApp/src/commonMain/kotlin/di/appModule.kt new file mode 100644 index 00000000..0971d6b6 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/di/appModule.kt @@ -0,0 +1,13 @@ +package di + +import AppNavigatorImpl +import com.stslex.core.ui.navigation.AppNavigator +import org.koin.dsl.module + +val appModule = module { + single { + AppNavigatorImpl( + lazyOf(get()) + ) + } +} \ No newline at end of file diff --git a/core/core/src/commonMain/kotlin/com/stslex/core/core/CoreModule.kt b/core/core/src/commonMain/kotlin/com/stslex/core/core/CoreModule.kt new file mode 100644 index 00000000..c1bc8736 --- /dev/null +++ b/core/core/src/commonMain/kotlin/com/stslex/core/core/CoreModule.kt @@ -0,0 +1,8 @@ +package com.stslex.core.core + +import org.koin.core.module.dsl.singleOf +import org.koin.dsl.module + +val coreModule = module { + singleOf(::AppDispatcherImpl) +} \ No newline at end of file diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index 2c316960..694a0e31 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -54,6 +54,7 @@ kotlin { api(libs.compose.ui.tooling.preview) api(libs.androidx.activity.compose) api(libs.koin.android) + api(libs.koin.androidx.compose) } } } diff --git a/core/ui/src/androidMain/kotlin/com/stslex/core/ui/base/ViewModel.android.kt b/core/ui/src/androidMain/kotlin/com/stslex/core/ui/base/ViewModel.android.kt index 410667d9..b53e9443 100644 --- a/core/ui/src/androidMain/kotlin/com/stslex/core/ui/base/ViewModel.android.kt +++ b/core/ui/src/androidMain/kotlin/com/stslex/core/ui/base/ViewModel.android.kt @@ -1,8 +1,10 @@ package com.stslex.core.ui.base +import androidx.compose.runtime.Composable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.CoroutineScope +import org.koin.androidx.compose.koinViewModel import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.core.definition.Definition import org.koin.core.definition.KoinDefinition @@ -10,7 +12,7 @@ import org.koin.core.module.Module import org.koin.core.qualifier.Qualifier import com.stslex.core.ui.base.ViewModel as VM -actual class ViewModel : ViewModel() { +actual open class ViewModel : ViewModel() { actual val scope: CoroutineScope get() = viewModelScope @@ -19,4 +21,7 @@ actual class ViewModel : ViewModel() { actual inline fun Module.viewModelDefinition( qualifier: Qualifier?, noinline definition: Definition, -): KoinDefinition = viewModel(qualifier = qualifier, definition = definition) \ No newline at end of file +): KoinDefinition = viewModel(qualifier = qualifier, definition = definition) + +@Composable +actual inline fun getViewModel(): T = koinViewModel() \ No newline at end of file diff --git a/core/ui/src/commonMain/kotlin/com/stslex/core/ui/base/ViewModel.kt b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/base/ViewModel.kt index 0de7d456..0961cbe0 100644 --- a/core/ui/src/commonMain/kotlin/com/stslex/core/ui/base/ViewModel.kt +++ b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/base/ViewModel.kt @@ -1,12 +1,17 @@ package com.stslex.core.ui.base +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow import kotlinx.coroutines.CoroutineScope +import org.koin.compose.getKoin import org.koin.core.definition.Definition import org.koin.core.definition.KoinDefinition import org.koin.core.module.Module import org.koin.core.qualifier.Qualifier +import org.koin.dsl.module -expect class ViewModel { +expect open class ViewModel() { val scope: CoroutineScope } @@ -14,4 +19,18 @@ expect class ViewModel { expect inline fun Module.viewModelDefinition( qualifier: Qualifier? = null, noinline definition: Definition -): KoinDefinition \ No newline at end of file +): KoinDefinition + +@Composable +expect inline fun getViewModel(): T + +@Composable +inline fun rememberStore(): VM { + val navigator = LocalNavigator.currentOrThrow + val module = module { single { navigator } } + getKoin().loadModules( + modules = listOf(module), + allowOverride = true, + ) + return getViewModel() +} diff --git a/core/ui/src/commonMain/kotlin/com/stslex/core/ui/mvi/BaseStore.kt b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/mvi/BaseStore.kt index 41e525e8..26be0ff6 100644 --- a/core/ui/src/commonMain/kotlin/com/stslex/core/ui/mvi/BaseStore.kt +++ b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/mvi/BaseStore.kt @@ -3,11 +3,12 @@ package com.stslex.core.ui.mvi import com.stslex.core.core.AppDispatcher import com.stslex.core.core.Logger import com.stslex.core.core.coroutineExceptionHandler -import com.stslex.core.ui.navigation.Router +import com.stslex.core.ui.base.ViewModel import com.stslex.core.ui.mvi.Store.Action import com.stslex.core.ui.mvi.Store.Event import com.stslex.core.ui.mvi.Store.Navigation import com.stslex.core.ui.mvi.Store.State +import com.stslex.core.ui.navigation.Router import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job @@ -26,15 +27,13 @@ abstract class BaseStore( private val router: Router, private val appDispatcher: AppDispatcher, initialState: S -) { +) : Store, ViewModel() { abstract fun sendAction(action: A) private val _state: MutableStateFlow = MutableStateFlow(initialState) val state: StateFlow = _state.asStateFlow() - private val scope: CoroutineScope = CoroutineScope(appDispatcher.default) - private fun exceptionHandler( onError: suspend (cause: Throwable) -> Unit = {}, ) = CoroutineExceptionHandler { coroutineContext, throwable -> diff --git a/core/ui/src/commonMain/kotlin/com/stslex/core/ui/navigation/AppNavigator.kt b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/navigation/AppNavigator.kt new file mode 100644 index 00000000..b08e5746 --- /dev/null +++ b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/navigation/AppNavigator.kt @@ -0,0 +1,6 @@ +package com.stslex.core.ui.navigation + +interface AppNavigator { + + fun navigate(screen: AppScreen) +} \ No newline at end of file diff --git a/core/ui/src/commonMain/kotlin/com/stslex/core/ui/navigation/AppScreen.kt b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/navigation/AppScreen.kt new file mode 100644 index 00000000..6ca7fbed --- /dev/null +++ b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/navigation/AppScreen.kt @@ -0,0 +1,8 @@ +package com.stslex.core.ui.navigation + +sealed interface AppScreen { + + data object Home : AppScreen + + data class SecondScreen(val text: String) : AppScreen +} \ No newline at end of file diff --git a/core/ui/src/commonMain/kotlin/com/stslex/core/ui/navigation/Router.kt b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/navigation/Router.kt index bd22011c..a6c1bdbc 100644 --- a/core/ui/src/commonMain/kotlin/com/stslex/core/ui/navigation/Router.kt +++ b/core/ui/src/commonMain/kotlin/com/stslex/core/ui/navigation/Router.kt @@ -4,4 +4,5 @@ import com.stslex.core.ui.mvi.Store fun interface Router { operator fun invoke(event: E) -} \ No newline at end of file +} + diff --git a/core/ui/src/desktopMain/kotlin/com/stslex/core/ui/base/ViewModel.desktop.kt b/core/ui/src/desktopMain/kotlin/com/stslex/core/ui/base/ViewModel.desktop.kt index dbd433d3..fd4947b9 100644 --- a/core/ui/src/desktopMain/kotlin/com/stslex/core/ui/base/ViewModel.desktop.kt +++ b/core/ui/src/desktopMain/kotlin/com/stslex/core/ui/base/ViewModel.desktop.kt @@ -1,13 +1,15 @@ package com.stslex.core.ui.base +import androidx.compose.runtime.Composable import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import org.koin.compose.koinInject import org.koin.core.definition.Definition import org.koin.core.definition.KoinDefinition import org.koin.core.module.Module import org.koin.core.qualifier.Qualifier -actual class ViewModel { +actual open class ViewModel { actual val scope: CoroutineScope get() = CoroutineScope(Dispatchers.Default) @@ -16,4 +18,7 @@ actual class ViewModel { actual inline fun Module.viewModelDefinition( qualifier: Qualifier?, noinline definition: Definition, -): KoinDefinition = factory(qualifier = qualifier, definition = definition) \ No newline at end of file +): KoinDefinition = factory(qualifier = qualifier, definition = definition) + +@Composable +actual inline fun getViewModel(): T = koinInject() \ No newline at end of file diff --git a/core/ui/src/iosMain/kotlin/com/stslex/core/ui/base/ViewModel.ios.kt b/core/ui/src/iosMain/kotlin/com/stslex/core/ui/base/ViewModel.ios.kt index dbd433d3..fd4947b9 100644 --- a/core/ui/src/iosMain/kotlin/com/stslex/core/ui/base/ViewModel.ios.kt +++ b/core/ui/src/iosMain/kotlin/com/stslex/core/ui/base/ViewModel.ios.kt @@ -1,13 +1,15 @@ package com.stslex.core.ui.base +import androidx.compose.runtime.Composable import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import org.koin.compose.koinInject import org.koin.core.definition.Definition import org.koin.core.definition.KoinDefinition import org.koin.core.module.Module import org.koin.core.qualifier.Qualifier -actual class ViewModel { +actual open class ViewModel { actual val scope: CoroutineScope get() = CoroutineScope(Dispatchers.Default) @@ -16,4 +18,7 @@ actual class ViewModel { actual inline fun Module.viewModelDefinition( qualifier: Qualifier?, noinline definition: Definition, -): KoinDefinition = factory(qualifier = qualifier, definition = definition) \ No newline at end of file +): KoinDefinition = factory(qualifier = qualifier, definition = definition) + +@Composable +actual inline fun getViewModel(): T = koinInject() \ No newline at end of file diff --git a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/di/HomeModule.kt b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/di/HomeModule.kt index 70aeb59e..58bd1044 100644 --- a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/di/HomeModule.kt +++ b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/di/HomeModule.kt @@ -1,9 +1,14 @@ package com.stslex.feature.home.di -import com.stslex.feature.home.domain.HomeInteractor -import com.stslex.feature.home.domain.HomeInteractorImpl +import com.stslex.core.ui.base.viewModelDefinition +import com.stslex.feature.home.navigation.HomeScreenRouter +import com.stslex.feature.home.navigation.HomeScreenRouterImpl +import com.stslex.feature.home.ui.store.HomeScreenStore import org.koin.dsl.module val homeModule = module { - single { HomeInteractorImpl() } -} \ No newline at end of file + viewModelDefinition { HomeScreenStore(get(), get()) } + factory { + HomeScreenRouterImpl(get()) + } +} diff --git a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/domain/HomeInteractor.kt b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/domain/HomeInteractor.kt deleted file mode 100644 index 583a480e..00000000 --- a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/domain/HomeInteractor.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.stslex.feature.home.domain - -interface HomeInteractor { - - val greet: String -} - -class HomeInteractorImpl : HomeInteractor { - - override val greet: String - get() = "hello world greet" -} \ No newline at end of file diff --git a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/navigation/HomeScreenRouter.kt b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/navigation/HomeScreenRouter.kt new file mode 100644 index 00000000..fbd425e8 --- /dev/null +++ b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/navigation/HomeScreenRouter.kt @@ -0,0 +1,19 @@ +package com.stslex.feature.home.navigation + +import com.stslex.core.ui.navigation.AppNavigator +import com.stslex.core.ui.navigation.AppScreen +import com.stslex.core.ui.navigation.Router +import com.stslex.feature.home.ui.store.HomeScreenStoreComponent.Navigation + +interface HomeScreenRouter : Router + +class HomeScreenRouterImpl( + private val navigator: AppNavigator +) : HomeScreenRouter { + + override fun invoke(event: Navigation) { + when (event) { + is Navigation.SecondScreen -> navigator.navigate(AppScreen.SecondScreen(event.text)) + } + } +} \ No newline at end of file diff --git a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/HomeScreen.kt b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/ui/HomeScreen.kt similarity index 65% rename from feature/home/src/commonMain/kotlin/com/stslex/feature/home/HomeScreen.kt rename to feature/home/src/commonMain/kotlin/com/stslex/feature/home/ui/HomeScreen.kt index 63a3171d..76719806 100644 --- a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/HomeScreen.kt +++ b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/ui/HomeScreen.kt @@ -1,4 +1,4 @@ -package com.stslex.feature.home +package com.stslex.feature.home.ui import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.background @@ -13,6 +13,7 @@ import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -20,21 +21,38 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import com.stslex.feature.home.domain.HomeInteractor -import org.koin.compose.koinInject +import cafe.adriel.voyager.core.screen.Screen +import com.stslex.core.ui.base.rememberStore +import com.stslex.feature.home.ui.store.HomeScreenStore +import com.stslex.feature.home.ui.store.HomeScreenStoreComponent +import com.stslex.feature.home.ui.store.HomeScreenStoreComponent.Action + +object HomeScreen : Screen { + + @Composable + override fun Content() { + val store = rememberStore() + val state by remember { store.state }.collectAsState() + + HomeScreenContent( + state = state, + sendAction = store::sendAction + ) + } +} @Composable -fun HomeScreen( - modifier: Modifier = Modifier +private fun HomeScreenContent( + state: HomeScreenStoreComponent.State, + sendAction: (Action) -> Unit, ) { - val interactor = koinInject() Box( - modifier = modifier + modifier = Modifier .fillMaxSize() .background(MaterialTheme.colorScheme.background) ) { val defaultGreetState = "Hello World!" - val clickedGreetState = "Compose: ${interactor.greet}" + val clickedGreetState = "Compose: ${state.text}" var isClicked by remember { mutableStateOf(false) } val greetingText by remember { derivedStateOf { @@ -63,6 +81,13 @@ fun HomeScreen( tint = MaterialTheme.colorScheme.primary ) } + Button( + onClick = { + sendAction(Action.OnClick) + } + ) { + Text("second screen") + } } } } \ No newline at end of file diff --git a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/ui/SecondScreen.kt b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/ui/SecondScreen.kt new file mode 100644 index 00000000..aff48511 --- /dev/null +++ b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/ui/SecondScreen.kt @@ -0,0 +1,15 @@ +package com.stslex.feature.home.ui + +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import cafe.adriel.voyager.core.screen.Screen + +data class SecondScreen( + private val text: String +) : Screen { + + @Composable + override fun Content() { + Text(text = "Second Screen: $text") + } +} \ No newline at end of file diff --git a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/ui/store/HomeScreenStore.kt b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/ui/store/HomeScreenStore.kt new file mode 100644 index 00000000..5a1f4771 --- /dev/null +++ b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/ui/store/HomeScreenStore.kt @@ -0,0 +1,24 @@ +package com.stslex.feature.home.ui.store + +import com.stslex.core.core.AppDispatcher +import com.stslex.core.ui.mvi.BaseStore +import com.stslex.feature.home.navigation.HomeScreenRouter +import com.stslex.feature.home.ui.store.HomeScreenStoreComponent.Action +import com.stslex.feature.home.ui.store.HomeScreenStoreComponent.Event +import com.stslex.feature.home.ui.store.HomeScreenStoreComponent.Navigation +import com.stslex.feature.home.ui.store.HomeScreenStoreComponent.State + +class HomeScreenStore( + appDispatcher: AppDispatcher, + router: HomeScreenRouter +) : HomeScreenStoreComponent, BaseStore( + router = router, + initialState = State.INITIAL, + appDispatcher = appDispatcher +) { + override fun sendAction(action: Action) { + when (action) { + Action.OnClick -> navigate(Navigation.SecondScreen(state.value.text)) + } + } +} \ No newline at end of file diff --git a/feature/home/src/commonMain/kotlin/com/stslex/feature/home/ui/store/HomeScreenStoreComponent.kt b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/ui/store/HomeScreenStoreComponent.kt new file mode 100644 index 00000000..f24da794 --- /dev/null +++ b/feature/home/src/commonMain/kotlin/com/stslex/feature/home/ui/store/HomeScreenStoreComponent.kt @@ -0,0 +1,27 @@ +package com.stslex.feature.home.ui.store + +import com.stslex.core.ui.mvi.Store + +interface HomeScreenStoreComponent : Store { + + data class State( + val text: String + ) : Store.State { + + companion object { + val INITIAL = State(text = "Hello, World!") + } + } + + interface Event : Store.Event + + interface Action : Store.Action { + + object OnClick : Action + } + + interface Navigation : Store.Navigation { + + data class SecondScreen(val text: String) : Navigation + } +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 051ebfdb..d27a5f26 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -45,6 +45,7 @@ androidx-activity-compose = { module = "androidx.activity:activity-compose", ver koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" } koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" } koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin-compose"} +koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin" } voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyagerVersion" } voyager-koin = { module = "cafe.adriel.voyager:voyager-koin", version.ref = "voyagerVersion" }