summaryrefslogtreecommitdiffhomepage
path: root/android/app/src
diff options
context:
space:
mode:
authorDavid Göransson <david.goransson@mullvad.net>2025-11-04 10:14:40 +0100
committerDavid Göransson <david.goransson@mullvad.net>2025-11-04 10:14:40 +0100
commitd7b8059e7ffee1826b8a4d7647b892442cbc8b2c (patch)
treed59130e5403cab95a9060498c47261743e49554b /android/app/src
parent0fa8b56af36f292b01e8c161d8453987d878b9c2 (diff)
parent58770773cc8874f566b1be34c9d3b4ee52be4352 (diff)
downloadmullvadvpn-d7b8059e7ffee1826b8a4d7647b892442cbc8b2c.tar.xz
mullvadvpn-d7b8059e7ffee1826b8a4d7647b892442cbc8b2c.zip
Merge branch 'show-feature-indicators-also-when-connecting-droid-2243'
Diffstat (limited to 'android/app/src')
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/ConnectionDetailPanel.kt29
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/FeatureIndicatorsPanel.kt47
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt28
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/Udp2TcpSettingsScreen.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt18
6 files changed, 70 insertions, 56 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt
index 8a5f94d730..8217da8dbe 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt
@@ -120,7 +120,7 @@ private fun ObfuscationMode.toTitle() =
when (this) {
ObfuscationMode.Auto -> stringResource(id = R.string.automatic)
ObfuscationMode.Off -> stringResource(id = R.string.off)
- ObfuscationMode.Udp2Tcp -> stringResource(id = R.string.upd_over_tcp)
+ ObfuscationMode.Udp2Tcp -> stringResource(id = R.string.udp_over_tcp)
ObfuscationMode.Shadowsocks -> stringResource(id = R.string.shadowsocks)
ObfuscationMode.Quic -> stringResource(id = R.string.quic)
ObfuscationMode.Lwo -> stringResource(id = R.string.lwo)
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 92b782895b..cef0ab2cf9 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
@@ -2,6 +2,7 @@ package net.mullvad.mullvadvpn.compose.component.connectioninfo
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.selection.SelectionContainer
@@ -25,23 +26,25 @@ import net.mullvad.mullvadvpn.lib.ui.tag.LOCATION_INFO_CONNECTION_OUT_TEST_TAG
@Composable
fun ConnectionDetailPanel(
- connectionDetails: ConnectionDetails,
+ connectionDetails: ConnectionDetails?,
enableSelectableText: Boolean = true,
) {
- ConnectionInfoHeader(
- stringResource(R.string.connect_panel_connection_details),
- Modifier.fillMaxWidth().padding(bottom = Dimens.smallPadding),
- )
-
- AnimatedContent(connectionDetails, label = "ConnectionDetails") {
- ConnectionDetails(
- it.inAddress,
- it.outIpv4Address,
- it.outIpv6Address,
- modifier = Modifier.padding(bottom = Dimens.smallPadding),
- enableSelectableText = enableSelectableText,
+ Column {
+ ConnectionInfoHeader(
+ stringResource(R.string.connect_panel_connection_details),
+ Modifier.fillMaxWidth().padding(bottom = Dimens.smallPadding),
)
+
+ AnimatedContent(connectionDetails, label = "ConnectionDetails") {
+ ConnectionDetails(
+ it?.inAddress.orEmpty(),
+ it?.outIpv4Address,
+ it?.outIpv6Address,
+ modifier = Modifier.padding(bottom = Dimens.smallPadding),
+ enableSelectableText = enableSelectableText,
+ )
+ }
}
}
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 6c404a5bc9..c5051b1f8d 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
@@ -90,26 +90,24 @@ fun FeatureIndicators(
text = featureIndicator.text(),
onClick = { onNavigateToFeature(featureIndicator) },
modifier =
- Modifier.let {
- if (this@with != null && animatedVisibilityScope != null) {
- it.sharedBounds(
- rememberSharedContentState(
- key =
- if (featureIndicator == FeatureIndicator.DAITA_MULTIHOP)
- FeatureIndicator.DAITA
- else featureIndicator
- ),
- animatedVisibilityScope = animatedVisibilityScope,
- // This flag should be set to `true` (default), this would allow the
- // element to animate above all other views. However, it causes the
- // expand/collapse animation to become janky.
- renderInOverlayDuringTransition = false,
- enter = fadeIn(tween(easing = EaseInQuart)),
- exit = fadeOut(tween(easing = EaseOutQuad)),
- )
- } else {
- it
- }
+ if (this@with != null && animatedVisibilityScope != null) {
+ Modifier.sharedBounds(
+ rememberSharedContentState(
+ key =
+ if (featureIndicator == FeatureIndicator.DAITA_MULTIHOP)
+ FeatureIndicator.DAITA
+ else featureIndicator
+ ),
+ animatedVisibilityScope = animatedVisibilityScope,
+ // This flag should be set to `true` (default), this would allow the
+ // element to animate above all other views. However, it causes the
+ // expand/collapse animation to become janky.
+ renderInOverlayDuringTransition = false,
+ enter = fadeIn(tween(easing = EaseInQuart)),
+ exit = fadeOut(tween(easing = EaseOutQuad)),
+ )
+ } else {
+ Modifier
},
)
}
@@ -123,16 +121,17 @@ fun FeatureIndicators(
}
}
+@Suppress("CyclomaticComplexMethod")
@Composable
private fun FeatureIndicator.text(): String {
val resource =
when (this) {
FeatureIndicator.QUANTUM_RESISTANCE -> R.string.feature_quantum_resistant
FeatureIndicator.SPLIT_TUNNELING -> R.string.split_tunneling
- FeatureIndicator.SHADOWSOCKS,
- FeatureIndicator.UDP_2_TCP,
- FeatureIndicator.QUIC,
- FeatureIndicator.LWO -> R.string.feature_obfuscation
+ FeatureIndicator.SHADOWSOCKS -> R.string.shadowsocks
+ FeatureIndicator.UDP_2_TCP -> R.string.udp_over_tcp
+ FeatureIndicator.QUIC -> R.string.quic
+ FeatureIndicator.LWO -> R.string.lwo
FeatureIndicator.LAN_SHARING -> R.string.local_network_sharing
FeatureIndicator.DNS_CONTENT_BLOCKERS -> R.string.dns_content_blockers
FeatureIndicator.CUSTOM_DNS -> R.string.feature_custom_dns
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 c7074b10a6..d680da7cf4 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
@@ -3,6 +3,7 @@ package net.mullvad.mullvadvpn.compose.screen
import android.content.Context
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.compose.animation.AnimatedContent
+import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.AnimatedVisibilityScope
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState
@@ -528,7 +529,8 @@ private fun ConnectionCard(
onConnectClick: () -> Unit,
onNavigateToFeature: (FeatureIndicator) -> Unit,
) {
- var expanded by rememberSaveable(state.tunnelState::class) { mutableStateOf(false) }
+ var expanded by
+ rememberSaveable(state.tunnelState is TunnelState.Disconnected) { mutableStateOf(false) }
val containerColor =
animateColorAsState(
if (expanded) MaterialTheme.colorScheme.surfaceContainer
@@ -546,14 +548,14 @@ private fun ConnectionCard(
ConnectionCardHeader(state, state.location, expanded) { expanded = !expanded }
AnimatedContent(
- (state.tunnelState as? TunnelState.Connected)?.featureIndicators to expanded,
+ state.tunnelState.featureIndicators() to expanded,
modifier = Modifier.weight(1f, fill = false),
label = "connection_card_connection_details",
) { (featureIndicators, exp) ->
if (featureIndicators != null) {
ConnectionInfo(
featureIndicators,
- (state.tunnelState as? TunnelState.Connected)?.toConnectionsDetails(),
+ state.tunnelState.toConnectionsDetails(),
exp,
onToggleExpand = { expanded = !exp },
onNavigateToFeature = onNavigateToFeature,
@@ -589,14 +591,14 @@ private fun ConnectionCardHeader(
modifier =
Modifier.fillMaxWidth()
.clickable(
- enabled = state.tunnelState is TunnelState.Connected,
+ enabled = state.tunnelState.isConnectingOrConnected(),
onClick = onToggleExpand,
)
.testTag(CONNECT_CARD_HEADER_TEST_TAG)
) {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
ConnectionStatusText(state = state.tunnelState)
- if (state.tunnelState is TunnelState.Connected) {
+ if (state.tunnelState.isConnectingOrConnected()) {
ExpandChevron(isExpanded = !expanded)
}
}
@@ -676,7 +678,7 @@ private fun ConnectionInfo(
) {
FeatureIndicatorsPanel(featureIndicators, expanded, onToggleExpand, onNavigateToFeature)
- if (expanded && connectionDetails != null) {
+ AnimatedVisibility(expanded && connectionDetails != null) {
ConnectionDetailPanel(connectionDetails, enableSelectableText = !isTv())
}
}
@@ -690,12 +692,22 @@ data class ConnectionDetails(
)
@Composable
-fun TunnelState.Connected.toConnectionsDetails(): ConnectionDetails =
- ConnectionDetails(
+fun TunnelState.toConnectionsDetails(): ConnectionDetails? {
+ val endpoint =
+ when (this) {
+ is TunnelState.Connected -> endpoint
+ is TunnelState.Connecting -> endpoint
+ else -> null
+ }
+
+ if (endpoint == null) return null
+
+ return ConnectionDetails(
endpoint.toInAddress(),
location()?.ipv4?.hostAddress,
location()?.ipv6?.hostAddress,
)
+}
@Composable
private fun ButtonPanel(
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/Udp2TcpSettingsScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/Udp2TcpSettingsScreen.kt
index 00a8151254..829acb979b 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/Udp2TcpSettingsScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/Udp2TcpSettingsScreen.kt
@@ -72,7 +72,7 @@ fun Udp2TcpSettingsScreen(
onBackClick: () -> Unit,
) {
ScaffoldWithMediumTopBar(
- appBarTitle = stringResource(id = R.string.upd_over_tcp),
+ appBarTitle = stringResource(id = R.string.udp_over_tcp),
navigationIcon = { NavigateBackIconButton(onNavigateBack = onBackClick) },
) { modifier, lazyListState ->
LazyColumn(
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt
index 1cba4093f1..80e2f2688d 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt
@@ -796,15 +796,15 @@ fun VpnSettingsContent(
onInfoClicked = navigateToObfuscationInfo,
onCellClicked = navigateToObfuscationInfo,
background =
- if (
- initialScrollToFeature == FeatureIndicator.UDP_2_TCP ||
- initialScrollToFeature == FeatureIndicator.SHADOWSOCKS
- ) {
- MaterialTheme.colorScheme.primary.copy(
- alpha = highlightAnimation.value
- )
- } else {
- MaterialTheme.colorScheme.primary
+ when (initialScrollToFeature) {
+ FeatureIndicator.UDP_2_TCP,
+ FeatureIndicator.SHADOWSOCKS,
+ FeatureIndicator.QUIC,
+ FeatureIndicator.LWO ->
+ MaterialTheme.colorScheme.primary.copy(
+ alpha = highlightAnimation.value
+ )
+ else -> MaterialTheme.colorScheme.primary
},
testTag = LAZY_LIST_WIREGUARD_OBFUSCATION_TITLE_TEST_TAG,
modifier = Modifier.animateItem(),