diff options
| author | David Göransson <david.goransson90@gmail.com> | 2024-03-04 10:40:49 +0100 |
|---|---|---|
| committer | Albin <albin@mullvad.net> | 2024-03-05 12:41:44 +0100 |
| commit | 4ae1040d3a165df845333638518965ca79377b15 (patch) | |
| tree | c98956b27be46c295e6e4a312d02346ffaa684ec /android | |
| parent | dbf70755217470d42da760471d6fa950489060de (diff) | |
| download | mullvadvpn-4ae1040d3a165df845333638518965ca79377b15.tar.xz mullvadvpn-4ae1040d3a165df845333638518965ca79377b15.zip | |
Use collectAsStateWithLifecycle
Diffstat (limited to 'android')
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 |
