mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Add Assistant content URLs
This is surfaced in recents on Pixel devices for example. Docs: https://developer.android.com/guide/app-actions/assistant-sharing Co-authored-by: Jays2Kings <Jays2Kings@users.noreply.github.com>
This commit is contained in:
		@@ -18,6 +18,10 @@ interface Tab : cafe.adriel.voyager.navigator.tab.Tab {
 | 
			
		||||
    suspend fun onReselect(navigator: Navigator) {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface AssistContentScreen {
 | 
			
		||||
    fun onProvideAssistUrl(): String?
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun DefaultNavigatorScreenTransition(navigator: Navigator) {
 | 
			
		||||
    val slideDistance = rememberSlideDistance()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package eu.kanade.presentation.webview
 | 
			
		||||
 | 
			
		||||
import android.content.pm.ApplicationInfo
 | 
			
		||||
import android.graphics.Bitmap
 | 
			
		||||
import android.webkit.WebResourceRequest
 | 
			
		||||
import android.webkit.WebView
 | 
			
		||||
import androidx.compose.foundation.layout.Box
 | 
			
		||||
@@ -35,6 +36,7 @@ fun WebViewScreen(
 | 
			
		||||
    initialTitle: String?,
 | 
			
		||||
    url: String,
 | 
			
		||||
    headers: Map<String, String> = emptyMap(),
 | 
			
		||||
    onUrlChange: (String) -> Unit = {},
 | 
			
		||||
    onShare: (String) -> Unit,
 | 
			
		||||
    onOpenInBrowser: (String) -> Unit,
 | 
			
		||||
    onClearCookies: (String) -> Unit,
 | 
			
		||||
@@ -112,6 +114,11 @@ fun WebViewScreen(
 | 
			
		||||
    ) { contentPadding ->
 | 
			
		||||
        val webClient = remember {
 | 
			
		||||
            object : AccompanistWebViewClient() {
 | 
			
		||||
                override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
 | 
			
		||||
                    super.onPageStarted(view, url, favicon)
 | 
			
		||||
                    url?.let { onUrlChange(it) }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                override fun shouldOverrideUrlLoading(
 | 
			
		||||
                    view: WebView?,
 | 
			
		||||
                    request: WebResourceRequest?,
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,7 @@ import eu.kanade.presentation.components.ChangeCategoryDialog
 | 
			
		||||
import eu.kanade.presentation.components.Divider
 | 
			
		||||
import eu.kanade.presentation.components.DuplicateMangaDialog
 | 
			
		||||
import eu.kanade.presentation.components.Scaffold
 | 
			
		||||
import eu.kanade.presentation.util.AssistContentScreen
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.source.LocalSource
 | 
			
		||||
import eu.kanade.tachiyomi.source.online.HttpSource
 | 
			
		||||
@@ -62,10 +63,14 @@ import kotlinx.coroutines.flow.receiveAsFlow
 | 
			
		||||
data class BrowseSourceScreen(
 | 
			
		||||
    private val sourceId: Long,
 | 
			
		||||
    private val query: String? = null,
 | 
			
		||||
) : Screen {
 | 
			
		||||
) : Screen, AssistContentScreen {
 | 
			
		||||
 | 
			
		||||
    private var assistUrl: String? = null
 | 
			
		||||
 | 
			
		||||
    override val key = uniqueScreenKey
 | 
			
		||||
 | 
			
		||||
    override fun onProvideAssistUrl() = assistUrl
 | 
			
		||||
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun Content() {
 | 
			
		||||
        val navigator = LocalNavigator.currentOrThrow
 | 
			
		||||
@@ -74,7 +79,7 @@ data class BrowseSourceScreen(
 | 
			
		||||
        val haptic = LocalHapticFeedback.current
 | 
			
		||||
        val uriHandler = LocalUriHandler.current
 | 
			
		||||
 | 
			
		||||
        val screenModel = rememberScreenModel { BrowseSourceScreenModel(sourceId = sourceId, searchQuery = query) }
 | 
			
		||||
        val screenModel = rememberScreenModel { BrowseSourceScreenModel(sourceId, query) }
 | 
			
		||||
        val state by screenModel.state.collectAsState()
 | 
			
		||||
 | 
			
		||||
        val snackbarHostState = remember { SnackbarHostState() }
 | 
			
		||||
@@ -87,6 +92,10 @@ data class BrowseSourceScreen(
 | 
			
		||||
            context.startActivity(intent)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        LaunchedEffect(screenModel.source) {
 | 
			
		||||
            assistUrl = (screenModel.source as? HttpSource)?.baseUrl
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Scaffold(
 | 
			
		||||
            topBar = {
 | 
			
		||||
                Column(modifier = Modifier.background(MaterialTheme.colorScheme.surface)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.main
 | 
			
		||||
 | 
			
		||||
import android.animation.ValueAnimator
 | 
			
		||||
import android.app.SearchManager
 | 
			
		||||
import android.app.assist.AssistContent
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.graphics.Color
 | 
			
		||||
import android.os.Build
 | 
			
		||||
@@ -32,6 +33,7 @@ import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import androidx.core.animation.doOnEnd
 | 
			
		||||
import androidx.core.net.toUri
 | 
			
		||||
import androidx.core.splashscreen.SplashScreen
 | 
			
		||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
 | 
			
		||||
import androidx.core.view.WindowCompat
 | 
			
		||||
@@ -49,6 +51,7 @@ import eu.kanade.domain.library.service.LibraryPreferences
 | 
			
		||||
import eu.kanade.domain.source.service.SourcePreferences
 | 
			
		||||
import eu.kanade.domain.ui.UiPreferences
 | 
			
		||||
import eu.kanade.presentation.components.AppStateBanners
 | 
			
		||||
import eu.kanade.presentation.util.AssistContentScreen
 | 
			
		||||
import eu.kanade.presentation.util.DefaultNavigatorScreenTransition
 | 
			
		||||
import eu.kanade.presentation.util.collectAsState
 | 
			
		||||
import eu.kanade.tachiyomi.BuildConfig
 | 
			
		||||
@@ -261,6 +264,15 @@ class MainActivity : BaseActivity() {
 | 
			
		||||
        setSplashScreenExitAnimation(splashScreen)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onProvideAssistContent(outContent: AssistContent) {
 | 
			
		||||
        super.onProvideAssistContent(outContent)
 | 
			
		||||
        when (val screen = navigator.lastItem) {
 | 
			
		||||
            is AssistContentScreen -> {
 | 
			
		||||
                screen.onProvideAssistUrl()?.let { outContent.webUri = it.toUri() }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun showSettingsSheet(category: Category? = null) {
 | 
			
		||||
        if (category != null) {
 | 
			
		||||
            settingsSheet?.show(category)
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,11 @@ package eu.kanade.tachiyomi.ui.manga
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import androidx.activity.compose.rememberLauncherForActivityResult
 | 
			
		||||
import androidx.activity.result.contract.ActivityResultContracts
 | 
			
		||||
import androidx.compose.foundation.layout.systemBarsPadding
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.LaunchedEffect
 | 
			
		||||
import androidx.compose.runtime.collectAsState
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.runtime.remember
 | 
			
		||||
@@ -15,6 +15,7 @@ import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.compose.ui.platform.LocalHapticFeedback
 | 
			
		||||
import androidx.core.net.toUri
 | 
			
		||||
import cafe.adriel.voyager.core.model.rememberScreenModel
 | 
			
		||||
import cafe.adriel.voyager.core.screen.Screen
 | 
			
		||||
import cafe.adriel.voyager.core.screen.uniqueScreenKey
 | 
			
		||||
@@ -34,6 +35,7 @@ import eu.kanade.presentation.manga.MangaScreen
 | 
			
		||||
import eu.kanade.presentation.manga.components.DeleteChaptersDialog
 | 
			
		||||
import eu.kanade.presentation.manga.components.DownloadCustomAmountDialog
 | 
			
		||||
import eu.kanade.presentation.manga.components.MangaCoverDialog
 | 
			
		||||
import eu.kanade.presentation.util.AssistContentScreen
 | 
			
		||||
import eu.kanade.presentation.util.isTabletUi
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.source.Source
 | 
			
		||||
@@ -47,18 +49,25 @@ import eu.kanade.tachiyomi.ui.home.HomeScreen
 | 
			
		||||
import eu.kanade.tachiyomi.ui.manga.track.TrackInfoDialogHomeScreen
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
 | 
			
		||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.withIOContext
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.logcat
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.toShareIntent
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.toast
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import logcat.LogPriority
 | 
			
		||||
 | 
			
		||||
class MangaScreen(
 | 
			
		||||
    private val mangaId: Long,
 | 
			
		||||
    val fromSource: Boolean = false,
 | 
			
		||||
) : Screen {
 | 
			
		||||
) : Screen, AssistContentScreen {
 | 
			
		||||
 | 
			
		||||
    private var assistUrl: String? = null
 | 
			
		||||
 | 
			
		||||
    override val key = uniqueScreenKey
 | 
			
		||||
 | 
			
		||||
    override fun onProvideAssistUrl() = assistUrl
 | 
			
		||||
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun Content() {
 | 
			
		||||
        val navigator = LocalNavigator.currentOrThrow
 | 
			
		||||
@@ -77,6 +86,18 @@ class MangaScreen(
 | 
			
		||||
        val successState = state as MangaScreenState.Success
 | 
			
		||||
        val isHttpSource = remember { successState.source is HttpSource }
 | 
			
		||||
 | 
			
		||||
        LaunchedEffect(successState.manga, screenModel.source) {
 | 
			
		||||
            if (isHttpSource) {
 | 
			
		||||
                try {
 | 
			
		||||
                    withIOContext {
 | 
			
		||||
                        assistUrl = getMangaUrl(screenModel.manga, screenModel.source)
 | 
			
		||||
                    }
 | 
			
		||||
                } catch (e: Exception) {
 | 
			
		||||
                    logcat(LogPriority.ERROR, e) { "Failed to get manga URL" }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        MangaScreen(
 | 
			
		||||
            state = successState,
 | 
			
		||||
            snackbarHostState = screenModel.snackbarHostState,
 | 
			
		||||
@@ -208,27 +229,35 @@ class MangaScreen(
 | 
			
		||||
        context.startActivity(ReaderActivity.newIntent(context, chapter.mangaId, chapter.id))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun openMangaInWebView(context: Context, manga_: Manga?, source_: Source?) {
 | 
			
		||||
        val manga = manga_ ?: return
 | 
			
		||||
        val source = source_ as? HttpSource ?: return
 | 
			
		||||
    private fun getMangaUrl(manga_: Manga?, source_: Source?): String? {
 | 
			
		||||
        val manga = manga_ ?: return null
 | 
			
		||||
        val source = source_ as? HttpSource ?: return null
 | 
			
		||||
 | 
			
		||||
        val url = try {
 | 
			
		||||
        return try {
 | 
			
		||||
            source.getMangaUrl(manga.toSManga())
 | 
			
		||||
        } catch (e: Exception) {
 | 
			
		||||
            return
 | 
			
		||||
            null
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        val intent = WebViewActivity.newIntent(context, url, source.id, manga.title)
 | 
			
		||||
        context.startActivity(intent)
 | 
			
		||||
    private fun openMangaInWebView(context: Context, manga_: Manga?, source_: Source?) {
 | 
			
		||||
        getMangaUrl(manga_, source_)?.let { url ->
 | 
			
		||||
            val intent = WebViewActivity.newIntent(context, url, source_?.id, manga_?.title)
 | 
			
		||||
            context.startActivity(intent)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun shareManga(context: Context, manga_: Manga?, source_: Source?) {
 | 
			
		||||
        val manga = manga_ ?: return
 | 
			
		||||
        val source = source_ as? HttpSource ?: return
 | 
			
		||||
        try {
 | 
			
		||||
            val uri = Uri.parse(source.getMangaUrl(manga.toSManga()))
 | 
			
		||||
            val intent = uri.toShareIntent(context, type = "text/plain")
 | 
			
		||||
            context.startActivity(Intent.createChooser(intent, context.getString(R.string.action_share)))
 | 
			
		||||
            getMangaUrl(manga_, source_)?.let { url ->
 | 
			
		||||
                val intent = url.toUri().toShareIntent(context, type = "text/plain")
 | 
			
		||||
                context.startActivity(
 | 
			
		||||
                    Intent.createChooser(
 | 
			
		||||
                        intent,
 | 
			
		||||
                        context.getString(R.string.action_share),
 | 
			
		||||
                    ),
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        } catch (e: Exception) {
 | 
			
		||||
            context.toast(e.message)
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.reader
 | 
			
		||||
import android.annotation.SuppressLint
 | 
			
		||||
import android.annotation.TargetApi
 | 
			
		||||
import android.app.ProgressDialog
 | 
			
		||||
import android.app.assist.AssistContent
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.content.res.ColorStateList
 | 
			
		||||
@@ -29,6 +30,7 @@ import android.widget.FrameLayout
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.activity.viewModels
 | 
			
		||||
import androidx.core.graphics.ColorUtils
 | 
			
		||||
import androidx.core.net.toUri
 | 
			
		||||
import androidx.core.transition.doOnEnd
 | 
			
		||||
import androidx.core.view.WindowCompat
 | 
			
		||||
import androidx.core.view.WindowInsetsCompat
 | 
			
		||||
@@ -296,6 +298,13 @@ class ReaderActivity : BaseActivity() {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onProvideAssistContent(outContent: AssistContent) {
 | 
			
		||||
        super.onProvideAssistContent(outContent)
 | 
			
		||||
        viewModel.getChapterUrl()?.let { url ->
 | 
			
		||||
            outContent.webUri = url.toUri()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called when the options menu of the toolbar is being created. It adds our custom menu.
 | 
			
		||||
     */
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.webview
 | 
			
		||||
 | 
			
		||||
import android.app.assist.AssistContent
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
@@ -25,6 +26,8 @@ class WebViewActivity : BaseActivity() {
 | 
			
		||||
    private val sourceManager: SourceManager by injectLazy()
 | 
			
		||||
    private val network: NetworkHelper by injectLazy()
 | 
			
		||||
 | 
			
		||||
    private var assistUrl: String? = null
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        registerSecureActivity(this)
 | 
			
		||||
    }
 | 
			
		||||
@@ -52,6 +55,7 @@ class WebViewActivity : BaseActivity() {
 | 
			
		||||
                initialTitle = intent.extras?.getString(TITLE_KEY),
 | 
			
		||||
                url = url,
 | 
			
		||||
                headers = headers,
 | 
			
		||||
                onUrlChange = { assistUrl = it },
 | 
			
		||||
                onShare = this::shareWebpage,
 | 
			
		||||
                onOpenInBrowser = this::openInBrowser,
 | 
			
		||||
                onClearCookies = this::clearCookies,
 | 
			
		||||
@@ -59,6 +63,11 @@ class WebViewActivity : BaseActivity() {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onProvideAssistContent(outContent: AssistContent) {
 | 
			
		||||
        super.onProvideAssistContent(outContent)
 | 
			
		||||
        assistUrl?.let { outContent.webUri = it.toUri() }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun finish() {
 | 
			
		||||
        super.finish()
 | 
			
		||||
        overridePendingTransition(R.anim.shared_axis_x_pop_enter, R.anim.shared_axis_x_pop_exit)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user