From 44723cbbafdad89bef6043f99cbd0fbab1ecf19a Mon Sep 17 00:00:00 2001 From: michaelbel Date: Sun, 24 Mar 2024 11:35:35 +0300 Subject: [PATCH] Multiplatform --- androidApp/build.gradle.kts | 2 +- build.gradle.kts | 4 + core/analytics-kmp/build.gradle.kts | 2 +- core/common-kmp/build.gradle.kts | 4 +- .../movies/common/browser/Browser.kt | 2 +- .../movies/common/gender/GrammaticalGender.kt | 39 --------- .../movies/common/gender/GrammaticalGender.kt | 40 +++++++-- .../movies/common/browser/Browser.kt | 11 +++ .../movies/common/gender/GrammaticalGender.kt | 38 --------- core/debug-kmp/build.gradle.kts | 2 +- .../movies/debug/ui/DebugToolbar.kt | 5 +- core/interactor-kmp/build.gradle.kts | 2 +- .../movies/interactor/entity/Password.kt | 8 -- .../movies/interactor/entity/Username.kt | 8 -- .../movies/interactor/ktx/PasswordKtx.kt | 18 ---- .../movies/interactor/ktx/UsernameKtx.kt | 18 ---- .../movies/interactor/entity/Password.kt | 7 +- .../movies/interactor/entity/Username.kt | 7 +- .../movies/interactor/ktx/PasswordKtx.kt | 14 ++-- .../movies/interactor/ktx/UsernameKtx.kt | 14 ++-- core/navigation-kmp/build.gradle.kts | 2 +- core/network-kmp/build.gradle.kts | 14 +++- core/persistence-kmp/build.gradle.kts | 2 +- core/repository-kmp/build.gradle.kts | 2 +- core/ui-kmp/build.gradle.kts | 17 +++- .../MoviesContentDescriptionCommon.kt | 5 ++ .../movies/ui/compose/SwitchCheckIcon.kt | 10 +-- .../movies/ui/compose/iconbutton/BackIcon.kt | 3 +- .../ui/compose/iconbutton/SearchIcon.kt | 3 +- .../ui/compose/iconbutton/SettingsIcon.kt | 3 +- core/ui/build.gradle.kts | 1 - core/work-kmp/build.gradle.kts | 2 +- feature/account-impl-kmp/build.gradle.kts | 18 +++- feature/account-kmp/build.gradle.kts | 12 +-- feature/auth-impl-kmp/build.gradle.kts | 25 ++++-- .../movies/auth/ui/AuthScreenContent.kt | 14 ++-- feature/auth-kmp/build.gradle.kts | 8 +- feature/details-impl-kmp/build.gradle.kts | 25 ++++-- feature/details-kmp/build.gradle.kts | 2 +- feature/feed-impl-kmp/build.gradle.kts | 24 ++++-- feature/feed-kmp/build.gradle.kts | 2 +- feature/gallery-impl-kmp/build.gradle.kts | 25 ++++-- feature/gallery-kmp/build.gradle.kts | 2 +- feature/search-impl-kmp/build.gradle.kts | 25 ++++-- feature/search-kmp/build.gradle.kts | 2 +- feature/settings-impl-kmp/build.gradle.kts | 43 ++++++---- .../movies/settings/ktx/IconAliasKtx.kt | 16 ++-- .../movies/settings/ktx/SealedStringKtx.kt | 37 --------- .../settings/ui/SettingsScreenContent.kt | 14 ++-- .../movies/settings/ui/SettingsToolbar.kt | 7 +- .../movies/settings/ui/SettingsVersionBox.kt | 33 +++----- .../composeResources/values-ru/strings.xml | 57 +++++++++++++ .../composeResources/values/strings.xml | 57 +++++++++++++ .../movies/settings/ktx/SealedStringKtx.kt | 56 +++++++++++++ .../settings/ui/common/SettingDialog.kt | 33 +++----- .../movies/settings/ui/common/SettingItem.kt | 12 ++- .../settings/ui/common/SettingSwitchItem.kt | 51 +++++------- .../settings/ui/SettingsScreenContent.kt | 82 +++++++++---------- .../movies/settings/ui/SettingsToolbar.kt | 20 ++--- feature/settings-kmp/build.gradle.kts | 3 +- gradle/libs.versions.toml | 6 +- 61 files changed, 547 insertions(+), 473 deletions(-) delete mode 100644 core/common-kmp/src/androidMain/kotlin/org/michaelbel/movies/common/gender/GrammaticalGender.kt create mode 100644 core/common-kmp/src/desktopMain/kotlin/org/michaelbel/movies/common/browser/Browser.kt delete mode 100644 core/common-kmp/src/desktopMain/kotlin/org/michaelbel/movies/common/gender/GrammaticalGender.kt delete mode 100644 core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/entity/Password.kt delete mode 100644 core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/entity/Username.kt delete mode 100644 core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/ktx/PasswordKtx.kt delete mode 100644 core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/ktx/UsernameKtx.kt create mode 100644 core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/accessibility/MoviesContentDescriptionCommon.kt rename core/ui-kmp/src/{androidMain => commonMain}/kotlin/org/michaelbel/movies/ui/compose/SwitchCheckIcon.kt (84%) delete mode 100644 feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ktx/SealedStringKtx.kt create mode 100644 feature/settings-impl-kmp/src/commonMain/composeResources/values-ru/strings.xml create mode 100644 feature/settings-impl-kmp/src/commonMain/composeResources/values/strings.xml create mode 100644 feature/settings-impl-kmp/src/commonMain/kotlin/org/michaelbel/movies/settings/ktx/SealedStringKtx.kt rename feature/settings-impl-kmp/src/{androidMain => commonMain}/kotlin/org/michaelbel/movies/settings/ui/common/SettingDialog.kt (80%) rename feature/settings-impl-kmp/src/{androidMain => commonMain}/kotlin/org/michaelbel/movies/settings/ui/common/SettingItem.kt (91%) rename feature/settings-impl-kmp/src/{androidMain => commonMain}/kotlin/org/michaelbel/movies/settings/ui/common/SettingSwitchItem.kt (81%) diff --git a/androidApp/build.gradle.kts b/androidApp/build.gradle.kts index 86ca7a91e..4f94a81b6 100644 --- a/androidApp/build.gradle.kts +++ b/androidApp/build.gradle.kts @@ -109,7 +109,7 @@ android { applicationIdSuffix = MoviesBuildType.DEBUG.applicationIdSuffix manifestPlaceholders += mapOf("appName" to "@string/app_name_dev") isDefault = true - vcsInfo { include = true } // Version control system integration in App Quality Insights + //vcsInfo { include = true } // Version control system integration in App Quality Insights } create("benchmark") { initWith(getByName("release")) diff --git a/build.gradle.kts b/build.gradle.kts index 9722d02d2..f952bd0fb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,4 +30,8 @@ subprojects { if (name != "desktopApp") { apply(plugin = "io.gitlab.arturbosch.detekt") } +} + +extra.apply { + set("jvmTarget", "11") } \ No newline at end of file diff --git a/core/analytics-kmp/build.gradle.kts b/core/analytics-kmp/build.gradle.kts index 2953cfd85..51b35d921 100644 --- a/core/analytics-kmp/build.gradle.kts +++ b/core/analytics-kmp/build.gradle.kts @@ -8,7 +8,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } diff --git a/core/common-kmp/build.gradle.kts b/core/common-kmp/build.gradle.kts index ddc274039..9e9fe7b95 100644 --- a/core/common-kmp/build.gradle.kts +++ b/core/common-kmp/build.gradle.kts @@ -1,6 +1,7 @@ plugins { alias(libs.plugins.android.library) alias(libs.plugins.kotlin.multiplatform) + alias(libs.plugins.compose) id("movies-android-hilt") } @@ -8,7 +9,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } @@ -16,6 +17,7 @@ kotlin { sourceSets { commonMain.dependencies { + implementation(compose.material3) implementation(libs.kotlinx.coroutines.core) } androidMain.dependencies { diff --git a/core/common-kmp/src/androidMain/kotlin/org/michaelbel/movies/common/browser/Browser.kt b/core/common-kmp/src/androidMain/kotlin/org/michaelbel/movies/common/browser/Browser.kt index 6291ccd7d..f3d2ea3ee 100644 --- a/core/common-kmp/src/androidMain/kotlin/org/michaelbel/movies/common/browser/Browser.kt +++ b/core/common-kmp/src/androidMain/kotlin/org/michaelbel/movies/common/browser/Browser.kt @@ -7,7 +7,7 @@ import androidx.browser.customtabs.CustomTabColorSchemeParams import androidx.browser.customtabs.CustomTabsIntent import androidx.core.net.toUri -fun openUrl( +fun openUrlAndroid( resultContract: ManagedActivityResultLauncher, toolbarColor: Int, url: String diff --git a/core/common-kmp/src/androidMain/kotlin/org/michaelbel/movies/common/gender/GrammaticalGender.kt b/core/common-kmp/src/androidMain/kotlin/org/michaelbel/movies/common/gender/GrammaticalGender.kt deleted file mode 100644 index 2dc202241..000000000 --- a/core/common-kmp/src/androidMain/kotlin/org/michaelbel/movies/common/gender/GrammaticalGender.kt +++ /dev/null @@ -1,39 +0,0 @@ -@file:Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") - -package org.michaelbel.movies.common.gender - -import android.content.res.Configuration -import org.michaelbel.movies.common.SealedString -import org.michaelbel.movies.common.gender.exceptions.InvalidGenderException - -actual sealed class GrammaticalGender( - val value: Int -): SealedString { - - data object NotSpecified: GrammaticalGender(Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED) - - data object Neutral: GrammaticalGender(Configuration.GRAMMATICAL_GENDER_NEUTRAL) - - data object Feminine: GrammaticalGender(Configuration.GRAMMATICAL_GENDER_FEMININE) - - data object Masculine: GrammaticalGender(Configuration.GRAMMATICAL_GENDER_MASCULINE) - - companion object { - val VALUES = listOf( - NotSpecified, - Neutral, - Feminine, - Masculine - ) - - fun transform(gender: Int): GrammaticalGender { - return when (gender) { - Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED -> NotSpecified - Configuration.GRAMMATICAL_GENDER_NEUTRAL -> Neutral - Configuration.GRAMMATICAL_GENDER_FEMININE -> Feminine - Configuration.GRAMMATICAL_GENDER_MASCULINE -> Masculine - else -> throw InvalidGenderException - } - } - } -} \ No newline at end of file diff --git a/core/common-kmp/src/commonMain/kotlin/org/michaelbel/movies/common/gender/GrammaticalGender.kt b/core/common-kmp/src/commonMain/kotlin/org/michaelbel/movies/common/gender/GrammaticalGender.kt index e93a0c826..cc8a30cfd 100644 --- a/core/common-kmp/src/commonMain/kotlin/org/michaelbel/movies/common/gender/GrammaticalGender.kt +++ b/core/common-kmp/src/commonMain/kotlin/org/michaelbel/movies/common/gender/GrammaticalGender.kt @@ -1,8 +1,36 @@ -@file:Suppress( - "EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING", - "EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE" -) - package org.michaelbel.movies.common.gender -expect sealed class GrammaticalGender \ No newline at end of file +import org.michaelbel.movies.common.SealedString +import org.michaelbel.movies.common.gender.exceptions.InvalidGenderException + +sealed class GrammaticalGender( + val value: Int +): SealedString { + + data object NotSpecified: GrammaticalGender(0) + + data object Neutral: GrammaticalGender(1) + + data object Feminine: GrammaticalGender(2) + + data object Masculine: GrammaticalGender(3) + + companion object { + val VALUES = listOf( + NotSpecified, + Neutral, + Feminine, + Masculine + ) + + fun transform(gender: Int): GrammaticalGender { + return when (gender) { + 0 -> NotSpecified + 1 -> Neutral + 2 -> Feminine + 3 -> Masculine + else -> throw InvalidGenderException + } + } + } +} \ No newline at end of file diff --git a/core/common-kmp/src/desktopMain/kotlin/org/michaelbel/movies/common/browser/Browser.kt b/core/common-kmp/src/desktopMain/kotlin/org/michaelbel/movies/common/browser/Browser.kt new file mode 100644 index 000000000..b5b2389da --- /dev/null +++ b/core/common-kmp/src/desktopMain/kotlin/org/michaelbel/movies/common/browser/Browser.kt @@ -0,0 +1,11 @@ +package org.michaelbel.movies.common.browser + +import java.awt.Desktop +import java.net.URI + +fun openUrlDesktop(url: String) { + val desktop = if (Desktop.isDesktopSupported()) Desktop.getDesktop() else null + if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { + desktop.browse(URI.create(url)) + } +} \ No newline at end of file diff --git a/core/common-kmp/src/desktopMain/kotlin/org/michaelbel/movies/common/gender/GrammaticalGender.kt b/core/common-kmp/src/desktopMain/kotlin/org/michaelbel/movies/common/gender/GrammaticalGender.kt deleted file mode 100644 index 4cfdefe75..000000000 --- a/core/common-kmp/src/desktopMain/kotlin/org/michaelbel/movies/common/gender/GrammaticalGender.kt +++ /dev/null @@ -1,38 +0,0 @@ -@file:Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") - -package org.michaelbel.movies.common.gender - -import org.michaelbel.movies.common.SealedString -import org.michaelbel.movies.common.gender.exceptions.InvalidGenderException - -actual sealed class GrammaticalGender( - val value: Int -): SealedString { - - data object NotSpecified: GrammaticalGender(0) - - data object Neutral: GrammaticalGender(1) - - data object Feminine: GrammaticalGender(2) - - data object Masculine: GrammaticalGender(3) - - companion object { - val VALUES = listOf( - NotSpecified, - Neutral, - Feminine, - Masculine - ) - - fun transform(gender: Int): GrammaticalGender { - return when (gender) { - 0 -> NotSpecified - 1 -> Neutral - 2 -> Feminine - 3 -> Masculine - else -> throw InvalidGenderException - } - } - } -} \ No newline at end of file diff --git a/core/debug-kmp/build.gradle.kts b/core/debug-kmp/build.gradle.kts index 1f23b726e..c15702b70 100644 --- a/core/debug-kmp/build.gradle.kts +++ b/core/debug-kmp/build.gradle.kts @@ -9,7 +9,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } diff --git a/core/debug-kmp/src/androidMain/kotlin/org/michaelbel/movies/debug/ui/DebugToolbar.kt b/core/debug-kmp/src/androidMain/kotlin/org/michaelbel/movies/debug/ui/DebugToolbar.kt index 1c7139cd6..ee9c69a85 100644 --- a/core/debug-kmp/src/androidMain/kotlin/org/michaelbel/movies/debug/ui/DebugToolbar.kt +++ b/core/debug-kmp/src/androidMain/kotlin/org/michaelbel/movies/debug/ui/DebugToolbar.kt @@ -11,7 +11,6 @@ import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import org.michaelbel.movies.debug_kmp.R import org.michaelbel.movies.ui.compose.iconbutton.CloseIcon @@ -33,9 +32,7 @@ internal fun DebugToolbar( navigationIcon = { CloseIcon( onClick = onNavigationIconClick, - modifier = Modifier - .windowInsetsPadding(displayCutoutWindowInsets) - .testTag("BackIconButton") + modifier = Modifier.windowInsetsPadding(displayCutoutWindowInsets) ) }, colors = TopAppBarDefaults.topAppBarColors( diff --git a/core/interactor-kmp/build.gradle.kts b/core/interactor-kmp/build.gradle.kts index fd27e7d52..e8071a3bc 100644 --- a/core/interactor-kmp/build.gradle.kts +++ b/core/interactor-kmp/build.gradle.kts @@ -8,7 +8,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } diff --git a/core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/entity/Password.kt b/core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/entity/Password.kt deleted file mode 100644 index 024179a00..000000000 --- a/core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/entity/Password.kt +++ /dev/null @@ -1,8 +0,0 @@ -@file:Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") - -package org.michaelbel.movies.interactor.entity - -@JvmInline -actual value class Password( - val value: String -) \ No newline at end of file diff --git a/core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/entity/Username.kt b/core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/entity/Username.kt deleted file mode 100644 index bd6f2b5fa..000000000 --- a/core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/entity/Username.kt +++ /dev/null @@ -1,8 +0,0 @@ -@file:Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") - -package org.michaelbel.movies.interactor.entity - -@JvmInline -actual value class Username( - val value: String -) \ No newline at end of file diff --git a/core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/ktx/PasswordKtx.kt b/core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/ktx/PasswordKtx.kt deleted file mode 100644 index d4d81358d..000000000 --- a/core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/ktx/PasswordKtx.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.michaelbel.movies.interactor.ktx - -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.Saver -import org.michaelbel.movies.interactor.entity.Password - -actual val Password.isNotEmpty: Boolean - get() = value.isNotEmpty() - -actual val Password.trim: Password - get() = Password(value.trim()) - -actual val PasswordSaver: Saver, String> - get() = Saver( - save = { it.value.value }, - restore = { mutableStateOf(Password(it)) } - ) \ No newline at end of file diff --git a/core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/ktx/UsernameKtx.kt b/core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/ktx/UsernameKtx.kt deleted file mode 100644 index 8fc4eb8b6..000000000 --- a/core/interactor-kmp/src/androidMain/kotlin/org/michaelbel/movies/interactor/ktx/UsernameKtx.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.michaelbel.movies.interactor.ktx - -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.Saver -import org.michaelbel.movies.interactor.entity.Username - -actual val Username.isNotEmpty: Boolean - get() = value.isNotEmpty() - -actual val Username.trim: Username - get() = Username(value.trim()) - -actual val UsernameSaver: Saver, String> - get() = Saver( - save = { it.value.value }, - restore = { mutableStateOf(Username(it)) } - ) \ No newline at end of file diff --git a/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/entity/Password.kt b/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/entity/Password.kt index 4f3fc463f..983062fec 100644 --- a/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/entity/Password.kt +++ b/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/entity/Password.kt @@ -1,11 +1,6 @@ -@file:Suppress( - "EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING", - "EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE" -) - package org.michaelbel.movies.interactor.entity @JvmInline -expect value class Password( +value class Password( val value: String ) \ No newline at end of file diff --git a/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/entity/Username.kt b/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/entity/Username.kt index 671e0df25..8fd18d208 100644 --- a/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/entity/Username.kt +++ b/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/entity/Username.kt @@ -1,11 +1,6 @@ -@file:Suppress( - "EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING", - "EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE" -) - package org.michaelbel.movies.interactor.entity @JvmInline -expect value class Username( +value class Username( val value: String ) \ No newline at end of file diff --git a/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/ktx/PasswordKtx.kt b/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/ktx/PasswordKtx.kt index c6de9d2ff..d00584dcb 100644 --- a/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/ktx/PasswordKtx.kt +++ b/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/ktx/PasswordKtx.kt @@ -1,5 +1,3 @@ -@file:Suppress("EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE") - package org.michaelbel.movies.interactor.ktx import androidx.compose.runtime.MutableState @@ -7,8 +5,14 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.Saver import org.michaelbel.movies.interactor.entity.Password -expect val Password.isNotEmpty: Boolean +val Password.isNotEmpty: Boolean + get() = value.isNotEmpty() -expect val Password.trim: Password +val Password.trim: Password + get() = Password(value.trim()) -expect val PasswordSaver: Saver, String> \ No newline at end of file +val PasswordSaver: Saver, String> + get() = Saver( + save = { it.value.value }, + restore = { mutableStateOf(Password(it)) } + ) \ No newline at end of file diff --git a/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/ktx/UsernameKtx.kt b/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/ktx/UsernameKtx.kt index 9bb35863c..66c1f3377 100644 --- a/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/ktx/UsernameKtx.kt +++ b/core/interactor-kmp/src/commonMain/kotlin/org/michaelbel/movies/interactor/ktx/UsernameKtx.kt @@ -1,5 +1,3 @@ -@file:Suppress("EXPECT_AND_ACTUAL_IN_THE_SAME_MODULE") - package org.michaelbel.movies.interactor.ktx import androidx.compose.runtime.MutableState @@ -7,8 +5,14 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.Saver import org.michaelbel.movies.interactor.entity.Username -expect val Username.isNotEmpty: Boolean +val Username.isNotEmpty: Boolean + get() = value.isNotEmpty() -expect val Username.trim: Username +val Username.trim: Username + get() = Username(value.trim()) -expect val UsernameSaver: Saver, String> \ No newline at end of file +val UsernameSaver: Saver, String> + get() = Saver( + save = { it.value.value }, + restore = { mutableStateOf(Username(it)) } + ) \ No newline at end of file diff --git a/core/navigation-kmp/build.gradle.kts b/core/navigation-kmp/build.gradle.kts index 0d9098d36..2fe437c34 100644 --- a/core/navigation-kmp/build.gradle.kts +++ b/core/navigation-kmp/build.gradle.kts @@ -7,7 +7,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } diff --git a/core/network-kmp/build.gradle.kts b/core/network-kmp/build.gradle.kts index 5defbf258..9d0c211d5 100644 --- a/core/network-kmp/build.gradle.kts +++ b/core/network-kmp/build.gradle.kts @@ -17,7 +17,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } @@ -29,7 +29,6 @@ kotlin { implementation(libs.okhttp.logging.interceptor) implementation(libs.bundles.retrofit) implementation(libs.bundles.ktor) - implementation(libs.chucker.library) implementation(libs.flaker.android.okhttp) } } @@ -59,8 +58,15 @@ android { } dependencies { - debugImplementation(libs.chucker.library) - releaseImplementation(libs.chucker.library.no.op) + implementation(libs.chucker.library) { + exclude(group = "androidx.constraintlayout") + } + debugImplementation(libs.chucker.library) { + exclude(group = "androidx.constraintlayout") + } + releaseImplementation(libs.chucker.library.no.op) { + exclude(group = "androidx.constraintlayout") + } debugImplementation(libs.flaker.android.okhttp) releaseImplementation(libs.flaker.android.okhttp.noop) } diff --git a/core/persistence-kmp/build.gradle.kts b/core/persistence-kmp/build.gradle.kts index 1b8b64653..3aaf6745c 100644 --- a/core/persistence-kmp/build.gradle.kts +++ b/core/persistence-kmp/build.gradle.kts @@ -8,7 +8,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } diff --git a/core/repository-kmp/build.gradle.kts b/core/repository-kmp/build.gradle.kts index 941b03a39..958b7c3a6 100644 --- a/core/repository-kmp/build.gradle.kts +++ b/core/repository-kmp/build.gradle.kts @@ -8,7 +8,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } diff --git a/core/ui-kmp/build.gradle.kts b/core/ui-kmp/build.gradle.kts index 3318e4d4e..17e91f124 100644 --- a/core/ui-kmp/build.gradle.kts +++ b/core/ui-kmp/build.gradle.kts @@ -8,15 +8,22 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = rootProject.extra.get("jvmTarget") as String + } + } + } + jvm("desktop") { + compilations.all { + kotlinOptions { + jvmTarget = rootProject.extra.get("jvmTarget") as String } } } - jvm("desktop") sourceSets { commonMain.dependencies { implementation(project(":core:common-kmp")) + implementation(libs.constraintlayout.compose.multiplatform) implementation(compose.animation) implementation(compose.components.resources) implementation(compose.foundation) @@ -35,7 +42,6 @@ kotlin { implementation(project(":core:network-kmp")) implementation(project(":core:persistence-kmp")) api(libs.androidx.core.splashscreen) - api(libs.androidx.constraintlayout.compose) api(libs.androidx.palette.ktx) api(libs.coil.compose) api(libs.bundles.androidx.compose) @@ -56,6 +62,11 @@ android { compileSdk = libs.versions.compile.sdk.get().toInt() } + compileOptions { + sourceCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + targetCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + } + lint { quiet = true abortOnError = false diff --git a/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/accessibility/MoviesContentDescriptionCommon.kt b/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/accessibility/MoviesContentDescriptionCommon.kt new file mode 100644 index 000000000..2b92cae86 --- /dev/null +++ b/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/accessibility/MoviesContentDescriptionCommon.kt @@ -0,0 +1,5 @@ +package org.michaelbel.movies.ui.accessibility + +object MoviesContentDescriptionCommon { + val None: String? = null +} \ No newline at end of file diff --git a/core/ui-kmp/src/androidMain/kotlin/org/michaelbel/movies/ui/compose/SwitchCheckIcon.kt b/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/compose/SwitchCheckIcon.kt similarity index 84% rename from core/ui-kmp/src/androidMain/kotlin/org/michaelbel/movies/ui/compose/SwitchCheckIcon.kt rename to core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/compose/SwitchCheckIcon.kt index 4bdd43b04..4fe7c02c9 100644 --- a/core/ui-kmp/src/androidMain/kotlin/org/michaelbel/movies/ui/compose/SwitchCheckIcon.kt +++ b/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/compose/SwitchCheckIcon.kt @@ -7,11 +7,9 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SwitchDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview import org.michaelbel.movies.common.theme.AppTheme -import org.michaelbel.movies.ui.accessibility.MoviesContentDescription +import org.michaelbel.movies.ui.accessibility.MoviesContentDescriptionCommon import org.michaelbel.movies.ui.icons.MoviesIcons -import org.michaelbel.movies.ui.preview.DevicePreviews import org.michaelbel.movies.ui.theme.MoviesTheme @Composable @@ -20,13 +18,13 @@ fun SwitchCheckIcon( ) { Icon( imageVector = MoviesIcons.Check, - contentDescription = MoviesContentDescription.None, + contentDescription = MoviesContentDescriptionCommon.None, modifier = modifier.size(SwitchDefaults.IconSize), ) } @Composable -@DevicePreviews +/*@DevicePreviews*/ private fun SwitchCheckIconPreview() { MoviesTheme { SwitchCheckIcon( @@ -36,7 +34,7 @@ private fun SwitchCheckIconPreview() { } @Composable -@Preview +/*@Preview*/ private fun SwitchCheckIconAmoledPreview() { MoviesTheme( theme = AppTheme.Amoled diff --git a/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/compose/iconbutton/BackIcon.kt b/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/compose/iconbutton/BackIcon.kt index f84eb6c8d..322877a21 100644 --- a/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/compose/iconbutton/BackIcon.kt +++ b/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/compose/iconbutton/BackIcon.kt @@ -9,6 +9,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import org.michaelbel.movies.common.theme.AppTheme +import org.michaelbel.movies.ui.accessibility.MoviesContentDescriptionCommon import org.michaelbel.movies.ui.icons.MoviesIcons import org.michaelbel.movies.ui.theme.MoviesTheme @@ -24,7 +25,7 @@ fun BackIcon( ) { Image( imageVector = MoviesIcons.ArrowBack, - contentDescription = null, + contentDescription = MoviesContentDescriptionCommon.None, colorFilter = ColorFilter.tint(onContainerColor) ) } diff --git a/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/compose/iconbutton/SearchIcon.kt b/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/compose/iconbutton/SearchIcon.kt index fadf2da58..35eea6a7d 100644 --- a/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/compose/iconbutton/SearchIcon.kt +++ b/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/compose/iconbutton/SearchIcon.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ColorFilter import org.michaelbel.movies.common.theme.AppTheme +import org.michaelbel.movies.ui.accessibility.MoviesContentDescriptionCommon import org.michaelbel.movies.ui.icons.MoviesIcons import org.michaelbel.movies.ui.theme.MoviesTheme @@ -22,7 +23,7 @@ fun SearchIcon( ) { Image( imageVector = MoviesIcons.Search, - contentDescription = null, + contentDescription = MoviesContentDescriptionCommon.None, colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onPrimaryContainer) ) } diff --git a/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/compose/iconbutton/SettingsIcon.kt b/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/compose/iconbutton/SettingsIcon.kt index 15e8561e2..62087ee6e 100644 --- a/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/compose/iconbutton/SettingsIcon.kt +++ b/core/ui-kmp/src/commonMain/kotlin/org/michaelbel/movies/ui/compose/iconbutton/SettingsIcon.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ColorFilter import org.michaelbel.movies.common.theme.AppTheme +import org.michaelbel.movies.ui.accessibility.MoviesContentDescriptionCommon import org.michaelbel.movies.ui.icons.MoviesIcons import org.michaelbel.movies.ui.theme.MoviesTheme @@ -22,7 +23,7 @@ fun SettingsIcon( ) { Image( imageVector = MoviesIcons.Settings, - contentDescription = null, + contentDescription = MoviesContentDescriptionCommon.None, colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onPrimaryContainer) ) } diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index ea0e88db2..62104c8b9 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -49,7 +49,6 @@ dependencies { implementation(project(":core:persistence-kmp")) implementation(project(":core:ui-kmp")) api(libs.androidx.core.splashscreen) - api(libs.androidx.constraintlayout.compose) api(libs.androidx.palette.ktx) api(libs.coil.compose) api(libs.bundles.androidx.compose) diff --git a/core/work-kmp/build.gradle.kts b/core/work-kmp/build.gradle.kts index da2699b8b..5f379a9bf 100644 --- a/core/work-kmp/build.gradle.kts +++ b/core/work-kmp/build.gradle.kts @@ -8,7 +8,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } diff --git a/feature/account-impl-kmp/build.gradle.kts b/feature/account-impl-kmp/build.gradle.kts index ce35e02e9..c0c653b16 100644 --- a/feature/account-impl-kmp/build.gradle.kts +++ b/feature/account-impl-kmp/build.gradle.kts @@ -9,13 +9,22 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = rootProject.extra.get("jvmTarget") as String + } + } + } + jvm("desktop") { + compilations.all { + kotlinOptions { + jvmTarget = rootProject.extra.get("jvmTarget") as String } } } - jvm("desktop") sourceSets { + commonMain.dependencies { + implementation(libs.constraintlayout.compose.multiplatform) + } androidMain.dependencies { api(project(":core:navigation-kmp")) api(project(":core:ui")) @@ -58,6 +67,11 @@ android { kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get() } + compileOptions { + sourceCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + targetCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + } + lint { quiet = true abortOnError = false diff --git a/feature/account-kmp/build.gradle.kts b/feature/account-kmp/build.gradle.kts index 564e01f01..0e0b606dd 100644 --- a/feature/account-kmp/build.gradle.kts +++ b/feature/account-kmp/build.gradle.kts @@ -9,7 +9,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } @@ -18,21 +18,11 @@ kotlin { sourceSets { commonMain.dependencies { implementation(project(":core:navigation-kmp")) - } - androidMain.dependencies { implementation(project(":feature:account-impl-kmp")) } val desktopMain by getting desktopMain.dependencies { - implementation(project(":feature:account-impl-kmp")) - implementation(compose.desktop.currentOs) - implementation(compose.desktop.common) - implementation(compose.runtime) - implementation(compose.foundation) - implementation(compose.animation) - implementation(compose.material) implementation(compose.material3) - implementation(compose.components.resources) implementation(libs.precompose) } } diff --git a/feature/auth-impl-kmp/build.gradle.kts b/feature/auth-impl-kmp/build.gradle.kts index 1680ffd93..f23214240 100644 --- a/feature/auth-impl-kmp/build.gradle.kts +++ b/feature/auth-impl-kmp/build.gradle.kts @@ -9,13 +9,22 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = rootProject.extra.get("jvmTarget") as String + } + } + } + jvm("desktop") { + compilations.all { + kotlinOptions { + jvmTarget = rootProject.extra.get("jvmTarget") as String } } } - jvm("desktop") sourceSets { + commonMain.dependencies { + implementation(libs.constraintlayout.compose.multiplatform) + } androidMain.dependencies { api(project(":core:navigation-kmp")) api(project(":core:ui")) @@ -27,14 +36,7 @@ kotlin { } val desktopMain by getting desktopMain.dependencies { - implementation(compose.desktop.currentOs) - implementation(compose.desktop.common) - implementation(compose.runtime) - implementation(compose.foundation) - implementation(compose.animation) implementation(compose.material) - implementation(compose.material3) - implementation(compose.components.resources) implementation(libs.precompose) } } @@ -58,6 +60,11 @@ android { kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get() } + compileOptions { + sourceCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + targetCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + } + lint { quiet = true abortOnError = false diff --git a/feature/auth-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/auth/ui/AuthScreenContent.kt b/feature/auth-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/auth/ui/AuthScreenContent.kt index ce6e1637a..363b48a74 100644 --- a/feature/auth-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/auth/ui/AuthScreenContent.kt +++ b/feature/auth-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/auth/ui/AuthScreenContent.kt @@ -45,7 +45,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import org.michaelbel.movies.auth.AuthViewModel import org.michaelbel.movies.auth.ktx.text import org.michaelbel.movies.auth_impl_kmp.R -import org.michaelbel.movies.common.browser.openUrl +import org.michaelbel.movies.common.browser.openUrlAndroid import org.michaelbel.movies.common.exceptions.CreateSessionWithLoginException import org.michaelbel.movies.common.theme.AppTheme import org.michaelbel.movies.interactor.entity.Password @@ -114,7 +114,7 @@ fun AuthScreenContent( if (requestToken != null) { val signUrl = String.format(TMDB_AUTH_URL, requestToken, TMDB_AUTH_REDIRECT_URL) - openUrl(resultContract, toolbarColor, signUrl) + openUrlAndroid(resultContract, toolbarColor, signUrl) onResetRequestToken() } @@ -162,7 +162,7 @@ fun AuthScreenContent( top.linkTo(toolbar.bottom, 8.dp) end.linkTo(parent.end, 16.dp) } - .clickableWithoutRipple { openUrl(resultContract, toolbarColor, TMDB_URL) }, + .clickableWithoutRipple { openUrlAndroid(resultContract, toolbarColor, TMDB_URL) }, tint = MaterialTheme.colorScheme.onPrimaryContainer ) @@ -260,7 +260,7 @@ fun AuthScreenContent( exit = fadeOut() ) { TextButton( - onClick = { openUrl(resultContract, toolbarColor, TMDB_RESET_PASSWORD) } + onClick = { openUrlAndroid(resultContract, toolbarColor, TMDB_RESET_PASSWORD) } ) { Text( text = stringResource(R.string.auth_reset_password) @@ -281,7 +281,7 @@ fun AuthScreenContent( exit = fadeOut() ) { TextButton( - onClick = { openUrl(resultContract, toolbarColor, TMDB_REGISTER) } + onClick = { openUrlAndroid(resultContract, toolbarColor, TMDB_REGISTER) } ) { Text( text = stringResource(R.string.auth_sign_up) @@ -344,8 +344,8 @@ fun AuthScreenContent( } AuthLinksBox( - onTermsOfUseClick = { openUrl(resultContract, toolbarColor, TMDB_TERMS_OF_USE) }, - onPrivacyPolicyClick = { openUrl(resultContract, toolbarColor, TMDB_PRIVACY_POLICY) }, + onTermsOfUseClick = { openUrlAndroid(resultContract, toolbarColor, TMDB_TERMS_OF_USE) }, + onPrivacyPolicyClick = { openUrlAndroid(resultContract, toolbarColor, TMDB_PRIVACY_POLICY) }, modifier = Modifier.constrainAs(linksBox) { width = Dimension.fillToConstraints height = Dimension.wrapContent diff --git a/feature/auth-kmp/build.gradle.kts b/feature/auth-kmp/build.gradle.kts index 1f5dc7d48..a47df3a70 100644 --- a/feature/auth-kmp/build.gradle.kts +++ b/feature/auth-kmp/build.gradle.kts @@ -9,7 +9,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } @@ -25,14 +25,8 @@ kotlin { val desktopMain by getting desktopMain.dependencies { implementation(project(":feature:auth-impl-kmp")) - implementation(compose.desktop.currentOs) - implementation(compose.desktop.common) - implementation(compose.runtime) - implementation(compose.foundation) - implementation(compose.animation) implementation(compose.material) implementation(compose.material3) - implementation(compose.components.resources) implementation(libs.precompose) } } diff --git a/feature/details-impl-kmp/build.gradle.kts b/feature/details-impl-kmp/build.gradle.kts index d463c85f6..276e08f66 100644 --- a/feature/details-impl-kmp/build.gradle.kts +++ b/feature/details-impl-kmp/build.gradle.kts @@ -9,13 +9,22 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = rootProject.extra.get("jvmTarget") as String + } + } + } + jvm("desktop") { + compilations.all { + kotlinOptions { + jvmTarget = rootProject.extra.get("jvmTarget") as String } } } - jvm("desktop") sourceSets { + commonMain.dependencies { + implementation(libs.constraintlayout.compose.multiplatform) + } androidMain.dependencies { api(project(":core:navigation-kmp")) api(project(":core:ui")) @@ -26,14 +35,7 @@ kotlin { } val desktopMain by getting desktopMain.dependencies { - implementation(compose.desktop.currentOs) - implementation(compose.desktop.common) - implementation(compose.runtime) - implementation(compose.foundation) - implementation(compose.animation) - implementation(compose.material) implementation(compose.material3) - implementation(compose.components.resources) implementation(libs.precompose) } } @@ -57,6 +59,11 @@ android { kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get() } + compileOptions { + sourceCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + targetCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + } + lint { quiet = true abortOnError = false diff --git a/feature/details-kmp/build.gradle.kts b/feature/details-kmp/build.gradle.kts index 9d214aa50..426580575 100644 --- a/feature/details-kmp/build.gradle.kts +++ b/feature/details-kmp/build.gradle.kts @@ -9,7 +9,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } diff --git a/feature/feed-impl-kmp/build.gradle.kts b/feature/feed-impl-kmp/build.gradle.kts index e12d1f980..599fbaed8 100644 --- a/feature/feed-impl-kmp/build.gradle.kts +++ b/feature/feed-impl-kmp/build.gradle.kts @@ -9,13 +9,22 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = rootProject.extra.get("jvmTarget") as String + } + } + } + jvm("desktop") { + compilations.all { + kotlinOptions { + jvmTarget = rootProject.extra.get("jvmTarget") as String } } } - jvm("desktop") sourceSets { + commonMain.dependencies { + implementation(libs.constraintlayout.compose.multiplatform) + } androidMain.dependencies { implementation(project(":core:platform-services:interactor")) api(project(":core:navigation-kmp")) @@ -29,14 +38,8 @@ kotlin { val desktopMain by getting desktopMain.dependencies { implementation(project(":core:ui-kmp")) - implementation(compose.desktop.currentOs) - implementation(compose.desktop.common) - implementation(compose.runtime) - implementation(compose.foundation) - implementation(compose.animation) implementation(compose.material) implementation(compose.material3) - implementation(compose.components.resources) implementation(libs.precompose) } } @@ -60,6 +63,11 @@ android { kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get() } + compileOptions { + sourceCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + targetCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + } + lint { quiet = true abortOnError = false diff --git a/feature/feed-kmp/build.gradle.kts b/feature/feed-kmp/build.gradle.kts index 835c77f42..c139e1cfa 100644 --- a/feature/feed-kmp/build.gradle.kts +++ b/feature/feed-kmp/build.gradle.kts @@ -9,7 +9,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } diff --git a/feature/gallery-impl-kmp/build.gradle.kts b/feature/gallery-impl-kmp/build.gradle.kts index 5d48bafe0..7fb690b1f 100644 --- a/feature/gallery-impl-kmp/build.gradle.kts +++ b/feature/gallery-impl-kmp/build.gradle.kts @@ -9,13 +9,22 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = rootProject.extra.get("jvmTarget") as String + } + } + } + jvm("desktop") { + compilations.all { + kotlinOptions { + jvmTarget = rootProject.extra.get("jvmTarget") as String } } } - jvm("desktop") sourceSets { + commonMain.dependencies { + implementation(libs.constraintlayout.compose.multiplatform) + } androidMain.dependencies { api(project(":core:navigation-kmp")) api(project(":core:ui")) @@ -27,14 +36,7 @@ kotlin { } val desktopMain by getting desktopMain.dependencies { - implementation(compose.desktop.currentOs) - implementation(compose.desktop.common) - implementation(compose.runtime) - implementation(compose.foundation) - implementation(compose.animation) - implementation(compose.material) implementation(compose.material3) - implementation(compose.components.resources) implementation(libs.precompose) } } @@ -58,6 +60,11 @@ android { kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get() } + compileOptions { + sourceCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + targetCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + } + lint { quiet = true abortOnError = false diff --git a/feature/gallery-kmp/build.gradle.kts b/feature/gallery-kmp/build.gradle.kts index 815abf5dd..3532ecf64 100644 --- a/feature/gallery-kmp/build.gradle.kts +++ b/feature/gallery-kmp/build.gradle.kts @@ -9,7 +9,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } diff --git a/feature/search-impl-kmp/build.gradle.kts b/feature/search-impl-kmp/build.gradle.kts index a7e84ca30..1894db2c4 100644 --- a/feature/search-impl-kmp/build.gradle.kts +++ b/feature/search-impl-kmp/build.gradle.kts @@ -9,13 +9,22 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = rootProject.extra.get("jvmTarget") as String + } + } + } + jvm("desktop") { + compilations.all { + kotlinOptions { + jvmTarget = rootProject.extra.get("jvmTarget") as String } } } - jvm("desktop") sourceSets { + commonMain.dependencies { + implementation(libs.constraintlayout.compose.multiplatform) + } androidMain.dependencies { api(project(":core:navigation-kmp")) api(project(":core:ui")) @@ -27,14 +36,7 @@ kotlin { } val desktopMain by getting desktopMain.dependencies { - implementation(compose.desktop.currentOs) - implementation(compose.desktop.common) - implementation(compose.runtime) - implementation(compose.foundation) - implementation(compose.animation) - implementation(compose.material) implementation(compose.material3) - implementation(compose.components.resources) implementation(libs.precompose) } } @@ -58,6 +60,11 @@ android { kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get() } + compileOptions { + sourceCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + targetCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + } + lint { quiet = true abortOnError = false diff --git a/feature/search-kmp/build.gradle.kts b/feature/search-kmp/build.gradle.kts index 90e4434b5..5e2e64384 100644 --- a/feature/search-kmp/build.gradle.kts +++ b/feature/search-kmp/build.gradle.kts @@ -9,7 +9,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } diff --git a/feature/settings-impl-kmp/build.gradle.kts b/feature/settings-impl-kmp/build.gradle.kts index fa96773e8..79719e594 100644 --- a/feature/settings-impl-kmp/build.gradle.kts +++ b/feature/settings-impl-kmp/build.gradle.kts @@ -9,35 +9,37 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = rootProject.extra.get("jvmTarget") as String + } + } + } + jvm("desktop") { + compilations.all { + kotlinOptions { + jvmTarget = rootProject.extra.get("jvmTarget") as String } } } - jvm("desktop") sourceSets { + commonMain.dependencies { + implementation(project(":core:common-kmp")) + implementation(project(":core:ui-kmp")) + implementation(compose.components.resources) + implementation(compose.foundation) + implementation(compose.material3) + implementation(libs.constraintlayout.compose.multiplatform) + } androidMain.dependencies { - implementation(project(":core:platform-services:interactor")) - implementation(project(":core:widget")) - api(project(":core:navigation-kmp")) - api(project(":core:common-kmp")) - api(project(":core:ui")) - api(project(":core:ui-kmp")) implementation(project(":core:interactor-kmp")) + implementation(project(":core:navigation-kmp")) + implementation(project(":core:ui")) + implementation(project(":core:widget")) } val desktopMain by getting desktopMain.dependencies { - api(project(":core:common-kmp")) - api(project(":core:ui-kmp")) + implementation(project(":core:ui-kmp")) implementation(compose.desktop.currentOs) - implementation(compose.desktop.common) - implementation(compose.runtime) - implementation(compose.foundation) - implementation(compose.animation) - implementation(compose.material) - implementation(compose.material3) - implementation(compose.components.resources) - implementation(libs.precompose) } } } @@ -61,6 +63,11 @@ android { kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get() } + compileOptions { + sourceCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + targetCompatibility = JavaVersion.toVersion(rootProject.extra.get("jvmTarget") as String) + } + lint { quiet = true abortOnError = false diff --git a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ktx/IconAliasKtx.kt b/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ktx/IconAliasKtx.kt index bd3eaaa38..373a05590 100644 --- a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ktx/IconAliasKtx.kt +++ b/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ktx/IconAliasKtx.kt @@ -1,14 +1,12 @@ package org.michaelbel.movies.settings.ktx -import android.content.Context import org.michaelbel.movies.settings_impl_kmp.R import org.michaelbel.movies.ui.appicon.IconAlias -internal fun IconAlias.iconSnackbarText(context: Context): String { - return when (this) { - is IconAlias.Red -> context.getString(R.string.settings_app_launcher_icon_red) - is IconAlias.Purple -> context.getString(R.string.settings_app_launcher_icon_purple) - is IconAlias.Brown -> context.getString(R.string.settings_app_launcher_icon_brown) - is IconAlias.Amoled -> context.getString(R.string.settings_app_launcher_icon_amoled) - } -} \ No newline at end of file +internal val IconAlias.iconSnackbarTextRes: Int + get() = when (this) { + is IconAlias.Red -> R.string.settings_app_launcher_icon_red + is IconAlias.Purple -> R.string.settings_app_launcher_icon_purple + is IconAlias.Brown -> R.string.settings_app_launcher_icon_brown + is IconAlias.Amoled -> R.string.settings_app_launcher_icon_amoled + } \ No newline at end of file diff --git a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ktx/SealedStringKtx.kt b/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ktx/SealedStringKtx.kt deleted file mode 100644 index 5e5baed19..000000000 --- a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ktx/SealedStringKtx.kt +++ /dev/null @@ -1,37 +0,0 @@ -package org.michaelbel.movies.settings.ktx - -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource -import org.michaelbel.movies.common.SealedString -import org.michaelbel.movies.common.appearance.FeedView -import org.michaelbel.movies.common.gender.GrammaticalGender -import org.michaelbel.movies.common.list.MovieList -import org.michaelbel.movies.common.localization.model.AppLanguage -import org.michaelbel.movies.common.theme.AppTheme -import org.michaelbel.movies.settings_impl_kmp.R - -internal val SealedString.stringText: String - @Composable get() = when (this) { - is AppLanguage.English -> stringResource(R.string.settings_language_en) - is AppLanguage.Russian -> stringResource(R.string.settings_language_ru) - - is AppTheme.NightNo -> stringResource(R.string.settings_theme_light) - is AppTheme.NightYes -> stringResource(R.string.settings_theme_dark) - is AppTheme.FollowSystem -> stringResource(R.string.settings_theme_system) - is AppTheme.Amoled -> stringResource(R.string.settings_theme_amoled) - - is FeedView.FeedList -> stringResource(R.string.settings_appearance_list) - is FeedView.FeedGrid -> stringResource(R.string.settings_appearance_grid) - - is GrammaticalGender.NotSpecified -> stringResource(R.string.settings_gender_not_specified) - is GrammaticalGender.Neutral -> stringResource(R.string.settings_gender_neutral) - is GrammaticalGender.Feminine -> stringResource(R.string.settings_gender_feminine) - is GrammaticalGender.Masculine -> stringResource(R.string.settings_gender_masculine) - - is MovieList.NowPlaying -> stringResource(R.string.settings_movie_list_now_playing) - is MovieList.Popular -> stringResource(R.string.settings_movie_list_popular) - is MovieList.TopRated -> stringResource(R.string.settings_movie_list_top_rated) - is MovieList.Upcoming -> stringResource(R.string.settings_movie_list_upcoming) - - else -> "" - } \ No newline at end of file diff --git a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/SettingsScreenContent.kt b/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/SettingsScreenContent.kt index 533b4c51d..3854a07ee 100644 --- a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/SettingsScreenContent.kt +++ b/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/SettingsScreenContent.kt @@ -49,7 +49,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import kotlinx.coroutines.launch import org.michaelbel.movies.common.MOVIES_GITHUB_URL import org.michaelbel.movies.common.appearance.FeedView -import org.michaelbel.movies.common.browser.openUrl +import org.michaelbel.movies.common.browser.openUrlAndroid import org.michaelbel.movies.common.gender.GrammaticalGender import org.michaelbel.movies.common.ktx.notificationManager import org.michaelbel.movies.common.list.MovieList @@ -57,7 +57,7 @@ import org.michaelbel.movies.common.localization.model.AppLanguage import org.michaelbel.movies.common.theme.AppTheme import org.michaelbel.movies.common.version.AppVersionData import org.michaelbel.movies.settings.SettingsViewModel -import org.michaelbel.movies.settings.ktx.iconSnackbarText +import org.michaelbel.movies.settings.ktx.iconSnackbarTextRes import org.michaelbel.movies.settings.ktx.stringText import org.michaelbel.movies.settings.ui.common.SettingAppIcon import org.michaelbel.movies.settings.ui.common.SettingItem @@ -511,7 +511,7 @@ private fun SettingsScreenContent( SettingAppIcon( iconAlias = IconAlias.Red, onClick = { icon -> - onShowSnackbar(context.getString(R.string.settings_app_launcher_icon_changed_to, icon.iconSnackbarText(context))) + onShowSnackbar(context.getString(R.string.settings_app_launcher_icon_changed_to, context.getString(icon.iconSnackbarTextRes))) context.setIcon(icon) } ) @@ -519,7 +519,7 @@ private fun SettingsScreenContent( SettingAppIcon( iconAlias = IconAlias.Purple, onClick = { icon -> - onShowSnackbar(context.getString(R.string.settings_app_launcher_icon_changed_to, icon.iconSnackbarText(context))) + onShowSnackbar(context.getString(R.string.settings_app_launcher_icon_changed_to, context.getString(icon.iconSnackbarTextRes))) context.setIcon(icon) } ) @@ -527,7 +527,7 @@ private fun SettingsScreenContent( SettingAppIcon( iconAlias = IconAlias.Brown, onClick = { icon -> - onShowSnackbar(context.getString(R.string.settings_app_launcher_icon_changed_to, icon.iconSnackbarText(context))) + onShowSnackbar(context.getString(R.string.settings_app_launcher_icon_changed_to, context.getString(icon.iconSnackbarTextRes))) context.setIcon(icon) } ) @@ -535,7 +535,7 @@ private fun SettingsScreenContent( SettingAppIcon( iconAlias = IconAlias.Amoled, onClick = { icon -> - onShowSnackbar(context.getString(R.string.settings_app_launcher_icon_changed_to, icon.iconSnackbarText(context))) + onShowSnackbar(context.getString(R.string.settings_app_launcher_icon_changed_to, context.getString(icon.iconSnackbarTextRes))) context.setIcon(icon) } ) @@ -555,7 +555,7 @@ private fun SettingsScreenContent( title = stringResource(R.string.settings_github), description = stringResource(R.string.settings_github_description), icon = MoviesIcons.Github, - onClick = { openUrl(resultContract, toolbarColor, MOVIES_GITHUB_URL) } + onClick = { openUrlAndroid(resultContract, toolbarColor, MOVIES_GITHUB_URL) } ) } if (isReviewFeatureEnabled) { diff --git a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/SettingsToolbar.kt b/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/SettingsToolbar.kt index a09a5083c..c6b7a9de8 100644 --- a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/SettingsToolbar.kt +++ b/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/SettingsToolbar.kt @@ -12,7 +12,6 @@ import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import org.michaelbel.movies.common.theme.AppTheme @@ -32,17 +31,13 @@ internal fun SettingsToolbar( title = { Text( text = stringResource(R.string.settings_title), - modifier = Modifier.testTag("TitleText"), color = MaterialTheme.colorScheme.onPrimaryContainer ) }, - modifier = modifier.testTag("TopAppBar"), navigationIcon = { BackIcon( onClick = onNavigationIconClick, - modifier = Modifier - .windowInsetsPadding(displayCutoutWindowInsets) - .testTag("BackIconButton") + modifier = Modifier.windowInsetsPadding(displayCutoutWindowInsets) ) }, colors = TopAppBarDefaults.topAppBarColors( diff --git a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/SettingsVersionBox.kt b/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/SettingsVersionBox.kt index 3a31542eb..562ff6118 100644 --- a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/SettingsVersionBox.kt +++ b/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/SettingsVersionBox.kt @@ -9,7 +9,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter @@ -32,7 +31,7 @@ internal fun SettingsVersionBox( modifier: Modifier = Modifier ) { ConstraintLayout( - modifier = modifier.testTag("ConstraintLayout") + modifier = modifier ) { val (icon, version, code, flavor, debug) = createRefs() createHorizontalChain(icon, version, code, flavor, debug, chainStyle = ChainStyle.Packed) @@ -40,16 +39,14 @@ internal fun SettingsVersionBox( Icon( imageVector = MoviesIcons.MovieFilter, contentDescription = MoviesContentDescription.None, - modifier = Modifier - .constrainAs(icon) { - width = Dimension.value(24.dp) - height = Dimension.value(24.dp) - start.linkTo(parent.start) - top.linkTo(parent.top) - end.linkTo(version.start) - bottom.linkTo(parent.bottom) - } - .testTag("Icon"), + modifier = Modifier.constrainAs(icon) { + width = Dimension.value(24.dp) + height = Dimension.value(24.dp) + start.linkTo(parent.start) + top.linkTo(parent.top) + end.linkTo(version.start) + bottom.linkTo(parent.bottom) + }, tint = MaterialTheme.colorScheme.primary ) @@ -64,8 +61,7 @@ internal fun SettingsVersionBox( end.linkTo(code.start) bottom.linkTo(icon.bottom) } - .padding(start = 4.dp) - .testTag("TitleText"), + .padding(start = 4.dp), style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onPrimaryContainer) ) @@ -80,8 +76,7 @@ internal fun SettingsVersionBox( end.linkTo(flavor.start) bottom.linkTo(icon.bottom) } - .padding(start = 2.dp) - .testTag("ValueText"), + .padding(start = 2.dp), style = MaterialTheme.typography.bodySmall.copy(MaterialTheme.colorScheme.primary) ) @@ -96,8 +91,7 @@ internal fun SettingsVersionBox( end.linkTo(if (appVersionData.isDebug) debug.start else parent.end) bottom.linkTo(icon.bottom) } - .padding(start = 2.dp) - .testTag("FlavorText"), + .padding(start = 2.dp), style = MaterialTheme.typography.bodySmall.copy(MaterialTheme.colorScheme.onPrimaryContainer) ) @@ -113,8 +107,7 @@ internal fun SettingsVersionBox( end.linkTo(parent.end) bottom.linkTo(icon.bottom) } - .padding(start = 2.dp) - .testTag("DebugText"), + .padding(start = 2.dp), style = MaterialTheme.typography.bodySmall.copy(MaterialTheme.colorScheme.onPrimaryContainer) ) } diff --git a/feature/settings-impl-kmp/src/commonMain/composeResources/values-ru/strings.xml b/feature/settings-impl-kmp/src/commonMain/composeResources/values-ru/strings.xml new file mode 100644 index 000000000..dc26ce3f9 --- /dev/null +++ b/feature/settings-impl-kmp/src/commonMain/composeResources/values-ru/strings.xml @@ -0,0 +1,57 @@ + + Настройки + Тема + По умолчанию + Светлая + Темная + Amoled + Цвета обоев + Извлечь цвета из обоев + Уведомления + Разрешение отклонено + Разрешение предоставлено + Оцени приложение + Используя In-App Review API + Уведомления отключены. Активируйте их в настройках приложения + Перейти + Сервисы Google play недоступны + Приложение должно быть загружено из Google Play + Язык + English + Русский + Вид + Список + Сетка + Список фильмов + Премьеры + Популярные + Топ + Скоро + Иконка Приложения + Красную + Фиолетовую + Коричневую + Amoled + Иконка приложения изменена на %s + Movies v%s + (%s) + Debug + Отмена + Movies на GitHub + Посмотреть GitHub-репозиторий + Добавить виджет на главный экран + 3x2 %s + Добавить плитку в шторку + Плитка для запуска аппки + Плитка уже добавлена + Род + Не указан + Средний + Женский + Мужской + Запаролить приложение + Биометрия включена + Биометрия отключена + Обнови приложение + Используя In-App Update API + \ No newline at end of file diff --git a/feature/settings-impl-kmp/src/commonMain/composeResources/values/strings.xml b/feature/settings-impl-kmp/src/commonMain/composeResources/values/strings.xml new file mode 100644 index 000000000..4352e9289 --- /dev/null +++ b/feature/settings-impl-kmp/src/commonMain/composeResources/values/strings.xml @@ -0,0 +1,57 @@ + + Settings + Theme + Follow System + Light + Dark + Amoled + Dynamic Colors + Apply colors from wallpaper + Notifications + Permission denied + Permission granted + Rate App + Using In-App Review API + Notifications are disabled. Please go to app settings to activate them + Go + Google play services are not available + Your version of app must be downloaded from Google Play + Language + English + Русский + Appearance + List + Grid + Movie List + Now Playing + Popular + Top Rated + Upcoming + App Icon + Red + Purple + Brown + Amoled + App icon changed to %s + Movies v%s + (%s) + Debug + Cancel + Movies on GitHub + Check the GitHub repository + Add Widget to Home Screen + 3x2 %s + Add Tile to Quick Settings + Movies launcher tile + Tile already added + Gender + Not specified + Neutral + Feminine + Masculine + Lock App + Biometric added + Biometric not added + Update App + Using In-App Update API + \ No newline at end of file diff --git a/feature/settings-impl-kmp/src/commonMain/kotlin/org/michaelbel/movies/settings/ktx/SealedStringKtx.kt b/feature/settings-impl-kmp/src/commonMain/kotlin/org/michaelbel/movies/settings/ktx/SealedStringKtx.kt new file mode 100644 index 000000000..e57390e87 --- /dev/null +++ b/feature/settings-impl-kmp/src/commonMain/kotlin/org/michaelbel/movies/settings/ktx/SealedStringKtx.kt @@ -0,0 +1,56 @@ +@file:OptIn(ExperimentalResourceApi::class) + +package org.michaelbel.movies.settings.ktx + +import androidx.compose.runtime.Composable +import movies.feature.settings_impl_kmp.generated.resources.Res +import movies.feature.settings_impl_kmp.generated.resources.settings_appearance_grid +import movies.feature.settings_impl_kmp.generated.resources.settings_appearance_list +import movies.feature.settings_impl_kmp.generated.resources.settings_gender_feminine +import movies.feature.settings_impl_kmp.generated.resources.settings_gender_masculine +import movies.feature.settings_impl_kmp.generated.resources.settings_gender_neutral +import movies.feature.settings_impl_kmp.generated.resources.settings_gender_not_specified +import movies.feature.settings_impl_kmp.generated.resources.settings_language_en +import movies.feature.settings_impl_kmp.generated.resources.settings_language_ru +import movies.feature.settings_impl_kmp.generated.resources.settings_movie_list_now_playing +import movies.feature.settings_impl_kmp.generated.resources.settings_movie_list_popular +import movies.feature.settings_impl_kmp.generated.resources.settings_movie_list_top_rated +import movies.feature.settings_impl_kmp.generated.resources.settings_movie_list_upcoming +import movies.feature.settings_impl_kmp.generated.resources.settings_theme_amoled +import movies.feature.settings_impl_kmp.generated.resources.settings_theme_dark +import movies.feature.settings_impl_kmp.generated.resources.settings_theme_light +import movies.feature.settings_impl_kmp.generated.resources.settings_theme_system +import org.jetbrains.compose.resources.ExperimentalResourceApi +import org.jetbrains.compose.resources.stringResource +import org.michaelbel.movies.common.SealedString +import org.michaelbel.movies.common.appearance.FeedView +import org.michaelbel.movies.common.gender.GrammaticalGender +import org.michaelbel.movies.common.list.MovieList +import org.michaelbel.movies.common.localization.model.AppLanguage +import org.michaelbel.movies.common.theme.AppTheme + +val SealedString.stringText: String + @Composable get() = when (this) { + is AppLanguage.English -> stringResource(Res.string.settings_language_en) + is AppLanguage.Russian -> stringResource(Res.string.settings_language_ru) + + is AppTheme.NightNo -> stringResource(Res.string.settings_theme_light) + is AppTheme.NightYes -> stringResource(Res.string.settings_theme_dark) + is AppTheme.FollowSystem -> stringResource(Res.string.settings_theme_system) + is AppTheme.Amoled -> stringResource(Res.string.settings_theme_amoled) + + is FeedView.FeedList -> stringResource(Res.string.settings_appearance_list) + is FeedView.FeedGrid -> stringResource(Res.string.settings_appearance_grid) + + is GrammaticalGender.NotSpecified -> stringResource(Res.string.settings_gender_not_specified) + is GrammaticalGender.Neutral -> stringResource(Res.string.settings_gender_neutral) + is GrammaticalGender.Feminine -> stringResource(Res.string.settings_gender_feminine) + is GrammaticalGender.Masculine -> stringResource(Res.string.settings_gender_masculine) + + is MovieList.NowPlaying -> stringResource(Res.string.settings_movie_list_now_playing) + is MovieList.Popular -> stringResource(Res.string.settings_movie_list_popular) + is MovieList.TopRated -> stringResource(Res.string.settings_movie_list_top_rated) + is MovieList.Upcoming -> stringResource(Res.string.settings_movie_list_upcoming) + + else -> "" + } \ No newline at end of file diff --git a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingDialog.kt b/feature/settings-impl-kmp/src/commonMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingDialog.kt similarity index 80% rename from feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingDialog.kt rename to feature/settings-impl-kmp/src/commonMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingDialog.kt index 05a7d3a22..03123fd5f 100644 --- a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingDialog.kt +++ b/feature/settings-impl-kmp/src/commonMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingDialog.kt @@ -1,3 +1,5 @@ +@file:OptIn(ExperimentalResourceApi::class) + package org.michaelbel.movies.settings.ui.common import androidx.compose.foundation.clickable @@ -20,22 +22,14 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.platform.testTag -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp +import movies.feature.settings_impl_kmp.generated.resources.Res +import movies.feature.settings_impl_kmp.generated.resources.settings_action_cancel +import org.jetbrains.compose.resources.ExperimentalResourceApi +import org.jetbrains.compose.resources.stringResource import org.michaelbel.movies.common.SealedString -import org.michaelbel.movies.common.localization.model.AppLanguage -import org.michaelbel.movies.common.theme.AppTheme import org.michaelbel.movies.settings.ktx.stringText -import org.michaelbel.movies.settings_impl_kmp.R -import org.michaelbel.movies.ui.accessibility.MoviesContentDescription -import org.michaelbel.movies.ui.icons.MoviesIcons -import org.michaelbel.movies.ui.preview.DevicePreviews -import org.michaelbel.movies.ui.preview.provider.AppearancePreviewParameterProvider -import org.michaelbel.movies.ui.preview.provider.LanguagePreviewParameterProvider -import org.michaelbel.movies.ui.theme.MoviesTheme +import org.michaelbel.movies.ui.accessibility.MoviesContentDescriptionCommon @Composable internal fun SettingsDialog( @@ -50,12 +44,10 @@ internal fun SettingsDialog( onDismissRequest = onDismissRequest, confirmButton = { TextButton( - onClick = onDismissRequest, - modifier = Modifier.testTag("ConfirmTextButton") + onClick = onDismissRequest ) { Text( - text = stringResource(R.string.settings_action_cancel), - modifier = Modifier.testTag("ConfirmText"), + text = stringResource(Res.string.settings_action_cancel), style = MaterialTheme.typography.labelLarge.copy(MaterialTheme.colorScheme.primary) ) } @@ -63,14 +55,12 @@ internal fun SettingsDialog( icon = { Icon( imageVector = icon, - contentDescription = stringResource(MoviesContentDescription.AppearanceIcon), - modifier = Modifier.testTag("Icon") + contentDescription = MoviesContentDescriptionCommon.None ) }, title = { Text( text = title, - modifier = Modifier.testTag("Title"), style = MaterialTheme.typography.headlineSmall.copy(MaterialTheme.colorScheme.onSurface) ) }, @@ -119,6 +109,7 @@ internal fun SettingsDialog( ) } +/* @Composable @DevicePreviews private fun SettingDialogPreview( @@ -153,4 +144,4 @@ private fun SettingDialogAmoledPreview( onDismissRequest = {} ) } -} \ No newline at end of file +}*/ diff --git a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingItem.kt b/feature/settings-impl-kmp/src/commonMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingItem.kt similarity index 91% rename from feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingItem.kt rename to feature/settings-impl-kmp/src/commonMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingItem.kt index da0afb408..dd2de2591 100644 --- a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingItem.kt +++ b/feature/settings-impl-kmp/src/commonMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingItem.kt @@ -14,12 +14,10 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import org.michaelbel.movies.common.theme.AppTheme -import org.michaelbel.movies.ui.accessibility.MoviesContentDescription +import org.michaelbel.movies.ui.accessibility.MoviesContentDescriptionCommon import org.michaelbel.movies.ui.icons.MoviesIcons -import org.michaelbel.movies.ui.preview.DevicePreviews import org.michaelbel.movies.ui.theme.MoviesTheme @Composable @@ -33,13 +31,13 @@ internal fun SettingItem( Row( modifier = modifier .fillMaxWidth() - .clickable { onClick() } + .clickable(onClick = onClick) .padding(horizontal = 8.dp, vertical = 20.dp), verticalAlignment = Alignment.CenterVertically, ) { Icon( imageVector = icon, - contentDescription = MoviesContentDescription.None, + contentDescription = MoviesContentDescriptionCommon.None, modifier = Modifier .padding(start = 8.dp, end = 16.dp) .size(24.dp), @@ -63,7 +61,7 @@ internal fun SettingItem( } @Composable -@DevicePreviews +/*@DevicePreviews*/ private fun SettingItemPreview() { MoviesTheme { SettingItem( @@ -77,7 +75,7 @@ private fun SettingItemPreview() { } @Composable -@Preview +/*@Preview*/ private fun SettingItemAmoledPreview() { MoviesTheme( theme = AppTheme.Amoled diff --git a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingSwitchItem.kt b/feature/settings-impl-kmp/src/commonMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingSwitchItem.kt similarity index 81% rename from feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingSwitchItem.kt rename to feature/settings-impl-kmp/src/commonMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingSwitchItem.kt index 31be76af1..3c2c442ce 100644 --- a/feature/settings-impl-kmp/src/androidMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingSwitchItem.kt +++ b/feature/settings-impl-kmp/src/commonMain/kotlin/org/michaelbel/movies/settings/ui/common/SettingSwitchItem.kt @@ -14,18 +14,13 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.platform.testTag -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.constraintlayout.compose.ConstraintLayout import androidx.constraintlayout.compose.Dimension import org.michaelbel.movies.common.theme.AppTheme -import org.michaelbel.movies.ui.accessibility.MoviesContentDescription +import org.michaelbel.movies.ui.accessibility.MoviesContentDescriptionCommon import org.michaelbel.movies.ui.compose.SwitchCheckIcon import org.michaelbel.movies.ui.icons.MoviesIcons -import org.michaelbel.movies.ui.preview.DevicePreviews -import org.michaelbel.movies.ui.preview.provider.BooleanPreviewParameterProvider import org.michaelbel.movies.ui.theme.MoviesTheme @Composable @@ -47,7 +42,7 @@ internal fun SettingSwitchItem( Icon( imageVector = icon, - contentDescription = MoviesContentDescription.None, + contentDescription = MoviesContentDescriptionCommon.None, modifier = Modifier.constrainAs(iconRef) { width = Dimension.value(24.dp) height = Dimension.value(24.dp) @@ -82,15 +77,13 @@ internal fun SettingSwitchItem( Switch( checked = checked, onCheckedChange = null, - modifier = Modifier - .constrainAs(switch) { - width = Dimension.wrapContent - height = Dimension.wrapContent - top.linkTo(parent.top) - end.linkTo(parent.end, 16.dp) - bottom.linkTo(parent.bottom) - } - .testTag("Switch"), + modifier = Modifier.constrainAs(switch) { + width = Dimension.wrapContent + height = Dimension.wrapContent + top.linkTo(parent.top) + end.linkTo(parent.end, 16.dp) + bottom.linkTo(parent.bottom) + }, thumbContent = if (checked) { { SwitchCheckIcon() } } else null, colors = SwitchDefaults.colors( checkedTrackColor = MaterialTheme.colorScheme.surfaceTint, @@ -119,7 +112,7 @@ internal fun SettingSwitchItem( Icon( painter = icon, - contentDescription = MoviesContentDescription.None, + contentDescription = MoviesContentDescriptionCommon.None, modifier = Modifier.constrainAs(iconRef) { width = Dimension.value(24.dp) height = Dimension.value(24.dp) @@ -154,15 +147,13 @@ internal fun SettingSwitchItem( Switch( checked = checked, onCheckedChange = null, - modifier = Modifier - .constrainAs(switch) { - width = Dimension.wrapContent - height = Dimension.wrapContent - top.linkTo(parent.top) - end.linkTo(parent.end, 16.dp) - bottom.linkTo(parent.bottom) - } - .testTag("Switch"), + modifier = Modifier.constrainAs(switch) { + width = Dimension.wrapContent + height = Dimension.wrapContent + top.linkTo(parent.top) + end.linkTo(parent.end, 16.dp) + bottom.linkTo(parent.bottom) + }, thumbContent = if (checked) { { SwitchCheckIcon() } } else null, colors = SwitchDefaults.colors( checkedTrackColor = MaterialTheme.colorScheme.surfaceTint, @@ -173,9 +164,9 @@ internal fun SettingSwitchItem( } @Composable -@DevicePreviews +/*@DevicePreviews*/ private fun SettingSwitchItemPreview( - @PreviewParameter(BooleanPreviewParameterProvider::class) checked: Boolean + /*@PreviewParameter(BooleanPreviewParameterProvider::class)*/ checked: Boolean ) { MoviesTheme { SettingSwitchItem( @@ -190,9 +181,9 @@ private fun SettingSwitchItemPreview( } @Composable -@Preview +/*@Preview*/ private fun SettingSwitchItemAmoledPreview( - @PreviewParameter(BooleanPreviewParameterProvider::class) checked: Boolean + /*@PreviewParameter(BooleanPreviewParameterProvider::class)*/ checked: Boolean ) { MoviesTheme( theme = AppTheme.Amoled diff --git a/feature/settings-impl-kmp/src/desktopMain/kotlin/org/michaelbel/movies/settings/ui/SettingsScreenContent.kt b/feature/settings-impl-kmp/src/desktopMain/kotlin/org/michaelbel/movies/settings/ui/SettingsScreenContent.kt index d47535dc9..558e56873 100644 --- a/feature/settings-impl-kmp/src/desktopMain/kotlin/org/michaelbel/movies/settings/ui/SettingsScreenContent.kt +++ b/feature/settings-impl-kmp/src/desktopMain/kotlin/org/michaelbel/movies/settings/ui/SettingsScreenContent.kt @@ -1,22 +1,33 @@ -@file:OptIn(ExperimentalMaterial3Api::class) +@file:OptIn(ExperimentalResourceApi::class) package org.michaelbel.movies.settings.ui import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.unit.dp +import movies.feature.settings_impl_kmp.generated.resources.Res +import movies.feature.settings_impl_kmp.generated.resources.settings_github +import movies.feature.settings_impl_kmp.generated.resources.settings_github_description +import movies.feature.settings_impl_kmp.generated.resources.settings_language +import org.jetbrains.compose.resources.ExperimentalResourceApi +import org.jetbrains.compose.resources.stringResource +import org.michaelbel.movies.common.MOVIES_GITHUB_URL +import org.michaelbel.movies.common.browser.openUrlDesktop +import org.michaelbel.movies.common.localization.model.AppLanguage +import org.michaelbel.movies.settings.ui.common.SettingItem +import org.michaelbel.movies.settings.ui.common.SettingsDialog +import org.michaelbel.movies.ui.icons.MoviesIcons @Composable fun SettingsRoute( @@ -34,18 +45,13 @@ private fun SettingsScreenContent( onBackClick: () -> Unit, modifier: Modifier = Modifier ) { - val topAppBarScrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior( - state = rememberTopAppBarState(), - canScroll = { true } - ) val lazyListState = rememberLazyListState() Scaffold( - modifier = modifier.nestedScroll(topAppBarScrollBehavior.nestedScrollConnection), + modifier = modifier, topBar = { SettingsToolbar( modifier = Modifier.fillMaxWidth(), - topAppBarScrollBehavior = topAppBarScrollBehavior, onNavigationIconClick = onBackClick ) }, @@ -56,31 +62,24 @@ private fun SettingsScreenContent( contentPadding = innerPadding ) { item { - HorizontalDivider( - modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp), - thickness = .1.dp, - color = MaterialTheme.colorScheme.onPrimaryContainer - ) - } - item { - HorizontalDivider( - modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp), - thickness = .1.dp, - color = MaterialTheme.colorScheme.onPrimaryContainer - ) - } - item { - HorizontalDivider( - modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp), - thickness = .1.dp, - color = MaterialTheme.colorScheme.onPrimaryContainer - ) - } - item { - HorizontalDivider( - modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp), - thickness = .1.dp, - color = MaterialTheme.colorScheme.onPrimaryContainer + var languageDialog by remember { mutableStateOf(false) } + + if (languageDialog) { + SettingsDialog( + icon = MoviesIcons.Language, + title = stringResource(Res.string.settings_language), + items = AppLanguage.VALUES, + currentItem = AppLanguage.English, + onItemSelect = {}, + onDismissRequest = { languageDialog = false } + ) + } + + SettingItem( + title = stringResource(Res.string.settings_language), + description = "English", + icon = MoviesIcons.Language, + onClick = { languageDialog = true } ) } item { @@ -91,10 +90,11 @@ private fun SettingsScreenContent( ) } item { - HorizontalDivider( - modifier = Modifier.height(5000.dp).padding(horizontal = 16.dp, vertical = 4.dp), - thickness = .1.dp, - color = MaterialTheme.colorScheme.onPrimaryContainer + SettingItem( + title = stringResource(Res.string.settings_github), + description = stringResource(Res.string.settings_github_description), + icon = MoviesIcons.Github, + onClick = { openUrlDesktop(MOVIES_GITHUB_URL) } ) } } diff --git a/feature/settings-impl-kmp/src/desktopMain/kotlin/org/michaelbel/movies/settings/ui/SettingsToolbar.kt b/feature/settings-impl-kmp/src/desktopMain/kotlin/org/michaelbel/movies/settings/ui/SettingsToolbar.kt index 61c5a0334..7c3e6a825 100644 --- a/feature/settings-impl-kmp/src/desktopMain/kotlin/org/michaelbel/movies/settings/ui/SettingsToolbar.kt +++ b/feature/settings-impl-kmp/src/desktopMain/kotlin/org/michaelbel/movies/settings/ui/SettingsToolbar.kt @@ -1,18 +1,20 @@ -@file:OptIn(ExperimentalMaterial3Api::class) +@file:OptIn(ExperimentalMaterial3Api::class, ExperimentalResourceApi::class) package org.michaelbel.movies.settings.ui import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.LargeTopAppBar import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.testTag +import movies.feature.settings_impl_kmp.generated.resources.Res +import movies.feature.settings_impl_kmp.generated.resources.settings_title +import org.jetbrains.compose.resources.ExperimentalResourceApi +import org.jetbrains.compose.resources.stringResource import org.michaelbel.movies.common.theme.AppTheme import org.michaelbel.movies.ui.compose.iconbutton.BackIcon import org.michaelbel.movies.ui.theme.MoviesTheme @@ -20,17 +22,16 @@ import org.michaelbel.movies.ui.theme.MoviesTheme @Composable internal fun SettingsToolbar( modifier: Modifier = Modifier, - topAppBarScrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(), onNavigationIconClick: () -> Unit ) { - LargeTopAppBar( + TopAppBar( title = { Text( - text = "Settings", + text = stringResource(Res.string.settings_title), color = MaterialTheme.colorScheme.onPrimaryContainer ) }, - modifier = modifier.testTag("TopAppBar"), + modifier = modifier, navigationIcon = { BackIcon( onClick = onNavigationIconClick @@ -39,8 +40,7 @@ internal fun SettingsToolbar( colors = TopAppBarDefaults.topAppBarColors( containerColor = MaterialTheme.colorScheme.primaryContainer, scrolledContainerColor = MaterialTheme.colorScheme.inversePrimary - ), - scrollBehavior = topAppBarScrollBehavior + ) ) } diff --git a/feature/settings-kmp/build.gradle.kts b/feature/settings-kmp/build.gradle.kts index 128669850..46d952171 100644 --- a/feature/settings-kmp/build.gradle.kts +++ b/feature/settings-kmp/build.gradle.kts @@ -9,7 +9,7 @@ kotlin { androidTarget { compilations.all { kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_1_8.toString() } } } @@ -20,6 +20,7 @@ kotlin { implementation(project(":core:navigation-kmp")) } androidMain.dependencies { + implementation(project(":core:ui-kmp")) implementation(project(":feature:settings-impl-kmp")) } val desktopMain by getting diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8b2599810..b2d8e7d5e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -41,7 +41,6 @@ androidx-compose-material-icons-extended = "1.6.4" androidx-compose-material3 = "1.2.1" androidx-core-ktx = "1.12.0" androidx-core-splashscreen = "1.0.1" -androidx-constraintlayout = "1.0.1" androidx-datastore = "1.0.0" androidx-lifecycle = "2.7.0" androidx-glance = "1.0.0" @@ -64,7 +63,7 @@ compose = "1.6.1" detekt = "1.23.5" spotless = "6.25.0" coil = "2.6.0" -coil3 = "3.0.0-alpha01" +coil3 = "3.0.0-alpha05" okhttp = "4.12.0" retrofit = "2.10.0" chucker = "4.0.0" @@ -86,6 +85,7 @@ kotest = "5.8.1" sqldelight = "2.0.1" koin = "3.5.3" precompose = "1.6.0-rc04" +constraintlayout-compose-multiplatform = "0.3.1" [libraries] kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" } @@ -115,7 +115,6 @@ androidx-benchmark-macro-junit = { module = "androidx.benchmark:benchmark-macro- androidx-biometric-ktx = { module = "androidx.biometric:biometric-ktx", version.ref = "androidx-biometric-ktx" } androidx-browser = { module = "androidx.browser:browser", version.ref = "androidx-browser" } androidx-collection = { module = "androidx.collection:collection", version.ref = "androidx-collection" } -androidx-constraintlayout-compose = { module = "androidx.constraintlayout:constraintlayout-compose", version.ref = "androidx-constraintlayout" } androidx-compose-animation = { module = "androidx.compose.animation:animation", version.ref = "androidx-compose-animation" } androidx-compose-compiler = { module = "androidx.compose.compiler:compiler", version.ref = "androidx-compose-compiler" } androidx-compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "androidx-compose-foundation" } @@ -231,6 +230,7 @@ koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose", versi koin-test = { module = "io.insert-koin:koin-test", version.ref = "koin" } koin-test-junit4 = { module = "io.insert-koin:koin-test-junit4", version.ref = "koin" } precompose = { module = "moe.tlaster:precompose", version.ref = "precompose" } +constraintlayout-compose-multiplatform = { module = "tech.annexflow.compose:constraintlayout-compose-multiplatform", version.ref = "constraintlayout-compose-multiplatform" } gradle-plugin = { module = "com.android.tools.build:gradle", version.ref = "agp" } kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }