Quellcode durchsuchen

Make `SourceState` similar to `MigrateState` (#7053)

* make `SourceState` similar to `MigrateState`

* Review Changes
FourTOne5 vor 2 Jahren
Ursprung
Commit
bd45bf7407

+ 23 - 14
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<UiModel>,
+    list: List<SourceUiModel>,
     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<Source?>(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()
+}

+ 16 - 39
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<SourceController>() {
 
-    private val _state: MutableStateFlow<SourceState> = MutableStateFlow(SourceState.EMPTY)
+    private val _state: MutableStateFlow<SourceState> = MutableStateFlow(SourceState.Loading)
     val state: StateFlow<SourceState> = _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<Source>) {
+    private suspend fun collectLatestSources(sources: List<Source>) {
         val map = TreeMap<String, MutableList<Source>> { 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<UiModel>,
-    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<SourceUiModel>) : SourceState()
 }

+ 3 - 0
app/src/main/res/values/strings.xml

@@ -711,6 +711,9 @@
     <string name="clear_history_completed">History deleted</string>
     <string name="clear_history_confirmation">Are you sure? All history will be lost.</string>
 
+    <!-- Source Screen -->
+    <string name="source_empty_screen">No source found</string>
+
     <!-- Source Filter Screen -->
     <string name="source_filter_empty_screen">No installed source found</string>