From ab19d5c62a74d353961b3f554f82a2b6864bdbf0 Mon Sep 17 00:00:00 2001 From: arkon Date: Wed, 15 Feb 2023 22:47:47 -0500 Subject: [PATCH] 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 --- .../presentation/browse/BrowseSourceScreen.kt | 30 ++++++++- .../browse/components/BrowseSourceToolbar.kt | 4 +- .../kanade/tachiyomi/source/SourceManager.kt | 2 +- .../source/browse/BrowseSourceScreen.kt | 29 ++++++--- .../source/browse/BrowseSourceScreenModel.kt | 63 ++++++++++++------- .../java/exh/recs/RecommendsScreenModel.kt | 3 +- 6 files changed, 91 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt index 73f32474b..9b7dfea73 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt @@ -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 */Pair/* 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), + ) + } +} diff --git a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt index 4e74e4f92..7ca9cfe30 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt @@ -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, diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt b/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt index 69aa88d09..2de99a437 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt @@ -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 --> diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt index 644ec761b..fcc148dbb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt @@ -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 = { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt index c848d11c6..f69d445c9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt @@ -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 { + if (source !is CatalogueSource) return emptyList() + return getExhSavedSearch.await(source.id, source::getFilterList) + } // EXH <-- } diff --git a/app/src/main/java/exh/recs/RecommendsScreenModel.kt b/app/src/main/java/exh/recs/RecommendsScreenModel.kt index 88743d7cc..5f539c6cd 100644 --- a/app/src/main/java/exh/recs/RecommendsScreenModel.kt +++ b/app/src/main/java/exh/recs/RecommendsScreenModel.kt @@ -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) } }