diff options
| author | David Göransson <david.goransson@mullvad.net> | 2024-06-04 08:27:30 +0200 |
|---|---|---|
| committer | David Göransson <david.goransson@mullvad.net> | 2024-06-04 08:27:30 +0200 |
| commit | 45c369fe355a5eadc29dd3e6f492ff6d7430ee5d (patch) | |
| tree | 70925bd8ab3348533ca7217606ac4c2d42356453 /android/app | |
| parent | 3ac0f264402e42a16f0bd6c76e1a6a67e01ed4ef (diff) | |
| parent | 571c620b51cdc6b4338a3244b500f70e79b3ca7d (diff) | |
| download | mullvadvpn-45c369fe355a5eadc29dd3e6f492ff6d7430ee5d.tar.xz mullvadvpn-45c369fe355a5eadc29dd3e6f492ff6d7430ee5d.zip | |
Merge branch 'add-setting-for-udp2tcp-port-droid-249'
Diffstat (limited to 'android/app')
12 files changed, 220 insertions, 23 deletions
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt index ca7a01a0a9..650c51d641 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt @@ -8,6 +8,7 @@ import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performScrollToNode import io.mockk.MockKAnnotations +import io.mockk.coVerify import io.mockk.mockk import io.mockk.verify import net.mullvad.mullvadvpn.compose.createEdgeToEdgeComposeExtension @@ -17,6 +18,8 @@ import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_LAST_ITEM_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_QUANTUM_ITEM_OFF_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_QUANTUM_ITEM_ON_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_TEST_TAG +import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_UDP_OVER_TCP_PORT_ITEM_X_TEST_TAG +import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_UDP_OVER_TCP_PORT_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_WIREGUARD_CUSTOM_PORT_NUMBER_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG @@ -25,6 +28,7 @@ import net.mullvad.mullvadvpn.lib.model.Mtu import net.mullvad.mullvadvpn.lib.model.Port import net.mullvad.mullvadvpn.lib.model.PortRange import net.mullvad.mullvadvpn.lib.model.QuantumResistantState +import net.mullvad.mullvadvpn.lib.model.SelectedObfuscation import net.mullvad.mullvadvpn.onNodeWithTagAndText import net.mullvad.mullvadvpn.viewmodel.CustomDnsItem import org.junit.jupiter.api.BeforeEach @@ -207,6 +211,77 @@ class VpnSettingsScreenTest { } @Test + fun testSelectTcpOverUdpPortOption() = + composeExtension.use { + // Arrange + val onObfuscationPortSelected: (Constraint<Port>) -> Unit = mockk(relaxed = true) + setContentWithTheme { + VpnSettingsScreen( + state = + VpnSettingsUiState.createDefault( + selectedObfuscation = SelectedObfuscation.Udp2Tcp, + selectedObfuscationPort = Constraint.Only(Port(5001)) + ), + onObfuscationPortSelected = onObfuscationPortSelected + ) + } + + // Act + onNodeWithTag(LAZY_LIST_TEST_TAG) + .performScrollToNode(hasTestTag(LAZY_LIST_UDP_OVER_TCP_PORT_TEST_TAG)) + onNodeWithText("UDP-over-TCP port").performClick() + onNodeWithTag(LAZY_LIST_TEST_TAG) + .performScrollToNode( + hasTestTag(String.format(LAZY_LIST_UDP_OVER_TCP_PORT_ITEM_X_TEST_TAG, 5001)) + ) + + // Assert + onNodeWithTagAndText( + testTag = String.format(LAZY_LIST_UDP_OVER_TCP_PORT_ITEM_X_TEST_TAG, 5001), + text = "5001" + ) + .assertExists() + .performClick() + + coVerify(exactly = 1) { onObfuscationPortSelected.invoke(Constraint.Only(Port(5001))) } + } + + @Test + fun testAttemptSelectTcpOverUdpPortOption() = + composeExtension.use { + // Arrange + val onObfuscationPortSelected: (Constraint<Port>) -> Unit = mockk(relaxed = true) + setContentWithTheme { + VpnSettingsScreen( + state = + VpnSettingsUiState.createDefault( + selectedObfuscation = SelectedObfuscation.Off, + ), + onObfuscationPortSelected = onObfuscationPortSelected + ) + } + + // Act + onNodeWithTag(LAZY_LIST_TEST_TAG) + .performScrollToNode(hasTestTag(LAZY_LIST_UDP_OVER_TCP_PORT_TEST_TAG)) + onNodeWithText("UDP-over-TCP port").performClick() + onNodeWithTag(LAZY_LIST_TEST_TAG) + .performScrollToNode( + hasTestTag(String.format(LAZY_LIST_UDP_OVER_TCP_PORT_ITEM_X_TEST_TAG, 5001)) + ) + + // Assert + onNodeWithTagAndText( + testTag = String.format(LAZY_LIST_UDP_OVER_TCP_PORT_ITEM_X_TEST_TAG, 5001), + text = "5001" + ) + .assertExists() + .performClick() + + verify(exactly = 0) { onObfuscationPortSelected.invoke(any()) } + } + + @Test fun testShowSelectedTunnelQuantumOption() = composeExtension.use { // Arrange @@ -402,6 +477,29 @@ class VpnSettingsScreenTest { } @Test + fun testShowObfuscationInfo() = + composeExtension.use { + val mockedNavigateToObfuscationInfo: () -> Unit = mockk(relaxed = true) + + // Arrange + setContentWithTheme { + VpnSettingsScreen( + state = VpnSettingsUiState.createDefault(), + navigateToObfuscationInfo = mockedNavigateToObfuscationInfo + ) + } + + // Act + + onNodeWithTag(LAZY_LIST_TEST_TAG) + .performScrollToNode(hasTestTag(LAZY_LIST_UDP_OVER_TCP_PORT_TEST_TAG)) + onNodeWithText("WireGuard obfuscation").performClick() + + // Assert + verify(exactly = 1) { mockedNavigateToObfuscationInfo() } + } + + @Test fun testShowTunnelQuantumInfo() = composeExtension.use { val mockedShowTunnelQuantumInfoClick: () -> Unit = mockk(relaxed = true) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ExpandableComposeCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ExpandableComposeCell.kt index 73a6a5283d..b19f534456 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ExpandableComposeCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ExpandableComposeCell.kt @@ -13,6 +13,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.focus.focusProperties +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -46,6 +47,7 @@ fun ExpandableComposeCell( title: String, isExpanded: Boolean, isEnabled: Boolean = true, + testTag: String = "", onCellClicked: (Boolean) -> Unit = {}, onInfoClicked: (() -> Unit)? = null ) { @@ -53,7 +55,7 @@ fun ExpandableComposeCell( val bodyViewModifier = Modifier BaseCell( - modifier = Modifier.focusProperties { canFocus = false }, + modifier = Modifier.testTag(testTag).focusProperties { canFocus = false }, headlineContent = { BaseCellTitle( title = title, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt index d69194490e..a4cd9b9548 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt @@ -17,6 +17,7 @@ import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.component.SpacedColumn import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.lib.theme.Dimens +import net.mullvad.mullvadvpn.lib.theme.color.AlphaDisabled import net.mullvad.mullvadvpn.lib.theme.color.AlphaInvisible import net.mullvad.mullvadvpn.lib.theme.color.AlphaVisible import net.mullvad.mullvadvpn.lib.theme.color.selected @@ -36,6 +37,7 @@ private fun PreviewSelectableCell() { fun SelectableCell( title: String, isSelected: Boolean, + isEnabled: Boolean = true, iconContentDescription: String? = null, selectedIcon: @Composable RowScope.() -> Unit = { Icon( @@ -44,7 +46,10 @@ fun SelectableCell( tint = MaterialTheme.colorScheme.onPrimary, modifier = Modifier.padding(end = Dimens.selectableCellTextMargin) - .alpha(if (isSelected) AlphaVisible else AlphaInvisible) + .alpha( + if (isSelected && !isEnabled) AlphaDisabled + else if (isSelected) AlphaVisible else AlphaInvisible + ) ) }, titleStyle: TextStyle = MaterialTheme.typography.labelLarge, @@ -56,7 +61,16 @@ fun SelectableCell( ) { BaseCell( onCellClicked = onCellClicked, - headlineContent = { BaseCellTitle(title = title, style = titleStyle) }, + isRowEnabled = isEnabled, + headlineContent = { + BaseCellTitle( + title = title, + style = titleStyle, + color = + if (isEnabled) MaterialTheme.colorScheme.onPrimary + else MaterialTheme.colorScheme.onPrimary.copy(AlphaDisabled) + ) + }, background = if (isSelected) { selectedColor diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SwitchComposeCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SwitchComposeCell.kt index f74349113c..11045fa617 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SwitchComposeCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SwitchComposeCell.kt @@ -28,6 +28,7 @@ import net.mullvad.mullvadvpn.compose.component.textResource import net.mullvad.mullvadvpn.compose.extensions.toAnnotatedString import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.lib.theme.Dimens +import net.mullvad.mullvadvpn.lib.theme.color.AlphaDisabled @Preview @Composable @@ -67,7 +68,10 @@ fun NormalSwitchComposeCell( BaseCellTitle( title = title, style = MaterialTheme.typography.labelLarge, - modifier = Modifier.weight(1f, true) + modifier = Modifier.weight(1f, true), + color = + if (isEnabled) MaterialTheme.colorScheme.onPrimary + else MaterialTheme.colorScheme.onPrimary.copy(AlphaDisabled) ) }, isToggled = isToggled, 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 7eee7c1398..41b4ea8a2e 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 @@ -77,6 +77,9 @@ import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_LAST_ITEM_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_QUANTUM_ITEM_OFF_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_QUANTUM_ITEM_ON_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_TEST_TAG +import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_UDP_OVER_TCP_PORT_ITEM_AUTOMATIC_TEST_TAG +import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_UDP_OVER_TCP_PORT_ITEM_X_TEST_TAG +import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_UDP_OVER_TCP_PORT_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_WIREGUARD_CUSTOM_PORT_NUMBER_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG @@ -84,6 +87,7 @@ import net.mullvad.mullvadvpn.compose.transitions.SlideInFromRightTransition import net.mullvad.mullvadvpn.compose.util.LaunchedEffectCollect import net.mullvad.mullvadvpn.compose.util.OnNavResultValue import net.mullvad.mullvadvpn.compose.util.showSnackbarImmediately +import net.mullvad.mullvadvpn.constant.UDP2TCP_PRESET_PORTS import net.mullvad.mullvadvpn.constant.WIREGUARD_PRESET_PORTS import net.mullvad.mullvadvpn.lib.model.Constraint import net.mullvad.mullvadvpn.lib.model.Mtu @@ -258,6 +262,7 @@ fun VpnSettings( onSelectObfuscationSetting = vm::onSelectObfuscationSetting, onSelectQuantumResistanceSetting = vm::onSelectQuantumResistanceSetting, onWireguardPortSelected = vm::onWireguardPortSelected, + onObfuscationPortSelected = vm::onObfuscationPortSelected, ) } @@ -293,8 +298,10 @@ fun VpnSettingsScreen( onSelectObfuscationSetting: (selectedObfuscation: SelectedObfuscation) -> Unit = {}, onSelectQuantumResistanceSetting: (quantumResistant: QuantumResistantState) -> Unit = {}, onWireguardPortSelected: (port: Constraint<Port>) -> Unit = {}, + onObfuscationPortSelected: (port: Constraint<Port>) -> Unit = {}, ) { var expandContentBlockersState by rememberSaveable { mutableStateOf(false) } + var expandUdp2TcpPortSettings by rememberSaveable { mutableStateOf(false) } val biggerPadding = 54.dp val topPadding = 6.dp @@ -527,7 +534,8 @@ fun VpnSettingsScreen( itemWithDivider { SelectableCell( title = port.toString(), - testTag = String.format(LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG, port), + testTag = + String.format(null, LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG, port), isSelected = state.selectedWireguardPort.hasValue(port), onCellClicked = { onWireguardPortSelected(Constraint.Only(Port(port))) } ) @@ -583,6 +591,48 @@ fun VpnSettingsScreen( } itemWithDivider { + ExpandableComposeCell( + title = stringResource(R.string.udp_over_tcp_port_title), + isExpanded = expandUdp2TcpPortSettings, + isEnabled = state.selectedObfuscation != SelectedObfuscation.Off, + onInfoClicked = navigateUdp2TcpInfo, + onCellClicked = { expandUdp2TcpPortSettings = !expandUdp2TcpPortSettings }, + testTag = LAZY_LIST_UDP_OVER_TCP_PORT_TEST_TAG + ) + } + + if (expandUdp2TcpPortSettings) { + itemWithDivider { + SelectableCell( + title = stringResource(id = R.string.automatic), + isSelected = state.selectedObfuscationPort is Constraint.Any, + isEnabled = state.selectObfuscationPortEnabled, + onCellClicked = { onObfuscationPortSelected(Constraint.Any) }, + testTag = LAZY_LIST_UDP_OVER_TCP_PORT_ITEM_AUTOMATIC_TEST_TAG, + ) + } + + UDP2TCP_PRESET_PORTS.forEach { port -> + itemWithDivider { + SelectableCell( + title = port.toString(), + isSelected = state.selectedObfuscationPort.hasValue(port), + isEnabled = state.selectObfuscationPortEnabled, + onCellClicked = { + onObfuscationPortSelected(Constraint.Only(Port(port))) + }, + testTag = + String.format( + null, + LAZY_LIST_UDP_OVER_TCP_PORT_ITEM_X_TEST_TAG, + port + ) + ) + } + } + } + + itemWithDivider { Spacer(modifier = Modifier.height(Dimens.cellLabelVerticalPadding)) InformationComposeCell( title = stringResource(R.string.quantum_resistant_title), diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VpnSettingsUiState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VpnSettingsUiState.kt index dd9802db2c..17eb69d380 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VpnSettingsUiState.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VpnSettingsUiState.kt @@ -17,12 +17,14 @@ data class VpnSettingsUiState( val customDnsItems: List<CustomDnsItem>, val contentBlockersOptions: DefaultDnsOptions, val selectedObfuscation: SelectedObfuscation, + val selectedObfuscationPort: Constraint<Port>, val quantumResistant: QuantumResistantState, val selectedWireguardPort: Constraint<Port>, val customWireguardPort: Constraint<Port>?, val availablePortRanges: List<PortRange>, val systemVpnSettingsAvailable: Boolean, ) { + val selectObfuscationPortEnabled = selectedObfuscation != SelectedObfuscation.Off companion object { fun createDefault( @@ -33,6 +35,7 @@ data class VpnSettingsUiState( customDnsItems: List<CustomDnsItem> = emptyList(), contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions(), selectedObfuscation: SelectedObfuscation = SelectedObfuscation.Off, + selectedObfuscationPort: Constraint<Port> = Constraint.Any, quantumResistant: QuantumResistantState = QuantumResistantState.Off, selectedWireguardPort: Constraint<Port> = Constraint.Any, customWireguardPort: Constraint.Only<Port>? = null, @@ -47,6 +50,7 @@ data class VpnSettingsUiState( customDnsItems, contentBlockersOptions, selectedObfuscation, + selectedObfuscationPort, quantumResistant, selectedWireguardPort, customWireguardPort, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/test/ComposeTestTagConstants.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/test/ComposeTestTagConstants.kt index 8ebdaede33..0111fc7a46 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/test/ComposeTestTagConstants.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/test/ComposeTestTagConstants.kt @@ -9,11 +9,15 @@ const val LAZY_LIST_TEST_TAG = "lazy_list_test_tag" const val LAZY_LIST_LAST_ITEM_TEST_TAG = "lazy_list_last_item_test_tag" const val LAZY_LIST_QUANTUM_ITEM_OFF_TEST_TAG = "lazy_list_quantum_item_off_test_tag" const val LAZY_LIST_QUANTUM_ITEM_ON_TEST_TAG = "lazy_list_quantum_item_on_test_tag" -const val LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG = "lazy_list_quantum_item_%d_test_tag" +const val LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG = "lazy_list_wireguard_item_%d_test_tag" const val LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG = "lazy_list_wireguard_custom_port_text_test_tag" const val LAZY_LIST_WIREGUARD_CUSTOM_PORT_NUMBER_TEST_TAG = "lazy_list_wireguard_custom_port_number_test_tag" +const val LAZY_LIST_UDP_OVER_TCP_PORT_TEST_TAG = "lazy_list_udp_over_tcp_port_test_tag" +const val LAZY_LIST_UDP_OVER_TCP_PORT_ITEM_AUTOMATIC_TEST_TAG = + "lazy_list_udp_over_tcp_item_automatic_test_tag" +const val LAZY_LIST_UDP_OVER_TCP_PORT_ITEM_X_TEST_TAG = "lazy_list_udp_over_tcp_item_%d_test_tag" const val CUSTOM_PORT_DIALOG_INPUT_TEST_TAG = "custom_port_dialog_input_test_tag" // SelectLocationScreen, ConnectScreen, CustomListLocationsScreen diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/WireguardConstant.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/WireguardConstant.kt index b4ed1e29a9..6f6cb5a79b 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/WireguardConstant.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/constant/WireguardConstant.kt @@ -1,3 +1,4 @@ package net.mullvad.mullvadvpn.constant val WIREGUARD_PRESET_PORTS = listOf(51820, 53) +val UDP2TCP_PRESET_PORTS = listOf(80, 5001) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/SettingsRepository.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/SettingsRepository.kt index b721442197..7a9be0303a 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/SettingsRepository.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/SettingsRepository.kt @@ -8,13 +8,15 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.stateIn import net.mullvad.mullvadvpn.lib.daemon.grpc.ManagementService +import net.mullvad.mullvadvpn.lib.model.Constraint import net.mullvad.mullvadvpn.lib.model.CustomDnsOptions import net.mullvad.mullvadvpn.lib.model.DefaultDnsOptions import net.mullvad.mullvadvpn.lib.model.DnsOptions import net.mullvad.mullvadvpn.lib.model.DnsState import net.mullvad.mullvadvpn.lib.model.Mtu -import net.mullvad.mullvadvpn.lib.model.ObfuscationSettings +import net.mullvad.mullvadvpn.lib.model.Port import net.mullvad.mullvadvpn.lib.model.QuantumResistantState +import net.mullvad.mullvadvpn.lib.model.SelectedObfuscation import net.mullvad.mullvadvpn.lib.model.Settings class SettingsRepository( @@ -52,6 +54,9 @@ class SettingsRepository( suspend fun addCustomDns(address: InetAddress) = managementService.addCustomDns(address) + suspend fun setCustomObfuscationPort(constraint: Constraint<Port>) = + managementService.setObfuscationPort(constraint) + suspend fun setWireguardMtu(mtu: Mtu) = managementService.setWireguardMtu(mtu.value) suspend fun resetWireguardMtu() = managementService.resetWireguardMtu() @@ -59,8 +64,7 @@ class SettingsRepository( suspend fun setWireguardQuantumResistant(value: QuantumResistantState) = managementService.setWireguardQuantumResistant(value) - suspend fun setObfuscationOptions(value: ObfuscationSettings) = - managementService.setObfuscationOptions(value) + suspend fun setObfuscation(value: SelectedObfuscation) = managementService.setObfuscation(value) suspend fun setAutoConnect(isEnabled: Boolean) = managementService.setAutoConnect(isEnabled) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt index 864d402fb3..a0a38ef6f8 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt @@ -22,12 +22,10 @@ import net.mullvad.mullvadvpn.compose.state.VpnSettingsUiState import net.mullvad.mullvadvpn.lib.model.Constraint import net.mullvad.mullvadvpn.lib.model.DefaultDnsOptions import net.mullvad.mullvadvpn.lib.model.DnsState -import net.mullvad.mullvadvpn.lib.model.ObfuscationSettings import net.mullvad.mullvadvpn.lib.model.Port import net.mullvad.mullvadvpn.lib.model.QuantumResistantState import net.mullvad.mullvadvpn.lib.model.SelectedObfuscation import net.mullvad.mullvadvpn.lib.model.Settings -import net.mullvad.mullvadvpn.lib.model.Udp2TcpObfuscationSettings import net.mullvad.mullvadvpn.lib.model.WireguardConstraints import net.mullvad.mullvadvpn.repository.RelayListRepository import net.mullvad.mullvadvpn.repository.SettingsRepository @@ -57,10 +55,11 @@ class VpnSettingsViewModel( private val customPort = MutableStateFlow<Constraint<Port>?>(null) private val vmState = - combine(repository.settingsUpdates, relayListRepository.portRanges, customPort) { - settings, - portRanges, - customWgPort -> + combine( + repository.settingsUpdates, + relayListRepository.portRanges, + customPort, + ) { settings, portRanges, customWgPort -> VpnSettingsViewModelState( mtuValue = settings?.tunnelOptions?.wireguard?.mtu, isAutoConnectEnabled = settings?.autoConnect ?: false, @@ -71,6 +70,8 @@ class VpnSettingsViewModel( settings?.contentBlockersSettings() ?: DefaultDnsOptions(), selectedObfuscation = settings?.selectedObfuscationSettings() ?: SelectedObfuscation.Off, + selectedObfuscationPort = + settings?.obfuscationSettings?.udp2tcp?.port ?: Constraint.Any, quantumResistant = settings?.quantumResistant() ?: QuantumResistantState.Off, selectedWireguardPort = settings?.getWireguardPort() ?: Constraint.Any, customWireguardPort = customWgPort, @@ -203,17 +204,16 @@ class VpnSettingsViewModel( fun onSelectObfuscationSetting(selectedObfuscation: SelectedObfuscation) { viewModelScope.launch(dispatcher) { - repository - .setObfuscationOptions( - ObfuscationSettings( - selectedObfuscation = selectedObfuscation, - udp2tcp = Udp2TcpObfuscationSettings(Constraint.Any) - ) - ) - .onLeft { _uiSideEffect.send(VpnSettingsSideEffect.ShowToast.GenericError) } + repository.setObfuscation(selectedObfuscation).onLeft { + _uiSideEffect.send(VpnSettingsSideEffect.ShowToast.GenericError) + } } } + fun onObfuscationPortSelected(port: Constraint<Port>) { + viewModelScope.launch { repository.setCustomObfuscationPort(port) } + } + fun onSelectQuantumResistanceSetting(quantumResistant: QuantumResistantState) { viewModelScope.launch(dispatcher) { repository.setWireguardQuantumResistant(quantumResistant).onLeft { diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelState.kt index f8e4f0b799..d8be8d1cf2 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelState.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelState.kt @@ -17,6 +17,7 @@ data class VpnSettingsViewModelState( val customDnsList: List<CustomDnsItem>, val contentBlockersOptions: DefaultDnsOptions, val selectedObfuscation: SelectedObfuscation, + val selectedObfuscationPort: Constraint<Port>, val quantumResistant: QuantumResistantState, val selectedWireguardPort: Constraint<Port>, val customWireguardPort: Constraint<Port>?, @@ -32,6 +33,7 @@ data class VpnSettingsViewModelState( customDnsList, contentBlockersOptions, selectedObfuscation, + selectedObfuscationPort, quantumResistant, selectedWireguardPort, customWireguardPort, @@ -49,6 +51,7 @@ data class VpnSettingsViewModelState( customDnsList = listOf(), contentBlockersOptions = DefaultDnsOptions(), selectedObfuscation = SelectedObfuscation.Auto, + selectedObfuscationPort = Constraint.Any, quantumResistant = QuantumResistantState.Off, selectedWireguardPort = Constraint.Any, customWireguardPort = null, diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt index 29a6c764ba..a62b5d4bb3 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt @@ -67,6 +67,19 @@ class VpnSettingsViewModelTest { } @Test + fun `onSelectCustomTcpOverUdpPort should invoke setCustomObfuscationPort on SettingsRepository`() = + runTest { + val customPort = Port(5001) + coEvery { + mockSettingsRepository.setCustomObfuscationPort(Constraint.Only(customPort)) + } returns Unit.right() + viewModel.onObfuscationPortSelected(Constraint.Only(customPort)) + coVerify(exactly = 1) { + mockSettingsRepository.setCustomObfuscationPort(Constraint.Only(customPort)) + } + } + + @Test fun `onSelectQuantumResistanceSetting should invoke setWireguardQuantumResistant on SettingsRepository`() = runTest { val quantumResistantState = QuantumResistantState.On |
