@@ -6,6 +6,7 @@ import androidx.compose.runtime.snapshotFlow
66import com.flixclusive.core.datastore.AppSettingsManager
77import com.flixclusive.core.ui.common.util.showToast
88import com.flixclusive.core.util.coroutines.AppDispatchers
9+ import com.flixclusive.core.util.coroutines.AppDispatchers.Companion.withDefaultContext
910import com.flixclusive.core.util.coroutines.AppDispatchers.Companion.withIOContext
1011import com.flixclusive.core.util.exception.safeCall
1112import com.flixclusive.core.util.log.errorLog
@@ -36,6 +37,7 @@ import okhttp3.OkHttpClient
3637import java.io.File
3738import java.io.IOException
3839import java.io.InputStreamReader
40+ import java.util.Collections
3941import javax.inject.Inject
4042import javax.inject.Singleton
4143import com.flixclusive.core.locale.R as LocaleR
@@ -52,10 +54,10 @@ class ProviderManager @Inject constructor(
5254 private val providerApiRepository : ProviderApiRepository
5355) {
5456 /* * Map containing all loaded providers */
55- val providers: MutableMap <String , Provider > = LinkedHashMap ()
56- private val classLoaders: MutableMap <PathClassLoader , Provider > = HashMap ()
57+ val providers: MutableMap <String , Provider > = Collections .synchronizedMap( LinkedHashMap () )
58+ private val classLoaders: MutableMap <PathClassLoader , Provider > = Collections .synchronizedMap( HashMap () )
5759
58- private var notificationChannelHasBeensInitialized = false
60+ private var notificationChannelHasBeenInitialized = false
5961
6062 /* *
6163 * An observable map of provider data
@@ -72,6 +74,7 @@ class ProviderManager @Inject constructor(
7274 private val updaterJsonMap = HashMap <String , List <ProviderData >>()
7375
7476 private val dynamicResourceLoader = DynamicResourceLoader (context = context)
77+ private val LOCAL_PATH_PREFIX = context.getExternalFilesDir(null )?.absolutePath + " /providers/"
7578
7679 val workingApis = snapshotFlow {
7780 providerDataList
@@ -108,18 +111,17 @@ class ProviderManager @Inject constructor(
108111
109112 if (failedToLoad.isNotEmpty()) {
110113 context.notifyOnError(
111- shouldInitializeChannel = ! notificationChannelHasBeensInitialized ,
114+ shouldInitializeChannel = ! notificationChannelHasBeenInitialized ,
112115 providers = failedToLoad.keys,
113116 )
114117
115- notificationChannelHasBeensInitialized = true
118+ notificationChannelHasBeenInitialized = true
116119 }
117120 }
118121 }
119122
120123 private suspend fun initializeLocalProviders () {
121- val localPath = context.getExternalFilesDir(null )?.absolutePath + " /providers/"
122- val localDir = File (localPath)
124+ val localDir = File (LOCAL_PATH_PREFIX )
123125
124126 if (! localDir.exists()) {
125127 val isSuccess = localDir.mkdirs()
@@ -275,11 +277,11 @@ class ProviderManager @Inject constructor(
275277 val hasNewErrors = needsDownload && failedToLoad.size - initialFailedToLoadProviders > 0
276278 if (hasNewErrors) {
277279 context.notifyOnError(
278- shouldInitializeChannel = ! notificationChannelHasBeensInitialized ,
280+ shouldInitializeChannel = ! notificationChannelHasBeenInitialized ,
279281 providers = failedToLoad.keys,
280282 )
281283
282- notificationChannelHasBeensInitialized = true
284+ notificationChannelHasBeenInitialized = true
283285 }
284286 }
285287
@@ -290,11 +292,16 @@ class ProviderManager @Inject constructor(
290292 * @param providerData The provider information
291293 */
292294 @Suppress(" UNCHECKED_CAST" )
293- private suspend fun loadProvider (file : File , providerData : ProviderData ) {
295+ private suspend fun loadProvider (
296+ file : File ,
297+ providerData : ProviderData
298+ ) {
294299 val name = file.nameWithoutExtension
295300 val filePath = file.absolutePath
296301
297- var providerPreference = getProviderPreference(name)
302+ val providerPosition = getPositionIndexFromSettings(
303+ name = name
304+ )
298305
299306 infoLog(" Loading provider: $name " )
300307
@@ -343,14 +350,16 @@ class ProviderManager @Inject constructor(
343350 }
344351 }
345352
346- if (providerPreference == null ) {
347- providerPreference = ProviderPreference (
353+ val providerPreference = if (providerPosition > - 1 ) {
354+ appSettingsManager.cachedProviderSettings.providers[providerPosition]
355+ } else {
356+ ProviderPreference (
348357 name = name,
349358 filePath = filePath,
350359 isDisabled = false
351- )
352-
353- loadProviderOnSettings(providerPreference)
360+ ). also {
361+ loadProviderOnSettings(it)
362+ }
354363 }
355364
356365 if (! providerPreference.isDisabled) {
@@ -362,9 +371,16 @@ class ProviderManager @Inject constructor(
362371 )
363372 }
364373
365- providerDataList.add(providerData)
366374 providers[name] = providerInstance
367375 classLoaders[loader] = providerInstance
376+
377+ if (providerPosition > - 1 ) {
378+ providerDataList.add(
379+ index = providerPosition, element = providerData
380+ )
381+ } else {
382+ providerDataList.add(element = providerData)
383+ }
368384 } catch (e: Throwable ) {
369385 if (isCrashingOnGetApiMethod(e)) {
370386 val message = context.getApiCrashMessage(provider = name)
@@ -384,10 +400,21 @@ class ProviderManager @Inject constructor(
384400 }
385401 }
386402
387- private suspend fun loadProviderOnSettings (providerPreference : ProviderPreference ) {
403+ private suspend fun loadProviderOnSettings (
404+ provider : ProviderPreference ,
405+ index : Int = -1
406+ ) {
388407 appSettingsManager.updateProviderSettings {
408+ val providersList = it.providers.toMutableList()
409+
410+ if (index > - 1 ) {
411+ providersList[index] = provider
412+ } else {
413+ providersList.add(provider)
414+ }
415+
389416 it.copy(
390- providers = it.providers + listOf (providerPreference )
417+ providers = providersList.toList( )
391418 )
392419 }
393420 }
@@ -402,15 +429,13 @@ class ProviderManager @Inject constructor(
402429 providerData : ProviderData ,
403430 unloadOnSettings : Boolean = true
404431 ) {
405- val provider = providers[providerData.name]
406- val file = context.provideValidProviderPath(providerData)
407-
408- if (provider == null || ! file.exists()) {
409- errorLog(" Provider [${providerData.name} ] not found. Cannot be unloaded" )
410- return
411- }
432+ val index = getPositionIndexFromSettings(providerData.name)
433+ val providerPreference = appSettingsManager.cachedProviderSettings.providers[index]
412434
413- unloadProvider(provider, file, unloadOnSettings)
435+ unloadProvider(
436+ providerPreference = providerPreference,
437+ unloadOnSettings = unloadOnSettings
438+ )
414439 }
415440
416441 /* *
@@ -453,7 +478,10 @@ class ProviderManager @Inject constructor(
453478 providerApiRepository.remove(provider.name)
454479 providers.remove(provider.name)
455480 if (unloadOnSettings) {
456- unloadProviderOnSettings(file.absolutePath)
481+ unloadProviderOnSettings(
482+ name = provider.name,
483+ path = file.absolutePath
484+ )
457485 }
458486 file.delete()
459487
@@ -469,51 +497,60 @@ class ProviderManager @Inject constructor(
469497 }
470498 }
471499
472- private suspend fun unloadProviderOnSettings (path : String ) {
500+ private suspend fun unloadProviderOnSettings (name : String , path : String ) {
473501 appSettingsManager.updateProviderSettings {
474502 val newList = it.providers.toMutableList()
475503 newList.removeIf { providerPref ->
476- providerPref.equals(path)
504+ providerPref.filePath == path
505+ && providerPref.name == name
477506 }
478507
479508 it.copy(providers = newList)
480509 }
481510 }
482-
483- private suspend fun reloadProviderOnSettings (providerPreference : ProviderPreference ) {
484- appSettingsManager.updateProviderSettings {
485- val newList = it.providers.toMutableList()
486- val indexOfProviderToReload = newList.indexOfFirst { savedProviderPreference ->
487- providerPreference.name.equals(savedProviderPreference.name, true )
488- && providerPreference.filePath.equals(savedProviderPreference.filePath, true )
489- }
490511
491- newList[indexOfProviderToReload] = newList[indexOfProviderToReload].copy(
492- name = providerPreference.name // Need to do this because name changes might occur for some instances.
493- )
512+ private suspend fun reloadProviderOnSettings (
513+ oldProviderData : ProviderData ,
514+ newProviderData : ProviderData
515+ ) {
516+ val oldOrderPosition = getPositionIndexFromSettings(oldProviderData.name)
517+ val oldPreference = appSettingsManager.cachedProviderSettings.providers[oldOrderPosition]
494518
495- it.copy(providers = newList)
496- }
519+ val localPrefix = if (oldPreference.filePath.contains(LOCAL_PATH_PREFIX )) LOCAL_PATH_PREFIX else null
520+ val newPath = context.provideValidProviderPath(
521+ newProviderData,
522+ localPrefix = localPrefix
523+ )
524+
525+ loadProviderOnSettings(
526+ provider = oldPreference.copy(
527+ name = newProviderData.name,
528+ filePath = newPath.absolutePath
529+ ),
530+ index = oldOrderPosition
531+ )
497532 }
498533
499- suspend fun reloadProvider (providerData : ProviderData ) {
500- if (! providers.containsKey(providerData.name)) throw IllegalArgumentException (" No such provider: ${providerData.name} " )
501-
534+ suspend fun reloadProvider (
535+ oldProviderData : ProviderData ,
536+ newProviderData : ProviderData
537+ ) {
538+ if (! providers.containsKey(oldProviderData.name))
539+ throw IllegalArgumentException (" No such provider: ${oldProviderData.name} " )
540+
502541 unloadProvider(
503- providerData = providerData ,
542+ providerData = oldProviderData ,
504543 unloadOnSettings = false
505544 )
506- loadProvider(
507- providerData = providerData,
508- needsDownload = true
509- )
510545
511546 reloadProviderOnSettings(
512- providerPreference = ProviderPreference (
513- name = providerData.name,
514- filePath = context.provideValidProviderPath(providerData).absolutePath,
515- isDisabled = false
516- )
547+ oldProviderData = oldProviderData,
548+ newProviderData = newProviderData
549+ )
550+
551+ loadProvider(
552+ providerData = newProviderData,
553+ needsDownload = true
517554 )
518555 }
519556
@@ -557,7 +594,8 @@ class ProviderManager @Inject constructor(
557594 providerApiRepository.remove(providerData.name)
558595 } else {
559596 try {
560- val api = providers[providerData.name]?.getApi(context, client)
597+ val api = providers[providerData.name]
598+ ?.getApi(context, client)
561599
562600 if (api != null ) {
563601 providerApiRepository.add(
@@ -580,23 +618,27 @@ class ProviderManager @Inject constructor(
580618 isDisabled : Boolean
581619 ) {
582620 appSettingsManager.updateProviderSettings {
583- val listOfSavedProviders = it.providers.toMutableList()
621+ withDefaultContext {
622+ val listOfSavedProviders = it.providers.toMutableList()
584623
585- val indexOfProvider = listOfSavedProviders.indexOfFirst { provider ->
586- provider.name.equals(name, true )
587- }
588- val provider = listOfSavedProviders[indexOfProvider]
624+ val indexOfProvider = listOfSavedProviders.indexOfFirst { provider ->
625+ provider.name.equals(name, true )
626+ }
627+ val provider = listOfSavedProviders[indexOfProvider]
589628
590- listOfSavedProviders[indexOfProvider] = provider.copy(isDisabled = isDisabled)
629+ listOfSavedProviders[indexOfProvider] = provider.copy(isDisabled = isDisabled)
591630
592- it.copy(providers = listOfSavedProviders.toList())
631+ it.copy(providers = listOfSavedProviders.toList())
632+ }
593633 }
594634 }
595635
596- private fun getProviderPreference (name : String ): ProviderPreference ? {
597- return appSettingsManager.cachedProviderSettings
598- .providers
599- .find { it.name.equals(name, true ) }
636+ private suspend fun getPositionIndexFromSettings (name : String ): Int {
637+ return withDefaultContext {
638+ appSettingsManager.cachedProviderSettings
639+ .providers
640+ .indexOfFirst { it.name.equals(name, true ) }
641+ }
600642 }
601643
602644 /* *
0 commit comments