summaryrefslogtreecommitdiffhomepage
path: root/android/app
diff options
context:
space:
mode:
authorAlbin <albin@mullvad.net>2023-05-03 12:39:33 +0200
committerAlbin <albin@mullvad.net>2023-05-03 12:39:33 +0200
commitb8091d32497d52171ffc3888094d52856d96b194 (patch)
tree94160245ab983a95b13b132c436e0c4c71fd6b70 /android/app
parent49ea114adddba1a1db6ffc6c440e743c01797a47 (diff)
parent94076888b5af1eb389035a5c67397940aa6c907d (diff)
downloadmullvadvpn-b8091d32497d52171ffc3888094d52856d96b194.tar.xz
mullvadvpn-b8091d32497d52171ffc3888094d52856d96b194.zip
Merge branch 'dns-settings-text-additions-droid-123'
Diffstat (limited to 'android/app')
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingsScreenTest.kt130
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ContentBlockersInfoDialog.kt8
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/CustomDnsInfoDialog.kt13
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/InfoDialog.kt16
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingScreen.kt37
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/AdvancedSettingsUiState.kt8
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt8
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AdvancedFragment.kt4
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModel.kt26
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModelState.kt10
-rw-r--r--android/app/src/main/res/values/strings.xml2
11 files changed, 191 insertions, 71 deletions
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingsScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingsScreenTest.kt
index 1aaf119773..340b903886 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingsScreenTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingsScreenTest.kt
@@ -12,6 +12,8 @@ import io.mockk.MockKAnnotations
import io.mockk.mockk
import io.mockk.verify
import io.mockk.verifyAll
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
import net.mullvad.mullvadvpn.compose.state.AdvancedSettingsUiState
import net.mullvad.mullvadvpn.viewmodel.CustomDnsItem
import net.mullvad.mullvadvpn.viewmodel.StagedDns
@@ -32,7 +34,10 @@ class AdvancedSettingsScreenTest {
fun testDefaultState() {
// Arrange
composeTestRule.setContent {
- AdvancedSettingScreen(uiState = AdvancedSettingsUiState.DefaultUiState())
+ AdvancedSettingScreen(
+ uiState = AdvancedSettingsUiState.DefaultUiState(),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
+ )
}
// Assert
@@ -51,7 +56,8 @@ class AdvancedSettingsScreenTest {
// Arrange
composeTestRule.setContent {
AdvancedSettingScreen(
- uiState = AdvancedSettingsUiState.DefaultUiState(mtu = VALID_DUMMY_MTU_VALUE)
+ uiState = AdvancedSettingsUiState.DefaultUiState(mtu = VALID_DUMMY_MTU_VALUE),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -67,7 +73,8 @@ class AdvancedSettingsScreenTest {
composeTestRule.setContent {
AdvancedSettingScreen(
uiState = AdvancedSettingsUiState.DefaultUiState(),
- onMtuCellClick = mockedClickHandler
+ onMtuCellClick = mockedClickHandler,
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -84,7 +91,8 @@ class AdvancedSettingsScreenTest {
// Arrange
composeTestRule.setContent {
AdvancedSettingScreen(
- uiState = AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = EMPTY_STRING)
+ uiState = AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = EMPTY_STRING),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -99,7 +107,8 @@ class AdvancedSettingsScreenTest {
composeTestRule.setContent {
AdvancedSettingScreen(
uiState =
- AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = VALID_DUMMY_MTU_VALUE)
+ AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = VALID_DUMMY_MTU_VALUE),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -115,7 +124,8 @@ class AdvancedSettingsScreenTest {
composeTestRule.setContent {
AdvancedSettingScreen(
uiState = AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = EMPTY_STRING),
- onMtuInputChange = mockedInputHandler
+ onMtuInputChange = mockedInputHandler,
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -135,7 +145,8 @@ class AdvancedSettingsScreenTest {
AdvancedSettingScreen(
uiState =
AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = VALID_DUMMY_MTU_VALUE),
- onSaveMtuClick = mockedSubmitHandler
+ onSaveMtuClick = mockedSubmitHandler,
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -153,7 +164,10 @@ class AdvancedSettingsScreenTest {
composeTestRule.setContent {
AdvancedSettingScreen(
uiState =
- AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = INVALID_DUMMY_MTU_VALUE)
+ AdvancedSettingsUiState.MtuDialogUiState(
+ mtuEditValue = INVALID_DUMMY_MTU_VALUE
+ ),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -169,7 +183,8 @@ class AdvancedSettingsScreenTest {
composeTestRule.setContent {
AdvancedSettingScreen(
uiState = AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = EMPTY_STRING),
- onRestoreMtuClick = mockedClickHandler
+ onRestoreMtuClick = mockedClickHandler,
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -188,7 +203,8 @@ class AdvancedSettingsScreenTest {
composeTestRule.setContent {
AdvancedSettingScreen(
uiState = AdvancedSettingsUiState.MtuDialogUiState(mtuEditValue = EMPTY_STRING),
- onCancelMtuDialogClicked = mockedClickHandler
+ onCancelMtuDialogClicked = mockedClickHandler,
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -207,7 +223,8 @@ class AdvancedSettingsScreenTest {
composeTestRule.setContent {
AdvancedSettingScreen(
uiState = AdvancedSettingsUiState.DefaultUiState(),
- onSplitTunnelingNavigationClick = mockedClickHandler
+ onSplitTunnelingNavigationClick = mockedClickHandler,
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -232,9 +249,10 @@ class AdvancedSettingsScreenTest {
listOf(
CustomDnsItem(address = DUMMY_DNS_ADDRESS, false),
CustomDnsItem(address = DUMMY_DNS_ADDRESS_2, false),
- CustomDnsItem(address = DUMMY_DNS_ADDRESS_3, false)
- )
- )
+ CustomDnsItem(address = DUMMY_DNS_ADDRESS_3, false),
+ ),
+ ),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -256,8 +274,9 @@ class AdvancedSettingsScreenTest {
uiState =
AdvancedSettingsUiState.DefaultUiState(
isCustomDnsEnabled = false,
- customDnsItems = listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, false))
- )
+ customDnsItems = listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, false)),
+ ),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -277,8 +296,9 @@ class AdvancedSettingsScreenTest {
isCustomDnsEnabled = true,
isAllowLanEnabled = true,
customDnsItems =
- listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = true))
- )
+ listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = true)),
+ ),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -297,8 +317,9 @@ class AdvancedSettingsScreenTest {
isCustomDnsEnabled = true,
isAllowLanEnabled = false,
customDnsItems =
- listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = false))
- )
+ listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = false)),
+ ),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -317,8 +338,9 @@ class AdvancedSettingsScreenTest {
isCustomDnsEnabled = true,
isAllowLanEnabled = true,
customDnsItems =
- listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = false))
- )
+ listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = false)),
+ ),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -337,8 +359,9 @@ class AdvancedSettingsScreenTest {
isCustomDnsEnabled = true,
isAllowLanEnabled = false,
customDnsItems =
- listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = true))
- )
+ listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = true)),
+ ),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -356,7 +379,8 @@ class AdvancedSettingsScreenTest {
composeTestRule.setContent {
AdvancedSettingScreen(
uiState = AdvancedSettingsUiState.DefaultUiState(isCustomDnsEnabled = true),
- onDnsClick = mockedClickHandler
+ onDnsClick = mockedClickHandler,
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -377,9 +401,10 @@ class AdvancedSettingsScreenTest {
AdvancedSettingsUiState.DnsDialogUiState(
stagedDns =
StagedDns.NewDns(
- item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false)
- )
- )
+ item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false),
+ ),
+ ),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -398,9 +423,10 @@ class AdvancedSettingsScreenTest {
stagedDns =
StagedDns.EditDns(
item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false),
- index = 0
- )
- )
+ index = 0,
+ ),
+ ),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -419,10 +445,11 @@ class AdvancedSettingsScreenTest {
stagedDns =
StagedDns.NewDns(
item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = true),
- validationResult = StagedDns.ValidationResult.Success
+ validationResult = StagedDns.ValidationResult.Success,
),
- isAllowLanEnabled = false
- )
+ isAllowLanEnabled = false,
+ ),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -441,10 +468,11 @@ class AdvancedSettingsScreenTest {
stagedDns =
StagedDns.NewDns(
item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = true),
- validationResult = StagedDns.ValidationResult.Success
+ validationResult = StagedDns.ValidationResult.Success,
),
- isAllowLanEnabled = true
- )
+ isAllowLanEnabled = true,
+ ),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -463,10 +491,11 @@ class AdvancedSettingsScreenTest {
stagedDns =
StagedDns.NewDns(
item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false),
- validationResult = StagedDns.ValidationResult.Success
+ validationResult = StagedDns.ValidationResult.Success,
),
- isAllowLanEnabled = true
- )
+ isAllowLanEnabled = true,
+ ),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -485,10 +514,11 @@ class AdvancedSettingsScreenTest {
stagedDns =
StagedDns.NewDns(
item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false),
- validationResult = StagedDns.ValidationResult.Success
+ validationResult = StagedDns.ValidationResult.Success,
),
- isAllowLanEnabled = false
- )
+ isAllowLanEnabled = false,
+ ),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -507,9 +537,10 @@ class AdvancedSettingsScreenTest {
stagedDns =
StagedDns.NewDns(
item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false),
- validationResult = StagedDns.ValidationResult.InvalidAddress
- )
- )
+ validationResult = StagedDns.ValidationResult.InvalidAddress,
+ ),
+ ),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -528,9 +559,10 @@ class AdvancedSettingsScreenTest {
stagedDns =
StagedDns.NewDns(
item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false),
- validationResult = StagedDns.ValidationResult.DuplicateAddress
- )
- )
+ validationResult = StagedDns.ValidationResult.DuplicateAddress,
+ ),
+ ),
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ContentBlockersInfoDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ContentBlockersInfoDialog.kt
index 8dde91d091..29a57ed331 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ContentBlockersInfoDialog.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ContentBlockersInfoDialog.kt
@@ -13,7 +13,13 @@ fun ContentBlockersInfoDialog(onDismiss: () -> Unit) {
appendLine(stringResource(id = R.string.dns_content_blockers_info))
append(stringResource(id = R.string.dns_content_blockers_warning))
},
- additionalInfo = textResource(id = R.string.dns_content_blockers_custom_dns_warning),
+ additionalInfo =
+ buildString {
+ appendLine(textResource(id = R.string.dns_content_blockers_custom_dns_warning))
+ appendLine(
+ stringResource(id = R.string.settings_changes_effect_warning_content_blocker)
+ )
+ },
onDismiss = onDismiss
)
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/CustomDnsInfoDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/CustomDnsInfoDialog.kt
new file mode 100644
index 0000000000..ce3a325780
--- /dev/null
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/CustomDnsInfoDialog.kt
@@ -0,0 +1,13 @@
+package net.mullvad.mullvadvpn.compose.dialog
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.stringResource
+import net.mullvad.mullvadvpn.R
+
+@Composable
+fun CustomDnsInfoDialog(onDismiss: () -> Unit) {
+ InfoDialog(
+ message = stringResource(id = R.string.settings_changes_effect_warning_content_blocker),
+ onDismiss = onDismiss
+ )
+}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/InfoDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/InfoDialog.kt
index ddc60ad566..b7a6e4ba0d 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/InfoDialog.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/InfoDialog.kt
@@ -37,11 +37,7 @@ private fun PreviewChangelogDialogWithTwoLongItems() {
"The purpose of this specific sample text is to visualize a long text that will " +
"result in multiple lines in the changelog dialog."
- InfoDialog(
- message = longPreviewText,
- additionalInfo = longPreviewText,
- onDismiss = {},
- )
+ InfoDialog(message = longPreviewText, additionalInfo = longPreviewText, onDismiss = {})
}
@Composable
@@ -55,13 +51,13 @@ fun InfoDialog(message: String, additionalInfo: String? = null, onDismiss: () ->
modifier = Modifier.fillMaxWidth().height(iconHeight),
painter = painterResource(id = R.drawable.icon_info),
contentDescription = "",
- tint = MullvadWhite,
+ tint = MullvadWhite
)
},
text = {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
- modifier = Modifier.padding(top = verticalSpacing),
+ modifier = Modifier.padding(top = verticalSpacing)
) {
Text(
text = message,
@@ -91,9 +87,9 @@ fun InfoDialog(message: String, additionalInfo: String? = null, onDismiss: () ->
colors =
ButtonDefaults.buttonColors(
backgroundColor = colorResource(id = R.color.blue),
- contentColor = colorResource(id = R.color.white),
+ contentColor = colorResource(id = R.color.white)
),
- onClick = { onDismiss() },
+ onClick = { onDismiss() }
) {
Text(
text = stringResource(R.string.changes_dialog_dismiss_button),
@@ -106,6 +102,6 @@ fun InfoDialog(message: String, additionalInfo: String? = null, onDismiss: () ->
dismissOnClickOutside = true,
dismissOnBackPress = true,
),
- backgroundColor = colorResource(id = R.color.darkBlue),
+ backgroundColor = colorResource(id = R.color.darkBlue)
)
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingScreen.kt
index 92c58f1f77..bfe0088136 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AdvancedSettingScreen.kt
@@ -1,5 +1,6 @@
package net.mullvad.mullvadvpn.compose.screen
+import android.widget.Toast
import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
@@ -17,6 +18,7 @@ import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
@@ -24,6 +26,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.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
@@ -32,6 +35,9 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
import me.onebone.toolbar.ScrollStrategy
import me.onebone.toolbar.rememberCollapsingToolbarScaffoldState
import net.mullvad.mullvadvpn.R
@@ -47,6 +53,7 @@ import net.mullvad.mullvadvpn.compose.component.CollapsableAwareToolbarScaffold
import net.mullvad.mullvadvpn.compose.component.CollapsingTopBar
import net.mullvad.mullvadvpn.compose.component.drawVerticalScrollbar
import net.mullvad.mullvadvpn.compose.dialog.ContentBlockersInfoDialog
+import net.mullvad.mullvadvpn.compose.dialog.CustomDnsInfoDialog
import net.mullvad.mullvadvpn.compose.dialog.DnsDialog
import net.mullvad.mullvadvpn.compose.dialog.MalwareInfoDialog
import net.mullvad.mullvadvpn.compose.dialog.MtuDialog
@@ -65,7 +72,7 @@ private fun PreviewAdvancedSettings() {
AdvancedSettingsUiState.DefaultUiState(
mtu = "1337",
isCustomDnsEnabled = true,
- customDnsItems = listOf(CustomDnsItem("0.0.0.0", false))
+ customDnsItems = listOf(CustomDnsItem("0.0.0.0", false)),
),
onMtuCellClick = {},
onMtuInputChange = {},
@@ -86,8 +93,10 @@ private fun PreviewAdvancedSettings() {
onCancelDnsDialogClick = {},
onContentsBlockersInfoClicked = {},
onMalwareInfoClicked = {},
+ onCustomDnsInfoClicked = {},
onDismissInfoClicked = {},
- onBackClick = {}
+ onBackClick = {},
+ toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow()
)
}
@@ -116,9 +125,11 @@ fun AdvancedSettingScreen(
onCancelDnsDialogClick: () -> Unit = {},
onContentsBlockersInfoClicked: () -> Unit = {},
onMalwareInfoClicked: () -> Unit = {},
+ onCustomDnsInfoClicked: () -> Unit = {},
onDismissInfoClicked: () -> Unit = {},
onBackClick: () -> Unit = {},
- onStopEvent: () -> Unit = {}
+ onStopEvent: () -> Unit = {},
+ toastMessagesSharedFlow: SharedFlow<String>
) {
val cellVerticalSpacing = dimensionResource(id = R.dimen.cell_label_vertical_padding)
val cellHorizontalSpacing = dimensionResource(id = R.dimen.cell_left_padding)
@@ -146,6 +157,9 @@ fun AdvancedSettingScreen(
is AdvancedSettingsUiState.ContentBlockersInfoDialogUiState -> {
ContentBlockersInfoDialog(onDismissInfoClicked)
}
+ is AdvancedSettingsUiState.CustomDnsInfoDialogUiState -> {
+ CustomDnsInfoDialog(onDismissInfoClicked)
+ }
is AdvancedSettingsUiState.MalwareInfoDialogUiState -> {
MalwareInfoDialog(onDismissInfoClicked)
}
@@ -181,8 +195,14 @@ fun AdvancedSettingScreen(
modifier = scaffoldModifier,
backTitle = stringResource(id = R.string.settings)
)
- }
+ },
) {
+ val context = LocalContext.current
+ LaunchedEffect(Unit) {
+ toastMessagesSharedFlow.collect { message ->
+ Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
+ }
+ }
DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_STOP) {
@@ -275,7 +295,7 @@ fun AdvancedSettingScreen(
start = cellHorizontalSpacing,
top = topPadding,
end = cellHorizontalSpacing,
- bottom = cellVerticalSpacing,
+ bottom = cellVerticalSpacing
)
)
}
@@ -288,7 +308,8 @@ fun AdvancedSettingScreen(
title = stringResource(R.string.enable_custom_dns),
isToggled = uiState.isCustomDnsEnabled,
isEnabled = uiState.contentBlockersOptions.isAnyBlockerEnabled().not(),
- onCellClicked = { newValue -> onToggleDnsClick(newValue) }
+ onCellClicked = { newValue -> onToggleDnsClick(newValue) },
+ onInfoClicked = { onCustomDnsInfoClicked() }
)
}
@@ -316,7 +337,7 @@ fun AdvancedSettingScreen(
bodyView = {},
subtitle = null,
background = MullvadBlue20,
- startPadding = biggerPadding
+ startPadding = biggerPadding,
)
}
}
@@ -330,7 +351,7 @@ fun AdvancedSettingScreen(
start = cellHorizontalSpacing,
top = topPadding,
end = cellHorizontalSpacing,
- bottom = cellVerticalSpacing
+ bottom = cellVerticalSpacing,
)
)
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/AdvancedSettingsUiState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/AdvancedSettingsUiState.kt
index 71b608b51b..feaa8e0824 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/AdvancedSettingsUiState.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/AdvancedSettingsUiState.kt
@@ -45,6 +45,14 @@ sealed interface AdvancedSettingsUiState {
override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions()
) : AdvancedSettingsUiState
+ data class CustomDnsInfoDialogUiState(
+ override val mtu: String = "",
+ override val isCustomDnsEnabled: Boolean = false,
+ override val isAllowLanEnabled: Boolean = false,
+ override val customDnsItems: List<CustomDnsItem> = listOf(),
+ override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions()
+ ) : AdvancedSettingsUiState
+
data class MalwareInfoDialogUiState(
override val mtu: String = "",
override val isCustomDnsEnabled: Boolean = false,
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt
index 8427ae0773..1d1f02138e 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt
@@ -88,7 +88,13 @@ val uiModule = module {
ChangelogViewModel(get(), BuildConfig.VERSION_CODE, BuildConfig.ALWAYS_SHOW_CHANGELOG)
}
viewModel { PrivacyDisclaimerViewModel(get()) }
- viewModel { AdvancedSettingsViewModel(repository = get(), inetAddressValidator = get()) }
+ viewModel {
+ AdvancedSettingsViewModel(
+ get(),
+ get(),
+ get(),
+ )
+ }
}
const val APPS_SCOPE = "APPS_SCOPE"
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AdvancedFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AdvancedFragment.kt
index 62661b0455..5e9be88387 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AdvancedFragment.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/AdvancedFragment.kt
@@ -46,10 +46,12 @@ class AdvancedFragment : BaseFragment() {
onRemoveDnsClick = vm::onRemoveDnsClick,
onCancelDnsDialogClick = vm::onCancelDialogClick,
onContentsBlockersInfoClicked = vm::onContentsBlockerInfoClick,
+ onCustomDnsInfoClicked = vm::onCustomDnsInfoClick,
onMalwareInfoClicked = vm::onMalwareInfoClick,
onDismissInfoClicked = vm::onDismissInfoClick,
onBackClick = { activity?.onBackPressed() },
- onStopEvent = vm::onStopEvent
+ onStopEvent = vm::onStopEvent,
+ toastMessagesSharedFlow = vm.toastMessages
)
}
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModel.kt
index 540ed235ce..89f2df1399 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModel.kt
@@ -1,18 +1,22 @@
package net.mullvad.mullvadvpn.viewmodel
+import android.content.res.Resources
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import java.net.InetAddress
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
+import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.state.AdvancedSettingsUiState
import net.mullvad.mullvadvpn.model.DefaultDnsOptions
import net.mullvad.mullvadvpn.model.DnsState
@@ -24,9 +28,13 @@ import org.apache.commons.validator.routines.InetAddressValidator
class AdvancedSettingsViewModel(
private val repository: SettingsRepository,
private val inetAddressValidator: InetAddressValidator,
+ private val resources: Resources,
private val dispatcher: CoroutineDispatcher = Dispatchers.IO
) : ViewModel() {
+ private val _toastMessages = MutableSharedFlow<String>(extraBufferCapacity = 1)
+ val toastMessages = _toastMessages.asSharedFlow()
+
private val dialogState =
MutableStateFlow<AdvancedSettingsDialogState>(AdvancedSettingsDialogState.NoDialog)
@@ -90,6 +98,10 @@ class AdvancedSettingsViewModel(
dialogState.update { AdvancedSettingsDialogState.ContentBlockersInfoDialog }
}
+ fun onCustomDnsInfoClick() {
+ dialogState.update { AdvancedSettingsDialogState.CustomDnsInfoDialog }
+ }
+
fun onMalwareInfoClick() {
dialogState.update { AdvancedSettingsDialogState.MalwareInfoDialog }
}
@@ -192,36 +204,44 @@ class AdvancedSettingsViewModel(
hideDialog()
}
- fun onToggleDnsClick(isEnabled: Boolean) = updateCustomDnsState(isEnabled)
+ fun onToggleDnsClick(isEnabled: Boolean) {
+ updateCustomDnsState(isEnabled)
+ showApplySettingChangesWarningToast()
+ }
fun onToggleBlockAds(isEnabled: Boolean) {
updateDefaultDnsOptionsViaRepository(
vmState.value.contentBlockersOptions.copy(blockAds = isEnabled)
)
+ showApplySettingChangesWarningToast()
}
fun onToggleBlockTrackers(isEnabled: Boolean) {
updateDefaultDnsOptionsViaRepository(
vmState.value.contentBlockersOptions.copy(blockTrackers = isEnabled)
)
+ showApplySettingChangesWarningToast()
}
fun onToggleBlockMalware(isEnabled: Boolean) {
updateDefaultDnsOptionsViaRepository(
vmState.value.contentBlockersOptions.copy(blockMalware = isEnabled)
)
+ showApplySettingChangesWarningToast()
}
fun onToggleBlockAdultContent(isEnabled: Boolean) {
updateDefaultDnsOptionsViaRepository(
vmState.value.contentBlockersOptions.copy(blockAdultContent = isEnabled)
)
+ showApplySettingChangesWarningToast()
}
fun onToggleBlockGambling(isEnabled: Boolean) {
updateDefaultDnsOptionsViaRepository(
vmState.value.contentBlockersOptions.copy(blockGambling = isEnabled)
)
+ showApplySettingChangesWarningToast()
}
fun onRemoveDnsClick() =
@@ -314,6 +334,10 @@ class AdvancedSettingsViewModel(
}
}
+ private fun showApplySettingChangesWarningToast() {
+ _toastMessages.tryEmit(resources.getString(R.string.settings_changes_effect_warning_short))
+ }
+
companion object {
private const val EMPTY_STRING = ""
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModelState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModelState.kt
index 109e518ad5..fddcdfb5b7 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModelState.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/AdvancedSettingsViewModelState.kt
@@ -39,6 +39,14 @@ data class AdvancedSettingsViewModelState(
customDnsItems = customDnsList,
contentBlockersOptions = contentBlockersOptions
)
+ is AdvancedSettingsDialogState.CustomDnsInfoDialog ->
+ AdvancedSettingsUiState.CustomDnsInfoDialogUiState(
+ mtu = mtuValue,
+ isCustomDnsEnabled = isCustomDnsEnabled,
+ isAllowLanEnabled = isAllowLanEnabled,
+ customDnsItems = customDnsList,
+ contentBlockersOptions = contentBlockersOptions
+ )
is AdvancedSettingsDialogState.MalwareInfoDialog ->
AdvancedSettingsUiState.MalwareInfoDialogUiState(
mtu = mtuValue,
@@ -82,6 +90,8 @@ sealed class AdvancedSettingsDialogState {
object ContentBlockersInfoDialog : AdvancedSettingsDialogState()
+ object CustomDnsInfoDialog : AdvancedSettingsDialogState()
+
object MalwareInfoDialog : AdvancedSettingsDialogState()
}
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 6b1bdaac30..b0431964e2 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -184,4 +184,6 @@
<string name="custom_dns_disable_mode_subtitle">
<![CDATA[Disable all <b>DNS content blockers</b> above to activate this setting.]]>
</string>
+ <string name="settings_changes_effect_warning_short">DNS settings might not go into effect immediately</string>
+ <string name="settings_changes_effect_warning_content_blocker">Changes to DNS related settings might not go into effect immediately due to cached results.</string>
</resources>