import com.android.build.api.dsl.ManagedVirtualDevice import org.jetbrains.compose.ExperimentalComposeLibrary import org.jetbrains.compose.desktop.application.dsl.TargetFormat import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig import java.util.* plugins { alias(libs.plugins.multiplatform) alias(libs.plugins.compose.compiler) alias(libs.plugins.compose) alias(libs.plugins.android.application) alias(libs.plugins.kotlinx.serialization) } kotlin { @OptIn(ExperimentalWasmDsl::class) wasmJs { moduleName = "composeApp" browser { val rootDirPath = project.rootDir.path val projectDirPath = project.projectDir.path commonWebpackConfig { outputFileName = "composeApp.js" devServer = (devServer ?: KotlinWebpackConfig.DevServer()).apply { static = (static ?: mutableListOf()).apply { // Serve sources to debug inside browser add(rootDirPath) add(projectDirPath) } } } } binaries.executable() } androidTarget { compilations.all { compileTaskProvider { compilerOptions { jvmTarget.set(JvmTarget.JVM_17) //https://jakewharton.com/gradle-toolchains-are-rarely-a-good-idea/#what-do-i-do freeCompilerArgs.add("-Xjdk-release=${JavaVersion.VERSION_17}") } } } //https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-test.html @OptIn(ExperimentalKotlinGradlePluginApi::class) instrumentedTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) } jvm() listOf( iosX64(), iosArm64(), iosSimulatorArm64() ).forEach { it.binaries.framework { baseName = "ComposeApp" isStatic = true } } sourceSets { commonMain.dependencies { implementation(compose.runtime) implementation(compose.foundation) implementation(compose.material3) implementation(compose.materialIconsExtended) implementation(compose.components.resources) implementation(compose.components.uiToolingPreview) implementation(libs.voyager.navigator) implementation(libs.voyager.transitions) implementation(libs.coil) implementation(libs.coil.network.ktor) implementation(libs.kotlinx.coroutines.core) implementation(libs.ktor.core) implementation(libs.ktor.client.content.negotiation) implementation(libs.ktor.kotlinx.serialization.json) implementation(libs.kotlinx.serialization.json) implementation(libs.koin.core) implementation(libs.koin.compose) implementation(libs.koin.compose.viewmodel) implementation(libs.androidx.lifecycle.viewmodel) implementation(libs.androidx.lifecycle.viewmodel.compose) implementation(libs.androidx.lifecycle.runtime.compose) implementation(libs.haze) implementation(libs.haze.materials) implementation(libs.kstore) implementation(libs.napier) } commonTest.dependencies { implementation(kotlin("test")) @OptIn(ExperimentalComposeLibrary::class) implementation(compose.uiTest) implementation(libs.kotlinx.coroutines.test) } androidMain.dependencies { implementation(compose.uiTooling) implementation(libs.androidx.activityCompose) implementation(libs.kotlinx.coroutines.android) implementation(libs.ktor.client.okhttp) implementation(libs.kstore.file) } jvmMain.dependencies { implementation(compose.desktop.currentOs) implementation(libs.kotlinx.coroutines.swing) implementation(libs.ktor.client.okhttp) implementation(libs.appdirs) implementation(libs.kstore.file) } iosMain.dependencies { implementation(libs.ktor.client.darwin) implementation(libs.kstore.file) } wasmJsMain.dependencies { implementation(libs.kstore.storage) implementation(libs.ktor.client.js) } } } android { namespace = "dev.meloda.overseerr" compileSdk = 35 defaultConfig { minSdk = 26 targetSdk = 35 applicationId = "dev.meloda.overseerr" versionCode = 1 versionName = "1.0.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } //https://developer.android.com/studio/test/gradle-managed-devices @Suppress("UnstableApiUsage") testOptions { managedDevices.devices { maybeCreate("pixel5").apply { device = "Pixel 5" apiLevel = 34 systemImageSource = "aosp" } } } signingConfigs { create("release") { val keystoreProperties = Properties() val keystorePropertiesFile = file("./src/androidMain/keystore/keystore.properties") storeFile = file("./src/androidMain/keystore/keystore.jks") if (keystorePropertiesFile.exists()) { keystorePropertiesFile.inputStream().let(keystoreProperties::load) storePassword = keystoreProperties.getProperty("storePassword") keyAlias = keystoreProperties.getProperty("keyAlias") keyPassword = keystoreProperties.getProperty("keyPassword") } else { storePassword = System.getenv("KEYSTORE_PASSWORD") keyAlias = System.getenv("RELEASE_SIGN_KEY_ALIAS") keyPassword = System.getenv("RELEASE_SIGN_KEY_PASSWORD") } } create("debugSigning") { initWith(getByName("release")) } } buildTypes { getByName("debug") { signingConfig = signingConfigs.getByName("debugSigning") } getByName("release") { signingConfig = signingConfigs.getByName("release") isMinifyEnabled = false } } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } } //https://developer.android.com/develop/ui/compose/testing#setup dependencies { androidTestImplementation(libs.androidx.uitest.junit4) debugImplementation(libs.androidx.uitest.testManifest) //temporary fix: https://youtrack.jetbrains.com/issue/CMP-5864 androidTestImplementation("androidx.test:monitor") { version { strictly("1.6.1") } } } compose.desktop { application { mainClass = "MainKt" nativeDistributions { targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) packageName = "dev.meloda.overseerr" packageVersion = "1.0.0" } } }