splash state and project build fixes

This commit is contained in:
shabinder 2021-03-18 06:29:29 +05:30
parent cf9ed5e885
commit b330b0732f
22 changed files with 245 additions and 68 deletions

View File

@ -22,7 +22,7 @@ import com.shabinder.common.di.initKoin
import com.shabinder.spotiflyer.di.appModule import com.shabinder.spotiflyer.di.appModule
import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger import org.koin.android.ext.koin.androidLogger
import org.koin.core.KoinComponent import org.koin.core.component.KoinComponent
class App: Application(), KoinComponent { class App: Application(), KoinComponent {
override fun onCreate() { override fun onCreate() {

View File

@ -22,7 +22,13 @@ import com.shabinder.common.di.dispatcherIO
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@Composable @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) } var pic by remember(link) { mutableStateOf<ImageBitmap?>(null) }
LaunchedEffect(link){ LaunchedEffect(link){
withContext(dispatcherIO) { withContext(dispatcherIO) {
@ -31,7 +37,7 @@ actual fun ImageLoad(link:String, loader:suspend (String) -> Picture, desc: Stri
} }
Crossfade(pic){ 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)
} }
} }

View File

@ -12,7 +12,7 @@ expect fun ImageLoad(
loader:suspend (String) ->Picture, loader:suspend (String) ->Picture,
desc: String = "Album Art", desc: String = "Album Art",
modifier:Modifier = Modifier, modifier:Modifier = Modifier,
placeholder:ImageVector = PlaceHolderImage() //placeholder:ImageVector = PlaceHolderImage()
) )
@Composable @Composable

View File

@ -25,6 +25,8 @@ import com.shabinder.common.uikit.splash.Splash
import com.shabinder.common.uikit.splash.SplashState import com.shabinder.common.uikit.splash.SplashState
import com.shabinder.common.uikit.utils.verticalGradientScrim import com.shabinder.common.uikit.utils.verticalGradientScrim
private var isSplashShown = SplashState.Shown
@Composable @Composable
fun SpotiFlyerRootContent(component: SpotiFlyerRoot, statusBarHeight:Dp = 0.dp): SpotiFlyerRoot { 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( val splashAlpha by transition.animateFloat(
transitionSpec = { tween(durationMillis = 100) } 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( val contentAlpha by transition.animateFloat(
transitionSpec = { tween(durationMillis = 300) } 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( val contentTopPadding by transition.animateDp(
transitionSpec = { spring(stiffness = StiffnessLow) } 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{ Box{
Splash( Splash(
modifier = Modifier.alpha(splashAlpha), modifier = Modifier.alpha(splashAlpha),
onTimeout = { transitionState.targetState = SplashState.Completed } onTimeout = {
transitionState.targetState = SplashState.Completed
isSplashShown = SplashState.Completed
}
) )
MainScreen( MainScreen(
Modifier.alpha(contentAlpha), Modifier.alpha(contentAlpha),

View File

@ -16,9 +16,14 @@ import com.shabinder.common.di.Picture
import com.shabinder.common.di.dispatcherIO import com.shabinder.common.di.dispatcherIO
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@Composable @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) } var pic by remember(link) { mutableStateOf<ImageBitmap?>(null) }
LaunchedEffect(link){ LaunchedEffect(link){
withContext(dispatcherIO) { withContext(dispatcherIO) {
@ -27,7 +32,7 @@ actual fun ImageLoad(link:String, loader:suspend (String) -> Picture, desc: Stri
} }
Crossfade(pic){ 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)
} }
} }

View File

@ -13,6 +13,7 @@ kotlin {
implementation(project(":common:data-models")) implementation(project(":common:data-models"))
implementation(project(":common:database")) implementation(project(":common:database"))
implementation(project(":fuzzywuzzy:app")) 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-serialization-json:1.1.0")
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.1.1") implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.1.1")
implementation(Ktor.clientCore) implementation(Ktor.clientCore)
@ -23,7 +24,6 @@ kotlin {
// koin // koin
api(Koin.core) api(Koin.core)
api(Koin.test) api(Koin.test)
api(Extras.kermit) api(Extras.kermit)
} }
} }

View File

@ -18,6 +18,7 @@ package com.shabinder.common.di
import co.touchlab.kermit.Kermit import co.touchlab.kermit.Kermit
import com.github.kiulian.downloader.YoutubeDownloader import com.github.kiulian.downloader.YoutubeDownloader
import com.shabinder.common.di.utils.removeIllegalChars
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.PlatformQueryResult import com.shabinder.common.models.PlatformQueryResult
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails

View File

@ -2,6 +2,7 @@ package com.shabinder.common.di
import co.touchlab.kermit.Kermit import co.touchlab.kermit.Kermit
import com.shabinder.common.database.createDatabase import com.shabinder.common.database.createDatabase
import com.shabinder.common.di.utils.removeIllegalChars
import com.shabinder.common.models.DownloadResult import com.shabinder.common.models.DownloadResult
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.database.Database import com.shabinder.database.Database

View File

@ -16,8 +16,8 @@ class YoutubeMp3(
private val dir: Dir, private val dir: Dir,
):Yt1sMp3 { ):Yt1sMp3 {
suspend fun getMp3DownloadLink(videoID:String):String? = getLinkFromYt1sMp3(videoID)?.let{ 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*/)
if (currentPlatform is AllPlatforms.Js && corsProxy !is CorsProxy.PublicProxyWithExtension) "https://kind-grasshopper-73.telebit.io/cors/$it" "https://kind-grasshopper-73.telebit.io/cors/$it"
else it else it
} }
} }

View File

@ -169,7 +169,7 @@ class YoutubeMusic constructor(
} }
} }
} }
//logger.d(youtubeTracks.joinToString(" abc \n"),tag) //logger.d {youtubeTracks.joinToString("\n")}
return youtubeTracks return youtubeTracks
} }
@ -222,7 +222,7 @@ class YoutubeMusic constructor(
} }
if(artistMatchNumber == 0) { if(artistMatchNumber == 0) {
//log("YT Api Removing", result.toString()) //logger.d{ "YT Api Removing: $result" }
continue continue
} }

View File

@ -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.")
}*/

View File

@ -4,6 +4,7 @@ import com.github.kiulian.downloader.YoutubeDownloader
import com.github.kiulian.downloader.model.YoutubeVideo import com.github.kiulian.downloader.model.YoutubeVideo
import com.github.kiulian.downloader.model.formats.Format import com.github.kiulian.downloader.model.formats.Format
import com.github.kiulian.downloader.model.quality.AudioQuality 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.AllPlatforms
import com.shabinder.common.models.DownloadResult import com.shabinder.common.models.DownloadResult
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
@ -58,22 +59,27 @@ actual val isInternetAvailable:Boolean
val DownloadProgressFlow: MutableSharedFlow<HashMap<String,DownloadStatus>> = MutableSharedFlow(1) val DownloadProgressFlow: MutableSharedFlow<HashMap<String,DownloadStatus>> = MutableSharedFlow(1)
//Scope Allowing 4 Parallel Downloads
val DownloadScope = ParallelExecutor(Dispatchers.IO)
actual suspend fun downloadTracks( actual suspend fun downloadTracks(
list: List<TrackDetails>, list: List<TrackDetails>,
fetcher: FetchPlatformQueryResult, fetcher: FetchPlatformQueryResult,
dir: Dir dir: Dir
){ ){
list.forEach { list.forEach {
if (!it.videoID.isNullOrBlank()) {//Video ID already known! DownloadScope.execute { // Send Download to Pool.
downloadTrack(it.videoID!!, it,dir::saveFileWithMetadata) if (!it.videoID.isNullOrBlank()) {//Video ID already known!
} else { downloadTrack(it.videoID!!, it,dir::saveFileWithMetadata)
val searchQuery = "${it.title} - ${it.artists.joinToString(",")}" } else {
val videoId = fetcher.youtubeMusic.getYTIDBestMatch(searchQuery,it) val searchQuery = "${it.title} - ${it.artists.joinToString(",")}"
if (videoId.isNullOrBlank()) { val videoId = fetcher.youtubeMusic.getYTIDBestMatch(searchQuery,it)
DownloadProgressFlow.emit(DownloadProgressFlow.replayCache.getOrElse(0 if (videoId.isNullOrBlank()) {
) { hashMapOf() }.apply { set(it.title,DownloadStatus.Failed) }) DownloadProgressFlow.emit(DownloadProgressFlow.replayCache.getOrElse(0
} else {//Found Youtube Video ID ) { hashMapOf() }.apply { set(it.title,DownloadStatus.Failed) })
downloadTrack(videoId, it,dir::saveFileWithMetadata) } else {//Found Youtube Video ID
downloadTrack(videoId, it,dir::saveFileWithMetadata)
}
} }
} }
} }

View File

@ -18,6 +18,7 @@ package com.shabinder.common.di
import co.touchlab.kermit.Kermit import co.touchlab.kermit.Kermit
import com.github.kiulian.downloader.YoutubeDownloader import com.github.kiulian.downloader.YoutubeDownloader
import com.shabinder.common.di.utils.removeIllegalChars
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.PlatformQueryResult import com.shabinder.common.models.PlatformQueryResult
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails

View File

@ -52,6 +52,8 @@ actual val isInternetAvailable:Boolean
} }
val DownloadProgressFlow: MutableSharedFlow<HashMap<String, DownloadStatus>> = MutableSharedFlow(1) 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() val allTracksStatus: HashMap<String, DownloadStatus> = hashMapOf()
actual suspend fun downloadTracks( actual suspend fun downloadTracks(
@ -59,14 +61,15 @@ actual suspend fun downloadTracks(
fetcher: FetchPlatformQueryResult, fetcher: FetchPlatformQueryResult,
dir: Dir dir: Dir
){ ){
withContext(Dispatchers.Default){ list.forEach {
list.forEach { withContext(Dispatchers.Default) {
allTracksStatus[it.title] = DownloadStatus.Queued allTracksStatus[it.title] = DownloadStatus.Queued
if (!it.videoID.isNullOrBlank()) {//Video ID already known! if (!it.videoID.isNullOrBlank()) {//Video ID already known!
downloadTrack(it.videoID!!, it, fetcher, dir) downloadTrack(it.videoID!!, it, fetcher, dir)
} else { } else {
val searchQuery = "${it.title} - ${it.artists.joinToString(",")}" val searchQuery = "${it.title} - ${it.artists.joinToString(",")}"
val videoID = fetcher.youtubeMusic.getYTIDBestMatch(searchQuery,it) val videoID = fetcher.youtubeMusic.getYTIDBestMatch(searchQuery,it)
println(videoID+" : "+it.title)
if (videoID.isNullOrBlank()) { if (videoID.isNullOrBlank()) {
allTracksStatus[it.title] = DownloadStatus.Failed allTracksStatus[it.title] = DownloadStatus.Failed
DownloadProgressFlow.emit(allTracksStatus) DownloadProgressFlow.emit(allTracksStatus)
@ -74,8 +77,8 @@ actual suspend fun downloadTracks(
downloadTrack(videoID, it, fetcher, dir) downloadTrack(videoID, it, fetcher, dir)
} }
} }
DownloadProgressFlow.emit(allTracksStatus)
} }
DownloadProgressFlow.emit(allTracksStatus)
} }
} }

View File

@ -2,18 +2,14 @@ package com.shabinder.common.di
import co.touchlab.kermit.Kermit import co.touchlab.kermit.Kermit
import com.shabinder.common.di.gaana.corsApi 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.DownloadResult
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.database.Database import com.shabinder.database.Database
import kotlinext.js.Object import kotlinext.js.Object
import kotlinext.js.asJsObject
import kotlinext.js.js import kotlinext.js.js
import kotlinext.js.jsObject
import kotlinx.coroutines.flow.collect 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.khronos.webgl.ArrayBuffer
import org.w3c.dom.ImageBitmap import org.w3c.dom.ImageBitmap
import org.khronos.webgl.Int8Array import org.khronos.webgl.Int8Array
@ -56,7 +52,7 @@ actual class Dir actual constructor(
albumArt.collect { albumArt.collect {
when(it){ when(it){
is DownloadResult.Success -> { is DownloadResult.Success -> {
println("Album Art Downloaded Success") logger.d{"Album Art Downloaded Success"}
val albumArtObj = js { val albumArtObj = js {
this["type"] = 3 this["type"] = 3
this["data"] = it.byteArray.toArrayBuffer() this["data"] = it.byteArray.toArrayBuffer()
@ -65,10 +61,10 @@ actual class Dir actual constructor(
writeTagsAndSave(writer, albumArtObj as Object,trackDetails) writeTagsAndSave(writer, albumArtObj as Object,trackDetails)
} }
is DownloadResult.Error -> { is DownloadResult.Error -> {
println("Album Art Downloading Error") logger.d{"Album Art Downloading Error"}
writeTagsAndSave(writer,null,trackDetails) 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() writer.addTag()
allTracksStatus[trackDetails.title] = DownloadStatus.Downloaded allTracksStatus[trackDetails.title] = DownloadStatus.Downloaded
saveAs(writer.getBlob(), "${removeIllegalChars(trackDetails.title)}.mp3")
DownloadProgressFlow.emit(allTracksStatus) DownloadProgressFlow.emit(allTracksStatus)
saveAs(writer.getBlob(), "${removeIllegalChars(trackDetails.title)}.mp3")
} }
actual fun addToLibrary(path:String){} actual fun addToLibrary(path:String){}

View File

@ -21,6 +21,7 @@ import com.shabinder.common.uikit.showPopUpMessage as uikitShowPopUpMessage
private val koin = initKoin(enableNetworkLogs = true).koin private val koin = initKoin(enableNetworkLogs = true).koin
fun main(){ fun main(){
val lifecycle = LifecycleRegistry() val lifecycle = LifecycleRegistry()

View File

@ -43,27 +43,12 @@ kotlin {
implementation kotlin("stdlib-common") implementation kotlin("stdlib-common")
} }
} }
commonTest {
kotlin.srcDir('src/test')
dependencies {
implementation kotlin("test-common")
implementation kotlin("test-annotations-common")
}
}
jvmMain { jvmMain {
kotlin.srcDir('src/jvmMain/kotlin') kotlin.srcDir('src/jvmMain/kotlin')
dependencies { dependencies {
implementation kotlin("stdlib") implementation kotlin("stdlib")
} }
} }
jvmTest {
dependencies {
implementation kotlin("test")
implementation kotlin("test-junit")
implementation 'junit:junit:4.12'
}
}
jsMain { jsMain {
kotlin.srcDir('src/jsMain/kotlin') kotlin.srcDir('src/jsMain/kotlin')
dependencies { dependencies {
@ -78,12 +63,28 @@ kotlin {
kotlinOptions.moduleKind = "umd" kotlinOptions.moduleKind = "umd"
} }
} }
/*jsTest { /*
commonTest {
kotlin.srcDir('src/test')
dependencies {
implementation kotlin("test-common")
implementation kotlin("test-annotations-common")
}
}
jsTest {
dependencies { dependencies {
implementation kotlin("test-js") implementation kotlin("test-js")
implementation kotlin("stdlib-js") implementation kotlin("stdlib-js")
} }
}*/ }
jvmTest {
dependencies {
implementation kotlin("test")
implementation kotlin("test-junit")
implementation 'junit:junit:4.13.2'
}
}
*/
/*nativeMain { /*nativeMain {
kotlin.srcDir('src/nativeMain/kotlin') kotlin.srcDir('src/nativeMain/kotlin')
}*/ }*/

View File

@ -1,14 +1,14 @@
ext.versions = [ ext.versions = [
kotlin : '1.4.30', kotlin : '1.4.30',
kotlinCoroutines: '1.4.2', kotlinCoroutines: '1.4.2',
dokka : '0.9.17', dokka : '1.4.30',
nodePlugin: '1.2.0' nodePlugin: '1.3.1'
] ]
ext.deps = [ ext.deps = [
plugins: [ 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}", kotlin : "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}",
dokka : "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}", dokka : "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}",
node : "com.moowork.gradle:gradle-node-plugin:${versions.nodePlugin}" node : "com.moowork.gradle:gradle-node-plugin:${versions.nodePlugin}"
] ]
] ]

View File

@ -48,7 +48,7 @@ private val downloadAllButton = functionalComponent<DownloadAllButtonProps>("Dow
styledDiv { styledDiv {
attrs { attrs {
onClickFunction = { onClickFunction = {
//props.downloadAll() props.downloadAll()
setClicked(true) setClicked(true)
} }
} }

View File

@ -106,29 +106,31 @@ private val trackItem = functionalComponent<TrackItemProps>("Track-Item"){ props
status = downloadStatus status = downloadStatus
} }
} }
is DownloadStatus.Downloading -> { //TODO Fix Progress Indicator
/*is DownloadStatus.Downloading -> {
CircularProgressBar { CircularProgressBar {
progress = downloadStatus.progress progress = downloadStatus.progress
} }
} }
DownloadStatus.Queued -> { is DownloadStatus.Converting -> {
LoadingSpinner {} LoadingSpinner {}
} }
DownloadStatus.Downloaded -> { is DownloadStatus.Queued -> {
LoadingSpinner {}
}*/
is DownloadStatus.Downloaded -> {
DownloadButton { DownloadButton {
onClick = {} onClick = {}
status = downloadStatus status = downloadStatus
} }
} }
DownloadStatus.Converting -> { is DownloadStatus.Failed -> {
LoadingSpinner {}
}
DownloadStatus.Failed -> {
DownloadButton { DownloadButton {
onClick = {} onClick = {}
status = downloadStatus status = downloadStatus
} }
} }
else -> LoadingSpinner { }
} }
css { css {

0
web-app/src/main/resources/header-dark.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB