diff options
| author | Albin <albin@mullvad.net> | 2023-04-11 11:20:38 +0200 |
|---|---|---|
| committer | Albin <albin@mullvad.net> | 2023-04-11 11:20:38 +0200 |
| commit | 50a474c5be424577b674d9ac927abc5494503a9f (patch) | |
| tree | a465bb3184fe8d84a259990b42b257f7932d65e6 /android | |
| parent | 2cc9013dfe0b5336d7b7c3146a5c8702e3007477 (diff) | |
| parent | 60cd3692c6215b4e215739d4af9e17249e941397 (diff) | |
| download | mullvadvpn-50a474c5be424577b674d9ac927abc5494503a9f.tar.xz mullvadvpn-50a474c5be424577b674d9ac927abc5494503a9f.zip | |
Merge branch 'add-dns-content-blockers-droid-10'
Diffstat (limited to 'android')
40 files changed, 982 insertions, 119 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/BaseCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/BaseCell.kt index e07a34bef1..bab992bcc1 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/BaseCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/BaseCell.kt @@ -26,6 +26,7 @@ fun BaseCell( title: @Composable () -> Unit, bodyView: @Composable () -> Unit, modifier: Modifier = Modifier, + isRowEnabled: Boolean = true, onCellClicked: () -> Unit = {}, subtitle: @Composable (() -> Unit)? = null, subtitleModifier: Modifier = Modifier, @@ -38,13 +39,19 @@ fun BaseCell( val subtitleVerticalSpacing = dimensionResource(id = R.dimen.cell_footer_top_padding) Column(modifier = Modifier.fillMaxWidth().wrapContentHeight().background(background)) { + val rowModifier = + Modifier.let { + if (isRowEnabled) { + it.clickable { onCellClicked() } + } else it + } Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Start, modifier = - Modifier.height(cellHeight) + rowModifier + .height(cellHeight) .fillMaxWidth() - .clickable { onCellClicked.invoke() } .padding(start = startPadding, end = endPadding) ) { title() diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CustomDnsComposeCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CustomDnsComposeCell.kt deleted file mode 100644 index 3ed13f812f..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CustomDnsComposeCell.kt +++ /dev/null @@ -1,76 +0,0 @@ -package net.mullvad.mullvadvpn.compose.cell - -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.foundation.layout.wrapContentWidth -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.sp -import net.mullvad.mullvadvpn.R -import net.mullvad.mullvadvpn.compose.component.CellSwitch -import net.mullvad.mullvadvpn.compose.theme.MullvadWhite -import net.mullvad.mullvadvpn.compose.theme.MullvadWhite60 - -@Preview -@Composable -private fun PreviewDnsComposeCell() { - CustomDnsComposeCell(checkboxDefaultState = true, onToggle = {}) -} - -@Composable -fun CustomDnsComposeCell(checkboxDefaultState: Boolean, onToggle: (Boolean) -> Unit) { - val titleModifier = Modifier - val bodyViewModifier = Modifier - val subtitleModifier = Modifier - - BaseCell( - title = { CustomDnsCellTitle(modifier = titleModifier) }, - bodyView = { - CustomDnsCellView( - switchTriggered = { onToggle(it) }, - isToggled = checkboxDefaultState, - modifier = bodyViewModifier - ) - }, - onCellClicked = { onToggle(!checkboxDefaultState) }, - subtitleModifier = subtitleModifier - ) -} - -@Composable -fun CustomDnsCellTitle(modifier: Modifier) { - val textSize = dimensionResource(id = R.dimen.text_medium_plus).value.sp - Text( - text = stringResource(R.string.enable_custom_dns), - textAlign = TextAlign.Center, - fontWeight = FontWeight.Bold, - fontSize = textSize, - color = MullvadWhite, - modifier = modifier.wrapContentWidth(align = Alignment.End).wrapContentHeight() - ) -} - -@Composable -fun CustomDnsCellView(switchTriggered: (Boolean) -> Unit, isToggled: Boolean, modifier: Modifier) { - Row(modifier = modifier.wrapContentWidth().wrapContentHeight()) { - CellSwitch(isChecked = isToggled, onCheckedChange = null) - } -} - -@Composable -fun CustomDnsCellSubtitle(modifier: Modifier) { - val textSize = dimensionResource(id = R.dimen.text_small).value.sp - Text( - text = stringResource(R.string.custom_dns_footer), - fontSize = textSize, - color = MullvadWhite60, - modifier = modifier - ) -} 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 new file mode 100644 index 0000000000..3a27adf2a9 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ExpandableComposeCell.kt @@ -0,0 +1,111 @@ +package net.mullvad.mullvadvpn.compose.cell + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.material.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import net.mullvad.mullvadvpn.R +import net.mullvad.mullvadvpn.compose.component.ChevronView +import net.mullvad.mullvadvpn.compose.component.HtmlText +import net.mullvad.mullvadvpn.compose.component.textResource +import net.mullvad.mullvadvpn.compose.theme.AlphaActive +import net.mullvad.mullvadvpn.compose.theme.AlphaInactive +import net.mullvad.mullvadvpn.compose.theme.MullvadWhite +import net.mullvad.mullvadvpn.compose.theme.MullvadWhite60 + +@Preview +@Composable +private fun PreviewExpandedEnabledExpandableComposeCell() { + ExpandableComposeCell( + title = "Expandable row title", + isExpanded = true, + isEnabled = true, + onCellClicked = {}, + onInfoClicked = {} + ) +} + +@Composable +fun ExpandableComposeCell( + title: String, + isExpanded: Boolean, + isEnabled: Boolean = true, + onCellClicked: (Boolean) -> Unit = {}, + onInfoClicked: (() -> Unit)? = null +) { + val titleModifier = Modifier.alpha(if (isEnabled) AlphaActive else AlphaInactive) + val bodyViewModifier = Modifier + + BaseCell( + title = { SwitchCellTitle(title = title, modifier = titleModifier) }, + bodyView = { + ExpandableComposeCellBody( + isExpanded = isExpanded, + modifier = bodyViewModifier, + onInfoClicked = onInfoClicked + ) + }, + onCellClicked = { onCellClicked(!isExpanded) } + ) +} + +@Composable +private fun ExpandableComposeCellBody( + isExpanded: Boolean, + modifier: Modifier, + onInfoClicked: (() -> Unit)? = null +) { + val horizontalPadding = dimensionResource(id = R.dimen.medium_padding) + val verticalPadding = 13.dp + Row( + modifier = modifier.wrapContentWidth().wrapContentHeight(), + verticalAlignment = Alignment.CenterVertically + ) { + if (onInfoClicked != null) { + Icon( + modifier = + Modifier.clickable { onInfoClicked() } + .padding( + start = horizontalPadding, + end = horizontalPadding, + top = verticalPadding, + bottom = verticalPadding + ) + .align(Alignment.CenterVertically), + painter = painterResource(id = R.drawable.icon_info), + contentDescription = null, + tint = MullvadWhite + ) + } + + ChevronView(isExpanded) + } +} + +@Composable +fun ContentBlockersDisableModeCellSubtitle(modifier: Modifier) { + val textSize = dimensionResource(id = R.dimen.text_small).value + + HtmlText( + htmlFormattedString = + textResource( + id = R.string.dns_content_blockers_subtitle, + stringResource(id = R.string.enable_custom_dns) + ), + textSize = textSize, + textColor = MullvadWhite60.toArgb(), + modifier = modifier + ) +} 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 new file mode 100644 index 0000000000..e41fed10ad --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SwitchComposeCell.kt @@ -0,0 +1,142 @@ +package net.mullvad.mullvadvpn.compose.cell + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.material.Icon +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import net.mullvad.mullvadvpn.R +import net.mullvad.mullvadvpn.compose.component.CellSwitch +import net.mullvad.mullvadvpn.compose.component.HtmlText +import net.mullvad.mullvadvpn.compose.component.textResource +import net.mullvad.mullvadvpn.compose.theme.AlphaActive +import net.mullvad.mullvadvpn.compose.theme.AlphaInactive +import net.mullvad.mullvadvpn.compose.theme.MullvadBlue +import net.mullvad.mullvadvpn.compose.theme.MullvadWhite +import net.mullvad.mullvadvpn.compose.theme.MullvadWhite60 + +@Preview +@Composable +private fun PreviewSwitchComposeCell() { + SwitchComposeCell( + title = "Checkbox Title", + isEnabled = true, + isToggled = true, + onCellClicked = {}, + onInfoClicked = {} + ) +} + +@Composable +fun SwitchComposeCell( + title: String, + isToggled: Boolean, + isEnabled: Boolean = true, + background: Color = MullvadBlue, + onCellClicked: (Boolean) -> Unit = {}, + onInfoClicked: (() -> Unit)? = null +) { + val alpha = if (isEnabled) AlphaActive else AlphaInactive + val titleModifier = Modifier.alpha(alpha) + val bodyViewModifier = Modifier.alpha(alpha) + val subtitleModifier = Modifier + + BaseCell( + title = { SwitchCellTitle(title = title, modifier = titleModifier) }, + isRowEnabled = isEnabled, + bodyView = { + SwitchCellView( + onSwitchClicked = null, + isEnabled = isEnabled, + isToggled = isToggled, + modifier = bodyViewModifier, + onInfoClicked = onInfoClicked + ) + }, + background = background, + onCellClicked = { onCellClicked(!isToggled) }, + subtitleModifier = subtitleModifier + ) +} + +@Composable +fun SwitchCellTitle(title: String, modifier: Modifier) { + val textSize = dimensionResource(id = R.dimen.text_medium_plus).value.sp + Text( + text = title, + textAlign = TextAlign.Center, + fontWeight = FontWeight.Bold, + fontSize = textSize, + color = MullvadWhite, + modifier = modifier.wrapContentWidth(align = Alignment.End).wrapContentHeight() + ) +} + +@Composable +fun SwitchCellView( + isEnabled: Boolean, + isToggled: Boolean, + modifier: Modifier, + onSwitchClicked: ((Boolean) -> Unit)? = null, + onInfoClicked: (() -> Unit)? = null +) { + val horizontalPadding = dimensionResource(id = R.dimen.medium_padding) + val verticalPadding = 13.dp + Row( + modifier = modifier.wrapContentWidth().wrapContentHeight(), + verticalAlignment = Alignment.CenterVertically, + ) { + if (onInfoClicked != null) { + Icon( + modifier = + Modifier.clickable { onInfoClicked() } + .padding( + start = horizontalPadding, + end = horizontalPadding, + top = verticalPadding, + bottom = verticalPadding, + ) + .align(Alignment.CenterVertically), + painter = painterResource(id = R.drawable.icon_info), + contentDescription = null, + tint = MullvadWhite + ) + } + + CellSwitch(isChecked = isToggled, isEnabled = isEnabled, onCheckedChange = onSwitchClicked) + } +} + +@Composable +fun CustomDnsCellSubtitle(isCellClickable: Boolean, modifier: Modifier) { + val textSize = dimensionResource(id = R.dimen.text_small).value + + HtmlText( + htmlFormattedString = + textResource( + if (isCellClickable) { + R.string.custom_dns_footer + } else { + R.string.custom_dns_disable_mode_subtitle + } + ), + textSize = textSize, + textColor = MullvadWhite60.toArgb(), + modifier = modifier + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Chevron.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Chevron.kt new file mode 100644 index 0000000000..8d458c7077 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Chevron.kt @@ -0,0 +1,36 @@ +package net.mullvad.mullvadvpn.compose.component + +import androidx.compose.animation.core.Animatable +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.tween +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.rotate +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import net.mullvad.mullvadvpn.R + +@Composable +fun ChevronView(isExpanded: Boolean) { + val resourceId = R.drawable.icon_chevron + val rotation = remember { Animatable(90f) } + + LaunchedEffect(isExpanded) { + rotation.animateTo( + targetValue = 90f + if (isExpanded) 0f else 180f, + animationSpec = tween(100, easing = LinearEasing) + ) + } + + Image( + painterResource(id = resourceId), + contentDescription = null, + modifier = Modifier.size(30.dp).rotate(rotation.value), + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/HtmlText.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/HtmlText.kt index b22390cfa8..2042c04278 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/HtmlText.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/HtmlText.kt @@ -4,15 +4,25 @@ import android.util.TypedValue import android.widget.TextView import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.viewinterop.AndroidView import androidx.core.text.HtmlCompat @Composable -fun HtmlText(htmlFormattedString: String, textSize: Float, modifier: Modifier = Modifier) { +fun HtmlText( + htmlFormattedString: String, + textSize: Float, + modifier: Modifier = Modifier, + textColor: Int = Color.White.toArgb(), +) { AndroidView( modifier = modifier, factory = { context -> - TextView(context).apply { setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize) } + TextView(context).apply { + setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize) + setTextColor(textColor) + } }, update = { it.text = HtmlCompat.fromHtml(htmlFormattedString, HtmlCompat.FROM_HTML_MODE_COMPACT) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Switch.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Switch.kt index 1b1117afb9..2c0adcf4cf 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Switch.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Switch.kt @@ -3,6 +3,7 @@ package net.mullvad.mullvadvpn.compose.component import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.Canvas import androidx.compose.foundation.gestures.detectTapGestures +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -20,6 +21,8 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import net.mullvad.mullvadvpn.compose.theme.AlphaActive +import net.mullvad.mullvadvpn.compose.theme.AlphaInactive import net.mullvad.mullvadvpn.compose.theme.MullvadGreen import net.mullvad.mullvadvpn.compose.theme.MullvadRed import net.mullvad.mullvadvpn.compose.theme.MullvadWhite @@ -27,7 +30,10 @@ import net.mullvad.mullvadvpn.compose.theme.MullvadWhite @Preview @Composable private fun PreviewSwitch() { - CellSwitch(isChecked = false, onCheckedChange = null) + Column { + CellSwitch(isChecked = true, onCheckedChange = null) + CellSwitch(isChecked = false, onCheckedChange = null, isEnabled = false) + } } @Composable @@ -36,6 +42,7 @@ fun CellSwitch( onCheckedChange: ((Boolean) -> Unit)?, modifier: Modifier = Modifier, scale: Float = 1f, + isEnabled: Boolean = true, thumbCheckedTrackColor: Color = MullvadGreen, thumbUncheckedTrackColor: Color = MullvadRed, thumbColor: Color = MullvadWhite @@ -66,7 +73,7 @@ fun CellSwitch( .size(width = width, height = height) .scale(scale = scale) .pointerInput(Unit) { - if (onCheckedChange != null) { + if (onCheckedChange != null && isEnabled) { detectTapGestures(onTap = { onCheckedChange(!isChecked) }) } } @@ -74,20 +81,26 @@ fun CellSwitch( // Track drawRoundRect( color = thumbColor, + alpha = if (isEnabled) AlphaActive else AlphaInactive, cornerRadius = CornerRadius(x = 15.dp.toPx(), y = 15.dp.toPx()), style = Stroke( width = 2.dp.toPx(), miter = 6.dp.toPx(), cap = StrokeCap.Square, - ), + ) ) // Thumb drawCircle( color = if (isChecked) thumbCheckedTrackColor else thumbUncheckedTrackColor, + alpha = if (isEnabled) AlphaActive else AlphaInactive, radius = thumbRadius.toPx(), - center = Offset(x = animatePosition.value, y = size.height / 2) + center = + Offset( + x = animatePosition.value, + y = size.height / 2, + ) ) } 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 new file mode 100644 index 0000000000..652c67e66e --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/ContentBlockersInfoDialog.kt @@ -0,0 +1,14 @@ +package net.mullvad.mullvadvpn.compose.dialog + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import net.mullvad.mullvadvpn.R + +@Composable +fun ContentBlockersInfoDialog(onDismiss: () -> Unit) { + InfoDialog( + message = stringResource(id = R.string.dns_content_blockers_info), + additionalInfo = stringResource(id = R.string.dns_content_blockers_warning), + 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 new file mode 100644 index 0000000000..1c9870b50f --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/InfoDialog.kt @@ -0,0 +1,111 @@ +package net.mullvad.mullvadvpn.compose.dialog + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.material.AlertDialog +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Icon +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.DialogProperties +import net.mullvad.mullvadvpn.R +import net.mullvad.mullvadvpn.compose.theme.MullvadWhite + +@Preview +@Composable +private fun PreviewChangelogDialogWithTwoLongItems() { + val longPreviewText = + "This is a sample changelog item of a Compose Preview visualization. " + + "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 = {}, + ) +} + +@Composable +fun InfoDialog(message: String, additionalInfo: String? = null, onDismiss: () -> Unit) { + val verticalSpacing = 24.dp + val iconHeight = 44.dp + AlertDialog( + onDismissRequest = { onDismiss() }, + title = { + Icon( + modifier = Modifier.fillMaxWidth().height(iconHeight), + painter = painterResource(id = R.drawable.icon_info), + contentDescription = "", + tint = MullvadWhite, + ) + }, + text = { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.padding(top = verticalSpacing), + ) { + Text( + text = message, + color = colorResource(id = R.color.white), + fontSize = dimensionResource(id = R.dimen.text_small).value.sp, + fontStyle = FontStyle.Normal, + textAlign = TextAlign.Start, + modifier = Modifier.padding(bottom = verticalSpacing).fillMaxWidth() + ) + if (additionalInfo != null) { + Text( + text = additionalInfo, + color = colorResource(id = R.color.white), + fontSize = dimensionResource(id = R.dimen.text_small).value.sp, + fontStyle = FontStyle.Normal, + textAlign = TextAlign.Start, + modifier = Modifier.fillMaxWidth() + ) + } + } + }, + buttons = { + Button( + modifier = + Modifier.wrapContentHeight() + .padding(all = dimensionResource(id = R.dimen.medium_padding)) + .defaultMinSize(minHeight = dimensionResource(id = R.dimen.button_height)) + .fillMaxWidth(), + colors = + ButtonDefaults.buttonColors( + backgroundColor = colorResource(id = R.color.blue), + contentColor = colorResource(id = R.color.white), + ), + onClick = { onDismiss() }, + ) { + Text( + text = stringResource(R.string.changes_dialog_dismiss_button), + fontSize = dimensionResource(id = R.dimen.text_medium_plus).value.sp, + ) + } + }, + properties = + DialogProperties( + dismissOnClickOutside = true, + dismissOnBackPress = true, + ), + backgroundColor = colorResource(id = R.color.darkBlue), + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/MalwareInfoDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/MalwareInfoDialog.kt new file mode 100644 index 0000000000..985b63e5c5 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/MalwareInfoDialog.kt @@ -0,0 +1,10 @@ +package net.mullvad.mullvadvpn.compose.dialog + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import net.mullvad.mullvadvpn.R + +@Composable +fun MalwareInfoDialog(onDismiss: () -> Unit) { + InfoDialog(message = stringResource(id = R.string.malware_info), onDismiss = onDismiss) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/extensions/LazyListExtensions.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/extensions/LazyListExtensions.kt new file mode 100644 index 0000000000..5fe6a6d509 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/extensions/LazyListExtensions.kt @@ -0,0 +1,13 @@ +package net.mullvad.mullvadvpn.compose.extensions + +import androidx.compose.foundation.lazy.LazyItemScope +import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.material.Divider +import androidx.compose.runtime.Composable + +inline fun LazyListScope.itemWithDivider( + crossinline itemContent: @Composable LazyItemScope.() -> Unit +) = item { + itemContent() + Divider() +} 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 bd115447d6..110a20aa09 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 @@ -3,8 +3,10 @@ package net.mullvad.mullvadvpn.compose.screen import androidx.compose.animation.animateContentSize import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyColumn @@ -14,6 +16,10 @@ import androidx.compose.material.Divider import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -25,16 +31,21 @@ import me.onebone.toolbar.ScrollStrategy import me.onebone.toolbar.rememberCollapsingToolbarScaffoldState import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.cell.BaseCell +import net.mullvad.mullvadvpn.compose.cell.ContentBlockersDisableModeCellSubtitle import net.mullvad.mullvadvpn.compose.cell.CustomDnsCellSubtitle -import net.mullvad.mullvadvpn.compose.cell.CustomDnsComposeCell import net.mullvad.mullvadvpn.compose.cell.DnsCell +import net.mullvad.mullvadvpn.compose.cell.ExpandableComposeCell import net.mullvad.mullvadvpn.compose.cell.MtuComposeCell import net.mullvad.mullvadvpn.compose.cell.NavigationComposeCell +import net.mullvad.mullvadvpn.compose.cell.SwitchComposeCell 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.DnsDialog +import net.mullvad.mullvadvpn.compose.dialog.MalwareInfoDialog import net.mullvad.mullvadvpn.compose.dialog.MtuDialog +import net.mullvad.mullvadvpn.compose.extensions.itemWithDivider import net.mullvad.mullvadvpn.compose.state.AdvancedSettingsUiState import net.mullvad.mullvadvpn.compose.theme.CollapsingToolbarTheme import net.mullvad.mullvadvpn.compose.theme.MullvadBlue20 @@ -59,12 +70,20 @@ private fun PreviewAdvancedSettings() { onCancelMtuDialogClicked = {}, onSplitTunnelingNavigationClick = {}, onToggleDnsClick = {}, + onToggleBlockAds = {}, + onToggleBlockTrackers = {}, + onToggleBlockMalware = {}, + onToggleBlockAdultContent = {}, + onToggleBlockGambling = {}, onDnsClick = {}, onDnsInputChange = {}, onSaveDnsClick = {}, onRemoveDnsClick = {}, onCancelDnsDialogClick = {}, - onBackClick = {}, + onContentsBlockersInfoClicked = {}, + onMalwareInfoClicked = {}, + onDismissInfoClicked = {}, + onBackClick = {} ) } @@ -80,11 +99,19 @@ fun AdvancedSettingScreen( onCancelMtuDialogClicked: () -> Unit = {}, onSplitTunnelingNavigationClick: () -> Unit = {}, onToggleDnsClick: (Boolean) -> Unit = {}, + onToggleBlockAds: (Boolean) -> Unit = {}, + onToggleBlockTrackers: (Boolean) -> Unit = {}, + onToggleBlockMalware: (Boolean) -> Unit = {}, + onToggleBlockAdultContent: (Boolean) -> Unit = {}, + onToggleBlockGambling: (Boolean) -> Unit = {}, onDnsClick: (index: Int?) -> Unit = {}, onDnsInputChange: (String) -> Unit = {}, onSaveDnsClick: () -> Unit = {}, onRemoveDnsClick: () -> Unit = {}, onCancelDnsDialogClick: () -> Unit = {}, + onContentsBlockersInfoClicked: () -> Unit = {}, + onMalwareInfoClicked: () -> Unit = {}, + onDismissInfoClicked: () -> Unit = {}, onBackClick: () -> Unit = {} ) { val cellVerticalSpacing = dimensionResource(id = R.dimen.cell_label_vertical_padding) @@ -107,18 +134,24 @@ fun AdvancedSettingScreen( onIpAddressChanged = { onDnsInputChange(it) }, onAttemptToSave = { onSaveDnsClick() }, onRemove = { onRemoveDnsClick() }, - onDismiss = { onCancelDnsDialogClick() }, + onDismiss = { onCancelDnsDialogClick() } ) } + is AdvancedSettingsUiState.ContentBlockersInfoDialogUiState -> { + ContentBlockersInfoDialog(onDismissInfoClicked) + } + is AdvancedSettingsUiState.MalwareInfoDialogUiState -> { + MalwareInfoDialog(onDismissInfoClicked) + } else -> { // NOOP } } val lazyListState = rememberLazyListState() + var expandContentBlockersState by remember { mutableStateOf(false) } val biggerPadding = 54.dp val topPadding = 6.dp - CollapsingToolbarTheme { val state = rememberCollapsingToolbarScaffoldState() val progress = state.toolbarState.progress @@ -141,7 +174,7 @@ fun AdvancedSettingScreen( title = stringResource(id = R.string.settings_advanced), progress = progress, modifier = scaffoldModifier, - backTitle = stringResource(id = R.string.settings), + backTitle = stringResource(id = R.string.settings) ) } ) { @@ -155,20 +188,94 @@ fun AdvancedSettingScreen( ) { item { MtuComposeCell(mtuValue = uiState.mtu, onEditMtu = { onMtuCellClick() }) } - item { + itemWithDivider { NavigationComposeCell( title = stringResource(id = R.string.split_tunneling), onClick = { onSplitTunnelingNavigationClick.invoke() } ) - Divider() + } + + itemWithDivider { + ExpandableComposeCell( + title = stringResource(R.string.dns_content_blockers_title), + isExpanded = !expandContentBlockersState, + isEnabled = !uiState.isCustomDnsEnabled, + onInfoClicked = { onContentsBlockersInfoClicked() }, + onCellClicked = { expandContentBlockersState = !expandContentBlockersState } + ) + } + + if (expandContentBlockersState) { + itemWithDivider { + SwitchComposeCell( + title = stringResource(R.string.block_ads_title), + isToggled = uiState.contentBlockersOptions.blockAds, + isEnabled = !uiState.isCustomDnsEnabled, + onCellClicked = { onToggleBlockAds(it) }, + background = MullvadBlue20 + ) + } + itemWithDivider { + SwitchComposeCell( + title = stringResource(R.string.block_trackers_title), + isToggled = uiState.contentBlockersOptions.blockTrackers, + isEnabled = !uiState.isCustomDnsEnabled, + onCellClicked = { onToggleBlockTrackers(it) }, + background = MullvadBlue20 + ) + } + itemWithDivider { + SwitchComposeCell( + title = stringResource(R.string.block_malware_title), + isToggled = uiState.contentBlockersOptions.blockMalware, + isEnabled = !uiState.isCustomDnsEnabled, + onCellClicked = { onToggleBlockMalware(it) }, + onInfoClicked = { onMalwareInfoClicked() }, + background = MullvadBlue20 + ) + } + itemWithDivider { + SwitchComposeCell( + title = stringResource(R.string.block_gambling_title), + isToggled = uiState.contentBlockersOptions.blockGambling, + isEnabled = !uiState.isCustomDnsEnabled, + onCellClicked = { onToggleBlockGambling(it) }, + background = MullvadBlue20 + ) + } + itemWithDivider { + SwitchComposeCell( + title = stringResource(R.string.block_adult_content_title), + isToggled = uiState.contentBlockersOptions.blockAdultContent, + isEnabled = !uiState.isCustomDnsEnabled, + onCellClicked = { onToggleBlockAdultContent(it) }, + background = MullvadBlue20 + ) + } + } + + if (uiState.isCustomDnsEnabled) { + item { + ContentBlockersDisableModeCellSubtitle( + Modifier.background(MullvadDarkBlue) + .padding( + start = cellHorizontalSpacing, + top = topPadding, + end = cellHorizontalSpacing, + bottom = cellVerticalSpacing, + ) + ) + } } item { - CustomDnsComposeCell( - checkboxDefaultState = uiState.isCustomDnsEnabled, - onToggle = { newValue -> onToggleDnsClick(newValue) } + Spacer(modifier = Modifier.height(cellVerticalSpacing)) + SwitchComposeCell( + title = stringResource(R.string.enable_custom_dns), + isToggled = uiState.isCustomDnsEnabled, + isEnabled = uiState.contentBlockersOptions.isAnyBlockerEnabled().not(), + onCellClicked = { newValue -> onToggleDnsClick(newValue) } ) - Divider() } if (uiState.isCustomDnsEnabled) { @@ -178,18 +285,18 @@ fun AdvancedSettingScreen( isUnreachableLocalDnsWarningVisible = item.isLocal && uiState.isAllowLanEnabled.not(), onClick = { onDnsClick(index) }, - modifier = Modifier.animateItemPlacement(), + modifier = Modifier.animateItemPlacement() ) Divider() } - item { + itemWithDivider { BaseCell( onCellClicked = { onDnsClick(null) }, title = { Text( text = stringResource(id = R.string.add_a_server), - color = Color.White + color = Color.White, ) }, bodyView = {}, @@ -197,19 +304,21 @@ fun AdvancedSettingScreen( background = MullvadBlue20, startPadding = biggerPadding ) - Divider() } } item { CustomDnsCellSubtitle( - Modifier.background(MullvadDarkBlue) - .padding( - start = cellHorizontalSpacing, - top = topPadding, - end = cellHorizontalSpacing, - bottom = cellVerticalSpacing - ) + isCellClickable = + uiState.contentBlockersOptions.isAnyBlockerEnabled().not(), + modifier = + Modifier.background(MullvadDarkBlue) + .padding( + start = cellHorizontalSpacing, + top = topPadding, + end = cellHorizontalSpacing, + 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 59c3551eb3..71b608b51b 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 @@ -1,5 +1,6 @@ package net.mullvad.mullvadvpn.compose.state +import net.mullvad.mullvadvpn.model.DefaultDnsOptions import net.mullvad.mullvadvpn.viewmodel.CustomDnsItem import net.mullvad.mullvadvpn.viewmodel.StagedDns @@ -7,13 +8,15 @@ sealed interface AdvancedSettingsUiState { val mtu: String val isCustomDnsEnabled: Boolean val customDnsItems: List<CustomDnsItem> + val contentBlockersOptions: DefaultDnsOptions val isAllowLanEnabled: Boolean data class DefaultUiState( override val mtu: String = "", override val isCustomDnsEnabled: Boolean = false, override val isAllowLanEnabled: Boolean = false, - override val customDnsItems: List<CustomDnsItem> = listOf() + override val customDnsItems: List<CustomDnsItem> = listOf(), + override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions() ) : AdvancedSettingsUiState data class MtuDialogUiState( @@ -21,6 +24,7 @@ sealed interface AdvancedSettingsUiState { override val isCustomDnsEnabled: Boolean = false, override val isAllowLanEnabled: Boolean = false, override val customDnsItems: List<CustomDnsItem> = listOf(), + override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions(), val mtuEditValue: String ) : AdvancedSettingsUiState @@ -29,6 +33,23 @@ sealed interface AdvancedSettingsUiState { override val isCustomDnsEnabled: Boolean = false, override val isAllowLanEnabled: Boolean = false, override val customDnsItems: List<CustomDnsItem> = listOf(), - val stagedDns: StagedDns, + override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions(), + val stagedDns: StagedDns + ) : AdvancedSettingsUiState + + data class ContentBlockersInfoDialogUiState( + 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, + override val isAllowLanEnabled: Boolean = false, + override val customDnsItems: List<CustomDnsItem> = listOf(), + override val contentBlockersOptions: DefaultDnsOptions = DefaultDnsOptions() ) : AdvancedSettingsUiState } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/Color.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/Color.kt index 2c542951ab..503fc4dd02 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/Color.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/Color.kt @@ -17,3 +17,6 @@ val MullvadWhite10 = Color(0x1AFFFFFF) val MullvadWhite20 = Color(0x33FFFFFF) val MullvadWhite40 = Color(0x66FFFFFF) val MullvadWhite60 = Color(0x99FFFFFF) + +const val AlphaActive = 1f +const val AlphaInactive = 0.2f diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/DefaultDnsOptions.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/DefaultDnsOptions.kt index 6b24f363cc..eb22c93994 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/DefaultDnsOptions.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/model/DefaultDnsOptions.kt @@ -10,4 +10,8 @@ data class DefaultDnsOptions( val blockMalware: Boolean = false, val blockAdultContent: Boolean = false, val blockGambling: Boolean = false, -) : Parcelable +) : Parcelable { + fun isAnyBlockerEnabled(): Boolean { + return blockAds || blockTrackers || blockMalware || blockAdultContent || blockGambling + } +} 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 6eef99ecce..1e00efc3c5 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 @@ -32,7 +32,11 @@ class SettingsRepository( .onStart { serviceConnectionManager.settingsListener()?.settingsNotifier?.latestEvent } .stateIn(CoroutineScope(dispatcher), SharingStarted.WhileSubscribed(), null) - fun setDnsOptions(isCustomDnsEnabled: Boolean, dnsList: List<InetAddress>) { + fun setDnsOptions( + isCustomDnsEnabled: Boolean, + dnsList: List<InetAddress>, + contentBlockersOptions: DefaultDnsOptions + ) { serviceConnectionManager .customDns() ?.setDnsOptions( @@ -40,7 +44,7 @@ class SettingsRepository( DnsOptions( state = if (isCustomDnsEnabled) DnsState.Custom else DnsState.Default, customOptions = CustomDnsOptions(ArrayList(dnsList)), - defaultOptions = DefaultDnsOptions() + defaultOptions = contentBlockersOptions ) ) } 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 018aa2fc6d..6eee351e78 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 @@ -33,11 +33,19 @@ class AdvancedFragment : BaseFragment() { onCancelMtuDialogClicked = vm::onCancelDialogClick, onSplitTunnelingNavigationClick = ::openSplitTunnelingFragment, onToggleDnsClick = vm::onToggleDnsClick, + onToggleBlockAds = vm::onToggleBlockAds, + onToggleBlockTrackers = vm::onToggleBlockTrackers, + onToggleBlockMalware = vm::onToggleBlockMalware, + onToggleBlockAdultContent = vm::onToggleBlockAdultContent, + onToggleBlockGambling = vm::onToggleBlockGambling, onDnsClick = vm::onDnsClick, onDnsInputChange = vm::onDnsInputChange, onSaveDnsClick = vm::onSaveDnsClick, onRemoveDnsClick = vm::onRemoveDnsClick, onCancelDnsDialogClick = vm::onCancelDialogClick, + onContentsBlockersInfoClicked = vm::onContentsBlockerInfoClick, + onMalwareInfoClicked = vm::onMalwareInfoClick, + onDismissInfoClicked = vm::onDismissInfoClick, onBackClick = { activity?.onBackPressed() } ) } 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 c29573e819..17679b6e29 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 @@ -14,6 +14,7 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.AdvancedSettingsUiState +import net.mullvad.mullvadvpn.model.DefaultDnsOptions import net.mullvad.mullvadvpn.model.DnsState import net.mullvad.mullvadvpn.model.Settings import net.mullvad.mullvadvpn.repository.SettingsRepository @@ -30,13 +31,15 @@ class AdvancedSettingsViewModel( MutableStateFlow<AdvancedSettingsDialogState>(AdvancedSettingsDialogState.NoDialog) private val vmState = - combine(repository.settingsUpdates, dialogState) { settings, interaction -> + combine(repository.settingsUpdates, dialogState) { settings, dialogState -> AdvancedSettingsViewModelState( mtuValue = settings?.mtuString() ?: "", isCustomDnsEnabled = settings?.isCustomDnsEnabled() ?: false, customDnsList = settings?.addresses()?.asStringAddressList() ?: listOf(), + contentBlockersOptions = settings?.contentBlockersSettings() + ?: DefaultDnsOptions(), isAllowLanEnabled = settings?.allowLan ?: false, - dialogState = interaction + dialogState = dialogState ) } .stateIn( @@ -83,6 +86,18 @@ class AdvancedSettingsViewModel( hideDialog() } + fun onContentsBlockerInfoClick() { + dialogState.update { AdvancedSettingsDialogState.ContentBlockersInfoDialog } + } + + fun onMalwareInfoClick() { + dialogState.update { AdvancedSettingsDialogState.MalwareInfoDialog } + } + + fun onDismissInfoClick() { + hideDialog() + } + fun onDnsClick(index: Int? = null) { val stagedDns = if (index == null) { @@ -165,7 +180,11 @@ class AdvancedSettingsViewModel( } } - repository.setDnsOptions(isCustomDnsEnabled = true, dnsList = updatedList) + repository.setDnsOptions( + isCustomDnsEnabled = true, + dnsList = updatedList, + contentBlockersOptions = vmState.value.contentBlockersOptions + ) hideDialog() } @@ -174,10 +193,41 @@ class AdvancedSettingsViewModel( viewModelScope.launch(dispatcher) { repository.setDnsOptions( isEnabled, - dnsList = vmState.value.customDnsList.map { it.address }.asInetAddressList() + dnsList = vmState.value.customDnsList.map { it.address }.asInetAddressList(), + contentBlockersOptions = vmState.value.contentBlockersOptions ) } + fun onToggleBlockAds(isEnabled: Boolean) { + updateDefaultDnsOptionsViaRepository( + vmState.value.contentBlockersOptions.copy(blockAds = isEnabled) + ) + } + + fun onToggleBlockTrackers(isEnabled: Boolean) { + updateDefaultDnsOptionsViaRepository( + vmState.value.contentBlockersOptions.copy(blockTrackers = isEnabled) + ) + } + + fun onToggleBlockMalware(isEnabled: Boolean) { + updateDefaultDnsOptionsViaRepository( + vmState.value.contentBlockersOptions.copy(blockMalware = isEnabled) + ) + } + + fun onToggleBlockAdultContent(isEnabled: Boolean) { + updateDefaultDnsOptionsViaRepository( + vmState.value.contentBlockersOptions.copy(blockAdultContent = isEnabled) + ) + } + + fun onToggleBlockGambling(isEnabled: Boolean) { + updateDefaultDnsOptionsViaRepository( + vmState.value.contentBlockersOptions.copy(blockGambling = isEnabled) + ) + } + fun onRemoveDnsClick() = viewModelScope.launch(dispatcher) { val dialog = @@ -192,12 +242,21 @@ class AdvancedSettingsViewModel( repository.setDnsOptions( isCustomDnsEnabled = vmState.value.isCustomDnsEnabled && updatedList.isNotEmpty(), - dnsList = updatedList + dnsList = updatedList, + contentBlockersOptions = vmState.value.contentBlockersOptions ) - hideDialog() } + private fun updateDefaultDnsOptionsViaRepository(contentBlockersOption: DefaultDnsOptions) = + viewModelScope.launch(dispatcher) { + repository.setDnsOptions( + isCustomDnsEnabled = vmState.value.isCustomDnsEnabled, + dnsList = vmState.value.customDnsList.map { it.address }.asInetAddressList(), + contentBlockersOptions = contentBlockersOption + ) + } + private fun hideDialog() { dialogState.update { AdvancedSettingsDialogState.NoDialog } } @@ -229,6 +288,8 @@ class AdvancedSettingsViewModel( private fun Settings.addresses() = tunnelOptions.dnsOptions.customOptions.addresses + private fun Settings.contentBlockersSettings() = tunnelOptions.dnsOptions.defaultOptions + private fun String.isValidIp(): Boolean { return inetAddressValidator.isValid(this) } 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 002d478b8f..109e518ad5 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 @@ -1,12 +1,14 @@ package net.mullvad.mullvadvpn.viewmodel import net.mullvad.mullvadvpn.compose.state.AdvancedSettingsUiState +import net.mullvad.mullvadvpn.model.DefaultDnsOptions data class AdvancedSettingsViewModelState( val mtuValue: String, val isCustomDnsEnabled: Boolean, val isAllowLanEnabled: Boolean, val customDnsList: List<CustomDnsItem>, + val contentBlockersOptions: DefaultDnsOptions, val dialogState: AdvancedSettingsDialogState ) { fun toUiState(): AdvancedSettingsUiState { @@ -17,7 +19,8 @@ data class AdvancedSettingsViewModelState( isCustomDnsEnabled = isCustomDnsEnabled, isAllowLanEnabled = isAllowLanEnabled, customDnsItems = customDnsList, - mtuEditValue = dialogState.mtuEditValue, + contentBlockersOptions = contentBlockersOptions, + mtuEditValue = dialogState.mtuEditValue ) is AdvancedSettingsDialogState.DnsDialog -> AdvancedSettingsUiState.DnsDialogUiState( @@ -25,7 +28,24 @@ data class AdvancedSettingsViewModelState( isCustomDnsEnabled = isCustomDnsEnabled, isAllowLanEnabled = isAllowLanEnabled, customDnsItems = customDnsList, - stagedDns = dialogState.stagedDns, + contentBlockersOptions = contentBlockersOptions, + stagedDns = dialogState.stagedDns + ) + is AdvancedSettingsDialogState.ContentBlockersInfoDialog -> + AdvancedSettingsUiState.ContentBlockersInfoDialogUiState( + mtu = mtuValue, + isCustomDnsEnabled = isCustomDnsEnabled, + isAllowLanEnabled = isAllowLanEnabled, + customDnsItems = customDnsList, + contentBlockersOptions = contentBlockersOptions + ) + is AdvancedSettingsDialogState.MalwareInfoDialog -> + AdvancedSettingsUiState.MalwareInfoDialogUiState( + mtu = mtuValue, + isCustomDnsEnabled = isCustomDnsEnabled, + isAllowLanEnabled = isAllowLanEnabled, + customDnsItems = customDnsList, + contentBlockersOptions = contentBlockersOptions ) else -> AdvancedSettingsUiState.DefaultUiState( @@ -33,6 +53,7 @@ data class AdvancedSettingsViewModelState( isCustomDnsEnabled = isCustomDnsEnabled, isAllowLanEnabled = isAllowLanEnabled, customDnsItems = customDnsList, + contentBlockersOptions = contentBlockersOptions ) } } @@ -45,6 +66,7 @@ data class AdvancedSettingsViewModelState( mtuValue = EMPTY_STRING, isCustomDnsEnabled = false, customDnsList = listOf(), + contentBlockersOptions = DefaultDnsOptions(), isAllowLanEnabled = false, dialogState = AdvancedSettingsDialogState.NoDialog ) @@ -57,6 +79,10 @@ sealed class AdvancedSettingsDialogState { data class MtuDialog(val mtuEditValue: String) : AdvancedSettingsDialogState() data class DnsDialog(val stagedDns: StagedDns) : AdvancedSettingsDialogState() + + object ContentBlockersInfoDialog : AdvancedSettingsDialogState() + + object MalwareInfoDialog : AdvancedSettingsDialogState() } sealed interface StagedDns { diff --git a/android/app/src/main/res/drawable/icon_info.xml b/android/app/src/main/res/drawable/icon_info.xml new file mode 100644 index 0000000000..98f45776a3 --- /dev/null +++ b/android/app/src/main/res/drawable/icon_info.xml @@ -0,0 +1,8 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path android:pathData="M12,24A12,12 0,0 1,3.515 3.515a12,12 0,1 1,16.97 16.97A11.922,11.922 0,0 1,12 24zM12,9a1.5,1.5 0,0 0,-1.5 1.5L10.5,18a1.5,1.5 0,1 0,3 0v-7.5A1.5,1.5 0,0 0,12 9zM12,4.5A1.5,1.5 0,1 0,13.5 6,1.5 1.5,0 0,0 12,4.5z" + android:fillColor="#294d73" /> +</vector> diff --git a/android/app/src/main/res/values-da/strings.xml b/android/app/src/main/res/values-da/strings.xml index c6d1953dbe..64683a5c26 100644 --- a/android/app/src/main/res/values-da/strings.xml +++ b/android/app/src/main/res/values-da/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">Auto-tilslutning</string> <string name="auto_connect_footer">Opret automatisk forbindelse til en server, når appen starter.</string> <string name="back">Tilbage</string> + <string name="block_ads_title">Annoncer</string> + <string name="block_adult_content_title">Voksenindhold</string> + <string name="block_gambling_title">Hasardspil</string> + <string name="block_malware_title">Malware</string> + <string name="block_trackers_title">Trackere</string> <string name="blocked_connection">FORBINDELSE BLOKERET</string> <string name="blocking_all_connections">Blokerer alle forbindelser</string> <string name="blocking_internet">Blokerer internettet</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">Opretter konto...</string> <string name="creating_secure_connection">OPRETTER SIKKER FORBINDELSE</string> <string name="critical_error">Kritisk fejl (som kræver din opmærksomhed)</string> + <string name="custom_dns_disable_mode_subtitle">Deaktiver alle <b>DNS-indholdsblokkere</b> ovenfor for at aktivere denne indstilling.</string> <string name="custom_dns_footer">Aktiver for at tilføje mindst én DNS-server.</string> <string name="custom_dns_hint">Indtast IP</string> <string name="custom_tunnel_host_resolution_error">Kunne ikke fortolke værtsnavnet på den tilpassede server</string> @@ -51,6 +57,10 @@ <string name="disconnect">Afbryd forbindelse</string> <string name="disconnecting">Afbryder</string> <string name="dismiss">Afvis</string> + <string name="dns_content_blockers_info">Når denne funktion er aktiveret, forhindrer den enheden i at kontakte bestemte domæner eller websteder, der er kendt for at distribuere annoncer, malware, trackere og lignende.</string> + <string name="dns_content_blockers_subtitle">Deaktiver <b>%1$s</b> nedenfor for at aktivere disse indstillinger.</string> + <string name="dns_content_blockers_title">DNS-indholdsblokkere</string> + <string name="dns_content_blockers_warning">Dette kan forårsage problemer på visse websteder, tjenester og programmer.</string> <string name="dont_have_an_account">Har du ikke noget kontonummer?</string> <string name="edit_message">Rediger meddelelse</string> <string name="enable">Aktiver</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">Ugyldigt kontonummer</string> <string name="login_fail_title">Login mislykkedes</string> <string name="login_title">Log ind</string> + <string name="malware_info">Advarsel: Malware-blokkeren er ikke antivirus og bør ikke behandles som sådan. Dette er blot et ekstra lag af beskyttelse.</string> <string name="max_devices_confirm_removal_description">Er du sikker på, at du vil logge <b>%1$s</b> ud?</string> <string name="max_devices_resolved_description">Du kan nu fortsætte med at logge ind på denne enhed.</string> <string name="max_devices_resolved_title">Super!</string> diff --git a/android/app/src/main/res/values-de/strings.xml b/android/app/src/main/res/values-de/strings.xml index 76a1425fb1..903121b42e 100644 --- a/android/app/src/main/res/values-de/strings.xml +++ b/android/app/src/main/res/values-de/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">Automatische Verbindung</string> <string name="auto_connect_footer">Stellt automatisch eine Verbindung zum Server her, wenn die App startet.</string> <string name="back">Zurück</string> + <string name="block_ads_title">Werbung</string> + <string name="block_adult_content_title">Inhalte für Erwachsene</string> + <string name="block_gambling_title">Glücksspiel</string> + <string name="block_malware_title">Malware</string> + <string name="block_trackers_title">Tracker</string> <string name="blocked_connection">GESPERRTE VERBINDUNG</string> <string name="blocking_all_connections">Alle Verbindungen werden blockiert</string> <string name="blocking_internet">Internet wird gesperrt</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">Konto wird erstellt ...</string> <string name="creating_secure_connection">SICHERE VERBINDUNG WIRD ERSTELLT</string> <string name="critical_error">Kritischer Fehler (Ihre Aufmerksamkeit ist erforderlich)</string> + <string name="custom_dns_disable_mode_subtitle">Deaktivieren Sie oben alle <b>DNS-Inhaltssperren</b>, um diese Einstellung zu aktivieren.</string> <string name="custom_dns_footer">Aktivieren, um mindestens einen DNS-Server hinzuzufügen.</string> <string name="custom_dns_hint">IP eingeben</string> <string name="custom_tunnel_host_resolution_error">Der Hostname des benutzerdefinierten Servers konnte nicht aufgelöst werden</string> @@ -51,6 +57,10 @@ <string name="disconnect">Verbindung trennen</string> <string name="disconnecting">Verbindung wird getrennt</string> <string name="dismiss">Ausblenden</string> + <string name="dns_content_blockers_info">Wenn diese Funktion aktiviert ist, wird das Gerät daran gehindert, bestimmte Domains oder Websites zu kontaktieren, die für die Verbreitung von Werbung, Malware, Trackern und mehr bekannt sind.</string> + <string name="dns_content_blockers_subtitle">Deaktivieren Sie unten <b>%1$s</b>, um diese Einstellungen zu aktivieren.</string> + <string name="dns_content_blockers_title">DNS-Inhaltssperren</string> + <string name="dns_content_blockers_warning">Dies kann bei bestimmten Websites, Diensten und Programmen zu Problemen führen.</string> <string name="dont_have_an_account">Sie haben keine Kontonummer?</string> <string name="edit_message">Nachricht bearbeiten</string> <string name="enable">Aktivieren</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">Ungültige Kontonummer</string> <string name="login_fail_title">Anmeldung fehlgeschlagen</string> <string name="login_title">Anmelden</string> + <string name="malware_info">Der Malware-Blocker ist kein Antivirusprogramm und sollte auch nicht als solches behandelt werden. Es dient lediglich als zusätzliche Schutzschicht.</string> <string name="max_devices_confirm_removal_description">Möchten Sie <b>%1$s</b> wirklich abmelden?</string> <string name="max_devices_resolved_description">Sie können jetzt mit der Anmeldung auf diesem Gerät fortfahren.</string> <string name="max_devices_resolved_title">Super!</string> diff --git a/android/app/src/main/res/values-es/strings.xml b/android/app/src/main/res/values-es/strings.xml index 8095b85289..7e5989dea0 100644 --- a/android/app/src/main/res/values-es/strings.xml +++ b/android/app/src/main/res/values-es/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">Conexión automática</string> <string name="auto_connect_footer">Al iniciarse la aplicación, se conecta automáticamente a un servidor.</string> <string name="back">Volver</string> + <string name="block_ads_title">Anuncios</string> + <string name="block_adult_content_title">Contenido para adultos</string> + <string name="block_gambling_title">Juegos de azar</string> + <string name="block_malware_title">Malware</string> + <string name="block_trackers_title">Rastreadores</string> <string name="blocked_connection">CONEXIÓN BLOQUEADA</string> <string name="blocking_all_connections">Bloqueando todas las conexiones</string> <string name="blocking_internet">Internet bloqueado</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">Creando cuenta…</string> <string name="creating_secure_connection">CREANDO CONEXIÓN SEGURA</string> <string name="critical_error">Error crítico (precisa su atención)</string> + <string name="custom_dns_disable_mode_subtitle">Deshabilite todos los <b>bloqueadores de contenido DNS</b> de arriba para activar este ajuste.</string> <string name="custom_dns_footer">Active esta opción para agregar como mínimo un servidor DNS.</string> <string name="custom_dns_hint">Escriba la IP</string> <string name="custom_tunnel_host_resolution_error">No se puede resolver el nombre de host del servidor personalizado</string> @@ -51,6 +57,10 @@ <string name="disconnect">Desconectar</string> <string name="disconnecting">Desconectando</string> <string name="dismiss">Descartar</string> + <string name="dns_content_blockers_info">Al activar esta opción se evita que el dispositivo contacte con determinados dominios o sitios web que se sabe que distribuyen anuncios, malware, rastreadores y más.</string> + <string name="dns_content_blockers_subtitle">Deshabilite <b>%1$s</b> abajo para activar estos ajustes.</string> + <string name="dns_content_blockers_title">Bloqueadores de contenido DNS</string> + <string name="dns_content_blockers_warning">Esto podría causar problemas con determinados sitios web, servicios y programas.</string> <string name="dont_have_an_account">¿No tiene un número de cuenta?</string> <string name="edit_message">Editar mensaje</string> <string name="enable">Habilitar</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">Número de cuenta no válido</string> <string name="login_fail_title">Error de inicio de sesión</string> <string name="login_title">Iniciar sesión</string> + <string name="malware_info">Advertencia: El bloqueador de malware no es un antivirus y no debe considerarse como tal, tan solo es un nivel de protección adicional.</string> <string name="max_devices_confirm_removal_description">¿Seguro que quiere cerrar la sesión de <b>%1$s</b>?</string> <string name="max_devices_resolved_description">Ya puede iniciar sesión en este dispositivo.</string> <string name="max_devices_resolved_title">¡Genial!</string> diff --git a/android/app/src/main/res/values-fi/strings.xml b/android/app/src/main/res/values-fi/strings.xml index fdf9a7ffb9..dea15889a8 100644 --- a/android/app/src/main/res/values-fi/strings.xml +++ b/android/app/src/main/res/values-fi/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">Automaattinen yhteys</string> <string name="auto_connect_footer">Muodosta yhteys palvelimeen automaattisesti, kun sovellus avataan.</string> <string name="back">Takaisin</string> + <string name="block_ads_title">Mainokset</string> + <string name="block_adult_content_title">Aikuisille suunnattu sisältö</string> + <string name="block_gambling_title">Uhkapelaaminen</string> + <string name="block_malware_title">Haittaohjelmat</string> + <string name="block_trackers_title">Seurantapalvelimet</string> <string name="blocked_connection">ESTETTY YHTEYS</string> <string name="blocking_all_connections">Kaikki yhteydet estetään</string> <string name="blocking_internet">Verkkoyhteys estetään</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">Luodaan tiliä...</string> <string name="creating_secure_connection">LUODAAN SUOJATTU YHTEYS</string> <string name="critical_error">Vakava virhe (vaatii huomiotasi)</string> + <string name="custom_dns_disable_mode_subtitle">Voit ottaa asetuksen käyttöön poistamalla ensin kaikki <b>DNS-sisällönestotoiminnot</b> käytöstä yltä.</string> <string name="custom_dns_footer">Ota käyttöön lisätäksesi vähintään yhden DNS-palvelimen.</string> <string name="custom_dns_hint">Anna IP-osoite</string> <string name="custom_tunnel_host_resolution_error">Mukautetun palvelimen isäntänimen selvittäminen epäonnistui</string> @@ -51,6 +57,10 @@ <string name="disconnect">Katkaise yhteys</string> <string name="disconnecting">Katkaistaan yhteyttä</string> <string name="dismiss">Jätä huomiotta</string> + <string name="dns_content_blockers_info">Kun tämä ominaisuus on käytössä, se estää laitetta ottamasta yhteyttä tiettyihin verkkotunnuksiin tai -sivustoihin, jotka tunnetaan mainosten, haittaohjelmien, seurantaohjelmien tai muiden vastaavien jakelijoina.</string> + <string name="dns_content_blockers_subtitle">Ota nämä asetukset käyttöön poistamalla <b>%1$s</b> käytöstä alta.</string> + <string name="dns_content_blockers_title">DNS-sisällönestotoiminnot</string> + <string name="dns_content_blockers_warning">Tämä voi aiheuttaa ongelmia tietyillä verkkosivustoilla, palveluissa ja ohjelmissa.</string> <string name="dont_have_an_account">Eikö sinulla ole tilinumeroa?</string> <string name="edit_message">Muokkaa viestiä</string> <string name="enable">Ota käyttöön</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">Virheellinen tilin numero</string> <string name="login_fail_title">Sisäänkirjautuminen epäonnistui</string> <string name="login_title">Kirjaudu sisään</string> + <string name="malware_info">Varoitus: haittaohjelmien estotoiminto ei ole virustorjuntaohjelma, eikä sitä pidä käyttää sellaisena – kyseessä on vain ylimääräinen suojauskerros.</string> <string name="max_devices_confirm_removal_description">Haluatko varmasti kirjautua ulos laitteelta <b>%1$s</b>?</string> <string name="max_devices_resolved_description">Voit nyt jatkaa kirjautumista tällä laitteella.</string> <string name="max_devices_resolved_title">Mahtavaa!</string> diff --git a/android/app/src/main/res/values-fr/strings.xml b/android/app/src/main/res/values-fr/strings.xml index f501d2f5ce..3e30a8dfff 100644 --- a/android/app/src/main/res/values-fr/strings.xml +++ b/android/app/src/main/res/values-fr/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">Connexion automatique</string> <string name="auto_connect_footer">Connexion automatique à un serveur dès le démarrage de l\'application.</string> <string name="back">Retour</string> + <string name="block_ads_title">Publicités</string> + <string name="block_adult_content_title">Contenu pour adultes</string> + <string name="block_gambling_title">Jeux d\'argent</string> + <string name="block_malware_title">Malware</string> + <string name="block_trackers_title">Trackers</string> <string name="blocked_connection">CONNEXION BLOQUÉE</string> <string name="blocking_all_connections">Blocage de toutes les connexions</string> <string name="blocking_internet">Internet bloqué</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">Création du compte…</string> <string name="creating_secure_connection">CRÉATION D\'UNE CONNEXION SÉCURISÉE</string> <string name="critical_error">Erreur critique (votre attention est requise)</string> + <string name="custom_dns_disable_mode_subtitle">Désactivez tous les <b>bloqueurs de contenu DNS</b> pour activer ce paramètre.</string> <string name="custom_dns_footer">Activez pour ajouter au moins un serveur DNS.</string> <string name="custom_dns_hint">Saisir l\'IP</string> <string name="custom_tunnel_host_resolution_error">Échec de la résolution du nom d\'hôte du serveur personnalisé</string> @@ -51,6 +57,10 @@ <string name="disconnect">Déconnexion</string> <string name="disconnecting">Déconnexion en cours</string> <string name="dismiss">Ignorer</string> + <string name="dns_content_blockers_info">Lorsque cette fonctionnalité est activée, elle empêche l\'appareil de contacter certains domaines ou sites Web connus pour distribuer des publicités, des logiciels malveillants, des trackers et plus.</string> + <string name="dns_content_blockers_subtitle">Désactivez <b>%1$s</b> ci-dessous pour activer ces paramètres.</string> + <string name="dns_content_blockers_title">Bloqueurs de contenu DNS</string> + <string name="dns_content_blockers_warning">Cela peut causer des problèmes sur certains sites Web, services et programmes.</string> <string name="dont_have_an_account">Vous n\'avez pas de numéro de compte ?</string> <string name="edit_message">Modifier le message</string> <string name="enable">Activer</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">Numéro de compte non valide</string> <string name="login_fail_title">Échec de la connexion</string> <string name="login_title">Connexion</string> + <string name="malware_info">Avertissement : le bloqueur de malware n\'est pas un anti-virus et ne doit pas être traité comme tel, il s\'agit juste d\'une couche de protection supplémentaire.</string> <string name="max_devices_confirm_removal_description">Voulez-vous vraiment déconnecter <b>%1$s</b> ?</string> <string name="max_devices_resolved_description">Vous pouvez maintenant continuer la connexion sur cet appareil.</string> <string name="max_devices_resolved_title">Super !</string> diff --git a/android/app/src/main/res/values-it/strings.xml b/android/app/src/main/res/values-it/strings.xml index 82def46b78..342383f67b 100644 --- a/android/app/src/main/res/values-it/strings.xml +++ b/android/app/src/main/res/values-it/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">Connessione automatica</string> <string name="auto_connect_footer">Connettiti automaticamente al server all\'avvio dell\'app.</string> <string name="back">Indietro</string> + <string name="block_ads_title">Annunci</string> + <string name="block_adult_content_title">Contenuti per adulti</string> + <string name="block_gambling_title">Gioco d\'azzardo</string> + <string name="block_malware_title">Malware</string> + <string name="block_trackers_title">Tracker</string> <string name="blocked_connection">CONNESSIONE BLOCCATA</string> <string name="blocking_all_connections">Blocco di tutte le connessioni</string> <string name="blocking_internet">Blocco di Internet</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">Creazione account...</string> <string name="creating_secure_connection">CREAZIONE CONNESSIONE PROTETTA</string> <string name="critical_error">Errore critico (è necessario intervenire)</string> + <string name="custom_dns_disable_mode_subtitle">Disabilita tutti i <b>blocchi dei contenuti DNS</b> per attivare questa impostazione.</string> <string name="custom_dns_footer">Abilita per aggiungere almeno un server DNS.</string> <string name="custom_dns_hint">Inserisci IP</string> <string name="custom_tunnel_host_resolution_error">Impossibile risolvere il nome host del server personalizzato</string> @@ -51,6 +57,10 @@ <string name="disconnect">Disconnetti</string> <string name="disconnecting">Disconnessione</string> <string name="dismiss">Ignora</string> + <string name="dns_content_blockers_info">Quando è abilitata, questa funzionalità impedisce al dispositivo di contattare determinati domini o siti Web noti per la distribuzione di annunci, malware, tracker e altro.</string> + <string name="dns_content_blockers_subtitle">Disabilita <b>%1$s</b> di seguito per attivare queste impostazioni.</string> + <string name="dns_content_blockers_title">Blocchi dei contenuti DNS</string> + <string name="dns_content_blockers_warning">Ciò potrebbe causare problemi su determinati siti Web, servizi e programmi.</string> <string name="dont_have_an_account">Non hai un numero di account?</string> <string name="edit_message">Modifica messaggio</string> <string name="enable">Abilita</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">Numero di account non valido</string> <string name="login_fail_title">Accesso non riuscito</string> <string name="login_title">Accedi</string> + <string name="malware_info">Avvertenza: questa protezione dai malware non è un antivirus e non deve essere trattata come tale, è solo un ulteriore livello di protezione.</string> <string name="max_devices_confirm_removal_description">Vuoi davvero disconnettere <b>%1$s</b>?</string> <string name="max_devices_resolved_description">Ora puoi continuare ad accedere su questo dispositivo.</string> <string name="max_devices_resolved_title">Fantastico!</string> diff --git a/android/app/src/main/res/values-ja/strings.xml b/android/app/src/main/res/values-ja/strings.xml index eccdfa3610..888fbac831 100644 --- a/android/app/src/main/res/values-ja/strings.xml +++ b/android/app/src/main/res/values-ja/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">自動接続</string> <string name="auto_connect_footer">アプリ起動時に自動的にサーバーに接続します。</string> <string name="back">戻る</string> + <string name="block_ads_title">広告</string> + <string name="block_adult_content_title">アダルトコンテンツ</string> + <string name="block_gambling_title">ギャンブル</string> + <string name="block_malware_title">マルウェア</string> + <string name="block_trackers_title">トラッカー</string> <string name="blocked_connection">ブロックされた接続</string> <string name="blocking_all_connections">すべての接続をブロックしています</string> <string name="blocking_internet">インターネットをブロック中</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">アカウントを作成中...</string> <string name="creating_secure_connection">セキュリティ保護接続を確立中</string> <string name="critical_error">重大なエラー (ご注意ください)</string> + <string name="custom_dns_disable_mode_subtitle">この設定を有効にするには、すべての<b>DNSコンテンツブロッカー</b>を無効にしてください。</string> <string name="custom_dns_footer">1つ以上のDNSサーバーを追加するには有効にしてください。</string> <string name="custom_dns_hint">IPを入力</string> <string name="custom_tunnel_host_resolution_error">カスタムサーバーのホスト名を解決できませんでした</string> @@ -51,6 +57,10 @@ <string name="disconnect">接続解除</string> <string name="disconnecting">接続解除中</string> <string name="dismiss">閉じる</string> + <string name="dns_content_blockers_info">この機能を有効にすると、広告、マルウェア、トラッカーなどの配信が確認されている特定のドメインまたはWebサイトへのデバイスの接続が阻止されます。</string> + <string name="dns_content_blockers_subtitle">これらの設定を有効にするには、以下で<b>%1$s</b>を無効にしてください。</string> + <string name="dns_content_blockers_title">DNSコンテンツブロッカー</string> + <string name="dns_content_blockers_warning">これにより、特定のWebサイト、サービス、プログラムで問題が発生する可能性があります。</string> <string name="dont_have_an_account">アカウント番号を持っていませんか?</string> <string name="edit_message">メッセージを編集する</string> <string name="enable">有効にする</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">アカウント番号が正しくありません</string> <string name="login_fail_title">ログインに失敗しました</string> <string name="login_title">ログイン</string> + <string name="malware_info">警告: マルウェアブロッカーはウィルス対策ではありませんので、そのような用途には使用しないでください。あくまで追加の保護レイヤーに過ぎません。</string> <string name="max_devices_confirm_removal_description">本当に<b>%1$s</b>をログアウトしますか?</string> <string name="max_devices_resolved_description">このデバイスでログインを続けられるようになりました。</string> <string name="max_devices_resolved_title">素晴らしい!</string> diff --git a/android/app/src/main/res/values-ko/strings.xml b/android/app/src/main/res/values-ko/strings.xml index a0defd153e..8a5d117322 100644 --- a/android/app/src/main/res/values-ko/strings.xml +++ b/android/app/src/main/res/values-ko/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">자동 연결</string> <string name="auto_connect_footer">앱이 시작되면 자동으로 서버에 연결합니다.</string> <string name="back">뒤로</string> + <string name="block_ads_title">광고</string> + <string name="block_adult_content_title">성인 콘텐츠</string> + <string name="block_gambling_title">도박</string> + <string name="block_malware_title">맬웨어</string> + <string name="block_trackers_title">트래커</string> <string name="blocked_connection">연결 차단됨</string> <string name="blocking_all_connections">모든 연결 차단 중</string> <string name="blocking_internet">인터넷 차단</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">계정 생성 중...</string> <string name="creating_secure_connection">보안 연결 생성 중</string> <string name="critical_error">심각한 오류(주의가 필요함)</string> + <string name="custom_dns_disable_mode_subtitle">이 설정을 활성화하려면 위의 모든 <b>DNS 콘텐츠 차단기</b>를 비활성화하세요.</string> <string name="custom_dns_footer">하나 이상의 DNS 서버를 추가하려면 활성화합니다.</string> <string name="custom_dns_hint">IP 입력</string> <string name="custom_tunnel_host_resolution_error">사용자 지정 서버의 호스트 이름을 확인하지 못함</string> @@ -51,6 +57,10 @@ <string name="disconnect">연결 끊기</string> <string name="disconnecting">연결 해제 중</string> <string name="dismiss">해제</string> + <string name="dns_content_blockers_info">이 기능이 활성화되면 광고, 맬웨어, 트래커 등을 배포하는 것으로 알려진 특정 도메인이나 웹사이트에 장치가 연결하지 않게 방지됩니다.</string> + <string name="dns_content_blockers_subtitle">이 설정을 활성화하려면 아래의 <b>%1$s</b>을(를) 비활성화하세요.</string> + <string name="dns_content_blockers_title">DNS 콘텐츠 차단기</string> + <string name="dns_content_blockers_warning">이 기능을 사용하면 특정 웹 사이트, 서비스 및 프로그램에서 문제가 발생할 수 있습니다.</string> <string name="dont_have_an_account">계정 번호가 없으신가요?</string> <string name="edit_message">메시지 편집</string> <string name="enable">사용</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">유효하지 않은 계정 번호</string> <string name="login_fail_title">로그인 실패</string> <string name="login_title">로그인</string> + <string name="malware_info">경고: 맬웨어 차단기는 안티바이러스가 아니며 하나의 추가 보호 계층일 뿐입니다.</string> <string name="max_devices_confirm_removal_description"><b>%1$s</b>에서 로그아웃하시겠습니까?</string> <string name="max_devices_resolved_description">이제 이 장치에 계속 로그인할 수 있습니다.</string> <string name="max_devices_resolved_title">좋습니다!</string> diff --git a/android/app/src/main/res/values-my/strings.xml b/android/app/src/main/res/values-my/strings.xml index 84c51c424f..78ed4902ae 100644 --- a/android/app/src/main/res/values-my/strings.xml +++ b/android/app/src/main/res/values-my/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">အော်တို ချိတ်ဆက်မှု</string> <string name="auto_connect_footer">အက်ပ် စတင်ဆောင်ရွက်ချိန်တွင် ဆာဗာနှင့် အော်တို ချိတ်ဆက်သွားပါမည်။</string> <string name="back">နောက်သို့</string> + <string name="block_ads_title">ကြောငြာများ</string> + <string name="block_adult_content_title">လူကြီး အကြောင်းအရာ</string> + <string name="block_gambling_title">လောင်းကစား</string> + <string name="block_malware_title">မဲလ်ဝဲရ်</string> + <string name="block_trackers_title">ခြေရာခံများ</string> <string name="blocked_connection">ပိတ်ဆို့ထားသည့် ချိတ်ဆက်မှု</string> <string name="blocking_all_connections">ချိတ်ဆက်မှု အားလုံးကို ပိတ်ဆို့ထားပါသည်</string> <string name="blocking_internet">အင်တာနက် ပိတ်ဆို့နေပါသည်</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">အကောင့် ဖန်တီးနေဆဲ...</string> <string name="creating_secure_connection">လုံခြုံသည့် ချိတ်ဆက်မှုကို ဖန်တီးနေပါသည်</string> <string name="critical_error">အလွန်အရေးပါသည့် ချို့ယွင်းချက် (သင့်အာရုံစိုက်မှု လိုအပ်ပါသည်)</string> + <string name="custom_dns_disable_mode_subtitle">ဤဆက်တင်ကို သက်ဝင်လုပ်ဆောင်ရန် အထက်ပါ <b>DNS content blockers</b> အားလုံးကို ပိတ်ပါ။</string> <string name="custom_dns_footer">အနည်းဆုံး DNS ဆာဗာတစ်ခုကို ပေါင်းထည့်ပါ။</string> <string name="custom_dns_hint">IP ဖြည့်ပါ</string> <string name="custom_tunnel_host_resolution_error">စိတ်ကြိုက် ဆာဗာ၏ Hostname ကို ဖြေရှင်း၍ မရနိုင်ပါ</string> @@ -51,6 +57,10 @@ <string name="disconnect">ချိတ်ဆက်မှုဖြုတ်ရန်</string> <string name="disconnecting">ချိတ်ဆက်မှုဖြုတ်နေပါသည်</string> <string name="dismiss">ဖယ်ပစ်ရန်</string> + <string name="dns_content_blockers_info">ဤလုပ်ဆောင်ချက်ကို ဖွင့်ထားသည့်အခါ အနှောင့်အယှက်ဖြစ်စေသည့် ကြော်ငြာများ၊ မဲလ်ဝဲရ်၊ ခြေရာခံများနှင့် အစရှိသည်တို့နှင့်စပ်လျဉ်း၍ သိရှိထားသော အချို့သော Domain များ သို့မဟုတ် ဝဘ်ဆိုက်များနှင့် ဆက်သွယ်ခြင်းမှ စက်ကို ရပ်တန့်ပေးပါသည်။</string> + <string name="dns_content_blockers_subtitle">ဤဆက်တင်တို့ကို သက်ဝင်လုပ်ဆောင်ရန် အောက်ပါ <b>%1$s</b> ကို ပိတ်ပါ။</string> + <string name="dns_content_blockers_title">DNS အကြောင်းအရာ ပိတ်ဆို့မှုများ</string> + <string name="dns_content_blockers_warning">၎င်းသည် အချို့သော ဝဘ်ဆိုက်များ၊ ဝန်ဆောင်မှုများနှင့် ပရိုဂရမ်များတွင် ပြဿနာများကို ဖြစ်စေနိုင်သည်။</string> <string name="dont_have_an_account">အကောင့်နံပါတ် မရှိ ဖြစ်နေပါသလား။</string> <string name="edit_message">မက်ဆေ့ချ် တည်းဖြတ်ရန်</string> <string name="enable">ဖွင့်ရန်</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">အကောင့်နံပါတ် မှားယွင်းနေပါသည်</string> <string name="login_fail_title">ဝင်ရောက်မှု မအောင်မြင်ပါ</string> <string name="login_title">ဝင်ရန်</string> + <string name="malware_info">သတိပေးချက်- မဲလ်ဝဲရ် ပိတ်ဆို့မှုသည် အပိုအကာအကွယ်လွှာ တစ်ခုသာဖြစ်ပြီး ဗိုင်းရပ်စ် ကာကွယ်ရေး (anti-virus) မဟုတ်၍ ၎င်းအဖြစ် မမှတ်ယူသင့်ပါ။</string> <string name="max_devices_confirm_removal_description"><b>%1$s</b> မှ ထွက်လိုသည်မှာ သေချာပါသလား။</string> <string name="max_devices_resolved_description">သင်သည် ယခု ဤစက်တွင် ဆက်လက် ဝင်ရောက်နိုင်သည်။</string> <string name="max_devices_resolved_title">အလွန်ကောင်း။</string> diff --git a/android/app/src/main/res/values-nb/strings.xml b/android/app/src/main/res/values-nb/strings.xml index 5f136b7b55..554421b685 100644 --- a/android/app/src/main/res/values-nb/strings.xml +++ b/android/app/src/main/res/values-nb/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">Automatisk tilkobling</string> <string name="auto_connect_footer">Kobler automatisk til en server når appen starter.</string> <string name="back">Tilbake</string> + <string name="block_ads_title">Annonser</string> + <string name="block_adult_content_title">Vokseninnhold</string> + <string name="block_gambling_title">Pengespill</string> + <string name="block_malware_title">Skadelig programvare</string> + <string name="block_trackers_title">Sporing</string> <string name="blocked_connection">TILKOBLING BLOKKERT</string> <string name="blocking_all_connections">Blokkerer alle tilkoblinger</string> <string name="blocking_internet">Blokkerer internettet</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">Oppretter konto ...</string> <string name="creating_secure_connection">OPPRETTER SIKKER TILKOBLING</string> <string name="critical_error">Kritisk feil (krever din oppmerksomhet)</string> + <string name="custom_dns_disable_mode_subtitle">Deaktiver all <b>DNS-innholdsblokkering</b> over for å aktivere innstillingen.</string> <string name="custom_dns_footer">Aktiver for å legge til minst én DNS-server.</string> <string name="custom_dns_hint">Angi IP</string> <string name="custom_tunnel_host_resolution_error">Kunne ikke løse vertsnavnet til den egendefinerte serveren</string> @@ -51,6 +57,10 @@ <string name="disconnect">Koble fra</string> <string name="disconnecting">Kobler fra</string> <string name="dismiss">Ignorer</string> + <string name="dns_content_blockers_info">Når denne funksjonen er aktivert, forhindrer den enheten fra å kontakte bestemte domener og nettsteder som er kjent for å spre annonser, skadelig programvare, sporingsenheter og mer.</string> + <string name="dns_content_blockers_subtitle">Deaktiver <b>%1$s</b> under for å aktivere innstillingene.</string> + <string name="dns_content_blockers_title">DNS-innholdsblokkering</string> + <string name="dns_content_blockers_warning">Dette kan føre til problemer på enkelte nettsteder, tjenester og programmer.</string> <string name="dont_have_an_account">Har du ikke et kontonummer?</string> <string name="edit_message">Rediger melding</string> <string name="enable">Aktiver</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">Ugyldig kontonummer</string> <string name="login_fail_title">Kunne ikke logge inn</string> <string name="login_title">Logg inn</string> + <string name="malware_info">Advarsel: Blokkeringen av skadelig programvare er ikke et antivirusprogram og skal ikke brukes som dette. Det er bare et ekstra lag med beskyttelse.</string> <string name="max_devices_confirm_removal_description">Vil du virkelig logge av <b>%1$s</b>?</string> <string name="max_devices_resolved_description">Du kan nå fortsette med å logge på denne enheten.</string> <string name="max_devices_resolved_title">Supert!</string> diff --git a/android/app/src/main/res/values-nl/strings.xml b/android/app/src/main/res/values-nl/strings.xml index 5089823a58..39d29ed5d9 100644 --- a/android/app/src/main/res/values-nl/strings.xml +++ b/android/app/src/main/res/values-nl/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">Automatisch verbinden</string> <string name="auto_connect_footer">Automatisch verbinden met een server wanneer de app wordt gestart.</string> <string name="back">Terug</string> + <string name="block_ads_title">Advertenties</string> + <string name="block_adult_content_title">Content voor volwassenen</string> + <string name="block_gambling_title">Gokken</string> + <string name="block_malware_title">Malware</string> + <string name="block_trackers_title">Trackers</string> <string name="blocked_connection">VERBINDING GEBLOKKEERD</string> <string name="blocking_all_connections">Alle verbindingen worden geblokkeerd</string> <string name="blocking_internet">Internet blokkeren</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">Account aanmaken...</string> <string name="creating_secure_connection">BEVEILIGDE VERBINDING AANMAKEN</string> <string name="critical_error">Kritieke fout (uw aandacht is vereist)</string> + <string name="custom_dns_disable_mode_subtitle">Schakel alle <b>DNS-contentblokkeringen</b> hierboven uit om deze instelling te activeren.</string> <string name="custom_dns_footer">Schakel in om minimaal één DNS-server toe te voegen.</string> <string name="custom_dns_hint">Voer IP-adres in</string> <string name="custom_tunnel_host_resolution_error">Kon de hostnaam van de aangepaste server niet omzetten</string> @@ -51,6 +57,10 @@ <string name="disconnect">Verbinding verbreken</string> <string name="disconnecting">Verbinding wordt verbroken</string> <string name="dismiss">Negeren</string> + <string name="dns_content_blockers_info">Als deze functie is ingeschakeld, maakt het apparaat geen contact meer met bepaalde domeinen of websites waarvan bekend is dat ze advertenties, malware, trackers en meer verspreiden.</string> + <string name="dns_content_blockers_subtitle">Schakel <b>%1$s</b> hieronder uit om deze instellingen te activeren.</string> + <string name="dns_content_blockers_title">DNS-contentblokkeringen</string> + <string name="dns_content_blockers_warning">Dit kan problemen veroorzaken met bepaalde websites, diensten en programma\'s.</string> <string name="dont_have_an_account">Hebt u geen accountnummer?</string> <string name="edit_message">Bericht bewerken</string> <string name="enable">Inschakelen</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">Ongeldig accountnummer</string> <string name="login_fail_title">Aanmelden mislukt</string> <string name="login_title">Aanmelden</string> + <string name="malware_info">Waarschuwing: de malwareblocker is geen antivirus en mag niet als zodanig behandeld worden. Dit is slechts een extra beschermingslaag.</string> <string name="max_devices_confirm_removal_description">Weet u zeker dat u <b>%1$s</b> wilt afmelden?</string> <string name="max_devices_resolved_description">U kunt nu doorgaan met het aanmelden bij dit apparaat.</string> <string name="max_devices_resolved_title">Super!</string> diff --git a/android/app/src/main/res/values-pl/strings.xml b/android/app/src/main/res/values-pl/strings.xml index 323e5f92c9..07b4ce6525 100644 --- a/android/app/src/main/res/values-pl/strings.xml +++ b/android/app/src/main/res/values-pl/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">Automatyczne łączenie</string> <string name="auto_connect_footer">Automatycznie łącz z serwerem po uruchomieniu aplikacji.</string> <string name="back">Wstecz</string> + <string name="block_ads_title">Reklamy</string> + <string name="block_adult_content_title">Treści dla dorosłych</string> + <string name="block_gambling_title">Hazard</string> + <string name="block_malware_title">Złośliwe oprogramowanie</string> + <string name="block_trackers_title">Trackery</string> <string name="blocked_connection">ZABLOKOWANE POŁĄCZENIE</string> <string name="blocking_all_connections">Blokowanie wszystkich połączeń</string> <string name="blocking_internet">Blokowanie Internetu</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">Tworzenie konta...</string> <string name="creating_secure_connection">TWORZENIE BEZPIECZNEGO POŁĄCZENIA</string> <string name="critical_error">Błąd krytyczny (wymagana uwaga)</string> + <string name="custom_dns_disable_mode_subtitle">Aby to aktywować to ustawienie, wyłącz wszystkie <b>funkcje blokowania treści DNS</b>.</string> <string name="custom_dns_footer">Włącz, aby dodać co najmniej jeden serwer DNS.</string> <string name="custom_dns_hint">Wprowadź adres IP</string> <string name="custom_tunnel_host_resolution_error">Nie można rozpoznać nazwy hosta serwera niestandardowego</string> @@ -51,6 +57,10 @@ <string name="disconnect">Rozłącz</string> <string name="disconnecting">Rozłączanie</string> <string name="dismiss">Odrzuć</string> + <string name="dns_content_blockers_info">Po włączeniu funkcja ta uniemożliwia urządzeniu kontakt z określonymi domenami lub witrynami internetowymi, które rozpowszechniają reklamy, złośliwe oprogramowanie itd.</string> + <string name="dns_content_blockers_subtitle">Aby aktywować te ustawienia, wyłącz <b>%1$s</b> poniżej.</string> + <string name="dns_content_blockers_title">Funkcje blokowania treści DNS</string> + <string name="dns_content_blockers_warning">Może to powodować problemy z niektórymi witrynami, usługami i programami.</string> <string name="dont_have_an_account">Nie masz numeru konta?</string> <string name="edit_message">Edytuj wiadomość</string> <string name="enable">Włącz</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">Nieprawidłowy numer konta</string> <string name="login_fail_title">Błąd logowania</string> <string name="login_title">Logowanie</string> + <string name="malware_info">Ostrzeżenie: funkcja blokowania złośliwego oprogramowania nie jest programem antywirusowym i nie należy jej tak traktować. To jedynie dodatkowa warstwa zabezpieczeń.</string> <string name="max_devices_confirm_removal_description">Czy na pewno chcesz wylogować <b>%1$s</b>?</string> <string name="max_devices_resolved_description">Teraz można kontynuować logowanie się na tym urządzeniu.</string> <string name="max_devices_resolved_title">Super!</string> diff --git a/android/app/src/main/res/values-pt/strings.xml b/android/app/src/main/res/values-pt/strings.xml index 9bf0c8a942..59a310f3b2 100644 --- a/android/app/src/main/res/values-pt/strings.xml +++ b/android/app/src/main/res/values-pt/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">Ligação automática</string> <string name="auto_connect_footer">Liga-se automaticamente a um servidor quando a app inicia.</string> <string name="back">Retroceder</string> + <string name="block_ads_title">Anúncios</string> + <string name="block_adult_content_title">Conteúdo para adultos</string> + <string name="block_gambling_title">Jogos de azar</string> + <string name="block_malware_title">Malware</string> + <string name="block_trackers_title">Trackers</string> <string name="blocked_connection">LIGAÇÃO BLOQUEADA</string> <string name="blocking_all_connections">A bloquear todas as ligações</string> <string name="blocking_internet">A bloquear a Internet</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">A criar conta...</string> <string name="creating_secure_connection">A CRIAR LIGAÇÃO SEGURA</string> <string name="critical_error">Erro crítico (é necessária a sua atenção)</string> + <string name="custom_dns_disable_mode_subtitle">Desative todos os <b>bloqueadores de conteúdo de DNS</b> acima para ativar esta definição.</string> <string name="custom_dns_footer">Ativar para adicionar pelo menos um servidor DNS.</string> <string name="custom_dns_hint">Introduzir IP</string> <string name="custom_tunnel_host_resolution_error">Não foi possível resolver o nome do anfitrião do servidor personalizado</string> @@ -51,6 +57,10 @@ <string name="disconnect">Desligar</string> <string name="disconnecting">A desligar</string> <string name="dismiss">Dispensar</string> + <string name="dns_content_blockers_info">Quando esta funcionalidade é ativada, impede que o dispositivo contacte certos domínios ou sites conhecidos por distribuir anúncios, malware, trackers e muito mais.</string> + <string name="dns_content_blockers_subtitle">Desative <b>%1$s</b> abaixo para ativar estas definições.</string> + <string name="dns_content_blockers_title">Bloqueadores de conteúdo de DNS</string> + <string name="dns_content_blockers_warning">Pode causar problemas em alguns sites, serviços e programas.</string> <string name="dont_have_an_account">Não tem um número de conta?</string> <string name="edit_message">Editar mensagem</string> <string name="enable">Ativar</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">Número de conta inválido</string> <string name="login_fail_title">Erro ao iniciar sessão</string> <string name="login_title">Iniciar sessão</string> + <string name="malware_info">Aviso: o bloqueador de malware não é um antivírus e não deve ser tratado como tal, é apenas uma camada extra de proteção.</string> <string name="max_devices_confirm_removal_description">Tem a certeza de que quer terminar a sessão de <b>%1$s</b>?</string> <string name="max_devices_resolved_description">Agora pode continuar a ligação neste dispositivo.</string> <string name="max_devices_resolved_title">Excelente!</string> diff --git a/android/app/src/main/res/values-ru/strings.xml b/android/app/src/main/res/values-ru/strings.xml index 1d5da1695c..4e6c803faf 100644 --- a/android/app/src/main/res/values-ru/strings.xml +++ b/android/app/src/main/res/values-ru/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">Автоподключение</string> <string name="auto_connect_footer">Автоматически подключаться к серверу при запуске приложения.</string> <string name="back">Назад</string> + <string name="block_ads_title">Реклама</string> + <string name="block_adult_content_title">Контент для взрослых</string> + <string name="block_gambling_title">Азартные игры</string> + <string name="block_malware_title">Вредоносное ПО</string> + <string name="block_trackers_title">Трекеры</string> <string name="blocked_connection">ПОДКЛЮЧЕНИЕ ЗАБЛОКИРОВАНО</string> <string name="blocking_all_connections">Блокируются все подключения</string> <string name="blocking_internet">Блокируется доступ в Интернет</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">Создание учетной записи...</string> <string name="creating_secure_connection">СОЗДАНИЕ ЗАЩИЩЕННОГО ПОДКЛЮЧЕНИЯ</string> <string name="critical_error">Критическая ошибка (требуется ваше участие)</string> + <string name="custom_dns_disable_mode_subtitle">Чтобы активировать эту опцию, отключите все <b>DNS-блокировщики контента</b>.</string> <string name="custom_dns_footer">Чтобы добавить как минимум один DNS-сервер, включите этот параметр.</string> <string name="custom_dns_hint">Введите IP-адрес</string> <string name="custom_tunnel_host_resolution_error">Не удалось преобразовать имя узла пользовательского сервера</string> @@ -51,6 +57,10 @@ <string name="disconnect">Отключить</string> <string name="disconnecting">Отключение</string> <string name="dismiss">Закрыть</string> + <string name="dns_content_blockers_info">При включенной опции устройство не будет устанавливать соединение с определенными доменами и сайтами, известными распространением рекламы, вредоносного ПО, трекеров и т. д.</string> + <string name="dns_content_blockers_subtitle">Чтобы активировать эти параметры, отключите опцию <b>%1$s</b> ниже.</string> + <string name="dns_content_blockers_title">DNS-блокировщики контента</string> + <string name="dns_content_blockers_warning">Это может привести к проблемам при использовании некоторых сайтов, служб и программ.</string> <string name="dont_have_an_account">У вас нет номера учетной записи?</string> <string name="edit_message">Изменить сообщение</string> <string name="enable">Включить</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">Недействительный номер учетной записи</string> <string name="login_fail_title">Ошибка входа</string> <string name="login_title">Вход</string> + <string name="malware_info">Внимание! Блокировщик вредоносного ПО — это просто дополнительный уровень защиты, а не антивирус.</string> <string name="max_devices_confirm_removal_description">Действительно выйти из профиля на устройстве <b>%1$s</b>?</string> <string name="max_devices_resolved_description">Теперь можно войти в учетную запись на этом устройстве.</string> <string name="max_devices_resolved_title">Отлично!</string> diff --git a/android/app/src/main/res/values-sv/strings.xml b/android/app/src/main/res/values-sv/strings.xml index 30cd54d409..c14d953e1b 100644 --- a/android/app/src/main/res/values-sv/strings.xml +++ b/android/app/src/main/res/values-sv/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">Anslut automatiskt</string> <string name="auto_connect_footer">Anslut automatiskt till en server när appen startas.</string> <string name="back">Tillbaka</string> + <string name="block_ads_title">Annonser</string> + <string name="block_adult_content_title">Vuxet innehåll</string> + <string name="block_gambling_title">Hasardspel</string> + <string name="block_malware_title">Skadlig kod</string> + <string name="block_trackers_title">Spårare</string> <string name="blocked_connection">ANSLUTNINGEN BLOCKERAD</string> <string name="blocking_all_connections">Blockerar alla anslutningar</string> <string name="blocking_internet">Blockerar internet</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">Skapar konto...</string> <string name="creating_secure_connection">SKAPAR SÄKER ANSLUTNING</string> <string name="critical_error">Kritiskt fel (kräver din uppmärksamhet)</string> + <string name="custom_dns_disable_mode_subtitle">Inaktivera alla <b>DNS-innehållsblockerare</b> ovan för att aktivera den här inställningen.</string> <string name="custom_dns_footer">Aktivera för att lägga till minst en DNS-server.</string> <string name="custom_dns_hint">Ange IP</string> <string name="custom_tunnel_host_resolution_error">Det gick inte att lösa värdnamnet för den anpassade servern</string> @@ -51,6 +57,10 @@ <string name="disconnect">Koppla från</string> <string name="disconnecting">Kopplar från</string> <string name="dismiss">Ignorera</string> + <string name="dns_content_blockers_info">När den här funktionen är aktiverad stoppas enheten från att kontakta vissa domäner eller webbplatser som är kända för att sprida annonser, skadlig kod, spårare med mera.</string> + <string name="dns_content_blockers_subtitle">Inaktivera <b>%1$s</b> nedan för att aktivera dessa inställningar.</string> + <string name="dns_content_blockers_title">DNS-innehållsblockerare</string> + <string name="dns_content_blockers_warning">Detta kan orsaka problem på vissa webbplatser, tjänster och program.</string> <string name="dont_have_an_account">Har du inget kontonummer?</string> <string name="edit_message">Redigera meddelande</string> <string name="enable">Aktivera</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">Ogiltigt kontonummer</string> <string name="login_fail_title">Inloggningen misslyckades</string> <string name="login_title">Logga in</string> + <string name="malware_info">Varning! Blockering av skadlig kod är inte ett antivirusprogram och bör inte behandlas som ett. Det här är bara ett extra skyddslager.</string> <string name="max_devices_confirm_removal_description">Vill du verkligen logga ut <b>%1$s</b>?</string> <string name="max_devices_resolved_description">Du kan nu fortsätta med att logga in på den här enheten.</string> <string name="max_devices_resolved_title">Super!</string> diff --git a/android/app/src/main/res/values-th/strings.xml b/android/app/src/main/res/values-th/strings.xml index a4759648f3..926f7a35d1 100644 --- a/android/app/src/main/res/values-th/strings.xml +++ b/android/app/src/main/res/values-th/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">เชื่อมต่ออัตโนมัติ</string> <string name="auto_connect_footer">เชื่อมต่อเซิร์ฟเวอร์โดยอัตโนมัติทันทีที่เปิดแอป</string> <string name="back">ย้อนกลับ</string> + <string name="block_ads_title">โฆษณา</string> + <string name="block_adult_content_title">เนื้อหาสำหรับผู้ใหญ่</string> + <string name="block_gambling_title">การพนัน</string> + <string name="block_malware_title">มัลแวร์</string> + <string name="block_trackers_title">ตัวติดตาม</string> <string name="blocked_connection">การเชื่อมต่อที่ถูกบล็อก</string> <string name="blocking_all_connections">บล็อกการเชื่อมต่อทั้งหมด</string> <string name="blocking_internet">กำลังบล็อกอินเทอร์เน็ต</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">กำลังสร้างบัญชี...</string> <string name="creating_secure_connection">กำลังสร้างการเชื่อมต่อที่ปลอดภัย</string> <string name="critical_error">ข้อผิดพลาดร้ายแรง (คุณจำเป็นต้องตรวจสอบ)</string> + <string name="custom_dns_disable_mode_subtitle">ปิดใช้งาน<b>ตัวบล็อกเนื้อหา DNS</b> ทั้งหมดด้านบน เพื่อเปิดใช้งานการตั้งค่านี้</string> <string name="custom_dns_footer">เปิดเพื่อเพิ่มเซิร์ฟเวอร์ DNS อย่างน้อยหนึ่งรายการ</string> <string name="custom_dns_hint">ป้อน IP</string> <string name="custom_tunnel_host_resolution_error">ไม่พบชื่อโฮสต์ของเซิร์ฟเวอร์แบบกำหนดเอง</string> @@ -51,6 +57,10 @@ <string name="disconnect">ตัดการเชื่อมต่อ</string> <string name="disconnecting">กำลังตัดการเชื่อมต่อ</string> <string name="dismiss">ละทิ้ง</string> + <string name="dns_content_blockers_info">ในขณะที่เปิดใช้งานคุณสมบัตินี้ คุณสมบัตินี้จะหยุดไม่ให้อุปกรณ์ติดต่อโดเมน หรือเว็บไซต์ใดๆ ที่เป็นที่ทราบกันว่า ใช้ในการเผยแพร่โฆษณา มัลแวร์ ตัวติดตาม และอื่นๆ</string> + <string name="dns_content_blockers_subtitle">ปิดใช้งาน <b>%1$s</b> ด้านล่าง เพื่อเปิดใช้การตั้งค่าเหล่านี้</string> + <string name="dns_content_blockers_title">ตัวบล็อกเนื้อหา DNS</string> + <string name="dns_content_blockers_warning">นี่อาจก่อให้เกิดปัญหากับเว็บไซต์ บริการ และโปรแกรมบางอย่างได้</string> <string name="dont_have_an_account">ยังไม่มีหมายเลขบัญชีใช่ไหม</string> <string name="edit_message">แก้ไขข้อความ</string> <string name="enable">เปิดใช้งาน</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">หมายเลขบัญชีไม่ถูกต้อง</string> <string name="login_fail_title">การเข้าสู่ระบบล้มเหลว</string> <string name="login_title">เข้าสู่ระบบ</string> + <string name="malware_info">คำเตือน: ตัวบล็อกมัลแวร์ไม่ใช่แอนตี้ไวรัส และไม่ควรนำมาใช้ในรูปแบบดังกล่าว นี่เป็นเพียงชั้นการป้องกันเพิ่มเติมเท่านั้น</string> <string name="max_devices_confirm_removal_description">คุณแน่ใจหรือไม่ว่าต้องการออกจากระบบบน <b>%1$s</b></string> <string name="max_devices_resolved_description">คุณสามารถดำเนินการเข้าสู่ระบบต่อบนอุปกรณ์เครื่องนี้ได้แล้ว</string> <string name="max_devices_resolved_title">เยี่ยมยอด!</string> diff --git a/android/app/src/main/res/values-tr/strings.xml b/android/app/src/main/res/values-tr/strings.xml index 7fb6438320..c216691300 100644 --- a/android/app/src/main/res/values-tr/strings.xml +++ b/android/app/src/main/res/values-tr/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">Otomatik Bağlan</string> <string name="auto_connect_footer">Uygulama başladığında bir sunucuya otomatik olarak bağlan.</string> <string name="back">Geri</string> + <string name="block_ads_title">Reklamlar</string> + <string name="block_adult_content_title">Yetişkinlere özel içerik</string> + <string name="block_gambling_title">Kumar</string> + <string name="block_malware_title">Kötü amaçlı yazılım</string> + <string name="block_trackers_title">İzleyiciler</string> <string name="blocked_connection">ENGELLENEN BAĞLANTI</string> <string name="blocking_all_connections">Tüm bağlantılar engelleniyor</string> <string name="blocking_internet">İnternet bağlantısı engelleniyor</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">Hesap oluşturuluyor...</string> <string name="creating_secure_connection">GÜVENLİ BAĞLANTI OLUŞTURULUYOR</string> <string name="critical_error">Kritik hata (Lütfen dikkatli olun)</string> + <string name="custom_dns_disable_mode_subtitle">Bu ayarı etkinleştirmek için yukarıdaki tüm <b>DNS içerik engelleyicileri</b> devre dışı bırakın.</string> <string name="custom_dns_footer">En az bir DNS sunucusu eklemek için etkinleştirin.</string> <string name="custom_dns_hint">IP\'yi girin</string> <string name="custom_tunnel_host_resolution_error">Özel sunucu ana bilgisayar adı çözülemiyor</string> @@ -51,6 +57,10 @@ <string name="disconnect">Bağlantıyı Kes</string> <string name="disconnecting">Bağlantı kesiliyor</string> <string name="dismiss">Reddet</string> + <string name="dns_content_blockers_info">Bu özellik etkinleştirildiğinde, cihazınızın reklamlar, kötü amaçlı yazılımlar, izleyiciler ve daha fazlasını dağıttığı bilinen belirli alan adlarıyla veya web siteleriyle iletişim kurmasını durdurur.</string> + <string name="dns_content_blockers_subtitle">Bu ayarları etkinleştirmek için aşağıdaki <b>%1$s</b> seçeneğini devre dışı bırakın.</string> + <string name="dns_content_blockers_title">DNS içerik engelleyiciler</string> + <string name="dns_content_blockers_warning">Bu özellik belirli web sitelerinde, hizmetlerde ve programlarda sorunlara neden olabilir.</string> <string name="dont_have_an_account">Hesap numaranız yok mu?</string> <string name="edit_message">Mesajı düzenle</string> <string name="enable">Etkinleştir</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">Geçersiz hesap numarası</string> <string name="login_fail_title">Oturum açma başarısız</string> <string name="login_title">Oturum Aç</string> + <string name="malware_info">Uyarı: Kötü amaçlı yazılım engelleyici, virüsten koruma yazılımı değildir ve bu şekilde değerlendirilmemelidir. Sadece ek bir koruma seviyesi sağlamaktadır.</string> <string name="max_devices_confirm_removal_description"><b>%1$s</b> adlı cihazdan çıkış yapmak istediğinizden emin misiniz?</string> <string name="max_devices_resolved_description">Artık bu cihazda oturum açmaya devam edebilirsiniz.</string> <string name="max_devices_resolved_title">Süper!</string> diff --git a/android/app/src/main/res/values-zh-rCN/strings.xml b/android/app/src/main/res/values-zh-rCN/strings.xml index 9c5f98c8e1..62cba3caff 100644 --- a/android/app/src/main/res/values-zh-rCN/strings.xml +++ b/android/app/src/main/res/values-zh-rCN/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">自动连接</string> <string name="auto_connect_footer">在应用启动时自动连接到服务器。</string> <string name="back">返回</string> + <string name="block_ads_title">广告</string> + <string name="block_adult_content_title">成人内容</string> + <string name="block_gambling_title">博彩</string> + <string name="block_malware_title">恶意软件</string> + <string name="block_trackers_title">跟踪器</string> <string name="blocked_connection">已阻止连接</string> <string name="blocking_all_connections">正在阻止所有连接</string> <string name="blocking_internet">正在阻止网络</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">正在创建帐户…</string> <string name="creating_secure_connection">正在创建安全连接</string> <string name="critical_error">严重错误(需要注意)</string> + <string name="custom_dns_disable_mode_subtitle">禁用上方的所有 <b>DNS 内容阻止程序</b>以激活此设置。</string> <string name="custom_dns_footer">启用以添加至少一个 DNS 服务器。</string> <string name="custom_dns_hint">输入 IP</string> <string name="custom_tunnel_host_resolution_error">无法解析自定义服务器的主机名</string> @@ -51,6 +57,10 @@ <string name="disconnect">断开连接</string> <string name="disconnecting">正在断开连接</string> <string name="dismiss">关闭</string> + <string name="dns_content_blockers_info">启用此功能后,它将阻止设备与已知的分发广告、恶意软件、跟踪器等内容的特定域或网站联系。</string> + <string name="dns_content_blockers_subtitle">禁用下方的<b>%1$s</b>以激活这些设置。</string> + <string name="dns_content_blockers_title">DNS 内容阻止程序</string> + <string name="dns_content_blockers_warning">这可能会导致某些网站、服务和程序出现问题。</string> <string name="dont_have_an_account">没有帐号?</string> <string name="edit_message">编辑消息</string> <string name="enable">启用</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">帐号无效</string> <string name="login_fail_title">登录失败</string> <string name="login_title">登录</string> + <string name="malware_info">警告:恶意软件阻止程序不是防病毒软件,也不应被视为防病毒软件,这只是提供了一层额外的保护。</string> <string name="max_devices_confirm_removal_description">确定要退出<b>%1$s</b>吗?</string> <string name="max_devices_resolved_description">您现在可以继续在此设备上登录。</string> <string name="max_devices_resolved_title">太棒了!</string> diff --git a/android/app/src/main/res/values-zh-rTW/strings.xml b/android/app/src/main/res/values-zh-rTW/strings.xml index 02056bee04..c086b24941 100644 --- a/android/app/src/main/res/values-zh-rTW/strings.xml +++ b/android/app/src/main/res/values-zh-rTW/strings.xml @@ -18,6 +18,11 @@ <string name="auto_connect">自動連線</string> <string name="auto_connect_footer">啟動應用程式時,自動連線伺服器。</string> <string name="back">返回</string> + <string name="block_ads_title">廣告</string> + <string name="block_adult_content_title">成人內容</string> + <string name="block_gambling_title">賭博</string> + <string name="block_malware_title">惡意軟體</string> + <string name="block_trackers_title">追蹤程式</string> <string name="blocked_connection">被封鎖的連線</string> <string name="blocking_all_connections">正在封鎖所有連線</string> <string name="blocking_internet">正在封鎖網路</string> @@ -41,6 +46,7 @@ <string name="creating_new_account">正在建立帳戶…</string> <string name="creating_secure_connection">建立安全連線</string> <string name="critical_error">嚴重錯誤 (需注意)</string> + <string name="custom_dns_disable_mode_subtitle">停用上方所有 <b>DNS 內容封鎖程式</b>,以便啟動此設定。</string> <string name="custom_dns_footer">啟用以新增至少一個 DNS 伺服器。</string> <string name="custom_dns_hint">輸入 IP</string> <string name="custom_tunnel_host_resolution_error">無法解析自訂伺服器的主機名稱</string> @@ -51,6 +57,10 @@ <string name="disconnect">中斷連線</string> <string name="disconnecting">正在中斷連線</string> <string name="dismiss">取消</string> + <string name="dns_content_blockers_info">此功能啟用後,便會禁止裝置聯繫某些已知會傳播廣告、惡意軟體、追蹤程式等內容的網域或網站。</string> + <string name="dns_content_blockers_subtitle">停用下方的 <b>%1$s</b> 以啟動這些設定。</string> + <string name="dns_content_blockers_title">DNS 內容封鎖程式</string> + <string name="dns_content_blockers_warning">這可能會導致某些網站、服務和程式出現問題。</string> <string name="dont_have_an_account">沒有帳號?</string> <string name="edit_message">編輯訊息</string> <string name="enable">啟用</string> @@ -89,6 +99,7 @@ <string name="login_fail_description">帳號無效</string> <string name="login_fail_title">登入失敗</string> <string name="login_title">登入</string> + <string name="malware_info">警告:惡意軟體封鎖程式並非防毒軟體,只是提供了一層額外保護,不應將其視為防毒軟體。</string> <string name="max_devices_confirm_removal_description">確定要將 <b>%1$s</b> 登出嗎?</string> <string name="max_devices_resolved_description">現在,您可以繼續在此裝置上登入。</string> <string name="max_devices_resolved_title">太好了!</string> diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 747c3ee31e..477c299513 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -209,4 +209,23 @@ <string name="add_dns_server_dialog_title">Add DNS server</string> <string name="update_dns_server_dialog_title">Update DNS server</string> <string name="duplicate_address_warning">This address has already been entered.</string> + <string name="dns_content_blockers_title">DNS content blockers</string> + <string name="dns_content_blockers_info">When this feature is enabled it stops the device from + contacting certain domains or websites known for distributing ads, malware, trackers and + more.</string> + <string name="dns_content_blockers_warning">This might cause issues on certain websites, + services, and programs.</string> + <string name="block_ads_title">Ads</string> + <string name="block_trackers_title">Trackers</string> + <string name="block_malware_title">Malware</string> + <string name="malware_info">Warning: The malware blocker is not an anti-virus and should not be + treated as such, this is just an extra layer of protection.</string> + <string name="block_gambling_title">Gambling</string> + <string name="block_adult_content_title">Adult content</string> + <string name="dns_content_blockers_subtitle"> +<![CDATA[Disable <b>%s</b> below to activate these settings.]]> + </string> + <string name="custom_dns_disable_mode_subtitle"> +<![CDATA[Disable all <b>DNS content blockers</b> above to activate this setting.]]> + </string> </resources> |
