summaryrefslogtreecommitdiffhomepage
path: root/android/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'android/app/src')
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AutoConnectAndLockdownModeScreen.kt131
1 files changed, 103 insertions, 28 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AutoConnectAndLockdownModeScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AutoConnectAndLockdownModeScreen.kt
index f4d417e6f3..5a01e4c941 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AutoConnectAndLockdownModeScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AutoConnectAndLockdownModeScreen.kt
@@ -1,5 +1,7 @@
package net.mullvad.mullvadvpn.compose.screen
+import android.net.Uri
+import androidx.annotation.StringRes
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
@@ -16,6 +18,7 @@ import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
@@ -31,8 +34,14 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.UrlAnnotation
+import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextDecoration
+import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.constraintlayout.compose.ConstrainedLayoutReference
import androidx.constraintlayout.compose.ConstraintLayout
@@ -46,12 +55,15 @@ import net.mullvad.mullvadvpn.compose.component.NavigateBackIconButton
import net.mullvad.mullvadvpn.compose.component.ScaffoldWithLargeTopBarAndButton
import net.mullvad.mullvadvpn.compose.extensions.toAnnotatedString
import net.mullvad.mullvadvpn.compose.transitions.SlideInFromRightTransition
+import net.mullvad.mullvadvpn.lib.common.util.openLink
import net.mullvad.mullvadvpn.lib.common.util.openVpnSettings
import net.mullvad.mullvadvpn.lib.theme.AppTheme
import net.mullvad.mullvadvpn.lib.theme.Dimens
import net.mullvad.mullvadvpn.lib.theme.color.AlphaDescription
import net.mullvad.mullvadvpn.lib.theme.color.AlphaInvisible
import net.mullvad.mullvadvpn.lib.theme.color.AlphaVisible
+import net.mullvad.mullvadvpn.service.constant.IS_PLAY_BUILD
+import net.mullvad.mullvadvpn.util.appendHideNavOnPlayBuild
@Preview
@Composable
@@ -87,7 +99,8 @@ fun AutoConnectAndLockdownModeScreen(onBackClick: () -> Unit = {}) {
pagerState = pagerState,
backButtonRef = backButtonRef,
nextButtonRef = nextButtonRef,
- pager = pager
+ pager = pager,
+ onOpenUrl = { url -> context.openLink(Uri.parse(url)) }
)
// Go to previous page
@@ -131,17 +144,18 @@ fun AutoConnectAndLockdownModeScreen(onBackClick: () -> Unit = {}) {
)
}
}
- }
+ },
)
}
-@OptIn(ExperimentalFoundationApi::class)
+@OptIn(ExperimentalFoundationApi::class, ExperimentalTextApi::class)
@Composable
private fun ConstraintLayoutScope.AutoConnectCarousel(
pagerState: PagerState,
backButtonRef: ConstrainedLayoutReference,
nextButtonRef: ConstrainedLayoutReference,
- pager: ConstrainedLayoutReference
+ pager: ConstrainedLayoutReference,
+ onOpenUrl: (String) -> Unit
) {
HorizontalPager(
state = pagerState,
@@ -152,32 +166,27 @@ private fun ConstraintLayoutScope.AutoConnectCarousel(
start.linkTo(backButtonRef.end)
end.linkTo(nextButtonRef.start)
bottom.linkTo(parent.bottom)
- }
- ) { page ->
+ },
+ ) { pageIndex ->
+ val page = PAGES.entries[pageIndex]
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
- Text(
+ val annotatedTopText = page.annotatedTopText()
+ ClickableText(
modifier = Modifier.padding(horizontal = Dimens.largePadding),
style = MaterialTheme.typography.titleMedium,
- color = MaterialTheme.colorScheme.onSecondary,
- text =
- HtmlCompat.fromHtml(
- stringResource(id = PAGES.entries[page].topText),
- HtmlCompat.FROM_HTML_MODE_COMPACT
- )
- .toAnnotatedString(
- boldSpanStyle =
- SpanStyle(
- fontWeight = FontWeight.ExtraBold,
- color = MaterialTheme.colorScheme.onPrimary
- )
- )
+ text = annotatedTopText,
+ onClick = {
+ annotatedTopText.getUrlAnnotations(it, it).let { annotation ->
+ annotation.firstOrNull()?.item?.url?.let { onOpenUrl(it) }
+ }
+ },
)
Image(
modifier = Modifier.padding(top = Dimens.topPadding, bottom = Dimens.bottomPadding),
- painter = painterResource(id = PAGES.entries[page].image),
+ painter = painterResource(id = page.image),
contentDescription = null,
)
Text(
@@ -186,7 +195,7 @@ private fun ConstraintLayoutScope.AutoConnectCarousel(
color = MaterialTheme.colorScheme.onSecondary,
text =
HtmlCompat.fromHtml(
- stringResource(id = PAGES.entries[page].bottomText),
+ stringResource(id = page.bottomText),
HtmlCompat.FROM_HTML_MODE_COMPACT
)
.toAnnotatedString(
@@ -255,20 +264,86 @@ private fun ConstraintLayoutScope.PageIndicator(
}
}
-private enum class PAGES(val topText: Int, val image: Int, val bottomText: Int) {
+@Composable
+private fun buildTopText(@StringRes id: Int) = buildAnnotatedString {
+ withStyle(
+ style = SpanStyle(color = MaterialTheme.colorScheme.onSecondary),
+ ) {
+ append(
+ HtmlCompat.fromHtml(stringResource(id = id), HtmlCompat.FROM_HTML_MODE_COMPACT)
+ .toAnnotatedString(
+ boldSpanStyle =
+ SpanStyle(
+ fontWeight = FontWeight.ExtraBold,
+ color = MaterialTheme.colorScheme.onPrimary
+ )
+ )
+ )
+ }
+}
+
+@OptIn(ExperimentalTextApi::class)
+@Composable
+private fun buildLockdownTopText() = buildAnnotatedString {
+ append(buildTopText(id = R.string.auto_connect_carousel_third_slide_top_text))
+ append(" ")
+
+ withLink(
+ UrlAnnotation(
+ stringResource(id = R.string.lockdown_url).appendHideNavOnPlayBuild(IS_PLAY_BUILD)
+ )
+ ) {
+ withStyle(
+ style =
+ SpanStyle(
+ color = MaterialTheme.colorScheme.onPrimary,
+ textDecoration = TextDecoration.Underline
+ ),
+ ) {
+ append(
+ stringResource(
+ id = R.string.auto_connect_carousel_third_slide_top_text_website_link
+ )
+ )
+ append(".")
+ }
+ }
+}
+
+// Will be replaced by upstream withLink in Compose UI 1.7.0
+@OptIn(ExperimentalTextApi::class)
+inline fun <R : Any> AnnotatedString.Builder.withLink(
+ annotation: UrlAnnotation,
+ block: AnnotatedString.Builder.() -> R
+): R {
+ val index = pushUrlAnnotation(annotation)
+ return try {
+ block(this)
+ } finally {
+ pop(index)
+ }
+}
+
+private enum class PAGES(
+ val annotatedTopText: @Composable () -> AnnotatedString,
+ val image: Int,
+ val bottomText: Int
+) {
FIRST(
- R.string.auto_connect_carousel_first_slide_top_text,
+ annotatedTopText =
+ @Composable { buildTopText(id = R.string.auto_connect_carousel_first_slide_top_text) },
R.drawable.carousel_slide_1_cogwheel,
- R.string.auto_connect_carousel_first_slide_bottom_text
+ R.string.auto_connect_carousel_first_slide_bottom_text,
),
SECOND(
- R.string.auto_connect_carousel_second_slide_top_text,
+ annotatedTopText =
+ @Composable { buildTopText(id = R.string.auto_connect_carousel_second_slide_top_text) },
R.drawable.carousel_slide_2_always_on,
R.string.auto_connect_carousel_second_slide_bottom_text
),
THIRD(
- R.string.auto_connect_carousel_third_slide_top_text,
+ annotatedTopText = @Composable { buildLockdownTopText() },
R.drawable.carousel_slide_3_block_connections,
- R.string.auto_connect_carousel_third_slide_bottom_text
+ R.string.auto_connect_carousel_third_slide_bottom_text,
)
}