diff --git a/android/src/main/java/com/shabinder/spotiflyer/App.kt b/android/src/main/java/com/shabinder/spotiflyer/App.kt index e3f2fd77..cdef2ed9 100644 --- a/android/src/main/java/com/shabinder/spotiflyer/App.kt +++ b/android/src/main/java/com/shabinder/spotiflyer/App.kt @@ -22,7 +22,7 @@ import com.shabinder.common.di.initKoin import com.shabinder.spotiflyer.di.appModule import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger -import org.koin.core.KoinComponent +import org.koin.core.component.KoinComponent class App: Application(), KoinComponent { override fun onCreate() { diff --git a/common/compose/src/androidMain/kotlin/com/shabinder/common/uikit/AndroidImages.kt b/common/compose/src/androidMain/kotlin/com/shabinder/common/uikit/AndroidImages.kt index 04b5cbac..6beb34cd 100644 --- a/common/compose/src/androidMain/kotlin/com/shabinder/common/uikit/AndroidImages.kt +++ b/common/compose/src/androidMain/kotlin/com/shabinder/common/uikit/AndroidImages.kt @@ -22,7 +22,13 @@ import com.shabinder.common.di.dispatcherIO import kotlinx.coroutines.withContext @Composable -actual fun ImageLoad(link:String, loader:suspend (String) -> Picture, desc: String, modifier:Modifier, placeholder: ImageVector) { +actual fun ImageLoad( + link:String, + loader:suspend (String) -> Picture, + desc: String, + modifier:Modifier, + //placeholder: ImageVector +) { var pic by remember(link) { mutableStateOf(null) } LaunchedEffect(link){ withContext(dispatcherIO) { @@ -31,7 +37,7 @@ actual fun ImageLoad(link:String, loader:suspend (String) -> Picture, desc: Stri } Crossfade(pic){ - if(it == null) Image(placeholder, desc, modifier,contentScale = ContentScale.Crop) else Image(it, desc, modifier,contentScale = ContentScale.Crop) + if(it == null) Image(PlaceHolderImage(), desc, modifier,contentScale = ContentScale.Crop) else Image(it, desc, modifier,contentScale = ContentScale.Crop) } } diff --git a/common/compose/src/commonMain/kotlin/com/shabinder/common/uikit/ExpectImages.kt b/common/compose/src/commonMain/kotlin/com/shabinder/common/uikit/ExpectImages.kt index 375795be..c5b5f104 100644 --- a/common/compose/src/commonMain/kotlin/com/shabinder/common/uikit/ExpectImages.kt +++ b/common/compose/src/commonMain/kotlin/com/shabinder/common/uikit/ExpectImages.kt @@ -12,7 +12,7 @@ expect fun ImageLoad( loader:suspend (String) ->Picture, desc: String = "Album Art", modifier:Modifier = Modifier, - placeholder:ImageVector = PlaceHolderImage() + //placeholder:ImageVector = PlaceHolderImage() ) @Composable diff --git a/common/compose/src/commonMain/kotlin/com/shabinder/common/uikit/SpotiFlyerRootUi.kt b/common/compose/src/commonMain/kotlin/com/shabinder/common/uikit/SpotiFlyerRootUi.kt index 8a08c2b6..f894956f 100644 --- a/common/compose/src/commonMain/kotlin/com/shabinder/common/uikit/SpotiFlyerRootUi.kt +++ b/common/compose/src/commonMain/kotlin/com/shabinder/common/uikit/SpotiFlyerRootUi.kt @@ -25,6 +25,8 @@ import com.shabinder.common.uikit.splash.Splash import com.shabinder.common.uikit.splash.SplashState import com.shabinder.common.uikit.utils.verticalGradientScrim +private var isSplashShown = SplashState.Shown + @Composable fun SpotiFlyerRootContent(component: SpotiFlyerRoot, statusBarHeight:Dp = 0.dp): SpotiFlyerRoot { @@ -34,23 +36,26 @@ fun SpotiFlyerRootContent(component: SpotiFlyerRoot, statusBarHeight:Dp = 0.dp): val splashAlpha by transition.animateFloat( transitionSpec = { tween(durationMillis = 100) } ) { - if (it == SplashState.Shown) 1f else 0f + if (it == SplashState.Shown && isSplashShown == SplashState.Shown) 1f else 0f } val contentAlpha by transition.animateFloat( transitionSpec = { tween(durationMillis = 300) } ) { - if (it == SplashState.Shown) 0f else 1f + if (it == SplashState.Shown && isSplashShown == SplashState.Shown) 0f else 1f } val contentTopPadding by transition.animateDp( transitionSpec = { spring(stiffness = StiffnessLow) } ) { - if (it == SplashState.Shown) 100.dp else 0.dp + if (it == SplashState.Shown && isSplashShown == SplashState.Shown) 100.dp else 0.dp } Box{ Splash( modifier = Modifier.alpha(splashAlpha), - onTimeout = { transitionState.targetState = SplashState.Completed } + onTimeout = { + transitionState.targetState = SplashState.Completed + isSplashShown = SplashState.Completed + } ) MainScreen( Modifier.alpha(contentAlpha), 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 d5867bb6..f033eefe 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 @@ -16,9 +16,14 @@ import com.shabinder.common.di.Picture import com.shabinder.common.di.dispatcherIO import kotlinx.coroutines.withContext - @Composable -actual fun ImageLoad(link:String, loader:suspend (String) -> Picture, desc: String, modifier:Modifier, placeholder: ImageVector) { +actual fun ImageLoad( + link:String, + loader:suspend (String) -> Picture, + desc: String, + modifier:Modifier, + //placeholder: ImageVector +) { var pic by remember(link) { mutableStateOf(null) } LaunchedEffect(link){ withContext(dispatcherIO) { @@ -27,7 +32,7 @@ actual fun ImageLoad(link:String, loader:suspend (String) -> Picture, desc: Stri } Crossfade(pic){ - if(it == null) Image(placeholder, desc, modifier,contentScale = ContentScale.Crop) else Image(it, desc, modifier,contentScale = ContentScale.Crop) + if(it == null) Image(PlaceHolderImage(), desc, modifier,contentScale = ContentScale.Crop) else Image(it, desc, modifier,contentScale = ContentScale.Crop) } } diff --git a/common/dependency-injection/build.gradle.kts b/common/dependency-injection/build.gradle.kts index 3a146355..ad2e347c 100644 --- a/common/dependency-injection/build.gradle.kts +++ b/common/dependency-injection/build.gradle.kts @@ -13,6 +13,7 @@ kotlin { implementation(project(":common:data-models")) implementation(project(":common:database")) implementation(project(":fuzzywuzzy:app")) + implementation("org.jetbrains.kotlinx:atomicfu:0.15.1") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0") implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.1.1") implementation(Ktor.clientCore) @@ -23,7 +24,6 @@ kotlin { // koin api(Koin.core) api(Koin.test) - api(Extras.kermit) } } diff --git a/common/dependency-injection/src/androidMain/kotlin/com/shabinder/common/di/YoutubeProvider.kt b/common/dependency-injection/src/androidMain/kotlin/com/shabinder/common/di/YoutubeProvider.kt index 27854192..20af782b 100644 --- a/common/dependency-injection/src/androidMain/kotlin/com/shabinder/common/di/YoutubeProvider.kt +++ b/common/dependency-injection/src/androidMain/kotlin/com/shabinder/common/di/YoutubeProvider.kt @@ -18,6 +18,7 @@ package com.shabinder.common.di import co.touchlab.kermit.Kermit import com.github.kiulian.downloader.YoutubeDownloader +import com.shabinder.common.di.utils.removeIllegalChars import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.PlatformQueryResult import com.shabinder.common.models.TrackDetails diff --git a/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/Dir.kt b/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/Dir.kt index 8e0b8f08..3b0a3c81 100644 --- a/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/Dir.kt +++ b/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/Dir.kt @@ -2,6 +2,7 @@ package com.shabinder.common.di import co.touchlab.kermit.Kermit import com.shabinder.common.database.createDatabase +import com.shabinder.common.di.utils.removeIllegalChars import com.shabinder.common.models.DownloadResult import com.shabinder.common.models.TrackDetails import com.shabinder.database.Database diff --git a/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/providers/YoutubeMp3.kt b/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/providers/YoutubeMp3.kt index 74a0bfeb..b3d297f8 100644 --- a/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/providers/YoutubeMp3.kt +++ b/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/providers/YoutubeMp3.kt @@ -16,8 +16,8 @@ class YoutubeMp3( private val dir: Dir, ):Yt1sMp3 { suspend fun getMp3DownloadLink(videoID:String):String? = getLinkFromYt1sMp3(videoID)?.let{ - println("Is Self Hosted"+(corsProxy is CorsProxy.SelfHostedCorsProxy)) - if (currentPlatform is AllPlatforms.Js && corsProxy !is CorsProxy.PublicProxyWithExtension) "https://kind-grasshopper-73.telebit.io/cors/$it" + if (currentPlatform is AllPlatforms.Js/* && corsProxy !is CorsProxy.PublicProxyWithExtension*/) + "https://kind-grasshopper-73.telebit.io/cors/$it" else it } } \ No newline at end of file diff --git a/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/providers/YoutubeMusic.kt b/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/providers/YoutubeMusic.kt index a55c9d25..662f2a5c 100644 --- a/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/providers/YoutubeMusic.kt +++ b/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/providers/YoutubeMusic.kt @@ -169,7 +169,7 @@ class YoutubeMusic constructor( } } } - //logger.d(youtubeTracks.joinToString(" abc \n"),tag) + //logger.d {youtubeTracks.joinToString("\n")} return youtubeTracks } @@ -222,7 +222,7 @@ class YoutubeMusic constructor( } if(artistMatchNumber == 0) { - //log("YT Api Removing", result.toString()) + //logger.d{ "YT Api Removing: $result" } continue } diff --git a/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/utils/ParallelExecutor.kt b/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/utils/ParallelExecutor.kt new file mode 100644 index 00000000..d3ba9f2f --- /dev/null +++ b/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/utils/ParallelExecutor.kt @@ -0,0 +1,149 @@ +package com.shabinder.common.di.utils + +// Dependencies: +// implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9") +// implementation("org.jetbrains.kotlinx:atomicfu:0.14.4") +// Gist: https://gist.github.com/fluidsonic/ba32de21c156bbe8424c8d5fc20dcd8e + +import io.ktor.utils.io.core.* +import kotlinx.atomicfu.atomic +import kotlinx.coroutines.* +import kotlinx.coroutines.channels.* +import kotlinx.coroutines.selects.* +import kotlin.coroutines.* + +class ParallelExecutor( + parentContext: CoroutineContext, +) : Closeable { + + private val concurrentOperationLimit = atomic(4) + private val coroutineContext = parentContext + Job() + private var isClosed = atomic(false) + private val killQueue = Channel(Channel.UNLIMITED) + private val operationQueue = Channel>(Channel.RENDEZVOUS) + + + init { + startOrStopProcessors(expectedCount = concurrentOperationLimit.value, actualCount = 0) + } + + + override fun close() { + if (!isClosed.compareAndSet(expect = false, update = true)) + return + + val cause = CancellationException("Executor was closed.") + + killQueue.close(cause) + operationQueue.close(cause) + coroutineContext.cancel(cause) + } + + + private fun CoroutineScope.launchProcessor() = launch { + while (true) { + val operation = select?> { + killQueue.onReceive { null } + operationQueue.onReceive { it } + } ?: break + + operation.execute() + } + } + + + suspend fun execute(block: suspend () -> Result): Result = + withContext(coroutineContext) { + val operation = Operation(block) + operationQueue.send(operation) + + operation.result.await() + } + + + // TODO This launches all coroutines in advance even if they're never needed. Find a lazy way to do this. + fun setConcurrentOperationLimit(limit: Int) { + require(limit >= 1) { "'limit' must be greater than zero: $limit" } + require(limit < 1_000_000) { "Don't use a very high limit because it will cause a lot of coroutines to be started eagerly: $limit" } + + startOrStopProcessors(expectedCount = limit, actualCount = concurrentOperationLimit.getAndSet(limit)) + } + + + private fun startOrStopProcessors(expectedCount: Int, actualCount: Int) { + if (expectedCount == actualCount) + return + + if (isClosed.value) + return + + var change = expectedCount - actualCount + while (change > 0 && killQueue.poll() != null) + change -= 1 + + if (change > 0) + with(CoroutineScope(coroutineContext)) { + repeat(change) { launchProcessor() } + } + else + repeat(-change) { killQueue.offer(Unit) } + } + + + private class Operation( + private val block: suspend () -> Result, + ) { + + private val _result = CompletableDeferred() + + val result: Deferred get() = _result + + + suspend fun execute() { + try { + _result.complete(block()) + } + catch (e: Throwable) { + _result.completeExceptionally(e) + } + } + } +} + +/* +suspend fun main() = coroutineScope { + val executor = ParallelExecutor(coroutineContext) + + println("Concurrency: 1") + + coroutineScope { + (1 .. 200).forEach { i -> + launch { + executor.execute { + println("Execution $i") + delay(250) + + when (i) { + 10 -> { + println("Concurrency: 5") + executor.setConcurrentOperationLimit(5) + } + + 100 -> { + println("Concurrency: 1") + executor.setConcurrentOperationLimit(1) + } + + 110 -> { + println("Closing executor") + executor.close() + } + } + } + } + delay(1) + } + } + + println("Fin.") +}*/ diff --git a/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/Utils.kt b/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/utils/Utils.kt similarity index 96% rename from common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/Utils.kt rename to common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/utils/Utils.kt index cdd47a1d..9f39f67c 100644 --- a/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/Utils.kt +++ b/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/utils/Utils.kt @@ -1,4 +1,4 @@ -package com.shabinder.common.di +package com.shabinder.common.di.utils diff --git a/common/dependency-injection/src/desktopMain/kotlin/com/shabinder/common/di/DesktopActual.kt b/common/dependency-injection/src/desktopMain/kotlin/com/shabinder/common/di/DesktopActual.kt index df6ce47f..f1bb89b6 100644 --- a/common/dependency-injection/src/desktopMain/kotlin/com/shabinder/common/di/DesktopActual.kt +++ b/common/dependency-injection/src/desktopMain/kotlin/com/shabinder/common/di/DesktopActual.kt @@ -4,6 +4,7 @@ import com.github.kiulian.downloader.YoutubeDownloader import com.github.kiulian.downloader.model.YoutubeVideo import com.github.kiulian.downloader.model.formats.Format import com.github.kiulian.downloader.model.quality.AudioQuality +import com.shabinder.common.di.utils.ParallelExecutor import com.shabinder.common.models.AllPlatforms import com.shabinder.common.models.DownloadResult import com.shabinder.common.models.DownloadStatus @@ -58,22 +59,27 @@ actual val isInternetAvailable:Boolean val DownloadProgressFlow: MutableSharedFlow> = MutableSharedFlow(1) +//Scope Allowing 4 Parallel Downloads +val DownloadScope = ParallelExecutor(Dispatchers.IO) + actual suspend fun downloadTracks( list: List, fetcher: FetchPlatformQueryResult, dir: Dir ){ list.forEach { - if (!it.videoID.isNullOrBlank()) {//Video ID already known! - downloadTrack(it.videoID!!, it,dir::saveFileWithMetadata) - } else { - val searchQuery = "${it.title} - ${it.artists.joinToString(",")}" - val videoId = fetcher.youtubeMusic.getYTIDBestMatch(searchQuery,it) - if (videoId.isNullOrBlank()) { - DownloadProgressFlow.emit(DownloadProgressFlow.replayCache.getOrElse(0 - ) { hashMapOf() }.apply { set(it.title,DownloadStatus.Failed) }) - } else {//Found Youtube Video ID - downloadTrack(videoId, it,dir::saveFileWithMetadata) + DownloadScope.execute { // Send Download to Pool. + if (!it.videoID.isNullOrBlank()) {//Video ID already known! + downloadTrack(it.videoID!!, it,dir::saveFileWithMetadata) + } else { + val searchQuery = "${it.title} - ${it.artists.joinToString(",")}" + val videoId = fetcher.youtubeMusic.getYTIDBestMatch(searchQuery,it) + if (videoId.isNullOrBlank()) { + DownloadProgressFlow.emit(DownloadProgressFlow.replayCache.getOrElse(0 + ) { hashMapOf() }.apply { set(it.title,DownloadStatus.Failed) }) + } else {//Found Youtube Video ID + downloadTrack(videoId, it,dir::saveFileWithMetadata) + } } } } diff --git a/common/dependency-injection/src/desktopMain/kotlin/com/shabinder/common/di/YoutubeProvider.kt b/common/dependency-injection/src/desktopMain/kotlin/com/shabinder/common/di/YoutubeProvider.kt index 6a5a0713..015ec158 100644 --- a/common/dependency-injection/src/desktopMain/kotlin/com/shabinder/common/di/YoutubeProvider.kt +++ b/common/dependency-injection/src/desktopMain/kotlin/com/shabinder/common/di/YoutubeProvider.kt @@ -18,6 +18,7 @@ package com.shabinder.common.di import co.touchlab.kermit.Kermit import com.github.kiulian.downloader.YoutubeDownloader +import com.shabinder.common.di.utils.removeIllegalChars import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.PlatformQueryResult import com.shabinder.common.models.TrackDetails diff --git a/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebActual.kt b/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebActual.kt index 255e5087..c35e0d6b 100644 --- a/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebActual.kt +++ b/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebActual.kt @@ -52,6 +52,8 @@ actual val isInternetAvailable:Boolean } val DownloadProgressFlow: MutableSharedFlow> = MutableSharedFlow(1) +//Error:https://github.com/Kotlin/kotlinx.atomicfu/issues/182 +//val DownloadScope = ParallelExecutor(Dispatchers.Default) //Download Pool of 4 parallel val allTracksStatus: HashMap = hashMapOf() actual suspend fun downloadTracks( @@ -59,14 +61,15 @@ actual suspend fun downloadTracks( fetcher: FetchPlatformQueryResult, dir: Dir ){ - withContext(Dispatchers.Default){ - list.forEach { + list.forEach { + withContext(Dispatchers.Default) { allTracksStatus[it.title] = DownloadStatus.Queued if (!it.videoID.isNullOrBlank()) {//Video ID already known! downloadTrack(it.videoID!!, it, fetcher, dir) } else { val searchQuery = "${it.title} - ${it.artists.joinToString(",")}" val videoID = fetcher.youtubeMusic.getYTIDBestMatch(searchQuery,it) + println(videoID+" : "+it.title) if (videoID.isNullOrBlank()) { allTracksStatus[it.title] = DownloadStatus.Failed DownloadProgressFlow.emit(allTracksStatus) @@ -74,8 +77,8 @@ actual suspend fun downloadTracks( downloadTrack(videoID, it, fetcher, dir) } } + DownloadProgressFlow.emit(allTracksStatus) } - DownloadProgressFlow.emit(allTracksStatus) } } diff --git a/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebDir.kt b/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebDir.kt index 90004b11..fdd30d47 100644 --- a/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebDir.kt +++ b/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebDir.kt @@ -2,18 +2,14 @@ package com.shabinder.common.di import co.touchlab.kermit.Kermit import com.shabinder.common.di.gaana.corsApi +import com.shabinder.common.di.utils.removeIllegalChars import com.shabinder.common.models.DownloadResult import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.TrackDetails import com.shabinder.database.Database import kotlinext.js.Object -import kotlinext.js.asJsObject import kotlinext.js.js -import kotlinext.js.jsObject import kotlinx.coroutines.flow.collect -import kotlinx.serialization.json.JsonArray -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.buildJsonObject import org.khronos.webgl.ArrayBuffer import org.w3c.dom.ImageBitmap import org.khronos.webgl.Int8Array @@ -56,7 +52,7 @@ actual class Dir actual constructor( albumArt.collect { when(it){ is DownloadResult.Success -> { - println("Album Art Downloaded Success") + logger.d{"Album Art Downloaded Success"} val albumArtObj = js { this["type"] = 3 this["data"] = it.byteArray.toArrayBuffer() @@ -65,10 +61,10 @@ actual class Dir actual constructor( writeTagsAndSave(writer, albumArtObj as Object,trackDetails) } is DownloadResult.Error -> { - println("Album Art Downloading Error") + logger.d{"Album Art Downloading Error"} writeTagsAndSave(writer,null,trackDetails) } - is DownloadResult.Progress -> println("Album Art Downloading: ${it.progress}") + is DownloadResult.Progress -> logger.d{"Album Art Downloading: ${it.progress}"} } } } @@ -86,8 +82,8 @@ actual class Dir actual constructor( } writer.addTag() allTracksStatus[trackDetails.title] = DownloadStatus.Downloaded - saveAs(writer.getBlob(), "${removeIllegalChars(trackDetails.title)}.mp3") DownloadProgressFlow.emit(allTracksStatus) + saveAs(writer.getBlob(), "${removeIllegalChars(trackDetails.title)}.mp3") } actual fun addToLibrary(path:String){} diff --git a/desktop/src/jvmMain/kotlin/Main.kt b/desktop/src/jvmMain/kotlin/Main.kt index 8c5dd18a..9e21cc5a 100644 --- a/desktop/src/jvmMain/kotlin/Main.kt +++ b/desktop/src/jvmMain/kotlin/Main.kt @@ -21,6 +21,7 @@ import com.shabinder.common.uikit.showPopUpMessage as uikitShowPopUpMessage private val koin = initKoin(enableNetworkLogs = true).koin + fun main(){ val lifecycle = LifecycleRegistry() diff --git a/fuzzywuzzy/app/build.gradle b/fuzzywuzzy/app/build.gradle index 68ee6e7d..0670cba1 100644 --- a/fuzzywuzzy/app/build.gradle +++ b/fuzzywuzzy/app/build.gradle @@ -43,27 +43,12 @@ kotlin { implementation kotlin("stdlib-common") } } - commonTest { - kotlin.srcDir('src/test') - dependencies { - implementation kotlin("test-common") - implementation kotlin("test-annotations-common") - } - } - jvmMain { kotlin.srcDir('src/jvmMain/kotlin') dependencies { implementation kotlin("stdlib") } } - jvmTest { - dependencies { - implementation kotlin("test") - implementation kotlin("test-junit") - implementation 'junit:junit:4.12' - } - } jsMain { kotlin.srcDir('src/jsMain/kotlin') dependencies { @@ -78,12 +63,28 @@ kotlin { kotlinOptions.moduleKind = "umd" } } - /*jsTest { + /* + commonTest { + kotlin.srcDir('src/test') + dependencies { + implementation kotlin("test-common") + implementation kotlin("test-annotations-common") + } + } + jsTest { dependencies { implementation kotlin("test-js") implementation kotlin("stdlib-js") } - }*/ + } + jvmTest { + dependencies { + implementation kotlin("test") + implementation kotlin("test-junit") + implementation 'junit:junit:4.13.2' + } + } + */ /*nativeMain { kotlin.srcDir('src/nativeMain/kotlin') }*/ diff --git a/fuzzywuzzy/gradle/dependencies.gradle b/fuzzywuzzy/gradle/dependencies.gradle index 80012566..51e73b89 100644 --- a/fuzzywuzzy/gradle/dependencies.gradle +++ b/fuzzywuzzy/gradle/dependencies.gradle @@ -1,14 +1,14 @@ ext.versions = [ kotlin : '1.4.30', kotlinCoroutines: '1.4.2', - dokka : '0.9.17', - nodePlugin: '1.2.0' + dokka : '1.4.30', + nodePlugin: '1.3.1' ] ext.deps = [ plugins: [ - android: 'com.android.tools.build:gradle:3.3.0', + android: 'com.android.tools.build:gradle:4.0.2', kotlin : "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}", dokka : "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}", node : "com.moowork.gradle:gradle-node-plugin:${versions.nodePlugin}" ] -] +] \ No newline at end of file diff --git a/web-app/src/main/kotlin/list/DownloadAllButton.kt b/web-app/src/main/kotlin/list/DownloadAllButton.kt index 7ef116ec..0a868a87 100644 --- a/web-app/src/main/kotlin/list/DownloadAllButton.kt +++ b/web-app/src/main/kotlin/list/DownloadAllButton.kt @@ -48,7 +48,7 @@ private val downloadAllButton = functionalComponent("Dow styledDiv { attrs { onClickFunction = { - //props.downloadAll() + props.downloadAll() setClicked(true) } } diff --git a/web-app/src/main/kotlin/list/TrackItem.kt b/web-app/src/main/kotlin/list/TrackItem.kt index 587b9789..148ec058 100644 --- a/web-app/src/main/kotlin/list/TrackItem.kt +++ b/web-app/src/main/kotlin/list/TrackItem.kt @@ -106,29 +106,31 @@ private val trackItem = functionalComponent("Track-Item"){ props status = downloadStatus } } - is DownloadStatus.Downloading -> { + //TODO Fix Progress Indicator + /*is DownloadStatus.Downloading -> { CircularProgressBar { progress = downloadStatus.progress } } - DownloadStatus.Queued -> { + is DownloadStatus.Converting -> { LoadingSpinner {} } - DownloadStatus.Downloaded -> { + is DownloadStatus.Queued -> { + LoadingSpinner {} + }*/ + is DownloadStatus.Downloaded -> { DownloadButton { onClick = {} status = downloadStatus } } - DownloadStatus.Converting -> { - LoadingSpinner {} - } - DownloadStatus.Failed -> { + is DownloadStatus.Failed -> { DownloadButton { onClick = {} status = downloadStatus } } + else -> LoadingSpinner { } } css { diff --git a/web-app/src/main/resources/header-dark.jpg b/web-app/src/main/resources/header-dark.jpg old mode 100644 new mode 100755