TrackList Ui Fix

This commit is contained in:
shabinder 2021-02-21 19:51:43 +05:30
parent 50fa91fbca
commit 80e6ecf1f3
13 changed files with 118 additions and 54 deletions

View File

@ -19,6 +19,7 @@ import com.shabinder.android.utils.requestStoragePermission
import com.shabinder.common.di.Dir import com.shabinder.common.di.Dir
import com.shabinder.common.di.FetchPlatformQueryResult import com.shabinder.common.di.FetchPlatformQueryResult
import com.shabinder.common.di.createDirectories import com.shabinder.common.di.createDirectories
import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.root.SpotiFlyerRoot import com.shabinder.common.root.SpotiFlyerRoot
import com.shabinder.common.root.SpotiFlyerRootContent import com.shabinder.common.root.SpotiFlyerRootContent
import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks
@ -26,6 +27,8 @@ import com.shabinder.common.ui.SpotiFlyerTheme
import com.shabinder.common.ui.colorOffWhite import com.shabinder.common.ui.colorOffWhite
import com.shabinder.database.Database import com.shabinder.database.Database
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
const val disableDozeCode = 1223 const val disableDozeCode = 1223
@ -38,6 +41,9 @@ class MainActivity : ComponentActivity() {
private lateinit var root: SpotiFlyerRoot private lateinit var root: SpotiFlyerRoot
private val callBacks: SpotiFlyerRootCallBacks private val callBacks: SpotiFlyerRootCallBacks
get() = root.callBacks get() = root.callBacks
//TODO pass updates from Foreground Service
private val downloadFlow = MutableStateFlow(hashMapOf<String, DownloadStatus>())
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -66,6 +72,7 @@ class MainActivity : ComponentActivity() {
override val database = this@MainActivity.database override val database = this@MainActivity.database
override val fetchPlatformQueryResult = this@MainActivity.fetcher override val fetchPlatformQueryResult = this@MainActivity.fetcher
override val directories: Dir = this@MainActivity.dir override val directories: Dir = this@MainActivity.dir
override val downloadProgressReport: StateFlow<HashMap<String, DownloadStatus>> = downloadFlow
} }
) )

View File

@ -1,16 +1,20 @@
package com.shabinder.common.list package com.shabinder.common.list
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.ImageBitmap
import com.arkivanov.decompose.ComponentContext import com.arkivanov.decompose.ComponentContext
import com.arkivanov.mvikotlin.core.store.StoreFactory import com.arkivanov.mvikotlin.core.store.StoreFactory
import com.shabinder.common.di.Dir import com.shabinder.common.di.Dir
import com.shabinder.common.di.FetchPlatformQueryResult import com.shabinder.common.di.FetchPlatformQueryResult
import com.shabinder.common.list.integration.SpotiFlyerListImpl import com.shabinder.common.list.integration.SpotiFlyerListImpl
import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.spotify.Source import com.shabinder.common.models.spotify.Source
import com.shabinder.common.utils.Consumer import com.shabinder.common.utils.Consumer
import com.shabinder.common.models.PlatformQueryResult import com.shabinder.common.models.PlatformQueryResult
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
interface SpotiFlyerList { interface SpotiFlyerList {
@ -20,10 +24,11 @@ interface SpotiFlyerList {
* Download All Tracks(after filtering already Downloaded) * Download All Tracks(after filtering already Downloaded)
* */ * */
fun onDownloadAllClicked(trackList:List<TrackDetails>) fun onDownloadAllClicked(trackList:List<TrackDetails>)
/* /*
* Download All Tracks(after filtering already Downloaded) * Download All Tracks(after filtering already Downloaded)
* */ * */
fun onDownloadClicked(wholeTrackList:List<TrackDetails>, trackIndex:Int) fun onDownloadClicked(track:TrackDetails)
/* /*
* To Pop and return back to Main Screen * To Pop and return back to Main Screen
@ -41,6 +46,7 @@ interface SpotiFlyerList {
val dir: Dir val dir: Dir
val link: String val link: String
val listOutput: Consumer<Output> val listOutput: Consumer<Output>
val downloadProgressFlow: StateFlow<HashMap<String,DownloadStatus>>
} }
sealed class Output { sealed class Output {
object Finished : Output() object Finished : Output()
@ -50,7 +56,8 @@ interface SpotiFlyerList {
"","", "","",
"Loading","", emptyList(), "Loading","", emptyList(),
Source.Spotify), Source.Spotify),
val link:String = "" val link:String = "",
val trackList:SnapshotStateList<TrackDetails> = mutableStateListOf()
) )
} }

View File

@ -23,6 +23,7 @@ import com.shabinder.common.ui.colorAccent
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.channelFlow import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -32,6 +33,7 @@ fun SpotiFlyerListContent(
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val model by component.models.collectAsState(SpotiFlyerList.State()) val model by component.models.collectAsState(SpotiFlyerList.State())
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
Box(modifier = modifier.fillMaxSize()) { Box(modifier = modifier.fillMaxSize()) {
@ -44,10 +46,10 @@ fun SpotiFlyerListContent(
item { item {
CoverImage(result.title, result.coverUrl, coroutineScope,component::loadImage) CoverImage(result.title, result.coverUrl, coroutineScope,component::loadImage)
} }
itemsIndexed(result.trackList) { index, item -> itemsIndexed(model.trackList) { index, item ->
TrackCard( TrackCard(
track = item, track = item,
downloadTrack = { component.onDownloadClicked(result.trackList,index) }, downloadTrack = { component.onDownloadClicked(item) },
loadImage = component::loadImage loadImage = component::loadImage
) )
} }
@ -88,22 +90,22 @@ fun TrackCard(
} }
} }
when(track.downloaded){ when(track.downloaded){
DownloadStatus.Downloaded -> { is DownloadStatus.Downloaded -> {
DownloadImageTick() DownloadImageTick()
} }
DownloadStatus.Queued -> { is DownloadStatus.Queued -> {
CircularProgressIndicator() CircularProgressIndicator()
} }
DownloadStatus.Failed -> { is DownloadStatus.Failed -> {
DownloadImageError() DownloadImageError()
} }
DownloadStatus.Downloading -> { is DownloadStatus.Downloading -> {
CircularProgressIndicator(progress = track.progress.toFloat()/100f) CircularProgressIndicator(progress = (track.downloaded as DownloadStatus.Downloading).progress.toFloat()/100f)
} }
DownloadStatus.Converting -> { is DownloadStatus.Converting -> {
CircularProgressIndicator(progress = 100f,color = colorAccent) CircularProgressIndicator(progress = 100f,color = colorAccent)
} }
DownloadStatus.NotDownloaded -> { is DownloadStatus.NotDownloaded -> {
DownloadImageArrow(Modifier.clickable(onClick = { DownloadImageArrow(Modifier.clickable(onClick = {
downloadTrack() downloadTrack()
})) }))

View File

@ -23,7 +23,8 @@ internal class SpotiFlyerListImpl(
dir = this.dir, dir = this.dir,
storeFactory = storeFactory, storeFactory = storeFactory,
fetchQuery = fetchQuery, fetchQuery = fetchQuery,
link = link link = link,
downloadProgressFlow = downloadProgressFlow
).provide() ).provide()
} }
@ -33,8 +34,8 @@ internal class SpotiFlyerListImpl(
store.accept(Intent.StartDownloadAll(trackList)) store.accept(Intent.StartDownloadAll(trackList))
} }
override fun onDownloadClicked(wholeTrackList: List<TrackDetails>, trackIndex: Int) { override fun onDownloadClicked(track:TrackDetails) {
store.accept(Intent.StartDownload(wholeTrackList,trackIndex)) store.accept(Intent.StartDownload(track))
} }
override fun onBackPressed(){ override fun onBackPressed(){

View File

@ -7,8 +7,8 @@ import com.shabinder.common.list.store.SpotiFlyerListStore.*
internal interface SpotiFlyerListStore: Store<Intent, State, Nothing> { internal interface SpotiFlyerListStore: Store<Intent, State, Nothing> {
sealed class Intent { sealed class Intent {
data class StartDownloadAll(val trackList: List<TrackDetails>): Intent()
data class StartDownload(val wholeTrackList: List<TrackDetails>, val trackIndex:Int): Intent()
data class SearchLink(val link: String): Intent() data class SearchLink(val link: String): Intent()
data class StartDownload(val track:TrackDetails): Intent()
data class StartDownloadAll(val trackList: List<TrackDetails>): Intent()
} }
} }

View File

@ -1,5 +1,7 @@
package com.shabinder.common.list.store package com.shabinder.common.list.store
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.snapshots.SnapshotStateList
import com.arkivanov.mvikotlin.core.store.* import com.arkivanov.mvikotlin.core.store.*
import com.arkivanov.mvikotlin.extensions.coroutines.SuspendExecutor import com.arkivanov.mvikotlin.extensions.coroutines.SuspendExecutor
import com.shabinder.common.di.Dir import com.shabinder.common.di.Dir
@ -11,12 +13,15 @@ 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
import com.shabinder.common.ui.showPopUpMessage import com.shabinder.common.ui.showPopUpMessage
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collectLatest
internal class SpotiFlyerListStoreProvider( internal class SpotiFlyerListStoreProvider(
private val dir: Dir, private val dir: Dir,
private val storeFactory: StoreFactory, private val storeFactory: StoreFactory,
private val fetchQuery: FetchPlatformQueryResult, private val fetchQuery: FetchPlatformQueryResult,
private val link: String private val link: String,
private val downloadProgressFlow: StateFlow<HashMap<String, DownloadStatus>>
) { ) {
fun provide(): SpotiFlyerListStore = fun provide(): SpotiFlyerListStore =
object : SpotiFlyerListStore, Store<Intent, State, Nothing> by storeFactory.create( object : SpotiFlyerListStore, Store<Intent, State, Nothing> by storeFactory.create(
@ -28,23 +33,29 @@ internal class SpotiFlyerListStoreProvider(
) {} ) {}
private sealed class Result { private sealed class Result {
data class ResultFetched(val result: PlatformQueryResult) : Result() data class ResultFetched(val result: PlatformQueryResult,val trackList: SnapshotStateList<TrackDetails>) : Result()
data class SearchLink(val link: String) : Result() data class UpdateTrackList(val list:SnapshotStateList<TrackDetails>): Result()
data class UpdateTrackList(val list:List<TrackDetails>): Result() data class UpdateTrackItem(val item:TrackDetails): Result()
} }
private inner class ExecutorImpl : SuspendExecutor<Intent, Unit, State, Result, Nothing>() { private inner class ExecutorImpl : SuspendExecutor<Intent, Unit, State, Result, Nothing>() {
override suspend fun executeAction(action: Unit, getState: () -> State) { override suspend fun executeAction(action: Unit, getState: () -> State) {
fetchQuery.query(link)?.let{ executeIntent(Intent.SearchLink(link),getState)
dispatch(Result.ResultFetched(it))
downloadProgressFlow.collectLatest { map ->
val updatedTrackList = getState().trackList.updateTracksStatuses(map)
if(updatedTrackList.isNotEmpty()) dispatch(Result.UpdateTrackList(updatedTrackList))
} }
} }
override suspend fun executeIntent(intent: Intent, getState: () -> State) { override suspend fun executeIntent(intent: Intent, getState: () -> State) {
when (intent) {//TODO: Add Dispatchers where needed when (intent) {
is Intent.SearchLink -> fetchQuery.query(link)?.let{ is Intent.SearchLink -> fetchQuery.query(link)?.let{ result ->
dispatch((Result.ResultFetched(it))) result.trackList = result.trackList.toMutableList()
dispatch((Result.ResultFetched(result,result.trackList.toMutableList().updateTracksStatuses(downloadProgressFlow.value))))
} }
is Intent.StartDownloadAll -> { is Intent.StartDownloadAll -> {
val finalList = val finalList =
intent.trackList.filter { it.downloaded == DownloadStatus.NotDownloaded } intent.trackList.filter { it.downloaded == DownloadStatus.NotDownloaded }
@ -57,17 +68,11 @@ internal class SpotiFlyerListStoreProvider(
} }
it it
} }
dispatch(Result.UpdateTrackList(list)) dispatch(Result.UpdateTrackList(list.toMutableList().updateTracksStatuses(downloadProgressFlow.value)))
}
is Intent.StartDownload -> {
val trackList = intent.wholeTrackList.toMutableList()
val track = trackList.getOrNull(intent.trackIndex)
?.apply { downloaded = DownloadStatus.Queued }
track?.let {
trackList[intent.trackIndex] = it
dispatch(Result.UpdateTrackList(trackList))
} }
is Intent.StartDownload -> {
dispatch(Result.UpdateTrackItem(intent.track.apply { downloaded = DownloadStatus.Queued }))
} }
} }
} }
@ -76,9 +81,31 @@ internal class SpotiFlyerListStoreProvider(
private object ReducerImpl : Reducer<State, Result> { private object ReducerImpl : Reducer<State, Result> {
override fun State.reduce(result: Result): State = override fun State.reduce(result: Result): State =
when (result) { when (result) {
is Result.ResultFetched -> copy(queryResult = result.result) is Result.ResultFetched -> copy(queryResult = result.result, trackList = result.trackList ,link = link)
is Result.SearchLink -> copy(link = result.link) is Result.UpdateTrackList -> copy(trackList = result.list)
is Result.UpdateTrackList -> copy(queryResult = this.queryResult?.apply { trackList = result.list }) is Result.UpdateTrackItem -> updateTrackItem(result.item)
}
private fun State.updateTrackItem(item: TrackDetails):State{
val position = this.trackList.map { it.title }.indexOf(item.title)
if(position != -1){
return copy(trackList = trackList.apply { set(position,item) })
}
return this
} }
} }
} }
private fun MutableList<TrackDetails>.updateTracksStatuses(map:HashMap<String,DownloadStatus>):SnapshotStateList<TrackDetails>{
val titleList = this.map { it.title }
val newStateList = mutableStateListOf<TrackDetails>()
for(newTrack in map){
titleList.indexOf(newTrack.key).let { position ->
this.getOrNull(position)?.apply { downloaded = newTrack.value }?.also { updatedTrack ->
this[position] = updatedTrack
}
}
}
newStateList.addAll(this)
return newStateList
}

View File

@ -8,11 +8,13 @@ import com.shabinder.common.di.Dir
import com.shabinder.common.di.FetchPlatformQueryResult import com.shabinder.common.di.FetchPlatformQueryResult
import com.shabinder.common.list.SpotiFlyerList import com.shabinder.common.list.SpotiFlyerList
import com.shabinder.common.main.SpotiFlyerMain import com.shabinder.common.main.SpotiFlyerMain
import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.root.SpotiFlyerRoot.Dependencies import com.shabinder.common.root.SpotiFlyerRoot.Dependencies
import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks
import com.shabinder.database.Database import com.shabinder.database.Database
import com.shabinder.common.root.integration.SpotiFlyerRootImpl import com.shabinder.common.root.integration.SpotiFlyerRootImpl
import com.shabinder.common.utils.Consumer import com.shabinder.common.utils.Consumer
import kotlinx.coroutines.flow.StateFlow
interface SpotiFlyerRoot { interface SpotiFlyerRoot {
@ -30,6 +32,7 @@ interface SpotiFlyerRoot {
val database: Database val database: Database
val fetchPlatformQueryResult: FetchPlatformQueryResult val fetchPlatformQueryResult: FetchPlatformQueryResult
val directories: Dir val directories: Dir
val downloadProgressReport: StateFlow<HashMap<String,DownloadStatus>>
} }
} }

View File

@ -11,11 +11,13 @@ import com.arkivanov.decompose.value.Value
import com.shabinder.common.di.Dir import com.shabinder.common.di.Dir
import com.shabinder.common.list.SpotiFlyerList import com.shabinder.common.list.SpotiFlyerList
import com.shabinder.common.main.SpotiFlyerMain import com.shabinder.common.main.SpotiFlyerMain
import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.root.SpotiFlyerRoot import com.shabinder.common.root.SpotiFlyerRoot
import com.shabinder.common.root.SpotiFlyerRoot.Child import com.shabinder.common.root.SpotiFlyerRoot.Child
import com.shabinder.common.root.SpotiFlyerRoot.Dependencies import com.shabinder.common.root.SpotiFlyerRoot.Dependencies
import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks
import com.shabinder.common.utils.Consumer import com.shabinder.common.utils.Consumer
import kotlinx.coroutines.flow.StateFlow
internal class SpotiFlyerRootImpl( internal class SpotiFlyerRootImpl(
componentContext: ComponentContext, componentContext: ComponentContext,
@ -58,6 +60,7 @@ internal class SpotiFlyerRootImpl(
override val dir: Dir = directories override val dir: Dir = directories
override val link: String = link override val link: String = link
override val listOutput : Consumer<SpotiFlyerList.Output> = Consumer(::onListOutput) override val listOutput : Consumer<SpotiFlyerList.Output> = Consumer(::onListOutput)
override val downloadProgressFlow = downloadProgressReport
} }
) )

View File

@ -72,16 +72,15 @@ actual class Dir actual constructor(
@Suppress("BlockingMethodInNonBlockingContext") @Suppress("BlockingMethodInNonBlockingContext")
actual suspend fun saveFileWithMetadata( actual suspend fun saveFileWithMetadata(
mp3ByteArray: ByteArray, mp3ByteArray: ByteArray,
path: String,
trackDetails: TrackDetails trackDetails: TrackDetails
) { ) {
val file = File(path) val file = File(trackDetails.outputFilePath)
file.writeBytes(mp3ByteArray) file.writeBytes(mp3ByteArray)
Mp3File(file) Mp3File(file)
.removeAllTags() .removeAllTags()
.setId3v1Tags(trackDetails) .setId3v1Tags(trackDetails)
.setId3v2TagsAndSaveFile(trackDetails,path) .setId3v2TagsAndSaveFile(trackDetails)
} }
actual suspend fun loadImage(url: String): ImageBitmap? { actual suspend fun loadImage(url: String): ImageBitmap? {

View File

@ -1,5 +1,6 @@
package com.shabinder.common.di.providers package com.shabinder.common.di.providers
import co.touchlab.kermit.Kermit
import co.touchlab.kermit.Logger import co.touchlab.kermit.Logger
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.models.YoutubeTrack import com.shabinder.common.models.YoutubeTrack
@ -13,7 +14,7 @@ import kotlin.math.absoluteValue
private const val apiKey = "AIzaSyC9XL3ZjWddXya6X74dJoCTL-WEYFDNX30" private const val apiKey = "AIzaSyC9XL3ZjWddXya6X74dJoCTL-WEYFDNX30"
class YoutubeMusic constructor( class YoutubeMusic constructor(
private val logger: Logger, private val logger: Kermit,
private val httpClient:HttpClient, private val httpClient:HttpClient,
) { ) {
private val tag = "YT Music" private val tag = "YT Music"
@ -166,7 +167,7 @@ class YoutubeMusic constructor(
} }
} }
} }
logger.i(youtubeTracks.joinToString(" abc \n"),tag) //logger.d(youtubeTracks.joinToString(" abc \n"),tag)
return youtubeTracks return youtubeTracks
} }

View File

@ -7,9 +7,7 @@ import com.github.kiulian.downloader.model.quality.AudioQuality
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 kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.*
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
actual fun openPlatform(packageID:String, platformLink:String){ actual fun openPlatform(packageID:String, platformLink:String){
@ -24,7 +22,7 @@ actual fun giveDonation(){
//TODO //TODO
} }
val DownloadProgressFlow = MutableStateFlow(Pair<String,DownloadStatus>("",DownloadStatus.Queued)) val DownloadProgressFlow: MutableStateFlow<HashMap<String,DownloadStatus>> = MutableStateFlow(hashMapOf())
actual suspend fun downloadTracks( actual suspend fun downloadTracks(
list: List<TrackDetails>, list: List<TrackDetails>,
@ -38,7 +36,7 @@ actual suspend fun downloadTracks(
val searchQuery = "${it.title} - ${it.artists.joinToString(",")}" val searchQuery = "${it.title} - ${it.artists.joinToString(",")}"
val videoId = getYTIDBestMatch(searchQuery,it) val videoId = getYTIDBestMatch(searchQuery,it)
if (videoId.isNullOrBlank()) { if (videoId.isNullOrBlank()) {
DownloadProgressFlow.emit(Pair(it.title,DownloadStatus.Failed)) DownloadProgressFlow.emit(DownloadProgressFlow.value.apply { set(it.title,DownloadStatus.Failed) })
} else {//Found Youtube Video ID } else {//Found Youtube Video ID
downloadTrack(videoId, it,saveFileWithMetaData) downloadTrack(videoId, it,saveFileWithMetaData)
} }
@ -46,7 +44,7 @@ actual suspend fun downloadTracks(
} }
} }
val ytDownloader = YoutubeDownloader() private val ytDownloader = YoutubeDownloader()
suspend fun downloadTrack( suspend fun downloadTrack(
videoID: String, videoID: String,
@ -61,14 +59,14 @@ suspend fun downloadTrack(
downloadFile(url).collect { downloadFile(url).collect {
when(it){ when(it){
is DownloadResult.Error -> { is DownloadResult.Error -> {
//TODO() DownloadProgressFlow.emit(DownloadProgressFlow.value.apply { set(trackDetails.title,DownloadStatus.Failed) })
} }
is DownloadResult.Progress -> { is DownloadResult.Progress -> {
DownloadProgressFlow.emit(Pair(trackDetails.title,DownloadStatus.Downloading(it.progress))) DownloadProgressFlow.emit(DownloadProgressFlow.value.apply { set(trackDetails.title,DownloadStatus.Downloading(it.progress)) })
} }
is DownloadResult.Success -> { is DownloadResult.Success -> {//Todo clear map
saveFileWithMetaData(it.byteArray,trackDetails) saveFileWithMetaData(it.byteArray,trackDetails)
DownloadProgressFlow.emit(Pair(trackDetails.title,DownloadStatus.Downloaded)) DownloadProgressFlow.emit(DownloadProgressFlow.value.apply { set(trackDetails.title,DownloadStatus.Downloaded) })
} }
} }
} }

View File

@ -17,6 +17,10 @@ import javax.imageio.ImageIO
actual class Dir actual constructor(private val logger: Kermit) { actual class Dir actual constructor(private val logger: Kermit) {
init {
createDirectories()
}
actual fun fileSeparator(): String = File.separator actual fun fileSeparator(): String = File.separator
actual fun imageCacheDir(): String = System.getProperty("user.home") + actual fun imageCacheDir(): String = System.getProperty("user.home") +

View File

@ -2,6 +2,7 @@ import androidx.compose.desktop.DesktopMaterialTheme
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Surface import androidx.compose.material.Surface
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import com.arkivanov.decompose.ComponentContext import com.arkivanov.decompose.ComponentContext
@ -10,6 +11,7 @@ import com.arkivanov.mvikotlin.core.lifecycle.LifecycleRegistry
import com.arkivanov.mvikotlin.core.lifecycle.resume import com.arkivanov.mvikotlin.core.lifecycle.resume
import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
import com.shabinder.common.di.Dir import com.shabinder.common.di.Dir
import com.shabinder.common.di.DownloadProgressFlow
import com.shabinder.common.di.FetchPlatformQueryResult import com.shabinder.common.di.FetchPlatformQueryResult
import com.shabinder.common.di.initKoin import com.shabinder.common.di.initKoin
import com.shabinder.common.root.SpotiFlyerRoot import com.shabinder.common.root.SpotiFlyerRoot
@ -19,6 +21,9 @@ import com.shabinder.common.ui.SpotiFlyerShapes
import com.shabinder.common.ui.SpotiFlyerTypography import com.shabinder.common.ui.SpotiFlyerTypography
import com.shabinder.common.ui.colorOffWhite import com.shabinder.common.ui.colorOffWhite
import com.shabinder.database.Database import com.shabinder.database.Database
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
private val koin = initKoin(enableNetworkLogs = true).koin private val koin = initKoin(enableNetworkLogs = true).koin
@ -38,7 +43,13 @@ fun main(){
typography = SpotiFlyerTypography, typography = SpotiFlyerTypography,
shapes = SpotiFlyerShapes shapes = SpotiFlyerShapes
) { ) {
SpotiFlyerRootContent(rootComponent(factory = ::spotiFlyerRoot)) val callBacks = SpotiFlyerRootContent(rootComponent(factory = ::spotiFlyerRoot)).callBacks
val scope = rememberCoroutineScope()
scope.launch {
DownloadProgressFlow.collect {
}
}
} }
} }
} }
@ -52,5 +63,6 @@ private fun spotiFlyerRoot(componentContext: ComponentContext): SpotiFlyerRoot =
override val database: Database = koin.get() override val database: Database = koin.get()
override val fetchPlatformQueryResult: FetchPlatformQueryResult = koin.get() override val fetchPlatformQueryResult: FetchPlatformQueryResult = koin.get()
override val directories: Dir = koin.get() override val directories: Dir = koin.get()
override val downloadProgressReport = DownloadProgressFlow
} }
) )