diff options
55 files changed, 286 insertions, 307 deletions
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/location/SelectLocationScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/location/SelectLocationScreenTest.kt index 3b259154a4..e03786aef3 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/location/SelectLocationScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/location/SelectLocationScreenTest.kt @@ -123,7 +123,8 @@ class SelectLocationScreenTest { filterChips = emptyList(), multihopEnabled = false, relayListType = RelayListType.EXIT, - isTopBarActionsEnabled = true, + isSearchButtonEnabled = true, + isFilterButtonEnabled = true, ) ) ) @@ -157,7 +158,8 @@ class SelectLocationScreenTest { filterChips = emptyList(), multihopEnabled = false, relayListType = RelayListType.EXIT, - isTopBarActionsEnabled = true, + isSearchButtonEnabled = true, + isFilterButtonEnabled = true, ) ) ) @@ -188,7 +190,8 @@ class SelectLocationScreenTest { filterChips = emptyList(), multihopEnabled = false, relayListType = RelayListType.EXIT, - isTopBarActionsEnabled = true, + isSearchButtonEnabled = true, + isFilterButtonEnabled = true, ) ), onSelectRelay = mockedOnSelectRelay, @@ -221,11 +224,11 @@ class SelectLocationScreenTest { state = Lc.Content( SelectLocationUiState( - // searchTerm = "", filterChips = emptyList(), multihopEnabled = false, relayListType = RelayListType.EXIT, - isTopBarActionsEnabled = true, + isSearchButtonEnabled = true, + isFilterButtonEnabled = true, ) ), onSelectRelay = mockedOnSelectRelay, @@ -260,7 +263,8 @@ class SelectLocationScreenTest { filterChips = emptyList(), multihopEnabled = false, relayListType = RelayListType.EXIT, - isTopBarActionsEnabled = true, + isSearchButtonEnabled = true, + isFilterButtonEnabled = true, ) ), onSelectRelay = mockedOnSelectRelay, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/button/MullvadButton.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/button/MullvadButton.kt index 7160f16ba8..250ba7da99 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/button/MullvadButton.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/button/MullvadButton.kt @@ -187,7 +187,7 @@ fun PrimaryTextButton( enabled = isEnabled, contentPadding = if (hasIcon) { - PaddingValues(vertical = Dimens.buttonVerticalPadding) + PaddingValues(vertical = Dimens.buttonSpacing) } else { ButtonDefaults.TextButtonContentPadding }, @@ -221,7 +221,7 @@ private fun BaseButton( enabled = isEnabled, contentPadding = if (hasIcon) { - PaddingValues(vertical = Dimens.buttonVerticalPadding) + PaddingValues(vertical = Dimens.buttonSpacing) } else { ButtonDefaults.ContentPadding }, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CheckboxCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CheckboxCell.kt index e1b0c1a5d5..7bf7a2262a 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CheckboxCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CheckboxCell.kt @@ -3,11 +3,9 @@ package net.mullvad.mullvadvpn.compose.cell import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -33,8 +31,8 @@ internal fun CheckboxCell( checked: Boolean, enabled: Boolean = true, onCheckedChange: (Boolean) -> Unit, - background: Color = MaterialTheme.colorScheme.surfaceContainerLow, - startPadding: Dp = Dimens.mediumPadding, + background: Color = MaterialTheme.colorScheme.surfaceContainerHighest, + startPadding: Dp = Dimens.smallPadding, endPadding: Dp = Dimens.cellEndPadding, minHeight: Dp = Dimens.cellHeight, ) { @@ -50,8 +48,6 @@ internal fun CheckboxCell( ) { MullvadCheckbox(checked = checked, onCheckedChange = onCheckedChange) - Spacer(modifier = Modifier.size(Dimens.mediumPadding)) - Text( text = title, style = MaterialTheme.typography.labelLarge, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CustomPortCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CustomPortCell.kt index 2befd75123..3c0947968f 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CustomPortCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CustomPortCell.kt @@ -83,7 +83,7 @@ fun CustomPortCell( if (isSelected) { MaterialTheme.colorScheme.selected } else { - MaterialTheme.colorScheme.surfaceContainerLow + MaterialTheme.colorScheme.surfaceContainerHighest } ) .padding(start = Dimens.cellStartPadding) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/DnsCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/DnsCell.kt index cc9ed30d9d..23f8145292 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/DnsCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/DnsCell.kt @@ -70,7 +70,7 @@ fun DnsCell( ) }, onCellClicked = { onClick.invoke() }, - background = MaterialTheme.colorScheme.surfaceContainerLow, + background = MaterialTheme.colorScheme.surfaceContainerHighest, startPadding = startPadding, modifier = modifier, ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/FilterRow.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/FilterRow.kt index ab708e77d1..23bbd38b2f 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/FilterRow.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/FilterRow.kt @@ -35,6 +35,7 @@ private fun PreviewFilterCell() { @Composable fun FilterRow( filters: List<FilterChip>, + modifier: Modifier = Modifier, showTitle: Boolean = true, onRemoveOwnershipFilter: () -> Unit, onRemoveProviderFilter: () -> Unit, @@ -43,7 +44,8 @@ fun FilterRow( Row( verticalAlignment = Alignment.CenterVertically, modifier = - Modifier.padding(horizontal = Dimens.searchFieldHorizontalPadding) + modifier + .padding(horizontal = Dimens.searchFieldHorizontalPadding) .fillMaxWidth() .horizontalScroll(scrollState), horizontalArrangement = Arrangement.spacedBy(Dimens.chipSpace), diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt index 34b3c097e4..c24d975e3c 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt @@ -68,7 +68,7 @@ fun ObfuscationModeCell( modifier .height(IntrinsicSize.Min) .fillMaxWidth() - .background(MaterialTheme.colorScheme.surfaceContainerLow) + .background(MaterialTheme.colorScheme.surfaceContainerHighest) .let { if (testTag != null) it.testTag(testTag) else it } .semantics { selected = isSelected } ) { diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt index d390e92f6a..9761f7891e 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt @@ -53,7 +53,7 @@ fun SelectableCell( titleStyle: TextStyle = MaterialTheme.typography.labelLarge, startPadding: Dp = Dimens.cellStartPadding, selectedColor: Color = MaterialTheme.colorScheme.selected, - backgroundColor: Color = MaterialTheme.colorScheme.surfaceContainerLow, + backgroundColor: Color = MaterialTheme.colorScheme.surfaceContainerHighest, onSelectedColor: Color = MaterialTheme.colorScheme.onSelected, onBackgroundColor: Color = MaterialTheme.colorScheme.onSurface, onCellClicked: () -> Unit = {}, 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 11904157e9..96bf9d5c90 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 @@ -73,7 +73,7 @@ fun SplitTunnelingCell( isSelected: Boolean, enabled: Boolean, modifier: Modifier = Modifier, - backgroundColor: Color = MaterialTheme.colorScheme.surfaceContainerHigh, + backgroundColor: Color = MaterialTheme.colorScheme.surfaceContainerHighest, onResolveIcon: (String) -> Drawable?, onCellClicked: () -> Unit, ) { 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 8bbd729edd..bdf383c74e 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 @@ -59,7 +59,7 @@ fun NormalSwitchComposeCell( modifier: Modifier = Modifier, startPadding: Dp = Dimens.indentedCellStartPadding, isEnabled: Boolean = true, - background: Color = MaterialTheme.colorScheme.surfaceContainerLow, + background: Color = MaterialTheme.colorScheme.surfaceContainerHighest, onBackground: Color = MaterialTheme.colorScheme.onSurface, onCellClicked: (Boolean) -> Unit, onInfoClicked: (() -> Unit)? = null, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/CircularProgressIndicator.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/CircularProgressIndicator.kt index 8d3def6425..aae37c3f0b 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/CircularProgressIndicator.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/CircularProgressIndicator.kt @@ -41,6 +41,7 @@ fun MullvadCircularProgressIndicatorLarge( ) { CircularProgressIndicator( modifier + .padding(Dimens.tinyPadding) .size(Dimens.circularProgressBarLargeSize) .testTag(CIRCULAR_PROGRESS_INDICATOR_TEST_TAG), color, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/EmptyRelayListText.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/EmptyRelayListText.kt index 5e61257d28..eb2fbf7cab 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/EmptyRelayListText.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/EmptyRelayListText.kt @@ -13,7 +13,7 @@ import net.mullvad.mullvadvpn.lib.theme.Dimens fun EmptyRelayListText() { Text( text = stringResource(R.string.no_locations_found), - modifier = Modifier.padding(Dimens.screenVerticalMargin), + modifier = Modifier.padding(Dimens.cellVerticalSpacing), style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/FeatureChip.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/FeatureChip.kt index be1139a44b..d82ece524d 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/FeatureChip.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/FeatureChip.kt @@ -34,7 +34,7 @@ fun MullvadFeatureChip( shape = MaterialTheme.shapes.chipShape, colors = FilterChipDefaults.filterChipColors( - disabledContainerColor = containerColor, + containerColor = containerColor, disabledLabelColor = labelColor, labelColor = labelColor, iconColor = iconColor, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/LocationsEmptyText.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/LocationsEmptyText.kt index bf3e36f57e..ecdf446291 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/LocationsEmptyText.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/LocationsEmptyText.kt @@ -19,6 +19,6 @@ fun LocationsEmptyText(searchTerm: String) { color = MaterialTheme.colorScheme.onSurfaceVariant, maxLines = 2, overflow = TextOverflow.Ellipsis, - modifier = Modifier.padding(Dimens.screenVerticalMargin), + modifier = Modifier.padding(Dimens.cellVerticalSpacing), ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/PlayPayment.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/PlayPayment.kt index 6c23a4646a..acd8f00443 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/PlayPayment.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/PlayPayment.kt @@ -49,7 +49,7 @@ private fun PreviewPlayPaymentPaymentAvailable() { ), onPurchaseBillingProductClick = {}, onInfoClick = {}, - modifier = Modifier.padding(Dimens.screenVerticalMargin), + modifier = Modifier.padding(Dimens.screenBottomMargin), ) } } @@ -64,7 +64,7 @@ private fun PreviewPlayPaymentLoading() { billingPaymentState = PaymentState.Loading, onPurchaseBillingProductClick = {}, onInfoClick = {}, - modifier = Modifier.padding(Dimens.screenVerticalMargin), + modifier = Modifier.padding(Dimens.screenBottomMargin), ) } } @@ -89,7 +89,7 @@ private fun PreviewPlayPaymentPaymentPending() { ), onPurchaseBillingProductClick = {}, onInfoClick = {}, - modifier = Modifier.padding(Dimens.screenVerticalMargin), + modifier = Modifier.padding(Dimens.screenBottomMargin), ) } } @@ -114,7 +114,7 @@ private fun PreviewPlayPaymentVerificationInProgress() { ), onPurchaseBillingProductClick = {}, onInfoClick = {}, - modifier = Modifier.padding(Dimens.screenVerticalMargin), + modifier = Modifier.padding(Dimens.screenBottomMargin), ) } } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt index fc2b02c97e..45d39f4b8e 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt @@ -169,6 +169,7 @@ fun ScaffoldWithMediumTopBar( actions: @Composable RowScope.() -> Unit = {}, scrollbarColor: Color = MaterialTheme.colorScheme.onSurface.copy(alpha = AlphaScrollbar), snackbarHostState: SnackbarHostState = remember { SnackbarHostState() }, + bottomBar: @Composable () -> Unit = {}, content: @Composable (modifier: Modifier) -> Unit, ) { val appBarState = rememberTopAppBarState() @@ -186,6 +187,7 @@ fun ScaffoldWithMediumTopBar( scrollBehavior = scrollBehavior, ) }, + bottomBar = bottomBar, snackbarHost = { SnackbarHost( snackbarHostState, @@ -241,7 +243,7 @@ fun ScaffoldWithLargeTopBarAndButton( modifier = Modifier.padding( horizontal = Dimens.sideMargin, - vertical = Dimens.screenVerticalMargin, + vertical = Dimens.screenBottomMargin, ), trailingIcon = { Icon( @@ -270,6 +272,7 @@ fun ScaffoldWithSmallTopBar( navigationIcon: @Composable () -> Unit = {}, actions: @Composable RowScope.() -> Unit = {}, snackbarHostState: SnackbarHostState = remember { SnackbarHostState() }, + bottomBar: @Composable () -> Unit = {}, content: @Composable (modifier: Modifier) -> Unit, ) { Scaffold( @@ -287,6 +290,7 @@ fun ScaffoldWithSmallTopBar( snackbar = { snackbarData -> MullvadSnackbar(snackbarData = snackbarData) }, ) }, + bottomBar = bottomBar, content = { content(Modifier.fillMaxSize().padding(it)) }, ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/TopBar.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/TopBar.kt index f8847150d4..2f246e5553 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/TopBar.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/TopBar.kt @@ -132,7 +132,7 @@ fun MullvadTopBar( BoxWithConstraints { val logoTextPainter = painterResource(id = R.drawable.logo_text) val logoHeight = Dimens.mediumPadding - val logoStartEndPadding = Dimens.mediumPadding + val logoStartEndPadding = Dimens.smallPadding val shouldShowText = remember(maxWidth) { @@ -149,7 +149,7 @@ fun MullvadTopBar( tint = iconTintColor, contentDescription = null, // No meaningful user info or action. modifier = - Modifier.padding(horizontal = Dimens.mediumPadding) + Modifier.padding(horizontal = logoStartEndPadding) .height(logoHeight), ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/SaveApiAccessMethodDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/SaveApiAccessMethodDialog.kt index a700c6cdec..528956286c 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/SaveApiAccessMethodDialog.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/SaveApiAccessMethodDialog.kt @@ -20,7 +20,7 @@ import com.ramcosta.composedestinations.result.ResultBackNavigator import com.ramcosta.composedestinations.spec.DestinationStyle import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.button.PrimaryButton -import net.mullvad.mullvadvpn.compose.component.MullvadCircularProgressIndicatorMedium +import net.mullvad.mullvadvpn.compose.component.MullvadCircularProgressIndicatorLarge import net.mullvad.mullvadvpn.compose.preview.SaveApiAccessMethodUiStatePreviewParameterProvider import net.mullvad.mullvadvpn.compose.state.SaveApiAccessMethodUiState import net.mullvad.mullvadvpn.compose.state.TestApiAccessMethodState @@ -90,18 +90,14 @@ fun SaveApiAccessMethodDialog( painter = painterResource( id = - if ( - testingState is TestApiAccessMethodState.Result.Successful - ) { + if (testingState is TestApiAccessMethodState.Result.Successful) R.drawable.icon_success - } else { - R.drawable.icon_fail - } + else R.drawable.icon_fail ), contentDescription = null, ) TestApiAccessMethodState.Testing -> - MullvadCircularProgressIndicatorMedium( + MullvadCircularProgressIndicatorLarge( modifier = Modifier.testTag(SAVE_API_ACCESS_METHOD_LOADING_SPINNER_TEST_TAG) ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/info/InfoConfirmationDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/info/InfoConfirmationDialog.kt index 0f314dc233..c412fd3800 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/info/InfoConfirmationDialog.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/info/InfoConfirmationDialog.kt @@ -149,7 +149,7 @@ fun <T> InfoConfirmationDialog( null }, confirmButton = { - Column(verticalArrangement = Arrangement.spacedBy(Dimens.buttonVerticalPadding)) { + Column(verticalArrangement = Arrangement.spacedBy(Dimens.buttonSpacing)) { PrimaryButton( modifier = Modifier.fillMaxWidth(), text = confirmButtonTitle, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/payment/PaymentDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/payment/PaymentDialog.kt index 9e64e0f037..bf9de7e449 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/payment/PaymentDialog.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/payment/PaymentDialog.kt @@ -19,7 +19,7 @@ import com.ramcosta.composedestinations.result.ResultBackNavigator import com.ramcosta.composedestinations.spec.DestinationStyle import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.button.PrimaryButton -import net.mullvad.mullvadvpn.compose.component.MullvadCircularProgressIndicatorMedium +import net.mullvad.mullvadvpn.compose.component.MullvadCircularProgressIndicatorLarge import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle import net.mullvad.mullvadvpn.lib.payment.model.ProductId import net.mullvad.mullvadvpn.lib.theme.AppTheme @@ -169,7 +169,7 @@ fun PaymentDialog( painter = painterResource(id = R.drawable.icon_fail), contentDescription = null, ) - PaymentDialogIcon.LOADING -> MullvadCircularProgressIndicatorMedium() + PaymentDialogIcon.LOADING -> MullvadCircularProgressIndicatorLarge() else -> {} } }, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/SelectLocationsUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/SelectLocationsUiStatePreviewParameterProvider.kt index 99bb6993ef..5b4028e6ca 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/SelectLocationsUiStatePreviewParameterProvider.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/SelectLocationsUiStatePreviewParameterProvider.kt @@ -17,7 +17,8 @@ class SelectLocationsUiStatePreviewParameterProvider : filterChips = emptyList(), multihopEnabled = false, relayListType = RelayListType.EXIT, - isTopBarActionsEnabled = true, + isSearchButtonEnabled = true, + isFilterButtonEnabled = true, ) ), Lc.Content( @@ -29,7 +30,8 @@ class SelectLocationsUiStatePreviewParameterProvider : ), multihopEnabled = false, relayListType = RelayListType.EXIT, - isTopBarActionsEnabled = true, + isSearchButtonEnabled = true, + isFilterButtonEnabled = true, ) ), Lc.Content( @@ -37,7 +39,8 @@ class SelectLocationsUiStatePreviewParameterProvider : filterChips = emptyList(), multihopEnabled = true, relayListType = RelayListType.ENTRY, - isTopBarActionsEnabled = true, + isSearchButtonEnabled = true, + isFilterButtonEnabled = true, ) ), Lc.Content( @@ -49,7 +52,8 @@ class SelectLocationsUiStatePreviewParameterProvider : ), multihopEnabled = true, relayListType = RelayListType.ENTRY, - isTopBarActionsEnabled = true, + isSearchButtonEnabled = true, + isFilterButtonEnabled = true, ) ), ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreen.kt index 584432f6a6..dfd1f2d8f7 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreen.kt @@ -165,7 +165,7 @@ fun AccountScreen( modifier .animateContentSize() .padding(horizontal = Dimens.sideMargin) - .padding(bottom = Dimens.screenVerticalMargin), + .padding(bottom = Dimens.screenBottomMargin), ) { Column( verticalArrangement = Arrangement.spacedBy(Dimens.accountRowSpacing), diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AutoConnectAndLockdownModeScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AutoConnectAndLockdownModeScreen.kt index ceddf9dc99..8f3b07806a 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AutoConnectAndLockdownModeScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AutoConnectAndLockdownModeScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.OpenInNew import androidx.compose.material.icons.filled.ChevronLeft import androidx.compose.material.icons.filled.ChevronRight import androidx.compose.material3.Icon @@ -52,8 +53,9 @@ import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.navigation.DestinationsNavigator import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.R +import net.mullvad.mullvadvpn.compose.button.PrimaryButton import net.mullvad.mullvadvpn.compose.component.NavigateBackIconButton -import net.mullvad.mullvadvpn.compose.component.ScaffoldWithLargeTopBarAndButton +import net.mullvad.mullvadvpn.compose.component.ScaffoldWithMediumTopBar import net.mullvad.mullvadvpn.compose.transitions.SlideInFromRightTransition import net.mullvad.mullvadvpn.lib.common.util.openVpnSettings import net.mullvad.mullvadvpn.lib.theme.AppTheme @@ -67,7 +69,7 @@ import net.mullvad.mullvadvpn.util.appendHideNavOnPlayBuild @Preview @Composable private fun PreviewAutoConnectAndLockdownModeScreen() { - AppTheme { AutoConnectAndLockdownModeScreen({}) } + AppTheme { AutoConnectAndLockdownModeScreen {} } } @Destination<RootGraph>(style = SlideInFromRightTransition::class) @@ -79,11 +81,27 @@ fun AutoConnectAndLockdownMode(navigator: DestinationsNavigator) { @Composable fun AutoConnectAndLockdownModeScreen(onBackClick: () -> Unit) { val context = LocalContext.current - ScaffoldWithLargeTopBarAndButton( + ScaffoldWithMediumTopBar( appBarTitle = stringResource(id = R.string.auto_connect_and_lockdown_mode), navigationIcon = { NavigateBackIconButton(onNavigateBack = onBackClick) }, - buttonTitle = stringResource(id = R.string.go_to_vpn_settings), - onButtonClick = { context.openVpnSettings() }, + bottomBar = { + PrimaryButton( + text = stringResource(id = R.string.go_to_vpn_settings), + onClick = { context.openVpnSettings() }, + modifier = + Modifier.padding( + horizontal = Dimens.sideMargin, + vertical = Dimens.screenBottomMargin, + ), + trailingIcon = { + Icon( + imageVector = Icons.AutoMirrored.Filled.OpenInNew, + tint = MaterialTheme.colorScheme.onPrimary, + contentDescription = null, + ) + }, + ) + }, content = { modifier -> Column(modifier = modifier, verticalArrangement = Arrangement.Center) { val pagerState = rememberPagerState(pageCount = { PAGES.entries.size }) @@ -176,7 +194,8 @@ private fun ConstraintLayoutScope.AutoConnectCarousel( text = annotatedTopText, ) Image( - modifier = Modifier.padding(top = Dimens.topPadding, bottom = Dimens.bottomPadding), + modifier = + Modifier.padding(top = Dimens.smallPadding, bottom = Dimens.bottomPadding), painter = painterResource(id = page.image), contentDescription = null, ) @@ -224,7 +243,7 @@ private fun ConstraintLayoutScope.PageIndicator( pager: ConstrainedLayoutReference, ) { Row( - Modifier.wrapContentHeight().fillMaxWidth().padding(top = Dimens.topPadding).constrainAs( + Modifier.wrapContentHeight().fillMaxWidth().padding(top = Dimens.mediumSpacer).constrainAs( pageIndicatorRef ) { top.linkTo(pager.bottom) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt index 26c08e4841..3533cde305 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt @@ -49,6 +49,7 @@ import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.layout import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.LocalWindowInfo @@ -408,7 +409,9 @@ private fun Content( onNavigateToFeature: (FeatureIndicator) -> Unit, onClickShowWireguardPortSettings: () -> Unit, ) { - val screenHeight = LocalWindowInfo.current.containerSize.height.dp + val screenHeight = + with(LocalDensity.current) { LocalWindowInfo.current.containerSize.height.toDp() } + val indicatorPercentOffset = if (screenHeight < SCREEN_HEIGHT_THRESHOLD) SHORT_SCREEN_INDICATOR_BIAS else TALL_SCREEN_INDICATOR_BIAS @@ -699,14 +702,9 @@ private fun ButtonPanel( action.invoke() } } - Column(modifier = Modifier.padding(vertical = Dimens.tinyPadding)) { + Column(modifier = Modifier.padding(top = Dimens.tinyPadding)) { SwitchLocationButton( - text = - if (state.selectedRelayItemTitle != null) { - state.selectedRelayItemTitle - } else { - stringResource(id = R.string.switch_location) - }, + text = state.selectedRelayItemTitle ?: stringResource(id = R.string.switch_location), onSwitchLocation = onSwitchLocationClick, reconnectClick = { handleThrottledAction { @@ -722,7 +720,7 @@ private fun ButtonPanel( .focusRequester(selectButtonFocusRequester), reconnectButtonTestTag = RECONNECT_BUTTON_TEST_TAG, ) - Spacer(Modifier.height(Dimens.buttonVerticalPadding)) + Spacer(Modifier.height(Dimens.buttonSpacing)) ConnectionButton( modifier = Modifier.fillMaxWidth().testTag(CONNECT_BUTTON_TEST_TAG), diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/CustomListsScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/CustomListsScreen.kt index 7bac85733c..3d50800137 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/CustomListsScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/CustomListsScreen.kt @@ -177,7 +177,7 @@ private fun LazyListScope.empty() { item(contentType = ContentType.EMPTY_TEXT) { Text( text = stringResource(R.string.no_custom_lists_available), - modifier = Modifier.padding(Dimens.screenVerticalMargin), + modifier = Modifier.padding(Dimens.mediumPadding), style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceListScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceListScreen.kt index fee2b70973..f711938bca 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceListScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceListScreen.kt @@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -145,11 +144,15 @@ fun DeviceListScreen( onAccountClicked = null, snackbarHostState = snackbarHostState, ) { - Column(modifier = Modifier.fillMaxSize().padding(it)) { + Column( + modifier = + Modifier.fillMaxSize().padding(it).padding(bottom = Dimens.screenBottomMargin) + ) { val scrollState = rememberScrollState() Column( modifier = Modifier.drawVerticalScrollbar(scrollState, MaterialTheme.colorScheme.onSurface) + .padding(top = Dimens.screenTopMargin) .verticalScroll(scrollState) .weight(1f) .fillMaxWidth() @@ -221,25 +224,17 @@ private fun ColumnScope.DeviceListHeader(state: DeviceListUiState) { } ), contentDescription = null, // No meaningful user info or action. - modifier = - Modifier.align(Alignment.CenterHorizontally) - .padding(top = Dimens.iconFailSuccessTopMargin) - .size(Dimens.bigIconSize), + modifier = Modifier.align(Alignment.CenterHorizontally), ) is DeviceListUiState.Error -> Image( painter = painterResource(id = R.drawable.icon_fail), contentDescription = null, // No meaningful user info or action. - modifier = - Modifier.align(Alignment.CenterHorizontally) - .padding(top = Dimens.iconFailSuccessTopMargin) - .size(Dimens.bigIconSize), + modifier = Modifier.align(Alignment.CenterHorizontally), ) DeviceListUiState.Loading -> MullvadCircularProgressIndicatorLarge( - modifier = - Modifier.align(Alignment.CenterHorizontally) - .padding(top = Dimens.iconFailSuccessTopMargin) + modifier = Modifier.align(Alignment.CenterHorizontally) ) } @@ -259,7 +254,7 @@ private fun ColumnScope.DeviceListHeader(state: DeviceListUiState) { Modifier.padding( start = Dimens.sideMargin, end = Dimens.sideMargin, - top = Dimens.screenVerticalMargin, + top = Dimens.screenTopMargin, ), ) @@ -301,7 +296,6 @@ private fun DeviceListButtonPanel( start = Dimens.sideMargin, end = Dimens.sideMargin, top = Dimens.spacingAboveButton, - bottom = Dimens.screenVerticalMargin, ) ) { VariantButton( diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceRevokedScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceRevokedScreen.kt index d0a334d561..4ab0fba693 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceRevokedScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceRevokedScreen.kt @@ -3,23 +3,22 @@ package net.mullvad.mullvadvpn.compose.screen import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.constraintlayout.compose.ConstraintLayout -import androidx.constraintlayout.compose.Dimension import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed import com.ramcosta.composedestinations.annotation.Destination @@ -31,11 +30,13 @@ import com.ramcosta.composedestinations.navigation.DestinationsNavigator import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.button.DeviceRevokedLoginButton import net.mullvad.mullvadvpn.compose.component.ScaffoldWithTopBar +import net.mullvad.mullvadvpn.compose.component.drawVerticalScrollbar import net.mullvad.mullvadvpn.compose.preview.DeviceRevokedUiStatePreviewParameterProvider import net.mullvad.mullvadvpn.compose.state.DeviceRevokedUiState import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.lib.theme.Dimens +import net.mullvad.mullvadvpn.lib.theme.color.AlphaScrollbar import net.mullvad.mullvadvpn.viewmodel.DeviceRevokedSideEffect import net.mullvad.mullvadvpn.viewmodel.DeviceRevokedViewModel import org.koin.androidx.compose.koinViewModel @@ -86,76 +87,62 @@ fun DeviceRevokedScreen( MaterialTheme.colorScheme.error } + val scrollState = rememberScrollState() ScaffoldWithTopBar( topBarColor = topColor, onSettingsClicked = onSettingsClicked, onAccountClicked = null, ) { - ConstraintLayout( + Column( modifier = Modifier.fillMaxSize() .padding(it) + .padding( + top = Dimens.screenTopMargin, + bottom = Dimens.screenBottomMargin, + start = Dimens.screenTopMargin, + end = Dimens.sideMargin, + ) + .verticalScroll(scrollState) + .drawVerticalScrollbar( + state = scrollState, + color = MaterialTheme.colorScheme.onSurface.copy(alpha = AlphaScrollbar), + ) .background(color = MaterialTheme.colorScheme.surface) ) { - val (icon, body, actionButtons) = createRefs() - Image( painter = painterResource(id = R.drawable.icon_fail), - contentDescription = null, // No meaningful user info or action. + contentDescription = null, modifier = - Modifier.constrainAs(icon) { - top.linkTo(parent.top, margin = 30.dp) - start.linkTo(parent.start) - end.linkTo(parent.end) - } - .padding(horizontal = 12.dp) - .size(Dimens.bigIconSize), + Modifier.align(Alignment.CenterHorizontally) + .padding(bottom = Dimens.mediumSpacer), + ) + Text( + text = stringResource(id = R.string.device_inactive_title), + style = MaterialTheme.typography.headlineLarge, + color = MaterialTheme.colorScheme.onSurface, ) - Column( - modifier = - Modifier.constrainAs(body) { - top.linkTo(icon.bottom, margin = 22.dp) - start.linkTo(parent.start, margin = 22.dp) - end.linkTo(parent.end, margin = 22.dp) - width = Dimension.fillToConstraints - } - ) { - Text( - text = stringResource(id = R.string.device_inactive_title), - fontSize = 24.sp, - color = MaterialTheme.colorScheme.onSurface, - fontWeight = FontWeight.Bold, - ) + Text( + text = stringResource(id = R.string.device_inactive_description), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.padding(top = Dimens.smallPadding), + ) + if (state == DeviceRevokedUiState.SECURED) { Text( - text = stringResource(id = R.string.device_inactive_description), - fontSize = 12.sp, + text = stringResource(id = R.string.device_inactive_unblock_warning), + style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurface, - modifier = Modifier.padding(top = 10.dp), + modifier = Modifier.padding(top = Dimens.mediumPadding), ) - - if (state == DeviceRevokedUiState.SECURED) { - Text( - text = stringResource(id = R.string.device_inactive_unblock_warning), - fontSize = 12.sp, - color = MaterialTheme.colorScheme.onSurface, - modifier = Modifier.padding(top = 10.dp), - ) - } } - Column( - modifier = - Modifier.constrainAs(actionButtons) { - bottom.linkTo(parent.bottom, margin = 22.dp) - start.linkTo(parent.start, margin = 22.dp) - end.linkTo(parent.end, margin = 22.dp) - width = Dimension.fillToConstraints - } - ) { - DeviceRevokedLoginButton(onClick = onGoToLoginClicked, state = state) - } + Spacer(modifier = Modifier.weight(1f).defaultMinSize(minHeight = Dimens.verticalSpace)) + + // Button area + DeviceRevokedLoginButton(onClick = onGoToLoginClicked, state = state) } } } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditApiAccessMethodScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditApiAccessMethodScreen.kt index 54023670f2..1c0a84c375 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditApiAccessMethodScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditApiAccessMethodScreen.kt @@ -238,7 +238,7 @@ fun EditApiAccessMethodScreen( color = MaterialTheme.colorScheme.onSurface.copy(alpha = AlphaScrollbar), ) .verticalScroll(scrollState) - .padding(horizontal = Dimens.sideMargin, vertical = Dimens.screenVerticalMargin) + .padding(horizontal = Dimens.sideMargin, vertical = Dimens.screenBottomMargin) ) { when (state) { is EditApiAccessMethodUiState.Loading -> Loading() diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditCustomListScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditCustomListScreen.kt index 074af07489..5814e9b377 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditCustomListScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditCustomListScreen.kt @@ -143,7 +143,7 @@ fun EditCustomListScreen( EditCustomListUiState.NotFound -> { Text( text = stringResource(id = R.string.not_found), - modifier = Modifier.padding(Dimens.screenVerticalMargin), + modifier = Modifier.padding(Dimens.sideMargin), style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.onSurface, ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/FilterScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/FilterScreen.kt index 7cc375f185..a869749328 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/FilterScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/FilterScreen.kt @@ -2,20 +2,12 @@ package net.mullvad.mullvadvpn.compose.screen import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyItemScope -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -25,7 +17,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -38,6 +29,8 @@ import net.mullvad.mullvadvpn.compose.button.ApplyButton import net.mullvad.mullvadvpn.compose.cell.CheckboxCell import net.mullvad.mullvadvpn.compose.cell.ExpandableComposeCell import net.mullvad.mullvadvpn.compose.cell.SelectableCell +import net.mullvad.mullvadvpn.compose.component.NavigateBackIconButton +import net.mullvad.mullvadvpn.compose.component.ScaffoldWithSmallTopBar import net.mullvad.mullvadvpn.compose.constant.ContentType import net.mullvad.mullvadvpn.compose.extensions.itemWithDivider import net.mullvad.mullvadvpn.compose.extensions.itemsWithDivider @@ -106,9 +99,10 @@ fun FilterScreen( var ownershipExpanded by rememberSaveable { mutableStateOf(false) } val backgroundColor = MaterialTheme.colorScheme.surface - Scaffold( - modifier = Modifier.background(backgroundColor).systemBarsPadding().fillMaxSize(), - topBar = { TopBar(onBackClick = onBackClick) }, + ScaffoldWithSmallTopBar( + modifier = Modifier.background(backgroundColor), + appBarTitle = stringResource(R.string.filter), + navigationIcon = { NavigateBackIconButton(onNavigateBack = onBackClick) }, bottomBar = { BottomBar( isApplyButtonEnabled = state.isApplyButtonEnabled, @@ -116,13 +110,13 @@ fun FilterScreen( onApplyClick = onApplyClick, ) }, - ) { contentPadding -> - LazyColumn(modifier = Modifier.padding(contentPadding).fillMaxSize()) { + ) { modifier -> + LazyColumn(modifier = modifier.fillMaxSize()) { itemWithDivider(key = Keys.OWNERSHIP_TITLE, contentType = ContentType.HEADER) { OwnershipHeader(ownershipExpanded) { ownershipExpanded = it } } if (ownershipExpanded) { - item(key = Keys.OWNERSHIP_ALL, contentType = ContentType.ITEM) { + itemWithDivider(key = Keys.OWNERSHIP_ALL, contentType = ContentType.ITEM) { AnyOwnership(state, { onSelectedOwnership(Constraint.Any) }) } itemsWithDivider( @@ -179,6 +173,7 @@ private fun LazyItemScope.AnyOwnership(state: RelayFilterUiState, onSelectedOwne isSelected = state.selectedOwnership is Constraint.Any, onCellClicked = { onSelectedOwnership() }, modifier = Modifier.animateItem(), + backgroundColor = MaterialTheme.colorScheme.surfaceContainerHighest, ) } @@ -193,6 +188,7 @@ private fun LazyItemScope.Ownership( isSelected = ownership == state.selectedOwnership.getOrNull(), onCellClicked = { onSelectedOwnership(ownership) }, modifier = Modifier.animateItem(), + backgroundColor = MaterialTheme.colorScheme.surfaceContainerHighest, ) } @@ -259,26 +255,6 @@ private fun LazyItemScope.RemovedProvider( } @Composable -private fun TopBar(onBackClick: () -> Unit) { - Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { - IconButton(onClick = onBackClick) { - Icon( - imageVector = Icons.AutoMirrored.Default.ArrowBack, - contentDescription = stringResource(id = R.string.back), - tint = MaterialTheme.colorScheme.onSurface, - ) - } - Text( - text = stringResource(R.string.filter), - modifier = Modifier.weight(1f).padding(end = Dimens.titleIconSize), - textAlign = TextAlign.Center, - style = MaterialTheme.typography.titleLarge, - color = MaterialTheme.colorScheme.onSurface, - ) - } -} - -@Composable private fun BottomBar( isApplyButtonEnabled: Boolean, backgroundColor: Color, @@ -288,19 +264,10 @@ private fun BottomBar( modifier = Modifier.fillMaxWidth() .background(color = backgroundColor) - .padding(top = Dimens.screenVerticalMargin), + .padding(vertical = Dimens.screenBottomMargin, horizontal = Dimens.sideMargin), contentAlignment = Alignment.BottomCenter, ) { - ApplyButton( - onClick = onApplyClick, - isEnabled = isApplyButtonEnabled, - modifier = - Modifier.padding( - start = Dimens.sideMargin, - end = Dimens.sideMargin, - bottom = Dimens.screenVerticalMargin, - ), - ) + ApplyButton(onClick = onApplyClick, isEnabled = isApplyButtonEnabled) } } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/LoginScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/LoginScreen.kt index 5b9499c89e..d07fad359f 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/LoginScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/LoginScreen.kt @@ -40,7 +40,6 @@ import androidx.compose.ui.autofill.ContentType import androidx.compose.ui.draw.clip import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusProperties -import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource @@ -320,14 +319,13 @@ private fun ColumnScope.LoginInput( @Composable private fun LoginIcon(loginState: LoginState, modifier: Modifier = Modifier) { - Box(contentAlignment = Alignment.Center, modifier = modifier.size(Dimens.bigIconSize)) { + Box(contentAlignment = Alignment.Center, modifier = modifier) { when (loginState) { is Idle -> if (loginState.loginError != null) { Image( painter = painterResource(id = R.drawable.icon_fail), contentDescription = stringResource(id = R.string.login_fail_title), - contentScale = ContentScale.Inside, ) } else { // If view is Idle, we display empty box to keep the same size as other states @@ -423,7 +421,7 @@ private fun CreateAccountPanel(onCreateAccountClick: () -> Unit, isEnabled: Bool Column( Modifier.fillMaxWidth() .background(MaterialTheme.colorScheme.background) - .padding(horizontal = Dimens.sideMargin, vertical = Dimens.screenVerticalMargin) + .padding(horizontal = Dimens.sideMargin, vertical = Dimens.screenBottomMargin) ) { Text( modifier = Modifier.padding(bottom = Dimens.smallPadding), diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/OutOfTimeScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/OutOfTimeScreen.kt index 5330e16d69..83febe7ea3 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/OutOfTimeScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/OutOfTimeScreen.kt @@ -2,12 +2,12 @@ package net.mullvad.mullvadvpn.compose.screen import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme @@ -171,6 +171,12 @@ fun OutOfTimeScreen( modifier = Modifier.fillMaxSize() .padding(it) + .padding( + top = Dimens.screenTopMargin, + start = Dimens.sideMargin, + end = Dimens.sideMargin, + bottom = Dimens.screenBottomMargin, + ) .verticalScroll(scrollState) .drawVerticalScrollbar( state = scrollState, @@ -183,16 +189,13 @@ fun OutOfTimeScreen( contentDescription = null, modifier = Modifier.align(Alignment.CenterHorizontally) - .padding(vertical = Dimens.screenVerticalMargin) - .size(Dimens.bigIconSize), + .padding(bottom = Dimens.mediumSpacer), ) Text( text = stringResource(id = R.string.out_of_time), style = MaterialTheme.typography.headlineLarge, color = MaterialTheme.colorScheme.onSurface, - modifier = - Modifier.padding(horizontal = Dimens.sideMargin) - .testTag(OUT_OF_TIME_SCREEN_TITLE_TEST_TAG), + modifier = Modifier.testTag(OUT_OF_TIME_SCREEN_TITLE_TEST_TAG), ) Text( text = @@ -205,12 +208,7 @@ fun OutOfTimeScreen( }, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurface, - modifier = - Modifier.padding( - top = Dimens.mediumPadding, - start = Dimens.sideMargin, - end = Dimens.sideMargin, - ), + modifier = Modifier.padding(top = Dimens.mediumPadding), ) Spacer(modifier = Modifier.weight(1f).defaultMinSize(minHeight = Dimens.verticalSpace)) // Button area @@ -237,17 +235,11 @@ private fun ButtonPanel( navigateToVerificationPendingDialog: () -> Unit, ) { - Column { + Column(verticalArrangement = Arrangement.spacedBy(Dimens.buttonSpacing)) { if (state.tunnelState.isSecured()) { NegativeButton( onClick = onDisconnectClick, text = stringResource(id = R.string.disconnect), - modifier = - Modifier.padding( - start = Dimens.sideMargin, - end = Dimens.sideMargin, - bottom = Dimens.buttonSpacing, - ), ) } state.billingPaymentState?.let { @@ -257,35 +249,16 @@ private fun ButtonPanel( onPurchaseBillingProductClick(productId) }, onInfoClick = navigateToVerificationPendingDialog, - modifier = - Modifier.padding( - start = Dimens.sideMargin, - end = Dimens.sideMargin, - bottom = Dimens.buttonSpacing, - ) - .align(Alignment.CenterHorizontally), ) } if (state.showSitePayment) { SitePaymentButton( onClick = onSitePaymentClick, isEnabled = state.tunnelState.enableSitePaymentButton(), - modifier = - Modifier.padding( - start = Dimens.sideMargin, - end = Dimens.sideMargin, - bottom = Dimens.buttonSpacing, - ), ) } RedeemVoucherButton( onClick = onRedeemVoucherClick, - modifier = - Modifier.padding( - start = Dimens.sideMargin, - end = Dimens.sideMargin, - bottom = Dimens.screenVerticalMargin, - ), isEnabled = state.tunnelState.enableRedeemButton(), ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/PrivacyDisclaimerScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/PrivacyDisclaimerScreen.kt index 4fafe36c7a..2d17a02fbc 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/PrivacyDisclaimerScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/PrivacyDisclaimerScreen.kt @@ -114,7 +114,12 @@ fun PrivacyDisclaimerScreen(state: PrivacyDisclaimerViewState, onAcceptClicked: .fillMaxSize() .background(color = MaterialTheme.colorScheme.surface) .verticalScroll(scrollState) - .padding(horizontal = Dimens.sideMargin, vertical = Dimens.screenVerticalMargin) + .padding( + start = Dimens.sideMargin, + end = Dimens.sideMargin, + top = Dimens.screenTopMargin, + bottom = Dimens.screenBottomMargin, + ) .drawVerticalScrollbar( state = scrollState, color = MaterialTheme.colorScheme.onPrimary.copy(alpha = AlphaScrollbar), diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ReportProblemScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ReportProblemScreen.kt index 042701357a..207e5cfc26 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ReportProblemScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ReportProblemScreen.kt @@ -154,7 +154,7 @@ private fun ReportProblemScreen( .padding( start = Dimens.sideMargin, end = Dimens.sideMargin, - bottom = Dimens.verticalSpace, + bottom = Dimens.screenBottomMargin, ) .height(IntrinsicSize.Max), verticalArrangement = Arrangement.spacedBy(Dimens.mediumPadding), @@ -242,7 +242,7 @@ fun ProblemMessageTextField( @Composable private fun ColumnScope.SendingContent() { MullvadCircularProgressIndicatorLarge(modifier = Modifier.align(Alignment.CenterHorizontally)) - Spacer(modifier = Modifier.height(Dimens.problemReportIconToTitlePadding)) + Spacer(modifier = Modifier.height(Dimens.mediumSpacer)) Text( text = stringResource(id = R.string.sending), style = MaterialTheme.typography.headlineLarge, @@ -256,11 +256,11 @@ private fun ColumnScope.SentContent(sendingState: SendingReportUiState.Success) Icon( painter = painterResource(id = R.drawable.icon_success), contentDescription = stringResource(id = R.string.sent), - modifier = Modifier.align(Alignment.CenterHorizontally).size(Dimens.dialogIconHeight), + modifier = Modifier.align(Alignment.CenterHorizontally), tint = Color.Unspecified, ) - Spacer(modifier = Modifier.height(Dimens.problemReportIconToTitlePadding)) + Spacer(modifier = Modifier.height(Dimens.mediumSpacer)) Text( text = stringResource(id = R.string.sent), style = MaterialTheme.typography.headlineLarge, @@ -310,10 +310,10 @@ private fun ColumnScope.ErrorContent(retry: () -> Unit, onDismiss: () -> Unit) { Icon( painter = painterResource(id = R.drawable.icon_fail), contentDescription = stringResource(id = R.string.failed_to_send), - modifier = Modifier.size(Dimens.dialogIconHeight).align(Alignment.CenterHorizontally), + modifier = Modifier.align(Alignment.CenterHorizontally), tint = Color.Unspecified, ) - Spacer(modifier = Modifier.height(Dimens.problemReportIconToTitlePadding)) + Spacer(modifier = Modifier.height(Dimens.mediumSpacer)) Text( text = stringResource(id = R.string.failed_to_send), style = MaterialTheme.typography.headlineLarge, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ServerIpOverridesScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ServerIpOverridesScreen.kt index 6dd85cbbc4..c0164483e9 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ServerIpOverridesScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ServerIpOverridesScreen.kt @@ -236,7 +236,7 @@ fun ServerIpOverridesScreen( text = stringResource(R.string.import_overrides_import), modifier = Modifier.padding(horizontal = Dimens.sideMargin) - .padding(bottom = Dimens.screenVerticalMargin) + .padding(bottom = Dimens.screenBottomMargin) .testTag(SERVER_IP_OVERRIDE_IMPORT_TEST_TAG), ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ViewLogsScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ViewLogsScreen.kt index 2b06606a3d..085060db48 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ViewLogsScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ViewLogsScreen.kt @@ -142,7 +142,7 @@ private fun Content(state: ViewLogsUiState, paddingValues: PaddingValues) { .padding( start = Dimens.sideMargin, end = Dimens.sideMargin, - bottom = Dimens.screenVerticalMargin, + bottom = Dimens.screenBottomMargin, ), colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.onPrimary), ) { 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 af5fbe8edc..499dbc620a 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 @@ -563,7 +563,7 @@ fun VpnSettingsContent( ) }, bodyView = {}, - background = MaterialTheme.colorScheme.surfaceContainerLow, + background = MaterialTheme.colorScheme.surfaceContainerHighest, startPadding = Dimens.cellStartPaddingLarge, ) } @@ -619,6 +619,7 @@ fun VpnSettingsContent( InformationComposeCell( title = stringResource(R.string.device_ip_version_title), onInfoClicked = navigateToDeviceIpInfo, + onCellClicked = navigateToDeviceIpInfo, modifier = Modifier.animateItem(), ) } @@ -659,7 +660,6 @@ fun VpnSettingsContent( isToggled = it.enabled, isEnabled = it.featureEnabled, onCellClicked = { onToggleBlockAds(it) }, - background = MaterialTheme.colorScheme.surfaceContainerLow, startPadding = Dimens.indentedCellStartPadding, modifier = Modifier.animateItem(), ) @@ -672,7 +672,6 @@ fun VpnSettingsContent( isToggled = it.enabled, isEnabled = it.featureEnabled, onCellClicked = { onToggleBlockAdultContent(it) }, - background = MaterialTheme.colorScheme.surfaceContainerLow, startPadding = Dimens.indentedCellStartPadding, modifier = Modifier.animateItem(), ) @@ -684,7 +683,6 @@ fun VpnSettingsContent( isToggled = it.enabled, isEnabled = it.featureEnabled, onCellClicked = { onToggleBlockGambling(it) }, - background = MaterialTheme.colorScheme.surfaceContainerLow, startPadding = Dimens.indentedCellStartPadding, modifier = Modifier.animateItem(), ) @@ -699,7 +697,6 @@ fun VpnSettingsContent( isEnabled = it.featureEnabled, onCellClicked = { onToggleBlockMalware(it) }, onInfoClicked = { navigateToMalwareInfo() }, - background = MaterialTheme.colorScheme.surfaceContainerLow, startPadding = Dimens.indentedCellStartPadding, ) } @@ -712,7 +709,6 @@ fun VpnSettingsContent( isToggled = it.enabled, isEnabled = it.featureEnabled, onCellClicked = { onToggleBlockSocialMedia(it) }, - background = MaterialTheme.colorScheme.surfaceContainerLow, startPadding = Dimens.indentedCellStartPadding, ) } @@ -725,7 +721,6 @@ fun VpnSettingsContent( isToggled = it.enabled, isEnabled = it.featureEnabled, onCellClicked = { onToggleBlockTrackers(it) }, - background = MaterialTheme.colorScheme.surfaceContainerLow, startPadding = Dimens.indentedCellStartPadding, ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreen.kt index 8f7286987d..482eafe863 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreen.kt @@ -240,7 +240,7 @@ private fun WelcomeInfo( modifier = Modifier.fillMaxWidth() .padding( - top = Dimens.screenVerticalMargin, + top = Dimens.screenTopMargin, start = Dimens.sideMargin, end = Dimens.sideMargin, ), @@ -303,7 +303,7 @@ private fun AccountNumberRow(snackbarHostState: SnackbarHostState, state: Welcom ) { Text( text = state.accountNumber?.value?.groupWithSpaces() ?: "", - modifier = Modifier.weight(1f).padding(vertical = Dimens.smallPadding), + modifier = Modifier.weight(1f).padding(top = Dimens.smallPadding), style = MaterialTheme.typography.headlineSmall, color = MaterialTheme.colorScheme.onSurface, ) @@ -357,7 +357,7 @@ private fun ButtonPanel( onDisconnectClick: () -> Unit, ) { Column(modifier = Modifier.fillMaxWidth().padding(top = Dimens.mediumPadding)) { - Spacer(modifier = Modifier.padding(top = Dimens.screenVerticalMargin)) + Spacer(modifier = Modifier.padding(top = Dimens.screenTopMargin)) if (showDisconnectButton) { NegativeButton( onClick = onDisconnectClick, @@ -405,7 +405,7 @@ private fun ButtonPanel( Modifier.padding( start = Dimens.sideMargin, end = Dimens.sideMargin, - bottom = Dimens.screenVerticalMargin, + bottom = Dimens.screenBottomMargin, ), ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/location/SelectLocationScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/location/SelectLocationScreen.kt index d6d3742162..ec8c25207b 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/location/SelectLocationScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/location/SelectLocationScreen.kt @@ -264,9 +264,9 @@ fun SelectLocationScreen( modifier = Modifier.testTag(SELECT_LOCATION_SCREEN_TEST_TAG), snackbarHostState = snackbarHostState, actions = { - val isTopBarActionsEnabled = state.contentOrNull()?.isTopBarActionsEnabled == true + val isSearchButtonEnabled = state.contentOrNull()?.isSearchButtonEnabled == true IconButton( - enabled = isTopBarActionsEnabled, + enabled = isSearchButtonEnabled, onClick = { state.contentOrNull()?.let { onSearchClick(it.relayListType) } }, ) { Icon( @@ -274,17 +274,18 @@ fun SelectLocationScreen( contentDescription = stringResource(id = R.string.search), tint = MaterialTheme.colorScheme.onSurface.copy( - alpha = if (isTopBarActionsEnabled) AlphaVisible else AlphaDisabled + alpha = if (isSearchButtonEnabled) AlphaVisible else AlphaDisabled ), ) } - IconButton(enabled = isTopBarActionsEnabled, onClick = onFilterClick) { + val isFilterButtonEnabled = state.contentOrNull()?.isFilterButtonEnabled == true + IconButton(enabled = isFilterButtonEnabled, onClick = onFilterClick) { Icon( imageVector = Icons.Default.FilterList, contentDescription = stringResource(id = R.string.filter), tint = MaterialTheme.colorScheme.onSurface.copy( - alpha = if (isTopBarActionsEnabled) AlphaVisible else AlphaDisabled + alpha = if (isFilterButtonEnabled) AlphaVisible else AlphaDisabled ), ) } @@ -316,12 +317,17 @@ fun SelectLocationScreen( Loading() } is Lc.Content -> { + if (state.value.multihopEnabled) { + MultihopBar(state.value.relayListType, onSelectRelayList) + } + AnimatedContent( targetState = state.value.filterChips, label = "Select location top bar", ) { filterChips -> if (filterChips.isNotEmpty()) { FilterRow( + modifier = Modifier.padding(bottom = Dimens.smallPadding), filters = filterChips, onRemoveOwnershipFilter = removeOwnershipFilter, onRemoveProviderFilter = removeProviderFilter, @@ -329,12 +335,8 @@ fun SelectLocationScreen( } } - if (state.value.multihopEnabled) { - MultihopBar(state.value.relayListType, onSelectRelayList) - } - - if (state.value.filterChips.isNotEmpty() || state.value.multihopEnabled) { - Spacer(modifier = Modifier.height(height = Dimens.verticalSpace)) + if (state.value.multihopEnabled && state.value.filterChips.isEmpty()) { + Spacer(modifier = Modifier.height(Dimens.smallPadding)) } RelayLists( @@ -356,7 +358,12 @@ fun SelectLocationScreen( private fun MultihopBar(relayListType: RelayListType, onSelectRelayList: (RelayListType) -> Unit) { SingleChoiceSegmentedButtonRow( modifier = - Modifier.fillMaxWidth().padding(start = Dimens.sideMargin, end = Dimens.sideMargin) + Modifier.fillMaxWidth() + .padding( + start = Dimens.sideMargin, + end = Dimens.sideMargin, + bottom = Dimens.smallPadding, + ) ) { MullvadSegmentedStartButton( selected = relayListType == RelayListType.ENTRY, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/SelectLocationUiState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/SelectLocationUiState.kt index 6f986f2916..d6014647ea 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/SelectLocationUiState.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/SelectLocationUiState.kt @@ -6,5 +6,6 @@ data class SelectLocationUiState( val filterChips: List<FilterChip>, val multihopEnabled: Boolean, val relayListType: RelayListType, - val isTopBarActionsEnabled: Boolean, + val isSearchButtonEnabled: Boolean, + val isFilterButtonEnabled: Boolean, ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt index c9c1f1e78a..cd071746c7 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt @@ -232,7 +232,7 @@ val uiModule = module { viewModel { WireguardCustomPortDialogViewModel(get()) } viewModel { LoginViewModel(get(), get(), get()) } viewModel { PrivacyDisclaimerViewModel(get(), IS_PLAY_BUILD) } - viewModel { SelectLocationViewModel(get(), get(), get(), get(), get(), get()) } + viewModel { SelectLocationViewModel(get(), get(), get(), get(), get(), get(), get()) } viewModel { SettingsViewModel(get(), get(), get(), get(), IS_PLAY_BUILD) } viewModel { SplashViewModel(get(), get(), get(), get()) } viewModel { VoucherDialogViewModel(get()) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/InAppNotificationController.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/InAppNotificationController.kt index 752e185d14..a792d2347a 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/InAppNotificationController.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/InAppNotificationController.kt @@ -33,8 +33,8 @@ class InAppNotificationController( .map { it.sortedWith( compareBy( - { notification -> notification.statusLevel.ordinal }, { notification -> -notification.priority }, + { notification -> notification.statusLevel.ordinal }, ) ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationListViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationListViewModel.kt index 846a56cdaf..fc01b69ea6 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationListViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationListViewModel.kt @@ -12,7 +12,6 @@ import net.mullvad.mullvadvpn.compose.state.SelectLocationListUiState import net.mullvad.mullvadvpn.lib.model.CustomListId import net.mullvad.mullvadvpn.lib.model.GeoLocationId import net.mullvad.mullvadvpn.lib.model.RelayItemId -import net.mullvad.mullvadvpn.lib.model.Settings import net.mullvad.mullvadvpn.repository.RelayListRepository import net.mullvad.mullvadvpn.repository.SettingsRepository import net.mullvad.mullvadvpn.repository.WireguardConstraintsRepository @@ -114,11 +113,4 @@ class SelectLocationListViewModel( wireguardConstraintsRepository.wireguardConstraints.value?.entryLocation RelayListType.EXIT -> relayListRepository.selectedLocation.value }?.getOrNull() - - // If Daita is enabled without direct only, it is not possible to manually select the entry - // location. - private fun Settings.entryBlocked() = - tunnelOptions.wireguard.daitaSettings.enabled && - !tunnelOptions.wireguard.daitaSettings.directOnly && - relaySettings.relayConstraints.wireguardConstraints.isMultihopEnabled } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModel.kt index f1a9240187..c9cca74602 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModel.kt @@ -21,6 +21,7 @@ import net.mullvad.mullvadvpn.lib.model.RelayItem import net.mullvad.mullvadvpn.repository.CustomListsRepository import net.mullvad.mullvadvpn.repository.RelayListFilterRepository import net.mullvad.mullvadvpn.repository.RelayListRepository +import net.mullvad.mullvadvpn.repository.SettingsRepository import net.mullvad.mullvadvpn.repository.WireguardConstraintsRepository import net.mullvad.mullvadvpn.usecase.FilterChipUseCase import net.mullvad.mullvadvpn.usecase.customlists.CustomListActionUseCase @@ -35,6 +36,7 @@ class SelectLocationViewModel( private val relayListRepository: RelayListRepository, private val wireguardConstraintsRepository: WireguardConstraintsRepository, private val filterChipUseCase: FilterChipUseCase, + private val settingsRepository: SettingsRepository, ) : ViewModel() { private val _relayListType: MutableStateFlow<RelayListType> = MutableStateFlow(RelayListType.EXIT) @@ -45,13 +47,18 @@ class SelectLocationViewModel( wireguardConstraintsRepository.wireguardConstraints, _relayListType, relayListRepository.relayList, - ) { filterChips, wireguardConstraints, relayListSelection, relayList -> + settingsRepository.settingsUpdates, + ) { filterChips, wireguardConstraints, relayListSelection, relayList, settings -> Lc.Content( SelectLocationUiState( filterChips = filterChips, multihopEnabled = wireguardConstraints?.isMultihopEnabled == true, relayListType = relayListSelection, - isTopBarActionsEnabled = relayList.isNotEmpty(), + isSearchButtonEnabled = + relayList.isNotEmpty() && + (relayListSelection == RelayListType.EXIT || + settings?.entryBlocked() != true), + isFilterButtonEnabled = relayList.isNotEmpty(), ) ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SettingsUtil.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SettingsUtil.kt new file mode 100644 index 0000000000..05245f2503 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SettingsUtil.kt @@ -0,0 +1,10 @@ +package net.mullvad.mullvadvpn.viewmodel.location + +import net.mullvad.mullvadvpn.lib.model.Settings + +// If Daita is enabled without direct only, it is not possible to manually select the entry +// location. +internal fun Settings.entryBlocked() = + tunnelOptions.wireguard.daitaSettings.enabled && + !tunnelOptions.wireguard.daitaSettings.directOnly && + relaySettings.relayConstraints.wireguardConstraints.isMultihopEnabled diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/InAppNotificationControllerTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/InAppNotificationControllerTest.kt index b7be4e574d..f9ee9f3d41 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/InAppNotificationControllerTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/InAppNotificationControllerTest.kt @@ -84,6 +84,7 @@ class InAppNotificationControllerTest { newVersionChangelogNotifications.value = listOf(newVersionChangelog) val errorState: ErrorState = mockk() + every { errorState.cause } returns mockk() val tunnelStateBlocked = InAppNotification.TunnelStateBlocked val tunnelStateError = InAppNotification.TunnelStateError(errorState) tunnelStateNotifications.value = listOf(tunnelStateBlocked, tunnelStateError) diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt index b298270fad..44f46b2778 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt @@ -280,6 +280,7 @@ class ConnectViewModelTest { runTest { // Arrange val mockErrorState: ErrorState = mockk() + every { mockErrorState.cause } returns mockk() val expectedConnectNotificationState = InAppNotification.TunnelStateError(mockErrorState) diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModelTest.kt index a7ecbe17f9..304b664dc6 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModelTest.kt @@ -29,11 +29,13 @@ import net.mullvad.mullvadvpn.lib.model.Ownership import net.mullvad.mullvadvpn.lib.model.Providers import net.mullvad.mullvadvpn.lib.model.RelayItem import net.mullvad.mullvadvpn.lib.model.RelayItemId +import net.mullvad.mullvadvpn.lib.model.Settings import net.mullvad.mullvadvpn.lib.model.WireguardConstraints import net.mullvad.mullvadvpn.relaylist.descendants import net.mullvad.mullvadvpn.repository.CustomListsRepository import net.mullvad.mullvadvpn.repository.RelayListFilterRepository import net.mullvad.mullvadvpn.repository.RelayListRepository +import net.mullvad.mullvadvpn.repository.SettingsRepository import net.mullvad.mullvadvpn.repository.WireguardConstraintsRepository import net.mullvad.mullvadvpn.usecase.FilterChip import net.mullvad.mullvadvpn.usecase.FilterChipUseCase @@ -53,6 +55,7 @@ class SelectLocationViewModelTest { private val mockCustomListsRepository: CustomListsRepository = mockk() private val mockWireguardConstraintsRepository: WireguardConstraintsRepository = mockk() private val mockFilterChipUseCase: FilterChipUseCase = mockk() + private val mockSettingsRepository: SettingsRepository = mockk() private lateinit var viewModel: SelectLocationViewModel @@ -60,6 +63,7 @@ class SelectLocationViewModelTest { private val wireguardConstraints = MutableStateFlow<WireguardConstraints>(mockk(relaxed = true)) private val filterChips = MutableStateFlow<List<FilterChip>>(emptyList()) private val relayList = MutableStateFlow<List<RelayItem.Location.Country>>(emptyList()) + private val settings = MutableStateFlow<Settings>(mockk(relaxed = true)) @BeforeEach fun setup() { @@ -69,6 +73,7 @@ class SelectLocationViewModelTest { wireguardConstraints every { mockFilterChipUseCase(any()) } returns filterChips every { mockRelayListRepository.relayList } returns relayList + every { mockSettingsRepository.settingsUpdates } returns settings mockkStatic(RELAY_LIST_EXTENSIONS) mockkStatic(RELAY_ITEM_EXTENSIONS) @@ -81,6 +86,7 @@ class SelectLocationViewModelTest { customListsRepository = mockCustomListsRepository, filterChipUseCase = mockFilterChipUseCase, wireguardConstraintsRepository = mockWireguardConstraintsRepository, + settingsRepository = mockSettingsRepository, ) } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/InAppNotification.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/InAppNotification.kt index fdaa5f3c9d..7a681da66c 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/InAppNotification.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/InAppNotification.kt @@ -6,6 +6,7 @@ enum class StatusLevel { Error, Warning, Info, + None, } sealed class InAppNotification { @@ -13,18 +14,23 @@ sealed class InAppNotification { abstract val priority: Long data class TunnelStateError(val error: ErrorState) : InAppNotification() { - override val statusLevel = StatusLevel.Error - override val priority: Long = 1001 + override val statusLevel = + if (error.cause is ErrorStateCause.IsOffline) { + StatusLevel.Warning + } else { + StatusLevel.Error + } + override val priority: Long = 1004 } data object TunnelStateBlocked : InAppNotification() { - override val statusLevel = StatusLevel.Error - override val priority: Long = 1000 + override val statusLevel = StatusLevel.None + override val priority: Long = 1003 } data class UnsupportedVersion(val versionInfo: VersionInfo) : InAppNotification() { override val statusLevel = StatusLevel.Error - override val priority: Long = 999 + override val priority: Long = 1002 } data class AccountExpiry(val expiry: Duration) : InAppNotification() { @@ -39,6 +45,6 @@ sealed class InAppNotification { data object NewVersionChangelog : InAppNotification() { override val statusLevel = StatusLevel.Info - override val priority: Long = 1001 + override val priority: Long = 1000 } } diff --git a/android/lib/resource/src/main/res/drawable/icon_fail.xml b/android/lib/resource/src/main/res/drawable/icon_fail.xml index 3f934a1300..efe8f0c89d 100644 --- a/android/lib/resource/src/main/res/drawable/icon_fail.xml +++ b/android/lib/resource/src/main/res/drawable/icon_fail.xml @@ -1,10 +1,12 @@ <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="44dp" - android:height="44dp" - android:viewportWidth="44" - android:viewportHeight="44"> - <path android:pathData="M22,22m-22,0a22,22 0,1 1,44 0a22,22 0,1 1,-44 0" - android:fillColor="#fff" /> - <path android:pathData="m25.147,22 l7.875,-7.872A2.225,2.225 0,0 0,29.875 10.982l-7.875,7.872L14.125,10.982A2.225,2.225 0,0 0,10.977 14.128l7.875,7.872 -7.875,7.871a2.225,2.225 0,0 0,3.147 3.146l7.875,-7.872 7.875,7.872a2.225,2.225 0,0 0,3.147 -3.146l-7.875,-7.872z" - android:fillColor="#e34039" /> + android:width="48dp" + android:height="48dp" + android:viewportWidth="48" + android:viewportHeight="48"> + <path + android:pathData="M24,44C35.046,44 44,35.046 44,24C44,12.954 35.046,4 24,4C12.954,4 4,12.954 4,24C4,35.046 12.954,44 24,44Z" + android:fillColor="#ffffff"/> + <path + android:pathData="M26.861,24L34.02,16.844C34.393,16.463 34.602,15.95 34.599,15.417C34.597,14.884 34.384,14.373 34.007,13.996C33.629,13.619 33.118,13.406 32.585,13.404C32.052,13.401 31.539,13.61 31.159,13.984L24,21.14L16.841,13.984C16.461,13.604 15.947,13.391 15.41,13.391C14.874,13.391 14.359,13.603 13.98,13.983C13.6,14.362 13.387,14.876 13.387,15.413C13.387,15.95 13.599,16.464 13.979,16.844L21.138,24L13.979,31.155C13.605,31.536 13.397,32.049 13.399,32.582C13.402,33.115 13.615,33.626 13.992,34.003C14.369,34.38 14.88,34.593 15.413,34.595C15.947,34.598 16.459,34.389 16.84,34.015L23.999,26.859L31.158,34.015C31.538,34.389 32.051,34.598 32.584,34.595C33.118,34.593 33.628,34.38 34.006,34.003C34.383,33.626 34.596,33.115 34.598,32.582C34.601,32.049 34.393,31.536 34.019,31.155L26.86,23.999L26.861,24Z" + android:fillColor="#E34039"/> </vector> diff --git a/android/lib/resource/src/main/res/drawable/icon_success.xml b/android/lib/resource/src/main/res/drawable/icon_success.xml index 1b15d4c1c4..2f0cf6d924 100644 --- a/android/lib/resource/src/main/res/drawable/icon_success.xml +++ b/android/lib/resource/src/main/res/drawable/icon_success.xml @@ -1,11 +1,12 @@ -<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="44dp" - android:height="44dp" - android:viewportWidth="44.0" - android:viewportHeight="44.0"> - <path android:fillColor="#fff" - android:pathData="M22,22m-22,0a22,22 0,1 1,44 0a22,22 0,1 1,-44 0" /> - <path android:fillColor="#44AD4D" - android:pathData="M11.4142136,20.5857864 C10.633165,19.8047379 9.366835,19.8047379 8.5857864,20.5857864 C7.8047379,21.366835 7.8047379,22.633165 8.5857864,23.4142136 L16.5857864,31.4142136 C17.366835,32.1952621 18.633165,32.1952621 19.4142136,31.4142136 L35.4142136,15.4142136 C36.1952621,14.633165 36.1952621,13.366835 35.4142136,12.5857864 C34.633165,11.8047379 33.366835,11.8047379 32.5857864,12.5857864 L18,27.1715729 L11.4142136,20.5857864 Z" /> + android:width="48dp" + android:height="48dp" + android:viewportWidth="48" + android:viewportHeight="48"> + <path + android:pathData="M24,44C35.046,44 44,35.046 44,24C44,12.954 35.046,4 24,4C12.954,4 4,12.954 4,24C4,35.046 12.954,44 24,44Z" + android:fillColor="#ffffff"/> + <path + android:pathData="M14.377,22.725C14.034,22.386 13.572,22.197 13.091,22.197C12.61,22.197 12.148,22.386 11.806,22.725C11.638,22.891 11.504,23.089 11.413,23.308C11.322,23.526 11.275,23.761 11.275,23.997C11.275,24.234 11.322,24.468 11.413,24.687C11.504,24.905 11.638,25.103 11.806,25.27L19.078,32.482C19.421,32.82 19.882,33.01 20.364,33.01C20.845,33.01 21.307,32.82 21.649,32.482L36.195,18.057C36.363,17.891 36.496,17.692 36.587,17.474C36.678,17.255 36.725,17.021 36.725,16.785C36.725,16.548 36.678,16.314 36.587,16.095C36.496,15.877 36.363,15.678 36.195,15.512C35.852,15.174 35.39,14.984 34.909,14.984C34.428,14.984 33.966,15.174 33.624,15.512L20.364,28.662L14.377,22.725Z" + android:fillColor="#44AD4D"/> </vector> diff --git a/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt b/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt index 77ac2c3e62..e7e38534ba 100644 --- a/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt +++ b/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt @@ -7,11 +7,10 @@ data class Dimensions( val accountRowMinHeight: Dp = 48.dp, val accountRowSpacing: Dp = 24.dp, val addIconSize: Dp = 24.dp, - val bigIconSize: Dp = 44.dp, + val bigIconSize: Dp = 40.dp, val bottomPadding: Dp = 4.dp, val buttonHeight: Dp = 44.dp, - val buttonSpacing: Dp = 12.dp, - val buttonVerticalPadding: Dp = 8.dp, + val buttonSpacing: Dp = 8.dp, val cellEndPadding: Dp = 16.dp, val cellFooterTopPadding: Dp = 6.dp, val cellHeight: Dp = 56.dp, @@ -22,7 +21,7 @@ data class Dimensions( val cellVerticalSpacing: Dp = 24.dp, val chipSpace: Dp = 8.dp, val chipVerticalPadding: Dp = 4.dp, - val circularProgressBarLargeSize: Dp = 44.dp, + val circularProgressBarLargeSize: Dp = 40.dp, val circularProgressBarLargeStrokeWidth: Dp = 6.dp, val circularProgressBarMediumSize: Dp = 32.dp, val circularProgressBarMediumStrokeWidth: Dp = 4.dp, @@ -57,7 +56,8 @@ data class Dimensions( val problemReportIconToTitlePadding: Dp = 60.dp, val reconnectButtonMinInteractiveComponentSize: Dp = 40.dp, val relayCircleSize: Dp = 16.dp, - val screenVerticalMargin: Dp = 24.dp, + val screenBottomMargin: Dp = 16.dp, + val screenTopMargin: Dp = 24.dp, val searchFieldHeight: Dp = 42.dp, val searchFieldHeightExpanded: Dp = 72.dp, val searchFieldHorizontalPadding: Dp = 22.dp, @@ -77,7 +77,6 @@ data class Dimensions( val switchLocationRetryMinWidth: Dp = 48.dp, val tinyPadding: Dp = 4.dp, val titleIconSize: Dp = 48.dp, - val topPadding: Dp = 20.dp, val tvDrawerHeaderStartPadding: Dp = 12.dp, val tvDrawerHeaderWithFocusStartPadding: Dp = 16.dp, val tvDrawerHorizontalPadding: Dp = 12.dp, diff --git a/android/lib/tv/src/main/kotlin/net/mullvad/mullvadvpn/lib/tv/NavigationDrawerTv.kt b/android/lib/tv/src/main/kotlin/net/mullvad/mullvadvpn/lib/tv/NavigationDrawerTv.kt index 2b74716950..56b15f9616 100644 --- a/android/lib/tv/src/main/kotlin/net/mullvad/mullvadvpn/lib/tv/NavigationDrawerTv.kt +++ b/android/lib/tv/src/main/kotlin/net/mullvad/mullvadvpn/lib/tv/NavigationDrawerTv.kt @@ -103,8 +103,8 @@ fun NavigationDrawerTv( Modifier.fillMaxHeight() .background(brush) .padding( - top = Dimens.screenVerticalMargin, - bottom = Dimens.screenVerticalMargin, + top = Dimens.screenBottomMargin, + bottom = Dimens.screenBottomMargin, start = Dimens.tvDrawerHorizontalPadding, end = Dimens.tvDrawerHorizontalPadding, ) diff --git a/android/lib/ui/component/src/main/kotlin/net/mullvad/mullvadvpn/lib/ui/component/AnimatedNotificationBanner.kt b/android/lib/ui/component/src/main/kotlin/net/mullvad/mullvadvpn/lib/ui/component/AnimatedNotificationBanner.kt index ba0a936109..62c3b5522a 100644 --- a/android/lib/ui/component/src/main/kotlin/net/mullvad/mullvadvpn/lib/ui/component/AnimatedNotificationBanner.kt +++ b/android/lib/ui/component/src/main/kotlin/net/mullvad/mullvadvpn/lib/ui/component/AnimatedNotificationBanner.kt @@ -18,6 +18,7 @@ import androidx.compose.material3.Text 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.graphics.vector.ImageVector import androidx.compose.ui.platform.testTag import androidx.compose.ui.semantics.Role @@ -184,6 +185,7 @@ private fun NotificationDot(statusLevel: StatusLevel, modifier: Modifier) { StatusLevel.Error -> MaterialTheme.colorScheme.error StatusLevel.Warning -> MaterialTheme.colorScheme.warning StatusLevel.Info -> MaterialTheme.colorScheme.tertiary + StatusLevel.None -> Color.Transparent }, shape = CircleShape, ) diff --git a/android/lib/ui/component/src/main/kotlin/net/mullvad/mullvadvpn/lib/ui/component/NotificationData.kt b/android/lib/ui/component/src/main/kotlin/net/mullvad/mullvadvpn/lib/ui/component/NotificationData.kt index c9bfcd887d..ed3da5b1b1 100644 --- a/android/lib/ui/component/src/main/kotlin/net/mullvad/mullvadvpn/lib/ui/component/NotificationData.kt +++ b/android/lib/ui/component/src/main/kotlin/net/mullvad/mullvadvpn/lib/ui/component/NotificationData.kt @@ -90,7 +90,7 @@ fun InAppNotification.toNotificationData( stringResource(id = R.string.new_device_notification_message, deviceName) .formatWithHtml() ), - statusLevel = StatusLevel.Info, + statusLevel = statusLevel, action = NotificationAction( Icons.Default.Clear, @@ -102,7 +102,7 @@ fun InAppNotification.toNotificationData( NotificationData( title = stringResource(id = R.string.account_credit_expires_soon), message = LocalContext.current.resources.getExpiryQuantityString(expiry), - statusLevel = StatusLevel.Error, + statusLevel = statusLevel, action = if (isPlayBuild) null else @@ -115,15 +115,15 @@ fun InAppNotification.toNotificationData( InAppNotification.TunnelStateBlocked -> NotificationData( title = stringResource(id = R.string.blocking_internet), - statusLevel = StatusLevel.Error, + statusLevel = StatusLevel.None, ) is InAppNotification.TunnelStateError -> - errorMessageBannerData(error, onClickShowWireguardPortSettings) + errorMessageBannerData(statusLevel, error, onClickShowWireguardPortSettings) is InAppNotification.UnsupportedVersion -> NotificationData( title = stringResource(id = R.string.unsupported_version), message = stringResource(id = R.string.unsupported_version_description), - statusLevel = StatusLevel.Error, + statusLevel = statusLevel, action = NotificationAction( Icons.AutoMirrored.Default.OpenInNew, @@ -150,7 +150,7 @@ fun InAppNotification.toNotificationData( contentDescription = stringResource(id = R.string.new_changelog_notification_message), ), - statusLevel = StatusLevel.Info, + statusLevel = statusLevel, action = NotificationAction( Icons.Default.Clear, @@ -162,13 +162,14 @@ fun InAppNotification.toNotificationData( @Composable private fun errorMessageBannerData( + statusLevel: StatusLevel, error: ErrorState, onClickShowWireguardPortSettings: () -> Unit, ) = NotificationData( title = error.title().formatWithHtml(), message = NotificationMessage.Text(error.message(onClickShowWireguardPortSettings)), - statusLevel = StatusLevel.Error, + statusLevel = statusLevel, ) @Composable |
