Fix: crash upon open RecommendsScreen if source is removed

This commit is contained in:
Cuong-Tran 2025-01-24 13:17:17 +07:00
parent 7e16b56911
commit 343cd3727c
No known key found for this signature in database
GPG key ID: 733AA7624B9315C2
9 changed files with 47 additions and 21 deletions

View file

@ -63,6 +63,7 @@ import eu.kanade.tachiyomi.ui.webview.WebViewScreen
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import exh.md.follows.MangaDexFollowsScreen import exh.md.follows.MangaDexFollowsScreen
import exh.source.isEhBasedSource import exh.source.isEhBasedSource
import exh.source.isMdBasedSource
import exh.ui.smartsearch.SmartSearchScreen import exh.ui.smartsearch.SmartSearchScreen
import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
@ -408,7 +409,7 @@ data class BrowseSourceScreen(
// KMK --> // KMK -->
onSavedSearchPressDesc = stringResource(KMR.strings.saved_searches_delete), onSavedSearchPressDesc = stringResource(KMR.strings.saved_searches_delete),
// KMK <-- // KMK <--
openMangaDexRandom = if (screenModel.sourceIsMangaDex) { openMangaDexRandom = if (screenModel.source.isMdBasedSource()) {
{ {
screenModel.onMangaDexRandom { screenModel.onMangaDexRandom {
navigator.replace( navigator.replace(
@ -422,7 +423,7 @@ data class BrowseSourceScreen(
} else { } else {
null null
}, },
openMangaDexFollows = if (screenModel.sourceIsMangaDex) { openMangaDexFollows = if (screenModel.source.isMdBasedSource()) {
{ {
navigator.replace(MangaDexFollowsScreen(sourceId)) navigator.replace(MangaDexFollowsScreen(sourceId))
} }

View file

@ -31,7 +31,6 @@ import eu.kanade.tachiyomi.source.online.all.MangaDex
import eu.kanade.tachiyomi.util.removeCovers import eu.kanade.tachiyomi.util.removeCovers
import exh.metadata.metadata.RaisedSearchMetadata import exh.metadata.metadata.RaisedSearchMetadata
import exh.source.getMainSource import exh.source.getMainSource
import exh.source.mangaDexSourceIds
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
@ -125,8 +124,6 @@ open class BrowseSourceScreenModel(
val startExpanded by uiPreferences.expandFilters().asState(screenModelScope) val startExpanded by uiPreferences.expandFilters().asState(screenModelScope)
private val filterSerializer = FilterSerializer() private val filterSerializer = FilterSerializer()
val sourceIsMangaDex = sourceId in mangaDexSourceIds
// SY <-- // SY <--
init { init {

View file

@ -7,6 +7,7 @@ import exh.recs.sources.RecommendationPagingSource
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import tachiyomi.domain.manga.interactor.GetManga import tachiyomi.domain.manga.interactor.GetManga
import tachiyomi.domain.source.service.SourceManager
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -15,12 +16,25 @@ class BrowseRecommendsScreenModel(
sourceId: Long, sourceId: Long,
private val recommendationSourceName: String, private val recommendationSourceName: String,
private val getManga: GetManga = Injekt.get(), private val getManga: GetManga = Injekt.get(),
// KMK -->
sourceManager: SourceManager = Injekt.get(),
// KMK <--
) : BrowseSourceScreenModel(sourceId, null) { ) : BrowseSourceScreenModel(sourceId, null) {
val manga = runBlocking { getManga.await(mangaId) }!! val manga = runBlocking { getManga.await(mangaId) }!!
// KMK -->
val source_ = sourceManager.get(sourceId)
?.let { it as CatalogueSource }
// KMK <--
val recommendationSource: RecommendationPagingSource val recommendationSource: RecommendationPagingSource
get() = RecommendationPagingSource.createSources(manga, source as CatalogueSource).first { get() = RecommendationPagingSource.createSources(
manga,
// KMK -->
source_,
// KMK <--
).first {
it::class.qualifiedName == recommendationSourceName it::class.qualifiedName == recommendationSourceName
} }

View file

@ -37,7 +37,10 @@ open class RecommendsScreenModel(
internal val networkToLocalManga: NetworkToLocalManga = Injekt.get(), internal val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
) : StateScreenModel<RecommendsScreenModel.State>(State()) { ) : StateScreenModel<RecommendsScreenModel.State>(State()) {
val source = sourceManager.getOrStub(sourceId) as CatalogueSource val source = sourceManager.get(sourceId)
// KMK -->
?.let { it as CatalogueSource }
// KMK <--
private val coroutineDispatcher = Dispatchers.IO.limitedParallelism(5) private val coroutineDispatcher = Dispatchers.IO.limitedParallelism(5)

View file

@ -21,7 +21,7 @@ import tachiyomi.core.common.util.system.logcat
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.sy.SYMR import tachiyomi.i18n.sy.SYMR
class AniListPagingSource(manga: Manga, source: CatalogueSource) : TrackerRecommendationPagingSource( class AniListPagingSource(manga: Manga, source: CatalogueSource?) : TrackerRecommendationPagingSource(
"https://graphql.anilist.co/", source, manga, "https://graphql.anilist.co/", source, manga,
) { ) {
override val name: String override val name: String

View file

@ -23,7 +23,7 @@ import tachiyomi.core.common.util.system.logcat
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.sy.SYMR import tachiyomi.i18n.sy.SYMR
abstract class MangaUpdatesPagingSource(manga: Manga, source: CatalogueSource) : TrackerRecommendationPagingSource( abstract class MangaUpdatesPagingSource(manga: Manga, source: CatalogueSource?) : TrackerRecommendationPagingSource(
"https://api.mangaupdates.com/v1/", source, manga, "https://api.mangaupdates.com/v1/", source, manga,
) { ) {
override val name: String override val name: String
@ -98,14 +98,14 @@ abstract class MangaUpdatesPagingSource(manga: Manga, source: CatalogueSource) :
} }
} }
class MangaUpdatesCommunityPagingSource(manga: Manga, source: CatalogueSource) : MangaUpdatesPagingSource(manga, source) { class MangaUpdatesCommunityPagingSource(manga: Manga, source: CatalogueSource?) : MangaUpdatesPagingSource(manga, source) {
override val category: StringResource override val category: StringResource
get() = SYMR.strings.community_recommendations get() = SYMR.strings.community_recommendations
override val recommendationJsonObjectName: String override val recommendationJsonObjectName: String
get() = "recommendations" get() = "recommendations"
} }
class MangaUpdatesSimilarPagingSource(manga: Manga, source: CatalogueSource) : MangaUpdatesPagingSource(manga, source) { class MangaUpdatesSimilarPagingSource(manga: Manga, source: CatalogueSource?) : MangaUpdatesPagingSource(manga, source) {
override val category: StringResource override val category: StringResource
get() = SYMR.strings.similar_titles get() = SYMR.strings.similar_titles
override val recommendationJsonObjectName: String override val recommendationJsonObjectName: String

View file

@ -17,7 +17,7 @@ import tachiyomi.core.common.util.system.logcat
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.sy.SYMR import tachiyomi.i18n.sy.SYMR
class MyAnimeListPagingSource(manga: Manga, source: CatalogueSource) : TrackerRecommendationPagingSource( class MyAnimeListPagingSource(manga: Manga, source: CatalogueSource?) : TrackerRecommendationPagingSource(
"https://api.jikan.moe/v4/", source, manga, "https://api.jikan.moe/v4/", source, manga,
) { ) {
override val name: String override val name: String

View file

@ -26,7 +26,7 @@ import uy.kohesive.injekt.injectLazy
* General class for recommendation sources. * General class for recommendation sources.
*/ */
abstract class RecommendationPagingSource( abstract class RecommendationPagingSource(
source: CatalogueSource, source: CatalogueSource?,
protected val manga: Manga, protected val manga: Manga,
) : SourcePagingSource(source) { ) : SourcePagingSource(source) {
// Display name // Display name
@ -44,7 +44,7 @@ abstract class RecommendationPagingSource(
open val associatedSourceId: Long? = null open val associatedSourceId: Long? = null
companion object { companion object {
fun createSources(manga: Manga, source: CatalogueSource): List<RecommendationPagingSource> { fun createSources(manga: Manga, source: CatalogueSource?): List<RecommendationPagingSource> {
return buildList { return buildList {
add(AniListPagingSource(manga, source)) add(AniListPagingSource(manga, source))
add(MangaUpdatesCommunityPagingSource(manga, source)) add(MangaUpdatesCommunityPagingSource(manga, source))
@ -52,12 +52,23 @@ abstract class RecommendationPagingSource(
add(MyAnimeListPagingSource(manga, source)) add(MyAnimeListPagingSource(manga, source))
// Only include MangaDex if the delegate sources are enabled and the source is MD-based // Only include MangaDex if the delegate sources are enabled and the source is MD-based
if (source.isMdBasedSource() && Injekt.get<DelegateSourcePreferences>().delegateSources().get()) { if (
// KMK -->
source != null &&
// KMK <--
source.isMdBasedSource() &&
Injekt.get<DelegateSourcePreferences>().delegateSources().get()
) {
add(MangaDexSimilarPagingSource(manga, source.getMainSource() as MangaDex)) add(MangaDexSimilarPagingSource(manga, source.getMainSource() as MangaDex))
} }
// Only include Comick if the source manga is from there // Only include Comick if the source manga is from there
if (source.isComickSource()) { if (
// KMK -->
source != null &&
// KMK <--
source.isComickSource()
) {
add(ComickPagingSource(manga, source)) add(ComickPagingSource(manga, source))
} }
}.sortedWith(compareBy({ it.name }, { it.category.resourceId })) }.sortedWith(compareBy({ it.name }, { it.category.resourceId }))
@ -70,7 +81,7 @@ abstract class RecommendationPagingSource(
*/ */
abstract class TrackerRecommendationPagingSource( abstract class TrackerRecommendationPagingSource(
protected val endpoint: String, protected val endpoint: String,
source: CatalogueSource, source: CatalogueSource?,
manga: Manga, manga: Manga,
) : RecommendationPagingSource(source, manga) { ) : RecommendationPagingSource(source, manga) {
private val getTracks: GetTracks by injectLazy() private val getTracks: GetTracks by injectLazy()

View file

@ -10,27 +10,27 @@ import exh.metadata.metadata.RaisedSearchMetadata
import tachiyomi.core.common.util.lang.withIOContext import tachiyomi.core.common.util.lang.withIOContext
import tachiyomi.domain.source.repository.SourcePagingSourceType import tachiyomi.domain.source.repository.SourcePagingSourceType
class SourceSearchPagingSource(source: CatalogueSource, val query: String, val filters: FilterList) : class SourceSearchPagingSource(/* KMK --> */ override val /* KMK <-- */source: CatalogueSource, val query: String, val filters: FilterList) :
SourcePagingSource(source) { SourcePagingSource(source) {
override suspend fun requestNextPage(currentPage: Int): MangasPage { override suspend fun requestNextPage(currentPage: Int): MangasPage {
return source.getSearchManga(currentPage, query, filters) return source.getSearchManga(currentPage, query, filters)
} }
} }
class SourcePopularPagingSource(source: CatalogueSource) : SourcePagingSource(source) { class SourcePopularPagingSource(/* KMK --> */ override val /* KMK <-- */source: CatalogueSource) : SourcePagingSource(source) {
override suspend fun requestNextPage(currentPage: Int): MangasPage { override suspend fun requestNextPage(currentPage: Int): MangasPage {
return source.getPopularManga(currentPage) return source.getPopularManga(currentPage)
} }
} }
class SourceLatestPagingSource(source: CatalogueSource) : SourcePagingSource(source) { class SourceLatestPagingSource(/* KMK --> */ override val /* KMK <-- */source: CatalogueSource) : SourcePagingSource(source) {
override suspend fun requestNextPage(currentPage: Int): MangasPage { override suspend fun requestNextPage(currentPage: Int): MangasPage {
return source.getLatestUpdates(currentPage) return source.getLatestUpdates(currentPage)
} }
} }
abstract class SourcePagingSource( abstract class SourcePagingSource(
protected open val source: CatalogueSource, protected open val source: CatalogueSource?,
) : SourcePagingSourceType() { ) : SourcePagingSourceType() {
abstract suspend fun requestNextPage(currentPage: Int): MangasPage abstract suspend fun requestNextPage(currentPage: Int): MangasPage