Skip to content

Commit

Permalink
Support RecommendsScreen even if MangaDex/Comick is not installed
Browse files Browse the repository at this point in the history
  • Loading branch information
cuong-tran committed Jan 24, 2025
1 parent 343cd37 commit c7c76d2
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 39 deletions.
57 changes: 49 additions & 8 deletions app/src/main/java/exh/md/similar/MangaDexSimilarPagingSource.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,37 @@ package exh.md.similar

import dev.icerock.moko.resources.StringResource
import eu.kanade.domain.manga.model.toSManga
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
import eu.kanade.tachiyomi.source.online.all.MangaDex
import exh.md.handlers.SimilarHandler
import exh.md.service.MangaDexService
import exh.md.service.SimilarService
import exh.md.utils.MdLang
import exh.recs.sources.RecommendationPagingSource
import exh.source.getMainSource
import exh.recs.sources.SourceCatalogue
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import tachiyomi.data.source.NoResultsException
import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.sy.SYMR
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get

/**
* MangaDexSimilarPagingSource inherited from the general Pager.
*/
class MangaDexSimilarPagingSource(
internal class MangaDexSimilarPagingSource(
manga: Manga,
private val mangaDex: MangaDex,
) : RecommendationPagingSource(mangaDex, manga) {
// KMK -->
private val sourceCatalogue: SourceCatalogue,
// KMK <--
) : RecommendationPagingSource(
// KMK -->
sourceCatalogue.source,
// KMK <--
manga,
) {

override val name: String
get() = "MangaDex"
Expand All @@ -28,12 +41,40 @@ class MangaDexSimilarPagingSource(
get() = SYMR.strings.similar_titles

override val associatedSourceId: Long
get() = mangaDex.getMainSource().id
// KMK -->
get() = sourceCatalogue.sourceId

private val client by lazy { Injekt.get<NetworkHelper>().client }

private val mdLang by lazy {
sourceCatalogue.source?.lang?.let { lang ->
MdLang.fromExt(lang)
} ?: MdLang.ENGLISH
}

private val mangadexService by lazy {
MangaDexService(client)
}
private val similarService by lazy {
SimilarService(client)
}
private val similarHandler by lazy {
SimilarHandler(mdLang.lang, mangadexService, similarService)
}
// KMK <--

override suspend fun requestNextPage(currentPage: Int): MangasPage {
val mangasPage = coroutineScope {
val similarPageDef = async { mangaDex.getMangaSimilar(manga.toSManga()) }
val relatedPageDef = async { mangaDex.getMangaRelated(manga.toSManga()) }
val similarPageDef = async {
// KMK -->
similarHandler.getSimilar(manga.toSManga())
// KMK <--
}
val relatedPageDef = async {
// KMK -->
similarHandler.getRelated(manga.toSManga())
// KMK <--
}
val similarPage = similarPageDef.await()
val relatedPage = relatedPageDef.await()

Expand Down
11 changes: 3 additions & 8 deletions app/src/main/java/exh/recs/BrowseRecommendsScreenModel.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package exh.recs

import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel
import exh.recs.sources.RecommendationPagingSource
import exh.recs.sources.SourceCatalogue
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.runBlocking
import tachiyomi.domain.manga.interactor.GetManga
import tachiyomi.domain.source.service.SourceManager
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get

Expand All @@ -16,23 +15,19 @@ class BrowseRecommendsScreenModel(
sourceId: Long,
private val recommendationSourceName: String,
private val getManga: GetManga = Injekt.get(),
// KMK -->
sourceManager: SourceManager = Injekt.get(),
// KMK <--
) : BrowseSourceScreenModel(sourceId, null) {

val manga = runBlocking { getManga.await(mangaId) }!!

// KMK -->
val source_ = sourceManager.get(sourceId)
?.let { it as CatalogueSource }
private val sourceCatalogue = SourceCatalogue(sourceId)
// KMK <--

val recommendationSource: RecommendationPagingSource
get() = RecommendationPagingSource.createSources(
manga,
// KMK -->
source_,
sourceCatalogue,
// KMK <--
).first {
it::class.qualifiedName == recommendationSourceName
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/exh/recs/RecommendsScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() {

val onClickItem = { manga: Manga ->
when (manga.source) {
-1L -> navigator.push(
RECOMMENDS_SOURCE -> navigator.push(
SourcesScreen(SourcesScreen.SmartSearchConfig(manga.ogTitle)),
)
else -> {
Expand All @@ -75,7 +75,7 @@ class RecommendsScreen(val mangaId: Long, val sourceId: Long) : Screen() {

val onLongClickItem = { manga: Manga ->
when (manga.source) {
-1L -> WebViewActivity.newIntent(context, manga.url, title = manga.title).let(context::startActivity)
RECOMMENDS_SOURCE -> WebViewActivity.newIntent(context, manga.url, title = manga.title).let(context::startActivity)
else -> {
// KMK -->
scope.launchIO {
Expand Down
20 changes: 12 additions & 8 deletions app/src/main/java/exh/recs/RecommendsScreenModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import androidx.compose.runtime.produceState
import cafe.adriel.voyager.core.model.StateScreenModel
import eu.kanade.domain.manga.model.toDomainManga
import eu.kanade.presentation.util.ioCoroutineScope
import eu.kanade.tachiyomi.source.CatalogueSource
import exh.recs.sources.RecommendationPagingSource
import exh.recs.sources.SourceCatalogue
import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.mutate
import kotlinx.collections.immutable.persistentMapOf
Expand All @@ -25,21 +25,18 @@ import kotlinx.coroutines.withContext
import tachiyomi.domain.manga.interactor.GetManga
import tachiyomi.domain.manga.interactor.NetworkToLocalManga
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.source.service.SourceManager
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get

open class RecommendsScreenModel(
val mangaId: Long,
val sourceId: Long,
sourceManager: SourceManager = Injekt.get(),
private val getManga: GetManga = Injekt.get(),
internal val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
) : StateScreenModel<RecommendsScreenModel.State>(State()) {

val source = sourceManager.get(sourceId)
// KMK -->
?.let { it as CatalogueSource }
// KMK -->
private val sourceCatalogue = SourceCatalogue(sourceId)
// KMK <--

private val coroutineDispatcher = Dispatchers.IO.limitedParallelism(5)
Expand All @@ -56,7 +53,12 @@ open class RecommendsScreenModel(
ioCoroutineScope.launch {
val manga = getManga.await(mangaId)!!
mutableState.update { it.copy(manga = manga) }
val recommendationSources = RecommendationPagingSource.createSources(manga, source)
val recommendationSources = RecommendationPagingSource.createSources(
manga,
// KMK -->
sourceCatalogue,
// KMK <--
)

updateItems(
recommendationSources
Expand All @@ -80,7 +82,7 @@ open class RecommendsScreenModel(
// KMK -->
// If the recommendation is associated with a source, resolve it
// Otherwise, skip this step. The user will be prompted to choose a source via SmartSearch
it.toDomainManga(recSourceId ?: -1)
it.toDomainManga(recSourceId ?: RECOMMENDS_SOURCE)
// KMK <--
}

Expand Down Expand Up @@ -155,3 +157,5 @@ sealed interface RecommendationItemResult {
return !onlyShowHasResults || (this is Success && !this.isEmpty)
}
}

const val RECOMMENDS_SOURCE = -1L
17 changes: 13 additions & 4 deletions app/src/main/java/exh/recs/sources/ComickPagingSource.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,17 @@ import uy.kohesive.injekt.injectLazy

fun CatalogueSource.isComickSource() = name == "Comick"

class ComickPagingSource(
internal class ComickPagingSource(
manga: Manga,
private val comickSource: CatalogueSource,
) : RecommendationPagingSource(comickSource, manga) {
// KMK -->
private val sourceCatalogue: SourceCatalogue,
// KMK <--
) : RecommendationPagingSource(
// KMK -->
sourceCatalogue.source,
// KMK <--
manga,
) {

override val name: String
get() = "Comick"
Expand All @@ -37,7 +44,9 @@ class ComickPagingSource(
get() = SYMR.strings.community_recommendations

override val associatedSourceId: Long
get() = comickSource.id
// KMK -->
get() = sourceCatalogue.sourceId
// KMK <--

private val client by lazy { Injekt.get<NetworkHelper>().client }
private val json by injectLazy<Json>()
Expand Down
55 changes: 46 additions & 9 deletions app/src/main/java/exh/recs/sources/RecommendationPagingSource.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.all.MangaDex
import exh.md.similar.MangaDexSimilarPagingSource
import exh.pref.DelegateSourcePreferences
import exh.source.getMainSource
import exh.source.COMICK_IDS
import exh.source.MANGADEX_IDS
import exh.source.isMdBasedSource
import kotlinx.serialization.json.Json
import logcat.LogPriority
import tachiyomi.core.common.util.system.logcat
import tachiyomi.data.source.NoResultsException
import tachiyomi.data.source.SourcePagingSource
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.source.service.SourceManager
import tachiyomi.domain.track.interactor.GetTracks
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
Expand Down Expand Up @@ -44,7 +45,15 @@ abstract class RecommendationPagingSource(
open val associatedSourceId: Long? = null

companion object {
fun createSources(manga: Manga, source: CatalogueSource?): List<RecommendationPagingSource> {
internal fun createSources(
manga: Manga,
// KMK -->
sourceCatalogue: SourceCatalogue,
// KMK <--
): List<RecommendationPagingSource> {
// KMK -->
val source = sourceCatalogue.source
// KMK <--
return buildList {
add(AniListPagingSource(manga, source))
add(MangaUpdatesCommunityPagingSource(manga, source))
Expand All @@ -54,22 +63,36 @@ abstract class RecommendationPagingSource(
// Only include MangaDex if the delegate sources are enabled and the source is MD-based
if (
// KMK -->
source != null &&
sourceCatalogue.isMangaDexSource() ||
// KMK <--
source.isMdBasedSource() &&
source?.isMdBasedSource() /* KMK --> */ == true /* KMK <-- */ &&
Injekt.get<DelegateSourcePreferences>().delegateSources().get()
) {
add(MangaDexSimilarPagingSource(manga, source.getMainSource() as MangaDex))
add(
MangaDexSimilarPagingSource(
manga,
// KMK -->
sourceCatalogue,
// KMK <--
),
)
}

// Only include Comick if the source manga is from there
if (
// KMK -->
source != null &&
sourceCatalogue.isComickSource() ||
// KMK <--
source.isComickSource()
source?.isComickSource() /* KMK --> */ == true /* KMK <-- */
) {
add(ComickPagingSource(manga, source))
add(
ComickPagingSource(
manga,
// KMK -->
sourceCatalogue,
// KMK <--
),
)
}
}.sortedWith(compareBy({ it.name }, { it.category.resourceId }))
}
Expand Down Expand Up @@ -123,3 +146,17 @@ abstract class TrackerRecommendationPagingSource(
return MangasPage(recs, false)
}
}

// KMK -->
internal class SourceCatalogue(
internal val sourceId: Long,
sourceManager: SourceManager = Injekt.get(),
) {
val source = sourceManager.get(sourceId)
?.let { it as CatalogueSource }

fun isComickSource(): Boolean = sourceId in COMICK_IDS

fun isMangaDexSource(): Boolean = sourceId in MANGADEX_IDS
}
// KMK <--
Loading

0 comments on commit c7c76d2

Please sign in to comment.