summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Göransson <david.goransson@mullvad.net>2025-05-15 13:54:08 +0200
committerDavid Göransson <david.goransson@mullvad.net>2025-05-15 13:54:08 +0200
commit1957ca9181c3badffc103166c3d4f668694e0345 (patch)
tree8d2988cca39fd83fb7ace454b6bca6348facb9d3
parent5cad8a58a60dd5b544ef96820a7be965b9a3febd (diff)
parent2658a984765bae7d097b530acf92d47aabe52da1 (diff)
downloadmullvadvpn-1957ca9181c3badffc103166c3d4f668694e0345.tar.xz
mullvadvpn-1957ca9181c3badffc103166c3d4f668694e0345.zip
Merge branch 'design-review-changes'
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/location/SelectLocationScreenTest.kt16
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/button/MullvadButton.kt4
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CheckboxCell.kt8
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/CustomPortCell.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/DnsCell.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/FilterRow.kt4
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SelectableCell.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SplitTunnelingCell.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/SwitchComposeCell.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/CircularProgressIndicator.kt1
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/EmptyRelayListText.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/FeatureChip.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/LocationsEmptyText.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/PlayPayment.kt8
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/Scaffolding.kt6
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/TopBar.kt4
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/SaveApiAccessMethodDialog.kt12
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/info/InfoConfirmationDialog.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/payment/PaymentDialog.kt4
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/SelectLocationsUiStatePreviewParameterProvider.kt12
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreen.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AutoConnectAndLockdownModeScreen.kt33
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt16
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/CustomListsScreen.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceListScreen.kt24
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceRevokedScreen.kt97
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditApiAccessMethodScreen.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditCustomListScreen.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/FilterScreen.kt59
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/LoginScreen.kt6
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/OutOfTimeScreen.kt49
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/PrivacyDisclaimerScreen.kt7
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ReportProblemScreen.kt12
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ServerIpOverridesScreen.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ViewLogsScreen.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt9
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreen.kt8
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/location/SelectLocationScreen.kt31
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/SelectLocationUiState.kt3
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/InAppNotificationController.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationListViewModel.kt8
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModel.kt11
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SettingsUtil.kt10
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/InAppNotificationControllerTest.kt1
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModelTest.kt1
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/location/SelectLocationViewModelTest.kt6
-rw-r--r--android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/InAppNotification.kt18
-rw-r--r--android/lib/resource/src/main/res/drawable/icon_fail.xml18
-rw-r--r--android/lib/resource/src/main/res/drawable/icon_success.xml19
-rw-r--r--android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt11
-rw-r--r--android/lib/tv/src/main/kotlin/net/mullvad/mullvadvpn/lib/tv/NavigationDrawerTv.kt4
-rw-r--r--android/lib/ui/component/src/main/kotlin/net/mullvad/mullvadvpn/lib/ui/component/AnimatedNotificationBanner.kt2
-rw-r--r--android/lib/ui/component/src/main/kotlin/net/mullvad/mullvadvpn/lib/ui/component/NotificationData.kt15
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