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>
(cherry picked from commit 3749cee28f269aabe5ea18ffb62483a28d0c75e7)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt
This commit is contained in:
arkon 2022-12-10 12:08:33 -05:00 committed by Jobobby04
parent 277a0b38bb
commit 35817cc7c5
7 changed files with 93 additions and 15 deletions

View File

@ -23,6 +23,10 @@ interface Tab : cafe.adriel.voyager.navigator.tab.Tab {
// SY <-- // SY <--
} }
interface AssistContentScreen {
fun onProvideAssistUrl(): String?
}
@Composable @Composable
fun DefaultNavigatorScreenTransition(navigator: Navigator) { fun DefaultNavigatorScreenTransition(navigator: Navigator) {
val slideDistance = rememberSlideDistance() val slideDistance = rememberSlideDistance()

View File

@ -1,6 +1,7 @@
package eu.kanade.presentation.webview package eu.kanade.presentation.webview
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.graphics.Bitmap
import android.webkit.WebResourceRequest import android.webkit.WebResourceRequest
import android.webkit.WebView import android.webkit.WebView
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
@ -35,6 +36,7 @@ fun WebViewScreen(
initialTitle: String?, initialTitle: String?,
url: String, url: String,
headers: Map<String, String> = emptyMap(), headers: Map<String, String> = emptyMap(),
onUrlChange: (String) -> Unit = {},
onShare: (String) -> Unit, onShare: (String) -> Unit,
onOpenInBrowser: (String) -> Unit, onOpenInBrowser: (String) -> Unit,
onClearCookies: (String) -> Unit, onClearCookies: (String) -> Unit,
@ -112,6 +114,11 @@ fun WebViewScreen(
) { contentPadding -> ) { contentPadding ->
val webClient = remember { val webClient = remember {
object : AccompanistWebViewClient() { object : AccompanistWebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
url?.let { onUrlChange(it) }
}
override fun shouldOverrideUrlLoading( override fun shouldOverrideUrlLoading(
view: WebView?, view: WebView?,
request: WebResourceRequest?, request: WebResourceRequest?,

View File

@ -50,6 +50,7 @@ import eu.kanade.presentation.components.ChangeCategoryDialog
import eu.kanade.presentation.components.Divider import eu.kanade.presentation.components.Divider
import eu.kanade.presentation.components.DuplicateMangaDialog import eu.kanade.presentation.components.DuplicateMangaDialog
import eu.kanade.presentation.components.Scaffold import eu.kanade.presentation.components.Scaffold
import eu.kanade.presentation.util.AssistContentScreen
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
@ -72,10 +73,14 @@ data class BrowseSourceScreen(
private val savedSearch: Long? = null, private val savedSearch: Long? = null,
private val smartSearchConfig: SourcesScreen.SmartSearchConfig? = null, private val smartSearchConfig: SourcesScreen.SmartSearchConfig? = null,
// SY <-- // SY <--
) : Screen { ) : Screen, AssistContentScreen {
private var assistUrl: String? = null
override val key = uniqueScreenKey override val key = uniqueScreenKey
override fun onProvideAssistUrl() = assistUrl
@Composable @Composable
override fun Content() { override fun Content() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
@ -106,6 +111,10 @@ data class BrowseSourceScreen(
context.startActivity(intent) context.startActivity(intent)
} }
LaunchedEffect(screenModel.source) {
assistUrl = (screenModel.source as? HttpSource)?.baseUrl
}
Scaffold( Scaffold(
topBar = { topBar = {
Column(modifier = Modifier.background(MaterialTheme.colorScheme.surface)) { Column(modifier = Modifier.background(MaterialTheme.colorScheme.surface)) {

View File

@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.main
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.app.SearchManager import android.app.SearchManager
import android.app.assist.AssistContent
import android.content.Intent import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.os.Build import android.os.Build
@ -29,6 +30,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.animation.doOnEnd import androidx.core.animation.doOnEnd
import androidx.core.net.toUri
import androidx.core.splashscreen.SplashScreen import androidx.core.splashscreen.SplashScreen
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
@ -49,6 +51,7 @@ import eu.kanade.domain.ui.UiPreferences
import eu.kanade.presentation.components.AppStateBanners import eu.kanade.presentation.components.AppStateBanners
import eu.kanade.presentation.more.settings.screen.ConfigureExhDialog import eu.kanade.presentation.more.settings.screen.ConfigureExhDialog
import eu.kanade.presentation.more.settings.screen.WhatsNewDialog import eu.kanade.presentation.more.settings.screen.WhatsNewDialog
import eu.kanade.presentation.util.AssistContentScreen
import eu.kanade.presentation.util.DefaultNavigatorScreenTransition import eu.kanade.presentation.util.DefaultNavigatorScreenTransition
import eu.kanade.presentation.util.collectAsState import eu.kanade.presentation.util.collectAsState
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.BuildConfig
@ -321,6 +324,15 @@ class MainActivity : BaseActivity() {
// SY --> // SY -->
} }
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) { private fun showSettingsSheet(category: Category? = null) {
if (category != null) { if (category != null) {
settingsSheet?.show(category) settingsSheet?.show(category)

View File

@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.manga
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.layout.systemBarsPadding
@ -18,6 +17,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.core.net.toUri
import cafe.adriel.voyager.core.model.rememberScreenModel import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.core.screen.uniqueScreenKey import cafe.adriel.voyager.core.screen.uniqueScreenKey
@ -40,6 +40,7 @@ import eu.kanade.presentation.manga.components.DeleteChaptersDialog
import eu.kanade.presentation.manga.components.DownloadCustomAmountDialog import eu.kanade.presentation.manga.components.DownloadCustomAmountDialog
import eu.kanade.presentation.manga.components.MangaCoverDialog import eu.kanade.presentation.manga.components.MangaCoverDialog
import eu.kanade.presentation.manga.components.SelectScanlatorsDialog import eu.kanade.presentation.manga.components.SelectScanlatorsDialog
import eu.kanade.presentation.util.AssistContentScreen
import eu.kanade.presentation.util.isTabletUi import eu.kanade.presentation.util.isTabletUi
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.CatalogueSource
@ -60,8 +61,10 @@ import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.ui.webview.WebViewActivity import eu.kanade.tachiyomi.ui.webview.WebViewActivity
import eu.kanade.tachiyomi.util.chapter.getNextUnread import eu.kanade.tachiyomi.util.chapter.getNextUnread
import eu.kanade.tachiyomi.util.lang.launchUI import eu.kanade.tachiyomi.util.lang.launchUI
import eu.kanade.tachiyomi.util.lang.withIOContext
import eu.kanade.tachiyomi.util.lang.withNonCancellableContext import eu.kanade.tachiyomi.util.lang.withNonCancellableContext
import eu.kanade.tachiyomi.util.system.copyToClipboard 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.toShareIntent
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import exh.md.similar.MangaDexSimilarScreen import exh.md.similar.MangaDexSimilarScreen
@ -76,6 +79,7 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.take import kotlinx.coroutines.flow.take
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import logcat.LogPriority
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -83,10 +87,14 @@ class MangaScreen(
private val mangaId: Long, private val mangaId: Long,
val fromSource: Boolean = false, val fromSource: Boolean = false,
private val smartSearchConfig: SourcesScreen.SmartSearchConfig? = null, private val smartSearchConfig: SourcesScreen.SmartSearchConfig? = null,
) : Screen { ) : Screen, AssistContentScreen {
private var assistUrl: String? = null
override val key = uniqueScreenKey override val key = uniqueScreenKey
override fun onProvideAssistUrl() = assistUrl
@Composable @Composable
override fun Content() { override fun Content() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
@ -105,6 +113,18 @@ class MangaScreen(
val successState = state as MangaScreenState.Success val successState = state as MangaScreenState.Success
val isHttpSource = remember { successState.source is HttpSource } 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" }
}
}
}
// SY --> // SY -->
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
screenModel.redirectFlow screenModel.redirectFlow
@ -301,27 +321,35 @@ class MangaScreen(
context.startActivity(ReaderActivity.newIntent(context, chapter.mangaId, chapter.id)) context.startActivity(ReaderActivity.newIntent(context, chapter.mangaId, chapter.id))
} }
private fun openMangaInWebView(context: Context, manga_: Manga?, source_: Source?) { private fun getMangaUrl(manga_: Manga?, source_: Source?): String? {
val manga = manga_ ?: return val manga = manga_ ?: return null
val source = source_ as? HttpSource ?: return val source = source_ as? HttpSource ?: return null
val url = try { return try {
source.getMangaUrl(manga.toSManga()) source.getMangaUrl(manga.toSManga())
} catch (e: Exception) { } catch (e: Exception) {
return null
}
} }
val intent = WebViewActivity.newIntent(context, url, source.id, manga.title) 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) context.startActivity(intent)
} }
}
private fun shareManga(context: Context, manga_: Manga?, source_: Source?) { private fun shareManga(context: Context, manga_: Manga?, source_: Source?) {
val manga = manga_ ?: return
val source = source_ as? HttpSource ?: return
try { try {
val uri = Uri.parse(source.getMangaUrl(manga.toSManga())) getMangaUrl(manga_, source_)?.let { url ->
val intent = uri.toShareIntent(context, type = "text/plain") val intent = url.toUri().toShareIntent(context, type = "text/plain")
context.startActivity(Intent.createChooser(intent, context.getString(R.string.action_share))) context.startActivity(
Intent.createChooser(
intent,
context.getString(R.string.action_share),
),
)
}
} catch (e: Exception) { } catch (e: Exception) {
context.toast(e.message) context.toast(e.message)
} }

View File

@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.reader
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.annotation.TargetApi import android.annotation.TargetApi
import android.app.ProgressDialog import android.app.ProgressDialog
import android.app.assist.AssistContent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.ColorStateList import android.content.res.ColorStateList
@ -35,6 +36,7 @@ import android.widget.Toast
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import androidx.core.net.toUri
import androidx.core.transition.doOnEnd import androidx.core.transition.doOnEnd
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
@ -385,6 +387,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. * Called when the options menu of the toolbar is being created. It adds our custom menu.
*/ */

View File

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.ui.webview package eu.kanade.tachiyomi.ui.webview
import android.app.assist.AssistContent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
@ -25,6 +26,8 @@ class WebViewActivity : BaseActivity() {
private val sourceManager: SourceManager by injectLazy() private val sourceManager: SourceManager by injectLazy()
private val network: NetworkHelper by injectLazy() private val network: NetworkHelper by injectLazy()
private var assistUrl: String? = null
init { init {
registerSecureActivity(this) registerSecureActivity(this)
} }
@ -52,6 +55,7 @@ class WebViewActivity : BaseActivity() {
initialTitle = intent.extras?.getString(TITLE_KEY), initialTitle = intent.extras?.getString(TITLE_KEY),
url = url, url = url,
headers = headers, headers = headers,
onUrlChange = { assistUrl = it },
onShare = this::shareWebpage, onShare = this::shareWebpage,
onOpenInBrowser = this::openInBrowser, onOpenInBrowser = this::openInBrowser,
onClearCookies = this::clearCookies, 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() { override fun finish() {
super.finish() super.finish()
overridePendingTransition(R.anim.shared_axis_x_pop_enter, R.anim.shared_axis_x_pop_exit) overridePendingTransition(R.anim.shared_axis_x_pop_enter, R.anim.shared_axis_x_pop_exit)