summaryrefslogtreecommitdiffhomepage
path: root/android/app/src
diff options
context:
space:
mode:
authorDavid Göransson <david.goransson@mullvad.net>2025-05-07 09:30:47 +0200
committerDavid Göransson <david.goransson@mullvad.net>2025-05-07 09:30:47 +0200
commit95bb5d4a6ecc83fb9a968fff941812231128d14f (patch)
tree1dab3727a500e36f213635c56f2c39bcb29000b7 /android/app/src
parentf7aefa938f8047e8e59fd98ee0175545d585c822 (diff)
parent7fb0b567faaff21c60009107a44840438ed67644 (diff)
downloadmullvadvpn-95bb5d4a6ecc83fb9a968fff941812231128d14f.tar.xz
mullvadvpn-95bb5d4a6ecc83fb9a968fff941812231128d14f.zip
Merge branch 'update-compose-to-180-droid-1969'
Diffstat (limited to 'android/app/src')
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/ConnectionDetailPanel.kt53
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/FeatureIndicatorsPanel.kt1
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt39
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/location/SelectLocationScreen.kt4
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/Clipboard.kt23
5 files changed, 66 insertions, 54 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/ConnectionDetailPanel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/ConnectionDetailPanel.kt
index c0a005ef40..08eec406bf 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/ConnectionDetailPanel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/ConnectionDetailPanel.kt
@@ -24,7 +24,10 @@ import net.mullvad.mullvadvpn.lib.ui.tag.LOCATION_INFO_CONNECTION_IN_TEST_TAG
import net.mullvad.mullvadvpn.lib.ui.tag.LOCATION_INFO_CONNECTION_OUT_TEST_TAG
@Composable
-fun ConnectionDetailPanel(connectionDetails: ConnectionDetails) {
+fun ConnectionDetailPanel(
+ connectionDetails: ConnectionDetails,
+ enableSelectableText: Boolean = true,
+) {
ConnectionInfoHeader(
stringResource(R.string.connect_panel_connection_details),
@@ -37,6 +40,7 @@ fun ConnectionDetailPanel(connectionDetails: ConnectionDetails) {
it.outIpv4Address,
it.outIpv6Address,
modifier = Modifier.padding(bottom = Dimens.smallPadding),
+ enableSelectableText = enableSelectableText,
)
}
}
@@ -48,6 +52,7 @@ fun ConnectionDetails(
outIPV4: String?,
outIPV6: String?,
modifier: Modifier = Modifier,
+ enableSelectableText: Boolean = true,
) {
ConstraintLayout(modifier = modifier.fillMaxWidth()) {
val (inAddrHeader, inAddr, outAddrV4Header, outAddrV4, outAddrV6Header, outAddrV6) =
@@ -131,15 +136,21 @@ fun ConnectionDetails(
width = Dimension.fillToConstraints
}
) {
- SelectionContainer {
- Text(
- modifier = Modifier.testTag(LOCATION_INFO_CONNECTION_OUT_TEST_TAG),
- text = outIPV4,
- color = MaterialTheme.colorScheme.onPrimary,
- style = MaterialTheme.typography.bodySmall,
- maxLines = 1,
- overflow = TextOverflow.Ellipsis,
- )
+ val outIpV4Text =
+ @Composable {
+ Text(
+ modifier = Modifier.testTag(LOCATION_INFO_CONNECTION_OUT_TEST_TAG),
+ text = outIPV4,
+ color = MaterialTheme.colorScheme.onPrimary,
+ style = MaterialTheme.typography.bodySmall,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ )
+ }
+ if (enableSelectableText) {
+ SelectionContainer(content = outIpV4Text)
+ } else {
+ outIpV4Text()
}
}
}
@@ -176,14 +187,20 @@ fun ConnectionDetails(
width = Dimension.fillToConstraints
}
) {
- SelectionContainer {
- Text(
- text = outIPV6,
- color = MaterialTheme.colorScheme.onPrimary,
- style = MaterialTheme.typography.bodySmall,
- maxLines = 1,
- overflow = TextOverflow.Ellipsis,
- )
+ val outIpV6Text =
+ @Composable {
+ Text(
+ text = outIPV6,
+ color = MaterialTheme.colorScheme.onPrimary,
+ style = MaterialTheme.typography.bodySmall,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ )
+ }
+ if (enableSelectableText) {
+ SelectionContainer(content = outIpV6Text)
+ } else {
+ outIpV6Text()
}
}
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/FeatureIndicatorsPanel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/FeatureIndicatorsPanel.kt
index afd13a7382..a485dbe9d9 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/FeatureIndicatorsPanel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/FeatureIndicatorsPanel.kt
@@ -1,4 +1,5 @@
@file:OptIn(ExperimentalSharedTransitionApi::class)
+@file:Suppress("DEPRECATION")
package net.mullvad.mullvadvpn.compose.component.connectioninfo
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt
index 45e9bdee52..94db024b41 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt
@@ -33,6 +33,7 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf
@@ -43,16 +44,14 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
-import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.focus.FocusRequester
-import androidx.compose.ui.focus.focusProperties
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.layout
-import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.platform.LocalUriHandler
+import androidx.compose.ui.platform.LocalWindowInfo
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
@@ -352,26 +351,12 @@ fun ConnectScreen(
if (isTv()) {
Scaffold(
- modifier =
- Modifier.focusProperties {
- enter = { focusDirection ->
- // When we return to this screen from SelectLocationScreen the focus is
- // sometimes put on the TV navigation drawer, which causes it expand
- // (when it was previously not expanded). When returning from
- // SelectLocationScreen we get a FocusDirection.Down event, so we focus
- // on the switch location composable.
- // When on TV and we return from account or settings we get a
- // FocusDirection.Enter event, so focus remains on the navigation drawer.
- if (focusDirection == FocusDirection.Down) contentFocusRequester
- else FocusRequester.Default
- }
- },
snackbarHost = {
SnackbarHost(
snackbarHostState,
snackbar = { snackbarData -> MullvadSnackbar(snackbarData = snackbarData) },
)
- },
+ }
) {
NavigationDrawerTv(
daysLeftUntilExpiry = state.daysLeftUntilExpiry,
@@ -382,6 +367,7 @@ fun ConnectScreen(
content(it)
}
}
+ LaunchedEffect(Unit) { contentFocusRequester.requestFocus() }
} else {
ScaffoldWithTopBarAndDeviceName(
topBarColor = state.tunnelState.topBarColor(),
@@ -414,8 +400,7 @@ private fun Content(
onDismissNewDeviceClick: () -> Unit,
onNavigateToFeature: (FeatureIndicator) -> Unit,
) {
- val configuration = LocalConfiguration.current
- val screenHeight = configuration.screenHeightDp.dp
+ val screenHeight = LocalWindowInfo.current.containerSize.height.dp
val indicatorPercentOffset =
if (screenHeight < SCREEN_HEIGHT_THRESHOLD) SHORT_SCREEN_INDICATOR_BIAS
else TALL_SCREEN_INDICATOR_BIAS
@@ -666,7 +651,7 @@ private fun ConnectionInfo(
FeatureIndicatorsPanel(featureIndicators, expanded, onToggleExpand, onNavigateToFeature)
if (expanded && connectionDetails != null) {
- ConnectionDetailPanel(connectionDetails)
+ ConnectionDetailPanel(connectionDetails, enableSelectableText = !isTv())
}
}
}
@@ -689,7 +674,7 @@ fun TunnelState.Connected.toConnectionsDetails(): ConnectionDetails =
@Composable
private fun ButtonPanel(
state: ConnectUiState,
- focusRequester: FocusRequester,
+ selectButtonFocusRequester: FocusRequester,
onSwitchLocationClick: () -> Unit,
onDisconnectClick: () -> Unit,
onReconnectClick: () -> Unit,
@@ -714,12 +699,18 @@ private fun ButtonPanel(
stringResource(id = R.string.switch_location)
},
onSwitchLocation = onSwitchLocationClick,
- reconnectClick = { handleThrottledAction(onReconnectClick) },
+ reconnectClick = {
+ handleThrottledAction {
+ onReconnectClick()
+ selectButtonFocusRequester.requestFocus()
+ }
+ },
isReconnectButtonEnabled =
state.tunnelState is TunnelState.Connected ||
state.tunnelState is TunnelState.Connecting,
modifier =
- Modifier.testTag(SELECT_LOCATION_BUTTON_TEST_TAG).focusRequester(focusRequester),
+ Modifier.testTag(SELECT_LOCATION_BUTTON_TEST_TAG)
+ .focusRequester(selectButtonFocusRequester),
reconnectButtonTestTag = RECONNECT_BUTTON_TEST_TAG,
)
Spacer(Modifier.height(Dimens.buttonVerticalPadding))
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/location/SelectLocationScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/location/SelectLocationScreen.kt
index c2c3a72c35..b41a95d64e 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/location/SelectLocationScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/location/SelectLocationScreen.kt
@@ -32,6 +32,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
@@ -372,7 +373,8 @@ private fun RelayLists(
) {
// This is a workaround for the HorizontalPager being broken on Android TV when it contains
// focusable views and you navigate with the D-pad. Remove this code once DROID-1639 is fixed.
- val configuration = LocalContext.current.resources.configuration
+ val configuration = LocalConfiguration.current
+
if (configuration.navigation == Configuration.NAVIGATION_DPAD) {
SelectLocationList(
backgroundColor = backgroundColor,
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/Clipboard.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/Clipboard.kt
index 55bc1855d3..3dbe8e7565 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/Clipboard.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/util/Clipboard.kt
@@ -7,8 +7,7 @@ import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.ui.platform.ClipboardManager
-import androidx.compose.ui.platform.LocalClipboardManager
+import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.platform.toClipEntry
import kotlinx.coroutines.launch
@@ -22,7 +21,7 @@ fun createCopyToClipboardHandle(
isSensitive: Boolean,
): CopyToClipboardHandle {
val scope = rememberCoroutineScope()
- val clipboardManager: ClipboardManager = LocalClipboardManager.current
+ val clipboardManager = LocalClipboard.current
return { textToCopy: String, toastMessage: String? ->
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU && toastMessage != null) {
@@ -34,14 +33,16 @@ fun createCopyToClipboardHandle(
}
}
- val clip =
- ClipData.newPlainText("", textToCopy)
- .apply {
- description.extras =
- PersistableBundle().apply { putBoolean(IS_SENSITIVE_FLAG, isSensitive) }
- }
- .toClipEntry()
+ scope.launch {
+ val clip =
+ ClipData.newPlainText("", textToCopy)
+ .apply {
+ description.extras =
+ PersistableBundle().apply { putBoolean(IS_SENSITIVE_FLAG, isSensitive) }
+ }
+ .toClipEntry()
- clipboardManager.setClip(clip)
+ clipboardManager.setClipEntry(clip)
+ }
}
}