Avoid crashing if opening browse with unavailable source

(cherry picked from commit 0ef7650c1a0ae7c4c6e17e458695191ce78944cb)

# Conflicts:
#	app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt
#	app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt
This commit is contained in:
arkon 2023-02-15 22:47:47 -05:00 committed by Jobobby04
parent 288fe0d888
commit ab19d5c62a
6 changed files with 91 additions and 40 deletions

View File

@ -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
@ -19,12 +21,15 @@ import eu.kanade.presentation.browse.components.BrowseSourceComfortableGrid
import eu.kanade.presentation.browse.components.BrowseSourceCompactGrid
import eu.kanade.presentation.browse.components.BrowseSourceEHentaiList
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 exh.metadata.metadata.base.RaisedSearchMetadata
import exh.source.isEhBasedSource
import kotlinx.coroutines.flow.StateFlow
@ -33,7 +38,7 @@ import tachiyomi.domain.manga.model.Manga
@Composable
fun BrowseSourceContent(
source: CatalogueSource?,
source: Source?,
mangaList: LazyPagingItems<StateFlow</* SY --> */Pair<Manga, RaisedSearchMetadata?>/* SY <-- */>>,
columns: GridCells,
// SY -->
@ -169,3 +174,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),
)
}
}

View File

@ -20,9 +20,9 @@ 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.ConfigurableSource
import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.Source
import exh.source.anyIs
import tachiyomi.domain.library.model.LibraryDisplayMode
@ -30,7 +30,7 @@ import tachiyomi.domain.library.model.LibraryDisplayMode
fun BrowseSourceToolbar(
searchQuery: String?,
onSearchQueryChange: (String?) -> Unit,
source: CatalogueSource?,
source: Source?,
displayMode: LibraryDisplayMode?,
onDisplayModeChange: (LibraryDisplayMode) -> Unit,
navigateUp: () -> Unit,

View File

@ -248,7 +248,7 @@ class SourceManager(
}
}
inner class SourceNotInstalledException(val sourceString: String) :
inner class SourceNotInstalledException(sourceString: String) :
Exception(context.getString(R.string.source_not_installed, sourceString))
// SY -->

View File

@ -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.FailedToLoadSavedSearchDialog
import eu.kanade.presentation.browse.components.RemoveMangaDialog
@ -51,7 +52,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.extension.details.SourcePreferencesScreen
import eu.kanade.tachiyomi.ui.browse.source.SourcesScreen
@ -83,12 +86,6 @@ 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 = sourceId,
@ -101,8 +98,7 @@ data class BrowseSourceScreen(
}
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)
@ -110,8 +106,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(
@ -169,7 +178,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 = {

View File

@ -143,7 +143,7 @@ open class BrowseSourceScreenModel(
var displayMode by sourcePreferences.sourceDisplayMode().asState(coroutineScope)
val source = sourceManager.get(sourceId) as CatalogueSource
val source = sourceManager.getOrStub(sourceId)
// SY -->
val ehentaiBrowseDisplayMode by unsortedPreferences.enhancedEHentaiView().asState(coroutineScope)
@ -152,20 +152,22 @@ open class BrowseSourceScreenModel(
// SY <--
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,
)
}
// SY -->
@ -185,14 +187,16 @@ open class BrowseSourceScreenModel(
}
}
getExhSavedSearch.subscribe(source.id, source::getFilterList)
.onEach { savedSearches ->
mutableState.update { it.copy(savedSearches = savedSearches) }
withUIContext {
filterSheet?.setSavedSearches(savedSearches)
if (source is CatalogueSource) {
getExhSavedSearch.subscribe(source.id, source::getFilterList)
.onEach { savedSearches ->
mutableState.update { it.copy(savedSearches = savedSearches) }
withUIContext {
filterSheet?.setSavedSearches(savedSearches)
}
}
}
.launchIn(coroutineScope)
.launchIn(coroutineScope)
}
// SY <--
}
@ -252,6 +256,8 @@ open class BrowseSourceScreenModel(
// SY <--
fun resetFilters() {
if (source !is CatalogueSource) return
mutableState.update { it.copy(filters = source.getFilterList()) }
}
@ -260,6 +266,7 @@ open class BrowseSourceScreenModel(
}
fun search(query: String? = null, filters: FilterList? = null) {
if (source !is CatalogueSource) return
// SY -->
if (filters != null && filters !== state.value.filters) {
mutableState.update { state -> state.copy(filters = filters) }
@ -280,6 +287,8 @@ open class BrowseSourceScreenModel(
}
fun searchGenre(genreName: String) {
if (source !is CatalogueSource) return
val defaultFilters = source.getFilterList()
var genreExists = false
@ -467,6 +476,7 @@ open class BrowseSourceScreenModel(
}
open fun initFilterSheet(context: Context, navigator: Navigator) {
source as? CatalogueSource ?: return
val state = state.value
/*if (state.filters.isEmpty()) {
return
@ -575,6 +585,7 @@ open class BrowseSourceScreenModel(
fun saveSearch(
name: String,
) {
if (source !is CatalogueSource) return
coroutineScope.launchNonCancellable {
val query = state.value.listing.query
val filterList = state.value.listing.filters.ifEmpty { source.getFilterList() }
@ -596,11 +607,15 @@ open class BrowseSourceScreenModel(
}
}
suspend fun loadSearch(searchId: Long) =
getExhSavedSearch.awaitOne(searchId, source::getFilterList)
suspend fun loadSearch(searchId: Long): EXHSavedSearch? {
if (source !is CatalogueSource) return null
return getExhSavedSearch.awaitOne(searchId, source::getFilterList)
}
suspend fun loadSearches() =
getExhSavedSearch.await(source.id, source::getFilterList)
suspend fun loadSearches(): List<EXHSavedSearch> {
if (source !is CatalogueSource) return emptyList()
return getExhSavedSearch.await(source.id, source::getFilterList)
}
// EXH <--
}

View File

@ -2,6 +2,7 @@ package exh.recs
import eu.kanade.domain.manga.interactor.GetManga
import eu.kanade.domain.source.model.SourcePagingSourceType
import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel
import kotlinx.coroutines.runBlocking
@ -17,6 +18,6 @@ class RecommendsScreenModel(
val manga = runBlocking { getManga.await(mangaId) }!!
override fun createSourcePagingSource(query: String, filters: FilterList): SourcePagingSourceType {
return RecommendsPagingSource(source, manga)
return RecommendsPagingSource(source as CatalogueSource, manga)
}
}