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:
parent
288fe0d888
commit
ab19d5c62a
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 -->
|
||||
|
@ -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 = {
|
||||
|
@ -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 <--
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user