Instance Keeper Freeze fix .IOS List Screen and Shared Code changes.

This commit is contained in:
shabinder 2021-05-02 22:24:40 +05:30
parent f80675cd13
commit 02d137588f
25 changed files with 236 additions and 153 deletions

View File

@ -265,8 +265,6 @@ class MainActivity : ComponentActivity(), PaymentResultListener {
}
override val isInternetAvailable get() = internetAvailability.value ?: true
override val dispatcherIO = Dispatchers.IO
override val currentPlatform = AllPlatforms.Jvm
}
}
)

View File

@ -36,6 +36,7 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import com.shabinder.common.database.R
import com.shabinder.common.di.Picture
import com.shabinder.common.di.dispatcherIO
import com.shabinder.common.models.methods
import kotlinx.coroutines.withContext
@ -50,7 +51,7 @@ actual fun ImageLoad(
var pic by remember(link) { mutableStateOf<ImageBitmap?>(null) }
LaunchedEffect(link) {
withContext(methods.value.dispatcherIO) {
withContext(dispatcherIO) {
pic = loader(link).image
}
}

View File

@ -35,6 +35,7 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.platform.Font
import com.shabinder.common.di.Picture
import com.shabinder.common.di.dispatcherIO
import com.shabinder.common.models.methods
import kotlinx.coroutines.withContext
@ -48,7 +49,7 @@ actual fun ImageLoad(
) {
var pic by remember(link) { mutableStateOf<ImageBitmap?>(null) }
LaunchedEffect(link) {
withContext(methods.value.dispatcherIO) {
withContext(dispatcherIO) {
pic = loader(link).image
}
}

View File

@ -10,9 +10,19 @@ actual interface PlatformActions {
val imageCacheDir: String
val sharedPreferences: SharedPreferences
val sharedPreferences: SharedPreferences?
fun addToLibrary(path: String)
fun sendTracksToService(array: ArrayList<TrackDetails>)
}
actual val StubPlatformActions = object: PlatformActions {
override val imageCacheDir: String = ""
override val sharedPreferences: SharedPreferences? = null
override fun addToLibrary(path: String) {}
override fun sendTracksToService(array: ArrayList<TrackDetails>) {}
}

View File

@ -1,8 +1,6 @@
package com.shabinder.common.models
import co.touchlab.stately.freeze
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
/*
* Holder to call platform actions from anywhere
@ -17,6 +15,9 @@ interface Actions {
// Platform Specific Actions
val platformActions: PlatformActions
// Platform Specific Implementation Preferred
val isInternetAvailable: Boolean
// Show Toast
fun showPopUpMessage(string: String, long: Boolean = false)
@ -37,15 +38,6 @@ interface Actions {
// Open / Redirect to another Platform
fun openPlatform(packageID: String, platformLink: String)
// IO-Dispatcher
val dispatcherIO: CoroutineDispatcher
// Internet Connectivity Check
val isInternetAvailable: Boolean
// Current Platform Info
val currentPlatform: AllPlatforms
}
@ -57,7 +49,5 @@ private fun stubActions() = object :Actions{
override fun giveDonation() {}
override fun shareApp() {}
override fun openPlatform(packageID: String, platformLink: String) {}
override val dispatcherIO: CoroutineDispatcher = Dispatchers.Default
override val isInternetAvailable: Boolean = true
override val currentPlatform: AllPlatforms = AllPlatforms.Jvm
}

View File

@ -1,3 +1,5 @@
package com.shabinder.common.models
expect interface PlatformActions
expect interface PlatformActions
expect val StubPlatformActions : PlatformActions

View File

@ -1,4 +1,5 @@
package com.shabinder.common.models
actual interface PlatformActions {
}
actual interface PlatformActions {}
actual val StubPlatformActions = object: PlatformActions {}

View File

@ -2,6 +2,7 @@ package com.shabinder.common.models
import kotlin.native.concurrent.AtomicReference
actual interface PlatformActions
actual interface PlatformActions {}
actual val StubPlatformActions = object: PlatformActions {}
actual typealias NativeAtomicReference<T> = AtomicReference<T>

View File

@ -1,4 +1,4 @@
package com.shabinder.common.models
actual interface PlatformActions {
}
actual interface PlatformActions {}
actual val StubPlatformActions = object: PlatformActions {}

View File

@ -16,8 +16,17 @@
package com.shabinder.common.di
import com.shabinder.common.models.AllPlatforms
import com.shabinder.common.models.TrackDetails
import com.shabinder.common.models.methods
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
// IO-Dispatcher
actual val dispatcherIO: CoroutineDispatcher = Dispatchers.IO
// Current Platform Info
actual val currentPlatform: AllPlatforms = AllPlatforms.Jvm
actual suspend fun downloadTracks(
list: List<TrackDetails>,

View File

@ -46,7 +46,8 @@ actual class Dir actual constructor(
const val DirKey = "downloadDir"
}
private val sharedPreferences:SharedPreferences by lazy { methods.value.platformActions.sharedPreferences }
// This Wont throw `NPE` as We will never pass null
private val sharedPreferences:SharedPreferences by lazy { methods.value.platformActions.sharedPreferences!! }
fun setDownloadDirectory(newBasePath:String){
sharedPreferences.edit().putString(DirKey,newBasePath).apply()
@ -77,7 +78,7 @@ actual class Dir actual constructor(
}
}
actual suspend fun clearCache() {
actual suspend fun clearCache(): Unit = withContext(dispatcherIO) {
File(imageCacheDir()).deleteRecursively()
}
@ -86,76 +87,74 @@ actual class Dir actual constructor(
mp3ByteArray: ByteArray,
trackDetails: TrackDetails,
postProcess:(track: TrackDetails)->Unit
) {
withContext(Dispatchers.IO){
val songFile = File(trackDetails.outputFilePath)
try {
/*
* Check , if Fetch was Used, File is saved Already, else write byteArray we Received
* */
if(!songFile.exists()) {
/*Make intermediate Dirs if they don't exist yet*/
songFile.parentFile.mkdirs()
) = withContext(dispatcherIO) {
val songFile = File(trackDetails.outputFilePath)
try {
/*
* Check , if Fetch was Used, File is saved Already, else write byteArray we Received
* */
if(!songFile.exists()) {
/*Make intermediate Dirs if they don't exist yet*/
songFile.parentFile.mkdirs()
}
if(mp3ByteArray.isNotEmpty()) songFile.writeBytes(mp3ByteArray)
when (trackDetails.outputFilePath.substringAfterLast('.')) {
".mp3" -> {
Mp3File(File(songFile.absolutePath))
.removeAllTags()
.setId3v1Tags(trackDetails)
.setId3v2TagsAndSaveFile(trackDetails)
addToLibrary(songFile.absolutePath)
}
if(mp3ByteArray.isNotEmpty()) songFile.writeBytes(mp3ByteArray)
when (trackDetails.outputFilePath.substringAfterLast('.')) {
".mp3" -> {
".m4a" -> {
/*FFmpeg.executeAsync(
"-i ${m4aFile.absolutePath} -y -b:a 160k -acodec libmp3lame -vn ${m4aFile.absolutePath.substringBeforeLast('.') + ".mp3"}"
){ _, returnCode ->
when (returnCode) {
Config.RETURN_CODE_SUCCESS -> {
//FFMPEG task Completed
logger.d{ "Async command execution completed successfully." }
scope.launch {
Mp3File(File(m4aFile.absolutePath.substringBeforeLast('.') + ".mp3"))
.removeAllTags()
.setId3v1Tags(trackDetails)
.setId3v2TagsAndSaveFile(trackDetails)
addToLibrary(m4aFile.absolutePath.substringBeforeLast('.') + ".mp3")
}
}
Config.RETURN_CODE_CANCEL -> {
logger.d{"Async command execution cancelled by user."}
}
else -> {
logger.d { "Async command execution failed with rc=$returnCode" }
}
}
}*/
}
else -> {
try {
Mp3File(File(songFile.absolutePath))
.removeAllTags()
.setId3v1Tags(trackDetails)
.setId3v2TagsAndSaveFile(trackDetails)
addToLibrary(songFile.absolutePath)
}
".m4a" -> {
/*FFmpeg.executeAsync(
"-i ${m4aFile.absolutePath} -y -b:a 160k -acodec libmp3lame -vn ${m4aFile.absolutePath.substringBeforeLast('.') + ".mp3"}"
){ _, returnCode ->
when (returnCode) {
Config.RETURN_CODE_SUCCESS -> {
//FFMPEG task Completed
logger.d{ "Async command execution completed successfully." }
scope.launch {
Mp3File(File(m4aFile.absolutePath.substringBeforeLast('.') + ".mp3"))
.removeAllTags()
.setId3v1Tags(trackDetails)
.setId3v2TagsAndSaveFile(trackDetails)
addToLibrary(m4aFile.absolutePath.substringBeforeLast('.') + ".mp3")
}
}
Config.RETURN_CODE_CANCEL -> {
logger.d{"Async command execution cancelled by user."}
}
else -> {
logger.d { "Async command execution failed with rc=$returnCode" }
}
}
}*/
}
else -> {
try {
Mp3File(File(songFile.absolutePath))
.removeAllTags()
.setId3v1Tags(trackDetails)
.setId3v2TagsAndSaveFile(trackDetails)
addToLibrary(songFile.absolutePath)
} catch (e: Exception) { e.printStackTrace() }
}
} catch (e: Exception) { e.printStackTrace() }
}
}catch (e:Exception){
withContext(Dispatchers.Main){
//Toast.makeText(appContext,"Could Not Create File:\n${songFile.absolutePath}",Toast.LENGTH_SHORT).show()
}
if(songFile.exists()) songFile.delete()
logger.e { "${songFile.absolutePath} could not be created" }
}
}catch (e:Exception){
withContext(Dispatchers.Main){
//Toast.makeText(appContext,"Could Not Create File:\n${songFile.absolutePath}",Toast.LENGTH_SHORT).show()
}
if(songFile.exists()) songFile.delete()
logger.e { "${songFile.absolutePath} could not be created" }
}
}
actual fun addToLibrary(path: String) = methods.value.platformActions.addToLibrary(path)
actual suspend fun loadImage(url: String): Picture = withContext(Dispatchers.IO){
actual suspend fun loadImage(url: String): Picture = withContext(dispatcherIO){
val cachePath = imageCacheDir() + getNameURL(url)
Picture(image = (loadCachedImage(cachePath) ?: freshImage(url))?.asImageBitmap())
}
@ -169,19 +168,17 @@ actual class Dir actual constructor(
}
}
actual suspend fun cacheImage(image: Any, path: String) {
withContext(Dispatchers.IO){
try {
FileOutputStream(path).use { out ->
(image as? Bitmap)?.compress(Bitmap.CompressFormat.JPEG, 100, out)
}
} catch (e: IOException) {
e.printStackTrace()
actual suspend fun cacheImage(image: Any, path: String):Unit = withContext(dispatcherIO) {
try {
FileOutputStream(path).use { out ->
(image as? Bitmap)?.compress(Bitmap.CompressFormat.JPEG, 100, out)
}
} catch (e: IOException) {
e.printStackTrace()
}
}
private suspend fun freshImage(url: String): Bitmap? = withContext(Dispatchers.IO) {
private suspend fun freshImage(url: String): Bitmap? = withContext(dispatcherIO) {
try {
val source = URL(url)
val connection: HttpURLConnection = source.openConnection() as HttpURLConnection

View File

@ -16,11 +16,14 @@
package com.shabinder.common.di
import com.shabinder.common.models.AllPlatforms
import com.shabinder.common.models.TrackDetails
import com.shabinder.common.models.methods
import io.ktor.client.request.*
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlin.native.concurrent.SharedImmutable
expect suspend fun downloadTracks(
list: List<TrackDetails>,
@ -28,8 +31,17 @@ expect suspend fun downloadTracks(
dir: Dir
)
// IO-Dispatcher
@SharedImmutable
expect val dispatcherIO: CoroutineDispatcher
// Current Platform Info
@SharedImmutable
expect val currentPlatform: AllPlatforms
suspend fun isInternetAccessible(): Boolean {
return withContext(methods.value.dispatcherIO) {
return withContext(dispatcherIO) {
try {
ktorHttpClient.head<String>("http://google.com")
true

View File

@ -16,6 +16,7 @@
package com.shabinder.common.di.gaana
import com.shabinder.common.di.currentPlatform
import com.shabinder.common.models.AllPlatforms
import com.shabinder.common.models.corsProxy
import com.shabinder.common.models.gaana.GaanaAlbum
@ -27,7 +28,7 @@ import com.shabinder.common.models.methods
import io.ktor.client.HttpClient
import io.ktor.client.request.get
val corsApi get() = if (methods.value.currentPlatform is AllPlatforms.Js) {
val corsApi get() = if (currentPlatform is AllPlatforms.Js) {
corsProxy.url
} // "https://spotiflyer-cors.azurewebsites.net/" //"https://spotiflyer-cors.herokuapp.com/"//"https://cors.bridged.cc/"
else ""

View File

@ -46,7 +46,7 @@ class SpotifyProvider(
/* init {
logger.d { "Creating Spotify Provider" }
GlobalScope.launch(Dispatchers.Default) {
if (methods.value.currentPlatform is AllPlatforms.Js) {
if (currentPlatform is AllPlatforms.Js) {
authenticateSpotifyClient(override = true)
} else authenticateSpotifyClient()
}

View File

@ -18,6 +18,7 @@ package com.shabinder.common.di.providers
import co.touchlab.kermit.Kermit
import com.shabinder.common.di.Dir
import com.shabinder.common.di.currentPlatform
import com.shabinder.common.di.youtubeMp3.Yt1sMp3
import com.shabinder.common.models.AllPlatforms
import com.shabinder.common.models.methods
@ -31,7 +32,7 @@ class YoutubeMp3(
suspend fun getMp3DownloadLink(videoID: String): String? = try {
getLinkFromYt1sMp3(videoID)?.let {
logger.i { "Download Link: $it" }
if (methods.value.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://spotiflyer.azurewebsites.net/$it" // Data OUT Limit issue
else it

View File

@ -21,6 +21,7 @@ package com.shabinder.common.di.utils
// implementation("org.jetbrains.kotlinx:atomicfu:0.14.4")
// Gist: https://gist.github.com/fluidsonic/ba32de21c156bbe8424c8d5fc20dcd8e
import com.shabinder.common.di.dispatcherIO
import com.shabinder.common.models.methods
import io.ktor.utils.io.core.Closeable
import kotlinx.atomicfu.atomic
@ -37,7 +38,7 @@ import kotlinx.coroutines.withContext
import kotlin.coroutines.CoroutineContext
class ParallelExecutor(
parentContext: CoroutineContext = methods.value.dispatcherIO,
parentContext: CoroutineContext = dispatcherIO,
) : Closeable {
private val concurrentOperationLimit = atomic(4)

View File

@ -17,10 +17,12 @@
package com.shabinder.common.di
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
import com.shabinder.common.models.TrackDetails
import com.shabinder.downloader.YoutubeDownloader
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.collect
@ -30,6 +32,12 @@ val DownloadProgressFlow: MutableSharedFlow<HashMap<String, DownloadStatus>> = M
// Scope Allowing 4 Parallel Downloads
val DownloadScope = ParallelExecutor(Dispatchers.IO)
// IO-Dispatcher
actual val dispatcherIO: CoroutineDispatcher = Dispatchers.IO
// Current Platform Info
actual val currentPlatform: AllPlatforms = AllPlatforms.Jvm
actual suspend fun downloadTracks(
list: List<TrackDetails>,
fetcher: FetchPlatformQueryResult,

View File

@ -1,6 +1,14 @@
package com.shabinder.common.di
import com.shabinder.common.models.AllPlatforms
import com.shabinder.common.models.TrackDetails
import kotlinx.coroutines.Dispatchers
@SharedImmutable
actual val dispatcherIO = Dispatchers.Default
@SharedImmutable
actual val currentPlatform: AllPlatforms = AllPlatforms.Native
actual suspend fun downloadTracks(
list: List<TrackDetails>,

View File

@ -6,6 +6,7 @@ import com.shabinder.common.models.TrackDetails
import com.shabinder.database.Database
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import platform.Foundation.NSCachesDirectory
import platform.Foundation.NSDirectoryEnumerationSkipsHiddenFiles
import platform.Foundation.NSFileManager
@ -25,10 +26,6 @@ actual class Dir actual constructor(
private val spotiFlyerDatabase: SpotiFlyerDatabase,
) {
init {
//createDirectories()
}
actual fun isPresent(path: String): Boolean = NSFileManager.defaultManager.fileExistsAtPath(path)
actual fun fileSeparator(): String = "/"
@ -37,6 +34,7 @@ actual class Dir actual constructor(
actual fun defaultDir(): String = defaultDirURL.path!!
val defaultDirURL: NSURL by lazy {
createDirectories()
val musicDir = NSFileManager.defaultManager.URLForDirectory(NSMusicDirectory, NSUserDomainMask,null,true,null)!!
musicDir.URLByAppendingPathComponent("SpotiFlyer",true)!!
}
@ -44,6 +42,7 @@ actual class Dir actual constructor(
actual fun imageCacheDir(): String = imageCacheURL.path!!
val imageCacheURL: NSURL by lazy {
createDirectories()
val cacheDir = NSFileManager.defaultManager.URLForDirectory(NSCachesDirectory, NSUserDomainMask,null,true,null)
cacheDir?.URLByAppendingPathComponent("SpotiFlyer",true)!!
}
@ -64,7 +63,7 @@ actual class Dir actual constructor(
}
}
actual suspend fun cacheImage(image: Any, path: String) {
actual suspend fun cacheImage(image: Any, path: String): Unit = withContext(dispatcherIO){
try {
(image as? UIImage)?.let {
// We Will Be Using JPEG as default format everywhere
@ -76,8 +75,8 @@ actual class Dir actual constructor(
}
}
actual suspend fun loadImage(url: String): Picture {
return try {
actual suspend fun loadImage(url: String): Picture = withContext(dispatcherIO){
try {
val cachePath = imageCacheURL.URLByAppendingPathComponent(getNameURL(url))
Picture(image = cachePath?.path?.let { loadCachedImage(it) } ?: loadFreshImage(url))
} catch (e: Exception) {
@ -95,8 +94,8 @@ actual class Dir actual constructor(
}
}
private suspend fun loadFreshImage(url: String):UIImage? {
return try {
private suspend fun loadFreshImage(url: String):UIImage? = withContext(dispatcherIO){
try {
val nsURL = NSURL(string = url)
val data = NSURLConnection.sendSynchronousRequest(NSURLRequest.requestWithURL(nsURL),null,null)
if (data != null) {
@ -112,7 +111,7 @@ actual class Dir actual constructor(
}
}
actual suspend fun clearCache() {
actual suspend fun clearCache(): Unit = withContext(dispatcherIO) {
try {
val fileManager = NSFileManager.defaultManager
val paths = fileManager.contentsOfDirectoryAtURL(imageCacheURL,
@ -136,7 +135,7 @@ actual class Dir actual constructor(
mp3ByteArray: ByteArray,
trackDetails: TrackDetails,
postProcess:(track: TrackDetails)->Unit
) {
) : Unit = withContext(dispatcherIO) {
when (trackDetails.outputFilePath.substringAfterLast('.')) {
".mp3" -> {
postProcess(trackDetails)

View File

@ -16,10 +16,13 @@
package com.shabinder.common.di
import com.shabinder.common.models.AllPlatforms
import com.shabinder.common.models.DownloadResult
import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.TrackDetails
import com.shabinder.common.models.methods
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.withContext
@ -29,13 +32,19 @@ val DownloadProgressFlow: MutableSharedFlow<HashMap<String, DownloadStatus>> = M
// val DownloadScope = ParallelExecutor(Dispatchers.Default) //Download Pool of 4 parallel
val allTracksStatus: HashMap<String, DownloadStatus> = hashMapOf()
// IO-Dispatcher
actual val dispatcherIO: CoroutineDispatcher = Dispatchers.Default
// Current Platform Info
actual val currentPlatform: AllPlatforms = AllPlatforms.Js
actual suspend fun downloadTracks(
list: List<TrackDetails>,
fetcher: FetchPlatformQueryResult,
dir: Dir
) {
list.forEach {
withContext(methods.value.dispatcherIO) {
withContext(dispatcherIO) {
allTracksStatus[it.title] = DownloadStatus.Queued
if (!it.videoID.isNullOrBlank()) { // Video ID already known!
downloadTrack(it.videoID!!, it, fetcher, dir)

View File

@ -16,6 +16,7 @@
package com.shabinder.common.list.integration
import co.touchlab.stately.ensureNeverFrozen
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.value.Value
import com.shabinder.common.di.Picture
@ -33,6 +34,10 @@ internal class SpotiFlyerListImpl(
dependencies: Dependencies
) : SpotiFlyerList, ComponentContext by componentContext, Dependencies by dependencies {
init {
instanceKeeper.ensureNeverFrozen()
}
private val store =
instanceKeeper.getStore {
SpotiFlyerListStoreProvider(

View File

@ -16,6 +16,7 @@
package com.shabinder.common.main.integration
import co.touchlab.stately.ensureNeverFrozen
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.value.Value
import com.shabinder.common.di.Picture
@ -35,6 +36,10 @@ internal class SpotiFlyerMainImpl(
dependencies: Dependencies
) : SpotiFlyerMain, ComponentContext by componentContext, Dependencies by dependencies {
init {
instanceKeeper.ensureNeverFrozen()
}
private val store =
instanceKeeper.getStore {
SpotiFlyerMainStoreProvider(

View File

@ -25,7 +25,6 @@ fun <T : Store<*, *, *>> InstanceKeeper.getStore(key: Any, factory: () -> T): T
.store
inline fun <reified T :
Store<*, *, *>> InstanceKeeper.getStore(noinline factory: () -> T): T =
getStore(T::class, factory)

View File

@ -16,6 +16,7 @@
package com.shabinder.common.root.integration
import co.touchlab.stately.ensureNeverFrozen
import co.touchlab.stately.freeze
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.RouterState
@ -26,9 +27,9 @@ import com.arkivanov.decompose.router
import com.arkivanov.decompose.statekeeper.Parcelable
import com.arkivanov.decompose.statekeeper.Parcelize
import com.arkivanov.decompose.value.Value
import com.shabinder.common.database.getLogger
import com.shabinder.common.di.Dir
import com.shabinder.common.di.createDirectories
import com.shabinder.common.di.currentPlatform
import com.shabinder.common.di.providers.SpotifyProvider
import com.shabinder.common.list.SpotiFlyerList
import com.shabinder.common.main.SpotiFlyerMain
import com.shabinder.common.models.Actions
@ -45,23 +46,40 @@ import kotlinx.coroutines.launch
internal class SpotiFlyerRootImpl(
componentContext: ComponentContext,
dependencies: Dependencies,
) : SpotiFlyerRoot, ComponentContext by componentContext, Dependencies by dependencies, Actions by dependencies.actions {
private val main: (ComponentContext, output:Consumer<SpotiFlyerMain.Output>)->SpotiFlyerMain,
private val list: (ComponentContext, link:String, output:Consumer<SpotiFlyerList.Output>)->SpotiFlyerList,
private val actions: Actions
) : SpotiFlyerRoot, ComponentContext by componentContext {
init {
methods.value = actions.freeze()
GlobalScope.launch {
/*TESTING*/
getLogger().apply {
d("Hey...","Background Thread")
//d(directories.defaultDir(),"Background Thread")
d("Hey...","Background Thread")
}
//*Authenticate Spotify Client*//*
/*fetchPlatformQueryResult.spotifyProvider.authenticateSpotifyClient(
override = true //methods.value.currentPlatform is AllPlatforms.Js
)*/
}
constructor(
componentContext: ComponentContext,
dependencies: Dependencies,
):this(
componentContext = componentContext,
main = { childContext,output ->
spotiFlyerMain(
childContext,
output,
dependencies
)
},
list = { childContext, link, output ->
spotiFlyerList(
childContext,
link,
output,
dependencies
)
},
actions = dependencies.actions.freeze()
) {
instanceKeeper.ensureNeverFrozen()
methods.value = dependencies.actions.freeze()
/*Authenticate Spotify Client*/
authenticateSpotify(
dependencies.fetchPlatformQueryResult.spotifyProvider,
currentPlatform is AllPlatforms.Js
)
}
private val router =
@ -80,36 +98,15 @@ internal class SpotiFlyerRootImpl(
it !is Configuration.Main
}
}
override fun setDownloadDirectory() { setDownloadDirectoryAction() }
override fun setDownloadDirectory() { actions.setDownloadDirectoryAction() }
}
private fun createChild(configuration: Configuration, componentContext: ComponentContext): Child =
when (configuration) {
is Configuration.Main -> Child.Main(spotiFlyerMain(componentContext))
is Configuration.List -> Child.List(spotiFlyerList(componentContext, link = configuration.link))
is Configuration.Main -> Child.Main(main(componentContext, Consumer(::onMainOutput)))
is Configuration.List -> Child.List(list(componentContext, configuration.link, Consumer(::onListOutput)))
}
private fun spotiFlyerMain(componentContext: ComponentContext): SpotiFlyerMain =
SpotiFlyerMain(
componentContext = componentContext,
dependencies = object : SpotiFlyerMain.Dependencies, Dependencies by this {
override val mainOutput: Consumer<SpotiFlyerMain.Output> = Consumer(::onMainOutput)
override val dir: Dir = directories
}
)
private fun spotiFlyerList(componentContext: ComponentContext, link: String): SpotiFlyerList =
SpotiFlyerList(
componentContext = componentContext,
dependencies = object : SpotiFlyerList.Dependencies, Dependencies by this {
override val fetchQuery = fetchPlatformQueryResult
override val dir: Dir = directories
override val link: String = link
override val listOutput: Consumer<SpotiFlyerList.Output> = Consumer(::onListOutput)
override val downloadProgressFlow = downloadProgressReport
}
)
private fun onMainOutput(output: SpotiFlyerMain.Output) =
when (output) {
is SpotiFlyerMain.Output.Search -> router.push(Configuration.List(link = output.link))
@ -120,6 +117,13 @@ internal class SpotiFlyerRootImpl(
is SpotiFlyerList.Output.Finished -> router.pop()
}
private fun authenticateSpotify(spotifyProvider: SpotifyProvider, override:Boolean){
GlobalScope.launch(Dispatchers.Default) {
/*Authenticate Spotify Client*/
spotifyProvider.authenticateSpotifyClient(override)
}
}
private sealed class Configuration : Parcelable {
@Parcelize
object Main : Configuration()
@ -128,3 +132,24 @@ internal class SpotiFlyerRootImpl(
data class List(val link: String) : Configuration()
}
}
private fun spotiFlyerMain(componentContext: ComponentContext, output: Consumer<SpotiFlyerMain.Output> ,dependencies: Dependencies): SpotiFlyerMain =
SpotiFlyerMain(
componentContext = componentContext,
dependencies = object : SpotiFlyerMain.Dependencies, Dependencies by dependencies {
override val mainOutput: Consumer<SpotiFlyerMain.Output> = output
override val dir: Dir = directories
}
)
private fun spotiFlyerList(componentContext: ComponentContext, link: String, output: Consumer<SpotiFlyerList.Output>, dependencies: Dependencies): SpotiFlyerList =
SpotiFlyerList(
componentContext = componentContext,
dependencies = object : SpotiFlyerList.Dependencies, Dependencies by dependencies {
override val fetchQuery = fetchPlatformQueryResult
override val dir: Dir = directories
override val link: String = link
override val listOutput: Consumer<SpotiFlyerList.Output> = output
override val downloadProgressFlow = downloadProgressReport
}
)

@ -1 +1 @@
Subproject commit 31517f90ef04efa4aea88c61ca627647c146f471
Subproject commit f218336b5b31b365bbf34503b79f2c4f2b703d7d