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…