import org.jetbrains.compose.ExperimentalComposeLibrary import org.jetbrains.compose.desktop.application.dsl.TargetFormat import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import java.util.* plugins { alias(libs.plugins.multiplatform) alias(libs.plugins.compose.compiler) alias(libs.plugins.compose) alias(libs.plugins.compose.hot.reload) alias(libs.plugins.android.application) alias(libs.plugins.kotlinx.serialization) } tasks.withType().configureEach { compilerOptions { freeCompilerArgs.addAll( "-opt-in=kotlin.RequiresOptIn", "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", "-opt-in=kotlinx.coroutines.FlowPreview", "-Xexpect-actual-classes" ) } } kotlin { androidTarget { compilerOptions { jvmTarget.set(JvmTarget.JVM_21) } } jvm() if (providers.gradleProperty("include_ios").get().toBoolean()) { listOf( iosX64(), iosArm64(), iosSimulatorArm64() ).forEach { iosTarget -> iosTarget.binaries.framework { baseName = "ComposeApp" isStatic = true } } } if (providers.gradleProperty("include_wasm").get().toBoolean()) { @OptIn(ExperimentalWasmDsl::class) wasmJs { outputModuleName = "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() } } sourceSets { commonMain.dependencies { implementation(compose.runtime) implementation(compose.foundation) implementation(compose.material3) implementation(compose.materialIconsExtended) implementation(compose.components.resources) implementation(libs.androidx.navigation.compose) 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) } findByName("iosMain")?.run { dependencies { implementation(libs.ktor.client.darwin) implementation(libs.kstore.file) } } findByName("wasmJsMain")?.run { dependencies { implementation(libs.kstore.storage) implementation(libs.ktor.client.js) } } } } android { namespace = "dev.meloda.overseerr" compileSdk = 36 defaultConfig { minSdk = 26 targetSdk = 36 applicationId = "dev.meloda.overseerr" versionCode = 1 versionName = "1.0.0" } packaging { resources { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } 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") // signingConfig = signingConfigs.getByName("debug") isMinifyEnabled = true isShrinkResources = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } compileOptions { sourceCompatibility = JavaVersion.VERSION_21 targetCompatibility = JavaVersion.VERSION_21 } } dependencies { androidTestImplementation(libs.androidx.uitest.junit4) debugImplementation(libs.androidx.uitest.testManifest) debugImplementation(compose.uiTooling) } compose.desktop { application { mainClass = "MainKt" nativeDistributions { targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) packageName = "dev.meloda.overseerr" packageVersion = "1.0.0" } } }