mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-12-22 12:47:54 +01:00
splash state and project build fixes
This commit is contained in:
parent
cf9ed5e885
commit
b330b0732f
@ -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() {
|
||||
|
@ -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<ImageBitmap?>(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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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<ImageBitmap?>(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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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<Unit>(Channel.UNLIMITED)
|
||||
private val operationQueue = Channel<Operation<*>>(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<Operation<*>?> {
|
||||
killQueue.onReceive { null }
|
||||
operationQueue.onReceive { it }
|
||||
} ?: break
|
||||
|
||||
operation.execute()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
suspend fun <Result> 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<Result>(
|
||||
private val block: suspend () -> Result,
|
||||
) {
|
||||
|
||||
private val _result = CompletableDeferred<Result>()
|
||||
|
||||
val result: Deferred<Result> 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.")
|
||||
}*/
|
@ -1,4 +1,4 @@
|
||||
package com.shabinder.common.di
|
||||
package com.shabinder.common.di.utils
|
||||
|
||||
|
||||
|
@ -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<HashMap<String,DownloadStatus>> = MutableSharedFlow(1)
|
||||
|
||||
//Scope Allowing 4 Parallel Downloads
|
||||
val DownloadScope = ParallelExecutor(Dispatchers.IO)
|
||||
|
||||
actual suspend fun downloadTracks(
|
||||
list: List<TrackDetails>,
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -52,6 +52,8 @@ actual val isInternetAvailable:Boolean
|
||||
}
|
||||
|
||||
val DownloadProgressFlow: MutableSharedFlow<HashMap<String, DownloadStatus>> = MutableSharedFlow(1)
|
||||
//Error:https://github.com/Kotlin/kotlinx.atomicfu/issues/182
|
||||
//val DownloadScope = ParallelExecutor(Dispatchers.Default) //Download Pool of 4 parallel
|
||||
val allTracksStatus: HashMap<String, DownloadStatus> = 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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){}
|
||||
|
@ -21,6 +21,7 @@ import com.shabinder.common.uikit.showPopUpMessage as uikitShowPopUpMessage
|
||||
|
||||
private val koin = initKoin(enableNetworkLogs = true).koin
|
||||
|
||||
|
||||
fun main(){
|
||||
|
||||
val lifecycle = LifecycleRegistry()
|
||||
|
@ -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')
|
||||
}*/
|
||||
|
@ -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}"
|
||||
]
|
||||
]
|
||||
]
|
@ -48,7 +48,7 @@ private val downloadAllButton = functionalComponent<DownloadAllButtonProps>("Dow
|
||||
styledDiv {
|
||||
attrs {
|
||||
onClickFunction = {
|
||||
//props.downloadAll()
|
||||
props.downloadAll()
|
||||
setClicked(true)
|
||||
}
|
||||
}
|
||||
|
@ -106,29 +106,31 @@ private val trackItem = functionalComponent<TrackItemProps>("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 {
|
||||
|
0
web-app/src/main/resources/header-dark.jpg
Normal file → Executable file
0
web-app/src/main/resources/header-dark.jpg
Normal file → Executable file
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
Loading…
Reference in New Issue
Block a user