summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
authorDavid Göransson <david.goransson90@gmail.com>2024-03-04 10:40:49 +0100
committerAlbin <albin@mullvad.net>2024-03-05 12:41:44 +0100
commit4ae1040d3a165df845333638518965ca79377b15 (patch)
treec98956b27be46c295e6e4a312d02346ffaa684ec /android
parentdbf70755217470d42da760471d6fa950489060de (diff)
downloadmullvadvpn-4ae1040d3a165df845333638518965ca79377b15.tar.xz
mullvadvpn-4ae1040d3a165df845333638518965ca79377b15.zip
Use collectAsStateWithLifecycle
Diffstat (limited to 'android')
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt20
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt49
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/FilterScreenTest.kt12
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/OutOfTimeScreenTest.kt22
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/RedeemVoucherDialogTest.kt12
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreenTest.kt10
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt4
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreenTest.kt12
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt42
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreenTest.kt23
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialog.kt6
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt50
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/payment/PaymentDialog.kt9
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreen.kt22
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt52
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceListScreen.kt4
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceRevokedScreen.kt4
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/FilterScreen.kt24
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/LoginScreen.kt57
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/OutOfTimeScreen.kt35
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/PrivacyDisclaimerScreen.kt11
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ReportProblemScreen.kt32
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreen.kt35
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreen.kt30
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreen.kt41
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ViewLogsScreen.kt29
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt88
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreen.kt34
28 files changed, 382 insertions, 387 deletions
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt
index 88aae0dd2f..a40cb14d65 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt
@@ -41,7 +41,7 @@ class AccountScreenTest {
// Arrange
setContentWithTheme {
AccountScreen(
- uiState =
+ state =
AccountUiState(
deviceName = DUMMY_DEVICE_NAME,
accountNumber = DUMMY_ACCOUNT_NUMBER,
@@ -65,7 +65,7 @@ class AccountScreenTest {
val mockedClickHandler: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
AccountScreen(
- uiState =
+ state =
AccountUiState(
showSitePayment = true,
deviceName = DUMMY_DEVICE_NAME,
@@ -92,7 +92,7 @@ class AccountScreenTest {
val mockedClickHandler: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
AccountScreen(
- uiState =
+ state =
AccountUiState(
deviceName = DUMMY_DEVICE_NAME,
accountNumber = DUMMY_ACCOUNT_NUMBER,
@@ -119,7 +119,7 @@ class AccountScreenTest {
val mockedClickHandler: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
AccountScreen(
- uiState =
+ state =
AccountUiState(
deviceName = DUMMY_DEVICE_NAME,
accountNumber = DUMMY_ACCOUNT_NUMBER,
@@ -145,7 +145,7 @@ class AccountScreenTest {
// Arrange
setContentWithTheme {
AccountScreen(
- uiState =
+ state =
AccountUiState.default()
.copy(billingPaymentState = PaymentState.Error.Billing),
uiSideEffect =
@@ -166,7 +166,7 @@ class AccountScreenTest {
every { mockPaymentProduct.status } returns null
setContentWithTheme {
AccountScreen(
- uiState =
+ state =
AccountUiState.default()
.copy(
billingPaymentState =
@@ -190,7 +190,7 @@ class AccountScreenTest {
every { mockPaymentProduct.status } returns PaymentStatus.PENDING
setContentWithTheme {
AccountScreen(
- uiState =
+ state =
AccountUiState.default()
.copy(
billingPaymentState =
@@ -215,7 +215,7 @@ class AccountScreenTest {
val mockNavigateToVerificationPending: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
AccountScreen(
- uiState =
+ state =
AccountUiState.default()
.copy(
billingPaymentState =
@@ -243,7 +243,7 @@ class AccountScreenTest {
every { mockPaymentProduct.status } returns PaymentStatus.VERIFICATION_IN_PROGRESS
setContentWithTheme {
AccountScreen(
- uiState =
+ state =
AccountUiState.default()
.copy(
billingPaymentState =
@@ -269,7 +269,7 @@ class AccountScreenTest {
every { mockPaymentProduct.status } returns null
setContentWithTheme {
AccountScreen(
- uiState =
+ state =
AccountUiState.default()
.copy(
billingPaymentState =
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt
index 630c70e96a..851866818b 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt
@@ -58,7 +58,7 @@ class ConnectScreenTest {
// Arrange
setContentWithTheme {
ConnectScreen(
- uiState = ConnectUiState.INITIAL,
+ state = ConnectUiState.INITIAL,
)
}
@@ -75,7 +75,7 @@ class ConnectScreenTest {
// Arrange
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = null,
@@ -109,7 +109,7 @@ class ConnectScreenTest {
every { mockTunnelEndpoint.quantumResistant } returns true
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = null,
@@ -144,7 +144,7 @@ class ConnectScreenTest {
val mockTunnelEndpoint: TunnelEndpoint = mockk(relaxed = true)
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = null,
@@ -176,7 +176,7 @@ class ConnectScreenTest {
every { mockTunnelEndpoint.quantumResistant } returns true
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = null,
@@ -209,7 +209,7 @@ class ConnectScreenTest {
every { mockSelectedLocation.locationName } returns mockLocationName
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = mockSelectedLocation,
@@ -244,7 +244,7 @@ class ConnectScreenTest {
every { mockSelectedLocation.locationName } returns mockLocationName
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = mockSelectedLocation,
@@ -277,7 +277,7 @@ class ConnectScreenTest {
every { mockSelectedLocation.locationName } returns mockLocationName
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = mockSelectedLocation,
@@ -320,7 +320,7 @@ class ConnectScreenTest {
every { mockSelectedLocation.locationName } returns mockLocationName
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = mockSelectedLocation,
@@ -361,7 +361,7 @@ class ConnectScreenTest {
// Arrange
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = null,
@@ -398,7 +398,7 @@ class ConnectScreenTest {
every { mockSelectedLocation.locationName } returns mockLocationName
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = mockSelectedLocation,
@@ -434,7 +434,7 @@ class ConnectScreenTest {
val mockedClickHandler: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = mockSelectedLocation,
@@ -468,7 +468,7 @@ class ConnectScreenTest {
val mockedClickHandler: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = null,
@@ -502,7 +502,7 @@ class ConnectScreenTest {
val mockedClickHandler: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = null,
@@ -535,7 +535,7 @@ class ConnectScreenTest {
val mockedClickHandler: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = null,
@@ -568,7 +568,7 @@ class ConnectScreenTest {
val mockedClickHandler: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = null,
@@ -609,7 +609,7 @@ class ConnectScreenTest {
every { mockLocation.hostname } returns mockHostName
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = mockLocation,
selectedRelayItem = null,
@@ -650,7 +650,7 @@ class ConnectScreenTest {
)
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = null,
@@ -686,7 +686,7 @@ class ConnectScreenTest {
)
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = null,
@@ -719,7 +719,7 @@ class ConnectScreenTest {
val expiryDate = DateTime(2020, 11, 11, 10, 10)
setContentWithTheme {
ConnectScreen(
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = null,
@@ -757,7 +757,7 @@ class ConnectScreenTest {
setContentWithTheme {
ConnectScreen(
onUpdateVersionClick = mockedClickHandler,
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = null,
@@ -791,7 +791,7 @@ class ConnectScreenTest {
setContentWithTheme {
ConnectScreen(
onManageAccountClick = mockedClickHandler,
- uiState =
+ state =
ConnectUiState(
location = null,
selectedRelayItem = null,
@@ -822,10 +822,7 @@ class ConnectScreenTest {
// Arrange
val onAccountClickMockk: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
- ConnectScreen(
- uiState = ConnectUiState.INITIAL,
- onAccountClick = onAccountClickMockk
- )
+ ConnectScreen(state = ConnectUiState.INITIAL, onAccountClick = onAccountClickMockk)
}
// Assert
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/FilterScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/FilterScreenTest.kt
index 4eb3c4517c..c57c5c3f62 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/FilterScreenTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/FilterScreenTest.kt
@@ -27,7 +27,7 @@ class FilterScreenTest {
composeExtension.use {
setContentWithTheme {
FilterScreen(
- uiState =
+ state =
RelayFilterState(
allProviders = DUMMY_RELAY_ALL_PROVIDERS,
selectedOwnership = null,
@@ -45,7 +45,7 @@ class FilterScreenTest {
composeExtension.use {
setContentWithTheme {
FilterScreen(
- uiState =
+ state =
RelayFilterState(
allProviders = DUMMY_RELAY_ALL_PROVIDERS,
selectedOwnership = null,
@@ -63,7 +63,7 @@ class FilterScreenTest {
composeExtension.use {
setContentWithTheme {
FilterScreen(
- uiState =
+ state =
RelayFilterState(
allProviders = DUMMY_RELAY_ALL_PROVIDERS,
selectedOwnership = Ownership.MullvadOwned,
@@ -81,7 +81,7 @@ class FilterScreenTest {
composeExtension.use {
setContentWithTheme {
FilterScreen(
- uiState =
+ state =
RelayFilterState(
allProviders = DUMMY_RELAY_ALL_PROVIDERS,
selectedOwnership = Ownership.Rented,
@@ -99,7 +99,7 @@ class FilterScreenTest {
composeExtension.use {
setContentWithTheme {
FilterScreen(
- uiState =
+ state =
RelayFilterState(
allProviders = DUMMY_RELAY_ALL_PROVIDERS,
selectedOwnership = null,
@@ -120,7 +120,7 @@ class FilterScreenTest {
val mockClickListener: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
FilterScreen(
- uiState =
+ state =
RelayFilterState(
allProviders = listOf(),
selectedOwnership = null,
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/OutOfTimeScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/OutOfTimeScreenTest.kt
index 548114a760..f54944356f 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/OutOfTimeScreenTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/OutOfTimeScreenTest.kt
@@ -37,7 +37,7 @@ class OutOfTimeScreenTest {
// Arrange
setContentWithTheme {
OutOfTimeScreen(
- uiState = OutOfTimeUiState(deviceName = ""),
+ state = OutOfTimeUiState(deviceName = ""),
onSitePaymentClick = {},
onRedeemVoucherClick = {},
onSettingsClick = {},
@@ -61,7 +61,7 @@ class OutOfTimeScreenTest {
// Arrange
setContentWithTheme {
OutOfTimeScreen(
- uiState = OutOfTimeUiState(deviceName = "", showSitePayment = true),
+ state = OutOfTimeUiState(deviceName = "", showSitePayment = true),
onSitePaymentClick = {},
onRedeemVoucherClick = {},
onSettingsClick = {},
@@ -81,7 +81,7 @@ class OutOfTimeScreenTest {
val mockClickListener: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
OutOfTimeScreen(
- uiState = OutOfTimeUiState(deviceName = "", showSitePayment = true),
+ state = OutOfTimeUiState(deviceName = "", showSitePayment = true),
onSitePaymentClick = mockClickListener,
onRedeemVoucherClick = {},
onSettingsClick = {},
@@ -104,7 +104,7 @@ class OutOfTimeScreenTest {
val mockClickListener: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
OutOfTimeScreen(
- uiState = OutOfTimeUiState(deviceName = "", showSitePayment = true),
+ state = OutOfTimeUiState(deviceName = "", showSitePayment = true),
onSitePaymentClick = {},
onRedeemVoucherClick = mockClickListener,
onSettingsClick = {},
@@ -127,7 +127,7 @@ class OutOfTimeScreenTest {
val mockClickListener: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
OutOfTimeScreen(
- uiState =
+ state =
OutOfTimeUiState(
tunnelState = TunnelState.Connecting(null, null),
deviceName = "",
@@ -154,7 +154,7 @@ class OutOfTimeScreenTest {
// Arrange
setContentWithTheme {
OutOfTimeScreen(
- uiState =
+ state =
OutOfTimeUiState(
showSitePayment = true,
billingPaymentState = PaymentState.Error.Billing
@@ -180,7 +180,7 @@ class OutOfTimeScreenTest {
every { mockPaymentProduct.status } returns null
setContentWithTheme {
OutOfTimeScreen(
- uiState =
+ state =
OutOfTimeUiState(
showSitePayment = true,
billingPaymentState =
@@ -207,7 +207,7 @@ class OutOfTimeScreenTest {
every { mockPaymentProduct.status } returns PaymentStatus.PENDING
setContentWithTheme {
OutOfTimeScreen(
- uiState =
+ state =
OutOfTimeUiState(
showSitePayment = true,
billingPaymentState =
@@ -230,7 +230,7 @@ class OutOfTimeScreenTest {
val mockNavigateToVerificationPending: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
OutOfTimeScreen(
- uiState =
+ state =
OutOfTimeUiState(
showSitePayment = true,
billingPaymentState =
@@ -257,7 +257,7 @@ class OutOfTimeScreenTest {
every { mockPaymentProduct.status } returns PaymentStatus.VERIFICATION_IN_PROGRESS
setContentWithTheme {
OutOfTimeScreen(
- uiState =
+ state =
OutOfTimeUiState(
billingPaymentState =
PaymentState.PaymentAvailable(listOf(mockPaymentProduct)),
@@ -281,7 +281,7 @@ class OutOfTimeScreenTest {
every { mockPaymentProduct.status } returns null
setContentWithTheme {
OutOfTimeScreen(
- uiState =
+ state =
OutOfTimeUiState(
billingPaymentState =
PaymentState.PaymentAvailable(listOf(mockPaymentProduct)),
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/RedeemVoucherDialogTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/RedeemVoucherDialogTest.kt
index 34a8a8908f..b3ac57d95c 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/RedeemVoucherDialogTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/RedeemVoucherDialogTest.kt
@@ -35,7 +35,7 @@ class RedeemVoucherDialogTest {
val mockedClickHandler: (Boolean) -> Unit = mockk(relaxed = true)
setContentWithTheme {
RedeemVoucherDialog(
- uiState = VoucherDialogUiState.INITIAL,
+ state = VoucherDialogUiState.INITIAL,
onVoucherInputChange = {},
onRedeem = {},
onDismiss = mockedClickHandler
@@ -56,7 +56,7 @@ class RedeemVoucherDialogTest {
val mockedClickHandler: (Boolean) -> Unit = mockk(relaxed = true)
setContentWithTheme {
RedeemVoucherDialog(
- uiState = VoucherDialogUiState(voucherState = VoucherDialogState.Success(0)),
+ state = VoucherDialogUiState(voucherState = VoucherDialogState.Success(0)),
onVoucherInputChange = {},
onRedeem = {},
onDismiss = mockedClickHandler
@@ -77,7 +77,7 @@ class RedeemVoucherDialogTest {
val mockedClickHandler: (String) -> Unit = mockk(relaxed = true)
setContentWithTheme {
RedeemVoucherDialog(
- uiState = VoucherDialogUiState(),
+ state = VoucherDialogUiState(),
onVoucherInputChange = mockedClickHandler,
onRedeem = {},
onDismiss = {}
@@ -97,7 +97,7 @@ class RedeemVoucherDialogTest {
// Arrange
setContentWithTheme {
RedeemVoucherDialog(
- uiState = VoucherDialogUiState(voucherState = VoucherDialogState.Verifying),
+ state = VoucherDialogUiState(voucherState = VoucherDialogState.Verifying),
onVoucherInputChange = {},
onRedeem = {},
onDismiss = {}
@@ -114,7 +114,7 @@ class RedeemVoucherDialogTest {
// Arrange
setContentWithTheme {
RedeemVoucherDialog(
- uiState = VoucherDialogUiState(voucherState = VoucherDialogState.Success(0)),
+ state = VoucherDialogUiState(voucherState = VoucherDialogState.Success(0)),
onVoucherInputChange = {},
onRedeem = {},
onDismiss = {}
@@ -131,7 +131,7 @@ class RedeemVoucherDialogTest {
// Arrange
setContentWithTheme {
RedeemVoucherDialog(
- uiState =
+ state =
VoucherDialogUiState(
voucherState = VoucherDialogState.Error(ERROR_MESSAGE)
),
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreenTest.kt
index 475e3a8802..fe28357048 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreenTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreenTest.kt
@@ -40,7 +40,7 @@ class SelectLocationScreenTest {
// Arrange
setContentWithTheme {
SelectLocationScreen(
- uiState = SelectLocationUiState.Loading,
+ state = SelectLocationUiState.Loading,
)
}
@@ -54,7 +54,7 @@ class SelectLocationScreenTest {
// Arrange
setContentWithTheme {
SelectLocationScreen(
- uiState =
+ state =
SelectLocationUiState.Data(
relayListState =
RelayListState.RelayList(
@@ -94,7 +94,7 @@ class SelectLocationScreenTest {
// Arrange
setContentWithTheme {
SelectLocationScreen(
- uiState =
+ state =
SelectLocationUiState.Data(
relayListState =
RelayListState.RelayList(
@@ -124,7 +124,7 @@ class SelectLocationScreenTest {
val mockedSearchTermInput: (String) -> Unit = mockk(relaxed = true)
setContentWithTheme {
SelectLocationScreen(
- uiState =
+ state =
SelectLocationUiState.Data(
relayListState =
RelayListState.RelayList(
@@ -155,7 +155,7 @@ class SelectLocationScreenTest {
val mockSearchString = "SEARCH"
setContentWithTheme {
SelectLocationScreen(
- uiState =
+ state =
SelectLocationUiState.Data(
relayListState = RelayListState.Empty,
selectedOwnership = null,
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt
index 7a4cb6c2c2..b8b6a4e4b8 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt
@@ -27,7 +27,7 @@ class SettingsScreenTest {
// Arrange
setContentWithTheme {
SettingsScreen(
- uiState =
+ state =
SettingsUiState(
appVersion = "",
isLoggedIn = true,
@@ -49,7 +49,7 @@ class SettingsScreenTest {
// Arrange
setContentWithTheme {
SettingsScreen(
- uiState =
+ state =
SettingsUiState(
appVersion = "",
isLoggedIn = false,
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreenTest.kt
index 766bbc961f..89f1a58f7a 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreenTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreenTest.kt
@@ -35,7 +35,7 @@ class SplitTunnelingScreenTest {
composeExtension.use {
// Arrange
setContentWithTheme {
- SplitTunnelingScreen(uiState = SplitTunnelingUiState.Loading(enabled = true))
+ SplitTunnelingScreen(state = SplitTunnelingUiState.Loading(enabled = true))
}
// Assert
@@ -64,7 +64,7 @@ class SplitTunnelingScreenTest {
)
setContentWithTheme {
SplitTunnelingScreen(
- uiState =
+ state =
SplitTunnelingUiState.ShowAppList(
enabled = true,
excludedApps = listOf(excludedApp),
@@ -96,7 +96,7 @@ class SplitTunnelingScreenTest {
)
setContentWithTheme {
SplitTunnelingScreen(
- uiState =
+ state =
SplitTunnelingUiState.ShowAppList(
enabled = true,
excludedApps = emptyList(),
@@ -135,7 +135,7 @@ class SplitTunnelingScreenTest {
val mockedClickHandler: (String) -> Unit = mockk(relaxed = true)
setContentWithTheme {
SplitTunnelingScreen(
- uiState =
+ state =
SplitTunnelingUiState.ShowAppList(
enabled = true,
excludedApps = listOf(excludedApp),
@@ -172,7 +172,7 @@ class SplitTunnelingScreenTest {
val mockedClickHandler: (String) -> Unit = mockk(relaxed = true)
setContentWithTheme {
SplitTunnelingScreen(
- uiState =
+ state =
SplitTunnelingUiState.ShowAppList(
enabled = true,
excludedApps = listOf(excludedApp),
@@ -209,7 +209,7 @@ class SplitTunnelingScreenTest {
val mockedClickHandler: (Boolean) -> Unit = mockk(relaxed = true)
setContentWithTheme {
SplitTunnelingScreen(
- uiState =
+ state =
SplitTunnelingUiState.ShowAppList(
enabled = true,
excludedApps = listOf(excludedApp),
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt
index 8c686e8489..471e39c38f 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt
@@ -45,7 +45,7 @@ class VpnSettingsScreenTest {
// Arrange
setContentWithTheme {
VpnSettingsScreen(
- uiState = VpnSettingsUiState.createDefault(),
+ state = VpnSettingsUiState.createDefault(),
)
}
@@ -67,7 +67,7 @@ class VpnSettingsScreenTest {
// Arrange
setContentWithTheme {
VpnSettingsScreen(
- uiState = VpnSettingsUiState.createDefault(mtu = VALID_DUMMY_MTU_VALUE),
+ state = VpnSettingsUiState.createDefault(mtu = VALID_DUMMY_MTU_VALUE),
)
}
@@ -84,7 +84,7 @@ class VpnSettingsScreenTest {
// Arrange
setContentWithTheme {
VpnSettingsScreen(
- uiState =
+ state =
VpnSettingsUiState.createDefault(
isCustomDnsEnabled = true,
customDnsItems =
@@ -110,7 +110,7 @@ class VpnSettingsScreenTest {
// Arrange
setContentWithTheme {
VpnSettingsScreen(
- uiState =
+ state =
VpnSettingsUiState.createDefault(
isCustomDnsEnabled = false,
customDnsItems =
@@ -131,7 +131,7 @@ class VpnSettingsScreenTest {
// Arrange
setContentWithTheme {
VpnSettingsScreen(
- uiState =
+ state =
VpnSettingsUiState.createDefault(
isCustomDnsEnabled = true,
isLocalNetworkSharingEnabled = true,
@@ -151,7 +151,7 @@ class VpnSettingsScreenTest {
// Arrange
setContentWithTheme {
VpnSettingsScreen(
- uiState =
+ state =
VpnSettingsUiState.createDefault(
isCustomDnsEnabled = true,
customDnsItems =
@@ -170,7 +170,7 @@ class VpnSettingsScreenTest {
// Arrange
setContentWithTheme {
VpnSettingsScreen(
- uiState =
+ state =
VpnSettingsUiState.createDefault(
isCustomDnsEnabled = true,
customDnsItems =
@@ -189,7 +189,7 @@ class VpnSettingsScreenTest {
// Arrange
setContentWithTheme {
VpnSettingsScreen(
- uiState =
+ state =
VpnSettingsUiState.createDefault(
isCustomDnsEnabled = true,
customDnsItems =
@@ -208,7 +208,7 @@ class VpnSettingsScreenTest {
// Arrange
setContentWithTheme {
VpnSettingsScreen(
- uiState =
+ state =
VpnSettingsUiState.createDefault(
quantumResistant = QuantumResistantState.On
),
@@ -230,7 +230,7 @@ class VpnSettingsScreenTest {
mockk(relaxed = true)
setContentWithTheme {
VpnSettingsScreen(
- uiState =
+ state =
VpnSettingsUiState.createDefault(
quantumResistant = QuantumResistantState.Auto,
),
@@ -254,7 +254,7 @@ class VpnSettingsScreenTest {
// Arrange
setContentWithTheme {
VpnSettingsScreen(
- uiState =
+ state =
VpnSettingsUiState.createDefault(
selectedWireguardPort = Constraint.Only(Port(53))
),
@@ -283,7 +283,7 @@ class VpnSettingsScreenTest {
mockk(relaxed = true)
setContentWithTheme {
VpnSettingsScreen(
- uiState =
+ state =
VpnSettingsUiState.createDefault(
selectedWireguardPort = Constraint.Only(Port(53))
),
@@ -314,7 +314,7 @@ class VpnSettingsScreenTest {
// Arrange
setContentWithTheme {
VpnSettingsScreen(
- uiState =
+ state =
VpnSettingsUiState.createDefault(
customWireguardPort = Constraint.Only(Port(4000))
),
@@ -336,7 +336,7 @@ class VpnSettingsScreenTest {
val onWireguardPortSelected: (Constraint<Port>) -> Unit = mockk(relaxed = true)
setContentWithTheme {
VpnSettingsScreen(
- uiState =
+ state =
VpnSettingsUiState.createDefault(
selectedWireguardPort = Constraint.Only(Port(4000)),
customWireguardPort = Constraint.Only(Port(4000))
@@ -363,7 +363,7 @@ class VpnSettingsScreenTest {
val mockedClickHandler: (Int?) -> Unit = mockk(relaxed = true)
setContentWithTheme {
VpnSettingsScreen(
- uiState = VpnSettingsUiState.createDefault(),
+ state = VpnSettingsUiState.createDefault(),
navigateToMtuDialog = mockedClickHandler
)
}
@@ -385,7 +385,7 @@ class VpnSettingsScreenTest {
val mockedClickHandler: (Int?, String?) -> Unit = mockk(relaxed = true)
setContentWithTheme {
VpnSettingsScreen(
- uiState = VpnSettingsUiState.createDefault(isCustomDnsEnabled = true),
+ state = VpnSettingsUiState.createDefault(isCustomDnsEnabled = true),
navigateToDns = mockedClickHandler
)
}
@@ -405,7 +405,7 @@ class VpnSettingsScreenTest {
// Arrange
setContentWithTheme {
VpnSettingsScreen(
- uiState = VpnSettingsUiState.createDefault(),
+ state = VpnSettingsUiState.createDefault(),
navigateToQuantumResistanceInfo = mockedShowTunnelQuantumInfoClick
)
}
@@ -428,7 +428,7 @@ class VpnSettingsScreenTest {
// Arrange
setContentWithTheme {
VpnSettingsScreen(
- uiState = VpnSettingsUiState.createDefault(),
+ state = VpnSettingsUiState.createDefault(),
navigateToWireguardPortInfo = mockedClickHandler
)
}
@@ -446,7 +446,7 @@ class VpnSettingsScreenTest {
// Arrange
setContentWithTheme {
VpnSettingsScreen(
- uiState = VpnSettingsUiState.createDefault(),
+ state = VpnSettingsUiState.createDefault(),
navigateToWireguardPortDialog = mockedClickHandler
)
}
@@ -466,7 +466,7 @@ class VpnSettingsScreenTest {
val mockOnShowCustomPortDialog: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
VpnSettingsScreen(
- uiState = VpnSettingsUiState.createDefault(),
+ state = VpnSettingsUiState.createDefault(),
navigateToWireguardPortDialog = mockOnShowCustomPortDialog
)
}
@@ -487,7 +487,7 @@ class VpnSettingsScreenTest {
val mockOnShowCustomPortDialog: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
VpnSettingsScreen(
- uiState =
+ state =
VpnSettingsUiState.createDefault(
selectedWireguardPort = Constraint.Only(Port(4000))
),
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreenTest.kt
index 49983faa27..d8711b4b61 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreenTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreenTest.kt
@@ -36,7 +36,7 @@ class WelcomeScreenTest {
// Arrange
setContentWithTheme {
WelcomeScreen(
- uiState = WelcomeUiState(),
+ state = WelcomeUiState(),
onSitePaymentClick = {},
onRedeemVoucherClick = {},
onSettingsClick = {},
@@ -58,7 +58,7 @@ class WelcomeScreenTest {
// Arrange
setContentWithTheme {
WelcomeScreen(
- uiState = WelcomeUiState(),
+ state = WelcomeUiState(),
onSitePaymentClick = {},
onRedeemVoucherClick = {},
onSettingsClick = {},
@@ -86,7 +86,7 @@ class WelcomeScreenTest {
val expectedAccountNumber = "1111 2222 3333 4444"
setContentWithTheme {
WelcomeScreen(
- uiState = WelcomeUiState(accountNumber = rawAccountNumber),
+ state = WelcomeUiState(accountNumber = rawAccountNumber),
onSitePaymentClick = {},
onRedeemVoucherClick = {},
onSettingsClick = {},
@@ -108,7 +108,7 @@ class WelcomeScreenTest {
val mockClickListener: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
WelcomeScreen(
- uiState = WelcomeUiState(showSitePayment = true),
+ state = WelcomeUiState(showSitePayment = true),
onSitePaymentClick = mockClickListener,
onRedeemVoucherClick = {},
onSettingsClick = {},
@@ -133,7 +133,7 @@ class WelcomeScreenTest {
val mockClickListener: () -> Unit = mockk(relaxed = true)
setContentWithTheme {
WelcomeScreen(
- uiState = WelcomeUiState(),
+ state = WelcomeUiState(),
onSitePaymentClick = {},
onRedeemVoucherClick = mockClickListener,
onSettingsClick = {},
@@ -157,8 +157,7 @@ class WelcomeScreenTest {
// Arrange
setContentWithTheme {
WelcomeScreen(
- uiState =
- WelcomeUiState().copy(billingPaymentState = PaymentState.Error.Billing),
+ state = WelcomeUiState().copy(billingPaymentState = PaymentState.Error.Billing),
onSitePaymentClick = {},
onRedeemVoucherClick = {},
onSettingsClick = {},
@@ -182,7 +181,7 @@ class WelcomeScreenTest {
every { mockPaymentProduct.status } returns null
setContentWithTheme {
WelcomeScreen(
- uiState =
+ state =
WelcomeUiState(
billingPaymentState =
PaymentState.PaymentAvailable(listOf(mockPaymentProduct))
@@ -210,7 +209,7 @@ class WelcomeScreenTest {
every { mockPaymentProduct.status } returns PaymentStatus.PENDING
setContentWithTheme {
WelcomeScreen(
- uiState =
+ state =
WelcomeUiState()
.copy(
billingPaymentState =
@@ -240,7 +239,7 @@ class WelcomeScreenTest {
val mockShowPendingInfo = mockk<() -> Unit>(relaxed = true)
setContentWithTheme {
WelcomeScreen(
- uiState =
+ state =
WelcomeUiState()
.copy(
billingPaymentState =
@@ -272,7 +271,7 @@ class WelcomeScreenTest {
every { mockPaymentProduct.status } returns PaymentStatus.VERIFICATION_IN_PROGRESS
setContentWithTheme {
WelcomeScreen(
- uiState =
+ state =
WelcomeUiState()
.copy(
billingPaymentState =
@@ -303,7 +302,7 @@ class WelcomeScreenTest {
every { mockPaymentProduct.status } returns null
setContentWithTheme {
WelcomeScreen(
- uiState =
+ state =
WelcomeUiState(
billingPaymentState =
PaymentState.PaymentAvailable(listOf(mockPaymentProduct))
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialog.kt
index 44f835c21e..b4b9d66efd 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialog.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialog.kt
@@ -9,12 +9,12 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.result.ResultBackNavigator
import com.ramcosta.composedestinations.spec.DestinationStyle
@@ -107,10 +107,10 @@ fun DnsDialog(
}
}
}
- val state by viewModel.uiState.collectAsState(null)
+ val state by viewModel.uiState.collectAsStateWithLifecycle()
DnsDialog(
- state ?: return,
+ state,
viewModel::onDnsInputChange,
onSaveDnsClick = viewModel::onSaveDnsClick,
onRemoveDnsClick = viewModel::onRemoveDnsClick,
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt
index a9029a3758..88eb682849 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt
@@ -12,7 +12,7 @@ import androidx.compose.material3.AlertDialog
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
@@ -24,6 +24,7 @@ import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.window.DialogProperties
import androidx.compose.ui.window.SecureFlagPolicy
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.result.ResultBackNavigator
import com.ramcosta.composedestinations.spec.DestinationStyle
@@ -51,7 +52,7 @@ import org.koin.androidx.compose.koinViewModel
private fun PreviewRedeemVoucherDialog() {
AppTheme {
RedeemVoucherDialog(
- uiState = VoucherDialogUiState.INITIAL,
+ state = VoucherDialogUiState.INITIAL,
onVoucherInputChange = {},
onRedeem = {},
onDismiss = {}
@@ -64,7 +65,7 @@ private fun PreviewRedeemVoucherDialog() {
private fun PreviewRedeemVoucherDialogVerifying() {
AppTheme {
RedeemVoucherDialog(
- uiState = VoucherDialogUiState("", VoucherDialogState.Verifying),
+ state = VoucherDialogUiState("", VoucherDialogState.Verifying),
onVoucherInputChange = {},
onRedeem = {},
onDismiss = {}
@@ -77,7 +78,7 @@ private fun PreviewRedeemVoucherDialogVerifying() {
private fun PreviewRedeemVoucherDialogError() {
AppTheme {
RedeemVoucherDialog(
- uiState = VoucherDialogUiState("", VoucherDialogState.Error("An Error message")),
+ state = VoucherDialogUiState("", VoucherDialogState.Error("An Error message")),
onVoucherInputChange = {},
onRedeem = {},
onDismiss = {}
@@ -90,7 +91,7 @@ private fun PreviewRedeemVoucherDialogError() {
private fun PreviewRedeemVoucherDialogSuccess() {
AppTheme {
RedeemVoucherDialog(
- uiState = VoucherDialogUiState("", VoucherDialogState.Success(3600)),
+ state = VoucherDialogUiState("", VoucherDialogState.Success(3600)),
onVoucherInputChange = {},
onRedeem = {},
onDismiss = {}
@@ -102,8 +103,9 @@ private fun PreviewRedeemVoucherDialogSuccess() {
@Composable
fun RedeemVoucher(resultBackNavigator: ResultBackNavigator<Boolean>) {
val vm = koinViewModel<VoucherDialogViewModel>()
+ val state by vm.uiState.collectAsStateWithLifecycle()
RedeemVoucherDialog(
- uiState = vm.uiState.collectAsState().value,
+ state = state,
onVoucherInputChange = vm::onVoucherInputChange,
onRedeem = vm::onRedeem,
onDismiss = { resultBackNavigator.navigateBack(result = it) }
@@ -112,37 +114,37 @@ fun RedeemVoucher(resultBackNavigator: ResultBackNavigator<Boolean>) {
@Composable
fun RedeemVoucherDialog(
- uiState: VoucherDialogUiState,
+ state: VoucherDialogUiState,
onVoucherInputChange: (String) -> Unit = {},
onRedeem: (voucherCode: String) -> Unit,
onDismiss: (isTimeAdded: Boolean) -> Unit
) {
AlertDialog(
title = {
- if (uiState.voucherState !is VoucherDialogState.Success)
+ if (state.voucherState !is VoucherDialogState.Success)
Text(
text = stringResource(id = R.string.enter_voucher_code),
)
},
confirmButton = {
Column {
- if (uiState.voucherState !is VoucherDialogState.Success) {
+ if (state.voucherState !is VoucherDialogState.Success) {
VariantButton(
text = stringResource(id = R.string.redeem),
- onClick = { onRedeem(uiState.voucherInput) },
+ onClick = { onRedeem(state.voucherInput) },
modifier = Modifier.padding(bottom = Dimens.buttonSpacing),
- isEnabled = uiState.voucherInput.length == VOUCHER_LENGTH
+ isEnabled = state.voucherInput.length == VOUCHER_LENGTH
)
}
PrimaryButton(
text =
stringResource(
id =
- if (uiState.voucherState is VoucherDialogState.Success)
+ if (state.voucherState is VoucherDialogState.Success)
R.string.got_it
else R.string.cancel
),
- onClick = { onDismiss(uiState.voucherState is VoucherDialogState.Success) }
+ onClick = { onDismiss(state.voucherState is VoucherDialogState.Success) }
)
}
},
@@ -151,9 +153,9 @@ fun RedeemVoucherDialog(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
- if (uiState.voucherState is VoucherDialogState.Success) {
+ if (state.voucherState is VoucherDialogState.Success) {
val days: Int =
- (uiState.voucherState.addedTime / DateTimeConstants.SECONDS_PER_DAY).toInt()
+ (state.voucherState.addedTime / DateTimeConstants.SECONDS_PER_DAY).toInt()
val message =
stringResource(
R.string.added_to_your_account,
@@ -177,7 +179,7 @@ fun RedeemVoucherDialog(
} else {
EnterVoucherBody(
- uiState = uiState,
+ state = state,
onVoucherInputChange = onVoucherInputChange,
onRedeem = onRedeem
)
@@ -186,7 +188,7 @@ fun RedeemVoucherDialog(
},
containerColor = MaterialTheme.colorScheme.background,
titleContentColor = MaterialTheme.colorScheme.onBackground,
- onDismissRequest = { onDismiss(uiState.voucherState is VoucherDialogState.Success) },
+ onDismissRequest = { onDismiss(state.voucherState is VoucherDialogState.Success) },
properties =
DialogProperties(
securePolicy =
@@ -226,20 +228,20 @@ private fun RedeemSuccessBody(message: String) {
@Composable
private fun EnterVoucherBody(
- uiState: VoucherDialogUiState,
+ state: VoucherDialogUiState,
onVoucherInputChange: (String) -> Unit = {},
onRedeem: (voucherCode: String) -> Unit
) {
CustomTextField(
- value = uiState.voucherInput,
+ value = state.voucherInput,
onSubmit = { input ->
- if (uiState.voucherInput.length == VOUCHER_LENGTH) {
+ if (state.voucherInput.length == VOUCHER_LENGTH) {
onRedeem(input)
}
},
onValueChanged = { input -> onVoucherInputChange(input) },
isValidValue =
- uiState.voucherInput.isEmpty() || uiState.voucherInput.length == MAX_VOUCHER_LENGTH,
+ state.voucherInput.isEmpty() || state.voucherInput.length == MAX_VOUCHER_LENGTH,
keyboardType = KeyboardType.Password,
placeholderText = stringResource(id = R.string.voucher_hint),
visualTransformation = vouchersVisualTransformation(),
@@ -251,7 +253,7 @@ private fun EnterVoucherBody(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.height(Dimens.listIconSize).fillMaxWidth()
) {
- if (uiState.voucherState is VoucherDialogState.Verifying) {
+ if (state.voucherState is VoucherDialogState.Verifying) {
MullvadCircularProgressIndicatorSmall()
Text(
text = stringResource(id = R.string.verifying_voucher),
@@ -259,9 +261,9 @@ private fun EnterVoucherBody(
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.bodySmall
)
- } else if (uiState.voucherState is VoucherDialogState.Error) {
+ } else if (state.voucherState is VoucherDialogState.Error) {
Text(
- text = uiState.voucherState.errorMessage,
+ text = state.voucherState.errorMessage,
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodySmall
)
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 88c305b8c0..556e18c193 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
@@ -6,7 +6,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.compositeOver
@@ -14,6 +13,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.result.ResultBackNavigator
import com.ramcosta.composedestinations.spec.DestinationStyle
@@ -123,7 +123,7 @@ private fun PreviewPaymentDialogPaymentAvailabilityError() {
@Composable
fun Payment(productId: ProductId, resultBackNavigator: ResultBackNavigator<Boolean>) {
val vm = koinViewModel<PaymentViewModel>()
- val uiState = vm.uiState.collectAsState().value
+ val state by vm.uiState.collectAsStateWithLifecycle()
LaunchedEffect(Unit) {
vm.uiSideEffect.collect {
@@ -137,9 +137,10 @@ fun Payment(productId: ProductId, resultBackNavigator: ResultBackNavigator<Boole
val context = LocalContext.current
LaunchedEffect(Unit) { vm.startBillingPayment(productId) { context.getActivity()!! } }
- if (uiState.paymentDialogData != null) {
+ val dialogData = state.paymentDialogData
+ if (dialogData != null) {
PaymentDialog(
- paymentDialogData = uiState.paymentDialogData,
+ paymentDialogData = dialogData,
retryPurchase = { vm.startBillingPayment(it) { context.getActivity()!! } },
onCloseDialog = { resultBackNavigator.navigateBack(result = it) }
)
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 38404ec96b..e4cfb120a7 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
@@ -17,7 +17,6 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
@@ -28,6 +27,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.popUpTo
@@ -75,7 +75,7 @@ import org.koin.androidx.compose.koinViewModel
private fun PreviewAccountScreen() {
AppTheme {
AccountScreen(
- uiState =
+ state =
AccountUiState(
deviceName = "Test Name",
accountNumber = "1234123412341234",
@@ -110,7 +110,7 @@ fun Account(
playPaymentResultRecipient: ResultRecipient<PaymentDestination, Boolean>
) {
val vm = koinViewModel<AccountViewModel>()
- val state by vm.uiState.collectAsState()
+ val state by vm.uiState.collectAsStateWithLifecycle()
playPaymentResultRecipient.onNavResult {
when (it) {
@@ -122,7 +122,7 @@ fun Account(
}
AccountScreen(
- uiState = state,
+ state = state,
uiSideEffect = vm.uiSideEffect,
onRedeemVoucherClick = {
navigator.navigate(RedeemVoucherDestination) { launchSingleTop = true }
@@ -152,7 +152,7 @@ fun Account(
@ExperimentalMaterial3Api
@Composable
fun AccountScreen(
- uiState: AccountUiState,
+ state: AccountUiState,
uiSideEffect: Flow<AccountViewModel.UiSideEffect>,
onCopyAccountNumber: (String) -> Unit = {},
onRedeemVoucherClick: () -> Unit = {},
@@ -199,18 +199,18 @@ fun AccountScreen(
verticalArrangement = Arrangement.spacedBy(Dimens.accountRowSpacing),
modifier = modifier.animateContentSize().padding(horizontal = Dimens.sideMargin)
) {
- DeviceNameRow(deviceName = uiState.deviceName ?: "", onInfoClick = navigateToDeviceInfo)
+ DeviceNameRow(deviceName = state.deviceName ?: "", onInfoClick = navigateToDeviceInfo)
- AccountNumberRow(accountNumber = uiState.accountNumber ?: "", onCopyAccountNumber)
+ AccountNumberRow(accountNumber = state.accountNumber ?: "", onCopyAccountNumber)
- PaidUntilRow(accountExpiry = uiState.accountExpiry)
+ PaidUntilRow(accountExpiry = state.accountExpiry)
Spacer(modifier = Modifier.weight(1f))
Column(modifier = Modifier.padding(bottom = Dimens.screenVerticalMargin)) {
- uiState.billingPaymentState?.let {
+ state.billingPaymentState?.let {
PlayPayment(
- billingPaymentState = uiState.billingPaymentState,
+ billingPaymentState = state.billingPaymentState,
onPurchaseBillingProductClick = { productId ->
onPurchaseBillingProductClick(productId)
},
@@ -219,7 +219,7 @@ fun AccountScreen(
)
}
- if (uiState.showSitePayment) {
+ if (state.showSitePayment) {
ExternalButton(
text = stringResource(id = R.string.manage_account),
onClick = onManageAccountClick,
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 fec3ede17c..17ae05e258 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
@@ -19,7 +19,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableLongStateOf
@@ -37,6 +36,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.popUpTo
@@ -95,7 +95,7 @@ private fun PreviewConnectScreen() {
val state = ConnectUiState.INITIAL
AppTheme {
ConnectScreen(
- uiState = state,
+ state = state,
)
}
}
@@ -105,7 +105,7 @@ private fun PreviewConnectScreen() {
fun Connect(navigator: DestinationsNavigator) {
val connectViewModel: ConnectViewModel = koinViewModel()
- val state = connectViewModel.uiState.collectAsState().value
+ val state by connectViewModel.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current
LaunchedEffect(key1 = Unit) {
@@ -130,7 +130,7 @@ fun Connect(navigator: DestinationsNavigator) {
}
}
ConnectScreen(
- uiState = state,
+ state = state,
onDisconnectClick = connectViewModel::onDisconnectClick,
onReconnectClick = connectViewModel::onReconnectClick,
onConnectClick = connectViewModel::onConnectClick,
@@ -160,7 +160,7 @@ fun Connect(navigator: DestinationsNavigator) {
@Composable
fun ConnectScreen(
- uiState: ConnectUiState,
+ state: ConnectUiState,
onDisconnectClick: () -> Unit = {},
onReconnectClick: () -> Unit = {},
onConnectClick: () -> Unit = {},
@@ -185,12 +185,12 @@ fun ConnectScreen(
}
ScaffoldWithTopBarAndDeviceName(
- topBarColor = uiState.tunnelUiState.topBarColor(),
- iconTintColor = uiState.tunnelUiState.iconTintColor(),
+ topBarColor = state.tunnelUiState.topBarColor(),
+ iconTintColor = state.tunnelUiState.iconTintColor(),
onSettingsClicked = onSettingsClick,
onAccountClicked = onAccountClick,
- deviceName = uiState.deviceName,
- timeLeft = uiState.daysLeftUntilExpiry
+ deviceName = state.deviceName,
+ timeLeft = state.daysLeftUntilExpiry
) {
var progressIndicatorBias by remember { mutableFloatStateOf(0f) }
@@ -198,18 +198,18 @@ fun ConnectScreen(
val baseZoom =
animateFloatAsState(
targetValue =
- if (uiState.tunnelRealState is TunnelState.Connected) SECURE_ZOOM
+ if (state.tunnelRealState is TunnelState.Connected) SECURE_ZOOM
else UNSECURE_ZOOM,
animationSpec = tween(SECURE_ZOOM_ANIMATION_MILLIS),
label = "baseZoom"
)
val markers =
- uiState.tunnelRealState.toMarker(uiState.location)?.let { listOf(it) } ?: emptyList()
+ state.tunnelRealState.toMarker(state.location)?.let { listOf(it) } ?: emptyList()
AnimatedMap(
modifier = Modifier.padding(top = it.calculateTopPadding()),
- cameraLocation = uiState.location?.toLatLong() ?: fallbackLatLong,
+ cameraLocation = state.location?.toLatLong() ?: fallbackLatLong,
cameraBaseZoom = baseZoom.value,
cameraVerticalBias = progressIndicatorBias,
markers = markers,
@@ -244,7 +244,7 @@ fun ConnectScreen(
end = Dimens.sideMargin,
top = Dimens.mediumPadding
)
- .alpha(if (uiState.showLoading) AlphaVisible else AlphaInvisible)
+ .alpha(if (state.showLoading) AlphaVisible else AlphaInvisible)
.align(Alignment.CenterHorizontally)
.testTag(CIRCULAR_PROGRESS_INDICATOR)
.onGloballyPositioned {
@@ -260,17 +260,17 @@ fun ConnectScreen(
)
Spacer(modifier = Modifier.defaultMinSize(minHeight = Dimens.mediumPadding).weight(1f))
ConnectionStatusText(
- state = uiState.tunnelRealState,
+ state = state.tunnelRealState,
modifier = Modifier.padding(horizontal = Dimens.sideMargin)
)
Text(
- text = uiState.location?.country ?: "",
+ text = state.location?.country ?: "",
style = MaterialTheme.typography.headlineLarge,
color = MaterialTheme.colorScheme.onPrimary,
modifier = Modifier.padding(horizontal = Dimens.sideMargin)
)
Text(
- text = uiState.location?.city ?: "",
+ text = state.location?.city ?: "",
style = MaterialTheme.typography.headlineLarge,
color = MaterialTheme.colorScheme.onPrimary,
modifier = Modifier.padding(horizontal = Dimens.sideMargin)
@@ -278,11 +278,11 @@ fun ConnectScreen(
var expanded by rememberSaveable { mutableStateOf(false) }
LocationInfo(
onToggleTunnelInfo = { expanded = !expanded },
- isVisible = uiState.showLocationInfo,
+ isVisible = state.showLocationInfo,
isExpanded = expanded,
- location = uiState.location,
- inAddress = uiState.inAddress,
- outAddress = uiState.outAddress,
+ location = state.location,
+ inAddress = state.inAddress,
+ outAddress = state.outAddress,
modifier =
Modifier.fillMaxWidth()
.padding(horizontal = Dimens.sideMargin)
@@ -295,17 +295,17 @@ fun ConnectScreen(
.padding(horizontal = Dimens.sideMargin)
.testTag(SELECT_LOCATION_BUTTON_TEST_TAG),
onClick = onSwitchLocationClick,
- showChevron = uiState.showLocation,
+ showChevron = state.showLocation,
text =
- if (uiState.showLocation && uiState.selectedRelayItem != null) {
- uiState.selectedRelayItem.locationName
+ if (state.showLocation && state.selectedRelayItem != null) {
+ state.selectedRelayItem.locationName
} else {
stringResource(id = R.string.switch_location)
}
)
Spacer(modifier = Modifier.height(Dimens.buttonSpacing))
ConnectionButton(
- state = uiState.tunnelUiState,
+ state = state.tunnelUiState,
modifier =
Modifier.padding(horizontal = Dimens.sideMargin)
.padding(bottom = Dimens.screenVerticalMargin)
@@ -323,8 +323,8 @@ fun ConnectScreen(
NotificationBanner(
modifier = Modifier.padding(top = it.calculateTopPadding()),
- notification = uiState.inAppNotification,
- isPlayBuild = uiState.isPlayBuild,
+ notification = state.inAppNotification,
+ isPlayBuild = state.isPlayBuild,
onClickUpdateVersion = onUpdateVersionClick,
onClickShowAccount = onManageAccountClick,
onClickDismissNewDevice = onDismissNewDeviceClick,
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 c0ba529610..f1306538d0 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
@@ -18,7 +18,6 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -26,6 +25,7 @@ import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.popUpTo
@@ -172,7 +172,7 @@ fun DeviceList(
confirmRemoveResultRecipient: ResultRecipient<RemoveDeviceConfirmationDialogDestination, String>
) {
val viewModel = koinViewModel<DeviceListViewModel>()
- val state by viewModel.uiState.collectAsState()
+ val state by viewModel.uiState.collectAsStateWithLifecycle()
confirmRemoveResultRecipient.onNavResult {
when (it) {
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 71ec904de5..2d5baef6bd 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
@@ -10,7 +10,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -22,6 +21,7 @@ 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 com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.popUpTo
@@ -49,7 +49,7 @@ private fun PreviewDeviceRevokedScreen() {
fun DeviceRevoked(navigator: DestinationsNavigator) {
val viewModel = koinViewModel<DeviceRevokedViewModel>()
- val state by viewModel.uiState.collectAsState()
+ val state by viewModel.uiState.collectAsStateWithLifecycle()
LaunchedEffect(Unit) {
viewModel.uiSideEffect.collect { sideEffect ->
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 864f909421..d3c5cf4e20 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
@@ -18,7 +18,6 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
@@ -30,6 +29,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import net.mullvad.mullvadvpn.R
@@ -58,7 +58,7 @@ private fun PreviewFilterScreen() {
)
AppTheme {
FilterScreen(
- uiState = state,
+ state = state,
onSelectedOwnership = {},
onSelectedProvider = { _, _ -> },
onAllProviderCheckChange = {},
@@ -70,7 +70,7 @@ private fun PreviewFilterScreen() {
@Composable
fun FilterScreen(navigator: DestinationsNavigator) {
val viewModel = koinViewModel<FilterViewModel>()
- val uiState by viewModel.uiState.collectAsState()
+ val state by viewModel.uiState.collectAsStateWithLifecycle()
LaunchedEffect(Unit) {
viewModel.uiSideEffect.collect {
@@ -80,7 +80,7 @@ fun FilterScreen(navigator: DestinationsNavigator) {
}
}
FilterScreen(
- uiState = uiState,
+ state = state,
onBackClick = navigator::navigateUp,
onApplyClick = viewModel::onApplyButtonClicked,
onSelectedOwnership = viewModel::setSelectedOwnership,
@@ -91,7 +91,7 @@ fun FilterScreen(navigator: DestinationsNavigator) {
@Composable
fun FilterScreen(
- uiState: RelayFilterState,
+ state: RelayFilterState,
onBackClick: () -> Unit = {},
onApplyClick: () -> Unit = {},
onSelectedOwnership: (ownership: Ownership?) -> Unit = {},
@@ -134,7 +134,7 @@ fun FilterScreen(
) {
ApplyButton(
onClick = onApplyClick,
- isEnabled = uiState.isApplyButtonEnabled,
+ isEnabled = state.isApplyButtonEnabled,
modifier =
Modifier.padding(
start = Dimens.sideMargin,
@@ -160,15 +160,15 @@ fun FilterScreen(
item {
SelectableCell(
title = stringResource(id = R.string.any),
- isSelected = uiState.selectedOwnership == null,
+ isSelected = state.selectedOwnership == null,
onCellClicked = { onSelectedOwnership(null) }
)
}
- items(uiState.filteredOwnershipByProviders) { ownership ->
+ items(state.filteredOwnershipByProviders) { ownership ->
Divider()
SelectableCell(
title = stringResource(id = ownership.stringResource()),
- isSelected = ownership == uiState.selectedOwnership,
+ isSelected = ownership == state.selectedOwnership,
onCellClicked = { onSelectedOwnership(ownership) }
)
}
@@ -188,15 +188,15 @@ fun FilterScreen(
Divider()
CheckboxCell(
providerName = stringResource(R.string.all_providers),
- checked = uiState.isAllProvidersChecked,
+ checked = state.isAllProvidersChecked,
onCheckedChange = { isChecked -> onAllProviderCheckChange(isChecked) }
)
}
- items(uiState.filteredProvidersByOwnership) { provider ->
+ items(state.filteredProvidersByOwnership) { provider ->
Divider()
CheckboxCell(
providerName = provider.name,
- checked = provider in uiState.selectedProviders,
+ checked = provider in state.selectedProviders,
onCheckedChange = { checked -> onSelectedProvider(checked, provider) }
)
}
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 4dac203fa8..5f7e963e95 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
@@ -27,7 +27,6 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -50,6 +49,7 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.popUpTo
@@ -85,33 +85,31 @@ import org.koin.androidx.compose.koinViewModel
@Preview
@Composable
private fun PreviewIdle() {
- AppTheme { LoginScreen(uiState = LoginUiState()) }
+ AppTheme { LoginScreen(state = LoginUiState()) }
}
@Preview
@Composable
private fun PreviewLoggingIn() {
- AppTheme { LoginScreen(uiState = LoginUiState(loginState = Loading.LoggingIn)) }
+ AppTheme { LoginScreen(state = LoginUiState(loginState = Loading.LoggingIn)) }
}
@Preview
@Composable
private fun PreviewCreatingAccount() {
- AppTheme { LoginScreen(uiState = LoginUiState(loginState = Loading.CreatingAccount)) }
+ AppTheme { LoginScreen(state = LoginUiState(loginState = Loading.CreatingAccount)) }
}
@Preview
@Composable
private fun PreviewLoginError() {
- AppTheme {
- LoginScreen(uiState = LoginUiState(loginState = Idle(LoginError.InvalidCredentials)))
- }
+ AppTheme { LoginScreen(state = LoginUiState(loginState = Idle(LoginError.InvalidCredentials))) }
}
@Preview
@Composable
private fun PreviewLoginSuccess() {
- AppTheme { LoginScreen(uiState = LoginUiState(loginState = Success)) }
+ AppTheme { LoginScreen(state = LoginUiState(loginState = Success)) }
}
@Destination(style = LoginTransition::class)
@@ -121,7 +119,7 @@ fun Login(
accountToken: String? = null,
vm: LoginViewModel = koinViewModel()
) {
- val state by vm.uiState.collectAsState()
+ val state by vm.uiState.collectAsStateWithLifecycle()
// Login with argument, e.g when user comes from Too Many Devices screen
LaunchedEffect(accountToken) {
@@ -171,7 +169,7 @@ fun Login(
@Composable
private fun LoginScreen(
- uiState: LoginUiState,
+ state: LoginUiState,
onLoginClick: (String) -> Unit = {},
onCreateAccountClick: () -> Unit = {},
onDeleteHistoryClick: () -> Unit = {},
@@ -182,7 +180,7 @@ private fun LoginScreen(
topBarColor = MaterialTheme.colorScheme.primary,
iconTintColor = MaterialTheme.colorScheme.onPrimary.copy(alpha = AlphaTopBar),
onSettingsClicked = onSettingsClick,
- enabled = uiState.loginState is Idle,
+ enabled = state.loginState is Idle,
onAccountClicked = null,
) {
val scrollState = rememberScrollState()
@@ -195,14 +193,14 @@ private fun LoginScreen(
) {
Spacer(modifier = Modifier.weight(1f))
LoginIcon(
- uiState.loginState,
+ state.loginState,
modifier =
Modifier.align(Alignment.CenterHorizontally)
.padding(bottom = Dimens.largePadding)
)
- LoginContent(uiState, onAccountNumberChange, onLoginClick, onDeleteHistoryClick)
+ LoginContent(state, onAccountNumberChange, onLoginClick, onDeleteHistoryClick)
Spacer(modifier = Modifier.weight(3f))
- CreateAccountPanel(onCreateAccountClick, isEnabled = uiState.loginState is Idle)
+ CreateAccountPanel(onCreateAccountClick, isEnabled = state.loginState is Idle)
}
}
}
@@ -210,14 +208,14 @@ private fun LoginScreen(
@Composable
@OptIn(ExperimentalComposeUiApi::class)
private fun LoginContent(
- uiState: LoginUiState,
+ state: LoginUiState,
onAccountNumberChange: (String) -> Unit,
onLoginClick: (String) -> Unit,
onDeleteHistoryClick: () -> Unit
) {
Column(modifier = Modifier.fillMaxWidth().padding(horizontal = Dimens.sideMargin)) {
Text(
- text = uiState.loginState.title(),
+ text = state.loginState.title(),
style = MaterialTheme.typography.headlineLarge,
color = MaterialTheme.colorScheme.onPrimary,
modifier =
@@ -232,10 +230,10 @@ private fun LoginContent(
Text(
modifier = Modifier.padding(bottom = Dimens.smallPadding),
- text = uiState.loginState.supportingText() ?: "",
+ text = state.loginState.supportingText() ?: "",
style = MaterialTheme.typography.labelMedium,
color =
- if (uiState.loginState.isError()) {
+ if (state.loginState.isError()) {
MaterialTheme.colorScheme.error
} else {
MaterialTheme.colorScheme.onPrimary
@@ -253,13 +251,13 @@ private fun LoginContent(
.fillMaxWidth()
.testTag(LOGIN_INPUT_TEST_TAG)
.let {
- if (!expandedDropdown || uiState.lastUsedAccount == null) {
+ if (!expandedDropdown || state.lastUsedAccount == null) {
it.clip(MaterialTheme.shapes.small)
} else {
it
}
},
- value = uiState.accountNumberInput,
+ value = state.accountNumberInput,
label = {
Text(
text = stringResource(id = R.string.login_description),
@@ -268,24 +266,23 @@ private fun LoginContent(
overflow = TextOverflow.Ellipsis
)
},
- keyboardActions =
- KeyboardActions(onDone = { onLoginClick(uiState.accountNumberInput) }),
+ keyboardActions = KeyboardActions(onDone = { onLoginClick(state.accountNumberInput) }),
keyboardOptions =
KeyboardOptions(
- imeAction = if (uiState.loginButtonEnabled) ImeAction.Done else ImeAction.None,
+ imeAction = if (state.loginButtonEnabled) ImeAction.Done else ImeAction.None,
keyboardType = KeyboardType.NumberPassword
),
onValueChange = onAccountNumberChange,
singleLine = true,
maxLines = 1,
visualTransformation = accountTokenVisualTransformation(),
- enabled = uiState.loginState is Idle,
+ enabled = state.loginState is Idle,
colors = mullvadWhiteTextFieldColors(),
- isError = uiState.loginState.isError(),
+ isError = state.loginState.isError(),
)
- AnimatedVisibility(visible = uiState.lastUsedAccount != null && expandedDropdown) {
- val token = uiState.lastUsedAccount?.value.orEmpty()
+ AnimatedVisibility(visible = state.lastUsedAccount != null && expandedDropdown) {
+ val token = state.lastUsedAccount?.value.orEmpty()
val accountTransformation = remember { accountTokenVisualTransformation() }
val transformedText =
remember(token) { accountTransformation.filter(AnnotatedString(token)).text }
@@ -294,7 +291,7 @@ private fun LoginContent(
modifier = Modifier.onFocusChanged { ddFocusState = it },
accountToken = transformedText.toString(),
onClick = {
- uiState.lastUsedAccount?.let {
+ state.lastUsedAccount?.let {
onAccountNumberChange(it.value)
onLoginClick(it.value)
}
@@ -305,8 +302,8 @@ private fun LoginContent(
Spacer(modifier = Modifier.size(Dimens.largePadding))
VariantButton(
- isEnabled = uiState.loginButtonEnabled,
- onClick = { onLoginClick(uiState.accountNumberInput) },
+ isEnabled = state.loginButtonEnabled,
+ onClick = { onLoginClick(state.accountNumberInput) },
text = stringResource(id = R.string.login_title),
modifier = Modifier.padding(bottom = Dimens.mediumPadding)
)
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 00cd339c09..dfc933e170 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
@@ -14,7 +14,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
@@ -22,6 +22,7 @@ import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.popUpTo
@@ -62,7 +63,7 @@ import org.koin.androidx.compose.koinViewModel
private fun PreviewOutOfTimeScreenDisconnected() {
AppTheme {
OutOfTimeScreen(
- uiState =
+ state =
OutOfTimeUiState(
tunnelState = TunnelState.Disconnected(),
"Heroic Frog",
@@ -77,7 +78,7 @@ private fun PreviewOutOfTimeScreenDisconnected() {
private fun PreviewOutOfTimeScreenConnecting() {
AppTheme {
OutOfTimeScreen(
- uiState =
+ state =
OutOfTimeUiState(
tunnelState = TunnelState.Connecting(null, null),
"Strong Rabbit",
@@ -92,7 +93,7 @@ private fun PreviewOutOfTimeScreenConnecting() {
private fun PreviewOutOfTimeScreenError() {
AppTheme {
OutOfTimeScreen(
- uiState =
+ state =
OutOfTimeUiState(
tunnelState =
TunnelState.Error(
@@ -113,7 +114,7 @@ fun OutOfTime(
playPaymentResultRecipient: ResultRecipient<PaymentDestination, Boolean>
) {
val vm = koinViewModel<OutOfTimeViewModel>()
- val state = vm.uiState.collectAsState().value
+ val state by vm.uiState.collectAsStateWithLifecycle()
redeemVoucherResultRecipient.onNavResult {
// If we successfully redeemed a voucher, navigate to Connect screen
if (it is NavResult.Value && it.value) {
@@ -150,7 +151,7 @@ fun OutOfTime(
}
OutOfTimeScreen(
- uiState = state,
+ state = state,
onSitePaymentClick = vm::onSitePaymentClick,
onRedeemVoucherClick = {
navigator.navigate(RedeemVoucherDestination) { launchSingleTop = true }
@@ -169,7 +170,7 @@ fun OutOfTime(
@Composable
fun OutOfTimeScreen(
- uiState: OutOfTimeUiState,
+ state: OutOfTimeUiState,
onDisconnectClick: () -> Unit = {},
onSitePaymentClick: () -> Unit = {},
onRedeemVoucherClick: () -> Unit = {},
@@ -182,13 +183,13 @@ fun OutOfTimeScreen(
val scrollState = rememberScrollState()
ScaffoldWithTopBarAndDeviceName(
topBarColor =
- if (uiState.tunnelState.isSecured()) {
+ if (state.tunnelState.isSecured()) {
MaterialTheme.colorScheme.inversePrimary
} else {
MaterialTheme.colorScheme.error
},
iconTintColor =
- if (uiState.tunnelState.isSecured()) {
+ if (state.tunnelState.isSecured()) {
MaterialTheme.colorScheme.onPrimary
} else {
MaterialTheme.colorScheme.onError
@@ -196,7 +197,7 @@ fun OutOfTimeScreen(
.copy(alpha = AlphaTopBar),
onSettingsClicked = onSettingsClick,
onAccountClicked = onAccountClick,
- deviceName = uiState.deviceName,
+ deviceName = state.deviceName,
timeLeft = null
) {
Column(
@@ -230,7 +231,7 @@ fun OutOfTimeScreen(
text =
buildString {
append(stringResource(R.string.account_credit_has_expired))
- if (uiState.showSitePayment) {
+ if (state.showSitePayment) {
append(" ")
append(stringResource(R.string.add_time_to_account))
}
@@ -246,7 +247,7 @@ fun OutOfTimeScreen(
)
Spacer(modifier = Modifier.weight(1f).defaultMinSize(minHeight = Dimens.verticalSpace))
// Button area
- if (uiState.tunnelState.showDisconnectButton()) {
+ if (state.tunnelState.showDisconnectButton()) {
NegativeButton(
onClick = onDisconnectClick,
text = stringResource(id = R.string.disconnect),
@@ -258,9 +259,9 @@ fun OutOfTimeScreen(
)
)
}
- uiState.billingPaymentState?.let {
+ state.billingPaymentState?.let {
PlayPayment(
- billingPaymentState = uiState.billingPaymentState,
+ billingPaymentState = state.billingPaymentState,
onPurchaseBillingProductClick = { productId ->
onPurchaseBillingProductClick(productId)
},
@@ -274,10 +275,10 @@ fun OutOfTimeScreen(
.align(Alignment.CenterHorizontally)
)
}
- if (uiState.showSitePayment) {
+ if (state.showSitePayment) {
SitePaymentButton(
onClick = onSitePaymentClick,
- isEnabled = uiState.tunnelState.enableSitePaymentButton(),
+ isEnabled = state.tunnelState.enableSitePaymentButton(),
modifier =
Modifier.padding(
start = Dimens.sideMargin,
@@ -294,7 +295,7 @@ fun OutOfTimeScreen(
end = Dimens.sideMargin,
bottom = Dimens.screenVerticalMargin
),
- isEnabled = uiState.tunnelState.enableRedeemButton()
+ 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 3f52af5fc3..c087f93ed1 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
@@ -16,7 +16,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -33,6 +33,7 @@ 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 com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.popUpTo
@@ -70,7 +71,7 @@ fun PrivacyDisclaimer(
navigator: DestinationsNavigator,
) {
val viewModel: PrivacyDisclaimerViewModel = koinViewModel()
- val uiState = viewModel.uiState.collectAsState()
+ val state by viewModel.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current
val scope = rememberCoroutineScope()
@@ -105,12 +106,12 @@ fun PrivacyDisclaimer(
}
}
}
- PrivacyDisclaimerScreen(uiState.value, {}, viewModel::setPrivacyDisclosureAccepted)
+ PrivacyDisclaimerScreen(state, {}, viewModel::setPrivacyDisclosureAccepted)
}
@Composable
fun PrivacyDisclaimerScreen(
- uiState: PrivacyDisclaimerViewState,
+ state: PrivacyDisclaimerViewState,
onPrivacyPolicyLinkClicked: () -> Unit,
onAcceptClicked: () -> Unit,
) {
@@ -202,7 +203,7 @@ fun PrivacyDisclaimerScreen(
},
horizontalAlignment = Alignment.CenterHorizontally
) {
- if (uiState.isStartingService) {
+ if (state.isStartingService) {
MullvadCircularProgressIndicatorMedium()
} else {
PrimaryButton(
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 4763b21997..6e72d26bcc 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
@@ -15,7 +15,6 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
@@ -28,6 +27,7 @@ import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.result.NavResult
@@ -55,7 +55,7 @@ import org.koin.androidx.compose.koinViewModel
@Preview
@Composable
private fun PreviewReportProblemScreen() {
- AppTheme { ReportProblemScreen(uiState = ReportProblemUiState()) }
+ AppTheme { ReportProblemScreen(state = ReportProblemUiState()) }
}
@Preview
@@ -63,7 +63,7 @@ private fun PreviewReportProblemScreen() {
private fun PreviewReportProblemSendingScreen() {
AppTheme {
ReportProblemScreen(
- uiState = ReportProblemUiState(sendingState = SendingReportUiState.Sending),
+ state = ReportProblemUiState(sendingState = SendingReportUiState.Sending),
)
}
}
@@ -73,7 +73,7 @@ private fun PreviewReportProblemSendingScreen() {
private fun PreviewReportProblemSuccessScreen() {
AppTheme {
ReportProblemScreen(
- uiState =
+ state =
ReportProblemUiState(sendingState = SendingReportUiState.Success("email@mail.com")),
)
}
@@ -84,7 +84,7 @@ private fun PreviewReportProblemSuccessScreen() {
private fun PreviewReportProblemErrorScreen() {
AppTheme {
ReportProblemScreen(
- uiState =
+ state =
ReportProblemUiState(
sendingState =
SendingReportUiState.Error(SendProblemReportResult.Error.CollectLog)
@@ -100,7 +100,7 @@ fun ReportProblem(
noEmailConfirmResultRecipent: ResultRecipient<ReportProblemNoEmailDialogDestination, Boolean>
) {
val vm = koinViewModel<ReportProblemViewModel>()
- val uiState by vm.uiState.collectAsState()
+ val state by vm.uiState.collectAsStateWithLifecycle()
LaunchedEffect(Unit) {
vm.uiSideEffect.collect {
@@ -115,13 +115,13 @@ fun ReportProblem(
noEmailConfirmResultRecipent.onNavResult {
when (it) {
NavResult.Canceled -> {}
- is NavResult.Value -> vm.sendReport(uiState.email, uiState.description, true)
+ is NavResult.Value -> vm.sendReport(state.email, state.description, true)
}
}
ReportProblemScreen(
- uiState,
- onSendReport = { vm.sendReport(uiState.email, uiState.description) },
+ state,
+ onSendReport = { vm.sendReport(state.email, state.description) },
onClearSendResult = vm::clearSendResult,
onNavigateToViewLogs = {
navigator.navigate(ViewLogsDestination()) { launchSingleTop = true }
@@ -134,7 +134,7 @@ fun ReportProblem(
@Composable
private fun ReportProblemScreen(
- uiState: ReportProblemUiState,
+ state: ReportProblemUiState,
onSendReport: () -> Unit = {},
onClearSendResult: () -> Unit = {},
onNavigateToViewLogs: () -> Unit = {},
@@ -148,7 +148,7 @@ private fun ReportProblemScreen(
navigationIcon = { NavigateBackIconButton(onBackClick) }
) { modifier ->
// Show sending states
- if (uiState.sendingState != null) {
+ if (state.sendingState != null) {
Column(
modifier =
modifier.padding(
@@ -156,10 +156,10 @@ private fun ReportProblemScreen(
horizontal = Dimens.sideMargin
)
) {
- when (uiState.sendingState) {
+ when (state.sendingState) {
SendingReportUiState.Sending -> SendingContent()
is SendingReportUiState.Error -> ErrorContent(onSendReport, onClearSendResult)
- is SendingReportUiState.Success -> SentContent(uiState.sendingState)
+ is SendingReportUiState.Success -> SentContent(state.sendingState)
}
return@ScaffoldWithMediumTopBar
}
@@ -180,7 +180,7 @@ private fun ReportProblemScreen(
TextField(
modifier = Modifier.fillMaxWidth(),
- value = uiState.email,
+ value = state.email,
onValueChange = onEmailChanged,
maxLines = 1,
singleLine = true,
@@ -190,7 +190,7 @@ private fun ReportProblemScreen(
TextField(
modifier = Modifier.fillMaxWidth().weight(1f),
- value = uiState.description,
+ value = state.description,
onValueChange = onDescriptionChanged,
placeholder = { Text(stringResource(R.string.user_message_hint)) },
colors = mullvadWhiteTextFieldColors()
@@ -204,7 +204,7 @@ private fun ReportProblemScreen(
Spacer(modifier = Modifier.height(Dimens.buttonSpacing))
VariantButton(
onClick = onSendReport,
- isEnabled = uiState.description.isNotEmpty(),
+ isEnabled = state.description.isNotEmpty(),
text = stringResource(id = R.string.send)
)
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreen.kt
index e024ae3132..e0c550af38 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreen.kt
@@ -21,7 +21,7 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
@@ -34,6 +34,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.text.HtmlCompat
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import net.mullvad.mullvadvpn.R
@@ -75,7 +76,7 @@ private fun PreviewSelectLocationScreen() {
)
AppTheme {
SelectLocationScreen(
- uiState = state,
+ state = state,
)
}
}
@@ -84,7 +85,7 @@ private fun PreviewSelectLocationScreen() {
@Composable
fun SelectLocation(navigator: DestinationsNavigator) {
val vm = koinViewModel<SelectLocationViewModel>()
- val state = vm.uiState.collectAsState().value
+ val state by vm.uiState.collectAsStateWithLifecycle()
LaunchedEffect(Unit) {
vm.uiSideEffect.collect {
when (it) {
@@ -94,7 +95,7 @@ fun SelectLocation(navigator: DestinationsNavigator) {
}
SelectLocationScreen(
- uiState = state,
+ state = state,
onSelectRelay = vm::selectRelay,
onSearchTermInput = vm::onSearchTermInput,
onBackClick = navigator::navigateUp,
@@ -106,7 +107,7 @@ fun SelectLocation(navigator: DestinationsNavigator) {
@Composable
fun SelectLocationScreen(
- uiState: SelectLocationUiState,
+ state: SelectLocationUiState,
onSelectRelay: (item: RelayItem) -> Unit = {},
onSearchTermInput: (searchTerm: String) -> Unit = {},
onBackClick: () -> Unit = {},
@@ -143,13 +144,13 @@ fun SelectLocationScreen(
}
}
- when (uiState) {
+ when (state) {
SelectLocationUiState.Loading -> {}
is SelectLocationUiState.Data -> {
- if (uiState.hasFilter) {
+ if (state.hasFilter) {
FilterCell(
- ownershipFilter = uiState.selectedOwnership,
- selectedProviderFilter = uiState.selectedProvidersCount,
+ ownershipFilter = state.selectedOwnership,
+ selectedProviderFilter = state.selectedProvidersCount,
removeOwnershipFilter = removeOwnershipFilter,
removeProviderFilter = removeProviderFilter
)
@@ -170,12 +171,12 @@ fun SelectLocationScreen(
Spacer(modifier = Modifier.height(height = Dimens.verticalSpace))
val lazyListState = rememberLazyListState()
if (
- uiState is SelectLocationUiState.Data &&
- uiState.relayListState is RelayListState.RelayList &&
- uiState.relayListState.selectedItem != null
+ state is SelectLocationUiState.Data &&
+ state.relayListState is RelayListState.RelayList &&
+ state.relayListState.selectedItem != null
) {
- LaunchedEffect(uiState.relayListState.selectedItem) {
- val index = uiState.relayListState.indexOfSelectedRelayItem()
+ LaunchedEffect(state.relayListState.selectedItem) {
+ val index = state.relayListState.indexOfSelectedRelayItem()
if (index >= 0) {
lazyListState.scrollToItem(index)
@@ -193,14 +194,14 @@ fun SelectLocationScreen(
state = lazyListState,
horizontalAlignment = Alignment.CenterHorizontally,
) {
- when (uiState) {
+ when (state) {
SelectLocationUiState.Loading -> {
loading()
}
is SelectLocationUiState.Data -> {
relayList(
- relayListState = uiState.relayListState,
- searchTerm = uiState.searchTerm,
+ relayListState = state.relayListState,
+ searchTerm = state.searchTerm,
onSelectRelay = onSelectRelay
)
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreen.kt
index 9805a7bb3b..70d7714de5 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreen.kt
@@ -11,13 +11,13 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import net.mullvad.mullvadvpn.R
@@ -46,7 +46,7 @@ import org.koin.androidx.compose.koinViewModel
private fun PreviewSettings() {
AppTheme {
SettingsScreen(
- uiState =
+ state =
SettingsUiState(
appVersion = "2222.22",
isLoggedIn = true,
@@ -62,9 +62,9 @@ private fun PreviewSettings() {
@Composable
fun Settings(navigator: DestinationsNavigator) {
val vm = koinViewModel<SettingsViewModel>()
- val state by vm.uiState.collectAsState()
+ val state by vm.uiState.collectAsStateWithLifecycle()
SettingsScreen(
- uiState = state,
+ state = state,
onVpnSettingCellClick = {
navigator.navigate(VpnSettingsDestination) { launchSingleTop = true }
},
@@ -81,7 +81,7 @@ fun Settings(navigator: DestinationsNavigator) {
@ExperimentalMaterial3Api
@Composable
fun SettingsScreen(
- uiState: SettingsUiState,
+ state: SettingsUiState,
onVpnSettingCellClick: () -> Unit = {},
onSplitTunnelingCellClick: () -> Unit = {},
onReportProblemCellClick: () -> Unit = {},
@@ -98,7 +98,7 @@ fun SettingsScreen(
state = lazyListState
) {
item { Spacer(modifier = Modifier.height(Dimens.cellLabelVerticalPadding)) }
- if (uiState.isLoggedIn) {
+ if (state.isLoggedIn) {
item {
NavigationComposeCell(
title = stringResource(id = R.string.settings_vpn),
@@ -123,32 +123,32 @@ fun SettingsScreen(
Uri.parse(
context.resources
.getString(R.string.download_url)
- .appendHideNavOnPlayBuild(uiState.isPlayBuild)
+ .appendHideNavOnPlayBuild(state.isPlayBuild)
)
)
},
bodyView =
@Composable {
- if (!uiState.isPlayBuild) {
+ if (!state.isPlayBuild) {
NavigationCellBody(
- content = uiState.appVersion,
+ content = state.appVersion,
contentBodyDescription =
stringResource(id = R.string.app_version),
isExternalLink = true,
)
} else {
Text(
- text = uiState.appVersion,
+ text = state.appVersion,
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onSecondary
)
}
},
- showWarning = uiState.isUpdateAvailable,
- isRowEnabled = !uiState.isPlayBuild
+ showWarning = state.isUpdateAvailable,
+ isRowEnabled = !state.isPlayBuild
)
}
- if (uiState.isUpdateAvailable) {
+ if (state.isUpdateAvailable) {
item {
Text(
text = stringResource(id = R.string.update_available_footer),
@@ -174,7 +174,7 @@ fun SettingsScreen(
)
}
- if (!uiState.isPlayBuild) {
+ if (!state.isPlayBuild) {
itemWithDivider {
val faqGuideLabel = stringResource(id = R.string.faqs_and_guides)
NavigationComposeCell(
@@ -199,7 +199,7 @@ fun SettingsScreen(
Uri.parse(
context.resources
.getString(R.string.privacy_policy_url)
- .appendHideNavOnPlayBuild(uiState.isPlayBuild)
+ .appendHideNavOnPlayBuild(state.isPlayBuild)
)
)
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreen.kt
index 12d7a62d78..29aca2b3b4 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreen.kt
@@ -10,7 +10,6 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
@@ -22,6 +21,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import net.mullvad.mullvadvpn.R
@@ -54,7 +54,7 @@ import org.koin.androidx.compose.koinViewModel
private fun PreviewSplitTunnelingScreen() {
AppTheme {
SplitTunnelingScreen(
- uiState =
+ state =
SplitTunnelingUiState.ShowAppList(
enabled = true,
excludedApps =
@@ -88,11 +88,11 @@ private fun PreviewSplitTunnelingScreen() {
@Composable
fun SplitTunneling(navigator: DestinationsNavigator) {
val viewModel = koinViewModel<SplitTunnelingViewModel>()
- val state by viewModel.uiState.collectAsState()
+ val state by viewModel.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current
val packageManager = remember(context) { context.packageManager }
SplitTunnelingScreen(
- uiState = state,
+ state = state,
onEnableSplitTunneling = viewModel::onEnableSplitTunneling,
onShowSystemAppsClick = viewModel::onShowSystemAppsClick,
onExcludeAppClick = viewModel::onExcludeAppClick,
@@ -106,7 +106,7 @@ fun SplitTunneling(navigator: DestinationsNavigator) {
@Composable
fun SplitTunnelingScreen(
- uiState: SplitTunnelingUiState,
+ state: SplitTunnelingUiState,
onEnableSplitTunneling: (Boolean) -> Unit = {},
onShowSystemAppsClick: (show: Boolean) -> Unit = {},
onExcludeAppClick: (packageName: String) -> Unit = {},
@@ -126,19 +126,16 @@ fun SplitTunnelingScreen(
horizontalAlignment = Alignment.CenterHorizontally,
state = lazyListState
) {
- enabledToggle(
- enabled = uiState.enabled,
- onEnableSplitTunneling = onEnableSplitTunneling
- )
- description(enabled = uiState.enabled)
+ enabledToggle(enabled = state.enabled, onEnableSplitTunneling = onEnableSplitTunneling)
+ description(enabled = state.enabled)
spacer()
- when (uiState) {
+ when (state) {
is SplitTunnelingUiState.Loading -> {
loading()
}
is SplitTunnelingUiState.ShowAppList -> {
appList(
- uiState = uiState,
+ state = state,
focusManager = focusManager,
onShowSystemAppsClick = onShowSystemAppsClick,
onExcludeAppClick = onExcludeAppClick,
@@ -184,45 +181,45 @@ private fun LazyListScope.loading() {
}
private fun LazyListScope.appList(
- uiState: SplitTunnelingUiState.ShowAppList,
+ state: SplitTunnelingUiState.ShowAppList,
focusManager: FocusManager,
onShowSystemAppsClick: (show: Boolean) -> Unit,
onExcludeAppClick: (packageName: String) -> Unit,
onIncludeAppClick: (packageName: String) -> Unit,
onResolveIcon: (String) -> Bitmap?
) {
- if (uiState.excludedApps.isNotEmpty()) {
+ if (state.excludedApps.isNotEmpty()) {
headerItem(
key = SplitTunnelingContentKey.EXCLUDED_APPLICATIONS,
textId = R.string.exclude_applications,
- enabled = uiState.enabled
+ enabled = state.enabled
)
appItems(
- apps = uiState.excludedApps,
+ apps = state.excludedApps,
focusManager = focusManager,
onAppClick = onIncludeAppClick,
onResolveIcon = onResolveIcon,
- enabled = uiState.enabled,
+ enabled = state.enabled,
excluded = true
)
spacer()
}
systemAppsToggle(
- showSystemApps = uiState.showSystemApps,
+ showSystemApps = state.showSystemApps,
onShowSystemAppsClick = onShowSystemAppsClick,
- enabled = uiState.enabled
+ enabled = state.enabled
)
headerItem(
key = SplitTunnelingContentKey.INCLUDED_APPLICATIONS,
textId = R.string.all_applications,
- enabled = uiState.enabled
+ enabled = state.enabled
)
appItems(
- apps = uiState.includedApps,
+ apps = state.includedApps,
focusManager = focusManager,
onAppClick = onExcludeAppClick,
onResolveIcon = onResolveIcon,
- enabled = uiState.enabled,
+ enabled = state.enabled,
excluded = false
)
}
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 ef4e58cda1..3e5a973d93 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
@@ -18,7 +18,7 @@ import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
@@ -27,6 +27,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import kotlinx.coroutines.launch
@@ -49,27 +50,27 @@ import org.koin.androidx.compose.koinViewModel
@Preview
@Composable
private fun PreviewViewLogsScreen() {
- AppTheme { ViewLogsScreen(uiState = ViewLogsUiState(listOf("Lorem ipsum"))) }
+ AppTheme { ViewLogsScreen(state = ViewLogsUiState(listOf("Lorem ipsum"))) }
}
@Preview
@Composable
private fun PreviewViewLogsLoadingScreen() {
- AppTheme { ViewLogsScreen(uiState = ViewLogsUiState()) }
+ AppTheme { ViewLogsScreen(state = ViewLogsUiState()) }
}
@Destination(style = SlideInFromRightTransition::class)
@Composable
fun ViewLogs(navigator: DestinationsNavigator) {
val vm = koinViewModel<ViewLogsViewModel>()
- val uiState = vm.uiState.collectAsState()
- ViewLogsScreen(uiState = uiState.value, onBackClick = navigator::navigateUp)
+ val state by vm.uiState.collectAsStateWithLifecycle()
+ ViewLogsScreen(state = state, onBackClick = navigator::navigateUp)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ViewLogsScreen(
- uiState: ViewLogsUiState,
+ state: ViewLogsUiState,
onBackClick: () -> Unit = {},
) {
val context = LocalContext.current
@@ -90,15 +91,13 @@ fun ViewLogsScreen(
navigationIcon = { NavigateBackIconButton(onBackClick) },
actions = {
val clipboardToastMessage = stringResource(R.string.copied_logs_to_clipboard)
- IconButton(
- onClick = { clipboardHandle(uiState.text(), clipboardToastMessage) }
- ) {
+ IconButton(onClick = { clipboardHandle(state.text(), clipboardToastMessage) }) {
Icon(
painter = painterResource(id = R.drawable.icon_copy),
contentDescription = null
)
}
- IconButton(onClick = { scope.launch { shareText(context, uiState.text()) } }) {
+ IconButton(onClick = { scope.launch { shareText(context, state.text()) } }) {
Icon(imageVector = Icons.Default.Share, contentDescription = null)
}
}
@@ -115,24 +114,24 @@ fun ViewLogsScreen(
bottom = Dimens.screenVerticalMargin
),
) {
- if (uiState.isLoading) {
+ if (state.isLoading) {
MullvadCircularProgressIndicatorMedium(
modifier =
Modifier.padding(Dimens.mediumPadding).align(Alignment.CenterHorizontally),
color = MaterialTheme.colorScheme.primary
)
} else {
- val state = rememberLazyListState()
+ val listState = rememberLazyListState()
LazyColumn(
- state = state,
+ state = listState,
modifier =
Modifier.drawVerticalScrollbar(
- state,
+ listState,
MaterialTheme.colorScheme.primary.copy(alpha = AlphaScrollbar)
)
.padding(horizontal = Dimens.smallPadding)
) {
- items(uiState.allLines) {
+ items(state.allLines) {
Text(text = it, style = MaterialTheme.typography.bodySmall)
}
}
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 32beb656e5..0aeece1c19 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
@@ -15,7 +15,6 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -30,6 +29,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.result.NavResult
@@ -97,7 +97,7 @@ import org.koin.androidx.compose.koinViewModel
private fun PreviewVpnSettings() {
AppTheme {
VpnSettingsScreen(
- uiState =
+ state =
VpnSettingsUiState.createDefault(
isAutoConnectEnabled = true,
mtu = "1337",
@@ -132,7 +132,7 @@ fun VpnSettings(
customWgPortResult: ResultRecipient<WireguardCustomPortDialogDestination, Int?>
) {
val vm = koinViewModel<VpnSettingsViewModel>()
- val state = vm.uiState.collectAsState().value
+ val state by vm.uiState.collectAsStateWithLifecycle()
dnsDialogResult.onNavResult {
when (it) {
@@ -185,7 +185,7 @@ fun VpnSettings(
}
VpnSettingsScreen(
- uiState = state,
+ state = state,
snackbarHostState = snackbarHostState,
navigateToContentBlockersInfo = {
navigator.navigate(ContentBlockersInfoDialogDestination) { launchSingleTop = true }
@@ -254,7 +254,7 @@ fun VpnSettings(
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun VpnSettingsScreen(
- uiState: VpnSettingsUiState,
+ state: VpnSettingsUiState,
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
navigateToContentBlockersInfo: () -> Unit = {},
navigateToAutoConnectScreen: () -> Unit = {},
@@ -295,7 +295,7 @@ fun VpnSettingsScreen(
modifier = modifier.testTag(LAZY_LIST_TEST_TAG).animateContentSize(),
state = lazyListState
) {
- if (uiState.systemVpnSettingsAvailable) {
+ if (state.systemVpnSettingsAvailable) {
item {
Spacer(modifier = Modifier.height(Dimens.cellLabelVerticalPadding))
NavigationComposeCell(
@@ -313,7 +313,7 @@ fun VpnSettingsScreen(
Spacer(modifier = Modifier.height(Dimens.cellLabelVerticalPadding))
HeaderSwitchComposeCell(
title = stringResource(R.string.auto_connect),
- isToggled = uiState.isAutoConnectEnabled,
+ isToggled = state.isAutoConnectEnabled,
isEnabled = true,
onCellClicked = { newValue -> onToggleAutoConnect(newValue) }
)
@@ -328,7 +328,7 @@ fun VpnSettingsScreen(
Spacer(modifier = Modifier.height(Dimens.cellLabelVerticalPadding))
HeaderSwitchComposeCell(
title = stringResource(R.string.local_network_sharing),
- isToggled = uiState.isLocalNetworkSharingEnabled,
+ isToggled = state.isLocalNetworkSharingEnabled,
isEnabled = true,
onCellClicked = { newValue -> onToggleLocalNetworkSharing(newValue) },
onInfoClicked = navigateToLocalNetworkSharingInfo
@@ -340,7 +340,7 @@ fun VpnSettingsScreen(
ExpandableComposeCell(
title = stringResource(R.string.dns_content_blockers_title),
isExpanded = expandContentBlockersState,
- isEnabled = !uiState.isCustomDnsEnabled,
+ isEnabled = !state.isCustomDnsEnabled,
onInfoClicked = { navigateToContentBlockersInfo() },
onCellClicked = { expandContentBlockersState = !expandContentBlockersState }
)
@@ -350,8 +350,8 @@ fun VpnSettingsScreen(
itemWithDivider {
NormalSwitchComposeCell(
title = stringResource(R.string.block_ads_title),
- isToggled = uiState.contentBlockersOptions.blockAds,
- isEnabled = !uiState.isCustomDnsEnabled,
+ isToggled = state.contentBlockersOptions.blockAds,
+ isEnabled = !state.isCustomDnsEnabled,
onCellClicked = { onToggleBlockAds(it) },
background = MaterialTheme.colorScheme.secondaryContainer,
startPadding = Dimens.indentedCellStartPadding
@@ -360,8 +360,8 @@ fun VpnSettingsScreen(
itemWithDivider {
NormalSwitchComposeCell(
title = stringResource(R.string.block_trackers_title),
- isToggled = uiState.contentBlockersOptions.blockTrackers,
- isEnabled = !uiState.isCustomDnsEnabled,
+ isToggled = state.contentBlockersOptions.blockTrackers,
+ isEnabled = !state.isCustomDnsEnabled,
onCellClicked = { onToggleBlockTrackers(it) },
background = MaterialTheme.colorScheme.secondaryContainer,
startPadding = Dimens.indentedCellStartPadding
@@ -370,8 +370,8 @@ fun VpnSettingsScreen(
itemWithDivider {
NormalSwitchComposeCell(
title = stringResource(R.string.block_malware_title),
- isToggled = uiState.contentBlockersOptions.blockMalware,
- isEnabled = !uiState.isCustomDnsEnabled,
+ isToggled = state.contentBlockersOptions.blockMalware,
+ isEnabled = !state.isCustomDnsEnabled,
onCellClicked = { onToggleBlockMalware(it) },
onInfoClicked = { navigateToMalwareInfo() },
background = MaterialTheme.colorScheme.secondaryContainer,
@@ -381,8 +381,8 @@ fun VpnSettingsScreen(
itemWithDivider {
NormalSwitchComposeCell(
title = stringResource(R.string.block_gambling_title),
- isToggled = uiState.contentBlockersOptions.blockGambling,
- isEnabled = !uiState.isCustomDnsEnabled,
+ isToggled = state.contentBlockersOptions.blockGambling,
+ isEnabled = !state.isCustomDnsEnabled,
onCellClicked = { onToggleBlockGambling(it) },
background = MaterialTheme.colorScheme.secondaryContainer,
startPadding = Dimens.indentedCellStartPadding
@@ -391,8 +391,8 @@ fun VpnSettingsScreen(
itemWithDivider {
NormalSwitchComposeCell(
title = stringResource(R.string.block_adult_content_title),
- isToggled = uiState.contentBlockersOptions.blockAdultContent,
- isEnabled = !uiState.isCustomDnsEnabled,
+ isToggled = state.contentBlockersOptions.blockAdultContent,
+ isEnabled = !state.isCustomDnsEnabled,
onCellClicked = { onToggleBlockAdultContent(it) },
background = MaterialTheme.colorScheme.secondaryContainer,
startPadding = Dimens.indentedCellStartPadding
@@ -402,15 +402,15 @@ fun VpnSettingsScreen(
item {
NormalSwitchComposeCell(
title = stringResource(R.string.block_social_media_title),
- isToggled = uiState.contentBlockersOptions.blockSocialMedia,
- isEnabled = !uiState.isCustomDnsEnabled,
+ isToggled = state.contentBlockersOptions.blockSocialMedia,
+ isEnabled = !state.isCustomDnsEnabled,
onCellClicked = { onToggleBlockSocialMedia(it) },
background = MaterialTheme.colorScheme.secondaryContainer,
startPadding = Dimens.indentedCellStartPadding
)
}
- if (uiState.isCustomDnsEnabled) {
+ if (state.isCustomDnsEnabled) {
item {
ContentBlockersDisableModeCellSubtitle(
Modifier.background(MaterialTheme.colorScheme.secondary)
@@ -428,19 +428,19 @@ fun VpnSettingsScreen(
item {
HeaderSwitchComposeCell(
title = stringResource(R.string.enable_custom_dns),
- isToggled = uiState.isCustomDnsEnabled,
- isEnabled = uiState.contentBlockersOptions.isAnyBlockerEnabled().not(),
+ isToggled = state.isCustomDnsEnabled,
+ isEnabled = state.contentBlockersOptions.isAnyBlockerEnabled().not(),
onCellClicked = { newValue -> onToggleDnsClick(newValue) },
onInfoClicked = { navigateToCustomDnsInfo() }
)
}
- if (uiState.isCustomDnsEnabled) {
- itemsIndexed(uiState.customDnsItems) { index, item ->
+ if (state.isCustomDnsEnabled) {
+ itemsIndexed(state.customDnsItems) { index, item ->
DnsCell(
address = item.address,
isUnreachableLocalDnsWarningVisible =
- item.isLocal && !uiState.isLocalNetworkSharingEnabled,
+ item.isLocal && !state.isLocalNetworkSharingEnabled,
onClick = { navigateToDns(index, item.address) },
modifier = Modifier.animateItemPlacement()
)
@@ -465,7 +465,7 @@ fun VpnSettingsScreen(
item {
CustomDnsCellSubtitle(
- isCellClickable = uiState.contentBlockersOptions.isAnyBlockerEnabled().not(),
+ isCellClickable = state.contentBlockersOptions.isAnyBlockerEnabled().not(),
modifier =
Modifier.background(MaterialTheme.colorScheme.secondary)
.padding(
@@ -481,15 +481,15 @@ fun VpnSettingsScreen(
Spacer(modifier = Modifier.height(Dimens.cellLabelVerticalPadding))
InformationComposeCell(
title = stringResource(id = R.string.wireguard_port_title),
- onInfoClicked = { navigateToWireguardPortInfo(uiState.availablePortRanges) },
- onCellClicked = { navigateToWireguardPortInfo(uiState.availablePortRanges) },
+ onInfoClicked = { navigateToWireguardPortInfo(state.availablePortRanges) },
+ onCellClicked = { navigateToWireguardPortInfo(state.availablePortRanges) },
)
}
itemWithDivider {
SelectableCell(
title = stringResource(id = R.string.automatic),
- isSelected = uiState.selectedWireguardPort is Constraint.Any,
+ isSelected = state.selectedWireguardPort is Constraint.Any,
onCellClicked = { onWireguardPortSelected(Constraint.Any()) }
)
}
@@ -499,7 +499,7 @@ fun VpnSettingsScreen(
SelectableCell(
title = port.toString(),
testTag = String.format(LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG, port),
- isSelected = uiState.selectedWireguardPort.hasValue(port),
+ isSelected = state.selectedWireguardPort.hasValue(port),
onCellClicked = { onWireguardPortSelected(Constraint.Only(Port(port))) }
)
}
@@ -508,11 +508,11 @@ fun VpnSettingsScreen(
itemWithDivider {
CustomPortCell(
title = stringResource(id = R.string.wireguard_custon_port_title),
- isSelected = uiState.selectedWireguardPort.isCustom(),
- port = uiState.customWireguardPort?.toValueOrNull(),
+ isSelected = state.selectedWireguardPort.isCustom(),
+ port = state.customWireguardPort?.toValueOrNull(),
onMainCellClicked = {
- if (uiState.customWireguardPort != null) {
- onWireguardPortSelected(uiState.customWireguardPort)
+ if (state.customWireguardPort != null) {
+ onWireguardPortSelected(state.customWireguardPort)
} else {
navigateToWireguardPortDialog()
}
@@ -534,21 +534,21 @@ fun VpnSettingsScreen(
itemWithDivider {
SelectableCell(
title = stringResource(id = R.string.automatic),
- isSelected = uiState.selectedObfuscation == SelectedObfuscation.Auto,
+ isSelected = state.selectedObfuscation == SelectedObfuscation.Auto,
onCellClicked = { onSelectObfuscationSetting(SelectedObfuscation.Auto) }
)
}
itemWithDivider {
SelectableCell(
title = stringResource(id = R.string.obfuscation_on_udp_over_tcp),
- isSelected = uiState.selectedObfuscation == SelectedObfuscation.Udp2Tcp,
+ isSelected = state.selectedObfuscation == SelectedObfuscation.Udp2Tcp,
onCellClicked = { onSelectObfuscationSetting(SelectedObfuscation.Udp2Tcp) }
)
}
itemWithDivider {
SelectableCell(
title = stringResource(id = R.string.off),
- isSelected = uiState.selectedObfuscation == SelectedObfuscation.Off,
+ isSelected = state.selectedObfuscation == SelectedObfuscation.Off,
onCellClicked = { onSelectObfuscationSetting(SelectedObfuscation.Off) }
)
}
@@ -564,7 +564,7 @@ fun VpnSettingsScreen(
itemWithDivider {
SelectableCell(
title = stringResource(id = R.string.automatic),
- isSelected = uiState.quantumResistant == QuantumResistantState.Auto,
+ isSelected = state.quantumResistant == QuantumResistantState.Auto,
onCellClicked = { onSelectQuantumResistanceSetting(QuantumResistantState.Auto) }
)
}
@@ -572,7 +572,7 @@ fun VpnSettingsScreen(
SelectableCell(
title = stringResource(id = R.string.on),
testTag = LAZY_LIST_QUANTUM_ITEM_ON_TEST_TAG,
- isSelected = uiState.quantumResistant == QuantumResistantState.On,
+ isSelected = state.quantumResistant == QuantumResistantState.On,
onCellClicked = { onSelectQuantumResistanceSetting(QuantumResistantState.On) }
)
}
@@ -580,7 +580,7 @@ fun VpnSettingsScreen(
SelectableCell(
title = stringResource(id = R.string.off),
testTag = LAZY_LIST_QUANTUM_ITEM_OFF_TEST_TAG,
- isSelected = uiState.quantumResistant == QuantumResistantState.Off,
+ isSelected = state.quantumResistant == QuantumResistantState.Off,
onCellClicked = { onSelectQuantumResistanceSetting(QuantumResistantState.Off) }
)
Spacer(modifier = Modifier.height(Dimens.cellLabelVerticalPadding))
@@ -588,8 +588,8 @@ fun VpnSettingsScreen(
item {
MtuComposeCell(
- mtuValue = uiState.mtu,
- onEditMtu = { navigateToMtuDialog(uiState.mtu.toIntOrNull()) }
+ mtuValue = state.mtu,
+ onEditMtu = { navigateToMtuDialog(state.mtu.toIntOrNull()) }
)
}
item {
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 ead6c41d78..cb9989a4df 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
@@ -17,7 +17,6 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
@@ -27,6 +26,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.popUpTo
@@ -68,7 +68,7 @@ import org.koin.androidx.compose.koinViewModel
private fun PreviewWelcomeScreen() {
AppTheme {
WelcomeScreen(
- uiState =
+ state =
WelcomeUiState(
accountNumber = "4444555566667777",
deviceName = "Happy Mole",
@@ -99,7 +99,7 @@ fun Welcome(
playPaymentResultRecipient: ResultRecipient<PaymentDestination, Boolean>
) {
val vm = koinViewModel<WelcomeViewModel>()
- val state by vm.uiState.collectAsState()
+ val state by vm.uiState.collectAsStateWithLifecycle()
voucherRedeemResultRecipient.onNavResult {
when (it) {
@@ -142,7 +142,7 @@ fun Welcome(
}
WelcomeScreen(
- uiState = state,
+ state = state,
onSitePaymentClick = vm::onSitePaymentClick,
onRedeemVoucherClick = {
navigator.navigate(RedeemVoucherDestination) { launchSingleTop = true }
@@ -163,7 +163,7 @@ fun Welcome(
@Composable
fun WelcomeScreen(
- uiState: WelcomeUiState,
+ state: WelcomeUiState,
onSitePaymentClick: () -> Unit,
onRedeemVoucherClick: () -> Unit,
onSettingsClick: () -> Unit,
@@ -177,13 +177,13 @@ fun WelcomeScreen(
ScaffoldWithTopBar(
topBarColor =
- if (uiState.tunnelState.isSecured()) {
+ if (state.tunnelState.isSecured()) {
MaterialTheme.colorScheme.inversePrimary
} else {
MaterialTheme.colorScheme.error
},
iconTintColor =
- if (uiState.tunnelState.isSecured()) {
+ if (state.tunnelState.isSecured()) {
MaterialTheme.colorScheme.onPrimary
} else {
MaterialTheme.colorScheme.onError
@@ -204,14 +204,14 @@ fun WelcomeScreen(
)
) {
// Welcome info area
- WelcomeInfo(snackbarHostState, uiState, navigateToDeviceInfoDialog)
+ WelcomeInfo(snackbarHostState, state, navigateToDeviceInfoDialog)
Spacer(modifier = Modifier.weight(1f))
// Payment button area
PaymentPanel(
- showSitePayment = uiState.showSitePayment,
- billingPaymentState = uiState.billingPaymentState,
+ showSitePayment = state.showSitePayment,
+ billingPaymentState = state.billingPaymentState,
onSitePaymentClick = onSitePaymentClick,
onRedeemVoucherClick = onRedeemVoucherClick,
onPurchaseBillingProductClick = onPurchaseBillingProductClick,
@@ -224,7 +224,7 @@ fun WelcomeScreen(
@Composable
private fun WelcomeInfo(
snackbarHostState: SnackbarHostState,
- uiState: WelcomeUiState,
+ state: WelcomeUiState,
navigateToDeviceInfoDialog: () -> Unit
) {
Column {
@@ -254,15 +254,15 @@ private fun WelcomeInfo(
color = MaterialTheme.colorScheme.onPrimary
)
- AccountNumberRow(snackbarHostState, uiState)
+ AccountNumberRow(snackbarHostState, state)
- DeviceNameRow(deviceName = uiState.deviceName, navigateToDeviceInfoDialog)
+ DeviceNameRow(deviceName = state.deviceName, navigateToDeviceInfoDialog)
Text(
text =
buildString {
append(stringResource(id = R.string.pay_to_start_using))
- if (uiState.showSitePayment) {
+ if (state.showSitePayment) {
append(" ")
append(stringResource(id = R.string.add_time_to_account))
}
@@ -281,11 +281,11 @@ private fun WelcomeInfo(
}
@Composable
-private fun AccountNumberRow(snackbarHostState: SnackbarHostState, uiState: WelcomeUiState) {
+private fun AccountNumberRow(snackbarHostState: SnackbarHostState, state: WelcomeUiState) {
val copiedAccountNumberMessage = stringResource(id = R.string.copied_mullvad_account_number)
val copyToClipboard = createCopyToClipboardHandle(snackbarHostState = snackbarHostState)
val onCopyToClipboard = {
- copyToClipboard(uiState.accountNumber ?: "", copiedAccountNumberMessage)
+ copyToClipboard(state.accountNumber ?: "", copiedAccountNumberMessage)
}
Row(
@@ -297,7 +297,7 @@ private fun AccountNumberRow(snackbarHostState: SnackbarHostState, uiState: Welc
.padding(horizontal = Dimens.sideMargin)
) {
Text(
- text = uiState.accountNumber?.groupWithSpaces() ?: "",
+ text = state.accountNumber?.groupWithSpaces() ?: "",
modifier = Modifier.weight(1f).padding(vertical = Dimens.smallPadding),
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onPrimary