mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +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