mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-22 01:04:31 +01:00
Preference Screen & Preference Manager (WIP)
This commit is contained in:
parent
bb3776af56
commit
c010916953
@ -52,6 +52,7 @@ import com.google.accompanist.insets.navigationBarsPadding
|
|||||||
import com.google.accompanist.insets.statusBarsHeight
|
import com.google.accompanist.insets.statusBarsHeight
|
||||||
import com.google.accompanist.insets.statusBarsPadding
|
import com.google.accompanist.insets.statusBarsPadding
|
||||||
import com.shabinder.common.di.*
|
import com.shabinder.common.di.*
|
||||||
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import com.shabinder.common.models.Actions
|
import com.shabinder.common.models.Actions
|
||||||
import com.shabinder.common.models.DownloadStatus
|
import com.shabinder.common.models.DownloadStatus
|
||||||
import com.shabinder.common.models.PlatformActions
|
import com.shabinder.common.models.PlatformActions
|
||||||
@ -78,6 +79,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
|
|
||||||
private val fetcher: FetchPlatformQueryResult by inject()
|
private val fetcher: FetchPlatformQueryResult by inject()
|
||||||
private val dir: Dir by inject()
|
private val dir: Dir by inject()
|
||||||
|
private val preferenceManager: PreferenceManager by inject()
|
||||||
private lateinit var root: SpotiFlyerRoot
|
private lateinit var root: SpotiFlyerRoot
|
||||||
private val callBacks: SpotiFlyerRootCallBacks get() = root.callBacks
|
private val callBacks: SpotiFlyerRootCallBacks get() = root.callBacks
|
||||||
private val trackStatusFlow = MutableSharedFlow<HashMap<String, DownloadStatus>>(1)
|
private val trackStatusFlow = MutableSharedFlow<HashMap<String, DownloadStatus>>(1)
|
||||||
@ -129,18 +131,18 @@ class MainActivity : ComponentActivity() {
|
|||||||
AnalyticsDialog(
|
AnalyticsDialog(
|
||||||
askForAnalyticsPermission,
|
askForAnalyticsPermission,
|
||||||
enableAnalytics = {
|
enableAnalytics = {
|
||||||
dir.toggleAnalytics(true)
|
preferenceManager.toggleAnalytics(true)
|
||||||
dir.firstLaunchDone()
|
preferenceManager.firstLaunchDone()
|
||||||
},
|
},
|
||||||
dismissDialog = {
|
dismissDialog = {
|
||||||
askForAnalyticsPermission = false
|
askForAnalyticsPermission = false
|
||||||
dir.firstLaunchDone()
|
preferenceManager.firstLaunchDone()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
LaunchedEffect(view) {
|
LaunchedEffect(view) {
|
||||||
permissionGranted.value = checkPermissions()
|
permissionGranted.value = checkPermissions()
|
||||||
if(dir.isFirstLaunch) {
|
if(preferenceManager.isFirstLaunch) {
|
||||||
delay(2500)
|
delay(2500)
|
||||||
// Ask For Analytics Permission on first Dialog
|
// Ask For Analytics Permission on first Dialog
|
||||||
askForAnalyticsPermission = true
|
askForAnalyticsPermission = true
|
||||||
@ -161,7 +163,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
* for `Github Downloads` we will track Downloads using : https://tooomm.github.io/github-release-stats/?username=Shabinder&repository=SpotiFlyer
|
* for `Github Downloads` we will track Downloads using : https://tooomm.github.io/github-release-stats/?username=Shabinder&repository=SpotiFlyer
|
||||||
* */
|
* */
|
||||||
if(isGithubRelease) { checkIfLatestVersion() }
|
if(isGithubRelease) { checkIfLatestVersion() }
|
||||||
if(dir.isAnalyticsEnabled && !isGithubRelease) {
|
if(preferenceManager.isAnalyticsEnabled && !isGithubRelease) {
|
||||||
// Download/App Install Event for F-Droid builds
|
// Download/App Install Event for F-Droid builds
|
||||||
TrackHelper.track().download().with(tracker)
|
TrackHelper.track().download().with(tracker)
|
||||||
}
|
}
|
||||||
@ -246,9 +248,10 @@ class MainActivity : ComponentActivity() {
|
|||||||
dependencies = object : SpotiFlyerRoot.Dependencies{
|
dependencies = object : SpotiFlyerRoot.Dependencies{
|
||||||
override val storeFactory = LoggingStoreFactory(DefaultStoreFactory)
|
override val storeFactory = LoggingStoreFactory(DefaultStoreFactory)
|
||||||
override val database = this@MainActivity.dir.db
|
override val database = this@MainActivity.dir.db
|
||||||
override val fetchPlatformQueryResult = this@MainActivity.fetcher
|
override val fetchQuery = this@MainActivity.fetcher
|
||||||
override val directories: Dir = this@MainActivity.dir
|
override val dir: Dir = this@MainActivity.dir
|
||||||
override val downloadProgressReport: MutableSharedFlow<HashMap<String, DownloadStatus>> = trackStatusFlow
|
override val preferenceManager = this@MainActivity.preferenceManager
|
||||||
|
override val downloadProgressFlow: MutableSharedFlow<HashMap<String, DownloadStatus>> = trackStatusFlow
|
||||||
override val actions = object: Actions {
|
override val actions = object: Actions {
|
||||||
|
|
||||||
override val platformActions = object : PlatformActions {
|
override val platformActions = object : PlatformActions {
|
||||||
@ -316,7 +319,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
* */
|
* */
|
||||||
override val analytics = object: Analytics {
|
override val analytics = object: Analytics {
|
||||||
override fun appLaunchEvent() {
|
override fun appLaunchEvent() {
|
||||||
if(dir.isAnalyticsEnabled){
|
if(preferenceManager.isAnalyticsEnabled){
|
||||||
TrackHelper.track()
|
TrackHelper.track()
|
||||||
.event("events","App_Launch")
|
.event("events","App_Launch")
|
||||||
.name("App Launch").with(tracker)
|
.name("App Launch").with(tracker)
|
||||||
@ -324,7 +327,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun homeScreenVisit() {
|
override fun homeScreenVisit() {
|
||||||
if(dir.isAnalyticsEnabled){
|
if(preferenceManager.isAnalyticsEnabled){
|
||||||
// HomeScreen Visit Event
|
// HomeScreen Visit Event
|
||||||
TrackHelper.track().screen("/main_activity/home_screen")
|
TrackHelper.track().screen("/main_activity/home_screen")
|
||||||
.title("HomeScreen").with(tracker)
|
.title("HomeScreen").with(tracker)
|
||||||
@ -332,7 +335,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun listScreenVisit() {
|
override fun listScreenVisit() {
|
||||||
if(dir.isAnalyticsEnabled){
|
if(preferenceManager.isAnalyticsEnabled){
|
||||||
// ListScreen Visit Event
|
// ListScreen Visit Event
|
||||||
TrackHelper.track().screen("/main_activity/list_screen")
|
TrackHelper.track().screen("/main_activity/list_screen")
|
||||||
.title("ListScreen").with(tracker)
|
.title("ListScreen").with(tracker)
|
||||||
@ -340,7 +343,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun donationDialogVisit() {
|
override fun donationDialogVisit() {
|
||||||
if (dir.isAnalyticsEnabled) {
|
if (preferenceManager.isAnalyticsEnabled) {
|
||||||
// Donation Dialog Open Event
|
// Donation Dialog Open Event
|
||||||
TrackHelper.track().screen("/main_activity/donation_dialog")
|
TrackHelper.track().screen("/main_activity/donation_dialog")
|
||||||
.title("DonationDialog").with(tracker)
|
.title("DonationDialog").with(tracker)
|
||||||
@ -384,7 +387,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
val f = File(path)
|
val f = File(path)
|
||||||
if (f.canWrite()) {
|
if (f.canWrite()) {
|
||||||
// hell yeah :)
|
// hell yeah :)
|
||||||
dir.setDownloadDirectory(path)
|
preferenceManager.setDownloadDirectory(path)
|
||||||
showPopUpMessage(
|
showPopUpMessage(
|
||||||
"Download Directory Set to:\n${dir.defaultDir()} "
|
"Download Directory Set to:\n${dir.defaultDir()} "
|
||||||
)
|
)
|
||||||
|
@ -33,12 +33,17 @@ allprojects {
|
|||||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "1.8"
|
jvmTarget = "1.8"
|
||||||
useIR = true
|
freeCompilerArgs = freeCompilerArgs + "-Xopt-in=kotlin.RequiresOptIn"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
afterEvaluate {
|
afterEvaluate {
|
||||||
project.extensions.findByType<org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension>()?.let { kmpExt ->
|
project.extensions.findByType<org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension>()?.let { kmpExt ->
|
||||||
kmpExt.sourceSets.removeAll { it.name == "androidAndroidTestRelease" }
|
kmpExt.sourceSets.run {
|
||||||
|
all {
|
||||||
|
languageSettings.useExperimentalAnnotation("kotlinx.serialization.ExperimentalSerializationApi")
|
||||||
|
}
|
||||||
|
removeAll { it.name == "androidAndroidTestRelease" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,10 @@ object HostOS {
|
|||||||
val isLinux = hostOs.startsWith("Linux",true)
|
val isLinux = hostOs.startsWith("Linux",true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object MultiPlatformSettings {
|
||||||
|
const val dep = "com.russhwolf:multiplatform-settings-no-arg:0.7.7"
|
||||||
|
}
|
||||||
|
|
||||||
object Koin {
|
object Koin {
|
||||||
val core = "io.insert-koin:koin-core:${Versions.koin}"
|
val core = "io.insert-koin:koin-core:${Versions.koin}"
|
||||||
val test = "io.insert-koin:koin-test:${Versions.koin}"
|
val test = "io.insert-koin:koin-test:${Versions.koin}"
|
||||||
|
@ -10,6 +10,11 @@ sealed class SpotiFlyerException(override val message: String): Exception(messag
|
|||||||
override val message: String = "MP3 Converter unreachable, probably BUSY ! \nCAUSE:$extraInfo"
|
override val message: String = "MP3 Converter unreachable, probably BUSY ! \nCAUSE:$extraInfo"
|
||||||
): SpotiFlyerException(message)
|
): SpotiFlyerException(message)
|
||||||
|
|
||||||
|
data class UnknownReason(
|
||||||
|
val exception: Throwable? = null,
|
||||||
|
override val message: String = "Unknown Error"
|
||||||
|
): SpotiFlyerException(message)
|
||||||
|
|
||||||
data class NoMatchFound(
|
data class NoMatchFound(
|
||||||
val trackName: String? = null,
|
val trackName: String? = null,
|
||||||
override val message: String = "$trackName : NO Match Found!"
|
override val message: String = "$trackName : NO Match Found!"
|
||||||
|
@ -32,7 +32,7 @@ kotlin {
|
|||||||
implementation(project(":common:database"))
|
implementation(project(":common:database"))
|
||||||
implementation("org.jetbrains.kotlinx:atomicfu:0.16.1")
|
implementation("org.jetbrains.kotlinx:atomicfu:0.16.1")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.2.1")
|
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.2.1")
|
||||||
implementation("com.russhwolf:multiplatform-settings-no-arg:0.7.7")
|
api(MultiPlatformSettings.dep)
|
||||||
implementation(Extras.youtubeDownloader)
|
implementation(Extras.youtubeDownloader)
|
||||||
implementation(Extras.fuzzyWuzzy)
|
implementation(Extras.fuzzyWuzzy)
|
||||||
implementation(MVIKotlin.rx)
|
implementation(MVIKotlin.rx)
|
||||||
|
@ -22,8 +22,8 @@ import android.os.Environment
|
|||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.mpatric.mp3agic.Mp3File
|
import com.mpatric.mp3agic.Mp3File
|
||||||
import com.russhwolf.settings.Settings
|
|
||||||
import com.shabinder.common.database.SpotiFlyerDatabase
|
import com.shabinder.common.database.SpotiFlyerDatabase
|
||||||
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import com.shabinder.common.di.utils.ParallelExecutor
|
import com.shabinder.common.di.utils.ParallelExecutor
|
||||||
import com.shabinder.common.models.TrackDetails
|
import com.shabinder.common.models.TrackDetails
|
||||||
import com.shabinder.common.models.methods
|
import com.shabinder.common.models.methods
|
||||||
@ -43,7 +43,7 @@ import java.net.URL
|
|||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
actual class Dir actual constructor(
|
actual class Dir actual constructor(
|
||||||
private val logger: Kermit,
|
private val logger: Kermit,
|
||||||
settingsPref: Settings,
|
private val preferenceManager: PreferenceManager,
|
||||||
spotiFlyerDatabase: SpotiFlyerDatabase,
|
spotiFlyerDatabase: SpotiFlyerDatabase,
|
||||||
) {
|
) {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
@ -54,7 +54,7 @@ actual class Dir actual constructor(
|
|||||||
actual fun imageCacheDir(): String = methods.value.platformActions.imageCacheDir
|
actual fun imageCacheDir(): String = methods.value.platformActions.imageCacheDir
|
||||||
|
|
||||||
// fun call in order to always access Updated Value
|
// fun call in order to always access Updated Value
|
||||||
actual fun defaultDir(): String = (settings.getStringOrNull(DirKey) ?: defaultBaseDir) +
|
actual fun defaultDir(): String = (preferenceManager.downloadDir ?: defaultBaseDir) +
|
||||||
File.separator + "SpotiFlyer" + File.separator
|
File.separator + "SpotiFlyer" + File.separator
|
||||||
|
|
||||||
actual fun isPresent(path: String): Boolean = File(path).exists()
|
actual fun isPresent(path: String): Boolean = File(path).exists()
|
||||||
@ -202,5 +202,4 @@ actual class Dir actual constructor(
|
|||||||
private val parallelExecutor = ParallelExecutor(Dispatchers.IO)
|
private val parallelExecutor = ParallelExecutor(Dispatchers.IO)
|
||||||
|
|
||||||
actual val db: Database? = spotiFlyerDatabase.instance
|
actual val db: Database? = spotiFlyerDatabase.instance
|
||||||
actual val settings: Settings = settingsPref
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package com.shabinder.common.di.saavn
|
package com.shabinder.common.di.providers.requests.saavn
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import io.ktor.util.InternalAPI
|
import io.ktor.util.*
|
||||||
import io.ktor.util.decodeBase64Bytes
|
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
import javax.crypto.SecretKey
|
import javax.crypto.SecretKey
|
@ -20,13 +20,8 @@ import co.touchlab.kermit.Kermit
|
|||||||
import com.russhwolf.settings.Settings
|
import com.russhwolf.settings.Settings
|
||||||
import com.shabinder.common.database.databaseModule
|
import com.shabinder.common.database.databaseModule
|
||||||
import com.shabinder.common.database.getLogger
|
import com.shabinder.common.database.getLogger
|
||||||
import com.shabinder.common.di.audioToMp3.AudioToMp3
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import com.shabinder.common.di.providers.GaanaProvider
|
import com.shabinder.common.di.providers.providersModule
|
||||||
import com.shabinder.common.di.providers.SaavnProvider
|
|
||||||
import com.shabinder.common.di.providers.SpotifyProvider
|
|
||||||
import com.shabinder.common.di.providers.YoutubeMp3
|
|
||||||
import com.shabinder.common.di.providers.YoutubeMusic
|
|
||||||
import com.shabinder.common.di.providers.YoutubeProvider
|
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import io.ktor.client.features.*
|
import io.ktor.client.features.*
|
||||||
import io.ktor.client.features.json.*
|
import io.ktor.client.features.json.*
|
||||||
@ -42,7 +37,11 @@ import kotlin.native.concurrent.ThreadLocal
|
|||||||
fun initKoin(enableNetworkLogs: Boolean = false, appDeclaration: KoinAppDeclaration = {}) =
|
fun initKoin(enableNetworkLogs: Boolean = false, appDeclaration: KoinAppDeclaration = {}) =
|
||||||
startKoin {
|
startKoin {
|
||||||
appDeclaration()
|
appDeclaration()
|
||||||
modules(commonModule(enableNetworkLogs = enableNetworkLogs), databaseModule())
|
modules(
|
||||||
|
commonModule(enableNetworkLogs = enableNetworkLogs),
|
||||||
|
providersModule(),
|
||||||
|
databaseModule()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by IOS
|
// Called by IOS
|
||||||
@ -52,16 +51,9 @@ fun commonModule(enableNetworkLogs: Boolean) = module {
|
|||||||
single { createHttpClient(enableNetworkLogs = enableNetworkLogs) }
|
single { createHttpClient(enableNetworkLogs = enableNetworkLogs) }
|
||||||
single { Dir(get(), get(), get()) }
|
single { Dir(get(), get(), get()) }
|
||||||
single { Settings() }
|
single { Settings() }
|
||||||
|
single { PreferenceManager(get()) }
|
||||||
single { Kermit(getLogger()) }
|
single { Kermit(getLogger()) }
|
||||||
single { TokenStore(get(), get()) }
|
single { TokenStore(get(), get()) }
|
||||||
single { AudioToMp3(get(), get()) }
|
|
||||||
single { SpotifyProvider(get(), get(), get()) }
|
|
||||||
single { GaanaProvider(get(), get(), get()) }
|
|
||||||
single { SaavnProvider(get(), get(), get(), get()) }
|
|
||||||
single { YoutubeProvider(get(), get(), get()) }
|
|
||||||
single { YoutubeMp3(get(), get()) }
|
|
||||||
single { YoutubeMusic(get(), get(), get(), get(), get()) }
|
|
||||||
single { FetchPlatformQueryResult(get(), get(), get(), get(), get(), get(), get(), get(), get()) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ThreadLocal
|
@ThreadLocal
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
package com.shabinder.common.di
|
package com.shabinder.common.di
|
||||||
|
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.russhwolf.settings.Settings
|
|
||||||
import com.shabinder.common.database.SpotiFlyerDatabase
|
import com.shabinder.common.database.SpotiFlyerDatabase
|
||||||
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import com.shabinder.common.di.utils.removeIllegalChars
|
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
|
||||||
@ -30,18 +30,12 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
const val DirKey = "downloadDir"
|
|
||||||
const val AnalyticsKey = "analytics"
|
|
||||||
const val FirstLaunch = "firstLaunch"
|
|
||||||
const val DonationInterval = "donationInterval"
|
|
||||||
|
|
||||||
expect class Dir(
|
expect class Dir(
|
||||||
logger: Kermit,
|
logger: Kermit,
|
||||||
settingsPref: Settings,
|
preferenceManager: PreferenceManager,
|
||||||
spotiFlyerDatabase: SpotiFlyerDatabase,
|
spotiFlyerDatabase: SpotiFlyerDatabase,
|
||||||
) {
|
) {
|
||||||
val db: Database?
|
val db: Database?
|
||||||
val settings: Settings
|
|
||||||
fun isPresent(path: String): Boolean
|
fun isPresent(path: String): Boolean
|
||||||
fun fileSeparator(): String
|
fun fileSeparator(): String
|
||||||
fun defaultDir(): String
|
fun defaultDir(): String
|
||||||
@ -54,22 +48,6 @@ expect class Dir(
|
|||||||
fun addToLibrary(path: String)
|
fun addToLibrary(path: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
val Dir.isAnalyticsEnabled get() = settings.getBooleanOrNull(AnalyticsKey) ?: false
|
|
||||||
fun Dir.toggleAnalytics(enabled: Boolean) = settings.putBoolean(AnalyticsKey, enabled)
|
|
||||||
|
|
||||||
fun Dir.setDownloadDirectory(newBasePath: String) = settings.putString(DirKey, newBasePath)
|
|
||||||
|
|
||||||
val Dir.getDonationOffset: Int get() = (settings.getIntOrNull(DonationInterval) ?: 3).also {
|
|
||||||
// Min. Donation Asking Interval is `3`
|
|
||||||
if (it < 3) setDonationOffset(3) else setDonationOffset(it - 1)
|
|
||||||
}
|
|
||||||
fun Dir.setDonationOffset(offset: Int = 5) = settings.putInt(DonationInterval, offset)
|
|
||||||
|
|
||||||
val Dir.isFirstLaunch get() = settings.getBooleanOrNull(FirstLaunch) ?: true
|
|
||||||
fun Dir.firstLaunchDone() {
|
|
||||||
settings.putBoolean(FirstLaunch, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call this function at startup!
|
* Call this function at startup!
|
||||||
* */
|
* */
|
||||||
|
@ -18,7 +18,6 @@ package com.shabinder.common.di
|
|||||||
|
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.shabinder.common.database.DownloadRecordDatabaseQueries
|
import com.shabinder.common.database.DownloadRecordDatabaseQueries
|
||||||
import com.shabinder.common.di.audioToMp3.AudioToMp3
|
|
||||||
import com.shabinder.common.di.providers.GaanaProvider
|
import com.shabinder.common.di.providers.GaanaProvider
|
||||||
import com.shabinder.common.di.providers.SaavnProvider
|
import com.shabinder.common.di.providers.SaavnProvider
|
||||||
import com.shabinder.common.di.providers.SpotifyProvider
|
import com.shabinder.common.di.providers.SpotifyProvider
|
||||||
@ -26,6 +25,7 @@ import com.shabinder.common.di.providers.YoutubeMp3
|
|||||||
import com.shabinder.common.di.providers.YoutubeMusic
|
import com.shabinder.common.di.providers.YoutubeMusic
|
||||||
import com.shabinder.common.di.providers.YoutubeProvider
|
import com.shabinder.common.di.providers.YoutubeProvider
|
||||||
import com.shabinder.common.di.providers.get
|
import com.shabinder.common.di.providers.get
|
||||||
|
import com.shabinder.common.di.providers.requests.audioToMp3.AudioToMp3
|
||||||
import com.shabinder.common.models.PlatformQueryResult
|
import com.shabinder.common.models.PlatformQueryResult
|
||||||
import com.shabinder.common.models.SpotiFlyerException
|
import com.shabinder.common.models.SpotiFlyerException
|
||||||
import com.shabinder.common.models.TrackDetails
|
import com.shabinder.common.models.TrackDetails
|
||||||
@ -35,6 +35,7 @@ import com.shabinder.common.models.event.coroutines.flatMapError
|
|||||||
import com.shabinder.common.models.event.coroutines.success
|
import com.shabinder.common.models.event.coroutines.success
|
||||||
import com.shabinder.common.models.spotify.Source
|
import com.shabinder.common.models.spotify.Source
|
||||||
import com.shabinder.common.requireNotNull
|
import com.shabinder.common.requireNotNull
|
||||||
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@ -137,6 +138,7 @@ class FetchPlatformQueryResult(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
private fun addToDatabaseAsync(link: String, result: PlatformQueryResult) {
|
private fun addToDatabaseAsync(link: String, result: PlatformQueryResult) {
|
||||||
GlobalScope.launch(dispatcherIO) {
|
GlobalScope.launch(dispatcherIO) {
|
||||||
db?.add(
|
db?.add(
|
||||||
|
@ -18,7 +18,7 @@ package com.shabinder.common.di
|
|||||||
|
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.shabinder.common.database.TokenDBQueries
|
import com.shabinder.common.database.TokenDBQueries
|
||||||
import com.shabinder.common.di.spotify.authenticateSpotify
|
import com.shabinder.common.di.providers.requests.spotify.authenticateSpotify
|
||||||
import com.shabinder.common.models.spotify.TokenData
|
import com.shabinder.common.models.spotify.TokenData
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.shabinder.common.di.preference
|
||||||
|
|
||||||
|
import com.russhwolf.settings.Settings
|
||||||
|
|
||||||
|
class PreferenceManager(settings: Settings): Settings by settings {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val DirKey = "downloadDir"
|
||||||
|
const val AnalyticsKey = "analytics"
|
||||||
|
const val FirstLaunch = "firstLaunch"
|
||||||
|
const val DonationInterval = "donationInterval"
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ANALYTICS */
|
||||||
|
val isAnalyticsEnabled get() = getBooleanOrNull(AnalyticsKey) ?: false
|
||||||
|
fun toggleAnalytics(enabled: Boolean) = putBoolean(AnalyticsKey, enabled)
|
||||||
|
|
||||||
|
|
||||||
|
/* DOWNLOAD DIRECTORY */
|
||||||
|
val downloadDir get() = getStringOrNull(DirKey)
|
||||||
|
fun setDownloadDirectory(newBasePath: String) = putString(DirKey, newBasePath)
|
||||||
|
|
||||||
|
|
||||||
|
/* OFFSET FOR WHEN TO ASK FOR SUPPORT */
|
||||||
|
val getDonationOffset: Int get() = (getIntOrNull(DonationInterval) ?: 3).also {
|
||||||
|
// Min. Donation Asking Interval is `3`
|
||||||
|
if (it < 3) setDonationOffset(3) else setDonationOffset(it - 1)
|
||||||
|
}
|
||||||
|
fun setDonationOffset(offset: Int = 5) = putInt(DonationInterval, offset)
|
||||||
|
|
||||||
|
|
||||||
|
/* TO CHECK IF THIS IS APP's FIRST LAUNCH */
|
||||||
|
val isFirstLaunch get() = getBooleanOrNull(FirstLaunch) ?: true
|
||||||
|
fun firstLaunchDone() = putBoolean(FirstLaunch, false)
|
||||||
|
}
|
@ -19,7 +19,7 @@ package com.shabinder.common.di.providers
|
|||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.shabinder.common.di.Dir
|
import com.shabinder.common.di.Dir
|
||||||
import com.shabinder.common.di.finalOutputDir
|
import com.shabinder.common.di.finalOutputDir
|
||||||
import com.shabinder.common.di.gaana.GaanaRequests
|
import com.shabinder.common.di.providers.requests.gaana.GaanaRequests
|
||||||
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.SpotiFlyerException
|
import com.shabinder.common.models.SpotiFlyerException
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.shabinder.common.di.providers
|
||||||
|
|
||||||
|
import com.shabinder.common.di.FetchPlatformQueryResult
|
||||||
|
import com.shabinder.common.di.providers.requests.audioToMp3.AudioToMp3
|
||||||
|
import org.koin.dsl.module
|
||||||
|
|
||||||
|
fun providersModule() = module {
|
||||||
|
single { AudioToMp3(get(), get()) }
|
||||||
|
single { SpotifyProvider(get(), get(), get()) }
|
||||||
|
single { GaanaProvider(get(), get(), get()) }
|
||||||
|
single { SaavnProvider(get(), get(), get(), get()) }
|
||||||
|
single { YoutubeProvider(get(), get(), get()) }
|
||||||
|
single { YoutubeMp3(get(), get()) }
|
||||||
|
single { YoutubeMusic(get(), get(), get(), get(), get()) }
|
||||||
|
single { FetchPlatformQueryResult(get(), get(), get(), get(), get(), get(), get(), get(), get()) }
|
||||||
|
}
|
@ -2,9 +2,9 @@ package com.shabinder.common.di.providers
|
|||||||
|
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.shabinder.common.di.Dir
|
import com.shabinder.common.di.Dir
|
||||||
import com.shabinder.common.di.audioToMp3.AudioToMp3
|
|
||||||
import com.shabinder.common.di.finalOutputDir
|
import com.shabinder.common.di.finalOutputDir
|
||||||
import com.shabinder.common.di.saavn.JioSaavnRequests
|
import com.shabinder.common.di.providers.requests.audioToMp3.AudioToMp3
|
||||||
|
import com.shabinder.common.di.providers.requests.saavn.JioSaavnRequests
|
||||||
import com.shabinder.common.di.utils.removeIllegalChars
|
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
|
||||||
|
@ -22,8 +22,8 @@ import com.shabinder.common.di.TokenStore
|
|||||||
import com.shabinder.common.di.createHttpClient
|
import com.shabinder.common.di.createHttpClient
|
||||||
import com.shabinder.common.di.finalOutputDir
|
import com.shabinder.common.di.finalOutputDir
|
||||||
import com.shabinder.common.di.globalJson
|
import com.shabinder.common.di.globalJson
|
||||||
import com.shabinder.common.di.spotify.SpotifyRequests
|
import com.shabinder.common.di.providers.requests.spotify.SpotifyRequests
|
||||||
import com.shabinder.common.di.spotify.authenticateSpotify
|
import com.shabinder.common.di.providers.requests.spotify.authenticateSpotify
|
||||||
import com.shabinder.common.models.DownloadStatus
|
import com.shabinder.common.models.DownloadStatus
|
||||||
import com.shabinder.common.models.NativeAtomicReference
|
import com.shabinder.common.models.NativeAtomicReference
|
||||||
import com.shabinder.common.models.PlatformQueryResult
|
import com.shabinder.common.models.PlatformQueryResult
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
package com.shabinder.common.di.providers
|
package com.shabinder.common.di.providers
|
||||||
|
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.shabinder.common.di.youtubeMp3.Yt1sMp3
|
import com.shabinder.common.di.providers.requests.youtubeMp3.Yt1sMp3
|
||||||
import com.shabinder.common.models.corsApi
|
import com.shabinder.common.models.corsApi
|
||||||
import com.shabinder.common.models.event.coroutines.SuspendableEvent
|
import com.shabinder.common.models.event.coroutines.SuspendableEvent
|
||||||
import com.shabinder.common.models.event.coroutines.map
|
import com.shabinder.common.models.event.coroutines.map
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
package com.shabinder.common.di.providers
|
package com.shabinder.common.di.providers
|
||||||
|
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.shabinder.common.di.audioToMp3.AudioToMp3
|
import com.shabinder.common.di.providers.requests.audioToMp3.AudioToMp3
|
||||||
import com.shabinder.common.models.SpotiFlyerException
|
import com.shabinder.common.models.SpotiFlyerException
|
||||||
import com.shabinder.common.models.TrackDetails
|
import com.shabinder.common.models.TrackDetails
|
||||||
import com.shabinder.common.models.YoutubeTrack
|
import com.shabinder.common.models.YoutubeTrack
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package com.shabinder.common.di.audioToMp3
|
package com.shabinder.common.di.providers.requests.audioToMp3
|
||||||
|
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.shabinder.common.models.AudioQuality
|
import com.shabinder.common.models.AudioQuality
|
@ -14,7 +14,7 @@
|
|||||||
* * along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* * along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.shabinder.common.di.gaana
|
package com.shabinder.common.di.providers.requests.gaana
|
||||||
|
|
||||||
import com.shabinder.common.models.corsApi
|
import com.shabinder.common.models.corsApi
|
||||||
import com.shabinder.common.models.gaana.GaanaAlbum
|
import com.shabinder.common.models.gaana.GaanaAlbum
|
@ -1,8 +1,8 @@
|
|||||||
package com.shabinder.common.di.saavn
|
package com.shabinder.common.di.providers.requests.saavn
|
||||||
|
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.shabinder.common.di.audioToMp3.AudioToMp3
|
|
||||||
import com.shabinder.common.di.globalJson
|
import com.shabinder.common.di.globalJson
|
||||||
|
import com.shabinder.common.di.providers.requests.audioToMp3.AudioToMp3
|
||||||
import com.shabinder.common.models.corsApi
|
import com.shabinder.common.models.corsApi
|
||||||
import com.shabinder.common.models.event.coroutines.SuspendableEvent
|
import com.shabinder.common.models.event.coroutines.SuspendableEvent
|
||||||
import com.shabinder.common.models.event.coroutines.map
|
import com.shabinder.common.models.event.coroutines.map
|
@ -1,4 +1,6 @@
|
|||||||
package com.shabinder.common.di.saavn
|
package com.shabinder.common.di.providers.requests.saavn
|
||||||
|
|
||||||
|
import com.shabinder.common.di.utils.unescape
|
||||||
|
|
||||||
expect suspend fun decryptURL(url: String): String
|
expect suspend fun decryptURL(url: String): String
|
||||||
|
|
@ -14,7 +14,7 @@
|
|||||||
* * along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* * along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.shabinder.common.di.spotify
|
package com.shabinder.common.di.providers.requests.spotify
|
||||||
|
|
||||||
import com.shabinder.common.di.globalJson
|
import com.shabinder.common.di.globalJson
|
||||||
import com.shabinder.common.models.SpotiFlyerException
|
import com.shabinder.common.models.SpotiFlyerException
|
@ -14,7 +14,7 @@
|
|||||||
* * along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* * along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.shabinder.common.di.spotify
|
package com.shabinder.common.di.providers.requests.spotify
|
||||||
|
|
||||||
import com.shabinder.common.models.NativeAtomicReference
|
import com.shabinder.common.models.NativeAtomicReference
|
||||||
import com.shabinder.common.models.corsApi
|
import com.shabinder.common.models.corsApi
|
@ -14,7 +14,7 @@
|
|||||||
* * along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* * along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.shabinder.common.di.youtubeMp3
|
package com.shabinder.common.di.providers.requests.youtubeMp3
|
||||||
|
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.shabinder.common.models.corsApi
|
import com.shabinder.common.models.corsApi
|
@ -1,4 +1,4 @@
|
|||||||
package com.shabinder.common.di.saavn
|
package com.shabinder.common.di.utils
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JSON UTILS
|
* JSON UTILS
|
@ -19,6 +19,7 @@ package com.shabinder.common.di
|
|||||||
import com.shabinder.common.di.utils.ParallelExecutor
|
import com.shabinder.common.di.utils.ParallelExecutor
|
||||||
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.SpotiFlyerException
|
||||||
import com.shabinder.common.models.TrackDetails
|
import com.shabinder.common.models.TrackDetails
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -40,41 +41,43 @@ actual suspend fun downloadTracks(
|
|||||||
) {
|
) {
|
||||||
list.forEach { trackDetails ->
|
list.forEach { trackDetails ->
|
||||||
DownloadScope.execute { // Send Download to Pool.
|
DownloadScope.execute { // Send Download to Pool.
|
||||||
val url = fetcher.findMp3DownloadLink(trackDetails)
|
fetcher.findMp3DownloadLink(trackDetails).fold(
|
||||||
if (!url.isNullOrBlank()) { // Successfully Grabbed Mp3 URL
|
success = { url ->
|
||||||
downloadFile(url).collect {
|
downloadFile(url).collect {
|
||||||
when (it) {
|
when (it) {
|
||||||
is DownloadResult.Error -> {
|
is DownloadResult.Error -> {
|
||||||
DownloadProgressFlow.emit(
|
DownloadProgressFlow.emit(
|
||||||
DownloadProgressFlow.replayCache.getOrElse(
|
DownloadProgressFlow.replayCache.getOrElse(
|
||||||
0
|
0
|
||||||
) { hashMapOf() }.apply { set(trackDetails.title, DownloadStatus.Failed) }
|
) { hashMapOf() }.apply { set(trackDetails.title, DownloadStatus.Failed(it.cause ?: SpotiFlyerException.UnknownReason(it.cause))) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is DownloadResult.Progress -> {
|
is DownloadResult.Progress -> {
|
||||||
DownloadProgressFlow.emit(
|
DownloadProgressFlow.emit(
|
||||||
DownloadProgressFlow.replayCache.getOrElse(
|
DownloadProgressFlow.replayCache.getOrElse(
|
||||||
0
|
0
|
||||||
) { hashMapOf() }.apply { set(trackDetails.title, DownloadStatus.Downloading(it.progress)) }
|
) { hashMapOf() }.apply { set(trackDetails.title, DownloadStatus.Downloading(it.progress)) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is DownloadResult.Success -> { // Todo clear map
|
is DownloadResult.Success -> { // Todo clear map
|
||||||
dir.saveFileWithMetadata(it.byteArray, trackDetails) {}
|
dir.saveFileWithMetadata(it.byteArray, trackDetails) {}
|
||||||
DownloadProgressFlow.emit(
|
DownloadProgressFlow.emit(
|
||||||
DownloadProgressFlow.replayCache.getOrElse(
|
DownloadProgressFlow.replayCache.getOrElse(
|
||||||
0
|
0
|
||||||
) { hashMapOf() }.apply { set(trackDetails.title, DownloadStatus.Downloaded) }
|
) { hashMapOf() }.apply { set(trackDetails.title, DownloadStatus.Downloaded) }
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
failure = { error ->
|
||||||
|
DownloadProgressFlow.emit(
|
||||||
|
DownloadProgressFlow.replayCache.getOrElse(
|
||||||
|
0
|
||||||
|
) { hashMapOf() }.apply { set(trackDetails.title, DownloadStatus.Failed(error)) }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
)
|
||||||
DownloadProgressFlow.emit(
|
|
||||||
DownloadProgressFlow.replayCache.getOrElse(
|
|
||||||
0
|
|
||||||
) { hashMapOf() }.apply { set(trackDetails.title, DownloadStatus.Failed) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,8 @@ import androidx.compose.ui.graphics.ImageBitmap
|
|||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.mpatric.mp3agic.Mp3File
|
import com.mpatric.mp3agic.Mp3File
|
||||||
import com.russhwolf.settings.Settings
|
|
||||||
import com.shabinder.common.database.SpotiFlyerDatabase
|
import com.shabinder.common.database.SpotiFlyerDatabase
|
||||||
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import com.shabinder.common.models.TrackDetails
|
import com.shabinder.common.models.TrackDetails
|
||||||
import com.shabinder.database.Database
|
import com.shabinder.database.Database
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -40,7 +40,7 @@ import javax.imageio.ImageIO
|
|||||||
|
|
||||||
actual class Dir actual constructor(
|
actual class Dir actual constructor(
|
||||||
private val logger: Kermit,
|
private val logger: Kermit,
|
||||||
settingsPref: Settings,
|
private val preferenceManager: PreferenceManager,
|
||||||
spotiFlyerDatabase: SpotiFlyerDatabase,
|
spotiFlyerDatabase: SpotiFlyerDatabase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ actual class Dir actual constructor(
|
|||||||
|
|
||||||
private val defaultBaseDir = System.getProperty("user.home")
|
private val defaultBaseDir = System.getProperty("user.home")
|
||||||
|
|
||||||
actual fun defaultDir(): String = (settings.getStringOrNull(DirKey) ?: defaultBaseDir) + fileSeparator() +
|
actual fun defaultDir(): String = (preferenceManager.downloadDir ?: defaultBaseDir) + fileSeparator() +
|
||||||
"SpotiFlyer" + fileSeparator()
|
"SpotiFlyer" + fileSeparator()
|
||||||
|
|
||||||
actual fun isPresent(path: String): Boolean = File(path).exists()
|
actual fun isPresent(path: String): Boolean = File(path).exists()
|
||||||
@ -199,7 +199,6 @@ actual class Dir actual constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
actual val db: Database? = spotiFlyerDatabase.instance
|
actual val db: Database? = spotiFlyerDatabase.instance
|
||||||
actual val settings: Settings = settingsPref
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun BufferedImage.toImageBitmap() = Image.makeFromEncoded(
|
fun BufferedImage.toImageBitmap() = Image.makeFromEncoded(
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package com.shabinder.common.di.saavn
|
package com.shabinder.common.di.providers.requests.saavn
|
||||||
|
|
||||||
import io.ktor.util.InternalAPI
|
import io.ktor.util.*
|
||||||
import io.ktor.util.decodeBase64Bytes
|
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
import javax.crypto.SecretKey
|
import javax.crypto.SecretKey
|
@ -1,8 +1,8 @@
|
|||||||
package com.shabinder.common.di
|
package com.shabinder.common.di
|
||||||
|
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.russhwolf.settings.Settings
|
|
||||||
import com.shabinder.common.database.SpotiFlyerDatabase
|
import com.shabinder.common.database.SpotiFlyerDatabase
|
||||||
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import com.shabinder.common.models.TrackDetails
|
import com.shabinder.common.models.TrackDetails
|
||||||
import com.shabinder.database.Database
|
import com.shabinder.database.Database
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
@ -24,7 +24,7 @@ import platform.UIKit.UIImageJPEGRepresentation
|
|||||||
|
|
||||||
actual class Dir actual constructor(
|
actual class Dir actual constructor(
|
||||||
val logger: Kermit,
|
val logger: Kermit,
|
||||||
settingsPref: Settings,
|
private val preferenceManager: PreferenceManager,
|
||||||
spotiFlyerDatabase: SpotiFlyerDatabase,
|
spotiFlyerDatabase: SpotiFlyerDatabase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ actual class Dir actual constructor(
|
|||||||
private val defaultBaseDir = NSFileManager.defaultManager.URLForDirectory(NSMusicDirectory, NSUserDomainMask, null, true, null)!!.path!!
|
private val defaultBaseDir = NSFileManager.defaultManager.URLForDirectory(NSMusicDirectory, NSUserDomainMask, null, true, null)!!.path!!
|
||||||
|
|
||||||
// TODO Error Handling
|
// TODO Error Handling
|
||||||
actual fun defaultDir(): String = (settings.getStringOrNull(DirKey) ?: defaultBaseDir) +
|
actual fun defaultDir(): String = (preferenceManager.downloadDir ?: defaultBaseDir) +
|
||||||
fileSeparator() + "SpotiFlyer" + fileSeparator()
|
fileSeparator() + "SpotiFlyer" + fileSeparator()
|
||||||
|
|
||||||
private val defaultDirURL: NSURL by lazy {
|
private val defaultDirURL: NSURL by lazy {
|
||||||
@ -176,6 +176,5 @@ actual class Dir actual constructor(
|
|||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
actual val settings: Settings = settingsPref
|
|
||||||
actual val db: Database? = spotiFlyerDatabase.instance
|
actual val db: Database? = spotiFlyerDatabase.instance
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package com.shabinder.common.di
|
|||||||
|
|
||||||
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.SpotiFlyerException
|
||||||
import com.shabinder.common.models.TrackDetails
|
import com.shabinder.common.models.TrackDetails
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -41,29 +42,31 @@ actual suspend fun downloadTracks(
|
|||||||
list.forEach { track ->
|
list.forEach { track ->
|
||||||
withContext(dispatcherIO) {
|
withContext(dispatcherIO) {
|
||||||
allTracksStatus[track.title] = DownloadStatus.Queued
|
allTracksStatus[track.title] = DownloadStatus.Queued
|
||||||
val url = fetcher.findMp3DownloadLink(track)
|
fetcher.findMp3DownloadLink(track).fold(
|
||||||
if (!url.isNullOrBlank()) { // Successfully Grabbed Mp3 URL
|
success = { url ->
|
||||||
downloadFile(url).collect {
|
downloadFile(url).collect {
|
||||||
when (it) {
|
when (it) {
|
||||||
is DownloadResult.Success -> {
|
is DownloadResult.Success -> {
|
||||||
println("Download Completed")
|
println("Download Completed")
|
||||||
dir.saveFileWithMetadata(it.byteArray, track) {}
|
dir.saveFileWithMetadata(it.byteArray, track) {}
|
||||||
}
|
}
|
||||||
is DownloadResult.Error -> {
|
is DownloadResult.Error -> {
|
||||||
allTracksStatus[track.title] = DownloadStatus.Failed
|
allTracksStatus[track.title] = DownloadStatus.Failed(it.cause ?: SpotiFlyerException.UnknownReason(it.cause))
|
||||||
println("Download Error: ${track.title}")
|
println("Download Error: ${track.title}")
|
||||||
}
|
}
|
||||||
is DownloadResult.Progress -> {
|
is DownloadResult.Progress -> {
|
||||||
allTracksStatus[track.title] = DownloadStatus.Downloading(it.progress)
|
allTracksStatus[track.title] = DownloadStatus.Downloading(it.progress)
|
||||||
println("Download Progress: ${it.progress} : ${track.title}")
|
println("Download Progress: ${it.progress} : ${track.title}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
DownloadProgressFlow.emit(allTracksStatus)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
failure = { error ->
|
||||||
|
allTracksStatus[track.title] = DownloadStatus.Failed(error)
|
||||||
DownloadProgressFlow.emit(allTracksStatus)
|
DownloadProgressFlow.emit(allTracksStatus)
|
||||||
}
|
}
|
||||||
} else {
|
)
|
||||||
allTracksStatus[track.title] = DownloadStatus.Failed
|
|
||||||
DownloadProgressFlow.emit(allTracksStatus)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,13 +17,13 @@
|
|||||||
package com.shabinder.common.di
|
package com.shabinder.common.di
|
||||||
|
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.russhwolf.settings.Settings
|
|
||||||
import com.shabinder.common.database.SpotiFlyerDatabase
|
import com.shabinder.common.database.SpotiFlyerDatabase
|
||||||
import com.shabinder.common.di.gaana.corsApi
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import com.shabinder.common.di.utils.removeIllegalChars
|
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.common.models.corsApi
|
||||||
import com.shabinder.database.Database
|
import com.shabinder.database.Database
|
||||||
import kotlinext.js.Object
|
import kotlinext.js.Object
|
||||||
import kotlinext.js.js
|
import kotlinext.js.js
|
||||||
@ -34,7 +34,7 @@ import org.w3c.dom.ImageBitmap
|
|||||||
|
|
||||||
actual class Dir actual constructor(
|
actual class Dir actual constructor(
|
||||||
private val logger: Kermit,
|
private val logger: Kermit,
|
||||||
settingsPref: Settings,
|
private val preferenceManager: PreferenceManager,
|
||||||
spotiFlyerDatabase: SpotiFlyerDatabase,
|
spotiFlyerDatabase: SpotiFlyerDatabase,
|
||||||
) {
|
) {
|
||||||
/*init {
|
/*init {
|
||||||
@ -116,7 +116,6 @@ actual class Dir actual constructor(
|
|||||||
private suspend fun freshImage(url: String): ImageBitmap? = null
|
private suspend fun freshImage(url: String): ImageBitmap? = null
|
||||||
|
|
||||||
actual val db: Database? = spotiFlyerDatabase.instance
|
actual val db: Database? = spotiFlyerDatabase.instance
|
||||||
actual val settings: Settings = settingsPref
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ByteArray.toArrayBuffer(): ArrayBuffer {
|
fun ByteArray.toArrayBuffer(): ArrayBuffer {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package com.shabinder.common.di.saavn
|
package com.shabinder.common.di.providers.requests.saavn
|
||||||
|
|
||||||
actual suspend fun decryptURL(url: String): String {
|
actual suspend fun decryptURL(url: String): String {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
@ -22,6 +22,7 @@ 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.di.Picture
|
import com.shabinder.common.di.Picture
|
||||||
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import com.shabinder.common.list.integration.SpotiFlyerListImpl
|
import com.shabinder.common.list.integration.SpotiFlyerListImpl
|
||||||
import com.shabinder.common.models.Consumer
|
import com.shabinder.common.models.Consumer
|
||||||
import com.shabinder.common.models.DownloadStatus
|
import com.shabinder.common.models.DownloadStatus
|
||||||
@ -67,6 +68,7 @@ interface SpotiFlyerList {
|
|||||||
val storeFactory: StoreFactory
|
val storeFactory: StoreFactory
|
||||||
val fetchQuery: FetchPlatformQueryResult
|
val fetchQuery: FetchPlatformQueryResult
|
||||||
val dir: Dir
|
val dir: Dir
|
||||||
|
val preferenceManager: PreferenceManager
|
||||||
val link: String
|
val link: String
|
||||||
val listOutput: Consumer<Output>
|
val listOutput: Consumer<Output>
|
||||||
val downloadProgressFlow: MutableSharedFlow<HashMap<String, DownloadStatus>>
|
val downloadProgressFlow: MutableSharedFlow<HashMap<String, DownloadStatus>>
|
||||||
|
@ -22,7 +22,6 @@ import com.arkivanov.decompose.lifecycle.doOnResume
|
|||||||
import com.arkivanov.decompose.value.Value
|
import com.arkivanov.decompose.value.Value
|
||||||
import com.shabinder.common.caching.Cache
|
import com.shabinder.common.caching.Cache
|
||||||
import com.shabinder.common.di.Picture
|
import com.shabinder.common.di.Picture
|
||||||
import com.shabinder.common.di.setDonationOffset
|
|
||||||
import com.shabinder.common.di.utils.asValue
|
import com.shabinder.common.di.utils.asValue
|
||||||
import com.shabinder.common.list.SpotiFlyerList
|
import com.shabinder.common.list.SpotiFlyerList
|
||||||
import com.shabinder.common.list.SpotiFlyerList.Dependencies
|
import com.shabinder.common.list.SpotiFlyerList.Dependencies
|
||||||
@ -48,6 +47,7 @@ internal class SpotiFlyerListImpl(
|
|||||||
instanceKeeper.getStore {
|
instanceKeeper.getStore {
|
||||||
SpotiFlyerListStoreProvider(
|
SpotiFlyerListStoreProvider(
|
||||||
dir = this.dir,
|
dir = this.dir,
|
||||||
|
preferenceManager = preferenceManager,
|
||||||
storeFactory = storeFactory,
|
storeFactory = storeFactory,
|
||||||
fetchQuery = fetchQuery,
|
fetchQuery = fetchQuery,
|
||||||
downloadProgressFlow = downloadProgressFlow,
|
downloadProgressFlow = downloadProgressFlow,
|
||||||
@ -79,7 +79,7 @@ internal class SpotiFlyerListImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun snoozeDonationDialog() {
|
override fun snoozeDonationDialog() {
|
||||||
dir.setDonationOffset(offset = 10)
|
preferenceManager.setDonationOffset(offset = 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun loadImage(url: String, isCover: Boolean): Picture {
|
override suspend fun loadImage(url: String, isCover: Boolean): Picture {
|
||||||
|
@ -24,7 +24,7 @@ import com.arkivanov.mvikotlin.extensions.coroutines.SuspendExecutor
|
|||||||
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.downloadTracks
|
import com.shabinder.common.di.downloadTracks
|
||||||
import com.shabinder.common.di.getDonationOffset
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import com.shabinder.common.list.SpotiFlyerList.State
|
import com.shabinder.common.list.SpotiFlyerList.State
|
||||||
import com.shabinder.common.list.store.SpotiFlyerListStore.Intent
|
import com.shabinder.common.list.store.SpotiFlyerListStore.Intent
|
||||||
import com.shabinder.common.models.DownloadStatus
|
import com.shabinder.common.models.DownloadStatus
|
||||||
@ -36,6 +36,7 @@ import kotlinx.coroutines.flow.collect
|
|||||||
|
|
||||||
internal class SpotiFlyerListStoreProvider(
|
internal class SpotiFlyerListStoreProvider(
|
||||||
private val dir: Dir,
|
private val dir: Dir,
|
||||||
|
private val preferenceManager: PreferenceManager,
|
||||||
private val storeFactory: StoreFactory,
|
private val storeFactory: StoreFactory,
|
||||||
private val fetchQuery: FetchPlatformQueryResult,
|
private val fetchQuery: FetchPlatformQueryResult,
|
||||||
private val link: String,
|
private val link: String,
|
||||||
@ -68,7 +69,7 @@ internal class SpotiFlyerListStoreProvider(
|
|||||||
dir.db?.downloadRecordDatabaseQueries?.getLastInsertId()?.executeAsOneOrNull()?.also {
|
dir.db?.downloadRecordDatabaseQueries?.getLastInsertId()?.executeAsOneOrNull()?.also {
|
||||||
// See if It's Time we can request for support for maintaining this project or not
|
// See if It's Time we can request for support for maintaining this project or not
|
||||||
fetchQuery.logger.d(message = { "Database List Last ID: $it" }, tag = "Database Last ID")
|
fetchQuery.logger.d(message = { "Database List Last ID: $it" }, tag = "Database Last ID")
|
||||||
val offset = dir.getDonationOffset
|
val offset = preferenceManager.getDonationOffset
|
||||||
dispatch(
|
dispatch(
|
||||||
Result.AskForSupport(
|
Result.AskForSupport(
|
||||||
// Every 3rd Interval or After some offset
|
// Every 3rd Interval or After some offset
|
||||||
|
@ -21,6 +21,7 @@ import com.arkivanov.decompose.value.Value
|
|||||||
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.Picture
|
import com.shabinder.common.di.Picture
|
||||||
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import com.shabinder.common.main.integration.SpotiFlyerMainImpl
|
import com.shabinder.common.main.integration.SpotiFlyerMainImpl
|
||||||
import com.shabinder.common.models.Consumer
|
import com.shabinder.common.models.Consumer
|
||||||
import com.shabinder.common.models.DownloadRecord
|
import com.shabinder.common.models.DownloadRecord
|
||||||
@ -63,6 +64,7 @@ interface SpotiFlyerMain {
|
|||||||
val storeFactory: StoreFactory
|
val storeFactory: StoreFactory
|
||||||
val database: Database?
|
val database: Database?
|
||||||
val dir: Dir
|
val dir: Dir
|
||||||
|
val preferenceManager: PreferenceManager
|
||||||
val mainAnalytics: Analytics
|
val mainAnalytics: Analytics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,10 @@ import com.shabinder.common.caching.Cache
|
|||||||
import com.shabinder.common.di.Picture
|
import com.shabinder.common.di.Picture
|
||||||
import com.shabinder.common.di.utils.asValue
|
import com.shabinder.common.di.utils.asValue
|
||||||
import com.shabinder.common.main.SpotiFlyerMain
|
import com.shabinder.common.main.SpotiFlyerMain
|
||||||
import com.shabinder.common.main.SpotiFlyerMain.*
|
import com.shabinder.common.main.SpotiFlyerMain.Dependencies
|
||||||
|
import com.shabinder.common.main.SpotiFlyerMain.HomeCategory
|
||||||
|
import com.shabinder.common.main.SpotiFlyerMain.Output
|
||||||
|
import com.shabinder.common.main.SpotiFlyerMain.State
|
||||||
import com.shabinder.common.main.store.SpotiFlyerMainStore.Intent
|
import com.shabinder.common.main.store.SpotiFlyerMainStore.Intent
|
||||||
import com.shabinder.common.main.store.SpotiFlyerMainStoreProvider
|
import com.shabinder.common.main.store.SpotiFlyerMainStoreProvider
|
||||||
import com.shabinder.common.main.store.getStore
|
import com.shabinder.common.main.store.getStore
|
||||||
@ -41,6 +44,7 @@ internal class SpotiFlyerMainImpl(
|
|||||||
private val store =
|
private val store =
|
||||||
instanceKeeper.getStore {
|
instanceKeeper.getStore {
|
||||||
SpotiFlyerMainStoreProvider(
|
SpotiFlyerMainStoreProvider(
|
||||||
|
preferenceManager = preferenceManager,
|
||||||
storeFactory = storeFactory,
|
storeFactory = storeFactory,
|
||||||
database = database,
|
database = database,
|
||||||
dir = dir
|
dir = dir
|
||||||
|
@ -22,8 +22,7 @@ import com.arkivanov.mvikotlin.core.store.Store
|
|||||||
import com.arkivanov.mvikotlin.core.store.StoreFactory
|
import com.arkivanov.mvikotlin.core.store.StoreFactory
|
||||||
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
|
||||||
import com.shabinder.common.di.isAnalyticsEnabled
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import com.shabinder.common.di.toggleAnalytics
|
|
||||||
import com.shabinder.common.main.SpotiFlyerMain
|
import com.shabinder.common.main.SpotiFlyerMain
|
||||||
import com.shabinder.common.main.SpotiFlyerMain.State
|
import com.shabinder.common.main.SpotiFlyerMain.State
|
||||||
import com.shabinder.common.main.store.SpotiFlyerMainStore.Intent
|
import com.shabinder.common.main.store.SpotiFlyerMainStore.Intent
|
||||||
@ -39,6 +38,7 @@ import kotlinx.coroutines.flow.map
|
|||||||
|
|
||||||
internal class SpotiFlyerMainStoreProvider(
|
internal class SpotiFlyerMainStoreProvider(
|
||||||
private val storeFactory: StoreFactory,
|
private val storeFactory: StoreFactory,
|
||||||
|
private val preferenceManager: PreferenceManager,
|
||||||
private val dir: Dir,
|
private val dir: Dir,
|
||||||
database: Database?
|
database: Database?
|
||||||
) {
|
) {
|
||||||
@ -76,7 +76,7 @@ internal class SpotiFlyerMainStoreProvider(
|
|||||||
|
|
||||||
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) {
|
||||||
dispatch(Result.ToggleAnalytics(dir.isAnalyticsEnabled))
|
dispatch(Result.ToggleAnalytics(preferenceManager.isAnalyticsEnabled))
|
||||||
updates?.collect {
|
updates?.collect {
|
||||||
dispatch(Result.ItemsLoaded(it))
|
dispatch(Result.ItemsLoaded(it))
|
||||||
}
|
}
|
||||||
@ -91,7 +91,7 @@ internal class SpotiFlyerMainStoreProvider(
|
|||||||
is Intent.SelectCategory -> dispatch(Result.CategoryChanged(intent.category))
|
is Intent.SelectCategory -> dispatch(Result.CategoryChanged(intent.category))
|
||||||
is Intent.ToggleAnalytics -> {
|
is Intent.ToggleAnalytics -> {
|
||||||
dispatch(Result.ToggleAnalytics(intent.enabled))
|
dispatch(Result.ToggleAnalytics(intent.enabled))
|
||||||
dir.toggleAnalytics(intent.enabled)
|
preferenceManager.toggleAnalytics(intent.enabled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import com.arkivanov.decompose.value.Value
|
|||||||
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.di.preference.PreferenceManager
|
||||||
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.Actions
|
import com.shabinder.common.models.Actions
|
||||||
@ -49,9 +50,10 @@ interface SpotiFlyerRoot {
|
|||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
val storeFactory: StoreFactory
|
val storeFactory: StoreFactory
|
||||||
val database: Database?
|
val database: Database?
|
||||||
val fetchPlatformQueryResult: FetchPlatformQueryResult
|
val fetchQuery: FetchPlatformQueryResult
|
||||||
val directories: Dir
|
val dir: Dir
|
||||||
val downloadProgressReport: MutableSharedFlow<HashMap<String, DownloadStatus>>
|
val preferenceManager: PreferenceManager
|
||||||
|
val downloadProgressFlow: MutableSharedFlow<HashMap<String, DownloadStatus>>
|
||||||
val actions: Actions
|
val actions: Actions
|
||||||
val analytics: Analytics
|
val analytics: Analytics
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ import com.arkivanov.decompose.router
|
|||||||
import com.arkivanov.decompose.statekeeper.Parcelable
|
import com.arkivanov.decompose.statekeeper.Parcelable
|
||||||
import com.arkivanov.decompose.statekeeper.Parcelize
|
import com.arkivanov.decompose.statekeeper.Parcelize
|
||||||
import com.arkivanov.decompose.value.Value
|
import com.arkivanov.decompose.value.Value
|
||||||
import com.shabinder.common.di.Dir
|
|
||||||
import com.shabinder.common.di.dispatcherIO
|
import com.shabinder.common.di.dispatcherIO
|
||||||
import com.shabinder.common.list.SpotiFlyerList
|
import com.shabinder.common.list.SpotiFlyerList
|
||||||
import com.shabinder.common.main.SpotiFlyerMain
|
import com.shabinder.common.main.SpotiFlyerMain
|
||||||
@ -39,6 +38,7 @@ import com.shabinder.common.root.SpotiFlyerRoot.Analytics
|
|||||||
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 kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -77,7 +77,7 @@ internal class SpotiFlyerRootImpl(
|
|||||||
instanceKeeper.ensureNeverFrozen()
|
instanceKeeper.ensureNeverFrozen()
|
||||||
methods.value = dependencies.actions.freeze()
|
methods.value = dependencies.actions.freeze()
|
||||||
/*Init App Launch & Authenticate Spotify Client*/
|
/*Init App Launch & Authenticate Spotify Client*/
|
||||||
initAppLaunchAndAuthenticateSpotify(dependencies.fetchPlatformQueryResult::authenticateSpotifyClient)
|
initAppLaunchAndAuthenticateSpotify(dependencies.fetchQuery::authenticateSpotifyClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val router =
|
private val router =
|
||||||
@ -128,6 +128,7 @@ internal class SpotiFlyerRootImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(DelicateCoroutinesApi::class)
|
||||||
private fun initAppLaunchAndAuthenticateSpotify(authenticator: suspend () -> Unit) {
|
private fun initAppLaunchAndAuthenticateSpotify(authenticator: suspend () -> Unit) {
|
||||||
GlobalScope.launch(dispatcherIO) {
|
GlobalScope.launch(dispatcherIO) {
|
||||||
analytics.appLaunchEvent()
|
analytics.appLaunchEvent()
|
||||||
@ -150,10 +151,7 @@ private fun spotiFlyerMain(componentContext: ComponentContext, output: Consumer<
|
|||||||
componentContext = componentContext,
|
componentContext = componentContext,
|
||||||
dependencies = object : SpotiFlyerMain.Dependencies, Dependencies by dependencies {
|
dependencies = object : SpotiFlyerMain.Dependencies, Dependencies by dependencies {
|
||||||
override val mainOutput: Consumer<SpotiFlyerMain.Output> = output
|
override val mainOutput: Consumer<SpotiFlyerMain.Output> = output
|
||||||
override val dir: Dir = directories
|
override val mainAnalytics = object : SpotiFlyerMain.Analytics , Analytics by analytics {}
|
||||||
override val mainAnalytics = object : SpotiFlyerMain.Analytics {
|
|
||||||
override fun donationDialogVisit() = analytics.donationDialogVisit()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -161,11 +159,8 @@ private fun spotiFlyerList(componentContext: ComponentContext, link: String, out
|
|||||||
SpotiFlyerList(
|
SpotiFlyerList(
|
||||||
componentContext = componentContext,
|
componentContext = componentContext,
|
||||||
dependencies = object : SpotiFlyerList.Dependencies, Dependencies by dependencies {
|
dependencies = object : SpotiFlyerList.Dependencies, Dependencies by dependencies {
|
||||||
override val fetchQuery = fetchPlatformQueryResult
|
|
||||||
override val dir: Dir = directories
|
|
||||||
override val link: String = link
|
override val link: String = link
|
||||||
override val listOutput: Consumer<SpotiFlyerList.Output> = output
|
override val listOutput: Consumer<SpotiFlyerList.Output> = output
|
||||||
override val downloadProgressFlow = downloadProgressReport
|
override val listAnalytics = object : SpotiFlyerList.Analytics, Analytics by analytics {}
|
||||||
override val listAnalytics = object : SpotiFlyerList.Analytics {}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -27,12 +27,21 @@ import com.arkivanov.decompose.extensions.compose.jetbrains.rememberRootComponen
|
|||||||
import com.arkivanov.mvikotlin.core.lifecycle.LifecycleRegistry
|
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.*
|
import com.shabinder.common.di.Dir
|
||||||
|
import com.shabinder.common.di.DownloadProgressFlow
|
||||||
|
import com.shabinder.common.di.FetchPlatformQueryResult
|
||||||
|
import com.shabinder.common.di.initKoin
|
||||||
|
import com.shabinder.common.di.isInternetAccessible
|
||||||
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import com.shabinder.common.models.Actions
|
import com.shabinder.common.models.Actions
|
||||||
import com.shabinder.common.models.PlatformActions
|
import com.shabinder.common.models.PlatformActions
|
||||||
import com.shabinder.common.models.TrackDetails
|
import com.shabinder.common.models.TrackDetails
|
||||||
import com.shabinder.common.root.SpotiFlyerRoot
|
import com.shabinder.common.root.SpotiFlyerRoot
|
||||||
import com.shabinder.common.uikit.*
|
import com.shabinder.common.uikit.SpotiFlyerColors
|
||||||
|
import com.shabinder.common.uikit.SpotiFlyerRootContent
|
||||||
|
import com.shabinder.common.uikit.SpotiFlyerShapes
|
||||||
|
import com.shabinder.common.uikit.SpotiFlyerTypography
|
||||||
|
import com.shabinder.common.uikit.colorOffWhite
|
||||||
import com.shabinder.database.Database
|
import com.shabinder.database.Database
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.piwik.java.tracking.PiwikTracker
|
import org.piwik.java.tracking.PiwikTracker
|
||||||
@ -79,10 +88,11 @@ private fun spotiFlyerRoot(componentContext: ComponentContext): SpotiFlyerRoot =
|
|||||||
componentContext = componentContext,
|
componentContext = componentContext,
|
||||||
dependencies = object : SpotiFlyerRoot.Dependencies {
|
dependencies = object : SpotiFlyerRoot.Dependencies {
|
||||||
override val storeFactory = DefaultStoreFactory
|
override val storeFactory = DefaultStoreFactory
|
||||||
override val fetchPlatformQueryResult: FetchPlatformQueryResult = koin.get()
|
override val fetchQuery: FetchPlatformQueryResult = koin.get()
|
||||||
override val directories: Dir = koin.get()
|
override val dir: Dir = koin.get()
|
||||||
override val database: Database? = directories.db
|
override val database: Database? = dir.db
|
||||||
override val downloadProgressReport = DownloadProgressFlow
|
override val preferenceManager: PreferenceManager = koin.get()
|
||||||
|
override val downloadProgressFlow = DownloadProgressFlow
|
||||||
override val actions: Actions = object: Actions {
|
override val actions: Actions = object: Actions {
|
||||||
override val platformActions = object : PlatformActions {}
|
override val platformActions = object : PlatformActions {}
|
||||||
|
|
||||||
@ -100,7 +110,7 @@ private fun spotiFlyerRoot(componentContext: ComponentContext): SpotiFlyerRoot =
|
|||||||
APPROVE_OPTION -> {
|
APPROVE_OPTION -> {
|
||||||
val directory = fileChooser.selectedFile
|
val directory = fileChooser.selectedFile
|
||||||
if(directory.canWrite()){
|
if(directory.canWrite()){
|
||||||
directories.setDownloadDirectory(directory.absolutePath)
|
preferenceManager.setDownloadDirectory(directory.absolutePath)
|
||||||
showPopUpMessage("Set New Download Directory:\n${directory.absolutePath}")
|
showPopUpMessage("Set New Download Directory:\n${directory.absolutePath}")
|
||||||
} else {
|
} else {
|
||||||
showPopUpMessage("Cant Write to Selected Directory!")
|
showPopUpMessage("Cant Write to Selected Directory!")
|
||||||
@ -137,10 +147,10 @@ private fun spotiFlyerRoot(componentContext: ComponentContext): SpotiFlyerRoot =
|
|||||||
}
|
}
|
||||||
override val analytics = object: SpotiFlyerRoot.Analytics {
|
override val analytics = object: SpotiFlyerRoot.Analytics {
|
||||||
override fun appLaunchEvent() {
|
override fun appLaunchEvent() {
|
||||||
if(directories.isFirstLaunch) {
|
if(preferenceManager.isFirstLaunch) {
|
||||||
// Enable Analytics on First Launch
|
// Enable Analytics on First Launch
|
||||||
directories.toggleAnalytics(true)
|
preferenceManager.toggleAnalytics(true)
|
||||||
directories.firstLaunchDone()
|
preferenceManager.firstLaunchDone()
|
||||||
}
|
}
|
||||||
tracker.trackAsync {
|
tracker.trackAsync {
|
||||||
eventName = "App Launch"
|
eventName = "App Launch"
|
||||||
|
@ -22,6 +22,7 @@ include(
|
|||||||
":common:root",
|
":common:root",
|
||||||
":common:main",
|
":common:main",
|
||||||
":common:list",
|
":common:list",
|
||||||
|
":common:preference",
|
||||||
":common:data-models",
|
":common:data-models",
|
||||||
":common:dependency-injection",
|
":common:dependency-injection",
|
||||||
":android",
|
":android",
|
||||||
|
@ -22,6 +22,7 @@ import com.arkivanov.mvikotlin.core.store.StoreFactory
|
|||||||
import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory
|
import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory
|
||||||
import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
|
import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
|
||||||
import com.shabinder.common.di.DownloadProgressFlow
|
import com.shabinder.common.di.DownloadProgressFlow
|
||||||
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import com.shabinder.common.models.Actions
|
import com.shabinder.common.models.Actions
|
||||||
import com.shabinder.common.models.PlatformActions
|
import com.shabinder.common.models.PlatformActions
|
||||||
import com.shabinder.common.models.TrackDetails
|
import com.shabinder.common.models.TrackDetails
|
||||||
@ -58,10 +59,11 @@ class App(props: AppProps): RComponent<AppProps, RState>(props) {
|
|||||||
private val root = SpotiFlyerRoot(ctx,
|
private val root = SpotiFlyerRoot(ctx,
|
||||||
object : SpotiFlyerRoot.Dependencies {
|
object : SpotiFlyerRoot.Dependencies {
|
||||||
override val storeFactory: StoreFactory = LoggingStoreFactory(DefaultStoreFactory)
|
override val storeFactory: StoreFactory = LoggingStoreFactory(DefaultStoreFactory)
|
||||||
override val fetchPlatformQueryResult = dependencies.fetchPlatformQueryResult
|
override val fetchQuery = dependencies.fetchPlatformQueryResult
|
||||||
override val directories = dependencies.directories
|
override val dir = dependencies.directories
|
||||||
override val database: Database? = directories.db
|
override val preferenceManager: PreferenceManager = dependencies.preferenceManager
|
||||||
override val downloadProgressReport = DownloadProgressFlow
|
override val database: Database? = dir.db
|
||||||
|
override val downloadProgressFlow = DownloadProgressFlow
|
||||||
override val actions = object : Actions {
|
override val actions = object : Actions {
|
||||||
override val platformActions = object : PlatformActions {}
|
override val platformActions = object : PlatformActions {}
|
||||||
|
|
||||||
|
@ -18,11 +18,12 @@ import co.touchlab.kermit.Kermit
|
|||||||
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.initKoin
|
import com.shabinder.common.di.initKoin
|
||||||
import react.dom.render
|
import com.shabinder.common.di.preference.PreferenceManager
|
||||||
import kotlinx.browser.document
|
import kotlinx.browser.document
|
||||||
import kotlinx.browser.window
|
import kotlinx.browser.window
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.get
|
import org.koin.core.component.get
|
||||||
|
import react.dom.render
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
window.onload = {
|
window.onload = {
|
||||||
@ -38,10 +39,12 @@ object AppDependencies : KoinComponent {
|
|||||||
val logger: Kermit
|
val logger: Kermit
|
||||||
val directories: Dir
|
val directories: Dir
|
||||||
val fetchPlatformQueryResult: FetchPlatformQueryResult
|
val fetchPlatformQueryResult: FetchPlatformQueryResult
|
||||||
|
val preferenceManager: PreferenceManager
|
||||||
init {
|
init {
|
||||||
initKoin()
|
initKoin()
|
||||||
directories = get()
|
directories = get()
|
||||||
logger = get()
|
logger = get()
|
||||||
fetchPlatformQueryResult = get()
|
fetchPlatformQueryResult = get()
|
||||||
|
preferenceManager = get()
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user