mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-21 16:54:33 +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.statusBarsPadding
|
||||
import com.shabinder.common.di.*
|
||||
import com.shabinder.common.di.preference.PreferenceManager
|
||||
import com.shabinder.common.models.Actions
|
||||
import com.shabinder.common.models.DownloadStatus
|
||||
import com.shabinder.common.models.PlatformActions
|
||||
@ -78,6 +79,7 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
private val fetcher: FetchPlatformQueryResult by inject()
|
||||
private val dir: Dir by inject()
|
||||
private val preferenceManager: PreferenceManager by inject()
|
||||
private lateinit var root: SpotiFlyerRoot
|
||||
private val callBacks: SpotiFlyerRootCallBacks get() = root.callBacks
|
||||
private val trackStatusFlow = MutableSharedFlow<HashMap<String, DownloadStatus>>(1)
|
||||
@ -129,18 +131,18 @@ class MainActivity : ComponentActivity() {
|
||||
AnalyticsDialog(
|
||||
askForAnalyticsPermission,
|
||||
enableAnalytics = {
|
||||
dir.toggleAnalytics(true)
|
||||
dir.firstLaunchDone()
|
||||
preferenceManager.toggleAnalytics(true)
|
||||
preferenceManager.firstLaunchDone()
|
||||
},
|
||||
dismissDialog = {
|
||||
askForAnalyticsPermission = false
|
||||
dir.firstLaunchDone()
|
||||
preferenceManager.firstLaunchDone()
|
||||
}
|
||||
)
|
||||
|
||||
LaunchedEffect(view) {
|
||||
permissionGranted.value = checkPermissions()
|
||||
if(dir.isFirstLaunch) {
|
||||
if(preferenceManager.isFirstLaunch) {
|
||||
delay(2500)
|
||||
// Ask For Analytics Permission on first Dialog
|
||||
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
|
||||
* */
|
||||
if(isGithubRelease) { checkIfLatestVersion() }
|
||||
if(dir.isAnalyticsEnabled && !isGithubRelease) {
|
||||
if(preferenceManager.isAnalyticsEnabled && !isGithubRelease) {
|
||||
// Download/App Install Event for F-Droid builds
|
||||
TrackHelper.track().download().with(tracker)
|
||||
}
|
||||
@ -246,9 +248,10 @@ class MainActivity : ComponentActivity() {
|
||||
dependencies = object : SpotiFlyerRoot.Dependencies{
|
||||
override val storeFactory = LoggingStoreFactory(DefaultStoreFactory)
|
||||
override val database = this@MainActivity.dir.db
|
||||
override val fetchPlatformQueryResult = this@MainActivity.fetcher
|
||||
override val directories: Dir = this@MainActivity.dir
|
||||
override val downloadProgressReport: MutableSharedFlow<HashMap<String, DownloadStatus>> = trackStatusFlow
|
||||
override val fetchQuery = this@MainActivity.fetcher
|
||||
override val dir: Dir = this@MainActivity.dir
|
||||
override val preferenceManager = this@MainActivity.preferenceManager
|
||||
override val downloadProgressFlow: MutableSharedFlow<HashMap<String, DownloadStatus>> = trackStatusFlow
|
||||
override val actions = object: Actions {
|
||||
|
||||
override val platformActions = object : PlatformActions {
|
||||
@ -316,7 +319,7 @@ class MainActivity : ComponentActivity() {
|
||||
* */
|
||||
override val analytics = object: Analytics {
|
||||
override fun appLaunchEvent() {
|
||||
if(dir.isAnalyticsEnabled){
|
||||
if(preferenceManager.isAnalyticsEnabled){
|
||||
TrackHelper.track()
|
||||
.event("events","App_Launch")
|
||||
.name("App Launch").with(tracker)
|
||||
@ -324,7 +327,7 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
override fun homeScreenVisit() {
|
||||
if(dir.isAnalyticsEnabled){
|
||||
if(preferenceManager.isAnalyticsEnabled){
|
||||
// HomeScreen Visit Event
|
||||
TrackHelper.track().screen("/main_activity/home_screen")
|
||||
.title("HomeScreen").with(tracker)
|
||||
@ -332,7 +335,7 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
override fun listScreenVisit() {
|
||||
if(dir.isAnalyticsEnabled){
|
||||
if(preferenceManager.isAnalyticsEnabled){
|
||||
// ListScreen Visit Event
|
||||
TrackHelper.track().screen("/main_activity/list_screen")
|
||||
.title("ListScreen").with(tracker)
|
||||
@ -340,7 +343,7 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
override fun donationDialogVisit() {
|
||||
if (dir.isAnalyticsEnabled) {
|
||||
if (preferenceManager.isAnalyticsEnabled) {
|
||||
// Donation Dialog Open Event
|
||||
TrackHelper.track().screen("/main_activity/donation_dialog")
|
||||
.title("DonationDialog").with(tracker)
|
||||
@ -384,7 +387,7 @@ class MainActivity : ComponentActivity() {
|
||||
val f = File(path)
|
||||
if (f.canWrite()) {
|
||||
// hell yeah :)
|
||||
dir.setDownloadDirectory(path)
|
||||
preferenceManager.setDownloadDirectory(path)
|
||||
showPopUpMessage(
|
||||
"Download Directory Set to:\n${dir.defaultDir()} "
|
||||
)
|
||||
|
@ -33,12 +33,17 @@ allprojects {
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
useIR = true
|
||||
freeCompilerArgs = freeCompilerArgs + "-Xopt-in=kotlin.RequiresOptIn"
|
||||
}
|
||||
}
|
||||
afterEvaluate {
|
||||
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)
|
||||
}
|
||||
|
||||
object MultiPlatformSettings {
|
||||
const val dep = "com.russhwolf:multiplatform-settings-no-arg:0.7.7"
|
||||
}
|
||||
|
||||
object Koin {
|
||||
val core = "io.insert-koin:koin-core:${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"
|
||||
): SpotiFlyerException(message)
|
||||
|
||||
data class UnknownReason(
|
||||
val exception: Throwable? = null,
|
||||
override val message: String = "Unknown Error"
|
||||
): SpotiFlyerException(message)
|
||||
|
||||
data class NoMatchFound(
|
||||
val trackName: String? = null,
|
||||
override val message: String = "$trackName : NO Match Found!"
|
||||
|
@ -32,7 +32,7 @@ kotlin {
|
||||
implementation(project(":common:database"))
|
||||
implementation("org.jetbrains.kotlinx:atomicfu:0.16.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.fuzzyWuzzy)
|
||||
implementation(MVIKotlin.rx)
|
||||
|
@ -22,8 +22,8 @@ import android.os.Environment
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import co.touchlab.kermit.Kermit
|
||||
import com.mpatric.mp3agic.Mp3File
|
||||
import com.russhwolf.settings.Settings
|
||||
import com.shabinder.common.database.SpotiFlyerDatabase
|
||||
import com.shabinder.common.di.preference.PreferenceManager
|
||||
import com.shabinder.common.di.utils.ParallelExecutor
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
import com.shabinder.common.models.methods
|
||||
@ -43,7 +43,7 @@ import java.net.URL
|
||||
@Suppress("DEPRECATION")
|
||||
actual class Dir actual constructor(
|
||||
private val logger: Kermit,
|
||||
settingsPref: Settings,
|
||||
private val preferenceManager: PreferenceManager,
|
||||
spotiFlyerDatabase: SpotiFlyerDatabase,
|
||||
) {
|
||||
@Suppress("DEPRECATION")
|
||||
@ -54,7 +54,7 @@ actual class Dir actual constructor(
|
||||
actual fun imageCacheDir(): String = methods.value.platformActions.imageCacheDir
|
||||
|
||||
// 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
|
||||
|
||||
actual fun isPresent(path: String): Boolean = File(path).exists()
|
||||
@ -202,5 +202,4 @@ actual class Dir actual constructor(
|
||||
private val parallelExecutor = ParallelExecutor(Dispatchers.IO)
|
||||
|
||||
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 io.ktor.util.InternalAPI
|
||||
import io.ktor.util.decodeBase64Bytes
|
||||
import io.ktor.util.*
|
||||
import java.security.SecureRandom
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.SecretKey
|
@ -20,13 +20,8 @@ import co.touchlab.kermit.Kermit
|
||||
import com.russhwolf.settings.Settings
|
||||
import com.shabinder.common.database.databaseModule
|
||||
import com.shabinder.common.database.getLogger
|
||||
import com.shabinder.common.di.audioToMp3.AudioToMp3
|
||||
import com.shabinder.common.di.providers.GaanaProvider
|
||||
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 com.shabinder.common.di.preference.PreferenceManager
|
||||
import com.shabinder.common.di.providers.providersModule
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.features.*
|
||||
import io.ktor.client.features.json.*
|
||||
@ -42,7 +37,11 @@ import kotlin.native.concurrent.ThreadLocal
|
||||
fun initKoin(enableNetworkLogs: Boolean = false, appDeclaration: KoinAppDeclaration = {}) =
|
||||
startKoin {
|
||||
appDeclaration()
|
||||
modules(commonModule(enableNetworkLogs = enableNetworkLogs), databaseModule())
|
||||
modules(
|
||||
commonModule(enableNetworkLogs = enableNetworkLogs),
|
||||
providersModule(),
|
||||
databaseModule()
|
||||
)
|
||||
}
|
||||
|
||||
// Called by IOS
|
||||
@ -52,16 +51,9 @@ fun commonModule(enableNetworkLogs: Boolean) = module {
|
||||
single { createHttpClient(enableNetworkLogs = enableNetworkLogs) }
|
||||
single { Dir(get(), get(), get()) }
|
||||
single { Settings() }
|
||||
single { PreferenceManager(get()) }
|
||||
single { Kermit(getLogger()) }
|
||||
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
|
||||
|
@ -17,8 +17,8 @@
|
||||
package com.shabinder.common.di
|
||||
|
||||
import co.touchlab.kermit.Kermit
|
||||
import com.russhwolf.settings.Settings
|
||||
import com.shabinder.common.database.SpotiFlyerDatabase
|
||||
import com.shabinder.common.di.preference.PreferenceManager
|
||||
import com.shabinder.common.di.utils.removeIllegalChars
|
||||
import com.shabinder.common.models.DownloadResult
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
@ -30,18 +30,12 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
const val DirKey = "downloadDir"
|
||||
const val AnalyticsKey = "analytics"
|
||||
const val FirstLaunch = "firstLaunch"
|
||||
const val DonationInterval = "donationInterval"
|
||||
|
||||
expect class Dir(
|
||||
logger: Kermit,
|
||||
settingsPref: Settings,
|
||||
preferenceManager: PreferenceManager,
|
||||
spotiFlyerDatabase: SpotiFlyerDatabase,
|
||||
) {
|
||||
val db: Database?
|
||||
val settings: Settings
|
||||
fun isPresent(path: String): Boolean
|
||||
fun fileSeparator(): String
|
||||
fun defaultDir(): String
|
||||
@ -54,22 +48,6 @@ expect class Dir(
|
||||
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!
|
||||
* */
|
||||
|
@ -18,7 +18,6 @@ package com.shabinder.common.di
|
||||
|
||||
import co.touchlab.kermit.Kermit
|
||||
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.SaavnProvider
|
||||
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.YoutubeProvider
|
||||
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.SpotiFlyerException
|
||||
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.spotify.Source
|
||||
import com.shabinder.common.requireNotNull
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@ -137,6 +138,7 @@ class FetchPlatformQueryResult(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
private fun addToDatabaseAsync(link: String, result: PlatformQueryResult) {
|
||||
GlobalScope.launch(dispatcherIO) {
|
||||
db?.add(
|
||||
|
@ -18,7 +18,7 @@ package com.shabinder.common.di
|
||||
|
||||
import co.touchlab.kermit.Kermit
|
||||
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 kotlinx.coroutines.GlobalScope
|
||||
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 com.shabinder.common.di.Dir
|
||||
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.PlatformQueryResult
|
||||
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 com.shabinder.common.di.Dir
|
||||
import com.shabinder.common.di.audioToMp3.AudioToMp3
|
||||
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.models.DownloadStatus
|
||||
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.finalOutputDir
|
||||
import com.shabinder.common.di.globalJson
|
||||
import com.shabinder.common.di.spotify.SpotifyRequests
|
||||
import com.shabinder.common.di.spotify.authenticateSpotify
|
||||
import com.shabinder.common.di.providers.requests.spotify.SpotifyRequests
|
||||
import com.shabinder.common.di.providers.requests.spotify.authenticateSpotify
|
||||
import com.shabinder.common.models.DownloadStatus
|
||||
import com.shabinder.common.models.NativeAtomicReference
|
||||
import com.shabinder.common.models.PlatformQueryResult
|
||||
|
@ -17,7 +17,7 @@
|
||||
package com.shabinder.common.di.providers
|
||||
|
||||
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.event.coroutines.SuspendableEvent
|
||||
import com.shabinder.common.models.event.coroutines.map
|
||||
|
@ -17,7 +17,7 @@
|
||||
package com.shabinder.common.di.providers
|
||||
|
||||
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.TrackDetails
|
||||
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 com.shabinder.common.models.AudioQuality
|
@ -14,7 +14,7 @@
|
||||
* * 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.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 com.shabinder.common.di.audioToMp3.AudioToMp3
|
||||
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.event.coroutines.SuspendableEvent
|
||||
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
|
||||
|
@ -14,7 +14,7 @@
|
||||
* * 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.models.SpotiFlyerException
|
@ -14,7 +14,7 @@
|
||||
* * 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.corsApi
|
@ -14,7 +14,7 @@
|
||||
* * 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 com.shabinder.common.models.corsApi
|
@ -1,4 +1,4 @@
|
||||
package com.shabinder.common.di.saavn
|
||||
package com.shabinder.common.di.utils
|
||||
|
||||
/*
|
||||
* JSON UTILS
|
@ -19,6 +19,7 @@ package com.shabinder.common.di
|
||||
import com.shabinder.common.di.utils.ParallelExecutor
|
||||
import com.shabinder.common.models.DownloadResult
|
||||
import com.shabinder.common.models.DownloadStatus
|
||||
import com.shabinder.common.models.SpotiFlyerException
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -40,41 +41,43 @@ actual suspend fun downloadTracks(
|
||||
) {
|
||||
list.forEach { trackDetails ->
|
||||
DownloadScope.execute { // Send Download to Pool.
|
||||
val url = fetcher.findMp3DownloadLink(trackDetails)
|
||||
if (!url.isNullOrBlank()) { // Successfully Grabbed Mp3 URL
|
||||
downloadFile(url).collect {
|
||||
when (it) {
|
||||
is DownloadResult.Error -> {
|
||||
DownloadProgressFlow.emit(
|
||||
DownloadProgressFlow.replayCache.getOrElse(
|
||||
0
|
||||
) { hashMapOf() }.apply { set(trackDetails.title, DownloadStatus.Failed) }
|
||||
)
|
||||
}
|
||||
is DownloadResult.Progress -> {
|
||||
DownloadProgressFlow.emit(
|
||||
DownloadProgressFlow.replayCache.getOrElse(
|
||||
0
|
||||
) { hashMapOf() }.apply { set(trackDetails.title, DownloadStatus.Downloading(it.progress)) }
|
||||
)
|
||||
}
|
||||
is DownloadResult.Success -> { // Todo clear map
|
||||
dir.saveFileWithMetadata(it.byteArray, trackDetails) {}
|
||||
DownloadProgressFlow.emit(
|
||||
DownloadProgressFlow.replayCache.getOrElse(
|
||||
0
|
||||
) { hashMapOf() }.apply { set(trackDetails.title, DownloadStatus.Downloaded) }
|
||||
)
|
||||
fetcher.findMp3DownloadLink(trackDetails).fold(
|
||||
success = { url ->
|
||||
downloadFile(url).collect {
|
||||
when (it) {
|
||||
is DownloadResult.Error -> {
|
||||
DownloadProgressFlow.emit(
|
||||
DownloadProgressFlow.replayCache.getOrElse(
|
||||
0
|
||||
) { hashMapOf() }.apply { set(trackDetails.title, DownloadStatus.Failed(it.cause ?: SpotiFlyerException.UnknownReason(it.cause))) }
|
||||
)
|
||||
}
|
||||
is DownloadResult.Progress -> {
|
||||
DownloadProgressFlow.emit(
|
||||
DownloadProgressFlow.replayCache.getOrElse(
|
||||
0
|
||||
) { hashMapOf() }.apply { set(trackDetails.title, DownloadStatus.Downloading(it.progress)) }
|
||||
)
|
||||
}
|
||||
is DownloadResult.Success -> { // Todo clear map
|
||||
dir.saveFileWithMetadata(it.byteArray, trackDetails) {}
|
||||
DownloadProgressFlow.emit(
|
||||
DownloadProgressFlow.replayCache.getOrElse(
|
||||
0
|
||||
) { 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 co.touchlab.kermit.Kermit
|
||||
import com.mpatric.mp3agic.Mp3File
|
||||
import com.russhwolf.settings.Settings
|
||||
import com.shabinder.common.database.SpotiFlyerDatabase
|
||||
import com.shabinder.common.di.preference.PreferenceManager
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
import com.shabinder.database.Database
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -40,7 +40,7 @@ import javax.imageio.ImageIO
|
||||
|
||||
actual class Dir actual constructor(
|
||||
private val logger: Kermit,
|
||||
settingsPref: Settings,
|
||||
private val preferenceManager: PreferenceManager,
|
||||
spotiFlyerDatabase: SpotiFlyerDatabase,
|
||||
) {
|
||||
|
||||
@ -55,7 +55,7 @@ actual class Dir actual constructor(
|
||||
|
||||
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()
|
||||
|
||||
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 settings: Settings = settingsPref
|
||||
}
|
||||
|
||||
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.decodeBase64Bytes
|
||||
import io.ktor.util.*
|
||||
import java.security.SecureRandom
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.SecretKey
|
@ -1,8 +1,8 @@
|
||||
package com.shabinder.common.di
|
||||
|
||||
import co.touchlab.kermit.Kermit
|
||||
import com.russhwolf.settings.Settings
|
||||
import com.shabinder.common.database.SpotiFlyerDatabase
|
||||
import com.shabinder.common.di.preference.PreferenceManager
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
import com.shabinder.database.Database
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@ -24,7 +24,7 @@ import platform.UIKit.UIImageJPEGRepresentation
|
||||
|
||||
actual class Dir actual constructor(
|
||||
val logger: Kermit,
|
||||
settingsPref: Settings,
|
||||
private val preferenceManager: PreferenceManager,
|
||||
spotiFlyerDatabase: SpotiFlyerDatabase,
|
||||
) {
|
||||
|
||||
@ -35,7 +35,7 @@ actual class Dir actual constructor(
|
||||
private val defaultBaseDir = NSFileManager.defaultManager.URLForDirectory(NSMusicDirectory, NSUserDomainMask, null, true, null)!!.path!!
|
||||
|
||||
// TODO Error Handling
|
||||
actual fun defaultDir(): String = (settings.getStringOrNull(DirKey) ?: defaultBaseDir) +
|
||||
actual fun defaultDir(): String = (preferenceManager.downloadDir ?: defaultBaseDir) +
|
||||
fileSeparator() + "SpotiFlyer" + fileSeparator()
|
||||
|
||||
private val defaultDirURL: NSURL by lazy {
|
||||
@ -176,6 +176,5 @@ actual class Dir actual constructor(
|
||||
// TODO
|
||||
}
|
||||
|
||||
actual val settings: Settings = settingsPref
|
||||
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.DownloadStatus
|
||||
import com.shabinder.common.models.SpotiFlyerException
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -41,29 +42,31 @@ actual suspend fun downloadTracks(
|
||||
list.forEach { track ->
|
||||
withContext(dispatcherIO) {
|
||||
allTracksStatus[track.title] = DownloadStatus.Queued
|
||||
val url = fetcher.findMp3DownloadLink(track)
|
||||
if (!url.isNullOrBlank()) { // Successfully Grabbed Mp3 URL
|
||||
downloadFile(url).collect {
|
||||
when (it) {
|
||||
is DownloadResult.Success -> {
|
||||
println("Download Completed")
|
||||
dir.saveFileWithMetadata(it.byteArray, track) {}
|
||||
}
|
||||
is DownloadResult.Error -> {
|
||||
allTracksStatus[track.title] = DownloadStatus.Failed
|
||||
println("Download Error: ${track.title}")
|
||||
}
|
||||
is DownloadResult.Progress -> {
|
||||
allTracksStatus[track.title] = DownloadStatus.Downloading(it.progress)
|
||||
println("Download Progress: ${it.progress} : ${track.title}")
|
||||
fetcher.findMp3DownloadLink(track).fold(
|
||||
success = { url ->
|
||||
downloadFile(url).collect {
|
||||
when (it) {
|
||||
is DownloadResult.Success -> {
|
||||
println("Download Completed")
|
||||
dir.saveFileWithMetadata(it.byteArray, track) {}
|
||||
}
|
||||
is DownloadResult.Error -> {
|
||||
allTracksStatus[track.title] = DownloadStatus.Failed(it.cause ?: SpotiFlyerException.UnknownReason(it.cause))
|
||||
println("Download Error: ${track.title}")
|
||||
}
|
||||
is DownloadResult.Progress -> {
|
||||
allTracksStatus[track.title] = DownloadStatus.Downloading(it.progress)
|
||||
println("Download Progress: ${it.progress} : ${track.title}")
|
||||
}
|
||||
}
|
||||
DownloadProgressFlow.emit(allTracksStatus)
|
||||
}
|
||||
},
|
||||
failure = { error ->
|
||||
allTracksStatus[track.title] = DownloadStatus.Failed(error)
|
||||
DownloadProgressFlow.emit(allTracksStatus)
|
||||
}
|
||||
} else {
|
||||
allTracksStatus[track.title] = DownloadStatus.Failed
|
||||
DownloadProgressFlow.emit(allTracksStatus)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,13 +17,13 @@
|
||||
package com.shabinder.common.di
|
||||
|
||||
import co.touchlab.kermit.Kermit
|
||||
import com.russhwolf.settings.Settings
|
||||
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.models.DownloadResult
|
||||
import com.shabinder.common.models.DownloadStatus
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
import com.shabinder.common.models.corsApi
|
||||
import com.shabinder.database.Database
|
||||
import kotlinext.js.Object
|
||||
import kotlinext.js.js
|
||||
@ -34,7 +34,7 @@ import org.w3c.dom.ImageBitmap
|
||||
|
||||
actual class Dir actual constructor(
|
||||
private val logger: Kermit,
|
||||
settingsPref: Settings,
|
||||
private val preferenceManager: PreferenceManager,
|
||||
spotiFlyerDatabase: SpotiFlyerDatabase,
|
||||
) {
|
||||
/*init {
|
||||
@ -116,7 +116,6 @@ actual class Dir actual constructor(
|
||||
private suspend fun freshImage(url: String): ImageBitmap? = null
|
||||
|
||||
actual val db: Database? = spotiFlyerDatabase.instance
|
||||
actual val settings: Settings = settingsPref
|
||||
}
|
||||
|
||||
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 {
|
||||
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.FetchPlatformQueryResult
|
||||
import com.shabinder.common.di.Picture
|
||||
import com.shabinder.common.di.preference.PreferenceManager
|
||||
import com.shabinder.common.list.integration.SpotiFlyerListImpl
|
||||
import com.shabinder.common.models.Consumer
|
||||
import com.shabinder.common.models.DownloadStatus
|
||||
@ -67,6 +68,7 @@ interface SpotiFlyerList {
|
||||
val storeFactory: StoreFactory
|
||||
val fetchQuery: FetchPlatformQueryResult
|
||||
val dir: Dir
|
||||
val preferenceManager: PreferenceManager
|
||||
val link: String
|
||||
val listOutput: Consumer<Output>
|
||||
val downloadProgressFlow: MutableSharedFlow<HashMap<String, DownloadStatus>>
|
||||
|
@ -22,7 +22,6 @@ import com.arkivanov.decompose.lifecycle.doOnResume
|
||||
import com.arkivanov.decompose.value.Value
|
||||
import com.shabinder.common.caching.Cache
|
||||
import com.shabinder.common.di.Picture
|
||||
import com.shabinder.common.di.setDonationOffset
|
||||
import com.shabinder.common.di.utils.asValue
|
||||
import com.shabinder.common.list.SpotiFlyerList
|
||||
import com.shabinder.common.list.SpotiFlyerList.Dependencies
|
||||
@ -48,6 +47,7 @@ internal class SpotiFlyerListImpl(
|
||||
instanceKeeper.getStore {
|
||||
SpotiFlyerListStoreProvider(
|
||||
dir = this.dir,
|
||||
preferenceManager = preferenceManager,
|
||||
storeFactory = storeFactory,
|
||||
fetchQuery = fetchQuery,
|
||||
downloadProgressFlow = downloadProgressFlow,
|
||||
@ -79,7 +79,7 @@ internal class SpotiFlyerListImpl(
|
||||
}
|
||||
|
||||
override fun snoozeDonationDialog() {
|
||||
dir.setDonationOffset(offset = 10)
|
||||
preferenceManager.setDonationOffset(offset = 10)
|
||||
}
|
||||
|
||||
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.FetchPlatformQueryResult
|
||||
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.store.SpotiFlyerListStore.Intent
|
||||
import com.shabinder.common.models.DownloadStatus
|
||||
@ -36,6 +36,7 @@ import kotlinx.coroutines.flow.collect
|
||||
|
||||
internal class SpotiFlyerListStoreProvider(
|
||||
private val dir: Dir,
|
||||
private val preferenceManager: PreferenceManager,
|
||||
private val storeFactory: StoreFactory,
|
||||
private val fetchQuery: FetchPlatformQueryResult,
|
||||
private val link: String,
|
||||
@ -68,7 +69,7 @@ internal class SpotiFlyerListStoreProvider(
|
||||
dir.db?.downloadRecordDatabaseQueries?.getLastInsertId()?.executeAsOneOrNull()?.also {
|
||||
// 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")
|
||||
val offset = dir.getDonationOffset
|
||||
val offset = preferenceManager.getDonationOffset
|
||||
dispatch(
|
||||
Result.AskForSupport(
|
||||
// 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.shabinder.common.di.Dir
|
||||
import com.shabinder.common.di.Picture
|
||||
import com.shabinder.common.di.preference.PreferenceManager
|
||||
import com.shabinder.common.main.integration.SpotiFlyerMainImpl
|
||||
import com.shabinder.common.models.Consumer
|
||||
import com.shabinder.common.models.DownloadRecord
|
||||
@ -63,6 +64,7 @@ interface SpotiFlyerMain {
|
||||
val storeFactory: StoreFactory
|
||||
val database: Database?
|
||||
val dir: Dir
|
||||
val preferenceManager: PreferenceManager
|
||||
val mainAnalytics: Analytics
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,10 @@ import com.shabinder.common.caching.Cache
|
||||
import com.shabinder.common.di.Picture
|
||||
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.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.SpotiFlyerMainStoreProvider
|
||||
import com.shabinder.common.main.store.getStore
|
||||
@ -41,6 +44,7 @@ internal class SpotiFlyerMainImpl(
|
||||
private val store =
|
||||
instanceKeeper.getStore {
|
||||
SpotiFlyerMainStoreProvider(
|
||||
preferenceManager = preferenceManager,
|
||||
storeFactory = storeFactory,
|
||||
database = database,
|
||||
dir = dir
|
||||
|
@ -22,8 +22,7 @@ import com.arkivanov.mvikotlin.core.store.Store
|
||||
import com.arkivanov.mvikotlin.core.store.StoreFactory
|
||||
import com.arkivanov.mvikotlin.extensions.coroutines.SuspendExecutor
|
||||
import com.shabinder.common.di.Dir
|
||||
import com.shabinder.common.di.isAnalyticsEnabled
|
||||
import com.shabinder.common.di.toggleAnalytics
|
||||
import com.shabinder.common.di.preference.PreferenceManager
|
||||
import com.shabinder.common.main.SpotiFlyerMain
|
||||
import com.shabinder.common.main.SpotiFlyerMain.State
|
||||
import com.shabinder.common.main.store.SpotiFlyerMainStore.Intent
|
||||
@ -39,6 +38,7 @@ import kotlinx.coroutines.flow.map
|
||||
|
||||
internal class SpotiFlyerMainStoreProvider(
|
||||
private val storeFactory: StoreFactory,
|
||||
private val preferenceManager: PreferenceManager,
|
||||
private val dir: Dir,
|
||||
database: Database?
|
||||
) {
|
||||
@ -76,7 +76,7 @@ internal class SpotiFlyerMainStoreProvider(
|
||||
|
||||
private inner class ExecutorImpl : SuspendExecutor<Intent, Unit, State, Result, Nothing>() {
|
||||
override suspend fun executeAction(action: Unit, getState: () -> State) {
|
||||
dispatch(Result.ToggleAnalytics(dir.isAnalyticsEnabled))
|
||||
dispatch(Result.ToggleAnalytics(preferenceManager.isAnalyticsEnabled))
|
||||
updates?.collect {
|
||||
dispatch(Result.ItemsLoaded(it))
|
||||
}
|
||||
@ -91,7 +91,7 @@ internal class SpotiFlyerMainStoreProvider(
|
||||
is Intent.SelectCategory -> dispatch(Result.CategoryChanged(intent.category))
|
||||
is Intent.ToggleAnalytics -> {
|
||||
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.shabinder.common.di.Dir
|
||||
import com.shabinder.common.di.FetchPlatformQueryResult
|
||||
import com.shabinder.common.di.preference.PreferenceManager
|
||||
import com.shabinder.common.list.SpotiFlyerList
|
||||
import com.shabinder.common.main.SpotiFlyerMain
|
||||
import com.shabinder.common.models.Actions
|
||||
@ -49,9 +50,10 @@ interface SpotiFlyerRoot {
|
||||
interface Dependencies {
|
||||
val storeFactory: StoreFactory
|
||||
val database: Database?
|
||||
val fetchPlatformQueryResult: FetchPlatformQueryResult
|
||||
val directories: Dir
|
||||
val downloadProgressReport: MutableSharedFlow<HashMap<String, DownloadStatus>>
|
||||
val fetchQuery: FetchPlatformQueryResult
|
||||
val dir: Dir
|
||||
val preferenceManager: PreferenceManager
|
||||
val downloadProgressFlow: MutableSharedFlow<HashMap<String, DownloadStatus>>
|
||||
val actions: Actions
|
||||
val analytics: Analytics
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ 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.di.Dir
|
||||
import com.shabinder.common.di.dispatcherIO
|
||||
import com.shabinder.common.list.SpotiFlyerList
|
||||
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.Dependencies
|
||||
import com.shabinder.common.root.callbacks.SpotiFlyerRootCallBacks
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
@ -77,7 +77,7 @@ internal class SpotiFlyerRootImpl(
|
||||
instanceKeeper.ensureNeverFrozen()
|
||||
methods.value = dependencies.actions.freeze()
|
||||
/*Init App Launch & Authenticate Spotify Client*/
|
||||
initAppLaunchAndAuthenticateSpotify(dependencies.fetchPlatformQueryResult::authenticateSpotifyClient)
|
||||
initAppLaunchAndAuthenticateSpotify(dependencies.fetchQuery::authenticateSpotifyClient)
|
||||
}
|
||||
|
||||
private val router =
|
||||
@ -128,6 +128,7 @@ internal class SpotiFlyerRootImpl(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
private fun initAppLaunchAndAuthenticateSpotify(authenticator: suspend () -> Unit) {
|
||||
GlobalScope.launch(dispatcherIO) {
|
||||
analytics.appLaunchEvent()
|
||||
@ -150,10 +151,7 @@ private fun spotiFlyerMain(componentContext: ComponentContext, output: Consumer<
|
||||
componentContext = componentContext,
|
||||
dependencies = object : SpotiFlyerMain.Dependencies, Dependencies by dependencies {
|
||||
override val mainOutput: Consumer<SpotiFlyerMain.Output> = output
|
||||
override val dir: Dir = directories
|
||||
override val mainAnalytics = object : SpotiFlyerMain.Analytics {
|
||||
override fun donationDialogVisit() = analytics.donationDialogVisit()
|
||||
}
|
||||
override val mainAnalytics = object : SpotiFlyerMain.Analytics , Analytics by analytics {}
|
||||
}
|
||||
)
|
||||
|
||||
@ -161,11 +159,8 @@ private fun spotiFlyerList(componentContext: ComponentContext, link: String, out
|
||||
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
|
||||
override val listAnalytics = object : SpotiFlyerList.Analytics {}
|
||||
override val listAnalytics = object : SpotiFlyerList.Analytics, Analytics by 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.resume
|
||||
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.PlatformActions
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
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 kotlinx.coroutines.runBlocking
|
||||
import org.piwik.java.tracking.PiwikTracker
|
||||
@ -79,10 +88,11 @@ private fun spotiFlyerRoot(componentContext: ComponentContext): SpotiFlyerRoot =
|
||||
componentContext = componentContext,
|
||||
dependencies = object : SpotiFlyerRoot.Dependencies {
|
||||
override val storeFactory = DefaultStoreFactory
|
||||
override val fetchPlatformQueryResult: FetchPlatformQueryResult = koin.get()
|
||||
override val directories: Dir = koin.get()
|
||||
override val database: Database? = directories.db
|
||||
override val downloadProgressReport = DownloadProgressFlow
|
||||
override val fetchQuery: FetchPlatformQueryResult = koin.get()
|
||||
override val dir: Dir = koin.get()
|
||||
override val database: Database? = dir.db
|
||||
override val preferenceManager: PreferenceManager = koin.get()
|
||||
override val downloadProgressFlow = DownloadProgressFlow
|
||||
override val actions: Actions = object: Actions {
|
||||
override val platformActions = object : PlatformActions {}
|
||||
|
||||
@ -100,7 +110,7 @@ private fun spotiFlyerRoot(componentContext: ComponentContext): SpotiFlyerRoot =
|
||||
APPROVE_OPTION -> {
|
||||
val directory = fileChooser.selectedFile
|
||||
if(directory.canWrite()){
|
||||
directories.setDownloadDirectory(directory.absolutePath)
|
||||
preferenceManager.setDownloadDirectory(directory.absolutePath)
|
||||
showPopUpMessage("Set New Download Directory:\n${directory.absolutePath}")
|
||||
} else {
|
||||
showPopUpMessage("Cant Write to Selected Directory!")
|
||||
@ -137,10 +147,10 @@ private fun spotiFlyerRoot(componentContext: ComponentContext): SpotiFlyerRoot =
|
||||
}
|
||||
override val analytics = object: SpotiFlyerRoot.Analytics {
|
||||
override fun appLaunchEvent() {
|
||||
if(directories.isFirstLaunch) {
|
||||
if(preferenceManager.isFirstLaunch) {
|
||||
// Enable Analytics on First Launch
|
||||
directories.toggleAnalytics(true)
|
||||
directories.firstLaunchDone()
|
||||
preferenceManager.toggleAnalytics(true)
|
||||
preferenceManager.firstLaunchDone()
|
||||
}
|
||||
tracker.trackAsync {
|
||||
eventName = "App Launch"
|
||||
|
@ -22,6 +22,7 @@ include(
|
||||
":common:root",
|
||||
":common:main",
|
||||
":common:list",
|
||||
":common:preference",
|
||||
":common:data-models",
|
||||
":common:dependency-injection",
|
||||
":android",
|
||||
|
@ -22,6 +22,7 @@ import com.arkivanov.mvikotlin.core.store.StoreFactory
|
||||
import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory
|
||||
import com.arkivanov.mvikotlin.main.store.DefaultStoreFactory
|
||||
import com.shabinder.common.di.DownloadProgressFlow
|
||||
import com.shabinder.common.di.preference.PreferenceManager
|
||||
import com.shabinder.common.models.Actions
|
||||
import com.shabinder.common.models.PlatformActions
|
||||
import com.shabinder.common.models.TrackDetails
|
||||
@ -58,10 +59,11 @@ class App(props: AppProps): RComponent<AppProps, RState>(props) {
|
||||
private val root = SpotiFlyerRoot(ctx,
|
||||
object : SpotiFlyerRoot.Dependencies {
|
||||
override val storeFactory: StoreFactory = LoggingStoreFactory(DefaultStoreFactory)
|
||||
override val fetchPlatformQueryResult = dependencies.fetchPlatformQueryResult
|
||||
override val directories = dependencies.directories
|
||||
override val database: Database? = directories.db
|
||||
override val downloadProgressReport = DownloadProgressFlow
|
||||
override val fetchQuery = dependencies.fetchPlatformQueryResult
|
||||
override val dir = dependencies.directories
|
||||
override val preferenceManager: PreferenceManager = dependencies.preferenceManager
|
||||
override val database: Database? = dir.db
|
||||
override val downloadProgressFlow = DownloadProgressFlow
|
||||
override val actions = object : Actions {
|
||||
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.FetchPlatformQueryResult
|
||||
import com.shabinder.common.di.initKoin
|
||||
import react.dom.render
|
||||
import com.shabinder.common.di.preference.PreferenceManager
|
||||
import kotlinx.browser.document
|
||||
import kotlinx.browser.window
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
import react.dom.render
|
||||
|
||||
fun main() {
|
||||
window.onload = {
|
||||
@ -38,10 +39,12 @@ object AppDependencies : KoinComponent {
|
||||
val logger: Kermit
|
||||
val directories: Dir
|
||||
val fetchPlatformQueryResult: FetchPlatformQueryResult
|
||||
val preferenceManager: PreferenceManager
|
||||
init {
|
||||
initKoin()
|
||||
directories = get()
|
||||
logger = get()
|
||||
fetchPlatformQueryResult = get()
|
||||
preferenceManager = get()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user