mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-03 23:58:55 +01:00 
			
		
		
		
	Allow extensions to open manga or chapter by URL (#9996)
* open manga and chapter using URL * removing unnnecessary logs * Resolving comments * Resolving comments
This commit is contained in:
		@@ -41,6 +41,7 @@ import tachiyomi.domain.category.interactor.UpdateCategory
 | 
			
		||||
import tachiyomi.domain.category.repository.CategoryRepository
 | 
			
		||||
import tachiyomi.domain.chapter.interactor.GetChapter
 | 
			
		||||
import tachiyomi.domain.chapter.interactor.GetChapterByMangaId
 | 
			
		||||
import tachiyomi.domain.chapter.interactor.GetChapterByUrlAndMangaId
 | 
			
		||||
import tachiyomi.domain.chapter.interactor.SetMangaDefaultChapterFlags
 | 
			
		||||
import tachiyomi.domain.chapter.interactor.ShouldUpdateDbChapter
 | 
			
		||||
import tachiyomi.domain.chapter.interactor.UpdateChapter
 | 
			
		||||
@@ -56,6 +57,7 @@ import tachiyomi.domain.manga.interactor.GetDuplicateLibraryManga
 | 
			
		||||
import tachiyomi.domain.manga.interactor.GetFavorites
 | 
			
		||||
import tachiyomi.domain.manga.interactor.GetLibraryManga
 | 
			
		||||
import tachiyomi.domain.manga.interactor.GetManga
 | 
			
		||||
import tachiyomi.domain.manga.interactor.GetMangaByUrlAndSourceId
 | 
			
		||||
import tachiyomi.domain.manga.interactor.GetMangaWithChapters
 | 
			
		||||
import tachiyomi.domain.manga.interactor.NetworkToLocalManga
 | 
			
		||||
import tachiyomi.domain.manga.interactor.ResetViewerFlags
 | 
			
		||||
@@ -99,6 +101,7 @@ class DomainModule : InjektModule {
 | 
			
		||||
        addFactory { GetFavorites(get()) }
 | 
			
		||||
        addFactory { GetLibraryManga(get()) }
 | 
			
		||||
        addFactory { GetMangaWithChapters(get(), get()) }
 | 
			
		||||
        addFactory { GetMangaByUrlAndSourceId(get()) }
 | 
			
		||||
        addFactory { GetManga(get()) }
 | 
			
		||||
        addFactory { GetNextChapters(get(), get(), get()) }
 | 
			
		||||
        addFactory { ResetViewerFlags(get()) }
 | 
			
		||||
@@ -126,6 +129,7 @@ class DomainModule : InjektModule {
 | 
			
		||||
        addSingletonFactory<ChapterRepository> { ChapterRepositoryImpl(get()) }
 | 
			
		||||
        addFactory { GetChapter(get()) }
 | 
			
		||||
        addFactory { GetChapterByMangaId(get()) }
 | 
			
		||||
        addFactory { GetChapterByUrlAndMangaId(get()) }
 | 
			
		||||
        addFactory { UpdateChapter(get()) }
 | 
			
		||||
        addFactory { SetReadStatus(get(), get(), get(), get()) }
 | 
			
		||||
        addFactory { ShouldUpdateDbChapter() }
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.collectAsState
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import cafe.adriel.voyager.core.model.rememberScreenModel
 | 
			
		||||
import cafe.adriel.voyager.navigator.LocalNavigator
 | 
			
		||||
@@ -14,6 +15,7 @@ import eu.kanade.presentation.util.Screen
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
 | 
			
		||||
import tachiyomi.presentation.core.components.material.Scaffold
 | 
			
		||||
import tachiyomi.presentation.core.screens.LoadingScreen
 | 
			
		||||
 | 
			
		||||
@@ -23,6 +25,7 @@ class DeepLinkScreen(
 | 
			
		||||
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun Content() {
 | 
			
		||||
        val context = LocalContext.current
 | 
			
		||||
        val navigator = LocalNavigator.currentOrThrow
 | 
			
		||||
 | 
			
		||||
        val screenModel = rememberScreenModel {
 | 
			
		||||
@@ -46,12 +49,22 @@ class DeepLinkScreen(
 | 
			
		||||
                    navigator.replace(GlobalSearchScreen(query))
 | 
			
		||||
                }
 | 
			
		||||
                is DeepLinkScreenModel.State.Result -> {
 | 
			
		||||
                    navigator.replace(
 | 
			
		||||
                        MangaScreen(
 | 
			
		||||
                            (state as DeepLinkScreenModel.State.Result).manga.id,
 | 
			
		||||
                            true,
 | 
			
		||||
                        ),
 | 
			
		||||
                    )
 | 
			
		||||
                    val resultState = state as DeepLinkScreenModel.State.Result
 | 
			
		||||
                    if (resultState.chapterId == null) {
 | 
			
		||||
                        navigator.replace(
 | 
			
		||||
                            MangaScreen(
 | 
			
		||||
                                resultState.manga.id,
 | 
			
		||||
                                true,
 | 
			
		||||
                            ),
 | 
			
		||||
                        )
 | 
			
		||||
                    } else {
 | 
			
		||||
                        navigator.pop()
 | 
			
		||||
                        ReaderActivity.newIntent(
 | 
			
		||||
                            context,
 | 
			
		||||
                            resultState.manga.id,
 | 
			
		||||
                            resultState.chapterId,
 | 
			
		||||
                        ).also(context::startActivity)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,10 +3,20 @@ package eu.kanade.tachiyomi.ui.deeplink
 | 
			
		||||
import androidx.compose.runtime.Immutable
 | 
			
		||||
import cafe.adriel.voyager.core.model.StateScreenModel
 | 
			
		||||
import cafe.adriel.voyager.core.model.coroutineScope
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
 | 
			
		||||
import eu.kanade.domain.manga.model.toDomainManga
 | 
			
		||||
import eu.kanade.domain.manga.model.toSManga
 | 
			
		||||
import eu.kanade.tachiyomi.source.Source
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.SChapter
 | 
			
		||||
import eu.kanade.tachiyomi.source.model.SManga
 | 
			
		||||
import eu.kanade.tachiyomi.source.online.ResolvableSource
 | 
			
		||||
import eu.kanade.tachiyomi.source.online.UriType
 | 
			
		||||
import kotlinx.coroutines.flow.update
 | 
			
		||||
import tachiyomi.core.util.lang.launchIO
 | 
			
		||||
import tachiyomi.domain.chapter.interactor.GetChapterByUrlAndMangaId
 | 
			
		||||
import tachiyomi.domain.chapter.model.Chapter
 | 
			
		||||
import tachiyomi.domain.manga.interactor.GetMangaByUrlAndSourceId
 | 
			
		||||
import tachiyomi.domain.manga.interactor.NetworkToLocalManga
 | 
			
		||||
import tachiyomi.domain.manga.model.Manga
 | 
			
		||||
import tachiyomi.domain.source.service.SourceManager
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
@@ -15,25 +25,59 @@ import uy.kohesive.injekt.api.get
 | 
			
		||||
class DeepLinkScreenModel(
 | 
			
		||||
    query: String = "",
 | 
			
		||||
    private val sourceManager: SourceManager = Injekt.get(),
 | 
			
		||||
    private val networkToLocalManga: NetworkToLocalManga = Injekt.get(),
 | 
			
		||||
    private val getChapterByUrlAndMangaId: GetChapterByUrlAndMangaId = Injekt.get(),
 | 
			
		||||
    private val getMangaByUrlAndSourceId: GetMangaByUrlAndSourceId = Injekt.get(),
 | 
			
		||||
    private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(),
 | 
			
		||||
) : StateScreenModel<DeepLinkScreenModel.State>(State.Loading) {
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        coroutineScope.launchIO {
 | 
			
		||||
            val manga = sourceManager.getCatalogueSources()
 | 
			
		||||
            val source = sourceManager.getCatalogueSources()
 | 
			
		||||
                .filterIsInstance<ResolvableSource>()
 | 
			
		||||
                .filter { it.canResolveUri(query) }
 | 
			
		||||
                .firstNotNullOfOrNull { it.getManga(query)?.toDomainManga(it.id) }
 | 
			
		||||
                .firstOrNull { it.getUriType(query) != UriType.Unknown }
 | 
			
		||||
 | 
			
		||||
            val manga = source?.getManga(query)?.let {
 | 
			
		||||
                getMangaFromSManga(it, source.id)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            val chapter = if (source?.getUriType(query) == UriType.Chapter && manga != null) {
 | 
			
		||||
                source.getChapter(query)?.let { getChapterFromSChapter(it, manga, source) }
 | 
			
		||||
            } else {
 | 
			
		||||
                null
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            mutableState.update {
 | 
			
		||||
                if (manga == null) {
 | 
			
		||||
                    State.NoResults
 | 
			
		||||
                } else {
 | 
			
		||||
                    State.Result(manga)
 | 
			
		||||
                    if (chapter == null) {
 | 
			
		||||
                        State.Result(manga)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        State.Result(manga, chapter.id)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private suspend fun getChapterFromSChapter(sChapter: SChapter, manga: Manga, source: Source): Chapter? {
 | 
			
		||||
        val localChapter = getChapterByUrlAndMangaId.await(sChapter.url, manga.id)
 | 
			
		||||
 | 
			
		||||
        return if (localChapter == null) {
 | 
			
		||||
            val sourceChapters = source.getChapterList(manga.toSManga())
 | 
			
		||||
            val newChapters = syncChaptersWithSource.await(sourceChapters, manga, source, false)
 | 
			
		||||
            newChapters.find { it.url == sChapter.url }
 | 
			
		||||
        } else {
 | 
			
		||||
            localChapter
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private suspend fun getMangaFromSManga(sManga: SManga, sourceId: Long): Manga {
 | 
			
		||||
        return getMangaByUrlAndSourceId.awaitManga(sManga.url, sourceId)
 | 
			
		||||
            ?: networkToLocalManga.await(sManga.toDomainManga(sourceId))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sealed interface State {
 | 
			
		||||
        @Immutable
 | 
			
		||||
        data object Loading : State
 | 
			
		||||
@@ -42,6 +86,6 @@ class DeepLinkScreenModel(
 | 
			
		||||
        data object NoResults : State
 | 
			
		||||
 | 
			
		||||
        @Immutable
 | 
			
		||||
        data class Result(val manga: Manga) : State
 | 
			
		||||
        data class Result(val manga: Manga, val chapterId: Long? = null) : State
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user