diff --git a/app/src/main/java/eu/kanade/presentation/source/SourceScreen.kt b/app/src/main/java/eu/kanade/presentation/source/SourceScreen.kt index 9a8274986..b2487936b 100644 --- a/app/src/main/java/eu/kanade/presentation/source/SourceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/source/SourceScreen.kt @@ -44,7 +44,7 @@ import eu.kanade.presentation.util.horizontalPadding import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.ui.browse.source.SourcePresenter -import eu.kanade.tachiyomi.ui.browse.source.UiModel +import eu.kanade.tachiyomi.ui.browse.source.SourceState import eu.kanade.tachiyomi.util.system.LocaleHelper @Composable @@ -58,13 +58,12 @@ fun SourceScreen( ) { val state by presenter.state.collectAsState() - when { - state.isLoading -> LoadingScreen() - state.hasError -> Text(text = state.error!!.message!!) - state.isEmpty -> EmptyScreen(message = "") - else -> SourceList( + when (state) { + is SourceState.Loading -> LoadingScreen() + is SourceState.Error -> Text(text = (state as SourceState.Error).error.message!!) + is SourceState.Success -> SourceList( nestedScrollConnection = nestedScrollInterop, - list = state.sources, + list = (state as SourceState.Success).uiModels, onClickItem = onClickItem, onClickDisable = onClickDisable, onClickLatest = onClickLatest, @@ -76,12 +75,17 @@ fun SourceScreen( @Composable fun SourceList( nestedScrollConnection: NestedScrollConnection, - list: List, + list: List, onClickItem: (Source) -> Unit, onClickDisable: (Source) -> Unit, onClickLatest: (Source) -> Unit, onClickPin: (Source) -> Unit, ) { + if (list.isEmpty()) { + EmptyScreen(textResource = R.string.source_empty_screen) + return + } + val (sourceState, setSourceState) = remember { mutableStateOf(null) } LazyColumn( modifier = Modifier @@ -92,25 +96,25 @@ fun SourceList( items = list, contentType = { when (it) { - is UiModel.Header -> "header" - is UiModel.Item -> "item" + is SourceUiModel.Header -> "header" + is SourceUiModel.Item -> "item" } }, key = { when (it) { - is UiModel.Header -> it.hashCode() - is UiModel.Item -> it.source.key() + is SourceUiModel.Header -> it.hashCode() + is SourceUiModel.Item -> it.source.key() } } ) { model -> when (model) { - is UiModel.Header -> { + is SourceUiModel.Header -> { SourceHeader( modifier = Modifier.animateItemPlacement(), language = model.language ) } - is UiModel.Item -> SourceItem( + is SourceUiModel.Item -> SourceItem( modifier = Modifier.animateItemPlacement(), source = model.source, onClickItem = onClickItem, @@ -262,3 +266,8 @@ fun SourceOptionsDialog( confirmButton = {}, ) } + +sealed class SourceUiModel { + data class Item(val source: Source) : SourceUiModel() + data class Header(val language: String) : SourceUiModel() +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcePresenter.kt index e35ad1054..ee0ea1a08 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcePresenter.kt @@ -6,6 +6,7 @@ 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 +import eu.kanade.presentation.source.SourceUiModel import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.util.lang.launchIO import kotlinx.coroutines.flow.MutableStateFlow @@ -13,7 +14,6 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.update import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.util.TreeMap @@ -28,7 +28,7 @@ class SourcePresenter( private val toggleSourcePin: ToggleSourcePin = Injekt.get() ) : BasePresenter() { - private val _state: MutableStateFlow = MutableStateFlow(SourceState.EMPTY) + private val _state: MutableStateFlow = MutableStateFlow(SourceState.Loading) val state: StateFlow = _state.asStateFlow() override fun onCreate(savedState: Bundle?) { @@ -36,15 +36,13 @@ class SourcePresenter( presenterScope.launchIO { getEnabledSources.subscribe() .catch { exception -> - _state.update { state -> - state.copy(sources = listOf(), error = exception) - } + _state.emit(SourceState.Error(exception)) } .collectLatest(::collectLatestSources) } } - private fun collectLatestSources(sources: List) { + private suspend fun collectLatestSources(sources: List) { val map = TreeMap> { d1, d2 -> // Catalogues without a lang defined will be placed at the end when { @@ -64,19 +62,16 @@ class SourcePresenter( else -> it.lang } } - _state.update { state -> - state.copy( - sources = byLang.flatMap { - listOf( - UiModel.Header(it.key), - *it.value.map { source -> - UiModel.Item(source) - }.toTypedArray() - ) - }, - error = null + + val uiModels = byLang.flatMap { + listOf( + SourceUiModel.Header(it.key), + *it.value.map { source -> + SourceUiModel.Item(source) + }.toTypedArray(), ) } + _state.emit(SourceState.Success(uiModels)) } fun toggleSource(source: Source) { @@ -93,26 +88,8 @@ class SourcePresenter( } } -sealed class UiModel { - data class Item(val source: Source) : UiModel() - data class Header(val language: String) : UiModel() -} - -data class SourceState( - val sources: List, - val error: Throwable? -) { - - val isLoading: Boolean - get() = sources.isEmpty() && error == null - - val hasError: Boolean - get() = error != null - - val isEmpty: Boolean - get() = sources.isEmpty() - - companion object { - val EMPTY = SourceState(listOf(), null) - } +sealed class SourceState { + object Loading : SourceState() + data class Error(val error: Throwable) : SourceState() + data class Success(val uiModels: List) : SourceState() } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f159a82ff..b3668e6ae 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -711,6 +711,9 @@ History deleted Are you sure? All history will be lost. + + No source found + No installed source found