Gradle Deps Catalog, Gradle Script Cleanup, Compose, WebApp Updated

This commit is contained in:
Shabinder Singh 2021-09-30 22:46:43 +05:30
parent f403ca63f2
commit 13471d4a28
50 changed files with 725 additions and 634 deletions

View File

@ -16,7 +16,6 @@
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
import org.jetbrains.compose.compose import org.jetbrains.compose.compose
import org.jetbrains.kotlin.kapt.cli.main
plugins { plugins {
id("com.android.application") id("com.android.application")
@ -79,6 +78,9 @@ android {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8
} }
packagingOptions {
exclude("META-INF/*")
}
configurations { configurations {
"implementation" { "implementation" {
exclude(group = "androidx.compose.animation") exclude(group = "androidx.compose.animation")
@ -92,7 +94,7 @@ android {
dependencies { dependencies {
implementation(compose.material) implementation(compose.material)
implementation(compose.materialIconsExtended) implementation(compose.materialIconsExtended)
implementation(Androidx.androidxActivity) implementation(deps.androidx.activity)
// Project's SubModules // Project's SubModules
implementation(project(":common:database")) implementation(project(":common:database"))
@ -103,43 +105,39 @@ dependencies {
implementation(project(":common:core-components")) implementation(project(":common:core-components"))
implementation(project(":common:providers")) implementation(project(":common:providers"))
with(deps) {
// Koin // Koin
implementation(Koin.android) with(koin) {
implementation(Koin.compose) implementation(androidx.compose)
implementation(android)
}
// DECOMPOSE // DECOMPOSE
implementation(Decompose.decompose) with(decompose) {
implementation(Decompose.extensionsCompose) implementation(dep)
implementation(extensions.compose)
// MVI
implementation(MVIKotlin.mvikotlin)
implementation(MVIKotlin.mvikotlinMain)
implementation(MVIKotlin.mvikotlinLogging)
implementation(MVIKotlin.mvikotlinTimeTravel)
// Extras
with(Extras.Android) {
implementation(countly)
implementation(appUpdator)
} }
with(Versions.androidxLifecycle) { implementation(countly.android)
implementation("androidx.lifecycle:lifecycle-service:$this") implementation(android.app.notifier)
implementation("androidx.lifecycle:lifecycle-common-java8:$this") implementation(storage.chooser)
implementation("androidx.lifecycle:lifecycle-runtime-ktx:$this")
}
implementation(Extras.kermit) with(bundles) {
// implementation("com.jakewharton.timber:timber:4.7.1") implementation(androidx.lifecycle)
implementation("dev.icerock.moko:parcelize:${Versions.mokoParcelize}") implementation(mviKotlin)
implementation("com.github.shabinder:storage-chooser:2.0.4.45") implementation(accompanist.inset)
implementation("com.google.accompanist:accompanist-insets:0.16.1") }
// Test // Test
testImplementation("junit:junit:4.13.2") testImplementation(junit)
androidTestImplementation(Androidx.junit) androidTestImplementation(androidx.junit)
androidTestImplementation(Androidx.expresso) androidTestImplementation(androidx.expresso)
// Desugaring // Desugar
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.5") coreLibraryDesugaring(androidx.desugar)
// Debug
debugImplementation(leak.canary)
}
} }

View File

@ -38,15 +38,25 @@ allprojects {
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>>().configureEach { tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>>().configureEach {
dependsOn(":common:data-models:generateI18n4kFiles") dependsOn(":common:data-models:generateI18n4kFiles")
kotlinOptions { kotlinOptions {
if(this is org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions) { if (this is org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions) {
jvmTarget = "1.8" jvmTarget = "1.8"
} }
freeCompilerArgs = (freeCompilerArgs + listOf("-Xopt-in=kotlin.RequiresOptIn")) freeCompilerArgs = (freeCompilerArgs + listOf("-Xopt-in=kotlin.RequiresOptIn"))
} }
} }
configurations.all {
resolutionStrategy {
eachDependency {
if (requested.group == "org.jetbrains.kotlin") {
@Suppress("UnstableApiUsage")
useVersion(deps.kotlin.kotlinGradlePlugin.get().versionConstraint.requiredVersion)
}
}
}
}
afterEvaluate { afterEvaluate {
project.extensions.findByType<org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension>()?.let { kmpExt -> project.extensions.findByType<org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension>()
?.let { kmpExt ->
kmpExt.sourceSets.run { kmpExt.sourceSets.run {
all { all {
languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn") languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn")

View File

@ -30,17 +30,20 @@ repositories {
} }
dependencies { dependencies {
implementation(Androidx.gradlePlugin) with(deps) {
implementation(JetBrains.Compose.gradlePlugin) implementation(androidx.gradle.plugin)
implementation(JetBrains.Kotlin.gradlePlugin) implementation(kotlin.compose.gradle)
implementation(JetBrains.Kotlin.serialization) implementation(ktlint.gradle)
implementation(SqlDelight.gradlePlugin) implementation(mosaic.gradle)
implementation(KTLint.gradlePlugin) implementation(kotlin.kotlinGradlePlugin)
implementation(Internationalization.gradlePlugin) implementation(sqldelight.gradle.plugin)
implementation(Mosaic.gradlePlugin) implementation(i18n4k.gradle.plugin)
implementation(kotlin.serialization)
}
} }
kotlin { kotlin {
// Add Deps to compilation, so it will become available in main project // Add Deps to compilation, so it will become available in main project
sourceSets.getByName("main").kotlin.srcDir("buildSrc/src/main/kotlin") sourceSets.getByName("main").kotlin.srcDir("buildSrc/src/main/kotlin")
} }

View File

@ -14,11 +14,15 @@
* * along with this program. If not, see <https://www.gnu.org/licenses/>. * * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@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.ExternalModuleDependency
import org.gradle.api.artifacts.VersionCatalog
import org.gradle.api.artifacts.VersionCatalogsExtension
import org.gradle.api.artifacts.dsl.DependencyHandler import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.kotlin.dsl.accessors.runtime.addDependencyTo import org.gradle.kotlin.dsl.accessors.runtime.addDependencyTo
import org.gradle.kotlin.dsl.getByType
object Versions { object Versions {
// App's Version (To be bumped at each update) // App's Version (To be bumped at each update)
@ -26,44 +30,10 @@ object Versions {
const val versionCode = 26 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 // Android
const val minSdkVersion = 21 const val minSdkVersion = 21
const val compileSdkVersion = 30 const val compileSdkVersion = 31
const val targetSdkVersion = 29 const val targetSdkVersion = 29
const val androidxLifecycle = "2.4.0-alpha03"
} }
object HostOS { object HostOS {
@ -74,143 +44,46 @@ object HostOS {
val isLinux = hostOs.startsWith("Linux", true) val isLinux = hostOs.startsWith("Linux", true)
} }
object MultiPlatformSettings { val Project.Deps: VersionCatalog get() = project.extensions.getByType<VersionCatalogsExtension>().named("deps")
const val dep = "com.russhwolf:multiplatform-settings-no-arg:0.7.7"
}
object KotlinJSWrappers { val VersionCatalog.ktorBundle get() = findBundle("ktor").get()
private const val bomVersion = "0.0.1-pre.235-kotlin-1.5.21" val VersionCatalog.statelyBundle get() = findBundle("stately").get()
val bom = "org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom:${bomVersion}" val VersionCatalog.androidXLifecycleBundle get() = findBundle("androidx-lifecycle").get()
const val kotlinReact = "org.jetbrains.kotlin-wrappers:kotlin-react" val VersionCatalog.androidXCommonBundle get() = findBundle("androidx-common").get()
const val kotlinReactDom = "org.jetbrains.kotlin-wrappers:kotlin-react-dom" val VersionCatalog.kotlinTestBundle get() = findBundle("kotlin-test").get()
const val kotlinStyled = "org.jetbrains.kotlin-wrappers:kotlin-styled" 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 VersionCatalog.kotlinJunitTest get() = findDependency("kotlin-kotlinTestJunit").get()
val core = "io.insert-koin:koin-core:${Versions.koin}" val VersionCatalog.kotlinJSTest get() = findDependency("kotlin-kotlinTestJs").get()
val test = "io.insert-koin:koin-test:${Versions.koin}" val VersionCatalog.kermit get() = findDependency("kermit").get()
val android = "io.insert-koin:koin-android:${Versions.koin}" val VersionCatalog.decompose get() = findDependency("decompose-dep").get()
val compose = "io.insert-koin:koin-androidx-compose:${Versions.koin}" val VersionCatalog.decomposeComposeExt get() = findDependency("decompose-extensions-compose").get()
} val VersionCatalog.jaffree get() = findDependency("jaffree").get()
object Androidx { val VersionCatalog.ktlintGradle get() = findDependency("ktlint-gradle").get()
const val androidxActivity = "androidx.activity:activity-compose:1.3.1" val VersionCatalog.androidGradle get() = findDependency("androidx-gradle-plugin").get()
const val core = "androidx.core:core-ktx:1.6.0" val VersionCatalog.mosaicGradle get() = findDependency("mosaic-gradle").get()
const val palette = "androidx.palette:palette-ktx:1.0.0" val VersionCatalog.kotlinComposeGradle get() = findDependency("kotlin-compose-gradle").get()
const val coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.coroutinesVersion}" 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" val VersionCatalog.koinCore get() = findDependency("koin-core").get()
const val expresso = "androidx.test.espresso:espresso-core:3.3.0" 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" 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()
object KTLint { val VersionCatalog.sqlDelightDriver get() = findDependency("sqldelight-driver").get()
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() }

135
buildSrc/deps.versions.toml Normal file
View File

@ -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"]

View File

@ -0,0 +1,12 @@
enableFeaturePreview("VERSION_CATALOGS")
dependencyResolutionManagement {
@Suppress("UnstableApiUsage")
versionCatalogs {
create("deps") {
from(files("deps.versions.toml"))
}
}
}
rootProject.name = "spotiflyer-build"

View File

@ -6,10 +6,10 @@ kotlin {
sourceSets { sourceSets {
all { all {
languageSettings.apply { languageSettings.apply {
useExperimentalAnnotation("kotlin.RequiresOptIn") optIn("kotlin.RequiresOptIn")
useExperimentalAnnotation("kotlin.Experimental") optIn("kotlin.Experimental")
useExperimentalAnnotation("kotlin.time.ExperimentalTime") optIn("kotlin.time.ExperimentalTime")
useExperimentalAnnotation("kotlinx.serialization.ExperimentalSerializationApi") optIn("kotlinx.serialization.ExperimentalSerializationApi")
} }
} }
} }

View File

@ -29,36 +29,23 @@ kotlin {
sourceSets { sourceSets {
all { all {
languageSettings.apply { languageSettings.apply {
useExperimentalAnnotation("androidx.compose.animation") optIn("androidx.compose.animation")
} }
} }
named("commonMain") { named("commonMain") {
dependencies { dependencies {
// Decompose
implementation(Decompose.decompose)
// MVI
implementation(MVIKotlin.coroutines)
implementation(MVIKotlin.mvikotlin)
implementation(compose.ui) implementation(compose.ui)
implementation(compose.runtime) implementation(compose.runtime)
implementation(compose.foundation) implementation(compose.foundation)
implementation(compose.material) implementation(compose.material)
implementation(compose.animation) implementation(compose.animation)
implementation(Deps.kotlinCoroutines)
implementation(Extras.kermit) implementation(Deps.decompose)
implementation("dev.icerock.moko:parcelize:${Versions.mokoParcelize}")
implementation(JetBrains.Kotlin.coroutines) {
@Suppress("DEPRECATION")
isForce = true
}
} }
} }
named("androidMain") { named("androidMain") {
dependencies { dependencies {
implementation(Androidx.androidxActivity) implementation(Deps.androidXCommonBundle)
implementation(Androidx.core)
} }
} }
named("desktopMain") { named("desktopMain") {

View File

@ -42,23 +42,24 @@ kotlin {
sourceSets { sourceSets {
named("commonTest") { named("commonTest") {
dependencies { dependencies {
implementation(JetBrains.Kotlin.testCommon) implementation(Deps.kotlinTestBundle)
implementation(JetBrains.Kotlin.testAnnotationsCommon)
} }
} }
named("androidTest") { named("androidTest") {
dependencies { dependencies {
implementation(JetBrains.Kotlin.testJunit) implementation(Deps.kotlinJunitTest)
} }
} }
named("desktopTest") { named("desktopTest") {
dependencies { dependencies {
implementation(JetBrains.Kotlin.testJunit) implementation(Deps.kotlinJunitTest)
} }
} }
named("jsTest") { named("jsTest") {
dependencies {} dependencies {
implementation(Deps.kotlinJSTest)
}
} }
} }
} }

View File

@ -25,7 +25,7 @@ plugins {
kotlin { kotlin {
/*IOS Target Can be only built on Mac*/ /*IOS Target Can be only built on Mac*/
if(HostOS.isMac){ if (HostOS.isMac) {
val sdkName: String? = System.getenv("SDK_NAME") val sdkName: String? = System.getenv("SDK_NAME")
val isiOSDevice = sdkName.orEmpty().startsWith("iphoneos") val isiOSDevice = sdkName.orEmpty().startsWith("iphoneos")
if (isiOSDevice) { if (isiOSDevice) {
@ -50,45 +50,25 @@ kotlin {
sourceSets { sourceSets {
named("commonMain") { named("commonMain") {
dependencies { dependencies {
// Decompose implementation(Deps.ktorBundle)
implementation(Decompose.decompose) implementation(Deps.kotlinxSerialization)
implementation(Deps.kotlinCoroutines)
// MVI implementation(Deps.mviKotlinBundle)
implementation(MVIKotlin.coroutines) implementation(Deps.decompose)
implementation(MVIKotlin.mvikotlin) implementation(Deps.koinCore)
// 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
}
} }
} }
named("androidMain") { named("androidMain") {
dependencies { dependencies {
implementation(Androidx.androidxActivity)
implementation(Androidx.core)
implementation(compose.runtime) implementation(compose.runtime)
implementation(compose.material) implementation(compose.material)
implementation(compose.foundation) implementation(compose.foundation)
implementation(compose.materialIconsExtended) implementation(compose.materialIconsExtended)
implementation(Decompose.extensionsCompose) implementation(Deps.androidXCommonBundle)
implementation(Ktor.clientAndroid) implementation(Deps.decomposeComposeExt)
implementation(Koin.android) implementation(Deps.ktorClientAndroid)
implementation(Deps.koinAndroidBundle)
} }
} }
@ -99,27 +79,20 @@ kotlin {
implementation(compose.material) implementation(compose.material)
implementation(compose.desktop.common) implementation(compose.desktop.common)
implementation(compose.materialIconsExtended) implementation(compose.materialIconsExtended)
implementation(Decompose.extensionsCompose) implementation(Deps.decomposeComposeExt)
implementation(Ktor.clientApache) implementation(Deps.ktorClientApache)
implementation(Ktor.slf4j) implementation(Deps.slf4j)
} }
} }
named("jsMain") { named("jsMain") {
dependencies { dependencies {
implementation(Ktor.clientJs) implementation(Deps.ktorClientJS)
/*with(KotlinJSWrappers) {
implementation(enforcedPlatform(bom))
implementation(kotlinReact)
implementation(kotlinReactDom)
implementation(kotlinStyled)
}*/
} }
} }
if(HostOS.isMac){ if (HostOS.isMac) {
named("iosMain"){ named("iosMain") {
dependencies { dependencies {
implementation(Ktor.clientIos) implementation(Deps.ktorClientIOS)
} }
} }
} }

View File

@ -40,7 +40,7 @@ kotlin {
implementation(project(":common:database")) implementation(project(":common:database"))
implementation(project(":common:data-models")) implementation(project(":common:data-models"))
implementation(project(":common:dependency-injection")) implementation(project(":common:dependency-injection"))
implementation(Decompose.extensionsCompose) implementation(deps.decompose.extensions.compose)
} }
} }
} }

View File

@ -21,15 +21,19 @@ package com.shabinder.common.uikit
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier 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.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.loadXmlImageVector
import androidx.compose.ui.res.vectorXmlResource import androidx.compose.ui.res.useResource
import org.xml.sax.InputSource
@Composable @Composable
internal actual fun <T> imageVectorResource(id: T): ImageVector = internal actual fun <T> imageVectorResource(id: T): ImageVector {
vectorXmlResource(id as String) val density = LocalDensity.current
return useResource(id as String) {
loadXmlImageVector(InputSource(it), density)
}
}
@Composable @Composable
actual fun DownloadImageTick() { actual fun DownloadImageTick() {

View File

@ -12,7 +12,7 @@ import androidx.compose.ui.unit.dp
actual val MARGIN_SCROLLBAR: Dp = 8.dp actual val MARGIN_SCROLLBAR: Dp = 8.dp
actual typealias ScrollbarAdapter = androidx.compose.foundation.ScrollbarAdapter actual typealias ScrollbarAdapter = ScrollbarAdapter
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
@ -23,8 +23,6 @@ actual fun rememberScrollbarAdapter(
): ScrollbarAdapter = ): ScrollbarAdapter =
androidx.compose.foundation.rememberScrollbarAdapter( androidx.compose.foundation.rememberScrollbarAdapter(
scrollState = scrollState, scrollState = scrollState,
itemCount = itemCount,
averageItemSize = averageItemSize
) )
@Composable @Composable

View File

@ -10,29 +10,37 @@ kotlin {
dependencies { dependencies {
implementation(project(":common:data-models")) implementation(project(":common:data-models"))
implementation(project(":common:database")) implementation(project(":common:database"))
api("org.jetbrains.kotlinx:atomicfu:0.16.2") with(deps) {
api(MultiPlatformSettings.dep) api(multiplatform.settings)
implementation(MVIKotlin.rx) api(kotlinx.atomicfu)
implementation(mviKotlin.rx)
implementation(decompose.dep)
}
} }
} }
androidMain { androidMain {
dependencies { dependencies {
implementation(Extras.mp3agic) with(deps) {
implementation(Extras.Android.countly) implementation(mp3agic)
implementation(countly.android)
}
implementation(project(":ffmpeg:android-ffmpeg")) implementation(project(":ffmpeg:android-ffmpeg"))
} }
} }
desktopMain { desktopMain {
dependencies { dependencies {
implementation(Extras.mp3agic) with(deps) {
implementation(Extras.Desktop.countly) implementation(mp3agic)
implementation("com.github.kokorin.jaffree:jaffree:2021.08.16") implementation(countly.desktop)
implementation(jaffree)
}
} }
} }
jsMain { jsMain {
dependencies { dependencies {
implementation(npm("browser-id3-writer", "4.4.0")) implementation(npm("browser-id3-writer", "4.4.0"))
implementation(npm("file-saver", "2.0.4")) implementation(npm("file-saver", "2.0.4"))
implementation(deps.kotlin.js.wrappers.ext)
} }
} }
} }

View File

@ -30,17 +30,20 @@ import com.shabinder.common.core_components.removeAllTags
import com.shabinder.common.core_components.setId3v1Tags import com.shabinder.common.core_components.setId3v1Tags
import com.shabinder.common.core_components.setId3v2TagsAndSaveFile import com.shabinder.common.core_components.setId3v2TagsAndSaveFile
import com.shabinder.common.database.SpotiFlyerDatabase import com.shabinder.common.database.SpotiFlyerDatabase
import com.shabinder.common.models.Actions
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.models.dispatcherIO import com.shabinder.common.models.dispatcherIO
import com.shabinder.common.models.event.coroutines.SuspendableEvent 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.event.coroutines.map
import com.shabinder.common.models.Actions
import com.shabinder.database.Database 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 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.bind
import org.koin.dsl.module import org.koin.dsl.module
import java.awt.image.BufferedImage import java.awt.image.BufferedImage
@ -165,7 +168,7 @@ class DesktopFileManager(
} }
SuspendableEvent.success(trackDetails.outputFilePath) SuspendableEvent.success(trackDetails.outputFilePath)
} catch (e: Throwable) { } 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() if (songFile.exists()) songFile.delete()
logger.e { "${songFile.absolutePath} could not be created" } logger.e { "${songFile.absolutePath} could not be created" }
SuspendableEvent.error(e) SuspendableEvent.error(e)

View File

@ -25,9 +25,6 @@ plugins {
id("de.comahe.i18n4k") id("de.comahe.i18n4k")
} }
val statelyVersion = "1.1.7"
val statelyIsoVersion = "1.1.7-a1"
i18n4k { i18n4k {
inputDirectory = "../../translations" inputDirectory = "../../translations"
packageName = "com.shabinder.common.translations" packageName = "com.shabinder.common.translations"
@ -50,11 +47,13 @@ kotlin {
} }
commonMain { commonMain {
dependencies { dependencies {
api("co.touchlab:stately-concurrency:$statelyVersion") with(deps) {
api("co.touchlab:stately-isolate:$statelyIsoVersion") api(bundles.stately)
api("co.touchlab:stately-iso-collections:$statelyIsoVersion") api(i18n4k.core)
implementation(Extras.youtubeDownloader) api(kermit)
api(Internationalization.dep) api(moko.parcelize)
implementation(youtube.downloader)
}
} }
} }
} }

View File

@ -34,31 +34,32 @@ kotlin {
implementation(project(":common:data-models")) implementation(project(":common:data-models"))
// SQL Delight // SQL Delight
implementation(SqlDelight.runtime) with(deps.sqldelight) {
implementation(SqlDelight.coroutineExtensions) implementation(runtime)
api(coroutines.extension)
// koin }
implementation(Koin.test)
} }
} }
androidMain { androidMain {
dependencies { dependencies {
implementation(SqlDelight.androidDriver) implementation(deps.sqldelight.android.driver)
} }
} }
desktopMain { desktopMain {
dependencies { dependencies {
implementation(SqlDelight.sqliteDriver) with(deps) {
implementation(SqlDelight.jdbcDriver) implementation(sqldelight.driver)
implementation(sqlite.jdbc.driver)
}
} }
} }
if (HostOS.isMac) { if (HostOS.isMac) {
val iosMain by getting { val iosMain by getting {
dependencies { dependencies {
implementation(SqlDelight.nativeDriver) implementation(deps.sqldelight.native.driver)
} }
} }
} }

View File

@ -14,8 +14,6 @@
* * along with this program. If not, see <https://www.gnu.org/licenses/>. * * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import org.jetbrains.compose.compose
plugins { plugins {
id("android-setup") id("android-setup")
id("multiplatform-setup") id("multiplatform-setup")

View File

@ -30,7 +30,6 @@ kotlin {
implementation(project(":common:database")) implementation(project(":common:database"))
implementation(project(":common:providers")) implementation(project(":common:providers"))
implementation(project(":common:core-components")) implementation(project(":common:core-components"))
implementation(SqlDelight.coroutineExtensions)
} }
} }
} }

View File

@ -30,7 +30,6 @@ kotlin {
implementation(project(":common:database")) implementation(project(":common:database"))
implementation(project(":common:providers")) implementation(project(":common:providers"))
implementation(project(":common:core-components")) implementation(project(":common:core-components"))
implementation(SqlDelight.coroutineExtensions)
} }
} }
} }

View File

@ -30,7 +30,6 @@ kotlin {
implementation(project(":common:database")) implementation(project(":common:database"))
implementation(project(":common:core-components")) implementation(project(":common:core-components"))
implementation(project(":common:providers")) implementation(project(":common:providers"))
implementation(SqlDelight.coroutineExtensions)
} }
} }
} }

View File

@ -12,23 +12,25 @@ kotlin {
sourceSets { sourceSets {
commonMain { commonMain {
dependencies { dependencies {
with(deps) {
implementation(project(":common:data-models")) implementation(project(":common:data-models"))
implementation(project(":common:database")) implementation(project(":common:database"))
implementation(project(":common:core-components")) implementation(project(":common:core-components"))
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.2.1") implementation(youtube.downloader)
implementation(Extras.youtubeDownloader) implementation(fuzzy.wuzzy)
implementation(Extras.fuzzyWuzzy) implementation(kotlinx.datetime)
}
} }
} }
androidMain { androidMain {
dependencies { dependencies {
implementation(Extras.mp3agic) implementation(deps.mp3agic)
} }
} }
desktopMain { desktopMain {
dependencies { dependencies {
implementation(Extras.mp3agic) implementation(deps.mp3agic)
implementation("com.github.kokorin.jaffree:jaffree:2021.08.16") implementation(deps.jaffree)
} }
} }
jsMain { jsMain {

View File

@ -32,7 +32,7 @@ interface SoundCloudRequests {
} }
@Suppress("NAME_SHADOWING") @Suppress("NAME_SHADOWING")
suspend fun getTrack(track: JsonObject): TrackDetails { suspend fun getTrack(track: JsonObject): TrackDetails? {
val track = getTrackInfo(track) val track = getTrackInfo(track)
val title = track.getString("title") val title = track.getString("title")
@ -42,7 +42,7 @@ interface SoundCloudRequests {
if (track.getBoolean("streamable") == false) if (track.getBoolean("streamable") == false)
throw SpotiFlyerException.LinkInvalid("\nSound Cloud Reports that $title is not streamable !\n") throw SpotiFlyerException.LinkInvalid("\nSound Cloud Reports that $title is not streamable !\n")
return null
} }

View File

@ -33,9 +33,10 @@ fun org.jetbrains.kotlin.gradle.dsl.KotlinNativeBinaryContainer.generateFramewor
export(project(":common:providers")) export(project(":common:providers"))
export(project(":common:list")) export(project(":common:list"))
export(project(":common:preference")) export(project(":common:preference"))
export(Decompose.decompose) with(deps) {
export(MVIKotlin.mvikotlinMain) export(decompose.dep)
export(MVIKotlin.mvikotlinLogging) export(bundles.mviKotlin)
}
} }
} }
@ -71,7 +72,6 @@ kotlin {
implementation(project(":common:providers")) implementation(project(":common:providers"))
implementation(project(":common:core-components")) implementation(project(":common:core-components"))
implementation(project(":common:preference")) implementation(project(":common:preference"))
implementation(SqlDelight.coroutineExtensions)
} }
} }
} }
@ -86,9 +86,10 @@ kotlin {
api(project(":common:list")) api(project(":common:list"))
api(project(":common:main")) api(project(":common:main"))
api(project(":common:preference")) api(project(":common:preference"))
api(Decompose.decompose) with(deps) {
api(MVIKotlin.mvikotlinMain) api(decompose.dep)
api(MVIKotlin.mvikotlinLogging) api(bundles.mviKotlin)
}
} }
} }
} }
@ -100,7 +101,10 @@ val packForXcode by tasks.creating(Sync::class) {
group = "build" group = "build"
val mode = System.getenv("CONFIGURATION") ?: "DEBUG" val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
val targetName = "ios" val targetName = "ios"
val framework = kotlin.targets.getByName<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget>(targetName) val framework =
kotlin.targets.getByName<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget>(
targetName
)
.binaries.getFramework(mode) .binaries.getFramework(mode)
inputs.property("mode", mode) inputs.property("mode", mode)
dependsOn(framework.linkTask) dependsOn(framework.linkTask)

View File

@ -19,6 +19,7 @@ application {
} }
dependencies { dependencies {
with(deps) {
implementation(Koin.core) implementation(Koin.core)
implementation(project(":common:database")) implementation(project(":common:database"))
implementation(project(":common:data-models")) implementation(project(":common:data-models"))
@ -40,7 +41,6 @@ dependencies {
implementation(Koin.core) implementation(Koin.core)
// Matomo // Matomo
implementation("org.piwik.java.tracking:matomo-java-tracker:1.6")
implementation(Ktor.slf4j) implementation(Ktor.slf4j)
implementation(Ktor.clientCore) implementation(Ktor.clientCore)
@ -51,6 +51,7 @@ dependencies {
implementation(Serialization.json) implementation(Serialization.json)
// testDeps // testDeps
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:1.5.21") testImplementation("org.jetbrains.kotlin:kotlin-test-junit:1.5.21")
}
} }
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach { tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions { kotlinOptions {

View File

@ -44,19 +44,21 @@ kotlin {
implementation(project(":common:compose")) implementation(project(":common:compose"))
implementation(project(":common:providers")) implementation(project(":common:providers"))
implementation(project(":common:root")) implementation(project(":common:root"))
implementation("com.github.kokorin.jaffree:jaffree:2021.08.16")
// Decompose with(deps) {
implementation(Decompose.decompose) implementation(jaffree)
implementation(Decompose.extensionsCompose)
// MVI with(decompose) {
implementation(MVIKotlin.mvikotlin) implementation(dep)
implementation(MVIKotlin.mvikotlinMain) implementation(extensions.compose)
}
// Koin with(mviKotlin) {
implementation(Koin.core) implementation(dep)
implementation(main)
}
implementation(koin.core)
}
} }
} }
val jvmTest by getting val jvmTest by getting

View File

@ -13,8 +13,6 @@ android {
minSdk = Versions.minSdkVersion minSdk = Versions.minSdkVersion
targetSdk = Versions.targetSdkVersion targetSdk = Versions.targetSdkVersion
// versionCode = Versions.versionCode
// versionName = Versions.versionName
/*ndk { /*ndk {
abiFilters.addAll(setOf("x86", "x86_64", "armeabi-v7a", "arm64-v8a")) abiFilters.addAll(setOf("x86", "x86_64", "armeabi-v7a", "arm64-v8a"))

View File

@ -2,6 +2,7 @@ package nl.bravobit.ffmpeg;
import android.os.Build; import android.os.Build;
@SuppressWarnings("deprecation")
public class CpuArchHelper { public class CpuArchHelper {
public static final String X86_CPU = "x86"; public static final String X86_CPU = "x86";
public static final String X86_64_CPU = "x86_64"; public static final String X86_64_CPU = "x86_64";

View File

@ -1,7 +1,6 @@
package nl.bravobit.ffmpeg; package nl.bravobit.ffmpeg;
import android.os.AsyncTask; import android.os.AsyncTask;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
@ -9,10 +8,12 @@ import java.io.OutputStream;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
@SuppressWarnings("deprecation")
class FFcommandExecuteAsyncTask extends AsyncTask<Void, String, CommandResult> implements FFtask { class FFcommandExecuteAsyncTask extends AsyncTask<Void, String, CommandResult> implements FFtask {
private final String[] cmd; private final String[] cmd;
private Map<String, String> environment; private final Map<String, String> environment;
private final StringBuilder outputStringBuilder = new StringBuilder();
private final FFcommandExecuteResponseHandler ffmpegExecuteResponseHandler; private final FFcommandExecuteResponseHandler ffmpegExecuteResponseHandler;
private final ShellCommand shellCommand; private final ShellCommand shellCommand;
private final long timeout; private final long timeout;
@ -39,6 +40,7 @@ class FFcommandExecuteAsyncTask extends AsyncTask<Void, String, CommandResult> i
@Override @Override
protected CommandResult doInBackground(Void... params) { protected CommandResult doInBackground(Void... params) {
CommandResult ret = CommandResult.getDummyFailureResponse();
try { try {
process = shellCommand.run(cmd, environment); process = shellCommand.run(cmd, environment);
if (process == null) { if (process == null) {
@ -46,16 +48,19 @@ class FFcommandExecuteAsyncTask extends AsyncTask<Void, String, CommandResult> i
} }
Log.d("Running publishing updates method"); Log.d("Running publishing updates method");
checkAndUpdateProcess(); checkAndUpdateProcess();
return CommandResult.getOutputFromProcess(process); ret = CommandResult.getOutputFromProcess(process);
outputStringBuilder.append(ret.output);
} catch (TimeoutException e) { } catch (TimeoutException e) {
Log.e("FFmpeg binary timed out", 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) { } catch (Exception e) {
Log.e("Error running FFmpeg binary", e); Log.e("Error running FFmpeg binary", e);
} finally { } finally {
Util.destroyProcess(process); Util.destroyProcess(process);
} }
return CommandResult.getDummyFailureResponse(); output = outputStringBuilder.toString();
return ret;
} }
@Override @Override
@ -68,7 +73,6 @@ class FFcommandExecuteAsyncTask extends AsyncTask<Void, String, CommandResult> i
@Override @Override
protected void onPostExecute(CommandResult commandResult) { protected void onPostExecute(CommandResult commandResult) {
if (ffmpegExecuteResponseHandler != null) { if (ffmpegExecuteResponseHandler != null) {
output += commandResult.output;
if (commandResult.success) { if (commandResult.success) {
ffmpegExecuteResponseHandler.onSuccess(output); ffmpegExecuteResponseHandler.onSuccess(output);
} else { } else {
@ -107,7 +111,7 @@ class FFcommandExecuteAsyncTask extends AsyncTask<Void, String, CommandResult> i
return; return;
} }
output += line + "\n"; outputStringBuilder.append(line); outputStringBuilder.append("\n");
publishProgress(line); publishProgress(line);
} }
} catch (IOException e) { } catch (IOException e) {

View File

@ -6,6 +6,7 @@ import android.os.AsyncTask;
import java.io.File; import java.io.File;
import java.util.Map; import java.util.Map;
@SuppressWarnings("deprecation")
public class FFprobe implements FFbinaryInterface { public class FFprobe implements FFbinaryInterface {
private final FFbinaryContextProvider context; private final FFbinaryContextProvider context;
@ -22,12 +23,7 @@ public class FFprobe implements FFbinaryInterface {
public static FFprobe getInstance(final Context context) { public static FFprobe getInstance(final Context context) {
if (instance == null) { if (instance == null) {
instance = new FFprobe(new FFbinaryContextProvider() { instance = new FFprobe(() -> context);
@Override
public Context provide() {
return context;
}
});
} }
return instance; return instance;
} }

View File

@ -22,7 +22,7 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html # http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process. # Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings. # 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. # When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit # 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 # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects

View File

@ -18,16 +18,15 @@ application {
} }
dependencies { dependencies {
implementation(Ktor.slf4j) with(deps) {
implementation(Ktor.clientCore) implementation(slf4j.simple)
implementation(Ktor.clientJson) implementation(bundles.ktor)
implementation(Ktor.clientApache) implementation(ktor.client.apache)
implementation(Ktor.clientLogging) implementation(kotlinx.serialization.json)
implementation(Ktor.clientSerialization)
implementation(Serialization.json)
// testDeps // testDep
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:1.5.21") testImplementation(kotlin.kotlinTestJunit)
}
} }
tasks.test { tasks.test {

View File

@ -14,6 +14,16 @@
* * along with this program. If not, see <https://www.gnu.org/licenses/>. * * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
enableFeaturePreview("VERSION_CATALOGS")
dependencyResolutionManagement {
@Suppress("UnstableApiUsage")
versionCatalogs {
create("deps") {
from(files("buildSrc/deps.versions.toml"))
}
}
}
rootProject.name = "spotiflyer" rootProject.name = "spotiflyer"
include( include(
@ -32,5 +42,5 @@ include(
":desktop", ":desktop",
":web-app", ":web-app",
//":console-app", //":console-app",
":maintenance-tasks" ":maintenance-tasks",
) )

View File

@ -21,20 +21,17 @@ plugins {
group = "com.shabinder" group = "com.shabinder"
version = "0.1" version = "0.1"
repositories {
mavenCentral()
//maven(url = "https://dl.bintray.com/kotlin/kotlin-js-wrappers")
}
dependencies { dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-js:1.5.21") with(deps) {
implementation(Koin.core) implementation(koin.core)
implementation(Extras.kermit) implementation(decompose.dep)
implementation(Decompose.decompose) implementation(ktor.client.js)
implementation(MVIKotlin.mvikotlin) with(bundles) {
implementation(MVIKotlin.coroutines) implementation(mviKotlin)
implementation(MVIKotlin.mvikotlinMain) implementation(ktor)
implementation(MVIKotlin.mvikotlinLogging) implementation(kotlin.js.wrappers)
}
}
implementation(project(":common:root")) implementation(project(":common:root"))
implementation(project(":common:main")) implementation(project(":common:main"))
implementation(project(":common:list")) implementation(project(":common:list"))
@ -43,27 +40,7 @@ dependencies {
implementation(project(":common:providers")) implementation(project(":common:providers"))
implementation(project(":common:core-components")) implementation(project(":common:core-components"))
implementation(project(":common:dependency-injection")) implementation(project(":common:dependency-injection"))
implementation("co.touchlab:stately-common:1.1.7") implementation("org.jetbrains.kotlin:kotlin-stdlib-js:${deps.kotlin.kotlinGradlePlugin.get().versionConstraint.requiredVersion}")
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)
}
} }
kotlin { kotlin {

View File

@ -23,21 +23,25 @@ import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory
import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
import com.shabinder.common.core_components.file_manager.DownloadProgressFlow import com.shabinder.common.core_components.file_manager.DownloadProgressFlow
import com.shabinder.common.core_components.preference_manager.PreferenceManager 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.Actions
import com.shabinder.common.models.PlatformActions import com.shabinder.common.models.PlatformActions
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.root.SpotiFlyerRoot import com.shabinder.common.root.SpotiFlyerRoot
import com.shabinder.database.Database import com.shabinder.database.Database
import extras.renderableChild import extras.renderableChild
import react.* import react.PropsWithChildren
import react.RBuilder
import react.RComponent
import react.State
import root.RootR import root.RootR
external interface AppProps : RProps { external interface AppProps : PropsWithChildren {
var dependencies: AppDependencies var dependencies: AppDependencies
} }
@Suppress("FunctionName") @Suppress("FunctionName")
fun RBuilder.App(attrs: AppProps.() -> Unit): ReactElement { fun RBuilder.App(attrs: AppProps.() -> Unit) {
return child(App::class) { return child(App::class) {
this.attrs(attrs) this.attrs(attrs)
} }
@ -46,7 +50,7 @@ fun RBuilder.App(attrs: AppProps.() -> Unit): ReactElement {
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED", "NON_EXPORTABLE_TYPE") @Suppress("EXPERIMENTAL_IS_NOT_ENABLED", "NON_EXPORTABLE_TYPE")
@OptIn(ExperimentalJsExport::class) @OptIn(ExperimentalJsExport::class)
@JsExport @JsExport
class App(props: AppProps) : RComponent<AppProps, RState>(props) { class App(props: AppProps) : RComponent<AppProps, State>(props) {
private val lifecycle = LifecycleRegistry() private val lifecycle = LifecycleRegistry()
private val ctx = DefaultComponentContext(lifecycle = lifecycle) private val ctx = DefaultComponentContext(lifecycle = lifecycle)
@ -62,6 +66,7 @@ class App(props: AppProps) : RComponent<AppProps, RState>(props) {
override val fetchQuery = dependencies.fetchPlatformQueryResult override val fetchQuery = dependencies.fetchPlatformQueryResult
override val fileManager = dependencies.fileManager override val fileManager = dependencies.fileManager
override val analyticsManager = dependencies.analyticsManager override val analyticsManager = dependencies.analyticsManager
override val appInit: ApplicationInit = dependencies.appInit
override val preferenceManager: PreferenceManager = dependencies.preferenceManager override val preferenceManager: PreferenceManager = dependencies.preferenceManager
override val database: Database? = fileManager.db override val database: Database? = fileManager.db
override val downloadProgressFlow = DownloadProgressFlow override val downloadProgressFlow = DownloadProgressFlow

View File

@ -18,6 +18,7 @@ import co.touchlab.kermit.Kermit
import com.shabinder.common.core_components.analytics.AnalyticsManager import com.shabinder.common.core_components.analytics.AnalyticsManager
import com.shabinder.common.core_components.file_manager.FileManager import com.shabinder.common.core_components.file_manager.FileManager
import com.shabinder.common.core_components.preference_manager.PreferenceManager 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.di.initKoin
import com.shabinder.common.providers.FetchPlatformQueryResult import com.shabinder.common.providers.FetchPlatformQueryResult
import kotlinx.browser.document import kotlinx.browser.document
@ -42,6 +43,7 @@ object AppDependencies : KoinComponent {
val fetchPlatformQueryResult: FetchPlatformQueryResult val fetchPlatformQueryResult: FetchPlatformQueryResult
val preferenceManager: PreferenceManager val preferenceManager: PreferenceManager
val analyticsManager: AnalyticsManager val analyticsManager: AnalyticsManager
val appInit: ApplicationInit
init { init {
initKoin() initKoin()
fileManager = get() fileManager = get()
@ -49,5 +51,6 @@ object AppDependencies : KoinComponent {
fetchPlatformQueryResult = get() fetchPlatformQueryResult = get()
preferenceManager = get() preferenceManager = get()
analyticsManager = get() analyticsManager = get()
appInit = get()
} }
} }

View File

@ -18,16 +18,16 @@ package extras
import com.arkivanov.decompose.value.Value import com.arkivanov.decompose.value.Value
import com.arkivanov.decompose.value.ValueObserver import com.arkivanov.decompose.value.ValueObserver
import react.PropsWithChildren
import react.RComponent import react.RComponent
import react.RProps import react.State
import react.RState
import react.setState import react.setState
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED", "NON_EXPORTABLE_TYPE") @Suppress("EXPERIMENTAL_IS_NOT_ENABLED", "NON_EXPORTABLE_TYPE")
@OptIn(ExperimentalJsExport::class) @OptIn(ExperimentalJsExport::class)
@JsExport @JsExport
abstract class RenderableComponent<T: Any, S: RState>( abstract class RenderableComponent<T : Any, S : State>(
props: Props<T>, props: Props<T>,
initialState: S initialState: S
) : RComponent<Props<T>, S>(props) { ) : RComponent<Props<T>, S>(props) {
@ -60,7 +60,6 @@ abstract class RenderableComponent<T: Any, S: RState>(
} }
protected class Subscription<T : Any>( protected class Subscription<T : Any>(
val value: Value<T>, val value: Value<T>,
val observer: ValueObserver<T> val observer: ValueObserver<T>
@ -72,8 +71,8 @@ abstract class RenderableComponent<T: Any, S: RState>(
@JsExport @JsExport
class RStateWrapper<T>( class RStateWrapper<T>(
var model: T var model: T
) : RState ) : State
external interface Props<T : Any> : RProps { external interface Props<T : Any> : PropsWithChildren {
var component: T var component: T
} }

View File

@ -17,39 +17,49 @@
package home package home
import Styles 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 kotlinx.html.id
import react.* import react.PropsWithChildren
import react.RBuilder
import react.dom.attrs 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 { external interface IconListProps : PropsWithChildren {
var iconsAndPlatforms: Map<String,String> var iconsAndPlatforms: Map<String, String>
var isBadge:Boolean var isBadge: Boolean
} }
@Suppress("FunctionName") @Suppress("FunctionName")
fun RBuilder.IconList(handler:IconListProps.() -> Unit): ReactElement { fun RBuilder.IconList(handler: IconListProps.() -> Unit) {
return child(iconList){ return child(iconList) {
attrs { attrs {
handler() handler()
} }
} }
} }
private val iconList = functionalComponent<IconListProps>("IconList") { props -> private val iconList = functionComponent<IconListProps>("IconList") { props ->
styledDiv { styledDiv {
css { css {
margin(18.px) margin(18.px)
if(props.isBadge) { if (props.isBadge) {
classes = mutableListOf("info-banners") classes.add("info-banners")
} }
+ Styles.makeRow +Styles.makeRow
} }
val firstElem = props.iconsAndPlatforms.keys.elementAt(1) val firstElem = props.iconsAndPlatforms.keys.elementAt(1)
for((icon,platformLink) in props.iconsAndPlatforms){ for ((icon, platformLink) in props.iconsAndPlatforms) {
if(icon == firstElem && props.isBadge){ if (icon == firstElem && props.isBadge) {
//<form><script src="https://checkout.razorpay.com/v1/payment-button.js" data-payment_button_id="pl_GnKuuDBdBu0ank" async> </script> </form> //<form><script src="https://checkout.razorpay.com/v1/payment-button.js" data-payment_button_id="pl_GnKuuDBdBu0ank" async> </script> </form>
styledForm { styledForm {
attrs { attrs {
@ -57,13 +67,13 @@ private val iconList = functionalComponent<IconListProps>("IconList") { props ->
} }
} }
} }
styledA(href = platformLink,target="_blank"){ styledA(href = platformLink, target = "_blank") {
styledImg { styledImg {
attrs { attrs {
src = icon src = icon
} }
css { css {
classes = mutableListOf("glow-button") classes.add("glow-button")
margin(8.px) margin(8.px)
if (!props.isBadge) { if (!props.isBadge) {
height = 42.px height = 42.px

View File

@ -18,34 +18,32 @@ package home
import kotlinx.css.em import kotlinx.css.em
import kotlinx.css.fontSize import kotlinx.css.fontSize
import react.PropsWithChildren
import react.RBuilder import react.RBuilder
import react.RProps import react.functionComponent
import react.ReactElement
import react.child
import react.functionalComponent
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
import styled.styledH1 import styled.styledH1
external interface MessageProps : RProps { external interface MessageProps : PropsWithChildren {
var text: String var text: String
} }
@Suppress("FunctionName") @Suppress("FunctionName")
fun RBuilder.Message(handler:MessageProps.() -> Unit): ReactElement { fun RBuilder.Message(handler: MessageProps.() -> Unit) {
return child(message){ return child(message) {
attrs { attrs {
handler() handler()
} }
} }
} }
private val message = functionalComponent<MessageProps>("Message") { props-> private val message = functionComponent<MessageProps>("Message") { props ->
styledDiv { styledDiv {
styledH1 { styledH1 {
+ props.text +props.text
css { css {
classes = mutableListOf("headingTitle") classes.add("headingTitle")
fontSize = 2.6.em fontSize = 2.6.em
} }
} }

View File

@ -22,32 +22,35 @@ import kotlinx.html.js.onChangeFunction
import kotlinx.html.js.onClickFunction import kotlinx.html.js.onClickFunction
import kotlinx.html.js.onKeyDownFunction import kotlinx.html.js.onKeyDownFunction
import org.w3c.dom.HTMLInputElement import org.w3c.dom.HTMLInputElement
import react.PropsWithChildren
import react.RBuilder import react.RBuilder
import react.RProps
import react.child
import react.dom.attrs import react.dom.attrs
import react.functionalComponent import react.functionComponent
import styled.* 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 link: String
var search:(String)->Unit var search: (String) -> Unit
var onLinkChange:(String)->Unit var onLinkChange: (String) -> Unit
} }
@Suppress("FunctionName") @Suppress("FunctionName")
fun RBuilder.SearchBar(handler:SearchbarProps.() -> Unit) = child(searchbar){ fun RBuilder.SearchBar(handler: SearchbarProps.() -> Unit) = child(searchbar) {
attrs { attrs {
handler() handler()
} }
} }
val searchbar = functionalComponent<SearchbarProps>("SearchBar"){ props -> val searchbar = functionComponent<SearchbarProps>("SearchBar") { props ->
styledDiv{ styledDiv {
css { css {
classes = mutableListOf("searchBox") classes.add("searchBox")
} }
styledInput(type = InputType.url){ styledInput(type = InputType.url) {
attrs { attrs {
placeholder = "Search" placeholder = "Search"
onChangeFunction = { onChangeFunction = {
@ -55,30 +58,30 @@ val searchbar = functionalComponent<SearchbarProps>("SearchBar"){ props ->
props.onLinkChange(target.value) props.onLinkChange(target.value)
} }
this.onKeyDownFunction = { this.onKeyDownFunction = {
if(it.asDynamic().key == "Enter") { if (it.asDynamic().key == "Enter") {
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) else props.search(props.link)
} }
} }
value = props.link value = props.link
} }
css { css {
classes = mutableListOf("searchInput") classes.add("searchInput")
} }
} }
styledButton { styledButton {
attrs { attrs {
onClickFunction = { 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) else props.search(props.link)
} }
} }
css { css {
classes = mutableListOf("searchButton") classes.add("searchButton")
} }
styledImg(src = "search.svg") { styledImg(src = "search.svg") {
css { css {
classes = mutableListOf("search-icon") classes.add("search-icon")
} }
} }
} }

View File

@ -23,42 +23,44 @@ import kotlinx.css.justifyContent
import kotlinx.css.marginBottom import kotlinx.css.marginBottom
import kotlinx.css.px import kotlinx.css.px
import kotlinx.css.width import kotlinx.css.width
import react.PropsWithChildren
import react.RBuilder import react.RBuilder
import react.RProps import react.functionComponent
import react.ReactElement
import react.child
import react.functionalComponent
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
import styled.styledSpan import styled.styledSpan
@Suppress("FunctionName") @Suppress("FunctionName")
fun RBuilder.CircularProgressBar(handler: CircularProgressBarProps.() -> Unit): ReactElement { fun RBuilder.CircularProgressBar(handler: CircularProgressBarProps.() -> Unit) {
return child(circularProgressBar){ return child(circularProgressBar) {
attrs { attrs {
handler() handler()
} }
} }
} }
external interface CircularProgressBarProps : RProps { external interface CircularProgressBarProps : PropsWithChildren {
var progress:Int var progress: Int
} }
private val circularProgressBar = functionalComponent<CircularProgressBarProps>("Circular-Progress-Bar") { props-> private val circularProgressBar = functionComponent<CircularProgressBarProps>("Circular-Progress-Bar") { props ->
styledDiv { styledDiv {
styledSpan { +"${props.progress}%" } styledSpan { +"${props.progress}%" }
styledDiv{ styledDiv {
css { css {
classes = mutableListOf("left-half-clipper") classes.add("left-half-clipper")
} }
styledDiv{ css { classes = mutableListOf("first50-bar") } } styledDiv { css { classes.add("first50-bar") } }
styledDiv{ css { classes = mutableListOf("value-bar") } } styledDiv { css { classes.add("value-bar") } }
} }
css{ css {
display = Display.flex display = Display.flex
justifyContent = JustifyContent.center 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 width = 50.px
marginBottom = 65.px marginBottom = 65.px
} }

View File

@ -16,32 +16,45 @@
package list 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 kotlinx.html.id
import react.* import react.PropsWithChildren
import react.RBuilder
import react.dom.attrs import react.dom.attrs
import react.functionComponent
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
import styled.styledH1 import styled.styledH1
import styled.styledImg import styled.styledImg
external interface CoverImageProps : RProps { external interface CoverImageProps : PropsWithChildren {
var coverImageURL: String var coverImageURL: String
var coverName: String var coverName: String
} }
@Suppress("FunctionName") @Suppress("FunctionName")
fun RBuilder.CoverImage(handler: CoverImageProps.() -> Unit): ReactElement { fun RBuilder.CoverImage(handler: CoverImageProps.() -> Unit) {
return child(coverImage){ return child(coverImage) {
attrs { attrs {
handler() handler()
} }
} }
} }
private val coverImage = functionalComponent<CoverImageProps>("CoverImage"){ props -> private val coverImage = functionComponent<CoverImageProps>("CoverImage") { props ->
styledDiv { styledDiv {
styledImg(src= props.coverImageURL){ styledImg(src = props.coverImageURL) {
css { css {
height = 220.px height = 220.px
width = 220.px width = 220.px

View File

@ -16,42 +16,56 @@
package list 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.id
import kotlinx.html.js.onClickFunction import kotlinx.html.js.onClickFunction
import react.* import react.PropsWithChildren
import react.RBuilder
import react.dom.attrs import react.dom.attrs
import react.functionComponent
import react.useEffect
import react.useState
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
import styled.styledH5 import styled.styledH5
import styled.styledImg import styled.styledImg
external interface DownloadAllButtonProps : RProps { external interface DownloadAllButtonProps : PropsWithChildren {
var isActive:Boolean var isActive: Boolean
var link : String var link: String
var downloadAll:()->Unit var downloadAll: () -> Unit
} }
@Suppress("FunctionName") @Suppress("FunctionName")
fun RBuilder.DownloadAllButton(handler: DownloadAllButtonProps.() -> Unit): ReactElement { fun RBuilder.DownloadAllButton(handler: DownloadAllButtonProps.() -> Unit) {
return child(downloadAllButton){ return child(downloadAllButton) {
attrs { attrs {
handler() handler()
} }
} }
} }
private val downloadAllButton = functionalComponent<DownloadAllButtonProps>("DownloadAllButton") { props-> private val downloadAllButton = functionComponent<DownloadAllButtonProps>("DownloadAllButton") { props ->
val (isClicked,setClicked) = useState(false) val (isClicked, setClicked) = useState(false)
useEffect(mutableListOf(props.link)){ useEffect(mutableListOf(props.link)) {
setClicked(false) setClicked(false)
} }
if(props.isActive){ if (props.isActive) {
if(isClicked) { if (isClicked) {
styledDiv{ styledDiv {
css { css {
display = Display.flex display = Display.flex
alignItems = Align.center alignItems = Align.center
@ -60,8 +74,7 @@ private val downloadAllButton = functionalComponent<DownloadAllButtonProps>("Dow
} }
LoadingSpinner { } LoadingSpinner { }
} }
} } else {
else{
styledDiv { styledDiv {
attrs { attrs {
onClickFunction = { onClickFunction = {
@ -71,9 +84,9 @@ private val downloadAllButton = functionalComponent<DownloadAllButtonProps>("Dow
} }
styledDiv { styledDiv {
styledImg(src = "download.svg",alt = "Download All Button") { styledImg(src = "download.svg", alt = "Download All Button") {
css { css {
classes = mutableListOf("download-all-icon") classes.add("download-all-icon")
height = 32.px height = 32.px
} }
} }
@ -82,7 +95,7 @@ private val downloadAllButton = functionalComponent<DownloadAllButtonProps>("Dow
attrs { attrs {
id = "download-all-text" id = "download-all-text"
} }
+ "Download All" +"Download All"
css { css {
whiteSpace = WhiteSpace.nowrap whiteSpace = WhiteSpace.nowrap
fontSize = 15.px fontSize = 15.px
@ -90,13 +103,13 @@ private val downloadAllButton = functionalComponent<DownloadAllButtonProps>("Dow
} }
css { css {
classes = mutableListOf("download-icon") classes.add("download-icon")
display = Display.flex display = Display.flex
alignItems = Align.center alignItems = Align.center
} }
} }
css { css {
classes = mutableListOf("download-button") classes.add("download-button")
display = Display.flex display = Display.flex
alignItems = Align.center alignItems = Align.center
} }

View File

@ -17,31 +17,37 @@
package list package list
import com.shabinder.common.models.DownloadStatus 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 kotlinx.html.js.onClickFunction
import react.* import react.PropsWithChildren
import react.RBuilder
import react.dom.attrs import react.dom.attrs
import react.functionComponent
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
import styled.styledImg import styled.styledImg
@Suppress("FunctionName") @Suppress("FunctionName")
fun RBuilder.DownloadButton(handler: DownloadButtonProps.() -> Unit): ReactElement { fun RBuilder.DownloadButton(handler: DownloadButtonProps.() -> Unit) {
return child(downloadButton){ return child(downloadButton) {
attrs { attrs {
handler() handler()
} }
} }
} }
external interface DownloadButtonProps : RProps { external interface DownloadButtonProps : PropsWithChildren {
var onClick:()->Unit var onClick: () -> Unit
var status :DownloadStatus var status: DownloadStatus
} }
private val downloadButton = functionalComponent<DownloadButtonProps>("Circular-Progress-Bar") { props-> private val downloadButton = functionComponent<DownloadButtonProps>("Circular-Progress-Bar") { props ->
styledDiv { styledDiv {
val src = when(props.status){ val src = when (props.status) {
is DownloadStatus.NotDownloaded -> "download-gradient.svg" is DownloadStatus.NotDownloaded -> "download-gradient.svg"
is DownloadStatus.Downloaded -> "check.svg" is DownloadStatus.Downloaded -> "check.svg"
is DownloadStatus.Failed -> "error.svg" is DownloadStatus.Failed -> "error.svg"
@ -59,7 +65,7 @@ private val downloadButton = functionalComponent<DownloadButtonProps>("Circular-
} }
} }
css { css {
classes = mutableListOf("glow-button") classes.add("glow-button")
borderRadius = 100.px borderRadius = 100.px
} }
} }

View File

@ -84,7 +84,7 @@ class ListScreen(
} }
css { css {
classes = mutableListOf("list-screen") classes.add("list-screen")
display = Display.flex display = Display.flex
padding(8.px) padding(8.px)
flexDirection = FlexDirection.column flexDirection = FlexDirection.column

View File

@ -24,43 +24,41 @@ import kotlinx.css.flexGrow
import kotlinx.css.height import kotlinx.css.height
import kotlinx.css.px import kotlinx.css.px
import kotlinx.css.width import kotlinx.css.width
import react.PropsWithChildren
import react.RBuilder import react.RBuilder
import react.RProps import react.functionComponent
import react.ReactElement
import react.child
import react.functionalComponent
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
@Suppress("FunctionName") @Suppress("FunctionName")
fun RBuilder.LoadingAnim(handler: RProps.() -> Unit): ReactElement { fun RBuilder.LoadingAnim(handler: PropsWithChildren.() -> Unit) {
return child(loadingAnim){ return child(loadingAnim) {
attrs { attrs {
handler() handler()
} }
} }
} }
private val loadingAnim = functionalComponent<RProps>("Loading Animation") { private val loadingAnim = functionComponent<PropsWithChildren>("Loading Animation") {
styledDiv{ styledDiv {
css { css {
flexGrow = 1.0 flexGrow = 1.0
display = Display.flex display = Display.flex
alignItems = Align.center alignItems = Align.center
} }
styledDiv { styledDiv {
styledDiv { css { classes = mutableListOf("sk-cube sk-cube1") } } styledDiv { css { classes.add("sk-cube sk-cube1") } }
styledDiv { css { classes = mutableListOf("sk-cube sk-cube2") } } styledDiv { css { classes.add("sk-cube sk-cube2") } }
styledDiv { css { classes = mutableListOf("sk-cube sk-cube3") } } styledDiv { css { classes.add("sk-cube sk-cube3") } }
styledDiv { css { classes = mutableListOf("sk-cube sk-cube4") } } styledDiv { css { classes.add("sk-cube sk-cube4") } }
styledDiv { css { classes = mutableListOf("sk-cube sk-cube5") } } styledDiv { css { classes.add("sk-cube sk-cube5") } }
styledDiv { css { classes = mutableListOf("sk-cube sk-cube6") } } styledDiv { css { classes.add("sk-cube sk-cube6") } }
styledDiv { css { classes = mutableListOf("sk-cube sk-cube7") } } styledDiv { css { classes.add("sk-cube sk-cube7") } }
styledDiv { css { classes = mutableListOf("sk-cube sk-cube8") } } styledDiv { css { classes.add("sk-cube sk-cube8") } }
styledDiv { css { classes = mutableListOf("sk-cube sk-cube9") } } styledDiv { css { classes.add("sk-cube sk-cube9") } }
css { css {
classes = mutableListOf("sk-cube-grid") classes.add("sk-cube-grid")
height = 60.px height = 60.px
width = 60.px width = 60.px
} }

View File

@ -19,31 +19,29 @@ package list
import kotlinx.css.marginRight import kotlinx.css.marginRight
import kotlinx.css.px import kotlinx.css.px
import kotlinx.css.width import kotlinx.css.width
import react.PropsWithChildren
import react.RBuilder import react.RBuilder
import react.RProps import react.functionComponent
import react.ReactElement
import react.child
import react.functionalComponent
import styled.css import styled.css
import styled.styledDiv import styled.styledDiv
@Suppress("FunctionName") @Suppress("FunctionName")
fun RBuilder.LoadingSpinner(handler: RProps.() -> Unit): ReactElement { fun RBuilder.LoadingSpinner(handler: PropsWithChildren.() -> Unit) {
return child(loadingSpinner){ return child(loadingSpinner) {
attrs { attrs {
handler() handler()
} }
} }
} }
private val loadingSpinner = functionalComponent<RProps>("Loading-Spinner") { private val loadingSpinner = functionComponent<PropsWithChildren>("Loading-Spinner") {
styledDiv { styledDiv {
styledDiv{} styledDiv {}
styledDiv{} styledDiv {}
styledDiv{} styledDiv {}
styledDiv{} styledDiv {}
css{ css {
classes = mutableListOf("lds-ring") classes.add("lds-ring")
width = 50.px width = 50.px
marginRight = 8.px marginRight = 8.px
} }

View File

@ -18,30 +18,61 @@ package list
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.TrackDetails 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 kotlinx.html.id
import react.* import react.PropsWithChildren
import react.RBuilder
import react.dom.attrs 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 { external interface TrackItemProps : PropsWithChildren {
var details:TrackDetails var details: TrackDetails
var downloadTrack:(TrackDetails)->Unit var downloadTrack: (TrackDetails) -> Unit
} }
@Suppress("FunctionName") @Suppress("FunctionName")
fun RBuilder.TrackItem(handler: TrackItemProps.() -> Unit): ReactElement { fun RBuilder.TrackItem(handler: TrackItemProps.() -> Unit) {
return child(trackItem){ return child(trackItem) {
attrs { attrs {
handler() handler()
} }
} }
} }
private val trackItem = functionalComponent<TrackItemProps>("Track-Item"){ props -> private val trackItem = functionComponent<TrackItemProps>("Track-Item") { props ->
val (downloadStatus,setDownloadStatus) = useState(props.details.downloaded) val (downloadStatus, setDownloadStatus) = useState(props.details.downloaded)
val details = props.details val details = props.details
useEffect(listOf(props.details)){ useEffect(listOf(props.details)) {
setDownloadStatus(props.details.downloaded) setDownloadStatus(props.details.downloaded)
} }
styledDiv { styledDiv {
@ -63,14 +94,14 @@ private val trackItem = functionalComponent<TrackItemProps>("Track-Item"){ props
flexDirection = FlexDirection.column flexDirection = FlexDirection.column
margin(8.px) margin(8.px)
} }
styledDiv{ styledDiv {
css { css {
height = 40.px height = 40.px
alignItems = Align.center alignItems = Align.center
display = Display.flex display = Display.flex
} }
styledH3 { styledH3 {
+ details.title +details.title
css { css {
padding(8.px) padding(8.px)
fontSize = 1.3.em fontSize = 1.3.em
@ -87,7 +118,7 @@ private val trackItem = functionalComponent<TrackItemProps>("Track-Item"){ props
display = Display.flex display = Display.flex
} }
styledH4 { styledH4 {
+ details.artists.joinToString(",") +details.artists.joinToString(",")
css { css {
flexGrow = 1.0 flexGrow = 1.0
padding(8.px) padding(8.px)
@ -109,12 +140,12 @@ private val trackItem = functionalComponent<TrackItemProps>("Track-Item"){ props
whiteSpace = WhiteSpace.nowrap whiteSpace = WhiteSpace.nowrap
overflow = Overflow.hidden overflow = Overflow.hidden
} }
+ "${details.durationSec/60} min, ${details.durationSec%60} sec" +"${details.durationSec / 60} min, ${details.durationSec % 60} sec"
} }
} }
} }
when(downloadStatus){ when (downloadStatus) {
is DownloadStatus.NotDownloaded ->{ is DownloadStatus.NotDownloaded -> {
DownloadButton { DownloadButton {
onClick = { onClick = {
setDownloadStatus(DownloadStatus.Queued) setDownloadStatus(DownloadStatus.Queued)
@ -152,7 +183,7 @@ private val trackItem = functionalComponent<TrackItemProps>("Track-Item"){ props
css { css {
alignItems = Align.center alignItems = Align.center
display =Display.flex display = Display.flex
paddingRight = 16.px paddingRight = 16.px
} }
} }

View File

@ -16,36 +16,55 @@
package navbar 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.id
import kotlinx.html.js.onBlurFunction import kotlinx.html.js.onBlurFunction
import kotlinx.html.js.onClickFunction import kotlinx.html.js.onClickFunction
import react.* import react.RBuilder
import react.RProps
import react.dom.attrs 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") @Suppress("FunctionName")
fun RBuilder.NavBar(handler: NavBarProps.() -> Unit): ReactElement{ fun RBuilder.NavBar(handler: NavBarProps.() -> Unit) {
return child(navBar){ return child(navBar) {
attrs { attrs {
handler() handler()
} }
} }
} }
external interface NavBarProps:RProps{ external interface NavBarProps : RProps {
var isBackVisible: Boolean var isBackVisible: Boolean
var popBackToHomeScreen: () -> Unit var popBackToHomeScreen: () -> Unit
} }
private val navBar = functionalComponent<NavBarProps>("NavBar") { props -> private val navBar = functionComponent<NavBarProps>("NavBar") { props ->
styledNav { styledNav {
css { css {
+NavBarStyles.nav +NavBarStyles.nav
} }
styledDiv{ styledDiv {
attrs { attrs {
onClickFunction = { onClickFunction = {
props.popBackToHomeScreen() props.popBackToHomeScreen()
@ -54,22 +73,22 @@ private val navBar = functionalComponent<NavBarProps>("NavBar") { props ->
props.popBackToHomeScreen() props.popBackToHomeScreen()
} }
} }
styledImg(src = "left-arrow.svg",alt = "Back Arrow"){ styledImg(src = "left-arrow.svg", alt = "Back Arrow") {
css { css {
height = 42.px height = 42.px
width = 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)" filter = "invert(100)"
marginRight = 12.px marginRight = 12.px
} }
} }
} }
styledA(href = "https://shabinder.github.io/SpotiFlyer/",target="_blank") { styledA(href = "https://shabinder.github.io/SpotiFlyer/", target = "_blank") {
css { css {
display = Display.flex display = Display.flex
alignItems = Align.center alignItems = Align.center
} }
styledImg(src = "spotiflyer.svg",alt = "Logo") { styledImg(src = "spotiflyer.svg", alt = "Logo") {
css { css {
height = 42.px height = 42.px
width = 42.px width = 42.px
@ -80,7 +99,7 @@ private val navBar = functionalComponent<NavBarProps>("NavBar") { props ->
attrs { attrs {
id = "appName" id = "appName"
} }
css{ css {
fontSize = 46.px fontSize = 46.px
margin(horizontal = 14.px) margin(horizontal = 14.px)
} }
@ -93,7 +112,7 @@ private val navBar = functionalComponent<NavBarProps>("NavBar") { props ->
setCorsMode(corsProxy) setCorsMode(corsProxy)
}*/ }*/
styledDiv{ styledDiv {
/*styledH4 { + "Extension" } /*styledH4 { + "Extension" }
@ -125,8 +144,8 @@ private val navBar = functionalComponent<NavBarProps>("NavBar") { props ->
} }
}*/ }*/
styledA(href = "https://github.com/Shabinder/SpotiFlyer/"){ styledA(href = "https://github.com/Shabinder/SpotiFlyer/") {
styledImg(src = "github.svg"){ styledImg(src = "github.svg") {
css { css {
height = 42.px height = 42.px
width = 42.px width = 42.px

View File

@ -26,7 +26,6 @@ import home.HomeScreen
import list.ListScreen import list.ListScreen
import navbar.NavBar import navbar.NavBar
import react.RBuilder import react.RBuilder
import react.RState
class RootR(props: Props<SpotiFlyerRoot>) : RenderableComponent<SpotiFlyerRoot, State>( class RootR(props: Props<SpotiFlyerRoot>) : RenderableComponent<SpotiFlyerRoot, State>(
props = props, props = props,
@ -58,4 +57,4 @@ class RootR(props: Props<SpotiFlyerRoot>) : RenderableComponent<SpotiFlyerRoot,
@JsExport @JsExport
class State( class State(
var routerState: RouterState<*, Child> var routerState: RouterState<*, Child>
) : RState ) : react.State