diff options
16 files changed, 352 insertions, 195 deletions
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt index 407bd15569..f18ba6a801 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt @@ -203,7 +203,7 @@ class VpnSettingsScreenTest { composeTestRule.setContent { VpnSettingsScreen( uiState = VpnSettingsUiState.MtuDialogUiState(mtuEditValue = EMPTY_STRING), - onCancelMtuDialogClicked = mockedClickHandler, + onCancelMtuDialogClick = mockedClickHandler, toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow() ) } 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 56a5a2b38b..47d1c8c894 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 @@ -11,18 +11,51 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.material.Text +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.text.TextStyle +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.dp import net.mullvad.mullvadvpn.R +import net.mullvad.mullvadvpn.compose.theme.AppTheme import net.mullvad.mullvadvpn.compose.theme.MullvadBlue import net.mullvad.mullvadvpn.compose.theme.MullvadDarkBlue +@Preview @Composable -fun BaseCell( +fun PreviewBaseCell() { + AppTheme { + Column { + BaseCell( + title = { + BaseCellTitle( + title = "Header title", + style = MaterialTheme.typography.titleMedium + ) + } + ) + Spacer(modifier = Modifier.height(1.dp)) + BaseCell( + title = { + BaseCellTitle( + title = "Normal title", + style = MaterialTheme.typography.labelLarge + ) + } + ) + } + } +} + +@Composable +internal fun BaseCell( modifier: Modifier = Modifier, title: @Composable () -> Unit, bodyView: @Composable () -> Unit = {}, @@ -80,3 +113,14 @@ fun BaseCell( } } } + +@Composable +internal fun BaseCellTitle(title: String, style: TextStyle, modifier: Modifier = Modifier) { + Text( + text = title, + textAlign = TextAlign.Center, + style = style, + color = MaterialTheme.colorScheme.onPrimary, + modifier = modifier.wrapContentWidth(align = Alignment.End).wrapContentHeight() + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ExpandableComposeCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ExpandableComposeCell.kt index 3a27adf2a9..17a8065693 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ExpandableComposeCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ExpandableComposeCell.kt @@ -6,6 +6,7 @@ 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.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -49,7 +50,13 @@ fun ExpandableComposeCell( val bodyViewModifier = Modifier BaseCell( - title = { SwitchCellTitle(title = title, modifier = titleModifier) }, + title = { + BaseCellTitle( + title = title, + style = MaterialTheme.typography.titleMedium, + modifier = titleModifier + ) + }, bodyView = { ExpandableComposeCellBody( isExpanded = isExpanded, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/InformationComposeCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/InformationComposeCell.kt index f276defee8..32ccd1365d 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/InformationComposeCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/InformationComposeCell.kt @@ -6,6 +6,7 @@ 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.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -44,7 +45,13 @@ fun InformationComposeCell( val bodyViewModifier = Modifier BaseCell( - title = { SwitchCellTitle(title = title, modifier = titleModifier) }, + title = { + BaseCellTitle( + title = title, + style = MaterialTheme.typography.titleMedium, + modifier = titleModifier + ) + }, background = background, bodyView = { InformationComposeCellBody(modifier = bodyViewModifier, onInfoClicked = onInfoClicked) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/MtuComposeCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/MtuComposeCell.kt index 2bc4679710..6cc8eccdc3 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/MtuComposeCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/MtuComposeCell.kt @@ -4,17 +4,16 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.layout.wrapContentWidth as wrapContentWidth1 import androidx.compose.material.Text +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -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.theme.AppTheme import net.mullvad.mullvadvpn.compose.theme.MullvadWhite60 import net.mullvad.mullvadvpn.constant.MTU_MAX_VALUE import net.mullvad.mullvadvpn.constant.MTU_MIN_VALUE @@ -22,7 +21,7 @@ import net.mullvad.mullvadvpn.constant.MTU_MIN_VALUE @Preview @Composable fun MtuComposeCellPreview() { - MtuComposeCell(mtuValue = "1300", onEditMtu = {}) + AppTheme { MtuComposeCell(mtuValue = "1300", onEditMtu = {}) } } @Composable @@ -44,13 +43,11 @@ fun MtuComposeCell( @Composable private fun MtuTitle(modifier: Modifier) { - val textSize = dimensionResource(id = R.dimen.text_medium_plus).value.sp Text( text = stringResource(R.string.wireguard_mtu), textAlign = TextAlign.Center, - fontWeight = FontWeight.Bold, - fontSize = textSize, - color = Color.White, + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onPrimary, modifier = modifier.wrapContentWidth1(align = Alignment.End).wrapContentHeight() ) } @@ -67,10 +64,9 @@ private fun MtuBodyView(mtuValue: String, modifier: Modifier) { @Composable private fun MtuSubtitle(modifier: Modifier) { - val textSize = dimensionResource(id = R.dimen.text_small).value.sp Text( text = stringResource(R.string.wireguard_mtu_footer, MTU_MIN_VALUE, MTU_MAX_VALUE), - fontSize = textSize, + style = MaterialTheme.typography.labelMedium, color = MullvadWhite60, modifier = modifier ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt new file mode 100644 index 0000000000..cead89cc63 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt @@ -0,0 +1,31 @@ +package net.mullvad.mullvadvpn.compose.cell + +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.Dp +import net.mullvad.mullvadvpn.compose.theme.Dimens + +@Composable +fun SelectableCell( + title: String, + isSelected: Boolean, + titleStyle: TextStyle = MaterialTheme.typography.labelLarge, + startPadding: Dp = Dimens.indentedCellStartPadding, + selectedColor: Color = MaterialTheme.colorScheme.surface, + backgroundColor: Color = MaterialTheme.colorScheme.secondaryContainer, + onCellClicked: () -> Unit = {}, +) { + BaseCell( + onCellClicked = onCellClicked, + title = { BaseCellTitle(title = title, style = titleStyle) }, + background = + if (isSelected) { + selectedColor + } else { + backgroundColor + }, + startPadding = startPadding + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SplitTunnelingCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SplitTunnelingCell.kt index 06e0197268..bab0a2caa5 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SplitTunnelingCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SplitTunnelingCell.kt @@ -59,7 +59,7 @@ fun SplitTunnelingCell( applicationImageView.packageName = packageName ?: "" }, modifier = - Modifier.padding(start = Dimens.cellLeftPadding) + Modifier.padding(start = Dimens.cellStartPadding) .align(Alignment.CenterVertically) .size(width = Dimens.listIconSize, height = Dimens.listIconSize) ) @@ -84,7 +84,7 @@ fun SplitTunnelingCell( ), contentDescription = null, modifier = - Modifier.padding(end = Dimens.cellRightPadding) + Modifier.padding(end = Dimens.cellStartPadding) .align(Alignment.CenterVertically) .padding(horizontal = Dimens.loadingSpinnerPadding) ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SwitchComposeCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SwitchComposeCell.kt index 0b5508d524..afbf04ec33 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SwitchComposeCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SwitchComposeCell.kt @@ -1,69 +1,134 @@ package net.mullvad.mullvadvpn.compose.cell import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height 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.material3.MaterialTheme 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.dp -import androidx.compose.ui.unit.sp +import androidx.core.text.HtmlCompat +import androidx.core.text.HtmlCompat.FROM_HTML_MODE_COMPACT 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 +import net.mullvad.mullvadvpn.compose.extensions.toAnnotatedString +import net.mullvad.mullvadvpn.compose.theme.AppTheme +import net.mullvad.mullvadvpn.compose.theme.Dimens @Preview @Composable private fun PreviewSwitchComposeCell() { + AppTheme { + Column { + HeaderSwitchComposeCell( + title = "Checkbox Title", + isEnabled = true, + isToggled = true, + onCellClicked = {}, + onInfoClicked = {} + ) + Spacer(modifier = Modifier.height(1.dp)) + HeaderSwitchComposeCell( + title = "Checkbox Title", + isEnabled = true, + isToggled = true, + onCellClicked = {}, + onInfoClicked = {}, + subtitle = "Subtitle" + ) + Spacer(modifier = Modifier.height(1.dp)) + NormalSwitchComposeCell( + title = "Checkbox Item", + isEnabled = true, + isToggled = true, + onCellClicked = {}, + onInfoClicked = {} + ) + } + } +} + +@Composable +fun NormalSwitchComposeCell( + title: String, + isToggled: Boolean, + startPadding: Dp = Dimens.indentedCellStartPadding, + subtitle: String? = null, + isEnabled: Boolean = true, + background: Color = MaterialTheme.colorScheme.primary, + onCellClicked: (Boolean) -> Unit = {}, + onInfoClicked: (() -> Unit)? = null +) { SwitchComposeCell( - title = "Checkbox Title", - isEnabled = true, - isToggled = true, - onCellClicked = {}, - onInfoClicked = {} + titleView = { BaseCellTitle(title = title, style = MaterialTheme.typography.labelLarge) }, + isToggled = isToggled, + startPadding = startPadding, + subtitle = subtitle, + isEnabled = isEnabled, + background = background, + onCellClicked = onCellClicked, + onInfoClicked = onInfoClicked ) } @Composable -fun SwitchComposeCell( +fun HeaderSwitchComposeCell( title: String, isToggled: Boolean, + startPadding: Dp = Dimens.cellStartPadding, subtitle: String? = null, isEnabled: Boolean = true, - background: Color = MullvadBlue, + background: Color = MaterialTheme.colorScheme.primary, onCellClicked: (Boolean) -> Unit = {}, onInfoClicked: (() -> Unit)? = null ) { + SwitchComposeCell( + titleView = { BaseCellTitle(title = title, style = MaterialTheme.typography.titleMedium) }, + isToggled = isToggled, + startPadding = startPadding, + subtitle = subtitle, + isEnabled = isEnabled, + background = background, + onCellClicked = onCellClicked, + onInfoClicked = onInfoClicked + ) +} - val textSize = dimensionResource(id = R.dimen.text_small).value.sp +@Composable +private fun SwitchComposeCell( + titleView: @Composable () -> Unit, + isToggled: Boolean, + startPadding: Dp, + subtitle: String?, + isEnabled: Boolean, + background: Color, + onCellClicked: (Boolean) -> Unit, + onInfoClicked: (() -> Unit)? +) { BaseCell( - title = { - SwitchCellTitle( - title = title, - modifier = Modifier.alpha(if (isEnabled) AlphaActive else AlphaInactive) - ) - }, + title = titleView, subtitle = subtitle?.let { - @Composable { Text(text = it, fontSize = textSize, color = MullvadWhite60) } + @Composable { + Text( + text = it, + style = MaterialTheme.typography.labelMedium, + color = MaterialTheme.colorScheme.onSecondary + ) + } }, isRowEnabled = isEnabled, bodyView = { @@ -75,20 +140,8 @@ fun SwitchComposeCell( ) }, background = background, - onCellClicked = { onCellClicked(!isToggled) } - ) -} - -@Composable -fun SwitchCellTitle(title: String, modifier: 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() + onCellClicked = { onCellClicked(!isToggled) }, + startPadding = startPadding ) } @@ -100,7 +153,7 @@ fun SwitchCellView( onSwitchClicked: ((Boolean) -> Unit)? = null, onInfoClicked: (() -> Unit)? = null ) { - val horizontalPadding = dimensionResource(id = R.dimen.medium_padding) + val horizontalPadding = Dimens.mediumPadding val verticalPadding = 13.dp Row( modifier = modifier.wrapContentWidth().wrapContentHeight(), @@ -119,7 +172,7 @@ fun SwitchCellView( .align(Alignment.CenterVertically), painter = painterResource(id = R.drawable.icon_info), contentDescription = null, - tint = MullvadWhite + tint = MaterialTheme.colorScheme.onPrimary ) } @@ -129,10 +182,8 @@ fun SwitchCellView( @Composable fun CustomDnsCellSubtitle(isCellClickable: Boolean, modifier: Modifier) { - val textSize = dimensionResource(id = R.dimen.text_small).value - - HtmlText( - htmlFormattedString = + val spanned = + HtmlCompat.fromHtml( textResource( if (isCellClickable) { R.string.custom_dns_footer @@ -140,8 +191,12 @@ fun CustomDnsCellSubtitle(isCellClickable: Boolean, modifier: Modifier) { R.string.custom_dns_disable_mode_subtitle } ), - textSize = textSize, - textColor = MullvadWhite60.toArgb(), + FROM_HTML_MODE_COMPACT + ) + Text( + text = spanned.toAnnotatedString(), + style = MaterialTheme.typography.labelMedium, + color = MaterialTheme.colorScheme.onSecondary, modifier = modifier ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/extensions/SpannedExtensions.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/extensions/SpannedExtensions.kt new file mode 100644 index 0000000000..dfc2cf117c --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/extensions/SpannedExtensions.kt @@ -0,0 +1,24 @@ +package net.mullvad.mullvadvpn.compose.extensions + +import android.graphics.Typeface +import android.text.Spanned +import android.text.style.StyleSpan +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight + +fun Spanned.toAnnotatedString(): AnnotatedString = buildAnnotatedString { + val spanned = this@toAnnotatedString + append(spanned.toString()) + getSpans(0, spanned.length, Any::class.java).forEach { span -> + val start = getSpanStart(span) + val end = getSpanEnd(span) + when (span) { + is StyleSpan -> + when (span.style) { + Typeface.BOLD -> addStyle(SpanStyle(fontWeight = FontWeight.Bold), start, end) + } + } + } +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreen.kt index a46e5dad35..3c3044a268 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreen.kt @@ -23,8 +23,8 @@ import me.onebone.toolbar.rememberCollapsingToolbarScaffoldState import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.applist.AppData import net.mullvad.mullvadvpn.compose.cell.BaseCell +import net.mullvad.mullvadvpn.compose.cell.HeaderSwitchComposeCell import net.mullvad.mullvadvpn.compose.cell.SplitTunnelingCell -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 @@ -175,7 +175,7 @@ fun SplitTunnelingScreen( key = SplitTunnelingContentKey.SHOW_SYSTEM_APPLICATIONS, contentType = ContentType.OTHER_ITEM ) { - SwitchComposeCell( + HeaderSwitchComposeCell( title = stringResource(id = R.string.show_system_apps), isToggled = uiState.showSystemApps, onCellClicked = { newValue -> onShowSystemAppsClick(newValue) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt index e5a1032afd..1414a32899 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt @@ -16,6 +16,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.Divider import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.Text +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect @@ -48,10 +49,11 @@ import net.mullvad.mullvadvpn.compose.cell.ContentBlockersDisableModeCellSubtitl import net.mullvad.mullvadvpn.compose.cell.CustomDnsCellSubtitle import net.mullvad.mullvadvpn.compose.cell.DnsCell import net.mullvad.mullvadvpn.compose.cell.ExpandableComposeCell +import net.mullvad.mullvadvpn.compose.cell.HeaderSwitchComposeCell import net.mullvad.mullvadvpn.compose.cell.InformationComposeCell import net.mullvad.mullvadvpn.compose.cell.MtuComposeCell -import net.mullvad.mullvadvpn.compose.cell.SwitchCellTitle -import net.mullvad.mullvadvpn.compose.cell.SwitchComposeCell +import net.mullvad.mullvadvpn.compose.cell.NormalSwitchComposeCell +import net.mullvad.mullvadvpn.compose.cell.SelectableCell import net.mullvad.mullvadvpn.compose.component.CollapsableAwareToolbarScaffold import net.mullvad.mullvadvpn.compose.component.CollapsingTopBar import net.mullvad.mullvadvpn.compose.component.drawVerticalScrollbar @@ -66,9 +68,8 @@ import net.mullvad.mullvadvpn.compose.extensions.itemWithDivider import net.mullvad.mullvadvpn.compose.state.VpnSettingsUiState import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_LAST_ITEM_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_TEST_TAG -import net.mullvad.mullvadvpn.compose.theme.MullvadBlue20 -import net.mullvad.mullvadvpn.compose.theme.MullvadDarkBlue -import net.mullvad.mullvadvpn.compose.theme.MullvadGreen +import net.mullvad.mullvadvpn.compose.theme.AppTheme +import net.mullvad.mullvadvpn.compose.theme.Dimens import net.mullvad.mullvadvpn.model.SelectedObfuscation import net.mullvad.mullvadvpn.viewmodel.CustomDnsItem @@ -76,43 +77,45 @@ import net.mullvad.mullvadvpn.viewmodel.CustomDnsItem @Preview @Composable private fun PreviewVpnSettings() { - VpnSettingsScreen( - uiState = - VpnSettingsUiState.DefaultUiState( - isAutoConnectEnabled = true, - mtu = "1337", - isCustomDnsEnabled = true, - customDnsItems = listOf(CustomDnsItem("0.0.0.0", false)), - ), - onMtuCellClick = {}, - onMtuInputChange = {}, - onSaveMtuClick = {}, - onRestoreMtuClick = {}, - onCancelMtuDialogClicked = {}, - onToggleAutoConnect = {}, - onToggleLocalNetworkSharing = {}, - onToggleDnsClick = {}, - onToggleBlockAds = {}, - onToggleBlockTrackers = {}, - onToggleBlockMalware = {}, - onToggleBlockAdultContent = {}, - onToggleBlockGambling = {}, - onDnsClick = {}, - onDnsInputChange = {}, - onSaveDnsClick = {}, - onRemoveDnsClick = {}, - onCancelDnsDialogClick = {}, - onLocalNetworkSharingInfoClick = {}, - onContentsBlockersInfoClicked = {}, - onMalwareInfoClicked = {}, - onCustomDnsInfoClicked = {}, - onDismissInfoClicked = {}, - onBackClick = {}, - toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow(), - onStopEvent = {}, - onSelectObfuscationSetting = {}, - onObfuscationInfoClicked = {} - ) + AppTheme { + VpnSettingsScreen( + uiState = + VpnSettingsUiState.DefaultUiState( + isAutoConnectEnabled = true, + mtu = "1337", + isCustomDnsEnabled = true, + customDnsItems = listOf(CustomDnsItem("0.0.0.0", false)), + ), + onMtuCellClick = {}, + onMtuInputChange = {}, + onSaveMtuClick = {}, + onRestoreMtuClick = {}, + onCancelMtuDialogClick = {}, + onToggleAutoConnect = {}, + onToggleLocalNetworkSharing = {}, + onToggleDnsClick = {}, + onToggleBlockAds = {}, + onToggleBlockTrackers = {}, + onToggleBlockMalware = {}, + onToggleBlockAdultContent = {}, + onToggleBlockGambling = {}, + onDnsClick = {}, + onDnsInputChange = {}, + onSaveDnsClick = {}, + onRemoveDnsClick = {}, + onCancelDnsDialogClick = {}, + onLocalNetworkSharingInfoClick = {}, + onContentsBlockersInfoClick = {}, + onMalwareInfoClick = {}, + onCustomDnsInfoClick = {}, + onDismissInfoClick = {}, + onBackClick = {}, + toastMessagesSharedFlow = MutableSharedFlow<String>().asSharedFlow(), + onStopEvent = {}, + onSelectObfuscationSetting = {}, + onObfuscationInfoClick = {} + ) + } } @OptIn(ExperimentalFoundationApi::class) @@ -125,7 +128,7 @@ fun VpnSettingsScreen( onMtuInputChange: (String) -> Unit = {}, onSaveMtuClick: () -> Unit = {}, onRestoreMtuClick: () -> Unit = {}, - onCancelMtuDialogClicked: () -> Unit = {}, + onCancelMtuDialogClick: () -> Unit = {}, onToggleAutoConnect: (Boolean) -> Unit = {}, onToggleLocalNetworkSharing: (Boolean) -> Unit = {}, onToggleDnsClick: (Boolean) -> Unit = {}, @@ -140,15 +143,15 @@ fun VpnSettingsScreen( onRemoveDnsClick: () -> Unit = {}, onCancelDnsDialogClick: () -> Unit = {}, onLocalNetworkSharingInfoClick: () -> Unit = {}, - onContentsBlockersInfoClicked: () -> Unit = {}, - onMalwareInfoClicked: () -> Unit = {}, - onCustomDnsInfoClicked: () -> Unit = {}, - onDismissInfoClicked: () -> Unit = {}, + onContentsBlockersInfoClick: () -> Unit = {}, + onMalwareInfoClick: () -> Unit = {}, + onCustomDnsInfoClick: () -> Unit = {}, + onDismissInfoClick: () -> Unit = {}, onBackClick: () -> Unit = {}, onStopEvent: () -> Unit = {}, toastMessagesSharedFlow: SharedFlow<String>, onSelectObfuscationSetting: (selectedObfuscation: SelectedObfuscation) -> Unit = {}, - onObfuscationInfoClicked: () -> Unit = {} + onObfuscationInfoClick: () -> Unit = {} ) { val cellVerticalSpacing = dimensionResource(id = R.dimen.cell_label_vertical_padding) val cellHorizontalSpacing = dimensionResource(id = R.dimen.cell_left_padding) @@ -160,7 +163,7 @@ fun VpnSettingsScreen( onMtuValueChanged = { onMtuInputChange(it) }, onSave = { onSaveMtuClick() }, onRestoreDefaultValue = { onRestoreMtuClick() }, - onDismiss = { onCancelMtuDialogClicked() } + onDismiss = { onCancelMtuDialogClick() } ) } is VpnSettingsUiState.DnsDialogUiState -> { @@ -174,19 +177,19 @@ fun VpnSettingsScreen( ) } is VpnSettingsUiState.LocalNetworkSharingInfoDialogUiState -> { - LocalNetworkSharingInfoDialog(onDismissInfoClicked) + LocalNetworkSharingInfoDialog(onDismissInfoClick) } is VpnSettingsUiState.ContentBlockersInfoDialogUiState -> { - ContentBlockersInfoDialog(onDismissInfoClicked) + ContentBlockersInfoDialog(onDismissInfoClick) } is VpnSettingsUiState.CustomDnsInfoDialogUiState -> { - CustomDnsInfoDialog(onDismissInfoClicked) + CustomDnsInfoDialog(onDismissInfoClick) } is VpnSettingsUiState.MalwareInfoDialogUiState -> { - MalwareInfoDialog(onDismissInfoClicked) + MalwareInfoDialog(onDismissInfoClick) } is VpnSettingsUiState.ObfuscationInfoDialogUiState -> { - ObfuscationInfoDialog(onDismissInfoClicked) + ObfuscationInfoDialog(onDismissInfoClick) } else -> { // NOOP @@ -201,7 +204,7 @@ fun VpnSettingsScreen( val progress = state.toolbarState.progress CollapsableAwareToolbarScaffold( - backgroundColor = MullvadDarkBlue, + backgroundColor = MaterialTheme.colorScheme.background, modifier = Modifier.fillMaxSize(), state = state, scrollStrategy = ScrollStrategy.ExitUntilCollapsed, @@ -213,7 +216,7 @@ fun VpnSettingsScreen( whenExpanded = Alignment.BottomStart ) CollapsingTopBar( - backgroundColor = MullvadDarkBlue, + backgroundColor = MaterialTheme.colorScheme.background, onBackClicked = { onBackClick() }, title = stringResource(id = R.string.settings_vpn), progress = progress, @@ -248,7 +251,7 @@ fun VpnSettingsScreen( ) { item { Spacer(modifier = Modifier.height(cellVerticalSpacing)) - SwitchComposeCell( + HeaderSwitchComposeCell( title = stringResource(R.string.auto_connect), subtitle = stringResource(id = R.string.auto_connect_footer), isToggled = uiState.isAutoConnectEnabled, @@ -258,7 +261,7 @@ fun VpnSettingsScreen( } item { Spacer(modifier = Modifier.height(cellVerticalSpacing)) - SwitchComposeCell( + HeaderSwitchComposeCell( title = stringResource(R.string.local_network_sharing), isToggled = uiState.isAllowLanEnabled, isEnabled = true, @@ -276,63 +279,68 @@ fun VpnSettingsScreen( title = stringResource(R.string.dns_content_blockers_title), isExpanded = !expandContentBlockersState, isEnabled = !uiState.isCustomDnsEnabled, - onInfoClicked = { onContentsBlockersInfoClicked() }, + onInfoClicked = { onContentsBlockersInfoClick() }, onCellClicked = { expandContentBlockersState = !expandContentBlockersState } ) } if (expandContentBlockersState) { itemWithDivider { - SwitchComposeCell( + NormalSwitchComposeCell( title = stringResource(R.string.block_ads_title), isToggled = uiState.contentBlockersOptions.blockAds, isEnabled = !uiState.isCustomDnsEnabled, onCellClicked = { onToggleBlockAds(it) }, - background = MullvadBlue20 + background = MaterialTheme.colorScheme.secondaryContainer, + startPadding = Dimens.indentedCellStartPadding ) } itemWithDivider { - SwitchComposeCell( + NormalSwitchComposeCell( title = stringResource(R.string.block_trackers_title), isToggled = uiState.contentBlockersOptions.blockTrackers, isEnabled = !uiState.isCustomDnsEnabled, onCellClicked = { onToggleBlockTrackers(it) }, - background = MullvadBlue20 + background = MaterialTheme.colorScheme.secondaryContainer, + startPadding = Dimens.indentedCellStartPadding ) } itemWithDivider { - SwitchComposeCell( + NormalSwitchComposeCell( title = stringResource(R.string.block_malware_title), isToggled = uiState.contentBlockersOptions.blockMalware, isEnabled = !uiState.isCustomDnsEnabled, onCellClicked = { onToggleBlockMalware(it) }, - onInfoClicked = { onMalwareInfoClicked() }, - background = MullvadBlue20 + onInfoClicked = { onMalwareInfoClick() }, + background = MaterialTheme.colorScheme.secondaryContainer, + startPadding = Dimens.indentedCellStartPadding ) } itemWithDivider { - SwitchComposeCell( + NormalSwitchComposeCell( title = stringResource(R.string.block_gambling_title), isToggled = uiState.contentBlockersOptions.blockGambling, isEnabled = !uiState.isCustomDnsEnabled, onCellClicked = { onToggleBlockGambling(it) }, - background = MullvadBlue20 + background = MaterialTheme.colorScheme.secondaryContainer, + startPadding = Dimens.indentedCellStartPadding ) } itemWithDivider { - SwitchComposeCell( + NormalSwitchComposeCell( title = stringResource(R.string.block_adult_content_title), isToggled = uiState.contentBlockersOptions.blockAdultContent, isEnabled = !uiState.isCustomDnsEnabled, onCellClicked = { onToggleBlockAdultContent(it) }, - background = MullvadBlue20 + background = MaterialTheme.colorScheme.secondaryContainer, + startPadding = Dimens.indentedCellStartPadding ) } if (uiState.isCustomDnsEnabled) { item { ContentBlockersDisableModeCellSubtitle( - Modifier.background(MullvadDarkBlue) + Modifier.background(MaterialTheme.colorScheme.secondary) .padding( start = cellHorizontalSpacing, top = topPadding, @@ -348,66 +356,39 @@ fun VpnSettingsScreen( Spacer(modifier = Modifier.height(cellVerticalSpacing)) InformationComposeCell( title = stringResource(R.string.obfuscation_title), - onInfoClicked = { onObfuscationInfoClicked() } + onInfoClicked = { onObfuscationInfoClick() } ) } itemWithDivider { - BaseCell( - onCellClicked = { onSelectObfuscationSetting(SelectedObfuscation.Auto) }, - title = { - SwitchCellTitle( - title = stringResource(id = R.string.automatic), - ) - }, - background = - if (uiState.selectedObfuscation == SelectedObfuscation.Auto) { - MullvadGreen - } else { - MullvadBlue20 - } + SelectableCell( + title = stringResource(id = R.string.automatic), + isSelected = uiState.selectedObfuscation == SelectedObfuscation.Auto, + onCellClicked = { onSelectObfuscationSetting(SelectedObfuscation.Auto) } ) } itemWithDivider { - BaseCell( - onCellClicked = { onSelectObfuscationSetting(SelectedObfuscation.Udp2Tcp) }, - title = { - SwitchCellTitle( - title = stringResource(id = R.string.obfuscation_on_udp_over_tcp), - ) - }, - background = - if (uiState.selectedObfuscation == SelectedObfuscation.Udp2Tcp) { - MullvadGreen - } else { - MullvadBlue20 - } + SelectableCell( + title = stringResource(id = R.string.obfuscation_on_udp_over_tcp), + isSelected = uiState.selectedObfuscation == SelectedObfuscation.Udp2Tcp, + onCellClicked = { onSelectObfuscationSetting(SelectedObfuscation.Udp2Tcp) } ) } itemWithDivider { - BaseCell( - onCellClicked = { onSelectObfuscationSetting(SelectedObfuscation.Off) }, - title = { - SwitchCellTitle( - title = stringResource(id = R.string.off), - ) - }, - background = - if (uiState.selectedObfuscation == SelectedObfuscation.Off) { - MullvadGreen - } else { - MullvadBlue20 - } + SelectableCell( + title = stringResource(id = R.string.off), + isSelected = uiState.selectedObfuscation == SelectedObfuscation.Off, + onCellClicked = { onSelectObfuscationSetting(SelectedObfuscation.Off) } ) } item { Spacer(modifier = Modifier.height(cellVerticalSpacing)) - SwitchComposeCell( + HeaderSwitchComposeCell( title = stringResource(R.string.enable_custom_dns), isToggled = uiState.isCustomDnsEnabled, isEnabled = uiState.contentBlockersOptions.isAnyBlockerEnabled().not(), onCellClicked = { newValue -> onToggleDnsClick(newValue) }, - onInfoClicked = { onCustomDnsInfoClicked() } + onInfoClicked = { onCustomDnsInfoClick() } ) } @@ -434,7 +415,7 @@ fun VpnSettingsScreen( }, bodyView = {}, subtitle = null, - background = MullvadBlue20, + background = MaterialTheme.colorScheme.secondaryContainer, startPadding = biggerPadding, ) } @@ -444,7 +425,7 @@ fun VpnSettingsScreen( CustomDnsCellSubtitle( isCellClickable = uiState.contentBlockersOptions.isAnyBlockerEnabled().not(), modifier = - Modifier.background(MullvadDarkBlue) + Modifier.background(MaterialTheme.colorScheme.secondary) .testTag(LAZY_LIST_LAST_ITEM_TEST_TAG) .padding( start = cellHorizontalSpacing, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/Theme.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/Theme.kt index 8749c7cb55..9b42dbdb3c 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/Theme.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/Theme.kt @@ -11,6 +11,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import net.mullvad.mullvadvpn.compose.theme.dimensions.Dimensions import net.mullvad.mullvadvpn.compose.theme.dimensions.defaultDimensions @@ -37,6 +38,12 @@ private val MullvadTypography = color = MullvadWhite60, fontSize = TypeScale.TextSmall, fontWeight = FontWeight.SemiBold + ), + labelLarge = + TextStyle( + fontWeight = FontWeight.Normal, + letterSpacing = TextUnit.Unspecified, + fontSize = TypeScale.TextMedium ) ) @@ -46,10 +53,13 @@ private val MullvadColorPalette = secondary = MullvadDarkBlue, tertiary = MullvadRed, background = MullvadDarkBlue, - onBackground = MullvadWhite, + surface = MullvadGreen, primaryContainer = MullvadBlue40, + secondaryContainer = MullvadBlue20, + onBackground = MullvadWhite, onSurfaceVariant = MullvadWhite, - onPrimary = MullvadWhite + onPrimary = MullvadWhite, + onSecondary = MullvadWhite60 ) val Shapes = diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/dimensions/Dimensions.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/dimensions/Dimensions.kt index 57c9f173a9..04236760d3 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/dimensions/Dimensions.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/dimensions/Dimensions.kt @@ -12,10 +12,11 @@ data class Dimensions( val loadingSpinnerSize: Dp = 24.dp, val loadingSpinnerStrokeWidth: Dp = 3.dp, val loadingSpinnerPadding: Dp = 12.dp, - val cellLeftPadding: Dp = 22.dp, - val cellRightPadding: Dp = 16.dp, + val cellStartPadding: Dp = 22.dp, + val cellEndPadding: Dp = 16.dp, val listIconSize: Dp = 24.dp, - val progressIndicatorSize: Dp = 60.dp + val progressIndicatorSize: Dp = 60.dp, + val indentedCellStartPadding: Dp = 38.dp ) val defaultDimensions = Dimensions() diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/typeface/TypeScale.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/typeface/TypeScale.kt index 1098dbdaf2..eecac666f9 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/typeface/TypeScale.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/theme/typeface/TypeScale.kt @@ -13,5 +13,6 @@ import androidx.compose.ui.unit.sp internal object TypeScale { val TextBig = 24.sp val TextMediumPlus = 18.sp + val TextMedium = 16.sp val TextSmall = 13.sp } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/VpnSettingsFragment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/VpnSettingsFragment.kt index 79347ad3a9..a299ce357a 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/VpnSettingsFragment.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/fragment/VpnSettingsFragment.kt @@ -32,7 +32,7 @@ class VpnSettingsFragment : BaseFragment() { onMtuInputChange = vm::onMtuInputChange, onSaveMtuClick = vm::onSaveMtuClick, onRestoreMtuClick = vm::onRestoreMtuClick, - onCancelMtuDialogClicked = vm::onCancelDialogClick, + onCancelMtuDialogClick = vm::onCancelDialogClick, onToggleAutoConnect = vm::onToggleAutoConnect, onToggleLocalNetworkSharing = vm::onToggleLocalNetworkSharing, onToggleDnsClick = vm::onToggleDnsClick, @@ -47,15 +47,15 @@ class VpnSettingsFragment : BaseFragment() { onRemoveDnsClick = vm::onRemoveDnsClick, onCancelDnsDialogClick = vm::onCancelDialogClick, onLocalNetworkSharingInfoClick = vm::onLocalNetworkSharingInfoClick, - onContentsBlockersInfoClicked = vm::onContentsBlockerInfoClick, - onCustomDnsInfoClicked = vm::onCustomDnsInfoClick, - onMalwareInfoClicked = vm::onMalwareInfoClick, - onDismissInfoClicked = vm::onDismissInfoClick, - onBackClick = { activity?.onBackPressed() }, + onContentsBlockersInfoClick = vm::onContentsBlockerInfoClick, + onCustomDnsInfoClick = vm::onCustomDnsInfoClick, + onMalwareInfoClick = vm::onMalwareInfoClick, + onDismissInfoClick = vm::onDismissInfoClick, + onBackClick = { activity?.onBackPressedDispatcher?.onBackPressed() }, onStopEvent = vm::onStopEvent, toastMessagesSharedFlow = vm.toastMessages, onSelectObfuscationSetting = vm::onSelectObfuscationSetting, - onObfuscationInfoClicked = vm::onObfuscationInfoClicked + onObfuscationInfoClick = vm::onObfuscationInfoClick ) } } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt index 9943ae60b6..77d95823a6 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt @@ -301,7 +301,7 @@ class VpnSettingsViewModel( } } - fun onObfuscationInfoClicked() { + fun onObfuscationInfoClick() { dialogState.update { VpnSettingsDialogState.ObfuscationInfoDialog } } |
