diff --git a/android/build.gradle.kts b/android/build.gradle.kts index f37792e1..fb95b215 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -16,7 +16,6 @@ import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties import org.jetbrains.compose.compose -import org.jetbrains.kotlin.kapt.cli.main plugins { id("com.android.application") @@ -79,6 +78,9 @@ android { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } + packagingOptions { + exclude("META-INF/*") + } configurations { "implementation" { exclude(group = "androidx.compose.animation") @@ -92,7 +94,7 @@ android { dependencies { implementation(compose.material) implementation(compose.materialIconsExtended) - implementation(Androidx.androidxActivity) + implementation(deps.androidx.activity) // Project's SubModules implementation(project(":common:database")) @@ -103,43 +105,39 @@ dependencies { implementation(project(":common:core-components")) implementation(project(":common:providers")) - // Koin - implementation(Koin.android) - implementation(Koin.compose) + with(deps) { - // DECOMPOSE - implementation(Decompose.decompose) - implementation(Decompose.extensionsCompose) + // Koin + with(koin) { + implementation(androidx.compose) + implementation(android) + } - // MVI - implementation(MVIKotlin.mvikotlin) - implementation(MVIKotlin.mvikotlinMain) - implementation(MVIKotlin.mvikotlinLogging) - implementation(MVIKotlin.mvikotlinTimeTravel) + // DECOMPOSE + with(decompose) { + implementation(dep) + implementation(extensions.compose) + } - // Extras - with(Extras.Android) { - implementation(countly) - implementation(appUpdator) + implementation(countly.android) + implementation(android.app.notifier) + implementation(storage.chooser) + + with(bundles) { + implementation(androidx.lifecycle) + implementation(mviKotlin) + implementation(accompanist.inset) + } + + // Test + testImplementation(junit) + androidTestImplementation(androidx.junit) + androidTestImplementation(androidx.expresso) + + // Desugar + coreLibraryDesugaring(androidx.desugar) + + // Debug + debugImplementation(leak.canary) } - - with(Versions.androidxLifecycle) { - implementation("androidx.lifecycle:lifecycle-service:$this") - implementation("androidx.lifecycle:lifecycle-common-java8:$this") - implementation("androidx.lifecycle:lifecycle-runtime-ktx:$this") - } - - implementation(Extras.kermit) - // implementation("com.jakewharton.timber:timber:4.7.1") - implementation("dev.icerock.moko:parcelize:${Versions.mokoParcelize}") - implementation("com.github.shabinder:storage-chooser:2.0.4.45") - implementation("com.google.accompanist:accompanist-insets:0.16.1") - - // Test - testImplementation("junit:junit:4.13.2") - androidTestImplementation(Androidx.junit) - androidTestImplementation(Androidx.expresso) - - // Desugaring - coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.5") } diff --git a/build.gradle.kts b/build.gradle.kts index d775fc1f..c6ff0025 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -38,22 +38,32 @@ allprojects { tasks.withType>().configureEach { dependsOn(":common:data-models:generateI18n4kFiles") kotlinOptions { - if(this is org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions) { + if (this is org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions) { jvmTarget = "1.8" } freeCompilerArgs = (freeCompilerArgs + listOf("-Xopt-in=kotlin.RequiresOptIn")) } } - - afterEvaluate { - project.extensions.findByType()?.let { kmpExt -> - kmpExt.sourceSets.run { - all { - languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn") - languageSettings.useExperimentalAnnotation("kotlinx.serialization.ExperimentalSerializationApi") + configurations.all { + resolutionStrategy { + eachDependency { + if (requested.group == "org.jetbrains.kotlin") { + @Suppress("UnstableApiUsage") + useVersion(deps.kotlin.kotlinGradlePlugin.get().versionConstraint.requiredVersion) } - removeAll { it.name == "androidAndroidTestRelease" } } } } + afterEvaluate { + project.extensions.findByType() + ?.let { kmpExt -> + kmpExt.sourceSets.run { + all { + languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn") + languageSettings.useExperimentalAnnotation("kotlinx.serialization.ExperimentalSerializationApi") + } + removeAll { it.name == "androidAndroidTestRelease" } + } + } + } } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 33d0caf4..7c635940 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -30,17 +30,20 @@ repositories { } dependencies { - implementation(Androidx.gradlePlugin) - implementation(JetBrains.Compose.gradlePlugin) - implementation(JetBrains.Kotlin.gradlePlugin) - implementation(JetBrains.Kotlin.serialization) - implementation(SqlDelight.gradlePlugin) - implementation(KTLint.gradlePlugin) - implementation(Internationalization.gradlePlugin) - implementation(Mosaic.gradlePlugin) + with(deps) { + implementation(androidx.gradle.plugin) + implementation(kotlin.compose.gradle) + implementation(ktlint.gradle) + implementation(mosaic.gradle) + implementation(kotlin.kotlinGradlePlugin) + implementation(sqldelight.gradle.plugin) + implementation(i18n4k.gradle.plugin) + implementation(kotlin.serialization) + } } kotlin { // Add Deps to compilation, so it will become available in main project sourceSets.getByName("main").kotlin.srcDir("buildSrc/src/main/kotlin") } + diff --git a/buildSrc/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/buildSrc/src/main/kotlin/Versions.kt index f837ff4b..9de83bc6 100644 --- a/buildSrc/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/buildSrc/src/main/kotlin/Versions.kt @@ -14,11 +14,15 @@ * * along with this program. If not, see . */ -@file:Suppress("MayBeConstant", "SpellCheckingInspection") +@file:Suppress("MayBeConstant", "SpellCheckingInspection", "UnstableApiUsage") +import org.gradle.api.Project import org.gradle.api.artifacts.ExternalModuleDependency +import org.gradle.api.artifacts.VersionCatalog +import org.gradle.api.artifacts.VersionCatalogsExtension import org.gradle.api.artifacts.dsl.DependencyHandler import org.gradle.kotlin.dsl.accessors.runtime.addDependencyTo +import org.gradle.kotlin.dsl.getByType object Versions { // App's Version (To be bumped at each update) @@ -26,44 +30,10 @@ object Versions { const val versionCode = 26 - // Kotlin - const val kotlinVersion = "1.5.21" - - const val coroutinesVersion = "1.5.1" - - // Code Formatting - const val ktLint = "10.1.0" - - // Console-App UI - const val mosaic = "0.1.0" - - // DI - const val koin = "3.1.2" - - // Logger - const val kermit = "0.1.9" - - const val mokoParcelize = "0.7.1" - - // Internet - const val ktor = "1.6.2" - - const val kotlinxSerialization = "1.2.2" - - // Database - const val sqlDelight = "1.5.1" - - const val sqliteJdbcDriver = "3.34.0" - const val slf4j = "1.7.31" - - // Internationalisation - const val i18n4k = "0.1.3" - // Android const val minSdkVersion = 21 - const val compileSdkVersion = 30 + const val compileSdkVersion = 31 const val targetSdkVersion = 29 - const val androidxLifecycle = "2.4.0-alpha03" } object HostOS { @@ -74,143 +44,46 @@ object HostOS { val isLinux = hostOs.startsWith("Linux", true) } -object MultiPlatformSettings { - const val dep = "com.russhwolf:multiplatform-settings-no-arg:0.7.7" -} +val Project.Deps: VersionCatalog get() = project.extensions.getByType().named("deps") -object KotlinJSWrappers { - private const val bomVersion = "0.0.1-pre.235-kotlin-1.5.21" - val bom = "org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom:${bomVersion}" - const val kotlinReact = "org.jetbrains.kotlin-wrappers:kotlin-react" - const val kotlinReactDom = "org.jetbrains.kotlin-wrappers:kotlin-react-dom" - const val kotlinStyled = "org.jetbrains.kotlin-wrappers:kotlin-styled" -} +val VersionCatalog.ktorBundle get() = findBundle("ktor").get() +val VersionCatalog.statelyBundle get() = findBundle("stately").get() +val VersionCatalog.androidXLifecycleBundle get() = findBundle("androidx-lifecycle").get() +val VersionCatalog.androidXCommonBundle get() = findBundle("androidx-common").get() +val VersionCatalog.kotlinTestBundle get() = findBundle("kotlin-test").get() +val VersionCatalog.sqldelightBundle get() = findBundle("sqldelight").get() +val VersionCatalog.mviKotlinBundle get() = findBundle("mviKotlin").get() +val VersionCatalog.essentyBundle get() = findBundle("essenty").get() +val VersionCatalog.koinAndroidBundle get() = findBundle("koin-android").get() +val VersionCatalog.kotlinJSWrappers get() = findBundle("kotlin-js-wrappers").get() -object Koin { - val core = "io.insert-koin:koin-core:${Versions.koin}" - val test = "io.insert-koin:koin-test:${Versions.koin}" - val android = "io.insert-koin:koin-android:${Versions.koin}" - val compose = "io.insert-koin:koin-androidx-compose:${Versions.koin}" -} +val VersionCatalog.kotlinJunitTest get() = findDependency("kotlin-kotlinTestJunit").get() +val VersionCatalog.kotlinJSTest get() = findDependency("kotlin-kotlinTestJs").get() +val VersionCatalog.kermit get() = findDependency("kermit").get() +val VersionCatalog.decompose get() = findDependency("decompose-dep").get() +val VersionCatalog.decomposeComposeExt get() = findDependency("decompose-extensions-compose").get() +val VersionCatalog.jaffree get() = findDependency("jaffree").get() -object Androidx { - const val androidxActivity = "androidx.activity:activity-compose:1.3.1" - const val core = "androidx.core:core-ktx:1.6.0" - const val palette = "androidx.palette:palette-ktx:1.0.0" - const val coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.coroutinesVersion}" +val VersionCatalog.ktlintGradle get() = findDependency("ktlint-gradle").get() +val VersionCatalog.androidGradle get() = findDependency("androidx-gradle-plugin").get() +val VersionCatalog.mosaicGradle get() = findDependency("mosaic-gradle").get() +val VersionCatalog.kotlinComposeGradle get() = findDependency("kotlin-compose-gradle").get() +val VersionCatalog.kotlinGradle get() = findDependency("kotlin-kotlinGradlePlugin").get() +val VersionCatalog.i18n4kGradle get() = findDependency("i18n4k-gradle-plugin").get() +val VersionCatalog.sqlDelightGradle get() = findDependency("sqldelight-gradle-plugin").get() +val VersionCatalog.kotlinSerializationPlugin get() = findDependency("kotlin-serialization").get() - const val junit = "androidx.test.ext:junit:1.1.2" - const val expresso = "androidx.test.espresso:espresso-core:3.3.0" +val VersionCatalog.koinCore get() = findDependency("koin-core").get() +val VersionCatalog.kotlinCoroutines get() = findDependency("kotlin-coroutines").get() +val VersionCatalog.kotlinxSerialization get() = findDependency("kotlinx-serialization-json").get() +val VersionCatalog.ktorClientIOS get() = findDependency("ktor-client-ios").get() +val VersionCatalog.ktorClientAndroid get() = findDependency("ktor-client-android").get() +val VersionCatalog.ktorClientApache get() = findDependency("ktor-client-apache").get() +val VersionCatalog.ktorClientJS get() = findDependency("ktor-client-js").get() +val VersionCatalog.ktorClientCIO get() = findDependency("ktor-client-cio").get() +val VersionCatalog.slf4j get() = findDependency("slf4j-simple").get() - const val gradlePlugin = "com.android.tools.build:gradle:7.0.1" -} - -object KTLint { - const val gradlePlugin = "org.jlleitschuh.gradle:ktlint-gradle:${Versions.ktLint}" -} - -object JetBrains { - object Kotlin { - const val coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1-native-mt" - const val gradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlinVersion}" - const val serialization = "org.jetbrains.kotlin:kotlin-serialization:${Versions.kotlinVersion}" - const val testCommon = "org.jetbrains.kotlin:kotlin-test-common:${Versions.kotlinVersion}" - const val testJunit = "org.jetbrains.kotlin:kotlin-test-junit:${Versions.kotlinVersion}" - const val testAnnotationsCommon = - "org.jetbrains.kotlin:kotlin-test-annotations-common:${Versions.kotlinVersion}" - } - - object Compose { - // __LATEST_COMPOSE_RELEASE_VERSION__ - private const val VERSION = "1.0.0-alpha3" - const val gradlePlugin = "org.jetbrains.compose:compose-gradle-plugin:$VERSION" - } -} - -object Mosaic { - const val gradlePlugin = "com.jakewharton.mosaic:mosaic-gradle-plugin:${Versions.mosaic}" -} - -object Decompose { - private const val VERSION = "0.3.1" - const val decompose = "com.arkivanov.decompose:decompose:$VERSION" - const val decomposeIosX64 = "com.arkivanov.decompose:decompose-iosx64:$VERSION" - const val decomposeIosArm64 = "com.arkivanov.decompose:decompose-iosarm64:$VERSION" - const val extensionsCompose = "com.arkivanov.decompose:extensions-compose-jetbrains:$VERSION" -} - -object MVIKotlin { - private const val VERSION = "2.0.4" - const val rx = "com.arkivanov.mvikotlin:rx:$VERSION" - const val mvikotlin = "com.arkivanov.mvikotlin:mvikotlin:$VERSION" - const val mvikotlinMain = "com.arkivanov.mvikotlin:mvikotlin-main:$VERSION" - const val coroutines = "com.arkivanov.mvikotlin:mvikotlin-extensions-coroutines:$VERSION" - const val keepers = "com.arkivanov.mvikotlin:keepers:$VERSION" - const val mvikotlinMainIosX64 = "com.arkivanov.mvikotlin:mvikotlin-main-iosx64:$VERSION" - const val mvikotlinMainIosArm64 = "com.arkivanov.mvikotlin:mvikotlin-main-iosarm64:$VERSION" - const val mvikotlinLogging = "com.arkivanov.mvikotlin:mvikotlin-logging:$VERSION" - const val mvikotlinTimeTravel = "com.arkivanov.mvikotlin:mvikotlin-timetravel:$VERSION" - const val mvikotlinExtensionsReaktive = "com.arkivanov.mvikotlin:mvikotlin-extensions-reaktive:$VERSION" -} - -object Ktor { - val clientCore = "io.ktor:ktor-client-core:${Versions.ktor}" - val clientJson = "io.ktor:ktor-client-json:${Versions.ktor}" - val clientLogging = "io.ktor:ktor-client-logging:${Versions.ktor}" - val clientSerialization = "io.ktor:ktor-client-serialization:${Versions.ktor}" - - val auth = "io.ktor:ktor-client-auth:${Versions.ktor}" - val clientAndroid = "io.ktor:ktor-client-android:${Versions.ktor}" - val clientCurl = "io.ktor:ktor-client-curl:${Versions.ktor}" - val clientApache = "io.ktor:ktor-client-apache:${Versions.ktor}" - val slf4j = "org.slf4j:slf4j-simple:${Versions.slf4j}" - val clientIos = "io.ktor:ktor-client-ios:${Versions.ktor}" - val clientCio = "io.ktor:ktor-client-cio:${Versions.ktor}" - val clientJs = "io.ktor:ktor-client-js:${Versions.ktor}" -} - -object Internationalization { - const val dep = "de.comahe.i18n4k:i18n4k-core:${Versions.i18n4k}" - const val gradlePlugin = "de.comahe.i18n4k:i18n4k-gradle-plugin:${Versions.i18n4k}" -} - -object Extras { - const val youtubeDownloader = "io.github.shabinder:youtube-api-dl:1.3" - const val fuzzyWuzzy = "io.github.shabinder:fuzzywuzzy:1.1" - const val mp3agic = "com.mpatric:mp3agic:0.9.0" - const val jaudioTagger = "com.github.Shabinder:JAudioTagger-Android:1.0" - const val kermit = "co.touchlab:kermit:${Versions.kermit}" - - object Android { - // Self Hosted Analytics & Crashlytics (FOSS) - val countly = "ly.count.android:sdk:20.11.8" - val appUpdator = "com.github.amitbd1508:AppUpdater:4.1.0" - } - - object Desktop { - val countly = "ly.count.sdk:java:20.11.0" - } -} - -object Serialization { - val json = "org.jetbrains.kotlinx:kotlinx-serialization-json:${Versions.kotlinxSerialization}" -} - -object SqlDelight { - val runtime = "com.squareup.sqldelight:runtime:${Versions.sqlDelight}" - val coroutineExtensions = "com.squareup.sqldelight:coroutines-extensions:${Versions.sqlDelight}" - - const val gradlePlugin = "com.squareup.sqldelight:gradle-plugin:${Versions.sqlDelight}" - const val androidDriver = "com.squareup.sqldelight:android-driver:${Versions.sqlDelight}" - const val sqliteDriver = "com.squareup.sqldelight:sqlite-driver:${Versions.sqlDelight}" - const val nativeDriver = "com.squareup.sqldelight:native-driver:${Versions.sqlDelight}" - val nativeDriverMacos = "com.squareup.sqldelight:native-driver-macosx64:${Versions.sqlDelight}" - val jdbcDriver = "org.xerial:sqlite-jdbc:${Versions.sqliteJdbcDriver}" -} - -fun DependencyHandler.`implementation`( - dependencyNotation: String, - dependencyConfiguration: ExternalModuleDependency.() -> Unit -): ExternalModuleDependency = addDependencyTo( - this, "implementation", dependencyNotation -) { dependencyConfiguration() } +val VersionCatalog.sqlDelightJDBC get() = findDependency("sqlite-jdbc-driver").get() +val VersionCatalog.sqlDelightNative get() = findDependency("sqldelight-native-driver").get() +val VersionCatalog.sqlDelightAndroid get() = findDependency("sqldelight-android-driver").get() +val VersionCatalog.sqlDelightDriver get() = findDependency("sqldelight-driver").get() diff --git a/buildSrc/deps.versions.toml b/buildSrc/deps.versions.toml new file mode 100644 index 00000000..ff4d0278 --- /dev/null +++ b/buildSrc/deps.versions.toml @@ -0,0 +1,135 @@ +[versions] +kotlin = "1.5.31" +androidCoroutines = "1.5.1" +ktLint = "10.1.0" +mosaic = "0.1.0" +koin = "3.1.2" +kermit = "0.1.9" +mokoParcelize = "0.7.1" +ktor = "1.6.3" +kotlinxSerialization = "1.2.2" +sqlDelight = "1.5.1" +sqliteJdbcDriver = "3.34.0" +slf4j = "1.7.31" +i18n4k = "0.1.3" +essenty = "0.1.3" +multiplatformSettings = "0.7.7" +decompose = "0.3.1" +mviKotlin = "2.0.4" +accompanist = "0.18.0" +statelyVersion = "1.1.10" +statelyIsoVersion = "1.2.0-nmm" +androidxLifecycle = "2.4.0-alpha03" + + +[libraries] +kotlin-kotlinGradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } +kotlin-serialization = { group = "org.jetbrains.kotlin", name = "kotlin-serialization", version.ref = "kotlin" } +kotlin-kotlinTestCommon = { group = "org.jetbrains.kotlin", name = "kotlin-test-common", version.ref = "kotlin" } +kotlin-kotlinTestJs = { group = "org.jetbrains.kotlin", name = "kotlin-test-js", version.ref = "kotlin" } +kotlin-kotlinTestJunit = { group = "org.jetbrains.kotlin", name = "kotlin-test-junit", version.ref = "kotlin" } +kotlin-kotlinTestAnnotationsCommon = { group = "org.jetbrains.kotlin", name = "kotlin-test-annotations-common", version.ref = "kotlin" } +kotlin-coroutines = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version = "1.5.2-native-mt" } +kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerialization" } +kotlinx-atomicfu = { group = "org.jetbrains.kotlinx", name = "atomicfu", version = "0.16.3" } +kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version = "0.2.1" } + +kotlin-compose-gradle = { group = "org.jetbrains.compose", name = "compose-gradle-plugin", version = "1.0.0-alpha4-build366" } +mosaic-gradle = { group = "com.jakewharton.mosaic", name = "mosaic-gradle-plugin", version.ref = "mosaic" } + +essenty-lifecycle = { group = "com.arkivanov.essenty", name = "lifecycle", version.ref = "essenty" } +essenty-instanceKeeper = { group = "com.arkivanov.essenty", name = "instance-keeper", version.ref = "essenty" } + +decompose-dep = { group = "com.arkivanov.decompose", name = "decompose", version.ref = "decompose" } +decompose-extensions-compose = { group = "com.arkivanov.decompose", name = "extensions-compose-jetbrains", version.ref = "decompose" } + +mviKotlin-dep = { group = "com.arkivanov.mvikotlin", name = "mvikotlin", version.ref = "mviKotlin" } +mviKotlin-rx = { group = "com.arkivanov.mvikotlin", name = "rx", version.ref = "mviKotlin" } +mviKotlin-main = { group = "com.arkivanov.mvikotlin", name = "mvikotlin-main", version.ref = "mviKotlin" } +mviKotlin-coroutines = { group = "com.arkivanov.mvikotlin", name = "mvikotlin-extensions-coroutines", version.ref = "mviKotlin" } +mviKotlin-keepers = { group = "com.arkivanov.mvikotlin", name = "keepers", version.ref = "mviKotlin" } +mviKotlin-logging = { group = "com.arkivanov.mvikotlin", name = "mvikotlin-logging", version.ref = "mviKotlin" } +mviKotlin-timetravel = { group = "com.arkivanov.mvikotlin", name = "mvikotlin-timetravel", version.ref = "mviKotlin" } +mviKotlin-extensions-reaktive = { group = "com.arkivanov.mvikotlin", name = "mvikotlin-extensions-reaktive", version.ref = "mviKotlin" } + +ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor" } +ktor-client-json = { group = "io.ktor", name = "ktor-client-json", version.ref = "ktor" } +ktor-client-logging = { group = "io.ktor", name = "ktor-client-logging", version.ref = "ktor" } +ktor-client-serialization = { group = "io.ktor", name = "ktor-client-serialization", version.ref = "ktor" } +ktor-client-auth = { group = "io.ktor", name = "ktor-client-auth", version.ref = "ktor" } +ktor-client-android = { group = "io.ktor", name = "ktor-client-android", version.ref = "ktor" } +ktor-client-curl = { group = "io.ktor", name = "ktor-client-curl", version.ref = "ktor" } +ktor-client-apache = { group = "io.ktor", name = "ktor-client-apache", version.ref = "ktor" } +ktor-client-ios = { group = "io.ktor", name = "ktor-client-ios", version.ref = "ktor" } +ktor-client-cio = { group = "io.ktor", name = "ktor-client-cio", version.ref = "ktor" } +ktor-client-js = { group = "io.ktor", name = "ktor-client-js", version.ref = "ktor" } +slf4j-simple = { group = "org.slf4j", name = "slf4j-simple", version.ref = "slf4j" } + +i18n4k-core = { group = "de.comahe.i18n4k", name = "i18n4k-core", version.ref = "i18n4k" } +i18n4k-gradle-plugin = { group = "de.comahe.i18n4k", name = "i18n4k-gradle-plugin", version.ref = "i18n4k" } + +youtube-downloader = { group = "io.github.shabinder", name = "youtube-api-dl", version = "1.3" } +fuzzy-wuzzy = { group = "io.github.shabinder", name = "fuzzywuzzy", version = "1.1" } +mp3agic = { group = "com.mpatric", name = "mp3agic", version = "0.9.0" } +kermit = { group = "co.touchlab", name = "kermit", version.ref = "kermit" } +storage-chooser = { group = "com.github.shabinder", name = "storage-chooser", version = "2.0.4.45" } +accompanist-inset = { group = "com.google.accompanist", name = "accompanist-insets", version.ref = "accompanist" } +android-app-notifier = { group = "com.github.amitbd1508", name = "AppUpdater", version = "4.1.0" } +moko-parcelize = { group = "dev.icerock.moko", name = "parcelize", version.ref = "mokoParcelize" } +jaffree = { group = "com.github.kokorin.jaffree", name = "jaffree", version = "2021.08.16" } +multiplatform-settings = { group = "com.russhwolf", name = "multiplatform-settings-no-arg", version.ref = "multiplatformSettings" } + +countly-android = { group = "ly.count.android", name = "sdk", version = "20.11.8" } +countly-desktop = { group = "ly.count.sdk", name = "java", version = "20.11.0" } + +stately-common = { group = "co.touchlab", name = "stately-common", version.ref = "statelyVersion" } +stately-concurrency = { group = "co.touchlab", name = "stately-concurrency", version.ref = "statelyVersion" } +stately-isolate = { group = "co.touchlab", name = "stately-isolate", version.ref = "statelyIsoVersion" } +stately-iso-collections = { group = "co.touchlab", name = "stately-iso-collections", version.ref = "statelyIsoVersion" } + +sqldelight-runtime = { group = "com.squareup.sqldelight", name = "runtime", version.ref = "sqlDelight" } +sqldelight-coroutines-extension = { group = "com.squareup.sqldelight", name = "coroutines-extensions", version.ref = "sqlDelight" } +sqldelight-gradle-plugin = { group = "com.squareup.sqldelight", name = "gradle-plugin", version.ref = "sqlDelight" } +sqldelight-driver = { group = "com.squareup.sqldelight", name = "sqlite-driver", version.ref = "sqlDelight" } +sqldelight-android-driver = { group = "com.squareup.sqldelight", name = "android-driver", version.ref = "sqlDelight" } +sqldelight-native-driver = { group = "com.squareup.sqldelight", name = "native-driver", version.ref = "sqlDelight" } +sqlite-jdbc-driver = { group = "org.xerial", name = "sqlite-jdbc", version.ref = "sqliteJdbcDriver" } + +koin-core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin" } +koin-test = { group = "io.insert-koin", name = "koin-test", version.ref = "koin" } +koin-android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" } +koin-androidx-compose = { group = "io.insert-koin", name = "koin-androidx-compose", version.ref = "koin" } + +kotlin-js-wrappers-react = { group = "org.jetbrains.kotlin-wrappers", name = "kotlin-react", version = "17.0.2-pre.251-kotlin-1.5.31" } +kotlin-js-wrappers-reactDom = { group = "org.jetbrains.kotlin-wrappers", name = "kotlin-react-dom", version = "17.0.2-pre.251-kotlin-1.5.31" } +kotlin-js-wrappers-styled = { group = "org.jetbrains.kotlin-wrappers", name = "kotlin-styled", version = "5.3.1-pre.250-kotlin-1.5.31" } +kotlin-js-wrappers-ext = { group = "org.jetbrains.kotlin-wrappers", name = "kotlin-extensions", version = "1.0.1-pre.251-kotlin-1.5.31" } + +androidx-activity = { group = "androidx.activity", name = "activity-compose", version = "1.3.1" } +androidx-core = { group = "androidx.core", name = "core-ktx", version = "1.6.0" } +androidx-palette = { group = "androidx.palette", name = "palette-ktx", version = "1.0.0" } +androidx-coroutines = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "androidCoroutines" } +androidx-junit = { group = "androidx.test.ext", name = "junit", version = "1.1.2" } +androidx-expresso = { group = "androidx.test.espresso", name = "espresso-core", version = "3.3.0" } +androidx-gradle-plugin = { group = "com.android.tools.build", name = "gradle", version = "4.2.2" } +androidx-lifecycle-service = { group = "androidx.lifecycle", name = "lifecycle-service", version.ref = "androidxLifecycle" } +androidx-lifecycle-common = { group = "androidx.lifecycle", name = "lifecycle-common-java8", version.ref = "androidxLifecycle" } +androidx-lifecycle-runtime = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "androidxLifecycle" } +androidx-desugar = { group = "com.android.tools", name = "desugar_jdk_libs", version = "1.1.5" } +leak-canary = { group = "com.squareup.leakcanary", name = "leakcanary-android", version = "2.7" } +junit = { group = "junit", name = "junit", version = "4.13.2" } + +ktlint-gradle = { group = "org.jlleitschuh.gradle", name = "ktlint-gradle", version.ref = "ktLint" } + +[bundles] +ktor = ["ktor-client-core","ktor-client-json","ktor-client-auth","ktor-client-logging","ktor-client-serialization"] +stately = ["stately-common","stately-concurrency","stately-isolate","stately-iso-collections"] +androidx-lifecycle = ["androidx-lifecycle-service","androidx-lifecycle-common","androidx-lifecycle-runtime"] +androidx-common = ["androidx-activity","androidx-core"] +kotlin-test = ["kotlin-kotlinTestCommon","kotlin-kotlinTestAnnotationsCommon"] +sqldelight = ["sqldelight-runtime","sqldelight-coroutines-extension","sqldelight-driver"] +mviKotlin = ["mviKotlin-dep","mviKotlin-main","mviKotlin-coroutines","mviKotlin-logging","mviKotlin-timetravel"] +kotlinCommon = ["kotlin-coroutines", "kotlin-serialization", "kotlinx-serialization-json", "kotlinx-atomicfu"] +essenty = ["essenty-lifecycle","essenty-instanceKeeper"] +koin-android = ["koin-androidx-compose","koin-android"] +kotlin-js-wrappers = ["kotlin-js-wrappers-react","kotlin-js-wrappers-reactDom","kotlin-js-wrappers-styled","kotlin-js-wrappers-ext"] \ No newline at end of file diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts new file mode 100644 index 00000000..72f011b1 --- /dev/null +++ b/buildSrc/settings.gradle.kts @@ -0,0 +1,12 @@ + +enableFeaturePreview("VERSION_CATALOGS") +dependencyResolutionManagement { + @Suppress("UnstableApiUsage") + versionCatalogs { + create("deps") { + from(files("deps.versions.toml")) + } + } +} + +rootProject.name = "spotiflyer-build" diff --git a/buildSrc/src/main/kotlin/compiler-args.gradle.kts b/buildSrc/src/main/kotlin/compiler-args.gradle.kts index 39907c63..34c5b8f5 100644 --- a/buildSrc/src/main/kotlin/compiler-args.gradle.kts +++ b/buildSrc/src/main/kotlin/compiler-args.gradle.kts @@ -6,10 +6,10 @@ kotlin { sourceSets { all { languageSettings.apply { - useExperimentalAnnotation("kotlin.RequiresOptIn") - useExperimentalAnnotation("kotlin.Experimental") - useExperimentalAnnotation("kotlin.time.ExperimentalTime") - useExperimentalAnnotation("kotlinx.serialization.ExperimentalSerializationApi") + optIn("kotlin.RequiresOptIn") + optIn("kotlin.Experimental") + optIn("kotlin.time.ExperimentalTime") + optIn("kotlinx.serialization.ExperimentalSerializationApi") } } } diff --git a/buildSrc/src/main/kotlin/multiplatform-compose-setup.gradle.kts b/buildSrc/src/main/kotlin/multiplatform-compose-setup.gradle.kts index 8b324515..34dea94a 100644 --- a/buildSrc/src/main/kotlin/multiplatform-compose-setup.gradle.kts +++ b/buildSrc/src/main/kotlin/multiplatform-compose-setup.gradle.kts @@ -29,36 +29,23 @@ kotlin { sourceSets { all { languageSettings.apply { - useExperimentalAnnotation("androidx.compose.animation") + optIn("androidx.compose.animation") } } named("commonMain") { dependencies { - // Decompose - implementation(Decompose.decompose) - - // MVI - implementation(MVIKotlin.coroutines) - implementation(MVIKotlin.mvikotlin) - implementation(compose.ui) implementation(compose.runtime) implementation(compose.foundation) implementation(compose.material) implementation(compose.animation) - - implementation(Extras.kermit) - implementation("dev.icerock.moko:parcelize:${Versions.mokoParcelize}") - implementation(JetBrains.Kotlin.coroutines) { - @Suppress("DEPRECATION") - isForce = true - } + implementation(Deps.kotlinCoroutines) + implementation(Deps.decompose) } } named("androidMain") { dependencies { - implementation(Androidx.androidxActivity) - implementation(Androidx.core) + implementation(Deps.androidXCommonBundle) } } named("desktopMain") { diff --git a/buildSrc/src/main/kotlin/multiplatform-setup-test.gradle.kts b/buildSrc/src/main/kotlin/multiplatform-setup-test.gradle.kts index c4a4889f..8f2e8408 100644 --- a/buildSrc/src/main/kotlin/multiplatform-setup-test.gradle.kts +++ b/buildSrc/src/main/kotlin/multiplatform-setup-test.gradle.kts @@ -42,23 +42,24 @@ kotlin { sourceSets { named("commonTest") { dependencies { - implementation(JetBrains.Kotlin.testCommon) - implementation(JetBrains.Kotlin.testAnnotationsCommon) + implementation(Deps.kotlinTestBundle) } } named("androidTest") { dependencies { - implementation(JetBrains.Kotlin.testJunit) + implementation(Deps.kotlinJunitTest) } } named("desktopTest") { dependencies { - implementation(JetBrains.Kotlin.testJunit) + implementation(Deps.kotlinJunitTest) } } named("jsTest") { - dependencies {} + dependencies { + implementation(Deps.kotlinJSTest) + } } } } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts b/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts index 43462d25..54b92e72 100644 --- a/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts +++ b/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts @@ -25,7 +25,7 @@ plugins { kotlin { /*IOS Target Can be only built on Mac*/ - if(HostOS.isMac){ + if (HostOS.isMac) { val sdkName: String? = System.getenv("SDK_NAME") val isiOSDevice = sdkName.orEmpty().startsWith("iphoneos") if (isiOSDevice) { @@ -50,45 +50,25 @@ kotlin { sourceSets { named("commonMain") { dependencies { - // Decompose - implementation(Decompose.decompose) - - // MVI - implementation(MVIKotlin.coroutines) - implementation(MVIKotlin.mvikotlin) - - // Koin - implementation(Koin.core) - - implementation(Ktor.auth) - implementation(Ktor.clientJson) - implementation(Ktor.clientCore) - implementation(Ktor.clientLogging) - implementation(Ktor.clientSerialization) - - // Extras - implementation(Extras.kermit) - implementation(Serialization.json) - implementation("co.touchlab:stately-common:1.1.7") - implementation("dev.icerock.moko:parcelize:${Versions.mokoParcelize}") - implementation(JetBrains.Kotlin.coroutines) { - @Suppress("DEPRECATION") - isForce = true - } + implementation(Deps.ktorBundle) + implementation(Deps.kotlinxSerialization) + implementation(Deps.kotlinCoroutines) + implementation(Deps.mviKotlinBundle) + implementation(Deps.decompose) + implementation(Deps.koinCore) } } named("androidMain") { dependencies { - implementation(Androidx.androidxActivity) - implementation(Androidx.core) implementation(compose.runtime) implementation(compose.material) implementation(compose.foundation) implementation(compose.materialIconsExtended) - implementation(Decompose.extensionsCompose) - implementation(Ktor.clientAndroid) - implementation(Koin.android) + implementation(Deps.androidXCommonBundle) + implementation(Deps.decomposeComposeExt) + implementation(Deps.ktorClientAndroid) + implementation(Deps.koinAndroidBundle) } } @@ -99,27 +79,20 @@ kotlin { implementation(compose.material) implementation(compose.desktop.common) implementation(compose.materialIconsExtended) - implementation(Decompose.extensionsCompose) - implementation(Ktor.clientApache) - implementation(Ktor.slf4j) + implementation(Deps.decomposeComposeExt) + implementation(Deps.ktorClientApache) + implementation(Deps.slf4j) } } named("jsMain") { dependencies { - implementation(Ktor.clientJs) - - /*with(KotlinJSWrappers) { - implementation(enforcedPlatform(bom)) - implementation(kotlinReact) - implementation(kotlinReactDom) - implementation(kotlinStyled) - }*/ + implementation(Deps.ktorClientJS) } } - if(HostOS.isMac){ - named("iosMain"){ + if (HostOS.isMac) { + named("iosMain") { dependencies { - implementation(Ktor.clientIos) + implementation(Deps.ktorClientIOS) } } } diff --git a/common/compose/build.gradle.kts b/common/compose/build.gradle.kts index c47e194a..ed4df484 100644 --- a/common/compose/build.gradle.kts +++ b/common/compose/build.gradle.kts @@ -40,7 +40,7 @@ kotlin { implementation(project(":common:database")) implementation(project(":common:data-models")) implementation(project(":common:dependency-injection")) - implementation(Decompose.extensionsCompose) + implementation(deps.decompose.extensions.compose) } } } diff --git a/common/compose/src/desktopMain/kotlin/com/shabinder/common/uikit/DesktopImages.kt b/common/compose/src/desktopMain/kotlin/com/shabinder/common/uikit/DesktopImages.kt index 2c4c1a91..859ce01b 100644 --- a/common/compose/src/desktopMain/kotlin/com/shabinder/common/uikit/DesktopImages.kt +++ b/common/compose/src/desktopMain/kotlin/com/shabinder/common/uikit/DesktopImages.kt @@ -21,15 +21,19 @@ package com.shabinder.common.uikit import androidx.compose.foundation.Image 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.graphics.vector.rememberVectorPainter +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.loadXmlImageVector -import androidx.compose.ui.res.vectorXmlResource +import androidx.compose.ui.res.useResource +import org.xml.sax.InputSource @Composable -internal actual fun imageVectorResource(id: T): ImageVector = - vectorXmlResource(id as String) +internal actual fun imageVectorResource(id: T): ImageVector { + val density = LocalDensity.current + return useResource(id as String) { + loadXmlImageVector(InputSource(it), density) + } +} @Composable actual fun DownloadImageTick() { diff --git a/common/compose/src/desktopMain/kotlin/com/shabinder/common/uikit/DesktopScrollBar.kt b/common/compose/src/desktopMain/kotlin/com/shabinder/common/uikit/DesktopScrollBar.kt index 9088ac4b..aad2af95 100644 --- a/common/compose/src/desktopMain/kotlin/com/shabinder/common/uikit/DesktopScrollBar.kt +++ b/common/compose/src/desktopMain/kotlin/com/shabinder/common/uikit/DesktopScrollBar.kt @@ -12,7 +12,7 @@ import androidx.compose.ui.unit.dp actual val MARGIN_SCROLLBAR: Dp = 8.dp -actual typealias ScrollbarAdapter = androidx.compose.foundation.ScrollbarAdapter +actual typealias ScrollbarAdapter = ScrollbarAdapter @OptIn(ExperimentalFoundationApi::class) @Composable @@ -23,8 +23,6 @@ actual fun rememberScrollbarAdapter( ): ScrollbarAdapter = androidx.compose.foundation.rememberScrollbarAdapter( scrollState = scrollState, - itemCount = itemCount, - averageItemSize = averageItemSize ) @Composable diff --git a/common/core-components/build.gradle.kts b/common/core-components/build.gradle.kts index 9a618a93..92592eda 100644 --- a/common/core-components/build.gradle.kts +++ b/common/core-components/build.gradle.kts @@ -10,29 +10,37 @@ kotlin { dependencies { implementation(project(":common:data-models")) implementation(project(":common:database")) - api("org.jetbrains.kotlinx:atomicfu:0.16.2") - api(MultiPlatformSettings.dep) - implementation(MVIKotlin.rx) + with(deps) { + api(multiplatform.settings) + api(kotlinx.atomicfu) + implementation(mviKotlin.rx) + implementation(decompose.dep) + } } } androidMain { dependencies { - implementation(Extras.mp3agic) - implementation(Extras.Android.countly) + with(deps) { + implementation(mp3agic) + implementation(countly.android) + } implementation(project(":ffmpeg:android-ffmpeg")) } } desktopMain { dependencies { - implementation(Extras.mp3agic) - implementation(Extras.Desktop.countly) - implementation("com.github.kokorin.jaffree:jaffree:2021.08.16") + with(deps) { + implementation(mp3agic) + implementation(countly.desktop) + implementation(jaffree) + } } } jsMain { dependencies { implementation(npm("browser-id3-writer", "4.4.0")) implementation(npm("file-saver", "2.0.4")) + implementation(deps.kotlin.js.wrappers.ext) } } } diff --git a/common/core-components/src/desktopMain/kotlin/com.shabinder.common.core_components/file_manager/DesktopFileManager.kt b/common/core-components/src/desktopMain/kotlin/com.shabinder.common.core_components/file_manager/DesktopFileManager.kt index 0f7b11a9..56efceb7 100644 --- a/common/core-components/src/desktopMain/kotlin/com.shabinder.common.core_components/file_manager/DesktopFileManager.kt +++ b/common/core-components/src/desktopMain/kotlin/com.shabinder.common.core_components/file_manager/DesktopFileManager.kt @@ -30,17 +30,20 @@ import com.shabinder.common.core_components.removeAllTags import com.shabinder.common.core_components.setId3v1Tags import com.shabinder.common.core_components.setId3v2TagsAndSaveFile import com.shabinder.common.database.SpotiFlyerDatabase +import com.shabinder.common.models.Actions import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.dispatcherIO import com.shabinder.common.models.event.coroutines.SuspendableEvent -import com.shabinder.common.models.event.coroutines.failure import com.shabinder.common.models.event.coroutines.map -import com.shabinder.common.models.Actions import com.shabinder.database.Database -import kotlinx.coroutines.* +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.flow.MutableSharedFlow -import org.jetbrains.skija.Image +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.jetbrains.skia.Image import org.koin.dsl.bind import org.koin.dsl.module import java.awt.image.BufferedImage @@ -165,7 +168,7 @@ class DesktopFileManager( } SuspendableEvent.success(trackDetails.outputFilePath) } catch (e: Throwable) { - if(e is JaffreeException) Actions.instance.showPopUpMessage("No FFmpeg found at path.") + if (e is JaffreeException) Actions.instance.showPopUpMessage("No FFmpeg found at path.") if (songFile.exists()) songFile.delete() logger.e { "${songFile.absolutePath} could not be created" } SuspendableEvent.error(e) diff --git a/common/data-models/build.gradle.kts b/common/data-models/build.gradle.kts index d5f215cb..0db019de 100644 --- a/common/data-models/build.gradle.kts +++ b/common/data-models/build.gradle.kts @@ -25,9 +25,6 @@ plugins { id("de.comahe.i18n4k") } -val statelyVersion = "1.1.7" -val statelyIsoVersion = "1.1.7-a1" - i18n4k { inputDirectory = "../../translations" packageName = "com.shabinder.common.translations" @@ -50,11 +47,13 @@ kotlin { } commonMain { dependencies { - api("co.touchlab:stately-concurrency:$statelyVersion") - api("co.touchlab:stately-isolate:$statelyIsoVersion") - api("co.touchlab:stately-iso-collections:$statelyIsoVersion") - implementation(Extras.youtubeDownloader) - api(Internationalization.dep) + with(deps) { + api(bundles.stately) + api(i18n4k.core) + api(kermit) + api(moko.parcelize) + implementation(youtube.downloader) + } } } } diff --git a/common/database/build.gradle.kts b/common/database/build.gradle.kts index 45fc19bb..c4d095d1 100644 --- a/common/database/build.gradle.kts +++ b/common/database/build.gradle.kts @@ -34,31 +34,32 @@ kotlin { implementation(project(":common:data-models")) // SQL Delight - implementation(SqlDelight.runtime) - implementation(SqlDelight.coroutineExtensions) - - // koin - implementation(Koin.test) + with(deps.sqldelight) { + implementation(runtime) + api(coroutines.extension) + } } } androidMain { dependencies { - implementation(SqlDelight.androidDriver) + implementation(deps.sqldelight.android.driver) } } desktopMain { dependencies { - implementation(SqlDelight.sqliteDriver) - implementation(SqlDelight.jdbcDriver) + with(deps) { + implementation(sqldelight.driver) + implementation(sqlite.jdbc.driver) + } } } if (HostOS.isMac) { val iosMain by getting { dependencies { - implementation(SqlDelight.nativeDriver) + implementation(deps.sqldelight.native.driver) } } } diff --git a/common/dependency-injection/build.gradle.kts b/common/dependency-injection/build.gradle.kts index 3ae71372..0a7234a2 100644 --- a/common/dependency-injection/build.gradle.kts +++ b/common/dependency-injection/build.gradle.kts @@ -14,8 +14,6 @@ * * along with this program. If not, see . */ -import org.jetbrains.compose.compose - plugins { id("android-setup") id("multiplatform-setup") diff --git a/common/list/build.gradle.kts b/common/list/build.gradle.kts index 0e9910be..60894115 100644 --- a/common/list/build.gradle.kts +++ b/common/list/build.gradle.kts @@ -30,7 +30,6 @@ kotlin { implementation(project(":common:database")) implementation(project(":common:providers")) implementation(project(":common:core-components")) - implementation(SqlDelight.coroutineExtensions) } } } diff --git a/common/main/build.gradle.kts b/common/main/build.gradle.kts index 0e9910be..60894115 100644 --- a/common/main/build.gradle.kts +++ b/common/main/build.gradle.kts @@ -30,7 +30,6 @@ kotlin { implementation(project(":common:database")) implementation(project(":common:providers")) implementation(project(":common:core-components")) - implementation(SqlDelight.coroutineExtensions) } } } diff --git a/common/preference/build.gradle.kts b/common/preference/build.gradle.kts index c9bec637..67bbc40b 100644 --- a/common/preference/build.gradle.kts +++ b/common/preference/build.gradle.kts @@ -30,7 +30,6 @@ kotlin { implementation(project(":common:database")) implementation(project(":common:core-components")) implementation(project(":common:providers")) - implementation(SqlDelight.coroutineExtensions) } } } diff --git a/common/providers/build.gradle.kts b/common/providers/build.gradle.kts index b4309fba..79e289f8 100644 --- a/common/providers/build.gradle.kts +++ b/common/providers/build.gradle.kts @@ -12,23 +12,25 @@ kotlin { sourceSets { commonMain { dependencies { - implementation(project(":common:data-models")) - implementation(project(":common:database")) - implementation(project(":common:core-components")) - implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.2.1") - implementation(Extras.youtubeDownloader) - implementation(Extras.fuzzyWuzzy) + with(deps) { + implementation(project(":common:data-models")) + implementation(project(":common:database")) + implementation(project(":common:core-components")) + implementation(youtube.downloader) + implementation(fuzzy.wuzzy) + implementation(kotlinx.datetime) + } } } androidMain { dependencies { - implementation(Extras.mp3agic) + implementation(deps.mp3agic) } } desktopMain { dependencies { - implementation(Extras.mp3agic) - implementation("com.github.kokorin.jaffree:jaffree:2021.08.16") + implementation(deps.mp3agic) + implementation(deps.jaffree) } } jsMain { diff --git a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/sound_cloud/requests/SoundCloudRequests.kt b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/sound_cloud/requests/SoundCloudRequests.kt index 238c782d..91c050ff 100644 --- a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/sound_cloud/requests/SoundCloudRequests.kt +++ b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/sound_cloud/requests/SoundCloudRequests.kt @@ -32,7 +32,7 @@ interface SoundCloudRequests { } @Suppress("NAME_SHADOWING") - suspend fun getTrack(track: JsonObject): TrackDetails { + suspend fun getTrack(track: JsonObject): TrackDetails? { val track = getTrackInfo(track) val title = track.getString("title") @@ -42,7 +42,7 @@ interface SoundCloudRequests { if (track.getBoolean("streamable") == false) throw SpotiFlyerException.LinkInvalid("\nSound Cloud Reports that $title is not streamable !\n") - + return null } diff --git a/common/root/build.gradle.kts b/common/root/build.gradle.kts index 8687f531..1bbe64e2 100644 --- a/common/root/build.gradle.kts +++ b/common/root/build.gradle.kts @@ -33,9 +33,10 @@ fun org.jetbrains.kotlin.gradle.dsl.KotlinNativeBinaryContainer.generateFramewor export(project(":common:providers")) export(project(":common:list")) export(project(":common:preference")) - export(Decompose.decompose) - export(MVIKotlin.mvikotlinMain) - export(MVIKotlin.mvikotlinLogging) + with(deps) { + export(decompose.dep) + export(bundles.mviKotlin) + } } } @@ -71,7 +72,6 @@ kotlin { implementation(project(":common:providers")) implementation(project(":common:core-components")) implementation(project(":common:preference")) - implementation(SqlDelight.coroutineExtensions) } } } @@ -86,9 +86,10 @@ kotlin { api(project(":common:list")) api(project(":common:main")) api(project(":common:preference")) - api(Decompose.decompose) - api(MVIKotlin.mvikotlinMain) - api(MVIKotlin.mvikotlinLogging) + with(deps) { + api(decompose.dep) + api(bundles.mviKotlin) + } } } } @@ -100,8 +101,11 @@ val packForXcode by tasks.creating(Sync::class) { group = "build" val mode = System.getenv("CONFIGURATION") ?: "DEBUG" val targetName = "ios" - val framework = kotlin.targets.getByName(targetName) - .binaries.getFramework(mode) + val framework = + kotlin.targets.getByName( + targetName + ) + .binaries.getFramework(mode) inputs.property("mode", mode) dependsOn(framework.linkTask) val targetDir = File(buildDir, "xcode-frameworks") diff --git a/console-app/build.gradle.kts b/console-app/build.gradle.kts index c3da4280..da6958db 100644 --- a/console-app/build.gradle.kts +++ b/console-app/build.gradle.kts @@ -19,38 +19,39 @@ application { } dependencies { - implementation(Koin.core) - implementation(project(":common:database")) - implementation(project(":common:data-models")) - implementation(project(":common:dependency-injection")) - implementation(project(":common:root")) - implementation(project(":common:main")) - implementation(project(":common:list")) - implementation(project(":common:list")) + with(deps) { + implementation(Koin.core) + implementation(project(":common:database")) + implementation(project(":common:data-models")) + implementation(project(":common:dependency-injection")) + implementation(project(":common:root")) + implementation(project(":common:main")) + implementation(project(":common:list")) + implementation(project(":common:list")) - // Decompose - implementation(Decompose.decompose) - implementation(Decompose.extensionsCompose) + // Decompose + implementation(Decompose.decompose) + implementation(Decompose.extensionsCompose) - // MVI - implementation(MVIKotlin.mvikotlin) - implementation(MVIKotlin.mvikotlinMain) + // MVI + implementation(MVIKotlin.mvikotlin) + implementation(MVIKotlin.mvikotlinMain) - // Koin - implementation(Koin.core) + // Koin + implementation(Koin.core) - // Matomo - implementation("org.piwik.java.tracking:matomo-java-tracker:1.6") + // Matomo - implementation(Ktor.slf4j) - implementation(Ktor.clientCore) - implementation(Ktor.clientJson) - implementation(Ktor.clientApache) - implementation(Ktor.clientLogging) - implementation(Ktor.clientSerialization) - implementation(Serialization.json) - // testDeps - testImplementation("org.jetbrains.kotlin:kotlin-test-junit:1.5.21") + implementation(Ktor.slf4j) + implementation(Ktor.clientCore) + implementation(Ktor.clientJson) + implementation(Ktor.clientApache) + implementation(Ktor.clientLogging) + implementation(Ktor.clientSerialization) + implementation(Serialization.json) + // testDeps + testImplementation("org.jetbrains.kotlin:kotlin-test-junit:1.5.21") + } } tasks.withType().configureEach { kotlinOptions { diff --git a/desktop/build.gradle.kts b/desktop/build.gradle.kts index 0ccbe2dc..87db9a8a 100644 --- a/desktop/build.gradle.kts +++ b/desktop/build.gradle.kts @@ -44,19 +44,21 @@ kotlin { implementation(project(":common:compose")) implementation(project(":common:providers")) implementation(project(":common:root")) - implementation("com.github.kokorin.jaffree:jaffree:2021.08.16") - // Decompose - implementation(Decompose.decompose) - implementation(Decompose.extensionsCompose) + with(deps) { + implementation(jaffree) - // MVI - implementation(MVIKotlin.mvikotlin) - implementation(MVIKotlin.mvikotlinMain) - - // Koin - implementation(Koin.core) + with(decompose) { + implementation(dep) + implementation(extensions.compose) + } + with(mviKotlin) { + implementation(dep) + implementation(main) + } + implementation(koin.core) + } } } val jvmTest by getting diff --git a/ffmpeg/android-ffmpeg/build.gradle.kts b/ffmpeg/android-ffmpeg/build.gradle.kts index 24a62ad6..be58fa56 100644 --- a/ffmpeg/android-ffmpeg/build.gradle.kts +++ b/ffmpeg/android-ffmpeg/build.gradle.kts @@ -13,8 +13,6 @@ android { minSdk = Versions.minSdkVersion targetSdk = Versions.targetSdkVersion -// versionCode = Versions.versionCode -// versionName = Versions.versionName /*ndk { abiFilters.addAll(setOf("x86", "x86_64", "armeabi-v7a", "arm64-v8a")) diff --git a/ffmpeg/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/CpuArchHelper.java b/ffmpeg/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/CpuArchHelper.java index a363885e..19e681cc 100644 --- a/ffmpeg/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/CpuArchHelper.java +++ b/ffmpeg/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/CpuArchHelper.java @@ -2,6 +2,7 @@ package nl.bravobit.ffmpeg; import android.os.Build; +@SuppressWarnings("deprecation") public class CpuArchHelper { public static final String X86_CPU = "x86"; public static final String X86_64_CPU = "x86_64"; diff --git a/ffmpeg/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFcommandExecuteAsyncTask.java b/ffmpeg/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFcommandExecuteAsyncTask.java index 7ec21b44..83f93c79 100644 --- a/ffmpeg/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFcommandExecuteAsyncTask.java +++ b/ffmpeg/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFcommandExecuteAsyncTask.java @@ -1,7 +1,6 @@ package nl.bravobit.ffmpeg; import android.os.AsyncTask; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -9,10 +8,12 @@ import java.io.OutputStream; import java.util.Map; import java.util.concurrent.TimeoutException; +@SuppressWarnings("deprecation") class FFcommandExecuteAsyncTask extends AsyncTask implements FFtask { private final String[] cmd; - private Map environment; + private final Map environment; + private final StringBuilder outputStringBuilder = new StringBuilder(); private final FFcommandExecuteResponseHandler ffmpegExecuteResponseHandler; private final ShellCommand shellCommand; private final long timeout; @@ -39,6 +40,7 @@ class FFcommandExecuteAsyncTask extends AsyncTask i @Override protected CommandResult doInBackground(Void... params) { + CommandResult ret = CommandResult.getDummyFailureResponse(); try { process = shellCommand.run(cmd, environment); if (process == null) { @@ -46,16 +48,19 @@ class FFcommandExecuteAsyncTask extends AsyncTask i } Log.d("Running publishing updates method"); checkAndUpdateProcess(); - return CommandResult.getOutputFromProcess(process); + ret = CommandResult.getOutputFromProcess(process); + outputStringBuilder.append(ret.output); } catch (TimeoutException e) { Log.e("FFmpeg binary timed out", e); - return new CommandResult(false, e.getMessage()); + ret = new CommandResult(false, e.getMessage()); + outputStringBuilder.append(ret.output); } catch (Exception e) { Log.e("Error running FFmpeg binary", e); } finally { Util.destroyProcess(process); } - return CommandResult.getDummyFailureResponse(); + output = outputStringBuilder.toString(); + return ret; } @Override @@ -68,7 +73,6 @@ class FFcommandExecuteAsyncTask extends AsyncTask i @Override protected void onPostExecute(CommandResult commandResult) { if (ffmpegExecuteResponseHandler != null) { - output += commandResult.output; if (commandResult.success) { ffmpegExecuteResponseHandler.onSuccess(output); } else { @@ -107,7 +111,7 @@ class FFcommandExecuteAsyncTask extends AsyncTask i return; } - output += line + "\n"; + outputStringBuilder.append(line); outputStringBuilder.append("\n"); publishProgress(line); } } catch (IOException e) { @@ -139,4 +143,4 @@ class FFcommandExecuteAsyncTask extends AsyncTask i e.printStackTrace(); } } -} +} \ No newline at end of file diff --git a/ffmpeg/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFprobe.java b/ffmpeg/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFprobe.java index 447229d6..76bf63b6 100644 --- a/ffmpeg/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFprobe.java +++ b/ffmpeg/android-ffmpeg/src/main/java/nl/bravobit/ffmpeg/FFprobe.java @@ -6,6 +6,7 @@ import android.os.AsyncTask; import java.io.File; import java.util.Map; +@SuppressWarnings("deprecation") public class FFprobe implements FFbinaryInterface { private final FFbinaryContextProvider context; @@ -22,12 +23,7 @@ public class FFprobe implements FFbinaryInterface { public static FFprobe getInstance(final Context context) { if (instance == null) { - instance = new FFprobe(new FFbinaryContextProvider() { - @Override - public Context provide() { - return context; - } - }); + instance = new FFprobe(() -> context); } return instance; } diff --git a/gradle.properties b/gradle.properties index b2589535..61c33e1d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,7 +22,7 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m +org.gradle.jvmargs=-Xmx2048m -XX:+UseParallelGC # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects diff --git a/maintenance-tasks/build.gradle.kts b/maintenance-tasks/build.gradle.kts index b0395302..440b0d2c 100644 --- a/maintenance-tasks/build.gradle.kts +++ b/maintenance-tasks/build.gradle.kts @@ -18,16 +18,15 @@ application { } dependencies { - implementation(Ktor.slf4j) - implementation(Ktor.clientCore) - implementation(Ktor.clientJson) - implementation(Ktor.clientApache) - implementation(Ktor.clientLogging) - implementation(Ktor.clientSerialization) - implementation(Serialization.json) + with(deps) { + implementation(slf4j.simple) + implementation(bundles.ktor) + implementation(ktor.client.apache) + implementation(kotlinx.serialization.json) - // testDeps - testImplementation("org.jetbrains.kotlin:kotlin-test-junit:1.5.21") + // testDep + testImplementation(kotlin.kotlinTestJunit) + } } tasks.test { diff --git a/settings.gradle.kts b/settings.gradle.kts index ed7aeddd..755545b7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -14,6 +14,16 @@ * * along with this program. If not, see . */ +enableFeaturePreview("VERSION_CATALOGS") +dependencyResolutionManagement { + @Suppress("UnstableApiUsage") + versionCatalogs { + create("deps") { + from(files("buildSrc/deps.versions.toml")) + } + } +} + rootProject.name = "spotiflyer" include( @@ -32,5 +42,5 @@ include( ":desktop", ":web-app", //":console-app", - ":maintenance-tasks" + ":maintenance-tasks", ) diff --git a/web-app/build.gradle.kts b/web-app/build.gradle.kts index e13b2509..0c424a61 100644 --- a/web-app/build.gradle.kts +++ b/web-app/build.gradle.kts @@ -21,20 +21,17 @@ plugins { group = "com.shabinder" version = "0.1" -repositories { - mavenCentral() - //maven(url = "https://dl.bintray.com/kotlin/kotlin-js-wrappers") -} - dependencies { - implementation("org.jetbrains.kotlin:kotlin-stdlib-js:1.5.21") - implementation(Koin.core) - implementation(Extras.kermit) - implementation(Decompose.decompose) - implementation(MVIKotlin.mvikotlin) - implementation(MVIKotlin.coroutines) - implementation(MVIKotlin.mvikotlinMain) - implementation(MVIKotlin.mvikotlinLogging) + with(deps) { + implementation(koin.core) + implementation(decompose.dep) + implementation(ktor.client.js) + with(bundles) { + implementation(mviKotlin) + implementation(ktor) + implementation(kotlin.js.wrappers) + } + } implementation(project(":common:root")) implementation(project(":common:main")) implementation(project(":common:list")) @@ -43,27 +40,7 @@ dependencies { implementation(project(":common:providers")) implementation(project(":common:core-components")) implementation(project(":common:dependency-injection")) - implementation("co.touchlab:stately-common:1.1.7") - implementation("dev.icerock.moko:parcelize:${Versions.mokoParcelize}") - // implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1") - - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.2") { - // https://youtrack.jetbrains.com/issue/KTOR-2670 - @Suppress("DEPRECATION") - isForce = true - } - - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1-native-mt") { - @Suppress("DEPRECATION") - isForce = true - } - - with(KotlinJSWrappers) { - implementation(enforcedPlatform(bom)) - implementation(kotlinReact) - implementation(kotlinReactDom) - implementation(kotlinStyled) - } + implementation("org.jetbrains.kotlin:kotlin-stdlib-js:${deps.kotlin.kotlinGradlePlugin.get().versionConstraint.requiredVersion}") } kotlin { diff --git a/web-app/src/main/kotlin/App.kt b/web-app/src/main/kotlin/App.kt index 0f2ee177..f8cacb7b 100644 --- a/web-app/src/main/kotlin/App.kt +++ b/web-app/src/main/kotlin/App.kt @@ -23,21 +23,25 @@ import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory import com.shabinder.common.core_components.file_manager.DownloadProgressFlow import com.shabinder.common.core_components.preference_manager.PreferenceManager +import com.shabinder.common.di.ApplicationInit import com.shabinder.common.models.Actions import com.shabinder.common.models.PlatformActions import com.shabinder.common.models.TrackDetails import com.shabinder.common.root.SpotiFlyerRoot import com.shabinder.database.Database import extras.renderableChild -import react.* +import react.PropsWithChildren +import react.RBuilder +import react.RComponent +import react.State import root.RootR -external interface AppProps : RProps { +external interface AppProps : PropsWithChildren { var dependencies: AppDependencies } @Suppress("FunctionName") -fun RBuilder.App(attrs: AppProps.() -> Unit): ReactElement { +fun RBuilder.App(attrs: AppProps.() -> Unit) { return child(App::class) { this.attrs(attrs) } @@ -46,7 +50,7 @@ fun RBuilder.App(attrs: AppProps.() -> Unit): ReactElement { @Suppress("EXPERIMENTAL_IS_NOT_ENABLED", "NON_EXPORTABLE_TYPE") @OptIn(ExperimentalJsExport::class) @JsExport -class App(props: AppProps) : RComponent(props) { +class App(props: AppProps) : RComponent(props) { private val lifecycle = LifecycleRegistry() private val ctx = DefaultComponentContext(lifecycle = lifecycle) @@ -62,6 +66,7 @@ class App(props: AppProps) : RComponent(props) { override val fetchQuery = dependencies.fetchPlatformQueryResult override val fileManager = dependencies.fileManager override val analyticsManager = dependencies.analyticsManager + override val appInit: ApplicationInit = dependencies.appInit override val preferenceManager: PreferenceManager = dependencies.preferenceManager override val database: Database? = fileManager.db override val downloadProgressFlow = DownloadProgressFlow diff --git a/web-app/src/main/kotlin/client.kt b/web-app/src/main/kotlin/client.kt index 1efce0ae..50ca5c69 100644 --- a/web-app/src/main/kotlin/client.kt +++ b/web-app/src/main/kotlin/client.kt @@ -18,6 +18,7 @@ import co.touchlab.kermit.Kermit import com.shabinder.common.core_components.analytics.AnalyticsManager import com.shabinder.common.core_components.file_manager.FileManager import com.shabinder.common.core_components.preference_manager.PreferenceManager +import com.shabinder.common.di.ApplicationInit import com.shabinder.common.di.initKoin import com.shabinder.common.providers.FetchPlatformQueryResult import kotlinx.browser.document @@ -42,6 +43,7 @@ object AppDependencies : KoinComponent { val fetchPlatformQueryResult: FetchPlatformQueryResult val preferenceManager: PreferenceManager val analyticsManager: AnalyticsManager + val appInit: ApplicationInit init { initKoin() fileManager = get() @@ -49,5 +51,6 @@ object AppDependencies : KoinComponent { fetchPlatformQueryResult = get() preferenceManager = get() analyticsManager = get() + appInit = get() } } \ No newline at end of file diff --git a/web-app/src/main/kotlin/extras/RenderableComponent.kt b/web-app/src/main/kotlin/extras/RenderableComponent.kt index cc3731a0..dc37157c 100644 --- a/web-app/src/main/kotlin/extras/RenderableComponent.kt +++ b/web-app/src/main/kotlin/extras/RenderableComponent.kt @@ -18,16 +18,16 @@ package extras import com.arkivanov.decompose.value.Value import com.arkivanov.decompose.value.ValueObserver +import react.PropsWithChildren import react.RComponent -import react.RProps -import react.RState +import react.State import react.setState @Suppress("EXPERIMENTAL_IS_NOT_ENABLED", "NON_EXPORTABLE_TYPE") @OptIn(ExperimentalJsExport::class) @JsExport -abstract class RenderableComponent( +abstract class RenderableComponent( props: Props, initialState: S ) : RComponent, S>(props) { @@ -60,7 +60,6 @@ abstract class RenderableComponent( } - protected class Subscription( val value: Value, val observer: ValueObserver @@ -72,8 +71,8 @@ abstract class RenderableComponent( @JsExport class RStateWrapper( var model: T -) : RState +) : State -external interface Props : RProps { +external interface Props : PropsWithChildren { var component: T } \ No newline at end of file diff --git a/web-app/src/main/kotlin/home/IconList.kt b/web-app/src/main/kotlin/home/IconList.kt index 1b751793..af947314 100644 --- a/web-app/src/main/kotlin/home/IconList.kt +++ b/web-app/src/main/kotlin/home/IconList.kt @@ -17,39 +17,49 @@ package home import Styles -import kotlinx.css.* +import kotlinx.css.borderRadius +import kotlinx.css.height +import kotlinx.css.margin +import kotlinx.css.px +import kotlinx.css.width import kotlinx.html.id -import react.* +import react.PropsWithChildren +import react.RBuilder import react.dom.attrs -import styled.* +import react.functionComponent +import styled.css +import styled.styledA +import styled.styledDiv +import styled.styledForm +import styled.styledImg -external interface IconListProps : RProps { - var iconsAndPlatforms: Map - var isBadge:Boolean +external interface IconListProps : PropsWithChildren { + var iconsAndPlatforms: Map + var isBadge: Boolean } @Suppress("FunctionName") -fun RBuilder.IconList(handler:IconListProps.() -> Unit): ReactElement { - return child(iconList){ +fun RBuilder.IconList(handler: IconListProps.() -> Unit) { + return child(iconList) { attrs { handler() } } } -private val iconList = functionalComponent("IconList") { props -> +private val iconList = functionComponent("IconList") { props -> styledDiv { css { margin(18.px) - if(props.isBadge) { - classes = mutableListOf("info-banners") + if (props.isBadge) { + classes.add("info-banners") } - + Styles.makeRow + +Styles.makeRow } val firstElem = props.iconsAndPlatforms.keys.elementAt(1) - for((icon,platformLink) in props.iconsAndPlatforms){ - if(icon == firstElem && props.isBadge){ + for ((icon, platformLink) in props.iconsAndPlatforms) { + if (icon == firstElem && props.isBadge) { //
styledForm { attrs { @@ -57,13 +67,13 @@ private val iconList = functionalComponent("IconList") { props -> } } } - styledA(href = platformLink,target="_blank"){ + styledA(href = platformLink, target = "_blank") { styledImg { attrs { src = icon } css { - classes = mutableListOf("glow-button") + classes.add("glow-button") margin(8.px) if (!props.isBadge) { height = 42.px diff --git a/web-app/src/main/kotlin/home/Message.kt b/web-app/src/main/kotlin/home/Message.kt index 4896de97..04f31a45 100644 --- a/web-app/src/main/kotlin/home/Message.kt +++ b/web-app/src/main/kotlin/home/Message.kt @@ -18,34 +18,32 @@ package home import kotlinx.css.em import kotlinx.css.fontSize +import react.PropsWithChildren import react.RBuilder -import react.RProps -import react.ReactElement -import react.child -import react.functionalComponent +import react.functionComponent import styled.css import styled.styledDiv import styled.styledH1 -external interface MessageProps : RProps { +external interface MessageProps : PropsWithChildren { var text: String } @Suppress("FunctionName") -fun RBuilder.Message(handler:MessageProps.() -> Unit): ReactElement { - return child(message){ +fun RBuilder.Message(handler: MessageProps.() -> Unit) { + return child(message) { attrs { handler() } } } -private val message = functionalComponent("Message") { props-> +private val message = functionComponent("Message") { props -> styledDiv { styledH1 { - + props.text + +props.text css { - classes = mutableListOf("headingTitle") + classes.add("headingTitle") fontSize = 2.6.em } } diff --git a/web-app/src/main/kotlin/home/Searchbar.kt b/web-app/src/main/kotlin/home/Searchbar.kt index c611f1a3..30b9bdaa 100644 --- a/web-app/src/main/kotlin/home/Searchbar.kt +++ b/web-app/src/main/kotlin/home/Searchbar.kt @@ -22,32 +22,35 @@ import kotlinx.html.js.onChangeFunction import kotlinx.html.js.onClickFunction import kotlinx.html.js.onKeyDownFunction import org.w3c.dom.HTMLInputElement +import react.PropsWithChildren import react.RBuilder -import react.RProps -import react.child import react.dom.attrs -import react.functionalComponent -import styled.* +import react.functionComponent +import styled.css +import styled.styledButton +import styled.styledDiv +import styled.styledImg +import styled.styledInput -external interface SearchbarProps : RProps { +external interface SearchbarProps : PropsWithChildren { var link: String - var search:(String)->Unit - var onLinkChange:(String)->Unit + var search: (String) -> Unit + var onLinkChange: (String) -> Unit } @Suppress("FunctionName") -fun RBuilder.SearchBar(handler:SearchbarProps.() -> Unit) = child(searchbar){ +fun RBuilder.SearchBar(handler: SearchbarProps.() -> Unit) = child(searchbar) { attrs { handler() } } -val searchbar = functionalComponent("SearchBar"){ props -> - styledDiv{ +val searchbar = functionComponent("SearchBar") { props -> + styledDiv { css { - classes = mutableListOf("searchBox") + classes.add("searchBox") } - styledInput(type = InputType.url){ + styledInput(type = InputType.url) { attrs { placeholder = "Search" onChangeFunction = { @@ -55,30 +58,30 @@ val searchbar = functionalComponent("SearchBar"){ props -> props.onLinkChange(target.value) } this.onKeyDownFunction = { - if(it.asDynamic().key == "Enter") { - if(props.link.isEmpty()) window.alert("Enter a Link from Supported Platforms") + if (it.asDynamic().key == "Enter") { + if (props.link.isEmpty()) window.alert("Enter a Link from Supported Platforms") else props.search(props.link) } } value = props.link } css { - classes = mutableListOf("searchInput") + classes.add("searchInput") } } styledButton { attrs { onClickFunction = { - if(props.link.isEmpty()) window.alert("Enter a Link from Supported Platforms") + if (props.link.isEmpty()) window.alert("Enter a Link from Supported Platforms") else props.search(props.link) } } css { - classes = mutableListOf("searchButton") + classes.add("searchButton") } styledImg(src = "search.svg") { css { - classes = mutableListOf("search-icon") + classes.add("search-icon") } } } diff --git a/web-app/src/main/kotlin/list/CircularProgressBar.kt b/web-app/src/main/kotlin/list/CircularProgressBar.kt index 165a072d..42c51c6a 100644 --- a/web-app/src/main/kotlin/list/CircularProgressBar.kt +++ b/web-app/src/main/kotlin/list/CircularProgressBar.kt @@ -23,42 +23,44 @@ import kotlinx.css.justifyContent import kotlinx.css.marginBottom import kotlinx.css.px import kotlinx.css.width +import react.PropsWithChildren import react.RBuilder -import react.RProps -import react.ReactElement -import react.child -import react.functionalComponent +import react.functionComponent import styled.css import styled.styledDiv import styled.styledSpan @Suppress("FunctionName") -fun RBuilder.CircularProgressBar(handler: CircularProgressBarProps.() -> Unit): ReactElement { - return child(circularProgressBar){ +fun RBuilder.CircularProgressBar(handler: CircularProgressBarProps.() -> Unit) { + return child(circularProgressBar) { attrs { handler() } } } -external interface CircularProgressBarProps : RProps { - var progress:Int +external interface CircularProgressBarProps : PropsWithChildren { + var progress: Int } -private val circularProgressBar = functionalComponent("Circular-Progress-Bar") { props-> +private val circularProgressBar = functionComponent("Circular-Progress-Bar") { props -> styledDiv { styledSpan { +"${props.progress}%" } - styledDiv{ + styledDiv { css { - classes = mutableListOf("left-half-clipper") + classes.add("left-half-clipper") } - styledDiv{ css { classes = mutableListOf("first50-bar") } } - styledDiv{ css { classes = mutableListOf("value-bar") } } + styledDiv { css { classes.add("first50-bar") } } + styledDiv { css { classes.add("value-bar") } } } - css{ + css { display = Display.flex justifyContent = JustifyContent.center - classes = mutableListOf("progress-circle","p${props.progress}").apply { if(props.progress>50) add("over50") } + classes.addAll( + mutableListOf( + "progress-circle", + "p${props.progress}" + ).apply { if (props.progress > 50) add("over50") }) width = 50.px marginBottom = 65.px } diff --git a/web-app/src/main/kotlin/list/CoverImage.kt b/web-app/src/main/kotlin/list/CoverImage.kt index da2d489b..419e1503 100644 --- a/web-app/src/main/kotlin/list/CoverImage.kt +++ b/web-app/src/main/kotlin/list/CoverImage.kt @@ -16,32 +16,45 @@ package list -import kotlinx.css.* +import kotlinx.css.Align +import kotlinx.css.Display +import kotlinx.css.FlexDirection +import kotlinx.css.TextAlign +import kotlinx.css.alignItems +import kotlinx.css.display +import kotlinx.css.flexDirection +import kotlinx.css.height +import kotlinx.css.marginTop +import kotlinx.css.px +import kotlinx.css.textAlign +import kotlinx.css.width import kotlinx.html.id -import react.* +import react.PropsWithChildren +import react.RBuilder import react.dom.attrs +import react.functionComponent import styled.css import styled.styledDiv import styled.styledH1 import styled.styledImg -external interface CoverImageProps : RProps { +external interface CoverImageProps : PropsWithChildren { var coverImageURL: String var coverName: String } @Suppress("FunctionName") -fun RBuilder.CoverImage(handler: CoverImageProps.() -> Unit): ReactElement { - return child(coverImage){ +fun RBuilder.CoverImage(handler: CoverImageProps.() -> Unit) { + return child(coverImage) { attrs { handler() } } } -private val coverImage = functionalComponent("CoverImage"){ props -> +private val coverImage = functionComponent("CoverImage") { props -> styledDiv { - styledImg(src= props.coverImageURL){ + styledImg(src = props.coverImageURL) { css { height = 220.px width = 220.px diff --git a/web-app/src/main/kotlin/list/DownloadAllButton.kt b/web-app/src/main/kotlin/list/DownloadAllButton.kt index 6e79af2f..2dd4a0e9 100644 --- a/web-app/src/main/kotlin/list/DownloadAllButton.kt +++ b/web-app/src/main/kotlin/list/DownloadAllButton.kt @@ -16,52 +16,65 @@ package list -import kotlinx.css.* +import kotlinx.css.Align +import kotlinx.css.Display +import kotlinx.css.JustifyContent +import kotlinx.css.WhiteSpace +import kotlinx.css.alignItems +import kotlinx.css.display +import kotlinx.css.fontSize +import kotlinx.css.height +import kotlinx.css.justifyContent +import kotlinx.css.px +import kotlinx.css.whiteSpace import kotlinx.html.id import kotlinx.html.js.onClickFunction -import react.* +import react.PropsWithChildren +import react.RBuilder import react.dom.attrs +import react.functionComponent +import react.useEffect +import react.useState import styled.css import styled.styledDiv import styled.styledH5 import styled.styledImg -external interface DownloadAllButtonProps : RProps { - var isActive:Boolean - var link : String - var downloadAll:()->Unit +external interface DownloadAllButtonProps : PropsWithChildren { + var isActive: Boolean + var link: String + var downloadAll: () -> Unit } @Suppress("FunctionName") -fun RBuilder.DownloadAllButton(handler: DownloadAllButtonProps.() -> Unit): ReactElement { - return child(downloadAllButton){ +fun RBuilder.DownloadAllButton(handler: DownloadAllButtonProps.() -> Unit) { + return child(downloadAllButton) { attrs { handler() } } } -private val downloadAllButton = functionalComponent("DownloadAllButton") { props-> +private val downloadAllButton = functionComponent("DownloadAllButton") { props -> - val (isClicked,setClicked) = useState(false) + val (isClicked, setClicked) = useState(false) - useEffect(mutableListOf(props.link)){ + useEffect(mutableListOf(props.link)) { setClicked(false) } - if(props.isActive){ - if(isClicked) { - styledDiv{ + if (props.isActive) { + if (isClicked) { + styledDiv { css { display = Display.flex alignItems = Align.center justifyContent = JustifyContent.center height = 52.px } - LoadingSpinner { } + LoadingSpinner { } } - } - else{ + } else { styledDiv { attrs { onClickFunction = { @@ -71,9 +84,9 @@ private val downloadAllButton = functionalComponent("Dow } styledDiv { - styledImg(src = "download.svg",alt = "Download All Button") { + styledImg(src = "download.svg", alt = "Download All Button") { css { - classes = mutableListOf("download-all-icon") + classes.add("download-all-icon") height = 32.px } } @@ -82,7 +95,7 @@ private val downloadAllButton = functionalComponent("Dow attrs { id = "download-all-text" } - + "Download All" + +"Download All" css { whiteSpace = WhiteSpace.nowrap fontSize = 15.px @@ -90,13 +103,13 @@ private val downloadAllButton = functionalComponent("Dow } css { - classes = mutableListOf("download-icon") + classes.add("download-icon") display = Display.flex alignItems = Align.center } } css { - classes = mutableListOf("download-button") + classes.add("download-button") display = Display.flex alignItems = Align.center } diff --git a/web-app/src/main/kotlin/list/DownloadButton.kt b/web-app/src/main/kotlin/list/DownloadButton.kt index 922105c8..0b0f03a8 100644 --- a/web-app/src/main/kotlin/list/DownloadButton.kt +++ b/web-app/src/main/kotlin/list/DownloadButton.kt @@ -17,31 +17,37 @@ package list import com.shabinder.common.models.DownloadStatus -import kotlinx.css.* +import kotlinx.css.borderRadius +import kotlinx.css.em +import kotlinx.css.margin +import kotlinx.css.px +import kotlinx.css.width import kotlinx.html.js.onClickFunction -import react.* +import react.PropsWithChildren +import react.RBuilder import react.dom.attrs +import react.functionComponent import styled.css import styled.styledDiv import styled.styledImg @Suppress("FunctionName") -fun RBuilder.DownloadButton(handler: DownloadButtonProps.() -> Unit): ReactElement { - return child(downloadButton){ +fun RBuilder.DownloadButton(handler: DownloadButtonProps.() -> Unit) { + return child(downloadButton) { attrs { handler() } } } -external interface DownloadButtonProps : RProps { - var onClick:()->Unit - var status :DownloadStatus +external interface DownloadButtonProps : PropsWithChildren { + var onClick: () -> Unit + var status: DownloadStatus } -private val downloadButton = functionalComponent("Circular-Progress-Bar") { props-> +private val downloadButton = functionComponent("Circular-Progress-Bar") { props -> styledDiv { - val src = when(props.status){ + val src = when (props.status) { is DownloadStatus.NotDownloaded -> "download-gradient.svg" is DownloadStatus.Downloaded -> "check.svg" is DownloadStatus.Failed -> "error.svg" @@ -59,7 +65,7 @@ private val downloadButton = functionalComponent("Circular- } } css { - classes = mutableListOf("glow-button") + classes.add("glow-button") borderRadius = 100.px } } diff --git a/web-app/src/main/kotlin/list/ListScreen.kt b/web-app/src/main/kotlin/list/ListScreen.kt index 4fb0a767..ab9f3a51 100644 --- a/web-app/src/main/kotlin/list/ListScreen.kt +++ b/web-app/src/main/kotlin/list/ListScreen.kt @@ -84,7 +84,7 @@ class ListScreen( } css { - classes = mutableListOf("list-screen") + classes.add("list-screen") display = Display.flex padding(8.px) flexDirection = FlexDirection.column diff --git a/web-app/src/main/kotlin/list/LoadingAnim.kt b/web-app/src/main/kotlin/list/LoadingAnim.kt index f618c280..9d738f94 100644 --- a/web-app/src/main/kotlin/list/LoadingAnim.kt +++ b/web-app/src/main/kotlin/list/LoadingAnim.kt @@ -24,43 +24,41 @@ import kotlinx.css.flexGrow import kotlinx.css.height import kotlinx.css.px import kotlinx.css.width +import react.PropsWithChildren import react.RBuilder -import react.RProps -import react.ReactElement -import react.child -import react.functionalComponent +import react.functionComponent import styled.css import styled.styledDiv @Suppress("FunctionName") -fun RBuilder.LoadingAnim(handler: RProps.() -> Unit): ReactElement { - return child(loadingAnim){ +fun RBuilder.LoadingAnim(handler: PropsWithChildren.() -> Unit) { + return child(loadingAnim) { attrs { handler() } } } -private val loadingAnim = functionalComponent("Loading Animation") { - styledDiv{ +private val loadingAnim = functionComponent("Loading Animation") { + styledDiv { css { flexGrow = 1.0 display = Display.flex alignItems = Align.center } styledDiv { - styledDiv { css { classes = mutableListOf("sk-cube sk-cube1") } } - styledDiv { css { classes = mutableListOf("sk-cube sk-cube2") } } - styledDiv { css { classes = mutableListOf("sk-cube sk-cube3") } } - styledDiv { css { classes = mutableListOf("sk-cube sk-cube4") } } - styledDiv { css { classes = mutableListOf("sk-cube sk-cube5") } } - styledDiv { css { classes = mutableListOf("sk-cube sk-cube6") } } - styledDiv { css { classes = mutableListOf("sk-cube sk-cube7") } } - styledDiv { css { classes = mutableListOf("sk-cube sk-cube8") } } - styledDiv { css { classes = mutableListOf("sk-cube sk-cube9") } } + styledDiv { css { classes.add("sk-cube sk-cube1") } } + styledDiv { css { classes.add("sk-cube sk-cube2") } } + styledDiv { css { classes.add("sk-cube sk-cube3") } } + styledDiv { css { classes.add("sk-cube sk-cube4") } } + styledDiv { css { classes.add("sk-cube sk-cube5") } } + styledDiv { css { classes.add("sk-cube sk-cube6") } } + styledDiv { css { classes.add("sk-cube sk-cube7") } } + styledDiv { css { classes.add("sk-cube sk-cube8") } } + styledDiv { css { classes.add("sk-cube sk-cube9") } } css { - classes = mutableListOf("sk-cube-grid") + classes.add("sk-cube-grid") height = 60.px width = 60.px } diff --git a/web-app/src/main/kotlin/list/LoadingSpinner.kt b/web-app/src/main/kotlin/list/LoadingSpinner.kt index a03cb107..2bd9cece 100644 --- a/web-app/src/main/kotlin/list/LoadingSpinner.kt +++ b/web-app/src/main/kotlin/list/LoadingSpinner.kt @@ -19,31 +19,29 @@ package list import kotlinx.css.marginRight import kotlinx.css.px import kotlinx.css.width +import react.PropsWithChildren import react.RBuilder -import react.RProps -import react.ReactElement -import react.child -import react.functionalComponent +import react.functionComponent import styled.css import styled.styledDiv @Suppress("FunctionName") -fun RBuilder.LoadingSpinner(handler: RProps.() -> Unit): ReactElement { - return child(loadingSpinner){ +fun RBuilder.LoadingSpinner(handler: PropsWithChildren.() -> Unit) { + return child(loadingSpinner) { attrs { handler() } } } -private val loadingSpinner = functionalComponent("Loading-Spinner") { +private val loadingSpinner = functionComponent("Loading-Spinner") { styledDiv { - styledDiv{} - styledDiv{} - styledDiv{} - styledDiv{} - css{ - classes = mutableListOf("lds-ring") + styledDiv {} + styledDiv {} + styledDiv {} + styledDiv {} + css { + classes.add("lds-ring") width = 50.px marginRight = 8.px } diff --git a/web-app/src/main/kotlin/list/TrackItem.kt b/web-app/src/main/kotlin/list/TrackItem.kt index 1d66d6b3..df04c40a 100644 --- a/web-app/src/main/kotlin/list/TrackItem.kt +++ b/web-app/src/main/kotlin/list/TrackItem.kt @@ -18,30 +18,61 @@ package list import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.TrackDetails -import kotlinx.css.* +import kotlinx.css.Align +import kotlinx.css.Display +import kotlinx.css.FlexDirection +import kotlinx.css.Overflow +import kotlinx.css.TextAlign +import kotlinx.css.TextOverflow +import kotlinx.css.WhiteSpace +import kotlinx.css.alignItems +import kotlinx.css.display +import kotlinx.css.em +import kotlinx.css.flexDirection +import kotlinx.css.flexGrow +import kotlinx.css.fontSize +import kotlinx.css.height +import kotlinx.css.margin +import kotlinx.css.minWidth +import kotlinx.css.overflow +import kotlinx.css.padding +import kotlinx.css.paddingRight +import kotlinx.css.px +import kotlinx.css.textAlign +import kotlinx.css.textOverflow +import kotlinx.css.whiteSpace +import kotlinx.css.width import kotlinx.html.id -import react.* +import react.PropsWithChildren +import react.RBuilder import react.dom.attrs -import styled.* +import react.functionComponent +import react.useEffect +import react.useState +import styled.css +import styled.styledDiv +import styled.styledH3 +import styled.styledH4 +import styled.styledImg -external interface TrackItemProps : RProps { - var details:TrackDetails - var downloadTrack:(TrackDetails)->Unit +external interface TrackItemProps : PropsWithChildren { + var details: TrackDetails + var downloadTrack: (TrackDetails) -> Unit } @Suppress("FunctionName") -fun RBuilder.TrackItem(handler: TrackItemProps.() -> Unit): ReactElement { - return child(trackItem){ +fun RBuilder.TrackItem(handler: TrackItemProps.() -> Unit) { + return child(trackItem) { attrs { handler() } } } -private val trackItem = functionalComponent("Track-Item"){ props -> - val (downloadStatus,setDownloadStatus) = useState(props.details.downloaded) +private val trackItem = functionComponent("Track-Item") { props -> + val (downloadStatus, setDownloadStatus) = useState(props.details.downloaded) val details = props.details - useEffect(listOf(props.details)){ + useEffect(listOf(props.details)) { setDownloadStatus(props.details.downloaded) } styledDiv { @@ -63,14 +94,14 @@ private val trackItem = functionalComponent("Track-Item"){ props flexDirection = FlexDirection.column margin(8.px) } - styledDiv{ + styledDiv { css { height = 40.px alignItems = Align.center display = Display.flex } styledH3 { - + details.title + +details.title css { padding(8.px) fontSize = 1.3.em @@ -87,7 +118,7 @@ private val trackItem = functionalComponent("Track-Item"){ props display = Display.flex } styledH4 { - + details.artists.joinToString(",") + +details.artists.joinToString(",") css { flexGrow = 1.0 padding(8.px) @@ -109,12 +140,12 @@ private val trackItem = functionalComponent("Track-Item"){ props whiteSpace = WhiteSpace.nowrap overflow = Overflow.hidden } - + "${details.durationSec/60} min, ${details.durationSec%60} sec" + +"${details.durationSec / 60} min, ${details.durationSec % 60} sec" } } } - when(downloadStatus){ - is DownloadStatus.NotDownloaded ->{ + when (downloadStatus) { + is DownloadStatus.NotDownloaded -> { DownloadButton { onClick = { setDownloadStatus(DownloadStatus.Queued) @@ -152,7 +183,7 @@ private val trackItem = functionalComponent("Track-Item"){ props css { alignItems = Align.center - display =Display.flex + display = Display.flex paddingRight = 16.px } } diff --git a/web-app/src/main/kotlin/navbar/NavBar.kt b/web-app/src/main/kotlin/navbar/NavBar.kt index afd781c8..4903a57e 100644 --- a/web-app/src/main/kotlin/navbar/NavBar.kt +++ b/web-app/src/main/kotlin/navbar/NavBar.kt @@ -16,36 +16,55 @@ package navbar -import kotlinx.css.* +import kotlinx.css.Align +import kotlinx.css.Display +import kotlinx.css.LinearDimension +import kotlinx.css.alignItems +import kotlinx.css.display +import kotlinx.css.filter +import kotlinx.css.fontSize +import kotlinx.css.height +import kotlinx.css.margin +import kotlinx.css.marginLeft +import kotlinx.css.marginRight +import kotlinx.css.px +import kotlinx.css.width import kotlinx.html.id import kotlinx.html.js.onBlurFunction import kotlinx.html.js.onClickFunction -import react.* +import react.RBuilder +import react.RProps import react.dom.attrs -import styled.* +import react.functionComponent +import styled.css +import styled.styledA +import styled.styledDiv +import styled.styledH1 +import styled.styledImg +import styled.styledNav @Suppress("FunctionName") -fun RBuilder.NavBar(handler: NavBarProps.() -> Unit): ReactElement{ - return child(navBar){ +fun RBuilder.NavBar(handler: NavBarProps.() -> Unit) { + return child(navBar) { attrs { handler() } } } -external interface NavBarProps:RProps{ +external interface NavBarProps : RProps { var isBackVisible: Boolean var popBackToHomeScreen: () -> Unit } -private val navBar = functionalComponent("NavBar") { props -> +private val navBar = functionComponent("NavBar") { props -> styledNav { css { +NavBarStyles.nav } - styledDiv{ + styledDiv { attrs { onClickFunction = { props.popBackToHomeScreen() @@ -54,22 +73,22 @@ private val navBar = functionalComponent("NavBar") { props -> props.popBackToHomeScreen() } } - styledImg(src = "left-arrow.svg",alt = "Back Arrow"){ + styledImg(src = "left-arrow.svg", alt = "Back Arrow") { css { height = 42.px width = 42.px - display = if(props.isBackVisible) Display.inline else Display.none + display = if (props.isBackVisible) Display.inline else Display.none filter = "invert(100)" marginRight = 12.px } } } - styledA(href = "https://shabinder.github.io/SpotiFlyer/",target="_blank") { + styledA(href = "https://shabinder.github.io/SpotiFlyer/", target = "_blank") { css { display = Display.flex alignItems = Align.center } - styledImg(src = "spotiflyer.svg",alt = "Logo") { + styledImg(src = "spotiflyer.svg", alt = "Logo") { css { height = 42.px width = 42.px @@ -80,7 +99,7 @@ private val navBar = functionalComponent("NavBar") { props -> attrs { id = "appName" } - css{ + css { fontSize = 46.px margin(horizontal = 14.px) } @@ -93,7 +112,7 @@ private val navBar = functionalComponent("NavBar") { props -> setCorsMode(corsProxy) }*/ - styledDiv{ + styledDiv { /*styledH4 { + "Extension" } @@ -125,8 +144,8 @@ private val navBar = functionalComponent("NavBar") { props -> } }*/ - styledA(href = "https://github.com/Shabinder/SpotiFlyer/"){ - styledImg(src = "github.svg"){ + styledA(href = "https://github.com/Shabinder/SpotiFlyer/") { + styledImg(src = "github.svg") { css { height = 42.px width = 42.px diff --git a/web-app/src/main/kotlin/root/RootR.kt b/web-app/src/main/kotlin/root/RootR.kt index 5b4a76af..b7a1c4d5 100644 --- a/web-app/src/main/kotlin/root/RootR.kt +++ b/web-app/src/main/kotlin/root/RootR.kt @@ -26,7 +26,6 @@ import home.HomeScreen import list.ListScreen import navbar.NavBar import react.RBuilder -import react.RState class RootR(props: Props) : RenderableComponent( props = props, @@ -58,4 +57,4 @@ class RootR(props: Props) : RenderableComponent -) : RState +) : react.State