ExtensionPresenter: Fix crash on first launch (#7685)

* Revert "Use SharedFlow for available extensions to always emit the value (#7609)"

This reverts commit 73901f50c0aee1cb82695642af72ff6ac7bc232d.

* ExtensionPresenter: Explicitly set refreshing status

* Scope coroutines job to presenter

* cleanup

* fix toast

(cherry picked from commit b3426f37e7d36be653363338288f74e2ae252a78)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt
This commit is contained in:
Ivan Iskandar 2022-08-05 02:44:37 +07:00 committed by Jobobby04
parent 353eef34b5
commit 4da028af6a
2 changed files with 36 additions and 38 deletions

View File

@ -16,6 +16,7 @@ import eu.kanade.tachiyomi.extension.util.ExtensionInstaller
import eu.kanade.tachiyomi.extension.util.ExtensionLoader import eu.kanade.tachiyomi.extension.util.ExtensionLoader
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.util.lang.launchNow import eu.kanade.tachiyomi.util.lang.launchNow
import eu.kanade.tachiyomi.util.lang.withUIContext
import eu.kanade.tachiyomi.util.preference.plusAssign import eu.kanade.tachiyomi.util.preference.plusAssign
import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.logcat
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
@ -25,11 +26,8 @@ import exh.source.EH_SOURCE_ID
import exh.source.EXH_SOURCE_ID import exh.source.EXH_SOURCE_ID
import exh.source.MERGED_SOURCE_ID import exh.source.MERGED_SOURCE_ID
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import logcat.LogPriority import logcat.LogPriority
import rx.Observable import rx.Observable
@ -110,15 +108,15 @@ class ExtensionManager(
var availableExtensions = emptyList<Extension.Available>() var availableExtensions = emptyList<Extension.Available>()
private set(value) { private set(value) {
field = value field = value
availableExtensionsFlow.tryEmit(field) availableExtensionsFlow.value = field
updatedInstalledExtensionsStatuses(value) updatedInstalledExtensionsStatuses(value)
setupAvailableExtensionsSourcesDataMap(value) setupAvailableExtensionsSourcesDataMap(value)
} }
private val availableExtensionsFlow = MutableSharedFlow<List<Extension.Available>>(replay = 1) private val availableExtensionsFlow = MutableStateFlow(availableExtensions)
fun getAvailableExtensionsFlow(): Flow<List<Extension.Available>> { fun getAvailableExtensionsFlow(): StateFlow<List<Extension.Available>> {
return availableExtensionsFlow.asSharedFlow() return availableExtensionsFlow.asStateFlow()
} }
private var availableExtensionsSourcesData: Map<Long, SourceData> = mapOf() private var availableExtensionsSourcesData: Map<Long, SourceData> = mapOf()
@ -193,21 +191,19 @@ class ExtensionManager(
/** /**
* Finds the available extensions in the [api] and updates [availableExtensions]. * Finds the available extensions in the [api] and updates [availableExtensions].
*/ */
fun findAvailableExtensions() { suspend fun findAvailableExtensions() {
launchNow { val extensions: List<Extension.Available> = try {
val extensions: List<Extension.Available> = try { api.findExtensions()
api.findExtensions() } catch (e: Exception) {
} catch (e: Exception) { logcat(LogPriority.ERROR, e)
logcat(LogPriority.ERROR, e) withUIContext { context.toast(R.string.extension_api_error) }
context.toast(R.string.extension_api_error) emptyList()
emptyList()
}
// SY -->
unalteredAvailableExtensions = extensions
availableExtensions = extensions.filterNotBlacklisted()
// SY <--
} }
// SY -->
unalteredAvailableExtensions = extensions
availableExtensions = extensions.filterNotBlacklisted()
// SY <--
} }
/** /**

View File

@ -36,8 +36,6 @@ class ExtensionsPresenter(
override fun onCreate(savedState: Bundle?) { override fun onCreate(savedState: Bundle?) {
super.onCreate(savedState) super.onCreate(savedState)
extensionManager.findAvailableExtensions()
val context = Injekt.get<Application>() val context = Injekt.get<Application>()
val extensionMapper: (Map<String, InstallStep>) -> ((Extension) -> ExtensionUiModel) = { map -> val extensionMapper: (Map<String, InstallStep>) -> ((Extension) -> ExtensionUiModel) = { map ->
{ {
@ -71,13 +69,13 @@ class ExtensionsPresenter(
} }
} }
launchIO { presenterScope.launchIO {
combine( combine(
_query, _query,
getExtensions.subscribe(), getExtensions.subscribe(),
_currentDownloads, _currentDownloads,
) { query, (updates, installed, available, untrusted), downloads -> ) { query, (_updates, _installed, _available, _untrusted), downloads ->
val languagesWithExtensions = available val languagesWithExtensions = _available
.filter(queryFilter(query)) .filter(queryFilter(query))
.groupBy { LocaleHelper.getSourceDisplayName(it.lang, context) } .groupBy { LocaleHelper.getSourceDisplayName(it.lang, context) }
.toSortedMap() .toSortedMap()
@ -90,14 +88,14 @@ class ExtensionsPresenter(
val items = mutableListOf<ExtensionUiModel>() val items = mutableListOf<ExtensionUiModel>()
val updates = updates.filter(queryFilter(query)).map(extensionMapper(downloads)) val updates = _updates.filter(queryFilter(query)).map(extensionMapper(downloads))
if (updates.isNotEmpty()) { if (updates.isNotEmpty()) {
items.add(ExtensionUiModel.Header.Resource(R.string.ext_updates_pending)) items.add(ExtensionUiModel.Header.Resource(R.string.ext_updates_pending))
items.addAll(updates) items.addAll(updates)
} }
val installed = installed.filter(queryFilter(query)).map(extensionMapper(downloads)) val installed = _installed.filter(queryFilter(query)).map(extensionMapper(downloads))
val untrusted = untrusted.filter(queryFilter(query)).map(extensionMapper(downloads)) val untrusted = _untrusted.filter(queryFilter(query)).map(extensionMapper(downloads))
if (installed.isNotEmpty() || untrusted.isNotEmpty()) { if (installed.isNotEmpty() || untrusted.isNotEmpty()) {
items.add(ExtensionUiModel.Header.Resource(R.string.ext_installed)) items.add(ExtensionUiModel.Header.Resource(R.string.ext_installed))
items.addAll(installed) items.addAll(installed)
@ -110,21 +108,22 @@ class ExtensionsPresenter(
items items
}.collectLatest { }.collectLatest {
state.isRefreshing = false
state.isLoading = false state.isLoading = false
state.items = it state.items = it
} }
} }
presenterScope.launchIO { findAvailableExtensions() }
} }
fun search(query: String) { fun search(query: String) {
launchIO { presenterScope.launchIO {
_query.emit(query) _query.emit(query)
} }
} }
fun updateAllExtensions() { fun updateAllExtensions() {
launchIO { presenterScope.launchIO {
if (state.isEmpty) return@launchIO if (state.isEmpty) return@launchIO
val items = state.items val items = state.items
items.mapNotNull { items.mapNotNull {
@ -151,16 +150,16 @@ class ExtensionsPresenter(
} }
private fun removeDownloadState(extension: Extension) { private fun removeDownloadState(extension: Extension) {
_currentDownloads.update { map -> _currentDownloads.update { _map ->
val map = map.toMutableMap() val map = _map.toMutableMap()
map.remove(extension.pkgName) map.remove(extension.pkgName)
map map
} }
} }
private fun addDownloadState(extension: Extension, installStep: InstallStep) { private fun addDownloadState(extension: Extension, installStep: InstallStep) {
_currentDownloads.update { map -> _currentDownloads.update { _map ->
val map = map.toMutableMap() val map = _map.toMutableMap()
map[extension.pkgName] = installStep map[extension.pkgName] = installStep
map map
} }
@ -180,8 +179,11 @@ class ExtensionsPresenter(
} }
fun findAvailableExtensions() { fun findAvailableExtensions() {
state.isRefreshing = true presenterScope.launchIO {
extensionManager.findAvailableExtensions() state.isRefreshing = true
extensionManager.findAvailableExtensions()
state.isRefreshing = false
}
} }
fun trustSignature(signatureHash: String) { fun trustSignature(signatureHash: String) {