mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 06:17:57 +01:00 
			
		
		
		
	Make SourceState similar to MigrateState (#7053)
				
					
				
			* make `SourceState` similar to `MigrateState` * Review Changes
This commit is contained in:
		| @@ -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() | ||||
| } | ||||
|   | ||||
| @@ -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() | ||||
| } | ||||
|   | ||||
| @@ -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> | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user