mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-14 21:18:56 +01:00
Migrate Source Filter Screen to Compose (#7031)
* Migrate Source Filter Screen to Compose * Changes from Review and some more fixes * Rename some variable and classes * Review Change * Ewbase and Review changes
This commit is contained in:
@@ -48,7 +48,7 @@ class SourceController : SearchableComposeController<SourcePresenter>() {
|
||||
openSource(source, BrowseSourceController(source))
|
||||
},
|
||||
onClickDisable = { source ->
|
||||
presenter.disableSource(source)
|
||||
presenter.toggleSource(source)
|
||||
},
|
||||
onClickLatest = { source ->
|
||||
openSource(source, LatestUpdatesController(source))
|
||||
|
||||
@@ -1,112 +1,34 @@
|
||||
package eu.kanade.tachiyomi.ui.browse.source
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.preference.CheckBoxPreference
|
||||
import androidx.preference.PreferenceGroup
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import eu.kanade.domain.source.model.Source
|
||||
import eu.kanade.presentation.source.SourceFilterScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.getPreferenceKey
|
||||
import eu.kanade.tachiyomi.source.icon
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.ui.setting.SettingsController
|
||||
import eu.kanade.tachiyomi.util.preference.minusAssign
|
||||
import eu.kanade.tachiyomi.util.preference.onChange
|
||||
import eu.kanade.tachiyomi.util.preference.plusAssign
|
||||
import eu.kanade.tachiyomi.util.preference.switchPreferenceCategory
|
||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.TreeMap
|
||||
import eu.kanade.tachiyomi.ui.base.controller.ComposeController
|
||||
|
||||
class SourceFilterController : SettingsController() {
|
||||
class SourceFilterController : ComposeController<SourceFilterPresenter>() {
|
||||
|
||||
private val onlineSources by lazy { Injekt.get<SourceManager>().getOnlineSources() }
|
||||
override fun getTitle() = resources?.getString(R.string.label_sources)
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
|
||||
titleRes = R.string.label_sources
|
||||
override fun createPresenter(): SourceFilterPresenter = SourceFilterPresenter()
|
||||
|
||||
// Get the list of active language codes.
|
||||
val activeLangsCodes = preferences.enabledLanguages().get()
|
||||
|
||||
// Get a map of sources grouped by language.
|
||||
val sourcesByLang = onlineSources.groupByTo(TreeMap(), { it.lang })
|
||||
|
||||
// Order first by active languages, then inactive ones
|
||||
val orderedLangs = sourcesByLang.keys.sortedWith(
|
||||
compareBy(
|
||||
{ it !in activeLangsCodes },
|
||||
{ LocaleHelper.getSourceDisplayName(it, context) },
|
||||
),
|
||||
@Composable
|
||||
override fun ComposeContent(nestedScrollInterop: NestedScrollConnection) {
|
||||
SourceFilterScreen(
|
||||
nestedScrollInterop = nestedScrollInterop,
|
||||
presenter = presenter,
|
||||
onClickLang = { language ->
|
||||
presenter.toggleLanguage(language)
|
||||
},
|
||||
onClickSource = { source ->
|
||||
presenter.toggleSource(source)
|
||||
},
|
||||
)
|
||||
|
||||
orderedLangs.forEach { lang ->
|
||||
val sources = sourcesByLang[lang].orEmpty().sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, { it.name }))
|
||||
|
||||
// Create a preference group and set initial state and change listener
|
||||
switchPreferenceCategory {
|
||||
this@apply.addPreference(this)
|
||||
title = LocaleHelper.getSourceDisplayName(lang, context)
|
||||
isPersistent = false
|
||||
if (lang in activeLangsCodes) {
|
||||
setChecked(true)
|
||||
addLanguageSources(this, sources)
|
||||
}
|
||||
|
||||
onChange { newValue ->
|
||||
val checked = newValue as Boolean
|
||||
if (!checked) {
|
||||
preferences.enabledLanguages() -= lang
|
||||
removeAll()
|
||||
} else {
|
||||
preferences.enabledLanguages() += lang
|
||||
addLanguageSources(this, sources)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setDivider(divider: Drawable?) {
|
||||
super.setDivider(null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the source list for the given group (language).
|
||||
*
|
||||
* @param group the language category.
|
||||
*/
|
||||
private fun addLanguageSources(group: PreferenceGroup, sources: List<HttpSource>) {
|
||||
val disabledSourceIds = preferences.disabledSources().get()
|
||||
|
||||
sources
|
||||
.sortedBy { it.id.toString() in disabledSourceIds }
|
||||
.map { source ->
|
||||
CheckBoxPreference(group.context).apply {
|
||||
val id = source.id.toString()
|
||||
title = source.name
|
||||
key = source.getPreferenceKey()
|
||||
isPersistent = false
|
||||
isChecked = id !in disabledSourceIds
|
||||
|
||||
val sourceIcon = source.icon()
|
||||
if (sourceIcon != null) {
|
||||
icon = sourceIcon
|
||||
}
|
||||
|
||||
onChange { newValue ->
|
||||
val checked = newValue as Boolean
|
||||
if (checked) {
|
||||
preferences.disabledSources() -= id
|
||||
} else {
|
||||
preferences.disabledSources() += id
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
.forEach { group.addPreference(it) }
|
||||
}
|
||||
}
|
||||
|
||||
sealed class FilterUiModel {
|
||||
data class Header(val language: String, val isEnabled: Boolean) : FilterUiModel()
|
||||
data class Item(val source: Source, val isEnabled: Boolean) : FilterUiModel()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package eu.kanade.tachiyomi.ui.browse.source
|
||||
|
||||
import android.os.Bundle
|
||||
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.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 kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class SourceFilterPresenter(
|
||||
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>() {
|
||||
|
||||
private val _state: MutableStateFlow<SourceFilterState> = MutableStateFlow(SourceFilterState.Loading)
|
||||
val state: StateFlow<SourceFilterState> = _state.asStateFlow()
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
presenterScope.launchIO {
|
||||
getLanguagesWithSources.subscribe()
|
||||
.catch { exception ->
|
||||
_state.emit(SourceFilterState.Error(exception))
|
||||
}
|
||||
.collectLatest { sourceLangMap ->
|
||||
val uiModels = sourceLangMap.toFilterUiModels()
|
||||
_state.emit(SourceFilterState.Success(uiModels))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Map<String, List<Source>>.toFilterUiModels(): List<FilterUiModel> {
|
||||
return this.flatMap {
|
||||
val isLangEnabled = it.key in preferences.enabledLanguages().get()
|
||||
val header = listOf(FilterUiModel.Header(it.key, isLangEnabled))
|
||||
|
||||
if (isLangEnabled.not()) return@flatMap header
|
||||
header + it.value.map { source ->
|
||||
FilterUiModel.Item(
|
||||
source,
|
||||
source.id.toString() !in preferences.disabledSources().get()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleSource(source: Source) {
|
||||
toggleSource.await(source)
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package eu.kanade.tachiyomi.ui.browse.source
|
||||
|
||||
import android.os.Bundle
|
||||
import eu.kanade.domain.source.interactor.DisableSource
|
||||
import eu.kanade.domain.source.interactor.GetEnabledSources
|
||||
import eu.kanade.domain.source.interactor.ToggleSource
|
||||
import eu.kanade.domain.source.interactor.ToggleSourcePin
|
||||
import eu.kanade.domain.source.model.Pin
|
||||
import eu.kanade.domain.source.model.Source
|
||||
@@ -24,7 +24,7 @@ import java.util.TreeMap
|
||||
*/
|
||||
class SourcePresenter(
|
||||
private val getEnabledSources: GetEnabledSources = Injekt.get(),
|
||||
private val disableSource: DisableSource = Injekt.get(),
|
||||
private val toggleSource: ToggleSource = Injekt.get(),
|
||||
private val toggleSourcePin: ToggleSourcePin = Injekt.get()
|
||||
) : BasePresenter<SourceController>() {
|
||||
|
||||
@@ -79,8 +79,8 @@ class SourcePresenter(
|
||||
}
|
||||
}
|
||||
|
||||
fun disableSource(source: Source) {
|
||||
disableSource.await(source)
|
||||
fun toggleSource(source: Source) {
|
||||
toggleSource.await(source)
|
||||
}
|
||||
|
||||
fun togglePin(source: Source) {
|
||||
|
||||
Reference in New Issue
Block a user