diff --git a/app/build.gradle b/app/build.gradle index 8374b6bfd..662116e9c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -143,6 +143,9 @@ dependencies { implementation "androidx.paging:paging-runtime:$paging" implementation "androidx.paging:paging-compose:1.0.0-alpha14" + // https://developer.android.com/jetpack/androidx/releases/paging + implementation "androidx.browser:browser:1.5.0" + // https://developer.android.com/jetpack/androidx/releases/navigation implementation "androidx.navigation:navigation-compose:$navigation" @@ -187,4 +190,5 @@ dependencies { testImplementation "junit:junit:4.13.2" androidTestImplementation "androidx.test.ext:junit:1.1.3" androidTestImplementation "androidx.test.espresso:espresso-core:3.4.0" + } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 405cb2a30..ed0debf76 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,6 +5,16 @@ + + + + + + + + + + - \ No newline at end of file + diff --git a/app/src/main/java/me/ash/reader/data/model/preference/OpenLinkPreference.kt b/app/src/main/java/me/ash/reader/data/model/preference/OpenLinkPreference.kt new file mode 100644 index 000000000..7addae17e --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/model/preference/OpenLinkPreference.kt @@ -0,0 +1,56 @@ +package me.ash.reader.data.model.preference + +import android.content.Context +import androidx.compose.ui.text.style.Hyphens.Companion.Auto +import androidx.datastore.preferences.core.Preferences +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import me.ash.reader.R +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class OpenLinkPreference(val value: Int) : Preference() { + object AutoPreferCustomTabs : OpenLinkPreference(0) + object AutoPreferDefaultBrowser : OpenLinkPreference(1) + object CustomTabs : OpenLinkPreference(2) + object DefaultBrowser : OpenLinkPreference(3) + object SpecificBrowser: OpenLinkPreference(4) + object AlwaysAsk: OpenLinkPreference(5) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch { + context.dataStore.put( + DataStoreKeys.OpenLink, + value + ) + } + } + + fun toDesc(context: Context): String = + when (this) { + AutoPreferCustomTabs -> context.getString(R.string.auto_customtabs) + AutoPreferDefaultBrowser -> context.getString(R.string.auto_default_browser) + CustomTabs -> context.getString(R.string.custom_tabs) + DefaultBrowser -> context.getString(R.string.default_browser) + SpecificBrowser -> context.getString(R.string.specific_browser) + AlwaysAsk -> context.getString(R.string.always_ask) + } + + companion object { + + val default = CustomTabs + val values = listOf(AutoPreferCustomTabs, AutoPreferDefaultBrowser, CustomTabs, DefaultBrowser, SpecificBrowser, AlwaysAsk) + + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.OpenLink.key]) { + 0 -> AutoPreferCustomTabs + 1 -> AutoPreferDefaultBrowser + 2 -> CustomTabs + 3 -> DefaultBrowser + 4 -> SpecificBrowser + 5 -> AlwaysAsk + else -> AutoPreferCustomTabs + } + } +} diff --git a/app/src/main/java/me/ash/reader/data/model/preference/OpenLinkSpecificBrowserPreference.kt b/app/src/main/java/me/ash/reader/data/model/preference/OpenLinkSpecificBrowserPreference.kt new file mode 100644 index 000000000..7a3bc8cac --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/model/preference/OpenLinkSpecificBrowserPreference.kt @@ -0,0 +1,54 @@ +package me.ash.reader.data.model.preference + +import android.content.Context +import android.content.pm.PackageManager +import android.os.Build +import androidx.datastore.preferences.core.Preferences +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import me.ash.reader.R +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +data class OpenLinkSpecificBrowserPreference( + val packageName: String? + ) : Preference() { + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch { + context.dataStore.put( + DataStoreKeys.OpenLinkAppSpecificBrowser, + packageName.orEmpty() + ) + } + } + + fun toDesc(context: Context): String { + val pm = context.packageManager + return runCatching { + pm.run { + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + getApplicationInfo( + this@OpenLinkSpecificBrowserPreference.packageName!!, + PackageManager.ApplicationInfoFlags.of(0) + ) + } else { + getApplicationInfo(this@OpenLinkSpecificBrowserPreference.packageName!!, 0) + } + } + }.map { + it.loadLabel(pm) + }.getOrDefault(context.getString(R.string.open_link_specific_browser_not_selected)).let { + context.getString(R.string.specific_browser_name, it) + } + } + + companion object { + val default = OpenLinkSpecificBrowserPreference(null) + fun fromPreferences(preferences: Preferences): OpenLinkSpecificBrowserPreference { + val packageName = preferences[DataStoreKeys.OpenLinkAppSpecificBrowser.key] + return OpenLinkSpecificBrowserPreference(packageName) + } + } +} diff --git a/app/src/main/java/me/ash/reader/data/model/preference/Preference.kt b/app/src/main/java/me/ash/reader/data/model/preference/Preference.kt index 861c90aa1..f07c16549 100644 --- a/app/src/main/java/me/ash/reader/data/model/preference/Preference.kt +++ b/app/src/main/java/me/ash/reader/data/model/preference/Preference.kt @@ -75,6 +75,8 @@ fun Preferences.toSettings(): Settings { // Interaction initialPage = InitialPagePreference.fromPreferences(this), initialFilter = InitialFilterPreference.fromPreferences(this), + openLink = OpenLinkPreference.fromPreferences(this), + openLinkSpecificBrowser = OpenLinkSpecificBrowserPreference.fromPreferences(this), // Languages languages = LanguagesPreference.fromPreferences(this), diff --git a/app/src/main/java/me/ash/reader/data/model/preference/Settings.kt b/app/src/main/java/me/ash/reader/data/model/preference/Settings.kt index 11d05fdae..3ed1f61d5 100644 --- a/app/src/main/java/me/ash/reader/data/model/preference/Settings.kt +++ b/app/src/main/java/me/ash/reader/data/model/preference/Settings.kt @@ -74,6 +74,8 @@ data class Settings( // Interaction val initialPage: InitialPagePreference = InitialPagePreference.default, val initialFilter: InitialFilterPreference = InitialFilterPreference.default, + val openLink: OpenLinkPreference = OpenLinkPreference.default, + val openLinkSpecificBrowser: OpenLinkSpecificBrowserPreference = OpenLinkSpecificBrowserPreference.default, // Languages val languages: LanguagesPreference = LanguagesPreference.default, @@ -172,6 +174,10 @@ val LocalReadingImageMaximize = val LocalInitialPage = compositionLocalOf { InitialPagePreference.default } val LocalInitialFilter = compositionLocalOf { InitialFilterPreference.default } +val LocalOpenLink = + compositionLocalOf { OpenLinkPreference.default } +val LocalOpenLinkSpecificBrowser = + compositionLocalOf { OpenLinkSpecificBrowserPreference.default } // Languages val LocalLanguages = @@ -253,6 +259,8 @@ fun SettingsProvider( // Interaction LocalInitialPage provides settings.initialPage, LocalInitialFilter provides settings.initialFilter, + LocalOpenLink provides settings.openLink, + LocalOpenLinkSpecificBrowser provides settings.openLinkSpecificBrowser, // Languages LocalLanguages provides settings.languages, diff --git a/app/src/main/java/me/ash/reader/ui/component/base/WebView.kt b/app/src/main/java/me/ash/reader/ui/component/base/WebView.kt index 869e6103f..da086075a 100644 --- a/app/src/main/java/me/ash/reader/ui/component/base/WebView.kt +++ b/app/src/main/java/me/ash/reader/ui/component/base/WebView.kt @@ -11,6 +11,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.viewinterop.AndroidView +import me.ash.reader.data.model.preference.LocalOpenLink +import me.ash.reader.data.model.preference.LocalOpenLinkSpecificBrowser +import me.ash.reader.ui.ext.openURL const val INJECTION_TOKEN = "/android_asset_font/" @@ -21,6 +24,8 @@ fun WebView( onReceivedError: (error: WebResourceError?) -> Unit = {}, ) { val context = LocalContext.current + val openLink = LocalOpenLink.current + val openLinkSpecificBrowser = LocalOpenLinkSpecificBrowser.current val color = MaterialTheme.colorScheme.onSurfaceVariant.toArgb() val backgroundColor = MaterialTheme.colorScheme.surface.toArgb() val webViewClient by remember { @@ -67,12 +72,7 @@ fun WebView( ): Boolean { if (null == request?.url) return false val url = request.url.toString() - if (url.isNotEmpty()) context.startActivity( - Intent( - Intent.ACTION_VIEW, - Uri.parse(url) - ) - ) + if (url.isNotEmpty()) context.openURL(url, openLink, openLinkSpecificBrowser) return true } diff --git a/app/src/main/java/me/ash/reader/ui/component/reader/Reader.kt b/app/src/main/java/me/ash/reader/ui/component/reader/Reader.kt index 19155edc4..e251a498b 100644 --- a/app/src/main/java/me/ash/reader/ui/component/reader/Reader.kt +++ b/app/src/main/java/me/ash/reader/ui/component/reader/Reader.kt @@ -25,14 +25,20 @@ import android.content.Intent import android.net.Uri import android.util.Log import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.runtime.Composable import me.ash.reader.R - +import me.ash.reader.data.model.preference.LocalOpenLink +import me.ash.reader.data.model.preference.LocalOpenLinkSpecificBrowser +import me.ash.reader.data.model.preference.OpenLinkPreference +import me.ash.reader.data.model.preference.OpenLinkSpecificBrowserPreference +import me.ash.reader.ui.ext.openURL @Suppress("FunctionName") fun LazyListScope.Reader( context: Context, subheadUpperCase: Boolean = false, link: String, content: String, + onLinkClick: (String) -> Unit ) { Log.i("RLog", "Reader: ") htmlFormattedText( @@ -40,13 +46,6 @@ fun LazyListScope.Reader( subheadUpperCase = subheadUpperCase, baseUrl = link, imagePlaceholder = R.drawable.ic_launcher_foreground, - onLinkClick = { - context.startActivity( - Intent( - Intent.ACTION_VIEW, - Uri.parse(it) - ) - ) - } + onLinkClick = onLinkClick ) } diff --git a/app/src/main/java/me/ash/reader/ui/ext/ContextExt.kt b/app/src/main/java/me/ash/reader/ui/ext/ContextExt.kt index b4e885668..89f7cabcb 100644 --- a/app/src/main/java/me/ash/reader/ui/ext/ContextExt.kt +++ b/app/src/main/java/me/ash/reader/ui/ext/ContextExt.kt @@ -4,16 +4,28 @@ import android.app.Activity import android.content.Context import android.content.ContextWrapper import android.content.Intent -import android.net.Uri -import android.os.Looper +import android.content.pm.PackageManager +import android.content.pm.ResolveInfo +import android.os.Build +import android.os.Parcelable import android.util.Log import android.widget.Toast +import androidx.browser.customtabs.CustomTabsIntent +import androidx.browser.customtabs.CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION +import androidx.browser.customtabs.CustomTabsService.START_REDELIVER_INTENT +import androidx.core.content.ContextCompat import androidx.core.content.FileProvider +import androidx.core.content.PackageManagerCompat +import androidx.core.net.toUri +import androidx.work.impl.utils.PackageManagerHelper import me.ash.reader.R import me.ash.reader.data.model.general.Version import me.ash.reader.data.model.general.toVersion +import me.ash.reader.data.model.preference.OpenLinkPreference +import me.ash.reader.data.model.preference.OpenLinkSpecificBrowserPreference import java.io.File + fun Context.findActivity(): Activity? = when (this) { is Activity -> this is ContextWrapper -> baseContext.findActivity() @@ -68,8 +80,114 @@ fun Context.share(content: String) { }, getString(R.string.share))) } -fun Context.openURL(url: String?) { - url?.trim().let { - if (!it.isNullOrEmpty()) startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(it))) +fun Context.openURL( + url: String?, + openLink: OpenLinkPreference, + specificBrowser: OpenLinkSpecificBrowserPreference = OpenLinkSpecificBrowserPreference.default +) { + if (!url.isNullOrBlank()) { + val uri = url.toUri() + val intent = Intent(Intent.ACTION_VIEW, uri) + val customTabsIntent = CustomTabsIntent.Builder().setShowTitle(true).build() + try { + when(openLink) { + OpenLinkPreference.AlwaysAsk -> { + val intents = packageManager.run { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + queryIntentActivities(intent, PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_ALL.toLong())) + } else { + queryIntentActivities(intent, PackageManager.MATCH_ALL) + } + }.map { + Intent(intent).setPackage(it.activityInfo.packageName) + }.toMutableList() + val chooser = Intent.createChooser(Intent(), null) + .putExtra( + Intent.EXTRA_ALTERNATE_INTENTS, + intents.toTypedArray() + ) + + startActivity(chooser) + } + OpenLinkPreference.AutoPreferCustomTabs -> { + customTabsIntent.launchUrl(this, uri) + } + OpenLinkPreference.AutoPreferDefaultBrowser-> startActivity(intent) + OpenLinkPreference.CustomTabs -> { + val customTabsPackages = getCustomTabsPackages() + require(customTabsPackages.isNotEmpty()) + val defaultBrowser = getDefaultBrowserInfo()!!.activityInfo.packageName + + val targetApp = if (customTabsPackages.contains(defaultBrowser)) { + defaultBrowser + } else { + customTabsPackages[0] + } + customTabsIntent.intent.setPackage(targetApp) + customTabsIntent.launchUrl(this, uri) + } + OpenLinkPreference.DefaultBrowser -> { + val packageName = getDefaultBrowserInfo()!!.activityInfo.packageName + startActivity(intent.setPackage(packageName)) + } + OpenLinkPreference.SpecificBrowser -> { + require(!specificBrowser.packageName.isNullOrBlank()) + startActivity(intent.setPackage(specificBrowser.packageName)) + } + + } + } catch (_: Throwable) { + showToast(getString(R.string.open_link_something_wrong)) + startActivity(intent) + } + } +} + + +fun Context.getBrowserAppList(): List { + val pm: PackageManager = packageManager + val intent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_APP_BROWSER) + val appInfoList = pm.run { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + queryIntentActivities(intent, PackageManager.ResolveInfoFlags.of(0)) + } else { + queryIntentActivities(intent, 0) + } } + return appInfoList.sortedBy { it.loadLabel(pm).toString() } +} + +fun Context.getDefaultBrowserInfo() = packageManager.run { + val intent = Intent(Intent.ACTION_VIEW, "https://".toUri()) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + resolveActivity(intent, PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())) + } else { + resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) + } +} + +fun Context.getCustomTabsPackages(): List { + val pm = packageManager + val intent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_APP_BROWSER) + val appInfoList = pm.run { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + queryIntentActivities(intent, PackageManager.MATCH_ALL) + } else { + queryIntentActivities(intent, PackageManager.MATCH_ALL) + } + } + return appInfoList.mapNotNull { info -> + val serviceIntent = Intent(ACTION_CUSTOM_TABS_CONNECTION).setPackage(info.activityInfo.packageName) + val service = pm.run { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + resolveService(serviceIntent, PackageManager.ResolveInfoFlags.of(0)) + } else { + resolveService(serviceIntent, 0) + } + } + if (service != null) { + return@mapNotNull info.activityInfo.packageName + } + return@mapNotNull null + }.toList() } diff --git a/app/src/main/java/me/ash/reader/ui/ext/DataStoreExt.kt b/app/src/main/java/me/ash/reader/ui/ext/DataStoreExt.kt index f9708b6d0..377f6069e 100644 --- a/app/src/main/java/me/ash/reader/ui/ext/DataStoreExt.kt +++ b/app/src/main/java/me/ash/reader/ui/ext/DataStoreExt.kt @@ -398,6 +398,18 @@ sealed class DataStoreKeys { get() = intPreferencesKey("initialFilter") } + object OpenLink : DataStoreKeys() { + + override val key: Preferences.Key + get() = intPreferencesKey("openLink") + } + + object OpenLinkAppSpecificBrowser : DataStoreKeys() { + + override val key: Preferences.Key + get() = stringPreferencesKey("openLppSpecificBrowser") + } + // Languages object Languages : DataStoreKeys() { diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/feed/FeedOptionDrawer.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/feed/FeedOptionDrawer.kt index d4deb9d8f..eec70dcb6 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/feed/FeedOptionDrawer.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/feed/FeedOptionDrawer.kt @@ -20,6 +20,8 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import kotlinx.coroutines.launch import me.ash.reader.R +import me.ash.reader.data.model.preference.LocalOpenLink +import me.ash.reader.data.model.preference.LocalOpenLinkSpecificBrowser import me.ash.reader.ui.component.ChangeUrlDialog import me.ash.reader.ui.component.FeedIcon import me.ash.reader.ui.component.RenameDialog @@ -39,6 +41,8 @@ fun FeedOptionDrawer( ) { val context = LocalContext.current val view = LocalView.current + val openLink = LocalOpenLink.current + val openLinkSpecificBrowser = LocalOpenLinkSpecificBrowser.current val scope = rememberCoroutineScope() val feedOptionUiState = feedOptionViewModel.feedOptionUiState.collectAsStateValue() val feed = feedOptionUiState.feed @@ -111,7 +115,7 @@ fun FeedOptionDrawer( feedOptionViewModel.showNewGroupDialog() }, onFeedUrlClick = { - context.openURL(feed?.url) + context.openURL(feed?.url, openLink, openLinkSpecificBrowser) }, onFeedUrlLongClick = { if (feedOptionViewModel.rssRepository.get().update) { diff --git a/app/src/main/java/me/ash/reader/ui/page/home/reading/Content.kt b/app/src/main/java/me/ash/reader/ui/page/home/reading/Content.kt index 676fdc976..5c7af9f2f 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/reading/Content.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/reading/Content.kt @@ -13,9 +13,12 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp +import me.ash.reader.data.model.preference.LocalOpenLink +import me.ash.reader.data.model.preference.LocalOpenLinkSpecificBrowser import me.ash.reader.data.model.preference.LocalReadingSubheadUpperCase import me.ash.reader.ui.component.reader.Reader import me.ash.reader.ui.ext.drawVerticalScrollbar +import me.ash.reader.ui.ext.openURL import java.util.* @Composable @@ -32,6 +35,8 @@ fun Content( ) { val context = LocalContext.current val subheadUpperCase = LocalReadingSubheadUpperCase.current + val openLink = LocalOpenLink.current + val openLinkSpecificBrowser = LocalOpenLinkSpecificBrowser.current SelectionContainer { LazyColumn( @@ -84,7 +89,10 @@ fun Content( context = context, subheadUpperCase = subheadUpperCase.value, link = link ?: "", - content = content + content = content, + onLinkClick = { + context.openURL(it, openLink, openLinkSpecificBrowser) + } ) } item { diff --git a/app/src/main/java/me/ash/reader/ui/page/home/reading/Metadata.kt b/app/src/main/java/me/ash/reader/ui/page/home/reading/Metadata.kt index 6040dd618..3520f38dd 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/reading/Metadata.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/reading/Metadata.kt @@ -12,6 +12,8 @@ import androidx.compose.ui.draw.alpha import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp +import me.ash.reader.data.model.preference.LocalOpenLink +import me.ash.reader.data.model.preference.LocalOpenLinkSpecificBrowser import me.ash.reader.data.model.preference.LocalReadingFonts import me.ash.reader.data.model.preference.LocalReadingTitleAlign import me.ash.reader.data.model.preference.LocalReadingTitleBold @@ -33,6 +35,8 @@ fun Metadata( val titleBold = LocalReadingTitleBold.current val titleUpperCase = LocalReadingTitleUpperCase.current val titleAlign = LocalReadingTitleAlign.current + val openLink = LocalOpenLink.current + val openLinkSpecificBrowser = LocalOpenLinkSpecificBrowser.current val dateString = remember(publishedDate) { publishedDate.formatAsString(context, atHourMinute = true) } @@ -43,7 +47,7 @@ fun Metadata( modifier = Modifier .fillMaxWidth() .roundClick { - context.openURL(link) + context.openURL(link, openLink, openLinkSpecificBrowser) } .padding(12.dp) ) { diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/interaction/InteractionPage.kt b/app/src/main/java/me/ash/reader/ui/page/settings/interaction/InteractionPage.kt index 026e24536..322af599b 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/interaction/InteractionPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/interaction/InteractionPage.kt @@ -1,5 +1,11 @@ package me.ash.reader.ui.page.settings.interaction +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.content.pm.ResolveInfo +import android.os.Build +import android.util.Log import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons @@ -13,13 +19,18 @@ import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController import me.ash.reader.R import me.ash.reader.data.model.preference.InitialFilterPreference +import me.ash.reader.data.model.preference.OpenLinkPreference import me.ash.reader.data.model.preference.InitialPagePreference import me.ash.reader.data.model.preference.LocalInitialFilter +import me.ash.reader.data.model.preference.LocalOpenLink +import me.ash.reader.data.model.preference.LocalOpenLinkSpecificBrowser import me.ash.reader.data.model.preference.LocalInitialPage import me.ash.reader.ui.component.base.* +import me.ash.reader.ui.ext.getBrowserAppList import me.ash.reader.ui.page.settings.SettingItem import me.ash.reader.ui.theme.palette.onLight + @Composable fun InteractionPage( navController: NavHostController, @@ -27,9 +38,16 @@ fun InteractionPage( val context = LocalContext.current val initialPage = LocalInitialPage.current val initialFilter = LocalInitialFilter.current + val openLink = LocalOpenLink.current + val openLinkSpecificBrowser = LocalOpenLinkSpecificBrowser.current val scope = rememberCoroutineScope() + val isOpenLinkSpecificBrowserItemEnabled = remember(openLink) { + openLink == OpenLinkPreference.SpecificBrowser + } var initialPageDialogVisible by remember { mutableStateOf(false) } var initialFilterDialogVisible by remember { mutableStateOf(false) } + var openLinkDialogVisible by remember { mutableStateOf(false) } + var openLinkSpecificBrowserDialogVisible by remember { mutableStateOf(false) } RYScaffold( containerColor = MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface, @@ -67,6 +85,24 @@ fun InteractionPage( initialFilterDialogVisible = true }, ) {} + SettingItem( + title = stringResource(R.string.initial_open_app), + desc = openLink.toDesc(context), + onClick = { + openLinkDialogVisible = true + }, + ) {} + SettingItem( + title = stringResource(R.string.open_link_specific_browser), + desc = openLinkSpecificBrowser.toDesc(context), + enable = isOpenLinkSpecificBrowserItemEnabled, + onClick = { + + if (isOpenLinkSpecificBrowserItemEnabled) { + openLinkSpecificBrowserDialogVisible = true + } + }, + ) {} } item { Spacer(modifier = Modifier.height(24.dp)) @@ -105,4 +141,40 @@ fun InteractionPage( ) { initialFilterDialogVisible = false } + + RadioDialog( + visible = openLinkDialogVisible, + title = stringResource(R.string.initial_open_app), + options = OpenLinkPreference.values.map { + RadioDialogOption( + text = it.toDesc(context), + selected = it == openLink, + ) { + it.put(context, scope) + } + }, + ) { + openLinkDialogVisible = false + } + + val browserList = remember(context) { + context.getBrowserAppList() + } + + RadioDialog( + visible = openLinkSpecificBrowserDialogVisible , + title = stringResource(R.string.open_link_specific_browser), + options = browserList.map { + RadioDialogOption( + text = it.loadLabel(context.packageManager).toString(), + selected = it.activityInfo.packageName == openLinkSpecificBrowser.packageName, + ) { + openLinkSpecificBrowser.copy(packageName = it.activityInfo.packageName).put(context, scope) + } + }, + onDismissRequest = { + openLinkSpecificBrowserDialogVisible = false + } + ) + } diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/languages/LanguagesPage.kt b/app/src/main/java/me/ash/reader/ui/page/settings/languages/LanguagesPage.kt index 5d01f999d..ac5702cf3 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/languages/LanguagesPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/languages/LanguagesPage.kt @@ -22,10 +22,12 @@ import androidx.navigation.NavHostController import me.ash.reader.R import me.ash.reader.data.model.preference.LanguagesPreference import me.ash.reader.data.model.preference.LocalLanguages +import me.ash.reader.data.model.preference.OpenLinkPreference import me.ash.reader.ui.component.base.Banner import me.ash.reader.ui.component.base.DisplayText import me.ash.reader.ui.component.base.FeedbackIconButton import me.ash.reader.ui.component.base.RYScaffold +import me.ash.reader.ui.ext.openURL import me.ash.reader.ui.page.settings.SettingItem import me.ash.reader.ui.theme.palette.onLight @@ -64,12 +66,7 @@ fun LanguagesPage( ) }, ) { - context.startActivity( - Intent( - Intent.ACTION_VIEW, - Uri.parse(context.getString(R.string.translatable_url)) - ) - ) + context.openURL(context.getString(R.string.translatable_url), OpenLinkPreference.AutoPreferCustomTabs) } Spacer(modifier = Modifier.height(16.dp)) } diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/tips/TipsAndSupportPage.kt b/app/src/main/java/me/ash/reader/ui/page/settings/tips/TipsAndSupportPage.kt index af47aa71b..543874fb9 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/tips/TipsAndSupportPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/tips/TipsAndSupportPage.kt @@ -36,6 +36,7 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController import me.ash.reader.R +import me.ash.reader.data.model.preference.OpenLinkPreference import me.ash.reader.ui.component.base.CurlyCornerShape import me.ash.reader.ui.component.base.FeedbackIconButton import me.ash.reader.ui.component.base.RYScaffold @@ -194,12 +195,7 @@ fun TipsAndSupportPage( ) { view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) view.playSoundEffect(SoundEffectConstants.CLICK) - context.startActivity( - Intent( - Intent.ACTION_VIEW, - Uri.parse(context.getString(R.string.github_link)) - ) - ) + context.openURL(context.getString(R.string.github_link), OpenLinkPreference.AutoPreferCustomTabs) }) Spacer(modifier = Modifier.width(16.dp)) @@ -209,12 +205,7 @@ fun TipsAndSupportPage( ) { view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) view.playSoundEffect(SoundEffectConstants.CLICK) - context.startActivity( - Intent( - Intent.ACTION_VIEW, - Uri.parse(context.getString(R.string.telegram_link)) - ) - ) + context.openURL(context.getString(R.string.telegram_link), OpenLinkPreference.AutoPreferCustomTabs) }) Spacer(modifier = Modifier.width(16.dp)) diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/tips/UpdateDialog.kt b/app/src/main/java/me/ash/reader/ui/page/settings/tips/UpdateDialog.kt index d65d840b0..35e94c605 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/tips/UpdateDialog.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/tips/UpdateDialog.kt @@ -36,6 +36,7 @@ import me.ash.reader.data.source.Download import me.ash.reader.ui.component.base.RYDialog import me.ash.reader.ui.ext.collectAsStateValue import me.ash.reader.ui.ext.installLatestApk +import me.ash.reader.ui.ext.openURL @Composable fun UpdateDialog( @@ -106,12 +107,7 @@ fun UpdateDialog( confirmButton = { TextButton( onClick = { - context.startActivity( - Intent( - Intent.ACTION_VIEW, - Uri.parse("${context.getString(R.string.github_link)}/releases/latest"), - ) - ) + context.openURL("${context.getString(R.string.github_link)}/releases/latest", OpenLinkPreference.AutoPreferCustomTabs) // Disable automatic updates in F-Droid // if (downloadState !is Download.Progress) { // updateViewModel.dispatch( diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b970c0c73..b33944c2e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -391,4 +391,16 @@ Password Connection System + App when link is clicked + None + Auto (Prefer CustomTabs) + Auto (Prefer Default Browser) + Force CustomTabs + Force specific browser + Browser: %1$s + Force default browser + Always Ask + Browser + Open Link Setting was ignored because something went whrong. + Open with…