ui: open external link alerts (#6860)

* ui: open external link alerts

* update

* update

* update

* update

* update

* change link, add link to alert, close modals when opening chat

* refactor

* add string

* fix link in terms

* open simplex chat links from privacy policy in app

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
This commit is contained in:
spaced4ndy
2026-04-25 14:59:42 +00:00
committed by GitHub
parent 0ff297b3b7
commit ea6a09b66e
23 changed files with 109 additions and 60 deletions
@@ -537,6 +537,20 @@ fun UriHandler.openUriCatching(uri: String) {
}
}
fun UriHandler.openExternalLink(uri: String) {
val uriHandler = this
if (uri.startsWith("https://simplex.chat/contact#") || (uri.startsWith("https://smp") && ".simplex.im/a#" in uri)) {
uriHandler.openVerifiedSimplexUri(uri)
} else {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.open_external_link_title),
text = uri,
confirmText = generalGetString(MR.strings.open_verb),
onConfirm = { uriHandler.openUriCatching(uri) }
)
}
}
fun IntSize.Companion.Saver(): Saver<IntSize, *> = Saver(
save = { it.width to it.height },
restore = { IntSize(it.first, it.second) }
@@ -604,6 +604,7 @@ fun showPrepareContactAlert(
confirmText = generalGetString(MR.strings.connect_plan_open_new_chat),
onConfirm = {
AlertManager.privacySensitive.hideAlert()
ModalManager.closeAllModalsEverywhere()
withBGApi {
val chat = chatModel.controller.apiPrepareContact(rhId, connectionLink, contactShortLinkData)
if (chat != null) {
@@ -67,7 +67,7 @@ fun ReadableTextWithLink(stringResId: StringResource, link: String, textAlign: T
newStyles
}
val uriHandler = LocalUriHandler.current
Text(AnnotatedString(annotated.text, newStyles), modifier = Modifier.padding(padding).clickable { if (simplexLink) uriHandler.openVerifiedSimplexUri(link) else uriHandler.openUriCatching(link) }, textAlign = textAlign, lineHeight = 22.sp)
Text(AnnotatedString(annotated.text, newStyles), modifier = Modifier.padding(padding).clickable { if (simplexLink) uriHandler.openVerifiedSimplexUri(link) else uriHandler.openExternalLink(link) }, textAlign = textAlign, lineHeight = 22.sp)
}
@Composable
@@ -59,7 +59,7 @@ fun ModalData.WhatsNewView(updatedConditions: Boolean = false, viaSettings: Bool
Icon(
painterResource(MR.images.ic_open_in_new), stringResource(titleId), tint = MaterialTheme.colors.primary,
modifier = Modifier
.clickable { if (link.startsWith("simplex:")) uriHandler.openVerifiedSimplexUri(link) else uriHandler.openUriCatching(link) }
.clickable { if (link.startsWith("simplex:")) uriHandler.openVerifiedSimplexUri(link) else uriHandler.openExternalLink(link) }
)
}
@@ -229,7 +229,7 @@ fun ReadMoreButton(url: String) {
interactionSource = remember { MutableInteractionSource() },
indication = null
) {
uriHandler.openUriCatching(url)
uriHandler.openExternalLink(url)
}
)
Icon(painterResource(MR.images.ic_open_in_new), stringResource(MR.strings.whats_new_read_more), tint = MaterialTheme.colors.primary)
@@ -198,7 +198,7 @@ private fun howToButton() {
val uriHandler = LocalUriHandler.current
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable { uriHandler.openUriCatching("https://simplex.chat/docs/webrtc.html#configure-mobile-apps") }
modifier = Modifier.clickable { uriHandler.openExternalLink("https://simplex.chat/docs/webrtc.html#configure-mobile-apps") }
) {
Text(stringResource(MR.strings.how_to), color = MaterialTheme.colors.primary)
Icon(
@@ -75,7 +75,7 @@ fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit, close: (
}
val simplexTeamUri =
"simplex:/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D"
"simplex:/a#lrdvu2d8A1GumSmoKb2krQmtKhWXq-tyGpHuM7aMwsw?h=smp6.simplex.im"
@Composable
fun SettingsLayout(
@@ -207,7 +207,7 @@ fun ChatLockItem(
}
@Composable private fun ContributeItem(uriHandler: UriHandler) {
SectionItemView({ uriHandler.openUriCatching("https://github.com/simplex-chat/simplex-chat#contribute") }) {
SectionItemView({ uriHandler.openExternalLink("https://github.com/simplex-chat/simplex-chat#contribute") }) {
Icon(
painterResource(MR.images.ic_keyboard),
contentDescription = "GitHub",
@@ -235,7 +235,7 @@ fun ChatLockItem(
}
@Composable private fun StarOnGithubItem(uriHandler: UriHandler) {
SectionItemView({ uriHandler.openUriCatching("https://github.com/simplex-chat/simplex-chat") }) {
SectionItemView({ uriHandler.openExternalLink("https://github.com/simplex-chat/simplex-chat") }) {
Icon(
painter = painterResource(MR.images.ic_github),
contentDescription = "GitHub",
@@ -268,7 +268,7 @@ fun ChatLockItem(
}
@Composable fun InstallTerminalAppItem(uriHandler: UriHandler) {
SectionItemView({ uriHandler.openUriCatching("https://github.com/simplex-chat/simplex-chat") }) {
SectionItemView({ uriHandler.openExternalLink("https://github.com/simplex-chat/simplex-chat") }) {
Icon(
painter = painterResource(MR.images.ic_github),
contentDescription = "GitHub",
@@ -769,7 +769,7 @@ fun UsageConditionsView(
.clip(shape = CircleShape)
.clickable {
val commitUrl = "https://github.com/simplex-chat/simplex-chat/commit/$commit"
uriHandler.openUriCatching(commitUrl)
uriHandler.openExternalLink(commitUrl)
}
.padding(horizontal = 6.dp, vertical = 4.dp),
verticalAlignment = Alignment.CenterVertically,
@@ -500,7 +500,7 @@ fun OperatorInfoView(serverOperator: ServerOperator) {
Text(d)
}
val website = serverOperator.info.website
Text(website, color = MaterialTheme.colors.primary, modifier = Modifier.clickable { uriHandler.openUriCatching(website) })
Text(website, color = MaterialTheme.colors.primary, modifier = Modifier.clickable { uriHandler.openExternalLink(website) })
}
}
}
@@ -511,7 +511,7 @@ fun OperatorInfoView(serverOperator: ServerOperator) {
SectionView {
SectionItemView {
val (text, link) = selfhost
Text(text, color = MaterialTheme.colors.primary, modifier = Modifier.clickable { uriHandler.openUriCatching(link) })
Text(text, color = MaterialTheme.colors.primary, modifier = Modifier.clickable { uriHandler.openExternalLink(link) })
}
}
}
@@ -787,7 +787,7 @@ private fun ConditionsLinkView(conditionsLink: String) {
SectionItemView {
val uriHandler = LocalUriHandler.current
Text(stringResource(MR.strings.operator_conditions_failed_to_load), color = MaterialTheme.colors.onBackground)
Text(conditionsLink, color = MaterialTheme.colors.primary, modifier = Modifier.clickable { uriHandler.openUriCatching(conditionsLink) })
Text(conditionsLink, color = MaterialTheme.colors.primary, modifier = Modifier.clickable { uriHandler.openExternalLink(conditionsLink) })
}
}
@@ -821,13 +821,13 @@ fun ConditionsLinkButton() {
val commit = chatModel.conditions.value.currentConditions.conditionsCommit
ItemAction(stringResource(MR.strings.operator_open_conditions), painterResource(MR.images.ic_draft), onClick = {
val mdUrl = "https://github.com/simplex-chat/simplex-chat/blob/$commit/PRIVACY.md"
uriHandler.openUriCatching(mdUrl)
showMenu.value = false
uriHandler.openExternalLink(mdUrl)
})
ItemAction(stringResource(MR.strings.operator_open_changes), painterResource(MR.images.ic_more_horiz), onClick = {
val commitUrl = "https://github.com/simplex-chat/simplex-chat/commit/$commit"
uriHandler.openUriCatching(commitUrl)
showMenu.value = false
uriHandler.openExternalLink(commitUrl)
})
}
IconButton({ showMenu.value = true }) {
@@ -838,11 +838,7 @@ fun ConditionsLinkButton() {
private fun internalUriHandler(parentUriHandler: UriHandler): UriHandler = object: UriHandler {
override fun openUri(uri: String) {
if (uri.startsWith("https://simplex.chat/contact#")) {
openVerifiedSimplexUri(uri)
} else {
parentUriHandler.openUriCatching(uri)
}
parentUriHandler.openExternalLink(uri)
}
}
@@ -335,7 +335,7 @@ private fun HowToButton() {
SettingsActionItem(
painterResource(MR.images.ic_open_in_new),
stringResource(MR.strings.how_to_use_your_servers),
{ uriHandler.openUriCatching("https://simplex.chat/docs/server.html") },
{ uriHandler.openExternalLink("https://simplex.chat/docs/server.html") },
textColor = MaterialTheme.colors.primary,
iconColor = MaterialTheme.colors.primary
)
@@ -1376,6 +1376,7 @@
<string name="open_simplex_chat_to_accept_call">Open SimpleX Chat to accept call</string>
<string name="allow_accepting_calls_from_lock_screen">Enable calls from lock screen via Settings.</string>
<string name="open_verb">Open</string>
<string name="open_external_link_title">Open external link?</string>
<!-- Call overlay -->
<string name="status_e2e_encrypted">e2e encrypted</string>