mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-12 20:19:05 +01:00
Use Stable interface for Browse screens (#7544)
This commit is contained in:
@@ -20,6 +20,9 @@ import eu.kanade.tachiyomi.util.preference.plusAssign
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import logcat.LogPriority
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.Injekt
|
||||
@@ -63,9 +66,16 @@ class ExtensionManager(
|
||||
var installedExtensions = emptyList<Extension.Installed>()
|
||||
private set(value) {
|
||||
field = value
|
||||
installedExtensionsFlow.value = field
|
||||
installedExtensionsRelay.call(value)
|
||||
}
|
||||
|
||||
private val installedExtensionsFlow = MutableStateFlow(installedExtensions)
|
||||
|
||||
fun getInstalledExtensionsFlow(): StateFlow<List<Extension.Installed>> {
|
||||
return installedExtensionsFlow.asStateFlow()
|
||||
}
|
||||
|
||||
fun getAppIconForSource(source: Source): Drawable? {
|
||||
return getAppIconForSource(source.id)
|
||||
}
|
||||
|
||||
@@ -17,9 +17,6 @@ class ExtensionFilterController : ComposeController<ExtensionFilterPresenter>()
|
||||
ExtensionFilterScreen(
|
||||
nestedScrollInterop = nestedScrollInterop,
|
||||
presenter = presenter,
|
||||
onClickLang = { language ->
|
||||
presenter.toggleLanguage(language)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,32 +3,37 @@ package eu.kanade.tachiyomi.ui.browse.extension
|
||||
import android.os.Bundle
|
||||
import eu.kanade.domain.extension.interactor.GetExtensionLanguages
|
||||
import eu.kanade.domain.source.interactor.ToggleLanguage
|
||||
import eu.kanade.presentation.browse.ExtensionFilterState
|
||||
import eu.kanade.presentation.browse.ExtensionFilterStateImpl
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import logcat.LogPriority
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class ExtensionFilterPresenter(
|
||||
private val state: ExtensionFilterStateImpl = ExtensionFilterState() as ExtensionFilterStateImpl,
|
||||
private val getExtensionLanguages: GetExtensionLanguages = Injekt.get(),
|
||||
private val toggleLanguage: ToggleLanguage = Injekt.get(),
|
||||
private val preferences: PreferencesHelper = Injekt.get(),
|
||||
) : BasePresenter<ExtensionFilterController>() {
|
||||
) : BasePresenter<ExtensionFilterController>(), ExtensionFilterState by state {
|
||||
|
||||
private val _state: MutableStateFlow<ExtensionFilterState> = MutableStateFlow(ExtensionFilterState.Loading)
|
||||
val state: StateFlow<ExtensionFilterState> = _state.asStateFlow()
|
||||
private val _events = Channel<Event>(Int.MAX_VALUE)
|
||||
val events = _events.receiveAsFlow()
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
presenterScope.launchIO {
|
||||
getExtensionLanguages.subscribe()
|
||||
.catch { exception ->
|
||||
_state.value = ExtensionFilterState.Error(exception)
|
||||
logcat(LogPriority.ERROR, exception)
|
||||
_events.send(Event.FailedFetchingLanguages)
|
||||
}
|
||||
.collectLatest(::collectLatestSourceLangMap)
|
||||
}
|
||||
@@ -36,19 +41,17 @@ class ExtensionFilterPresenter(
|
||||
|
||||
private fun collectLatestSourceLangMap(extLangs: List<String>) {
|
||||
val enabledLanguages = preferences.enabledLanguages().get()
|
||||
val uiModels = extLangs.map {
|
||||
state.items = extLangs.map {
|
||||
FilterUiModel(it, it in enabledLanguages)
|
||||
}
|
||||
_state.value = ExtensionFilterState.Success(uiModels)
|
||||
state.isLoading = false
|
||||
}
|
||||
|
||||
fun toggleLanguage(language: String) {
|
||||
toggleLanguage.await(language)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ExtensionFilterState {
|
||||
object Loading : ExtensionFilterState()
|
||||
data class Error(val error: Throwable) : ExtensionFilterState()
|
||||
data class Success(val models: List<FilterUiModel>) : ExtensionFilterState()
|
||||
sealed class Event {
|
||||
object FailedFetchingLanguages : Event()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,11 @@ package eu.kanade.tachiyomi.ui.browse.extension
|
||||
import android.app.Application
|
||||
import android.os.Bundle
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import eu.kanade.domain.extension.interactor.GetExtensionUpdates
|
||||
import eu.kanade.domain.extension.interactor.GetExtensions
|
||||
import eu.kanade.presentation.browse.ExtensionState
|
||||
import eu.kanade.presentation.browse.ExtensionsState
|
||||
import eu.kanade.presentation.browse.ExtensionsStateImpl
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
@@ -17,8 +17,6 @@ import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.update
|
||||
@@ -27,20 +25,16 @@ import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class ExtensionsPresenter(
|
||||
private val state: ExtensionsStateImpl = ExtensionState() as ExtensionsStateImpl,
|
||||
private val extensionManager: ExtensionManager = Injekt.get(),
|
||||
private val getExtensionUpdates: GetExtensionUpdates = Injekt.get(),
|
||||
private val getExtensions: GetExtensions = Injekt.get(),
|
||||
) : BasePresenter<ExtensionsController>() {
|
||||
) : BasePresenter<ExtensionsController>(), ExtensionsState by state {
|
||||
|
||||
private val _query: MutableStateFlow<String> = MutableStateFlow("")
|
||||
|
||||
private var _currentDownloads = MutableStateFlow<Map<String, InstallStep>>(hashMapOf())
|
||||
|
||||
private val _state: MutableStateFlow<ExtensionState> = MutableStateFlow(ExtensionState.Uninitialized)
|
||||
val state: StateFlow<ExtensionState> = _state.asStateFlow()
|
||||
|
||||
var isRefreshing: Boolean by mutableStateOf(true)
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
@@ -86,8 +80,6 @@ class ExtensionsPresenter(
|
||||
getExtensionUpdates.subscribe(),
|
||||
_currentDownloads,
|
||||
) { query, (installed, untrusted, available), updates, downloads ->
|
||||
isRefreshing = false
|
||||
|
||||
val languagesWithExtensions = available
|
||||
.filter(queryFilter(query))
|
||||
.groupBy { LocaleHelper.getSourceDisplayName(it.lang, context) }
|
||||
@@ -121,7 +113,9 @@ class ExtensionsPresenter(
|
||||
|
||||
items
|
||||
}.collectLatest {
|
||||
_state.value = ExtensionState.Initialized(it)
|
||||
state.isRefreshing = false
|
||||
state.isLoading = false
|
||||
state.items = it
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,9 +128,9 @@ class ExtensionsPresenter(
|
||||
|
||||
fun updateAllExtensions() {
|
||||
launchIO {
|
||||
val state = _state.value
|
||||
if (state !is ExtensionState.Initialized) return@launchIO
|
||||
state.list.mapNotNull {
|
||||
if (state.isEmpty) return@launchIO
|
||||
val items = state.items
|
||||
items.mapNotNull {
|
||||
if (it !is ExtensionUiModel.Item) return@mapNotNull null
|
||||
if (it.extension !is Extension.Installed) return@mapNotNull null
|
||||
if (it.extension.hasUpdate.not()) return@mapNotNull null
|
||||
@@ -189,7 +183,7 @@ class ExtensionsPresenter(
|
||||
}
|
||||
|
||||
fun findAvailableExtensions() {
|
||||
isRefreshing = true
|
||||
state.isRefreshing = true
|
||||
extensionManager.findAvailableExtensions()
|
||||
}
|
||||
|
||||
@@ -217,8 +211,3 @@ sealed interface ExtensionUiModel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ExtensionState {
|
||||
object Uninitialized : ExtensionState()
|
||||
data class Initialized(val list: List<ExtensionUiModel>) : ExtensionState()
|
||||
}
|
||||
|
||||
@@ -43,7 +43,6 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
||||
nestedScrollInterop = nestedScrollInterop,
|
||||
presenter = presenter,
|
||||
onClickUninstall = { presenter.uninstallExtension() },
|
||||
onClickAppInfo = { presenter.openInSettings() },
|
||||
onClickSourcePreferences = { router.pushController(SourcePreferencesController(it)) },
|
||||
onClickSource = { presenter.toggleSource(it) },
|
||||
)
|
||||
|
||||
@@ -1,48 +1,52 @@
|
||||
package eu.kanade.tachiyomi.ui.browse.extension.details
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import eu.kanade.domain.extension.interactor.GetExtensionSources
|
||||
import eu.kanade.domain.source.interactor.ToggleSource
|
||||
import eu.kanade.presentation.browse.ExtensionDetailsState
|
||||
import eu.kanade.presentation.browse.ExtensionDetailsStateImpl
|
||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.drop
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.coroutines.flow.take
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class ExtensionDetailsPresenter(
|
||||
private val pkgName: String,
|
||||
private val state: ExtensionDetailsStateImpl = ExtensionDetailsState() as ExtensionDetailsStateImpl,
|
||||
private val context: Application = Injekt.get(),
|
||||
private val getExtensionSources: GetExtensionSources = Injekt.get(),
|
||||
private val toggleSource: ToggleSource = Injekt.get(),
|
||||
private val extensionManager: ExtensionManager = Injekt.get(),
|
||||
) : BasePresenter<ExtensionDetailsController>() {
|
||||
|
||||
val extension = extensionManager.installedExtensions.find { it.pkgName == pkgName }
|
||||
|
||||
private val _state: MutableStateFlow<List<ExtensionSourceItem>> = MutableStateFlow(emptyList())
|
||||
val sourcesState: StateFlow<List<ExtensionSourceItem>> = _state.asStateFlow()
|
||||
) : BasePresenter<ExtensionDetailsController>(), ExtensionDetailsState by state {
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
val extension = extension ?: return
|
||||
presenterScope.launchIO {
|
||||
extensionManager.getInstalledExtensionsFlow()
|
||||
.map { it.firstOrNull { it.pkgName == pkgName } }
|
||||
.collectLatest {
|
||||
state.extension = it
|
||||
fetchExtensionSources()
|
||||
}
|
||||
}
|
||||
|
||||
bindToUninstalledExtension()
|
||||
}
|
||||
|
||||
presenterScope.launchIO {
|
||||
getExtensionSources.subscribe(extension)
|
||||
private fun CoroutineScope.fetchExtensionSources() {
|
||||
launchIO {
|
||||
getExtensionSources.subscribe(extension!!)
|
||||
.map {
|
||||
it.sortedWith(
|
||||
compareBy(
|
||||
@@ -51,20 +55,24 @@ class ExtensionDetailsPresenter(
|
||||
),
|
||||
)
|
||||
}
|
||||
.collectLatest { _state.value = it }
|
||||
.collectLatest {
|
||||
state.isLoading = false
|
||||
state.sources = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindToUninstalledExtension() {
|
||||
extensionManager.getInstalledExtensionsObservable()
|
||||
.skip(1)
|
||||
.filter { extensions -> extensions.none { it.pkgName == pkgName } }
|
||||
.map { }
|
||||
.take(1)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeFirst({ view, _ ->
|
||||
view.onExtensionUninstalled()
|
||||
},)
|
||||
presenterScope.launchIO {
|
||||
extensionManager.getInstalledExtensionsFlow()
|
||||
.drop(1)
|
||||
.filter { extensions -> extensions.none { it.pkgName == pkgName } }
|
||||
.map { }
|
||||
.take(1)
|
||||
.collectLatest {
|
||||
view?.onExtensionUninstalled()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun uninstallExtension() {
|
||||
@@ -72,13 +80,6 @@ class ExtensionDetailsPresenter(
|
||||
extensionManager.uninstallExtension(extension.pkgName)
|
||||
}
|
||||
|
||||
fun openInSettings() {
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
||||
data = Uri.fromParts("package", pkgName, null)
|
||||
}
|
||||
view?.startActivity(intent)
|
||||
}
|
||||
|
||||
fun toggleSource(sourceId: Long) {
|
||||
toggleSource.await(sourceId)
|
||||
}
|
||||
|
||||
@@ -2,25 +2,29 @@ package eu.kanade.tachiyomi.ui.browse.migration.manga
|
||||
|
||||
import android.os.Bundle
|
||||
import eu.kanade.domain.manga.interactor.GetFavorites
|
||||
import eu.kanade.domain.manga.model.Manga
|
||||
import eu.kanade.presentation.browse.MigrateMangaState
|
||||
import eu.kanade.presentation.browse.MigrateMangaStateImpl
|
||||
import eu.kanade.presentation.browse.MigrationMangaState
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import logcat.LogPriority
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class MigrationMangaPresenter(
|
||||
class MigrateMangaPresenter(
|
||||
private val sourceId: Long,
|
||||
private val state: MigrateMangaStateImpl = MigrationMangaState() as MigrateMangaStateImpl,
|
||||
private val getFavorites: GetFavorites = Injekt.get(),
|
||||
) : BasePresenter<MigrationMangaController>() {
|
||||
) : BasePresenter<MigrationMangaController>(), MigrateMangaState by state {
|
||||
|
||||
private val _state: MutableStateFlow<MigrateMangaState> = MutableStateFlow(MigrateMangaState.Loading)
|
||||
val state: StateFlow<MigrateMangaState> = _state.asStateFlow()
|
||||
private val _events = Channel<Event>(Int.MAX_VALUE)
|
||||
val events = _events.receiveAsFlow()
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
@@ -28,20 +32,20 @@ class MigrationMangaPresenter(
|
||||
getFavorites
|
||||
.subscribe(sourceId)
|
||||
.catch { exception ->
|
||||
_state.value = MigrateMangaState.Error(exception)
|
||||
logcat(LogPriority.ERROR, exception)
|
||||
_events.send(Event.FailedFetchingFavorites)
|
||||
}
|
||||
.map { list ->
|
||||
list.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.title })
|
||||
}
|
||||
.collectLatest { sortedList ->
|
||||
_state.value = MigrateMangaState.Success(sortedList)
|
||||
state.isLoading = false
|
||||
state.items = sortedList
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class MigrateMangaState {
|
||||
object Loading : MigrateMangaState()
|
||||
data class Error(val error: Throwable) : MigrateMangaState()
|
||||
data class Success(val list: List<Manga>) : MigrateMangaState()
|
||||
sealed class Event {
|
||||
object FailedFetchingFavorites : Event()
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import eu.kanade.tachiyomi.ui.base.controller.pushController
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.search.SearchController
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
|
||||
class MigrationMangaController : ComposeController<MigrationMangaPresenter> {
|
||||
class MigrationMangaController : ComposeController<MigrateMangaPresenter> {
|
||||
|
||||
constructor(sourceId: Long, sourceName: String?) : super(
|
||||
bundleOf(
|
||||
@@ -30,7 +30,7 @@ class MigrationMangaController : ComposeController<MigrationMangaPresenter> {
|
||||
|
||||
override fun getTitle(): String? = sourceName
|
||||
|
||||
override fun createPresenter(): MigrationMangaPresenter = MigrationMangaPresenter(sourceId)
|
||||
override fun createPresenter(): MigrateMangaPresenter = MigrateMangaPresenter(sourceId)
|
||||
|
||||
@Composable
|
||||
override fun ComposeContent(nestedScrollInterop: NestedScrollConnection) {
|
||||
|
||||
@@ -10,7 +10,6 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.controller.ComposeController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.pushController
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrationMangaController
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||
|
||||
class MigrationSourcesController : ComposeController<MigrationSourcesPresenter>() {
|
||||
@@ -34,10 +33,6 @@ class MigrationSourcesController : ComposeController<MigrationSourcesPresenter>(
|
||||
),
|
||||
)
|
||||
},
|
||||
onLongClickItem = { source ->
|
||||
val sourceId = source.id.toString()
|
||||
activity?.copyToClipboard(sourceId, sourceId)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,24 +3,27 @@ package eu.kanade.tachiyomi.ui.browse.migration.sources
|
||||
import android.os.Bundle
|
||||
import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
|
||||
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
||||
import eu.kanade.domain.source.model.Source
|
||||
import eu.kanade.presentation.browse.MigrateSourceState
|
||||
import eu.kanade.presentation.browse.MigrateSourceStateImpl
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import logcat.LogPriority
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class MigrationSourcesPresenter(
|
||||
private val state: MigrateSourceStateImpl = MigrateSourceState() as MigrateSourceStateImpl,
|
||||
private val getSourcesWithFavoriteCount: GetSourcesWithFavoriteCount = Injekt.get(),
|
||||
private val setMigrateSorting: SetMigrateSorting = Injekt.get(),
|
||||
) : BasePresenter<MigrationSourcesController>() {
|
||||
) : BasePresenter<MigrationSourcesController>(), MigrateSourceState by state {
|
||||
|
||||
private val _state: MutableStateFlow<MigrateSourceState> = MutableStateFlow(MigrateSourceState.Loading)
|
||||
val state: StateFlow<MigrateSourceState> = _state.asStateFlow()
|
||||
private val _channel = Channel<Event>(Int.MAX_VALUE)
|
||||
val channel = _channel.receiveAsFlow()
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
@@ -28,10 +31,12 @@ class MigrationSourcesPresenter(
|
||||
presenterScope.launchIO {
|
||||
getSourcesWithFavoriteCount.subscribe()
|
||||
.catch { exception ->
|
||||
_state.value = MigrateSourceState.Error(exception)
|
||||
logcat(LogPriority.ERROR, exception)
|
||||
_channel.send(Event.FailedFetchingSourcesWithCount)
|
||||
}
|
||||
.collectLatest { sources ->
|
||||
_state.value = MigrateSourceState.Success(sources)
|
||||
state.items = sources
|
||||
state.isLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,10 +48,8 @@ class MigrationSourcesPresenter(
|
||||
fun setTotalSorting(isAscending: Boolean) {
|
||||
setMigrateSorting.await(SetMigrateSorting.Mode.TOTAL, isAscending)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class MigrateSourceState {
|
||||
object Loading : MigrateSourceState()
|
||||
data class Error(val error: Throwable) : MigrateSourceState()
|
||||
data class Success(val sources: List<Pair<Source, Long>>) : MigrateSourceState()
|
||||
sealed class Event {
|
||||
object FailedFetchingSourcesWithCount : Event()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,26 +5,30 @@ import eu.kanade.domain.source.interactor.GetLanguagesWithSources
|
||||
import eu.kanade.domain.source.interactor.ToggleLanguage
|
||||
import eu.kanade.domain.source.interactor.ToggleSource
|
||||
import eu.kanade.domain.source.model.Source
|
||||
import eu.kanade.presentation.browse.SourcesFilterState
|
||||
import eu.kanade.presentation.browse.SourcesFilterStateImpl
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import logcat.LogPriority
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class SourcesFilterPresenter(
|
||||
private val state: SourcesFilterStateImpl = SourcesFilterState() as SourcesFilterStateImpl,
|
||||
private val getLanguagesWithSources: GetLanguagesWithSources = Injekt.get(),
|
||||
private val toggleSource: ToggleSource = Injekt.get(),
|
||||
private val toggleLanguage: ToggleLanguage = Injekt.get(),
|
||||
private val preferences: PreferencesHelper = Injekt.get(),
|
||||
) : BasePresenter<SourceFilterController>() {
|
||||
) : BasePresenter<SourceFilterController>(), SourcesFilterState by state {
|
||||
|
||||
private val _state: MutableStateFlow<SourceFilterState> = MutableStateFlow(SourceFilterState.Loading)
|
||||
val state: StateFlow<SourceFilterState> = _state.asStateFlow()
|
||||
private val _events = Channel<Event>(Int.MAX_VALUE)
|
||||
val events = _events.receiveAsFlow()
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
@@ -32,14 +36,15 @@ class SourcesFilterPresenter(
|
||||
presenterScope.launchIO {
|
||||
getLanguagesWithSources.subscribe()
|
||||
.catch { exception ->
|
||||
_state.value = SourceFilterState.Error(exception)
|
||||
logcat(LogPriority.ERROR, exception)
|
||||
_events.send(Event.FailedFetchingLanguages)
|
||||
}
|
||||
.collectLatest(::collectLatestSourceLangMap)
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectLatestSourceLangMap(sourceLangMap: Map<String, List<Source>>) {
|
||||
val uiModels = sourceLangMap.flatMap {
|
||||
state.items = sourceLangMap.flatMap {
|
||||
val isLangEnabled = it.key in preferences.enabledLanguages().get()
|
||||
val header = listOf(FilterUiModel.Header(it.key, isLangEnabled))
|
||||
|
||||
@@ -51,7 +56,7 @@ class SourcesFilterPresenter(
|
||||
)
|
||||
}
|
||||
}
|
||||
_state.value = SourceFilterState.Success(uiModels)
|
||||
state.isLoading = false
|
||||
}
|
||||
|
||||
fun toggleSource(source: Source) {
|
||||
@@ -61,10 +66,8 @@ class SourcesFilterPresenter(
|
||||
fun toggleLanguage(language: String) {
|
||||
toggleLanguage.await(language)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class SourceFilterState {
|
||||
object Loading : SourceFilterState()
|
||||
data class Error(val error: Throwable) : SourceFilterState()
|
||||
data class Success(val models: List<FilterUiModel>) : SourceFilterState()
|
||||
sealed class Event {
|
||||
object FailedFetchingLanguages : Event()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,32 +7,37 @@ import eu.kanade.domain.source.interactor.ToggleSourcePin
|
||||
import eu.kanade.domain.source.model.Pin
|
||||
import eu.kanade.domain.source.model.Source
|
||||
import eu.kanade.presentation.browse.SourceUiModel
|
||||
import eu.kanade.presentation.browse.SourcesState
|
||||
import eu.kanade.presentation.browse.SourcesStateImpl
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import eu.kanade.tachiyomi.util.system.logcat
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import logcat.LogPriority
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.TreeMap
|
||||
|
||||
class SourcesPresenter(
|
||||
private val state: SourcesStateImpl = SourcesState() as SourcesStateImpl,
|
||||
private val getEnabledSources: GetEnabledSources = Injekt.get(),
|
||||
private val toggleSource: ToggleSource = Injekt.get(),
|
||||
private val toggleSourcePin: ToggleSourcePin = Injekt.get(),
|
||||
) : BasePresenter<SourcesController>() {
|
||||
) : BasePresenter<SourcesController>(), SourcesState by state {
|
||||
|
||||
private val _state: MutableStateFlow<SourceState> = MutableStateFlow(SourceState.Loading)
|
||||
val state: StateFlow<SourceState> = _state.asStateFlow()
|
||||
private val _events = Channel<Event>(Int.MAX_VALUE)
|
||||
val events = _events.receiveAsFlow()
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
presenterScope.launchIO {
|
||||
getEnabledSources.subscribe()
|
||||
.catch { exception ->
|
||||
_state.value = SourceState.Error(exception)
|
||||
logcat(LogPriority.ERROR, exception)
|
||||
_events.send(Event.FailedFetchingSources)
|
||||
}
|
||||
.collectLatest(::collectLatestSources)
|
||||
}
|
||||
@@ -67,7 +72,8 @@ class SourcesPresenter(
|
||||
}.toTypedArray(),
|
||||
)
|
||||
}
|
||||
_state.value = SourceState.Success(uiModels)
|
||||
state.isLoading = false
|
||||
state.items = uiModels
|
||||
}
|
||||
|
||||
fun toggleSource(source: Source) {
|
||||
@@ -78,14 +84,14 @@ class SourcesPresenter(
|
||||
toggleSourcePin.await(source)
|
||||
}
|
||||
|
||||
sealed class Event {
|
||||
object FailedFetchingSources : Event()
|
||||
}
|
||||
|
||||
data class Dialog(val source: Source)
|
||||
|
||||
companion object {
|
||||
const val PINNED_KEY = "pinned"
|
||||
const val LAST_USED_KEY = "last_used"
|
||||
}
|
||||
}
|
||||
|
||||
sealed class SourceState {
|
||||
object Loading : SourceState()
|
||||
data class Error(val error: Throwable) : SourceState()
|
||||
data class Success(val uiModels: List<SourceUiModel>) : SourceState()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user