mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Avoid crashing if opening browse with unavailable source
This commit is contained in:
		@@ -1,6 +1,7 @@
 | 
			
		||||
package eu.kanade.presentation.browse
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.PaddingValues
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.lazy.grid.GridCells
 | 
			
		||||
import androidx.compose.material.icons.Icons
 | 
			
		||||
import androidx.compose.material.icons.outlined.HelpOutline
 | 
			
		||||
@@ -11,6 +12,7 @@ import androidx.compose.material3.SnackbarHostState
 | 
			
		||||
import androidx.compose.material3.SnackbarResult
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.LaunchedEffect
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.paging.LoadState
 | 
			
		||||
import androidx.paging.compose.LazyPagingItems
 | 
			
		||||
@@ -18,19 +20,22 @@ import eu.kanade.data.source.NoResultsException
 | 
			
		||||
import eu.kanade.presentation.browse.components.BrowseSourceComfortableGrid
 | 
			
		||||
import eu.kanade.presentation.browse.components.BrowseSourceCompactGrid
 | 
			
		||||
import eu.kanade.presentation.browse.components.BrowseSourceList
 | 
			
		||||
import eu.kanade.presentation.components.AppBar
 | 
			
		||||
import eu.kanade.presentation.components.EmptyScreen
 | 
			
		||||
import eu.kanade.presentation.components.EmptyScreenAction
 | 
			
		||||
import eu.kanade.presentation.components.LoadingScreen
 | 
			
		||||
import eu.kanade.presentation.components.Scaffold
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.source.CatalogueSource
 | 
			
		||||
import eu.kanade.tachiyomi.source.LocalSource
 | 
			
		||||
import eu.kanade.tachiyomi.source.Source
 | 
			
		||||
import eu.kanade.tachiyomi.source.SourceManager
 | 
			
		||||
import kotlinx.coroutines.flow.StateFlow
 | 
			
		||||
import tachiyomi.domain.library.model.LibraryDisplayMode
 | 
			
		||||
import tachiyomi.domain.manga.model.Manga
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun BrowseSourceContent(
 | 
			
		||||
    source: CatalogueSource?,
 | 
			
		||||
    source: Source?,
 | 
			
		||||
    mangaList: LazyPagingItems<StateFlow<Manga>>,
 | 
			
		||||
    columns: GridCells,
 | 
			
		||||
    displayMode: LibraryDisplayMode,
 | 
			
		||||
@@ -139,3 +144,24 @@ fun BrowseSourceContent(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun MissingSourceScreen(
 | 
			
		||||
    source: SourceManager.StubSource,
 | 
			
		||||
    navigateUp: () -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    Scaffold(
 | 
			
		||||
        topBar = { scrollBehavior ->
 | 
			
		||||
            AppBar(
 | 
			
		||||
                title = source.name,
 | 
			
		||||
                navigateUp = navigateUp,
 | 
			
		||||
                scrollBehavior = scrollBehavior,
 | 
			
		||||
            )
 | 
			
		||||
        },
 | 
			
		||||
    ) { paddingValues ->
 | 
			
		||||
        EmptyScreen(
 | 
			
		||||
            message = source.getSourceNotInstalledException().message!!,
 | 
			
		||||
            modifier = Modifier.padding(paddingValues),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,15 +20,15 @@ import eu.kanade.presentation.components.DropdownMenu
 | 
			
		||||
import eu.kanade.presentation.components.RadioMenuItem
 | 
			
		||||
import eu.kanade.presentation.components.SearchToolbar
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.source.CatalogueSource
 | 
			
		||||
import eu.kanade.tachiyomi.source.LocalSource
 | 
			
		||||
import eu.kanade.tachiyomi.source.Source
 | 
			
		||||
import tachiyomi.domain.library.model.LibraryDisplayMode
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun BrowseSourceToolbar(
 | 
			
		||||
    searchQuery: String?,
 | 
			
		||||
    onSearchQueryChange: (String?) -> Unit,
 | 
			
		||||
    source: CatalogueSource?,
 | 
			
		||||
    source: Source?,
 | 
			
		||||
    displayMode: LibraryDisplayMode,
 | 
			
		||||
    onDisplayModeChange: (LibraryDisplayMode) -> Unit,
 | 
			
		||||
    navigateUp: () -> Unit,
 | 
			
		||||
 
 | 
			
		||||
@@ -152,6 +152,6 @@ class SourceManager(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inner class SourceNotInstalledException(val sourceString: String) :
 | 
			
		||||
    inner class SourceNotInstalledException(sourceString: String) :
 | 
			
		||||
        Exception(context.getString(R.string.source_not_installed, sourceString))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@ import cafe.adriel.voyager.core.screen.uniqueScreenKey
 | 
			
		||||
import cafe.adriel.voyager.navigator.LocalNavigator
 | 
			
		||||
import cafe.adriel.voyager.navigator.currentOrThrow
 | 
			
		||||
import eu.kanade.presentation.browse.BrowseSourceContent
 | 
			
		||||
import eu.kanade.presentation.browse.MissingSourceScreen
 | 
			
		||||
import eu.kanade.presentation.browse.components.BrowseSourceToolbar
 | 
			
		||||
import eu.kanade.presentation.browse.components.RemoveMangaDialog
 | 
			
		||||
import eu.kanade.presentation.components.ChangeCategoryDialog
 | 
			
		||||
@@ -48,7 +49,9 @@ import eu.kanade.presentation.components.Scaffold
 | 
			
		||||
import eu.kanade.presentation.util.AssistContentScreen
 | 
			
		||||
import eu.kanade.presentation.util.padding
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.source.CatalogueSource
 | 
			
		||||
import eu.kanade.tachiyomi.source.LocalSource
 | 
			
		||||
import eu.kanade.tachiyomi.source.SourceManager
 | 
			
		||||
import eu.kanade.tachiyomi.source.online.HttpSource
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel.Listing
 | 
			
		||||
import eu.kanade.tachiyomi.ui.category.CategoryScreen
 | 
			
		||||
@@ -73,17 +76,10 @@ data class BrowseSourceScreen(
 | 
			
		||||
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun Content() {
 | 
			
		||||
        val navigator = LocalNavigator.currentOrThrow
 | 
			
		||||
        val scope = rememberCoroutineScope()
 | 
			
		||||
        val context = LocalContext.current
 | 
			
		||||
        val haptic = LocalHapticFeedback.current
 | 
			
		||||
        val uriHandler = LocalUriHandler.current
 | 
			
		||||
 | 
			
		||||
        val screenModel = rememberScreenModel { BrowseSourceScreenModel(sourceId, listingQuery) }
 | 
			
		||||
        val state by screenModel.state.collectAsState()
 | 
			
		||||
 | 
			
		||||
        val snackbarHostState = remember { SnackbarHostState() }
 | 
			
		||||
 | 
			
		||||
        val navigator = LocalNavigator.currentOrThrow
 | 
			
		||||
        val navigateUp: () -> Unit = {
 | 
			
		||||
            when {
 | 
			
		||||
                !state.isUserQuery && state.toolbarQuery != null -> screenModel.setToolbarQuery(null)
 | 
			
		||||
@@ -91,8 +87,21 @@ data class BrowseSourceScreen(
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val onHelpClick = { uriHandler.openUri(LocalSource.HELP_URL) }
 | 
			
		||||
        if (screenModel.source is SourceManager.StubSource) {
 | 
			
		||||
            MissingSourceScreen(
 | 
			
		||||
                source = screenModel.source,
 | 
			
		||||
                navigateUp = navigateUp,
 | 
			
		||||
            )
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val scope = rememberCoroutineScope()
 | 
			
		||||
        val context = LocalContext.current
 | 
			
		||||
        val haptic = LocalHapticFeedback.current
 | 
			
		||||
        val uriHandler = LocalUriHandler.current
 | 
			
		||||
        val snackbarHostState = remember { SnackbarHostState() }
 | 
			
		||||
 | 
			
		||||
        val onHelpClick = { uriHandler.openUri(LocalSource.HELP_URL) }
 | 
			
		||||
        val onWebViewClick = f@{
 | 
			
		||||
            val source = screenModel.source as? HttpSource ?: return@f
 | 
			
		||||
            navigator.push(
 | 
			
		||||
@@ -147,7 +156,7 @@ data class BrowseSourceScreen(
 | 
			
		||||
                                Text(text = stringResource(R.string.popular))
 | 
			
		||||
                            },
 | 
			
		||||
                        )
 | 
			
		||||
                        if (screenModel.source.supportsLatest) {
 | 
			
		||||
                        if ((screenModel.source as CatalogueSource).supportsLatest) {
 | 
			
		||||
                            FilterChip(
 | 
			
		||||
                                selected = state.listing == Listing.Latest,
 | 
			
		||||
                                onClick = {
 | 
			
		||||
 
 | 
			
		||||
@@ -103,23 +103,25 @@ class BrowseSourceScreenModel(
 | 
			
		||||
 | 
			
		||||
    var displayMode by sourcePreferences.sourceDisplayMode().asState(coroutineScope)
 | 
			
		||||
 | 
			
		||||
    val source = sourceManager.get(sourceId) as CatalogueSource
 | 
			
		||||
    val source = sourceManager.getOrStub(sourceId)
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        mutableState.update {
 | 
			
		||||
            var query: String? = null
 | 
			
		||||
            var listing = it.listing
 | 
			
		||||
        if (source is CatalogueSource) {
 | 
			
		||||
            mutableState.update {
 | 
			
		||||
                var query: String? = null
 | 
			
		||||
                var listing = it.listing
 | 
			
		||||
 | 
			
		||||
            if (listing is Listing.Search) {
 | 
			
		||||
                query = listing.query
 | 
			
		||||
                listing = Listing.Search(query, source.getFilterList())
 | 
			
		||||
                if (listing is Listing.Search) {
 | 
			
		||||
                    query = listing.query
 | 
			
		||||
                    listing = Listing.Search(query, source.getFilterList())
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                it.copy(
 | 
			
		||||
                    listing = listing,
 | 
			
		||||
                    filters = source.getFilterList(),
 | 
			
		||||
                    toolbarQuery = query,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            it.copy(
 | 
			
		||||
                listing = listing,
 | 
			
		||||
                filters = source.getFilterList(),
 | 
			
		||||
                toolbarQuery = query,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -164,6 +166,8 @@ class BrowseSourceScreenModel(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun resetFilters() {
 | 
			
		||||
        if (source !is CatalogueSource) return
 | 
			
		||||
 | 
			
		||||
        mutableState.update { it.copy(filters = source.getFilterList()) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -172,6 +176,8 @@ class BrowseSourceScreenModel(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun search(query: String? = null, filters: FilterList? = null) {
 | 
			
		||||
        if (source !is CatalogueSource) return
 | 
			
		||||
 | 
			
		||||
        val input = state.value.listing as? Listing.Search
 | 
			
		||||
            ?: Listing.Search(query = null, filters = source.getFilterList())
 | 
			
		||||
 | 
			
		||||
@@ -187,6 +193,8 @@ class BrowseSourceScreenModel(
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun searchGenre(genreName: String) {
 | 
			
		||||
        if (source !is CatalogueSource) return
 | 
			
		||||
 | 
			
		||||
        val defaultFilters = source.getFilterList()
 | 
			
		||||
        var genreExists = false
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user