From 35817cc7c54d11d1ec81654d3170a1ea9aa7efb2 Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 10 Dec 2022 12:08:33 -0500 Subject: [PATCH] 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 (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 --- .../eu/kanade/presentation/util/Navigator.kt | 4 ++ .../presentation/webview/WebViewScreen.kt | 7 +++ .../source/browse/BrowseSourceScreen.kt | 11 +++- .../kanade/tachiyomi/ui/main/MainActivity.kt | 12 ++++ .../kanade/tachiyomi/ui/manga/MangaScreen.kt | 56 ++++++++++++++----- .../tachiyomi/ui/reader/ReaderActivity.kt | 9 +++ .../tachiyomi/ui/webview/WebViewActivity.kt | 9 +++ 7 files changed, 93 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt index dc41f1c2f..a89081ab7 100644 --- a/app/src/main/java/eu/kanade/presentation/util/Navigator.kt +++ b/app/src/main/java/eu/kanade/presentation/util/Navigator.kt @@ -23,6 +23,10 @@ interface Tab : cafe.adriel.voyager.navigator.tab.Tab { // SY <-- } +interface AssistContentScreen { + fun onProvideAssistUrl(): String? +} + @Composable fun DefaultNavigatorScreenTransition(navigator: Navigator) { val slideDistance = rememberSlideDistance() diff --git a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreen.kt b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreen.kt index 4c9e393c5..b05dab213 100644 --- a/app/src/main/java/eu/kanade/presentation/webview/WebViewScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/webview/WebViewScreen.kt @@ -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 = 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?, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt index f2dcf2e67..bc9c2aeaf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt @@ -50,6 +50,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 @@ -72,10 +73,14 @@ data class BrowseSourceScreen( private val savedSearch: Long? = null, private val smartSearchConfig: SourcesScreen.SmartSearchConfig? = null, // SY <-- -) : Screen { +) : Screen, AssistContentScreen { + + private var assistUrl: String? = null override val key = uniqueScreenKey + override fun onProvideAssistUrl() = assistUrl + @Composable override fun Content() { val navigator = LocalNavigator.currentOrThrow @@ -106,6 +111,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)) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index 7190f0d8c..2739407ca 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -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 @@ -29,6 +30,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext 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.ui.UiPreferences import eu.kanade.presentation.components.AppStateBanners import eu.kanade.presentation.more.settings.screen.ConfigureExhDialog 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.collectAsState import eu.kanade.tachiyomi.BuildConfig @@ -321,6 +324,15 @@ class MainActivity : BaseActivity() { // 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) { if (category != null) { settingsSheet?.show(category) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt index d45ffee88..283a4366f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt @@ -2,7 +2,6 @@ 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 @@ -18,6 +17,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 @@ -40,6 +40,7 @@ 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.manga.components.SelectScanlatorsDialog +import eu.kanade.presentation.util.AssistContentScreen import eu.kanade.presentation.util.isTabletUi import eu.kanade.tachiyomi.R 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.util.chapter.getNextUnread 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.system.copyToClipboard +import eu.kanade.tachiyomi.util.system.logcat import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toast import exh.md.similar.MangaDexSimilarScreen @@ -76,6 +79,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.take import kotlinx.coroutines.launch +import logcat.LogPriority import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -83,10 +87,14 @@ class MangaScreen( private val mangaId: Long, val fromSource: Boolean = false, private val smartSearchConfig: SourcesScreen.SmartSearchConfig? = 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 @@ -105,6 +113,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" } + } + } + } + // SY --> LaunchedEffect(Unit) { screenModel.redirectFlow @@ -301,27 +321,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) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 9ca85f1cb..e6bfcf021 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -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 @@ -35,6 +36,7 @@ import android.widget.Toast import androidx.activity.viewModels import androidx.annotation.ColorInt 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 @@ -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. */ diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/webview/WebViewActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/webview/WebViewActivity.kt index dd0d54f79..6ccfebb20 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/webview/WebViewActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/webview/WebViewActivity.kt @@ -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)