mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Add ResolvableSource interface for potentially opening entries directly based on some URI via a share intent
Implemented as an intermediate step in the existing Global Search share intent workflow. If any source manages to resolve the URI (e.g., a URL, a slug, etc.), the resolved SManga entry is directly opened. If nothing gets resolved, continue to a Global Search.
This commit is contained in:
		@@ -76,7 +76,7 @@ fun ExtensionScreen(
 | 
			
		||||
        enabled = !state.isLoading,
 | 
			
		||||
    ) {
 | 
			
		||||
        when {
 | 
			
		||||
            state.isLoading -> LoadingScreen(modifier = Modifier.padding(contentPadding))
 | 
			
		||||
            state.isLoading -> LoadingScreen(Modifier.padding(contentPadding))
 | 
			
		||||
            state.isEmpty -> {
 | 
			
		||||
                val msg = if (!searchQuery.isNullOrEmpty()) {
 | 
			
		||||
                    R.string.no_results_found
 | 
			
		||||
 
 | 
			
		||||
@@ -51,7 +51,7 @@ fun MigrateSourceScreen(
 | 
			
		||||
) {
 | 
			
		||||
    val context = LocalContext.current
 | 
			
		||||
    when {
 | 
			
		||||
        state.isLoading -> LoadingScreen(modifier = Modifier.padding(contentPadding))
 | 
			
		||||
        state.isLoading -> LoadingScreen(Modifier.padding(contentPadding))
 | 
			
		||||
        state.isEmpty -> EmptyScreen(
 | 
			
		||||
            textResource = R.string.information_empty_library,
 | 
			
		||||
            modifier = Modifier.padding(contentPadding),
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ fun SourcesScreen(
 | 
			
		||||
    onLongClickItem: (Source) -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    when {
 | 
			
		||||
        state.isLoading -> LoadingScreen(modifier = Modifier.padding(contentPadding))
 | 
			
		||||
        state.isLoading -> LoadingScreen(Modifier.padding(contentPadding))
 | 
			
		||||
        state.isEmpty -> EmptyScreen(
 | 
			
		||||
            textResource = R.string.source_empty_screen,
 | 
			
		||||
            modifier = Modifier.padding(contentPadding),
 | 
			
		||||
 
 | 
			
		||||
@@ -65,7 +65,7 @@ fun HistoryScreen(
 | 
			
		||||
    ) { contentPadding ->
 | 
			
		||||
        state.list.let {
 | 
			
		||||
            if (it == null) {
 | 
			
		||||
                LoadingScreen(modifier = Modifier.padding(contentPadding))
 | 
			
		||||
                LoadingScreen(Modifier.padding(contentPadding))
 | 
			
		||||
            } else if (it.isEmpty()) {
 | 
			
		||||
                val msg = if (!state.searchQuery.isNullOrEmpty()) {
 | 
			
		||||
                    R.string.no_results_found
 | 
			
		||||
 
 | 
			
		||||
@@ -81,7 +81,7 @@ fun UpdateScreen(
 | 
			
		||||
        snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
 | 
			
		||||
    ) { contentPadding ->
 | 
			
		||||
        when {
 | 
			
		||||
            state.isLoading -> LoadingScreen(modifier = Modifier.padding(contentPadding))
 | 
			
		||||
            state.isLoading -> LoadingScreen(Modifier.padding(contentPadding))
 | 
			
		||||
            state.items.isEmpty() -> EmptyScreen(
 | 
			
		||||
                textResource = R.string.information_no_recent,
 | 
			
		||||
                modifier = Modifier.padding(contentPadding),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,9 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.main
 | 
			
		||||
package eu.kanade.tachiyomi.ui.deeplink
 | 
			
		||||
 | 
			
		||||
import android.app.Activity
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import eu.kanade.tachiyomi.ui.main.MainActivity
 | 
			
		||||
 | 
			
		||||
class DeepLinkActivity : Activity() {
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,59 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.deeplink
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.collectAsState
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import cafe.adriel.voyager.core.model.rememberScreenModel
 | 
			
		||||
import cafe.adriel.voyager.navigator.LocalNavigator
 | 
			
		||||
import cafe.adriel.voyager.navigator.currentOrThrow
 | 
			
		||||
import eu.kanade.presentation.components.AppBar
 | 
			
		||||
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 tachiyomi.presentation.core.components.material.Scaffold
 | 
			
		||||
import tachiyomi.presentation.core.screens.LoadingScreen
 | 
			
		||||
 | 
			
		||||
class DeepLinkScreen(
 | 
			
		||||
    val query: String = "",
 | 
			
		||||
) : Screen() {
 | 
			
		||||
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun Content() {
 | 
			
		||||
        val navigator = LocalNavigator.currentOrThrow
 | 
			
		||||
 | 
			
		||||
        val screenModel = rememberScreenModel {
 | 
			
		||||
            DeepLinkScreenModel(query = query)
 | 
			
		||||
        }
 | 
			
		||||
        val state by screenModel.state.collectAsState()
 | 
			
		||||
        Scaffold(
 | 
			
		||||
            topBar = { scrollBehavior ->
 | 
			
		||||
                AppBar(
 | 
			
		||||
                    title = stringResource(R.string.action_search_hint),
 | 
			
		||||
                    navigateUp = navigator::pop,
 | 
			
		||||
                    scrollBehavior = scrollBehavior,
 | 
			
		||||
                )
 | 
			
		||||
            },
 | 
			
		||||
        ) { contentPadding ->
 | 
			
		||||
            when (state) {
 | 
			
		||||
                is DeepLinkScreenModel.State.Loading -> {
 | 
			
		||||
                    LoadingScreen(Modifier.padding(contentPadding))
 | 
			
		||||
                }
 | 
			
		||||
                is DeepLinkScreenModel.State.NoResults -> {
 | 
			
		||||
                    navigator.replace(GlobalSearchScreen(query))
 | 
			
		||||
                }
 | 
			
		||||
                is DeepLinkScreenModel.State.Result -> {
 | 
			
		||||
                    navigator.replace(
 | 
			
		||||
                        MangaScreen(
 | 
			
		||||
                            (state as DeepLinkScreenModel.State.Result).manga.id,
 | 
			
		||||
                            true,
 | 
			
		||||
                        ),
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,47 @@
 | 
			
		||||
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.manga.model.toDomainManga
 | 
			
		||||
import eu.kanade.tachiyomi.source.online.ResolvableSource
 | 
			
		||||
import kotlinx.coroutines.flow.update
 | 
			
		||||
import tachiyomi.core.util.lang.launchIO
 | 
			
		||||
import tachiyomi.domain.manga.model.Manga
 | 
			
		||||
import tachiyomi.domain.source.service.SourceManager
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
 | 
			
		||||
class DeepLinkScreenModel(
 | 
			
		||||
    query: String = "",
 | 
			
		||||
    private val sourceManager: SourceManager = Injekt.get(),
 | 
			
		||||
) : StateScreenModel<DeepLinkScreenModel.State>(State.Loading) {
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        coroutineScope.launchIO {
 | 
			
		||||
            val manga = sourceManager.getCatalogueSources()
 | 
			
		||||
                .filterIsInstance<ResolvableSource>()
 | 
			
		||||
                .filter { it.canResolveUri(query) }
 | 
			
		||||
                .firstNotNullOfOrNull { it.getManga(query)?.toDomainManga(it.id) }
 | 
			
		||||
 | 
			
		||||
            mutableState.update {
 | 
			
		||||
                if (manga == null) {
 | 
			
		||||
                    State.NoResults
 | 
			
		||||
                } else {
 | 
			
		||||
                    State.Result(manga)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sealed interface State {
 | 
			
		||||
        @Immutable
 | 
			
		||||
        data object Loading : State
 | 
			
		||||
 | 
			
		||||
        @Immutable
 | 
			
		||||
        data object NoResults : State
 | 
			
		||||
 | 
			
		||||
        @Immutable
 | 
			
		||||
        data class Result(val manga: Manga) : State
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -148,7 +148,7 @@ object LibraryTab : Tab {
 | 
			
		||||
            snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
 | 
			
		||||
        ) { contentPadding ->
 | 
			
		||||
            when {
 | 
			
		||||
                state.isLoading -> LoadingScreen(modifier = Modifier.padding(contentPadding))
 | 
			
		||||
                state.isLoading -> LoadingScreen(Modifier.padding(contentPadding))
 | 
			
		||||
                state.searchQuery.isNullOrEmpty() && !state.hasActiveFilters && state.isLibraryEmpty -> {
 | 
			
		||||
                    val handler = LocalUriHandler.current
 | 
			
		||||
                    EmptyScreen(
 | 
			
		||||
 
 | 
			
		||||
@@ -71,6 +71,7 @@ import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreen
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen
 | 
			
		||||
import eu.kanade.tachiyomi.ui.deeplink.DeepLinkScreen
 | 
			
		||||
import eu.kanade.tachiyomi.ui.home.HomeScreen
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
 | 
			
		||||
import eu.kanade.tachiyomi.ui.more.NewUpdateScreen
 | 
			
		||||
@@ -409,7 +410,7 @@ class MainActivity : BaseActivity() {
 | 
			
		||||
                val query = intent.getStringExtra(SearchManager.QUERY) ?: intent.getStringExtra(Intent.EXTRA_TEXT)
 | 
			
		||||
                if (!query.isNullOrEmpty()) {
 | 
			
		||||
                    navigator.popUntilRoot()
 | 
			
		||||
                    navigator.push(GlobalSearchScreen(query))
 | 
			
		||||
                    navigator.push(DeepLinkScreen(query))
 | 
			
		||||
                }
 | 
			
		||||
                null
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user