From 095ce70849053ea7d998919b9218555275cbe89b Mon Sep 17 00:00:00 2001 From: Maciej Procyk Date: Sun, 12 Nov 2023 12:24:40 +0100 Subject: [PATCH] update to Kotlin 1.9.20, compose-multiplatofrm 1.5.10 and resolve compilation warnings --- androidApp/build.gradle.kts | 7 +- desktopApp/build.gradle.kts | 19 +- .../{jvmMain => desktopMain}/kotlin/main.kt | 0 .../resources/ic_launcher.icns | Bin .../resources/ic_launcher.ico | Bin .../resources/ic_launcher.png | Bin gradle/libs.versions.toml | 8 +- shared/build.gradle.kts | 164 +++++++++--------- .../dev/kotlin/openotp/util/BiometryUtil.kt | 13 +- .../ml/dev/kotlin/openotp/OpenOtpApp.kt | 2 +- .../openotp/ui/component/OtpCodeItems.kt | 2 +- .../dev/kotlin/openotp/util/DecomposeUtil.kt | 5 - 12 files changed, 109 insertions(+), 111 deletions(-) rename desktopApp/src/{jvmMain => desktopMain}/kotlin/main.kt (100%) rename desktopApp/src/{jvmMain => desktopMain}/resources/ic_launcher.icns (100%) rename desktopApp/src/{jvmMain => desktopMain}/resources/ic_launcher.ico (100%) rename desktopApp/src/{jvmMain => desktopMain}/resources/ic_launcher.png (100%) diff --git a/androidApp/build.gradle.kts b/androidApp/build.gradle.kts index a090fec..d552a0d 100644 --- a/androidApp/build.gradle.kts +++ b/androidApp/build.gradle.kts @@ -9,11 +9,10 @@ plugins { kotlin { androidTarget() + sourceSets { - val androidMain by getting { - dependencies { - implementation(project(":shared")) - } + androidMain.dependencies { + implementation(project(":shared")) } } } diff --git a/desktopApp/build.gradle.kts b/desktopApp/build.gradle.kts index d83798c..6591f44 100644 --- a/desktopApp/build.gradle.kts +++ b/desktopApp/build.gradle.kts @@ -8,13 +8,14 @@ plugins { } kotlin { - jvm() + jvm("desktop") + sourceSets { - val jvmMain by getting { - dependencies { - implementation(compose.desktop.currentOs) - implementation(project(":shared")) - } + val desktopMain by getting + + desktopMain.dependencies { + implementation(compose.desktop.currentOs) + implementation(project(":shared")) } } jvmToolchain(17) @@ -32,17 +33,17 @@ compose.desktop { windows { menu = false upgradeUuid = "b3aef4be-d942-4334-bdfc-6f42a7689c17" - iconFile.set(projectDir.resolve("src/jvmMain/resources/ic_launcher.ico")) + iconFile.set(projectDir.resolve("src/desktopMain/resources/ic_launcher.ico")) } linux { - iconFile.set(projectDir.resolve("src/jvmMain/resources/ic_launcher.png")) + iconFile.set(projectDir.resolve("src/desktopMain/resources/ic_launcher.png")) } macOS { bundleID = "ml.dev.kotlin.openotp.OpenOtp" appStore = false - iconFile.set(projectDir.resolve("src/jvmMain/resources/ic_launcher.icns")) + iconFile.set(projectDir.resolve("src/desktopMain/resources/ic_launcher.icns")) signing { sign.set(false) } diff --git a/desktopApp/src/jvmMain/kotlin/main.kt b/desktopApp/src/desktopMain/kotlin/main.kt similarity index 100% rename from desktopApp/src/jvmMain/kotlin/main.kt rename to desktopApp/src/desktopMain/kotlin/main.kt diff --git a/desktopApp/src/jvmMain/resources/ic_launcher.icns b/desktopApp/src/desktopMain/resources/ic_launcher.icns similarity index 100% rename from desktopApp/src/jvmMain/resources/ic_launcher.icns rename to desktopApp/src/desktopMain/resources/ic_launcher.icns diff --git a/desktopApp/src/jvmMain/resources/ic_launcher.ico b/desktopApp/src/desktopMain/resources/ic_launcher.ico similarity index 100% rename from desktopApp/src/jvmMain/resources/ic_launcher.ico rename to desktopApp/src/desktopMain/resources/ic_launcher.ico diff --git a/desktopApp/src/jvmMain/resources/ic_launcher.png b/desktopApp/src/desktopMain/resources/ic_launcher.png similarity index 100% rename from desktopApp/src/jvmMain/resources/ic_launcher.png rename to desktopApp/src/desktopMain/resources/ic_launcher.png diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8ad3368..ee84ff6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ android-gradle-plugin = "8.1.0" android-minSdk = "26" # @keep android-targetSdk = "34" -androidx-activity-compose = "1.8.0-rc01" +androidx-activity-compose = "1.8.0" androidx-appcompat-appcompat = "1.6.1" androidx-biometric = "1.2.0-alpha05" androidx-core-ktx = "1.12.0" @@ -15,8 +15,8 @@ androidx-core-ktx = "1.12.0" androidx-crypto = "1.1.0-alpha05" barcodeScanning = "17.2.0" buffer = "1.3.6" -compose = "1.5.3" -compose-extensions = "0.0.2" +compose = "1.5.10" +compose-extensions = "1.5.10.0" decompose = "2.2.0-compose-experimental-alpha01" encoding = "2.0.0" essenty = "1.3.0-alpha01" @@ -25,7 +25,7 @@ kermit = "2.0.0-RC5" koin = "3.5.0" koin-compose = "1.1.0" # @pin -kotlin = "1.9.10" +kotlin = "1.9.20" kotlincrypto-hash = "0.3.0" kotlincrypto-macs = "0.3.0" kotlincrypto-secure-random = "0.1.0" diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 08e33a4..9451d1f 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -1,5 +1,6 @@ import dev.icerock.gradle.MRVisibility import org.jetbrains.compose.ExperimentalComposeLibrary +import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask plugins { alias(libs.plugins.kotlin.multiplatform) @@ -31,7 +32,11 @@ kotlin { } } + applyDefaultHierarchyTemplate() + sourceSets { + val desktopMain by getting + all { languageSettings.apply { optIn("kotlin.contracts.ExperimentalContracts") @@ -45,71 +50,67 @@ kotlin { optIn("androidx.compose.material3.ExperimentalMaterial3Api") optIn("androidx.compose.material.ExperimentalMaterialApi") optIn("com.arkivanov.decompose.ExperimentalDecomposeApi") - optIn("com.google.accompanist.permissions.ExperimentalPermissionsApi") } } - val commonMain by getting { - dependencies { - implementation(compose.runtime) - implementation(compose.foundation) - implementation(compose.material) - implementation(compose.material3) - implementation(compose.materialIconsExtended) - implementation(compose.animationGraphics) - - @OptIn(ExperimentalComposeLibrary::class) - implementation(compose.components.resources) - - implementation(libs.kotlinx.datetime) - implementation(libs.buffer) - implementation(libs.uuid) - implementation(libs.encoding.base32) - - implementation(libs.kotlincrypto.hash.sha2) - implementation(libs.kotlincrypto.macs.hmac.sha1) - implementation(libs.kotlincrypto.macs.hmac.sha2) - implementation(libs.kotlincrypto.secure.random) - implementation(libs.kotlincrypto.secure.random) - - implementation(libs.koin.core) - implementation(libs.koin.compose) - - implementation(libs.kermit) - implementation(libs.uriKmp) - - implementation(libs.multiplatform.settings) - implementation(libs.multiplatform.settings.coroutines) - - api(libs.decompose) - api(libs.decompose.extensionsComposeJetbrains) - - implementation(libs.kotlinx.serialization.json) - implementation(libs.kotlinx.serialization.cbor) - - api(libs.essenty.lifecycle) - api(libs.essenty.stateKeeper) - api(libs.essenty.parcelable) - api(libs.essenty.instanceKeeper) - - api(libs.moko.resoures) - api(libs.moko.resoures.compose) - - implementation(libs.compose.extensions.camera.permission) - implementation(libs.compose.extensions.camera.qr) - implementation(libs.compose.extensions.util) - - implementation(libs.ktor.client.content.negotiation) - implementation(libs.ktor.client.core) - implementation(libs.ktor.serialization.kotlinx.json) - } + commonMain.dependencies { + implementation(compose.runtime) + implementation(compose.foundation) + implementation(compose.material) + implementation(compose.material3) + implementation(compose.materialIconsExtended) + implementation(compose.animationGraphics) + + @OptIn(ExperimentalComposeLibrary::class) + implementation(compose.components.resources) + + implementation(libs.kotlinx.datetime) + implementation(libs.buffer) + implementation(libs.uuid) + implementation(libs.encoding.base32) + + implementation(libs.kotlincrypto.hash.sha2) + implementation(libs.kotlincrypto.macs.hmac.sha1) + implementation(libs.kotlincrypto.macs.hmac.sha2) + implementation(libs.kotlincrypto.secure.random) + implementation(libs.kotlincrypto.secure.random) + + implementation(libs.koin.core) + implementation(libs.koin.compose) + + implementation(libs.kermit) + implementation(libs.uriKmp) + + implementation(libs.multiplatform.settings) + implementation(libs.multiplatform.settings.coroutines) + + api(libs.decompose) + api(libs.decompose.extensionsComposeJetbrains) + + implementation(libs.kotlinx.serialization.json) + implementation(libs.kotlinx.serialization.cbor) + + api(libs.essenty.lifecycle) + api(libs.essenty.stateKeeper) + api(libs.essenty.parcelable) + api(libs.essenty.instanceKeeper) + + api(libs.moko.resoures) + api(libs.moko.resoures.compose) + + implementation(libs.compose.extensions.camera.permission) + implementation(libs.compose.extensions.camera.qr) + implementation(libs.compose.extensions.util) + + implementation(libs.ktor.client.content.negotiation) + implementation(libs.ktor.client.core) + implementation(libs.ktor.serialization.kotlinx.json) } - val commonTest by getting { - dependencies { - implementation(kotlin("test")) - } + commonTest.dependencies { + implementation(kotlin("test")) } - val androidMain by getting { - dependsOn(commonMain) + + androidMain { + dependsOn(commonMain.get()) dependencies { api(libs.androidx.activity.compose) @@ -125,15 +126,14 @@ kotlin { runtimeOnly(libs.kotlinx.coroutines.android) } + + languageSettings { + optIn("com.google.accompanist.permissions.ExperimentalPermissionsApi") + } } - val iosX64Main by getting - val iosArm64Main by getting - val iosSimulatorArm64Main by getting - val iosMain by creating { - dependsOn(commonMain) - iosX64Main.dependsOn(this) - iosArm64Main.dependsOn(this) - iosSimulatorArm64Main.dependsOn(this) + + iosMain { + dependsOn(commonMain.get()) dependencies { implementation(libs.ktor.client.darwin) @@ -141,20 +141,18 @@ kotlin { api(libs.parcelize.darwinRuntime) } } - val desktopMain by getting { - dependsOn(commonMain) - dependencies { - implementation(compose.desktop.common) - implementation(libs.webcam.capture) - implementation(libs.webcam.capture.driver.native) - implementation(libs.zxing.core) - implementation(libs.zxing.javase) + desktopMain.dependsOn(commonMain.get()) + desktopMain.dependencies { + implementation(compose.desktop.common) + implementation(libs.webcam.capture) + implementation(libs.webcam.capture.driver.native) + implementation(libs.zxing.core) + implementation(libs.zxing.javase) - runtimeOnly(libs.kotlinx.coroutines.swing) + runtimeOnly(libs.kotlinx.coroutines.swing) - implementation(libs.ktor.client.okhttp) - } + implementation(libs.ktor.client.okhttp) } } } @@ -187,3 +185,9 @@ multiplatformResources { multiplatformResourcesSourceSet = "commonMain" disableStaticFrameworkWarning = true } + +tasks.withType>().all { + compilerOptions { + freeCompilerArgs.add("-Xexpect-actual-classes") + } +} diff --git a/shared/src/androidMain/kotlin/ml/dev/kotlin/openotp/util/BiometryUtil.kt b/shared/src/androidMain/kotlin/ml/dev/kotlin/openotp/util/BiometryUtil.kt index d721708..749ebf5 100644 --- a/shared/src/androidMain/kotlin/ml/dev/kotlin/openotp/util/BiometryUtil.kt +++ b/shared/src/androidMain/kotlin/ml/dev/kotlin/openotp/util/BiometryUtil.kt @@ -3,7 +3,7 @@ package ml.dev.kotlin.openotp.util import android.annotation.SuppressLint import android.content.Context import androidx.biometric.BiometricManager -import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK +import androidx.biometric.BiometricManager.Authenticators.* import androidx.biometric.BiometricPrompt import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -14,9 +14,8 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentManager import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.OnLifecycleEvent import java.util.concurrent.Executor import kotlin.coroutines.suspendCoroutine @@ -28,10 +27,10 @@ actual class BiometryAuthenticator( fun bind(lifecycle: Lifecycle, fragmentManager: FragmentManager) { this.fragmentManager = fragmentManager - val observer = object : LifecycleObserver { + val observer = object : LifecycleEventObserver { + override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { + if (event != Lifecycle.Event.ON_DESTROY) return - @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) - fun onDestroyed(source: LifecycleOwner) { this@BiometryAuthenticator.fragmentManager = null source.lifecycle.removeObserver(this) } @@ -130,7 +129,7 @@ actual class BiometryAuthenticator( promptInfo = BiometricPrompt.PromptInfo.Builder() .setTitle(requestTitle) .setSubtitle(requestReason) - .setDeviceCredentialAllowed(true) + .setAllowedAuthenticators(BIOMETRIC_WEAK or BIOMETRIC_STRONG or DEVICE_CREDENTIAL) .build() biometricPrompt.authenticate(promptInfo) diff --git a/shared/src/commonMain/kotlin/ml/dev/kotlin/openotp/OpenOtpApp.kt b/shared/src/commonMain/kotlin/ml/dev/kotlin/openotp/OpenOtpApp.kt index 0d02986..d8f215a 100644 --- a/shared/src/commonMain/kotlin/ml/dev/kotlin/openotp/OpenOtpApp.kt +++ b/shared/src/commonMain/kotlin/ml/dev/kotlin/openotp/OpenOtpApp.kt @@ -12,6 +12,7 @@ import com.arkivanov.decompose.extensions.compose.jetbrains.stack.Children import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.slide import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.stackAnimation import com.arkivanov.decompose.extensions.compose.jetbrains.subscribeAsState +import `in`.procyk.compose.util.OnceLaunchedEffect import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.serialization.builtins.ListSerializer import ml.dev.kotlin.openotp.component.LinkedAccountsSyncState.NothingToSync @@ -24,7 +25,6 @@ import ml.dev.kotlin.openotp.ui.screen.* import ml.dev.kotlin.openotp.ui.theme.OpenOtpTheme import ml.dev.kotlin.openotp.util.BindBiometryAuthenticatorEffect import ml.dev.kotlin.openotp.util.BiometryAuthenticator -import ml.dev.kotlin.openotp.util.OnceLaunchedEffect import ml.dev.kotlin.openotp.util.StateFlowSettings import org.koin.compose.koinInject import org.koin.core.context.startKoin diff --git a/shared/src/commonMain/kotlin/ml/dev/kotlin/openotp/ui/component/OtpCodeItems.kt b/shared/src/commonMain/kotlin/ml/dev/kotlin/openotp/ui/component/OtpCodeItems.kt index 0ef7862..b02bda0 100644 --- a/shared/src/commonMain/kotlin/ml/dev/kotlin/openotp/ui/component/OtpCodeItems.kt +++ b/shared/src/commonMain/kotlin/ml/dev/kotlin/openotp/ui/component/OtpCodeItems.kt @@ -32,6 +32,7 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import dev.icerock.moko.resources.compose.stringResource +import `in`.procyk.compose.util.OnceLaunchedEffect import kotlinx.coroutines.isActive import ml.dev.kotlin.openotp.otp.HotpData import ml.dev.kotlin.openotp.otp.OtpData @@ -39,7 +40,6 @@ import ml.dev.kotlin.openotp.otp.PresentedOtpCodeData import ml.dev.kotlin.openotp.otp.TotpData import ml.dev.kotlin.openotp.shared.OpenOtpResources import ml.dev.kotlin.openotp.ui.issuerIcon -import ml.dev.kotlin.openotp.util.OnceLaunchedEffect import ml.dev.kotlin.openotp.util.currentEpochMilliseconds import ml.dev.kotlin.openotp.util.letTrue import kotlin.math.roundToInt diff --git a/shared/src/commonMain/kotlin/ml/dev/kotlin/openotp/util/DecomposeUtil.kt b/shared/src/commonMain/kotlin/ml/dev/kotlin/openotp/util/DecomposeUtil.kt index 38bc23f..12f7a6f 100644 --- a/shared/src/commonMain/kotlin/ml/dev/kotlin/openotp/util/DecomposeUtil.kt +++ b/shared/src/commonMain/kotlin/ml/dev/kotlin/openotp/util/DecomposeUtil.kt @@ -1,7 +1,5 @@ package ml.dev.kotlin.openotp.util -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import com.arkivanov.decompose.value.MutableValue import com.arkivanov.decompose.value.Value import com.arkivanov.essenty.lifecycle.Lifecycle @@ -21,9 +19,6 @@ fun LifecycleOwner.coroutineScope(context: CoroutineContext): CoroutineScope { return scope } -@Composable -inline fun OnceLaunchedEffect(noinline block: suspend CoroutineScope.() -> Unit): Unit = LaunchedEffect(Unit, block) - fun StateFlow.asValue( lifecycle: Lifecycle, context: CoroutineContext = Dispatchers.Main.immediate,