diff options
46 files changed, 665 insertions, 239 deletions
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/EditCustomListScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/EditCustomListScreenTest.kt index 7284a3294d..1207f2417b 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/EditCustomListScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/EditCustomListScreenTest.kt @@ -10,7 +10,7 @@ import io.mockk.verify import net.mullvad.mullvadvpn.compose.createEdgeToEdgeComposeExtension import net.mullvad.mullvadvpn.compose.data.DUMMY_CUSTOM_LISTS import net.mullvad.mullvadvpn.compose.setContentWithTheme -import net.mullvad.mullvadvpn.compose.state.EditCustomListState +import net.mullvad.mullvadvpn.compose.state.EditCustomListUiState import net.mullvad.mullvadvpn.compose.test.CIRCULAR_PROGRESS_INDICATOR import net.mullvad.mullvadvpn.compose.test.DELETE_DROPDOWN_MENU_ITEM_TEST_TAG import net.mullvad.mullvadvpn.compose.test.TOP_BAR_DROPDOWN_BUTTON_TEST_TAG @@ -33,7 +33,7 @@ class EditCustomListScreenTest { fun givenLoadingStateShouldShowLoadingSpinner() = composeExtension.use { // Arrange - setContentWithTheme { EditCustomListScreen(state = EditCustomListState.Loading) } + setContentWithTheme { EditCustomListScreen(state = EditCustomListUiState.Loading) } // Assert onNodeWithTag(CIRCULAR_PROGRESS_INDICATOR).assertExists() @@ -43,7 +43,7 @@ class EditCustomListScreenTest { fun givenNotFoundStateShouldShowNotFound() = composeExtension.use { // Arrange - setContentWithTheme { EditCustomListScreen(state = EditCustomListState.NotFound) } + setContentWithTheme { EditCustomListScreen(state = EditCustomListUiState.NotFound) } // Assert onNodeWithText(NOT_FOUND_TEXT).assertExists() @@ -57,7 +57,7 @@ class EditCustomListScreenTest { setContentWithTheme { EditCustomListScreen( state = - EditCustomListState.Content( + EditCustomListUiState.Content( id = customList.id, name = customList.name, locations = customList.locations, @@ -77,7 +77,7 @@ class EditCustomListScreenTest { setContentWithTheme { EditCustomListScreen( state = - EditCustomListState.Content( + EditCustomListUiState.Content( id = customList.id, name = customList.name, locations = customList.locations, @@ -98,7 +98,7 @@ class EditCustomListScreenTest { setContentWithTheme { EditCustomListScreen( state = - EditCustomListState.Content( + EditCustomListUiState.Content( id = customList.id, name = customList.name, locations = customList.locations, @@ -124,7 +124,7 @@ class EditCustomListScreenTest { setContentWithTheme { EditCustomListScreen( state = - EditCustomListState.Content( + EditCustomListUiState.Content( id = customList.id, name = customList.name, locations = customList.locations, @@ -149,7 +149,7 @@ class EditCustomListScreenTest { setContentWithTheme { EditCustomListScreen( state = - EditCustomListState.Content( + EditCustomListUiState.Content( id = customList.id, name = customList.name, locations = customList.locations, 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 b978fc49a0..7ca3d6941e 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 @@ -8,7 +8,7 @@ import io.mockk.mockk import io.mockk.verify import net.mullvad.mullvadvpn.compose.createEdgeToEdgeComposeExtension import net.mullvad.mullvadvpn.compose.setContentWithTheme -import net.mullvad.mullvadvpn.compose.state.RelayFilterState +import net.mullvad.mullvadvpn.compose.state.RelayFilterUiState import net.mullvad.mullvadvpn.lib.model.Ownership import net.mullvad.mullvadvpn.lib.model.Provider import net.mullvad.mullvadvpn.lib.model.ProviderId @@ -29,7 +29,7 @@ class FilterScreenTest { setContentWithTheme { FilterScreen( state = - RelayFilterState( + RelayFilterUiState( allProviders = DUMMY_RELAY_ALL_PROVIDERS, selectedOwnership = null, selectedProviders = DUMMY_SELECTED_PROVIDERS, @@ -47,7 +47,7 @@ class FilterScreenTest { setContentWithTheme { FilterScreen( state = - RelayFilterState( + RelayFilterUiState( allProviders = DUMMY_RELAY_ALL_PROVIDERS, selectedOwnership = null, selectedProviders = DUMMY_SELECTED_PROVIDERS, @@ -65,7 +65,7 @@ class FilterScreenTest { setContentWithTheme { FilterScreen( state = - RelayFilterState( + RelayFilterUiState( allProviders = DUMMY_RELAY_ALL_PROVIDERS, selectedOwnership = Ownership.MullvadOwned, selectedProviders = DUMMY_SELECTED_PROVIDERS, @@ -83,7 +83,7 @@ class FilterScreenTest { setContentWithTheme { FilterScreen( state = - RelayFilterState( + RelayFilterUiState( allProviders = DUMMY_RELAY_ALL_PROVIDERS, selectedOwnership = Ownership.Rented, selectedProviders = DUMMY_SELECTED_PROVIDERS, @@ -101,7 +101,7 @@ class FilterScreenTest { setContentWithTheme { FilterScreen( state = - RelayFilterState( + RelayFilterUiState( allProviders = DUMMY_RELAY_ALL_PROVIDERS, selectedOwnership = null, selectedProviders = DUMMY_SELECTED_PROVIDERS, @@ -122,7 +122,7 @@ class FilterScreenTest { setContentWithTheme { FilterScreen( state = - RelayFilterState( + RelayFilterUiState( allProviders = listOf(), selectedOwnership = null, selectedProviders = diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ServerIpOverridesScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ServerIpOverridesScreenTest.kt index 2cd3163e78..8d33d848f1 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ServerIpOverridesScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ServerIpOverridesScreenTest.kt @@ -16,7 +16,7 @@ import net.mullvad.mullvadvpn.compose.test.SERVER_IP_OVERRIDE_IMPORT_TEST_TAG import net.mullvad.mullvadvpn.compose.test.SERVER_IP_OVERRIDE_INFO_TEST_TAG import net.mullvad.mullvadvpn.compose.test.SERVER_IP_OVERRIDE_MORE_VERT_TEST_TAG import net.mullvad.mullvadvpn.compose.test.SERVER_IP_OVERRIDE_RESET_OVERRIDES_TEST_TAG -import net.mullvad.mullvadvpn.viewmodel.ServerIpOverridesViewState +import net.mullvad.mullvadvpn.viewmodel.ServerIpOverridesUiState import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.RegisterExtension @@ -33,7 +33,7 @@ class ServerIpOverridesScreenTest { @Suppress("TestFunctionName") @Composable private fun ScreenWithDefault( - state: ServerIpOverridesViewState, + state: ServerIpOverridesUiState, onBackClick: () -> Unit = {}, onInfoClick: () -> Unit = {}, onResetOverridesClick: () -> Unit = {}, @@ -55,7 +55,7 @@ class ServerIpOverridesScreenTest { composeExtension.use { // Arrange setContentWithTheme { - ScreenWithDefault(state = ServerIpOverridesViewState.Loaded(false)) + ScreenWithDefault(state = ServerIpOverridesUiState.Loaded(false)) } // Assert @@ -66,9 +66,7 @@ class ServerIpOverridesScreenTest { fun ensure_overrides_active_is_displayed() = composeExtension.use { // Arrange - setContentWithTheme { - ScreenWithDefault(state = ServerIpOverridesViewState.Loaded(true)) - } + setContentWithTheme { ScreenWithDefault(state = ServerIpOverridesUiState.Loaded(true)) } // Assert onNodeWithText("Overrides active").assertExists() @@ -78,9 +76,7 @@ class ServerIpOverridesScreenTest { fun ensure_overrides_active_shows_warning_on_import() = composeExtension.use { // Arrange - setContentWithTheme { - ScreenWithDefault(state = ServerIpOverridesViewState.Loaded(true)) - } + setContentWithTheme { ScreenWithDefault(state = ServerIpOverridesUiState.Loaded(true)) } // Act onNodeWithTag(testTag = SERVER_IP_OVERRIDE_IMPORT_TEST_TAG).performClick() @@ -99,7 +95,7 @@ class ServerIpOverridesScreenTest { val clickHandler: () -> Unit = mockk(relaxed = true) setContentWithTheme { ScreenWithDefault( - state = ServerIpOverridesViewState.Loaded(false), + state = ServerIpOverridesUiState.Loaded(false), onInfoClick = clickHandler, ) } @@ -118,7 +114,7 @@ class ServerIpOverridesScreenTest { val clickHandler: () -> Unit = mockk(relaxed = true) setContentWithTheme { ScreenWithDefault( - state = ServerIpOverridesViewState.Loaded(true), + state = ServerIpOverridesUiState.Loaded(true), onResetOverridesClick = clickHandler, ) } @@ -138,7 +134,7 @@ class ServerIpOverridesScreenTest { val clickHandler: () -> Unit = mockk(relaxed = true) setContentWithTheme { ScreenWithDefault( - state = ServerIpOverridesViewState.Loaded(false), + state = ServerIpOverridesUiState.Loaded(false), onImportByFile = clickHandler, ) } @@ -158,7 +154,7 @@ class ServerIpOverridesScreenTest { val clickHandler: () -> Unit = mockk(relaxed = true) setContentWithTheme { ScreenWithDefault( - state = ServerIpOverridesViewState.Loaded(false), + state = ServerIpOverridesUiState.Loaded(false), onImportByText = clickHandler, ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/AccountUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/AccountUiStatePreviewParameterProvider.kt new file mode 100644 index 0000000000..e6baaf9c20 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/AccountUiStatePreviewParameterProvider.kt @@ -0,0 +1,55 @@ +package net.mullvad.mullvadvpn.compose.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import net.mullvad.mullvadvpn.compose.state.PaymentState +import net.mullvad.mullvadvpn.lib.model.AccountNumber +import net.mullvad.mullvadvpn.lib.payment.model.PaymentProduct +import net.mullvad.mullvadvpn.lib.payment.model.PaymentStatus +import net.mullvad.mullvadvpn.lib.payment.model.ProductId +import net.mullvad.mullvadvpn.lib.payment.model.ProductPrice +import net.mullvad.mullvadvpn.viewmodel.AccountUiState +import org.joda.time.DateTime + +class AccountUiStatePreviewParameterProvider : PreviewParameterProvider<AccountUiState> { + override val values = + sequenceOf( + AccountUiState( + deviceName = "Test Name", + accountNumber = AccountNumber("1234123412341234"), + accountExpiry = DateTime.parse("2050-12-01"), + showSitePayment = true, + billingPaymentState = + PaymentState.PaymentAvailable( + listOf( + PaymentProduct( + ProductId("productId"), + price = ProductPrice("34 SEK"), + status = null, + ), + PaymentProduct( + ProductId("productId_pending"), + price = ProductPrice("34 SEK"), + status = PaymentStatus.PENDING, + ), + ) + ), + ) + ) + generateOtherStates() +} + +private fun generateOtherStates(): Sequence<AccountUiState> = + sequenceOf( + PaymentState.Loading, + PaymentState.NoPayment, + PaymentState.NoProductsFounds, + PaymentState.Error.Billing, + ) + .map { state -> + AccountUiState( + deviceName = "Test Name", + accountNumber = AccountNumber("1234123412341234"), + accountExpiry = null, + showSitePayment = false, + billingPaymentState = state, + ) + } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/ConnectUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/ConnectUiStatePreviewParameterProvider.kt new file mode 100644 index 0000000000..3a37033a8f --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/ConnectUiStatePreviewParameterProvider.kt @@ -0,0 +1,54 @@ +package net.mullvad.mullvadvpn.compose.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import java.net.InetAddress +import net.mullvad.mullvadvpn.compose.state.ConnectUiState +import net.mullvad.mullvadvpn.lib.model.ActionAfterDisconnect +import net.mullvad.mullvadvpn.lib.model.GeoIpLocation +import net.mullvad.mullvadvpn.lib.model.TransportProtocol + +private const val PORT = 23451 + +class ConnectUiStatePreviewParameterProvider : PreviewParameterProvider<ConnectUiState> { + override val values = sequenceOf(ConnectUiState.INITIAL) + generateOtherStates() +} + +private fun generateOtherStates(): Sequence<ConnectUiState> = + sequenceOf( + TunnelStatePreviewData.generateConnectedState( + featureIndicators = 8, + quantumResistant = true, + ), + TunnelStatePreviewData.generateDisconnectedState(), + TunnelStatePreviewData.generateConnectingState( + featureIndicators = 4, + quantumResistant = false, + ), + TunnelStatePreviewData.generateDisconnectingState( + actionAfterDisconnect = ActionAfterDisconnect.Reconnect + ), + TunnelStatePreviewData.generateErrorState(isBlocking = true), + ) + .map { state -> + ConnectUiState( + location = + GeoIpLocation( + ipv4 = InetAddress.getLocalHost(), + ipv6 = null, + country = "Sweden", + city = "Göteborg", + latitude = 23.3, + longitude = 12.99, + hostname = "Hostname", + ), + selectedRelayItemTitle = "Relay Title", + tunnelState = state, + inAddress = Triple("inaddress", PORT, TransportProtocol.Tcp), + outAddress = "192.168.1.1", + showLocation = true, + inAppNotification = null, + deviceName = "Cool Beans", + daysLeftUntilExpiry = 42, + isPlayBuild = true, + ) + } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/CustomListLocationUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/CustomListLocationUiStatePreviewParameterProvider.kt new file mode 100644 index 0000000000..7c4253be50 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/CustomListLocationUiStatePreviewParameterProvider.kt @@ -0,0 +1,43 @@ +package net.mullvad.mullvadvpn.compose.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import net.mullvad.mullvadvpn.compose.state.CustomListLocationsUiState +import net.mullvad.mullvadvpn.compose.state.RelayLocationListItem +import net.mullvad.mullvadvpn.lib.model.GeoLocationId + +class CustomListLocationUiStatePreviewParameterProvider : + PreviewParameterProvider<CustomListLocationsUiState> { + override val values = + sequenceOf( + CustomListLocationsUiState.Content.Data( + newList = true, + locations = + listOf( + RelayLocationListItem( + item = + RelayItemPreviewData.generateRelayItemCountry( + name = "A relay", + cityNames = listOf("City 1", "City 2"), + relaysPerCity = 2, + active = true, + ) + ), + RelayLocationListItem( + item = + RelayItemPreviewData.generateRelayItemCountry( + name = "Another relay", + cityNames = listOf("City X", "City Y", "City Z"), + relaysPerCity = 1, + active = false, + ) + .copy(id = GeoLocationId.Country("se")) + ), + ), + searchTerm = "", + saveEnabled = true, + hasUnsavedChanges = true, + ), + CustomListLocationsUiState.Content.Empty(newList = false, searchTerm = "searchTerm"), + CustomListLocationsUiState.Loading(newList = true), + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/CustomListsUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/CustomListsUiStatePreviewParameterProvider.kt new file mode 100644 index 0000000000..ccaa3b1bf1 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/CustomListsUiStatePreviewParameterProvider.kt @@ -0,0 +1,51 @@ +package net.mullvad.mullvadvpn.compose.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import net.mullvad.mullvadvpn.compose.state.CustomListsUiState +import net.mullvad.mullvadvpn.lib.model.CustomList +import net.mullvad.mullvadvpn.lib.model.CustomListId +import net.mullvad.mullvadvpn.lib.model.CustomListName +import net.mullvad.mullvadvpn.lib.model.GeoLocationId + +class CustomListsUiStatePreviewParameterProvider : PreviewParameterProvider<CustomListsUiState> { + override val values = + sequenceOf( + CustomListsUiState.Content( + customLists = + listOf( + CustomList( + id = CustomListId("list1"), + name = CustomListName.fromString("Custom List 1"), + locations = + listOf( + GeoLocationId.Hostname( + city = + GeoLocationId.City( + country = GeoLocationId.Country("se"), + code = "code", + ), + code = "code", + ) + ), + ), + CustomList( + id = CustomListId("list2"), + name = CustomListName.fromString("Custom List 2"), + locations = + listOf( + GeoLocationId.Hostname( + city = + GeoLocationId.City( + country = GeoLocationId.Country("de"), + code = "code", + ), + code = "code", + ) + ), + ), + ) + ), + CustomListsUiState.Content(), + CustomListsUiState.Loading, + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/DeviceRevokedUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/DeviceRevokedUiStatePreviewParameterProvider.kt new file mode 100644 index 0000000000..018a160686 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/DeviceRevokedUiStatePreviewParameterProvider.kt @@ -0,0 +1,14 @@ +package net.mullvad.mullvadvpn.compose.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import net.mullvad.mullvadvpn.compose.state.DeviceRevokedUiState + +class DeviceRevokedUiStatePreviewParameterProvider : + PreviewParameterProvider<DeviceRevokedUiState> { + override val values = + sequenceOf( + DeviceRevokedUiState.SECURED, + DeviceRevokedUiState.UNSECURED, + DeviceRevokedUiState.UNKNOWN, + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/EditCustomListUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/EditCustomListUiStatePreviewParameterProvider.kt new file mode 100644 index 0000000000..abd3e2743b --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/EditCustomListUiStatePreviewParameterProvider.kt @@ -0,0 +1,27 @@ +package net.mullvad.mullvadvpn.compose.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import net.mullvad.mullvadvpn.compose.state.EditCustomListUiState +import net.mullvad.mullvadvpn.lib.model.CustomListId +import net.mullvad.mullvadvpn.lib.model.CustomListName +import net.mullvad.mullvadvpn.lib.model.GeoLocationId + +class EditCustomListUiStatePreviewParameterProvider : + PreviewParameterProvider<EditCustomListUiState> { + override val values = + sequenceOf( + EditCustomListUiState.Content( + id = CustomListId("id"), + name = CustomListName.fromString("Custom list"), + locations = + listOf( + GeoLocationId.Hostname( + GeoLocationId.City(GeoLocationId.Country("country"), code = "city"), + "hostname", + ) + ), + ), + EditCustomListUiState.Loading, + EditCustomListUiState.NotFound, + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/FilterUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/FilterUiStatePreviewParameterProvider.kt new file mode 100644 index 0000000000..8728143067 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/FilterUiStatePreviewParameterProvider.kt @@ -0,0 +1,21 @@ +package net.mullvad.mullvadvpn.compose.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import net.mullvad.mullvadvpn.compose.state.RelayFilterUiState +import net.mullvad.mullvadvpn.lib.model.Ownership +import net.mullvad.mullvadvpn.lib.model.Provider +import net.mullvad.mullvadvpn.lib.model.ProviderId + +private val PROVIDER = + Provider(providerId = ProviderId("provider1"), ownership = Ownership.MullvadOwned) + +class FilterUiStatePreviewParameterProvider : PreviewParameterProvider<RelayFilterUiState> { + override val values = + sequenceOf( + RelayFilterUiState( + selectedOwnership = Ownership.MullvadOwned, + allProviders = listOf(PROVIDER), + selectedProviders = listOf(PROVIDER), + ) + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/SelectLocationsUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/SelectLocationsUiStatePreviewParameterProvider.kt new file mode 100644 index 0000000000..a3b4e1bcdc --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/SelectLocationsUiStatePreviewParameterProvider.kt @@ -0,0 +1,66 @@ +package net.mullvad.mullvadvpn.compose.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import net.mullvad.mullvadvpn.compose.state.FilterChip +import net.mullvad.mullvadvpn.compose.state.ModelOwnership +import net.mullvad.mullvadvpn.compose.state.RelayListItem +import net.mullvad.mullvadvpn.compose.state.SelectLocationUiState +import net.mullvad.mullvadvpn.lib.model.CustomListId +import net.mullvad.mullvadvpn.lib.model.CustomListName +import net.mullvad.mullvadvpn.lib.model.DomainCustomList +import net.mullvad.mullvadvpn.lib.model.GeoLocationId +import net.mullvad.mullvadvpn.lib.model.Ownership +import net.mullvad.mullvadvpn.lib.model.Provider +import net.mullvad.mullvadvpn.lib.model.ProviderId +import net.mullvad.mullvadvpn.lib.model.RelayItem + +private val RELAY = + RelayItem.Location.Relay( + id = + GeoLocationId.Hostname( + city = GeoLocationId.City(country = GeoLocationId.Country("se"), code = "code"), + code = "code", + ), + provider = Provider(providerId = ProviderId("providerId"), ownership = Ownership.Rented), + active = true, + daita = true, + ) + +class SelectLocationsUiStatePreviewParameterProvider : + PreviewParameterProvider<SelectLocationUiState> { + override val values = + sequenceOf( + SelectLocationUiState.Content( + searchTerm = "search term", + listOf(FilterChip.Ownership(ownership = ModelOwnership.MullvadOwned)), + relayListItems = + listOf( + RelayListItem.GeoLocationItem( + item = RELAY, + isSelected = true, + depth = 1, + expanded = true, + ) + ), + customLists = + listOf( + RelayItem.CustomList( + customList = + DomainCustomList( + id = CustomListId("custom_list_id"), + locations = + listOf( + GeoLocationId.City( + country = GeoLocationId.Country("dk"), + code = "code2", + ) + ), + name = CustomListName.fromString("Custom List"), + ), + locations = listOf(RELAY), + ) + ), + ), + SelectLocationUiState.Loading, + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/ServerIpOverridesUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/ServerIpOverridesUiStatePreviewParameterProvider.kt new file mode 100644 index 0000000000..2c2988e0da --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/ServerIpOverridesUiStatePreviewParameterProvider.kt @@ -0,0 +1,14 @@ +package net.mullvad.mullvadvpn.compose.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import net.mullvad.mullvadvpn.viewmodel.ServerIpOverridesUiState + +class ServerIpOverridesUiStatePreviewParameterProvider : + PreviewParameterProvider<ServerIpOverridesUiState> { + override val values = + sequenceOf( + ServerIpOverridesUiState.Loaded(overridesActive = true), + ServerIpOverridesUiState.Loaded(overridesActive = false), + ServerIpOverridesUiState.Loading, + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/SettingsUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/SettingsUiStatePreviewParameterProvider.kt new file mode 100644 index 0000000000..6230911766 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/SettingsUiStatePreviewParameterProvider.kt @@ -0,0 +1,22 @@ +package net.mullvad.mullvadvpn.compose.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import net.mullvad.mullvadvpn.compose.state.SettingsUiState + +class SettingsUiStatePreviewParameterProvider : PreviewParameterProvider<SettingsUiState> { + override val values = + sequenceOf( + SettingsUiState( + appVersion = "2222.22", + isLoggedIn = true, + isSupportedVersion = true, + isPlayBuild = true, + ), + SettingsUiState( + appVersion = "9000.1", + isLoggedIn = false, + isSupportedVersion = false, + isPlayBuild = false, + ), + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/SplitTunnelingUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/SplitTunnelingUiStatePreviewParameterProvider.kt new file mode 100644 index 0000000000..70d9d2eae2 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/SplitTunnelingUiStatePreviewParameterProvider.kt @@ -0,0 +1,39 @@ +package net.mullvad.mullvadvpn.compose.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import net.mullvad.mullvadvpn.R +import net.mullvad.mullvadvpn.applist.AppData +import net.mullvad.mullvadvpn.compose.state.SplitTunnelingUiState + +class SplitTunnelingUiStatePreviewParameterProvider : + PreviewParameterProvider<SplitTunnelingUiState> { + override val values = + sequenceOf( + SplitTunnelingUiState.ShowAppList( + enabled = true, + excludedApps = + listOf( + AppData( + packageName = "my.package.a", + name = "TitleA", + iconRes = R.drawable.icon_alert, + ), + AppData( + packageName = "my.package.b", + name = "TitleB", + iconRes = R.drawable.icon_chevron, + ), + ), + includedApps = + listOf( + AppData( + packageName = "my.package.c", + name = "TitleC", + iconRes = R.drawable.icon_alert, + ) + ), + showSystemApps = true, + ), + SplitTunnelingUiState.Loading(enabled = true), + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/ViewLogsUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/ViewLogsUiStatePreviewParameterProvider.kt new file mode 100644 index 0000000000..065a15de2b --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/ViewLogsUiStatePreviewParameterProvider.kt @@ -0,0 +1,14 @@ +package net.mullvad.mullvadvpn.compose.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import net.mullvad.mullvadvpn.viewmodel.ViewLogsUiState + +private const val SIZE = 50 + +class ViewLogsUiStatePreviewParameterProvider : PreviewParameterProvider<ViewLogsUiState> { + + val text = List(SIZE) { "Lorem ipsum dolor ".repeat(SIZE) } + + override val values = + sequenceOf(ViewLogsUiState(text, isLoading = false), ViewLogsUiState(isLoading = true)) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/VpnSettingsUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/VpnSettingsUiStatePreviewParameterProvider.kt new file mode 100644 index 0000000000..e583e6ea0c --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/VpnSettingsUiStatePreviewParameterProvider.kt @@ -0,0 +1,43 @@ +package net.mullvad.mullvadvpn.compose.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import net.mullvad.mullvadvpn.compose.state.VpnSettingsUiState +import net.mullvad.mullvadvpn.lib.model.Constraint +import net.mullvad.mullvadvpn.lib.model.DefaultDnsOptions +import net.mullvad.mullvadvpn.lib.model.Mtu +import net.mullvad.mullvadvpn.lib.model.Port +import net.mullvad.mullvadvpn.lib.model.QuantumResistantState +import net.mullvad.mullvadvpn.viewmodel.CustomDnsItem + +private const val MTU = 1337 +@Suppress("MagicNumber") private val PORT1 = Port(9001) +@Suppress("MagicNumber") private val PORT2 = Port(12433) + +class VpnSettingsUiStatePreviewParameterProvider : PreviewParameterProvider<VpnSettingsUiState> { + override val values = + sequenceOf( + VpnSettingsUiState.createDefault(), + VpnSettingsUiState.createDefault( + mtu = Mtu(MTU), + isAutoConnectEnabled = true, + isLocalNetworkSharingEnabled = true, + isDaitaEnabled = true, + isCustomDnsEnabled = true, + customDnsItems = listOf(CustomDnsItem("0.0.0.0", false)), + contentBlockersOptions = + DefaultDnsOptions( + blockAds = true, + blockMalware = true, + blockGambling = true, + blockTrackers = true, + blockSocialMedia = true, + blockAdultContent = true, + ), + quantumResistant = QuantumResistantState.On, + selectedWireguardPort = Constraint.Any, + customWireguardPort = PORT1, + availablePortRanges = listOf(PORT1..PORT2), + systemVpnSettingsAvailable = true, + ), + ) +} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/WelcomeScreenUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/WelcomeScreenUiStatePreviewParameterProvider.kt new file mode 100644 index 0000000000..79e7ae0069 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/WelcomeScreenUiStatePreviewParameterProvider.kt @@ -0,0 +1,25 @@ +package net.mullvad.mullvadvpn.compose.preview + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import net.mullvad.mullvadvpn.compose.state.PaymentState +import net.mullvad.mullvadvpn.compose.state.WelcomeUiState +import net.mullvad.mullvadvpn.lib.model.AccountNumber +import net.mullvad.mullvadvpn.lib.payment.model.PaymentProduct +import net.mullvad.mullvadvpn.lib.payment.model.ProductId +import net.mullvad.mullvadvpn.lib.payment.model.ProductPrice + +class WelcomeScreenUiStatePreviewParameterProvider : PreviewParameterProvider<WelcomeUiState> { + override val values = + sequenceOf( + WelcomeUiState( + tunnelState = TunnelStatePreviewData.generateDisconnectedState(), + accountNumber = AccountNumber("4444555566667777"), + deviceName = "Happy Mole", + billingPaymentState = + PaymentState.PaymentAvailable( + products = + listOf(PaymentProduct(ProductId("product"), ProductPrice("$44"), null)) + ), + ) + ) +} 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 8239646bca..ac1d758ecc 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 @@ -23,6 +23,7 @@ import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed import com.ramcosta.composedestinations.annotation.Destination @@ -49,17 +50,13 @@ import net.mullvad.mullvadvpn.compose.component.PlayPayment import net.mullvad.mullvadvpn.compose.component.ScaffoldWithMediumTopBar import net.mullvad.mullvadvpn.compose.extensions.createOpenAccountPageHook import net.mullvad.mullvadvpn.compose.extensions.dropUnlessResumed -import net.mullvad.mullvadvpn.compose.state.PaymentState +import net.mullvad.mullvadvpn.compose.preview.AccountUiStatePreviewParameterProvider import net.mullvad.mullvadvpn.compose.transitions.SlideInFromBottomTransition import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle import net.mullvad.mullvadvpn.compose.util.SecureScreenWhileInView import net.mullvad.mullvadvpn.compose.util.createCopyToClipboardHandle import net.mullvad.mullvadvpn.compose.util.showSnackbarImmediately -import net.mullvad.mullvadvpn.lib.model.AccountNumber -import net.mullvad.mullvadvpn.lib.payment.model.PaymentProduct -import net.mullvad.mullvadvpn.lib.payment.model.PaymentStatus import net.mullvad.mullvadvpn.lib.payment.model.ProductId -import net.mullvad.mullvadvpn.lib.payment.model.ProductPrice import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.lib.theme.Dimens import net.mullvad.mullvadvpn.util.toExpiryDateString @@ -69,35 +66,12 @@ import org.joda.time.DateTime import org.koin.androidx.compose.koinViewModel @OptIn(ExperimentalMaterial3Api::class) -@Preview +@Preview("PaymentAvailable|Loading|NoPayment|NoProductsFound|Error.Billing") @Composable -private fun PreviewAccountScreen() { - AppTheme { - AccountScreen( - state = - AccountUiState( - deviceName = "Test Name", - accountNumber = AccountNumber("1234123412341234"), - accountExpiry = null, - showSitePayment = true, - billingPaymentState = - PaymentState.PaymentAvailable( - listOf( - PaymentProduct( - ProductId("productId"), - price = ProductPrice("34 SEK"), - status = null, - ), - PaymentProduct( - ProductId("productId_pending"), - price = ProductPrice("34 SEK"), - status = PaymentStatus.PENDING, - ), - ) - ), - ) - ) - } +private fun PreviewAccountScreen( + @PreviewParameter(AccountUiStatePreviewParameterProvider::class) state: AccountUiState +) { + AppTheme { AccountScreen(state = state) } } @OptIn(ExperimentalMaterial3Api::class) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ApiAccessListScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ApiAccessListScreen.kt index 29303f0abf..afbbce2006 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ApiAccessListScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ApiAccessListScreen.kt @@ -44,7 +44,7 @@ import net.mullvad.mullvadvpn.lib.theme.Dimens import net.mullvad.mullvadvpn.viewmodel.ApiAccessListViewModel import org.koin.androidx.compose.koinViewModel -@Preview +@Preview("Default|WithoutCustomApi|WithCustomApi") @Composable private fun PreviewApiAccessList( @PreviewParameter(ApiAccessListUiStatePreviewParameterProvider::class) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ApiAccessMethodDetailsScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ApiAccessMethodDetailsScreen.kt index 3d67c60c07..4d806b3645 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ApiAccessMethodDetailsScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ApiAccessMethodDetailsScreen.kt @@ -66,7 +66,7 @@ import net.mullvad.mullvadvpn.viewmodel.ApiAccessMethodDetailsSideEffect import net.mullvad.mullvadvpn.viewmodel.ApiAccessMethodDetailsViewModel import org.koin.androidx.compose.koinViewModel -@Preview +@Preview("Loading|NonEditable|Editable") @Composable private fun PreviewApiAccessMethodDetailsScreen( @PreviewParameter(ApiAccessMethodDetailsUiStatePreviewParameterProvider::class) 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 b4811f95f0..4f39295d37 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 @@ -46,6 +46,7 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.lifecycle.Lifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -73,6 +74,7 @@ import net.mullvad.mullvadvpn.compose.component.connectioninfo.FeatureIndicators import net.mullvad.mullvadvpn.compose.component.drawVerticalScrollbar import net.mullvad.mullvadvpn.compose.component.notificationbanner.NotificationBanner import net.mullvad.mullvadvpn.compose.extensions.createOpenAccountPageHook +import net.mullvad.mullvadvpn.compose.preview.ConnectUiStatePreviewParameterProvider import net.mullvad.mullvadvpn.compose.state.ConnectUiState import net.mullvad.mullvadvpn.compose.test.CIRCULAR_PROGRESS_INDICATOR import net.mullvad.mullvadvpn.compose.test.CONNECT_BUTTON_TEST_TAG @@ -117,10 +119,11 @@ private val SCREEN_HEIGHT_THRESHOLD = 700.dp private const val SHORT_SCREEN_INDICATOR_BIAS = 0.2f private const val TALL_SCREEN_INDICATOR_BIAS = 0.3f -@Preview +@Preview("Initial|Connected|Disconnected|Connecting|Error.VpnPermissionDenied") @Composable -private fun PreviewConnectScreen() { - val state = ConnectUiState.INITIAL +private fun PreviewAccountScreen( + @PreviewParameter(ConnectUiStatePreviewParameterProvider::class) state: ConnectUiState +) { AppTheme { ConnectScreen(state = state) } } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/CustomListLocationsScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/CustomListLocationsScreen.kt index 1cab54d048..8fcf650bf4 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/CustomListLocationsScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/CustomListLocationsScreen.kt @@ -21,6 +21,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed import com.ramcosta.composedestinations.annotation.Destination @@ -40,6 +41,7 @@ import net.mullvad.mullvadvpn.compose.component.ScaffoldWithSmallTopBar import net.mullvad.mullvadvpn.compose.component.drawVerticalScrollbar import net.mullvad.mullvadvpn.compose.constant.CommonContentKey import net.mullvad.mullvadvpn.compose.constant.ContentType +import net.mullvad.mullvadvpn.compose.preview.CustomListLocationUiStatePreviewParameterProvider import net.mullvad.mullvadvpn.compose.state.CustomListLocationsUiState import net.mullvad.mullvadvpn.compose.test.CIRCULAR_PROGRESS_INDICATOR import net.mullvad.mullvadvpn.compose.test.SAVE_BUTTON_TEST_TAG @@ -48,16 +50,20 @@ import net.mullvad.mullvadvpn.compose.transitions.SlideInFromRightTransition import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle import net.mullvad.mullvadvpn.lib.model.CustomListId import net.mullvad.mullvadvpn.lib.model.RelayItem +import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.lib.theme.Dimens import net.mullvad.mullvadvpn.lib.theme.color.AlphaScrollbar import net.mullvad.mullvadvpn.viewmodel.CustomListLocationsSideEffect import net.mullvad.mullvadvpn.viewmodel.CustomListLocationsViewModel import org.koin.androidx.compose.koinViewModel +@Preview("Content|Empty|Loading") @Composable -@Preview -private fun PreviewCustomListLocationScreen() { - // AppTheme { CustomListLocationsScreen(state = CustomListLocationsUiState.Content.Data()) } +private fun PreviewCustomListLocationScreen( + @PreviewParameter(CustomListLocationUiStatePreviewParameterProvider::class) + state: CustomListLocationsUiState +) { + AppTheme { CustomListLocationsScreen(state = state) } } data class CustomListLocationsNavArgs(val customListId: CustomListId, val newList: Boolean) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/CustomListsScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/CustomListsScreen.kt index 9fc0dff018..65fca696e8 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/CustomListsScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/CustomListsScreen.kt @@ -21,6 +21,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.compose.ui.tooling.preview.PreviewParameter import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed import com.ramcosta.composedestinations.annotation.Destination @@ -41,6 +42,7 @@ import net.mullvad.mullvadvpn.compose.component.ScaffoldWithMediumTopBar import net.mullvad.mullvadvpn.compose.constant.ContentType import net.mullvad.mullvadvpn.compose.extensions.dropUnlessResumed import net.mullvad.mullvadvpn.compose.extensions.itemsWithDivider +import net.mullvad.mullvadvpn.compose.preview.CustomListsUiStatePreviewParameterProvider import net.mullvad.mullvadvpn.compose.state.CustomListsUiState import net.mullvad.mullvadvpn.compose.test.CIRCULAR_PROGRESS_INDICATOR import net.mullvad.mullvadvpn.compose.test.NEW_LIST_BUTTON_TEST_TAG @@ -52,10 +54,12 @@ import net.mullvad.mullvadvpn.lib.theme.Dimens import net.mullvad.mullvadvpn.viewmodel.CustomListsViewModel import org.koin.androidx.compose.koinViewModel -@Preview +@Preview("Content|Empty|Loading") @Composable -private fun PreviewCustomListsScreen() { - AppTheme { CustomListsScreen(CustomListsUiState.Content(), SnackbarHostState()) } +private fun PreviewAccountScreen( + @PreviewParameter(CustomListsUiStatePreviewParameterProvider::class) state: CustomListsUiState +) { + AppTheme { CustomListsScreen(state = state, SnackbarHostState()) } } @Composable 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 56219e62d3..7617a8cb63 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 @@ -68,7 +68,7 @@ import net.mullvad.mullvadvpn.viewmodel.DeviceListViewModel import org.koin.androidx.compose.koinViewModel @Composable -@Preview +@Preview("Normal|TooMany|Empty|Loading|Error") private fun PreviewDeviceListScreenContent( @PreviewParameter(DeviceListUiStatePreviewParameterProvider::class) state: DeviceListUiState ) { 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 8cf8f9b236..39f8f2fd84 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 @@ -15,6 +15,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.constraintlayout.compose.ConstraintLayout @@ -30,6 +31,7 @@ import com.ramcosta.composedestinations.navigation.DestinationsNavigator import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.button.DeviceRevokedLoginButton import net.mullvad.mullvadvpn.compose.component.ScaffoldWithTopBar +import net.mullvad.mullvadvpn.compose.preview.DeviceRevokedUiStatePreviewParameterProvider import net.mullvad.mullvadvpn.compose.state.DeviceRevokedUiState import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle import net.mullvad.mullvadvpn.lib.theme.AppTheme @@ -38,10 +40,13 @@ import net.mullvad.mullvadvpn.viewmodel.DeviceRevokedSideEffect import net.mullvad.mullvadvpn.viewmodel.DeviceRevokedViewModel import org.koin.androidx.compose.koinViewModel -@Preview +@Preview("Secured|Unsecured|Unknown") @Composable -private fun PreviewDeviceRevokedScreen() { - AppTheme { DeviceRevokedScreen(state = DeviceRevokedUiState.SECURED) } +private fun PreviewDeviceRevokedScreen( + @PreviewParameter(DeviceRevokedUiStatePreviewParameterProvider::class) + state: DeviceRevokedUiState +) { + AppTheme { DeviceRevokedScreen(state = state) } } @Destination<RootGraph> diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditApiAccessMethodScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditApiAccessMethodScreen.kt index 6e7f606089..32a4242a91 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditApiAccessMethodScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditApiAccessMethodScreen.kt @@ -72,7 +72,7 @@ import net.mullvad.mullvadvpn.viewmodel.EditApiAccessMethodViewModel import net.mullvad.mullvadvpn.viewmodel.EditApiAccessSideEffect import org.koin.androidx.compose.koinViewModel -@Preview +@Preview("Loading|Default|Shadowsocks|Socks5|Socks5Errors") @Composable private fun PreviewEditApiAccessMethodScreen( @PreviewParameter(EditApiAccessMethodUiStatePreviewParameterProvider::class) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditCustomListScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditCustomListScreen.kt index 0c79b06d17..e73f0885ca 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditCustomListScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/EditCustomListScreen.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed import com.ramcosta.composedestinations.annotation.Destination @@ -34,45 +35,32 @@ import com.ramcosta.composedestinations.result.ResultRecipient import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.cell.TwoRowCell import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData -import net.mullvad.mullvadvpn.compose.communication.Deleted import net.mullvad.mullvadvpn.compose.component.MullvadCircularProgressIndicatorLarge import net.mullvad.mullvadvpn.compose.component.NavigateBackIconButton import net.mullvad.mullvadvpn.compose.component.ScaffoldWithMediumTopBar import net.mullvad.mullvadvpn.compose.component.SpacedColumn import net.mullvad.mullvadvpn.compose.extensions.dropUnlessResumed -import net.mullvad.mullvadvpn.compose.state.EditCustomListState +import net.mullvad.mullvadvpn.compose.preview.EditCustomListUiStatePreviewParameterProvider +import net.mullvad.mullvadvpn.compose.state.EditCustomListUiState import net.mullvad.mullvadvpn.compose.test.CIRCULAR_PROGRESS_INDICATOR import net.mullvad.mullvadvpn.compose.test.DELETE_DROPDOWN_MENU_ITEM_TEST_TAG import net.mullvad.mullvadvpn.compose.test.TOP_BAR_DROPDOWN_BUTTON_TEST_TAG import net.mullvad.mullvadvpn.compose.transitions.SlideInFromRightTransition import net.mullvad.mullvadvpn.lib.model.CustomListId import net.mullvad.mullvadvpn.lib.model.CustomListName -import net.mullvad.mullvadvpn.lib.model.GeoLocationId import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.lib.theme.Dimens import net.mullvad.mullvadvpn.lib.theme.color.menuItemColors import net.mullvad.mullvadvpn.viewmodel.EditCustomListViewModel import org.koin.androidx.compose.koinViewModel -@Preview +@Preview("Content|Loading|NotFound") @Composable -private fun PreviewEditCustomListScreen() { - AppTheme { - EditCustomListScreen( - state = - EditCustomListState.Content( - id = CustomListId("id"), - name = CustomListName.fromString("Custom list"), - locations = - listOf( - GeoLocationId.Hostname( - GeoLocationId.City(GeoLocationId.Country("country"), code = "city"), - "hostname", - ) - ), - ) - ) - } +private fun PreviewEditCustomListScreen( + @PreviewParameter(EditCustomListUiStatePreviewParameterProvider::class) + state: EditCustomListUiState +) { + AppTheme { EditCustomListScreen(state = state) } } data class EditCustomListNavArgs(val customListId: CustomListId) @@ -125,7 +113,7 @@ fun EditCustomList( @Composable fun EditCustomListScreen( - state: EditCustomListState, + state: EditCustomListUiState, onDeleteList: (id: CustomListId, name: CustomListName) -> Unit = { _, _ -> }, onNameClicked: (id: CustomListId, name: CustomListName) -> Unit = { _, _ -> }, onLocationsClicked: (CustomListId) -> Unit = {}, @@ -135,11 +123,11 @@ fun EditCustomListScreen( appBarTitle = stringResource(id = R.string.edit_list), navigationIcon = { NavigateBackIconButton(onNavigateBack = onBackClick) }, actions = { - val content = state as? EditCustomListState.Content + val content = state as? EditCustomListUiState.Content Actions( enabled = content?.name != null, onDeleteList = { - if (content is EditCustomListState.Content) { + if (content is EditCustomListUiState.Content) { onDeleteList(content.id, content.name) } }, @@ -148,12 +136,12 @@ fun EditCustomListScreen( ) { modifier: Modifier -> SpacedColumn(modifier = modifier, alignment = Alignment.Top) { when (state) { - EditCustomListState.Loading -> { + EditCustomListUiState.Loading -> { MullvadCircularProgressIndicatorLarge( modifier = Modifier.testTag(CIRCULAR_PROGRESS_INDICATOR) ) } - EditCustomListState.NotFound -> { + EditCustomListUiState.NotFound -> { Text( text = stringResource(id = R.string.not_found), modifier = Modifier.padding(Dimens.screenVerticalMargin), @@ -161,7 +149,7 @@ fun EditCustomListScreen( color = MaterialTheme.colorScheme.onSurface, ) } - is EditCustomListState.Content -> { + is EditCustomListUiState.Content -> { // Name cell TwoRowCell( titleText = stringResource(id = R.string.list_name), 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 0ce854a29f..e2de301c9c 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 @@ -26,6 +26,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.compose.ui.tooling.preview.PreviewParameter import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed import com.ramcosta.composedestinations.annotation.Destination @@ -39,7 +40,8 @@ import net.mullvad.mullvadvpn.compose.cell.SelectableCell import net.mullvad.mullvadvpn.compose.constant.ContentType import net.mullvad.mullvadvpn.compose.extensions.itemWithDivider import net.mullvad.mullvadvpn.compose.extensions.itemsWithDivider -import net.mullvad.mullvadvpn.compose.state.RelayFilterState +import net.mullvad.mullvadvpn.compose.preview.FilterUiStatePreviewParameterProvider +import net.mullvad.mullvadvpn.compose.state.RelayFilterUiState import net.mullvad.mullvadvpn.compose.transitions.SlideInFromRightTransition import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle import net.mullvad.mullvadvpn.lib.model.Ownership @@ -52,13 +54,9 @@ import org.koin.androidx.compose.koinViewModel @Preview @Composable -private fun PreviewFilterScreen() { - val state = - RelayFilterState( - selectedOwnership = null, - allProviders = listOf(), - selectedProviders = listOf(), - ) +private fun PreviewFilterScreen( + @PreviewParameter(FilterUiStatePreviewParameterProvider::class) state: RelayFilterUiState +) { AppTheme { FilterScreen( state = state, @@ -92,7 +90,7 @@ fun Filter(navigator: DestinationsNavigator) { @Composable fun FilterScreen( - state: RelayFilterState, + state: RelayFilterUiState, onBackClick: () -> Unit = {}, onApplyClick: () -> Unit = {}, onSelectedOwnership: (ownership: Ownership?) -> Unit = {}, @@ -163,7 +161,7 @@ private fun LazyItemScope.OwnershipHeader(expanded: Boolean, onToggleExpanded: ( @Composable private fun LazyItemScope.AnyOwnership( - state: RelayFilterState, + state: RelayFilterUiState, onSelectedOwnership: (ownership: Ownership?) -> Unit, ) { SelectableCell( @@ -177,7 +175,7 @@ private fun LazyItemScope.AnyOwnership( @Composable private fun LazyItemScope.Ownership( ownership: Ownership, - state: RelayFilterState, + state: RelayFilterUiState, onSelectedOwnership: (ownership: Ownership?) -> Unit, ) { SelectableCell( @@ -202,7 +200,7 @@ private fun LazyItemScope.ProvidersHeader(expanded: Boolean, onToggleExpanded: ( @Composable private fun LazyItemScope.AllProviders( - state: RelayFilterState, + state: RelayFilterUiState, onAllProviderCheckChange: (isChecked: Boolean) -> Unit, ) { CheckboxCell( @@ -216,7 +214,7 @@ private fun LazyItemScope.AllProviders( @Composable private fun LazyItemScope.Provider( provider: Provider, - state: RelayFilterState, + state: RelayFilterUiState, onSelectedProvider: (checked: Boolean, provider: Provider) -> Unit, ) { CheckboxCell( 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 16bfb7ab95..d29ed293b7 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 @@ -84,7 +84,7 @@ import net.mullvad.mullvadvpn.viewmodel.LoginUiSideEffect import net.mullvad.mullvadvpn.viewmodel.LoginViewModel import org.koin.androidx.compose.koinViewModel -@Preview +@Preview("Default|Loading.LogginIn|Loading.CreatingAccount|LoginError|Success") @Composable private fun PreviewLoginScreen( @PreviewParameter(LoginUiStatePreviewParameterProvider::class) state: LoginUiState 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 d6ec6c3b77..10fc9cd3af 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 @@ -64,7 +64,7 @@ import net.mullvad.mullvadvpn.lib.theme.color.AlphaScrollbar import net.mullvad.mullvadvpn.viewmodel.OutOfTimeViewModel import org.koin.androidx.compose.koinViewModel -@Preview +@Preview("Disconnected|Connecting|Error") @Composable private fun PreviewOutOfTimeScreen( @PreviewParameter(OutOfTimeScreenPreviewParameterProvider::class) state: OutOfTimeUiState 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 db8d3f56c9..2e5688da81 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 @@ -66,7 +66,7 @@ import net.mullvad.mullvadvpn.viewmodel.ReportProblemViewModel import net.mullvad.mullvadvpn.viewmodel.SendingReportUiState import org.koin.androidx.compose.koinViewModel -@Preview +@Preview("Default|Sending|Success|Error") @Composable private fun PreviewReportProblemScreen( @PreviewParameter(ReportProblemUiStatePreviewParameterProvider::class) 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 013ed1d029..bc3918bddb 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 @@ -45,6 +45,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.compose.ui.tooling.preview.PreviewParameter import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed import com.ramcosta.composedestinations.annotation.Destination @@ -77,6 +78,7 @@ import net.mullvad.mullvadvpn.compose.component.MullvadSnackbar import net.mullvad.mullvadvpn.compose.component.drawVerticalScrollbar import net.mullvad.mullvadvpn.compose.constant.ContentType import net.mullvad.mullvadvpn.compose.extensions.dropUnlessResumed +import net.mullvad.mullvadvpn.compose.preview.SelectLocationsUiStatePreviewParameterProvider import net.mullvad.mullvadvpn.compose.screen.BottomSheetState.ShowCustomListsBottomSheet import net.mullvad.mullvadvpn.compose.screen.BottomSheetState.ShowCustomListsEntryBottomSheet import net.mullvad.mullvadvpn.compose.screen.BottomSheetState.ShowEditCustomListBottomSheet @@ -107,16 +109,12 @@ import net.mullvad.mullvadvpn.viewmodel.SelectLocationSideEffect import net.mullvad.mullvadvpn.viewmodel.SelectLocationViewModel import org.koin.androidx.compose.koinViewModel -@Preview +@Preview("Content|Loading") @Composable -private fun PreviewSelectLocationScreen() { - val state = - SelectLocationUiState.Content( - searchTerm = "", - emptyList(), - relayListItems = emptyList(), - customLists = emptyList(), - ) +private fun PreviewSelectLocationScreen( + @PreviewParameter(SelectLocationsUiStatePreviewParameterProvider::class) + state: SelectLocationUiState +) { AppTheme { SelectLocationScreen(state = state) } } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ServerIpOverridesScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ServerIpOverridesScreen.kt index 88d72072ae..de257f319f 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ServerIpOverridesScreen.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ServerIpOverridesScreen.kt @@ -39,6 +39,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.compose.ui.tooling.preview.PreviewParameter import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed import com.ramcosta.composedestinations.annotation.Destination @@ -59,6 +60,7 @@ import net.mullvad.mullvadvpn.compose.component.MullvadModalBottomSheet import net.mullvad.mullvadvpn.compose.component.MullvadSnackbar import net.mullvad.mullvadvpn.compose.component.NavigateBackIconButton import net.mullvad.mullvadvpn.compose.component.ScaffoldWithMediumTopBar +import net.mullvad.mullvadvpn.compose.preview.ServerIpOverridesUiStatePreviewParameterProvider import net.mullvad.mullvadvpn.compose.test.SERVER_IP_OVERRIDES_IMPORT_BY_FILE_TEST_TAG import net.mullvad.mullvadvpn.compose.test.SERVER_IP_OVERRIDES_IMPORT_BY_TEXT_TEST_TAG import net.mullvad.mullvadvpn.compose.test.SERVER_IP_OVERRIDE_IMPORT_TEST_TAG @@ -74,16 +76,19 @@ import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.lib.theme.Dimens import net.mullvad.mullvadvpn.lib.theme.color.AlphaDisabled import net.mullvad.mullvadvpn.viewmodel.ServerIpOverridesUiSideEffect +import net.mullvad.mullvadvpn.viewmodel.ServerIpOverridesUiState import net.mullvad.mullvadvpn.viewmodel.ServerIpOverridesViewModel -import net.mullvad.mullvadvpn.viewmodel.ServerIpOverridesViewState import org.koin.androidx.compose.koinViewModel -@Preview +@Preview("Loaded.Active|Loaded.Inactive|Loading") @Composable -private fun PreviewServerIpOverridesScreen() { +private fun PreviewServerIpOverridesScreen( + @PreviewParameter(ServerIpOverridesUiStatePreviewParameterProvider::class) + state: ServerIpOverridesUiState +) { AppTheme { ServerIpOverridesScreen( - ServerIpOverridesViewState.Loaded(false), + state = state, onBackClick = {}, onInfoClick = {}, onResetOverridesClick = {}, @@ -158,7 +163,7 @@ fun ServerIpOverrides( @OptIn(ExperimentalMaterial3Api::class) @Composable fun ServerIpOverridesScreen( - state: ServerIpOverridesViewState, + state: ServerIpOverridesUiState, onBackClick: () -> Unit, onInfoClick: () -> Unit, onResetOverridesClick: () -> Unit, 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 9023a3ef49..df18ba86cc 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 @@ -18,6 +18,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.compose.ui.tooling.preview.PreviewParameter import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed import com.ramcosta.composedestinations.annotation.Destination @@ -34,6 +35,7 @@ import net.mullvad.mullvadvpn.compose.cell.NavigationComposeCell import net.mullvad.mullvadvpn.compose.component.NavigateBackDownIconButton import net.mullvad.mullvadvpn.compose.component.ScaffoldWithMediumTopBar import net.mullvad.mullvadvpn.compose.extensions.itemWithDivider +import net.mullvad.mullvadvpn.compose.preview.SettingsUiStatePreviewParameterProvider import net.mullvad.mullvadvpn.compose.state.SettingsUiState import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_TEST_TAG import net.mullvad.mullvadvpn.compose.transitions.SettingsTransition @@ -45,20 +47,12 @@ import net.mullvad.mullvadvpn.viewmodel.SettingsViewModel import org.koin.androidx.compose.koinViewModel @OptIn(ExperimentalMaterial3Api::class) -@Preview +@Preview("Supported|Unsupported") @Composable -private fun PreviewSettings() { - AppTheme { - SettingsScreen( - state = - SettingsUiState( - appVersion = "2222.22", - isLoggedIn = true, - isSupportedVersion = true, - isPlayBuild = false, - ) - ) - } +private fun PreviewSettingsScreen( + @PreviewParameter(SettingsUiStatePreviewParameterProvider::class) state: SettingsUiState +) { + AppTheme { SettingsScreen(state = state) } } @OptIn(ExperimentalMaterial3Api::class) 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 cc8a616c26..660beaae94 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 @@ -22,6 +22,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.compose.ui.tooling.preview.PreviewParameter import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed import com.ramcosta.composedestinations.annotation.Destination @@ -42,6 +43,7 @@ import net.mullvad.mullvadvpn.compose.constant.ContentType import net.mullvad.mullvadvpn.compose.constant.SplitTunnelingContentKey import net.mullvad.mullvadvpn.compose.extensions.itemWithDivider import net.mullvad.mullvadvpn.compose.extensions.itemsIndexedWithDivider +import net.mullvad.mullvadvpn.compose.preview.SplitTunnelingUiStatePreviewParameterProvider import net.mullvad.mullvadvpn.compose.state.SplitTunnelingUiState import net.mullvad.mullvadvpn.compose.transitions.SlideInFromRightTransition import net.mullvad.mullvadvpn.lib.theme.AppTheme @@ -52,39 +54,13 @@ import net.mullvad.mullvadvpn.util.getApplicationIconBitmapOrNull import net.mullvad.mullvadvpn.viewmodel.SplitTunnelingViewModel import org.koin.androidx.compose.koinViewModel -@Preview +@Preview("ShowAppList|Loading") @Composable -private fun PreviewSplitTunnelingScreen() { - AppTheme { - SplitTunnelingScreen( - state = - SplitTunnelingUiState.ShowAppList( - enabled = true, - excludedApps = - listOf( - AppData( - packageName = "my.package.a", - name = "TitleA", - iconRes = R.drawable.icon_alert, - ), - AppData( - packageName = "my.package.b", - name = "TitleB", - iconRes = R.drawable.icon_chevron, - ), - ), - includedApps = - listOf( - AppData( - packageName = "my.package.c", - name = "TitleC", - iconRes = R.drawable.icon_alert, - ) - ), - showSystemApps = true, - ) - ) - } +private fun PreviewSplitTunnelingScreen( + @PreviewParameter(SplitTunnelingUiStatePreviewParameterProvider::class) + state: SplitTunnelingUiState +) { + AppTheme { SplitTunnelingScreen(state = state) } } @Destination<RootGraph>(style = SlideInFromRightTransition::class) 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 0018d3e2aa..24825aec04 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 @@ -33,6 +33,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.compose.ui.tooling.preview.PreviewParameter import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed import com.ramcosta.composedestinations.annotation.Destination @@ -45,6 +46,7 @@ import net.mullvad.mullvadvpn.compose.component.MullvadMediumTopBar import net.mullvad.mullvadvpn.compose.component.MullvadSnackbar import net.mullvad.mullvadvpn.compose.component.NavigateBackIconButton import net.mullvad.mullvadvpn.compose.component.drawVerticalScrollbar +import net.mullvad.mullvadvpn.compose.preview.ViewLogsUiStatePreviewParameterProvider import net.mullvad.mullvadvpn.compose.transitions.SlideInFromRightTransition import net.mullvad.mullvadvpn.compose.util.CopyToClipboardHandle import net.mullvad.mullvadvpn.compose.util.createCopyToClipboardHandle @@ -56,16 +58,12 @@ import net.mullvad.mullvadvpn.viewmodel.ViewLogsUiState import net.mullvad.mullvadvpn.viewmodel.ViewLogsViewModel import org.koin.androidx.compose.koinViewModel -@Preview +@Preview("Content|Loading") @Composable -private fun PreviewViewLogsScreen() { - AppTheme { ViewLogsScreen(state = ViewLogsUiState(listOf("Lorem ipsum"))) } -} - -@Preview -@Composable -private fun PreviewViewLogsLoadingScreen() { - AppTheme { ViewLogsScreen(state = ViewLogsUiState()) } +private fun PreviewViewLogsScreen( + @PreviewParameter(ViewLogsUiStatePreviewParameterProvider::class) state: ViewLogsUiState +) { + AppTheme { ViewLogsScreen(state = state) } } @Destination<RootGraph>(style = SlideInFromRightTransition::class) 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 d5416ad0e7..75d12bd717 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 @@ -25,6 +25,7 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.core.text.HtmlCompat import androidx.lifecycle.Lifecycle @@ -78,6 +79,7 @@ import net.mullvad.mullvadvpn.compose.extensions.dropUnlessResumed import net.mullvad.mullvadvpn.compose.extensions.itemWithDivider import net.mullvad.mullvadvpn.compose.extensions.itemsIndexedWithDivider import net.mullvad.mullvadvpn.compose.extensions.toAnnotatedString +import net.mullvad.mullvadvpn.compose.preview.VpnSettingsUiStatePreviewParameterProvider import net.mullvad.mullvadvpn.compose.state.VpnSettingsUiState import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_LAST_ITEM_TEST_TAG import net.mullvad.mullvadvpn.compose.test.LAZY_LIST_QUANTUM_ITEM_OFF_TEST_TAG @@ -100,23 +102,18 @@ import net.mullvad.mullvadvpn.lib.model.PortRange import net.mullvad.mullvadvpn.lib.model.QuantumResistantState import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.lib.theme.Dimens -import net.mullvad.mullvadvpn.viewmodel.CustomDnsItem import net.mullvad.mullvadvpn.viewmodel.VpnSettingsSideEffect import net.mullvad.mullvadvpn.viewmodel.VpnSettingsViewModel import org.koin.androidx.compose.koinViewModel -@Preview +@Preview("Default|NonDefault") @Composable -private fun PreviewVpnSettings() { +private fun PreviewVpnSettings( + @PreviewParameter(VpnSettingsUiStatePreviewParameterProvider::class) state: VpnSettingsUiState +) { AppTheme { VpnSettingsScreen( - state = - VpnSettingsUiState.createDefault( - isAutoConnectEnabled = true, - mtu = Mtu(1337), - isCustomDnsEnabled = true, - customDnsItems = listOf(CustomDnsItem("0.0.0.0", false)), - ), + state = state, snackbarHostState = SnackbarHostState(), onToggleBlockTrackers = {}, onToggleBlockAds = {}, 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 c67ff28765..b5f7ae9752 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 @@ -27,6 +27,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.compose.ui.tooling.preview.PreviewParameter import androidx.lifecycle.Lifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed @@ -53,6 +54,7 @@ import net.mullvad.mullvadvpn.compose.component.ScaffoldWithTopBar import net.mullvad.mullvadvpn.compose.component.drawVerticalScrollbar import net.mullvad.mullvadvpn.compose.extensions.createOpenAccountPageHook import net.mullvad.mullvadvpn.compose.extensions.dropUnlessResumed +import net.mullvad.mullvadvpn.compose.preview.WelcomeScreenUiStatePreviewParameterProvider import net.mullvad.mullvadvpn.compose.state.PaymentState import net.mullvad.mullvadvpn.compose.state.WelcomeUiState import net.mullvad.mullvadvpn.compose.transitions.HomeTransition @@ -60,10 +62,7 @@ import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle import net.mullvad.mullvadvpn.compose.util.createCopyToClipboardHandle import net.mullvad.mullvadvpn.compose.util.showSnackbarImmediately import net.mullvad.mullvadvpn.lib.common.util.groupWithSpaces -import net.mullvad.mullvadvpn.lib.model.AccountNumber -import net.mullvad.mullvadvpn.lib.payment.model.PaymentProduct import net.mullvad.mullvadvpn.lib.payment.model.ProductId -import net.mullvad.mullvadvpn.lib.payment.model.ProductPrice import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.lib.theme.Dimens import net.mullvad.mullvadvpn.lib.theme.color.AlphaScrollbar @@ -72,21 +71,12 @@ import org.koin.androidx.compose.koinViewModel @Preview @Composable -private fun PreviewWelcomeScreen() { +private fun PreviewWelcomeScreen( + @PreviewParameter(WelcomeScreenUiStatePreviewParameterProvider::class) state: WelcomeUiState +) { AppTheme { WelcomeScreen( - state = - WelcomeUiState( - accountNumber = AccountNumber("4444555566667777"), - deviceName = "Happy Mole", - billingPaymentState = - PaymentState.PaymentAvailable( - products = - listOf( - PaymentProduct(ProductId("product"), ProductPrice("$44"), null) - ) - ), - ), + state = state, onSitePaymentClick = {}, onRedeemVoucherClick = {}, onSettingsClick = {}, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/EditCustomListState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/EditCustomListUiState.kt index 27a3fe881e..6af59be686 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/EditCustomListState.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/EditCustomListUiState.kt @@ -4,14 +4,14 @@ import net.mullvad.mullvadvpn.lib.model.CustomListId import net.mullvad.mullvadvpn.lib.model.CustomListName import net.mullvad.mullvadvpn.lib.model.GeoLocationId -sealed interface EditCustomListState { - data object Loading : EditCustomListState +sealed interface EditCustomListUiState { + data object Loading : EditCustomListUiState - data object NotFound : EditCustomListState + data object NotFound : EditCustomListUiState data class Content( val id: CustomListId, val name: CustomListName, val locations: List<GeoLocationId>, - ) : EditCustomListState + ) : EditCustomListUiState } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/RelayFilterState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/RelayFilterUiState.kt index c9393f67e3..ffc26b0bb7 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/RelayFilterState.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/RelayFilterUiState.kt @@ -3,7 +3,7 @@ package net.mullvad.mullvadvpn.compose.state import net.mullvad.mullvadvpn.lib.model.Ownership import net.mullvad.mullvadvpn.lib.model.Provider -data class RelayFilterState( +data class RelayFilterUiState( val selectedOwnership: Ownership? = null, val allProviders: List<Provider> = emptyList(), val selectedProviders: List<Provider> = allProviders, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListViewModel.kt index aa2520c7a1..c736781fcc 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListViewModel.kt @@ -7,7 +7,7 @@ import com.ramcosta.composedestinations.generated.destinations.EditCustomListDes import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn -import net.mullvad.mullvadvpn.compose.state.EditCustomListState +import net.mullvad.mullvadvpn.compose.state.EditCustomListUiState import net.mullvad.mullvadvpn.lib.model.CustomListId import net.mullvad.mullvadvpn.repository.CustomListsRepository @@ -24,12 +24,16 @@ class EditCustomListViewModel( customLists ?.find { it.id == customListId } ?.let { - EditCustomListState.Content( + EditCustomListUiState.Content( id = it.id, name = it.name, locations = it.locations, ) - } ?: EditCustomListState.NotFound + } ?: EditCustomListUiState.NotFound } - .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), EditCustomListState.Loading) + .stateIn( + viewModelScope, + SharingStarted.WhileSubscribed(), + EditCustomListUiState.Loading, + ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/FilterViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/FilterViewModel.kt index 4eaaf21c0f..548d6b70a7 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/FilterViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/FilterViewModel.kt @@ -11,7 +11,7 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import net.mullvad.mullvadvpn.compose.state.RelayFilterState +import net.mullvad.mullvadvpn.compose.state.RelayFilterUiState import net.mullvad.mullvadvpn.compose.state.toConstraintProviders import net.mullvad.mullvadvpn.compose.state.toOwnershipConstraint import net.mullvad.mullvadvpn.compose.state.toSelectedProviders @@ -45,12 +45,12 @@ class FilterViewModel( } } - val uiState: StateFlow<RelayFilterState> = + val uiState: StateFlow<RelayFilterUiState> = combine(selectedOwnership, availableProvidersUseCase(), selectedProviders) { selectedOwnership, allProviders, selectedProviders -> - RelayFilterState( + RelayFilterUiState( selectedOwnership = selectedOwnership, allProviders = allProviders, selectedProviders = selectedProviders, @@ -59,7 +59,7 @@ class FilterViewModel( .stateIn( viewModelScope, SharingStarted.WhileSubscribed(), - RelayFilterState( + RelayFilterUiState( allProviders = emptyList(), selectedOwnership = null, selectedProviders = emptyList(), diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ServerIpOverridesViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ServerIpOverridesViewModel.kt index 99440530a5..bf8999493c 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ServerIpOverridesViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ServerIpOverridesViewModel.kt @@ -25,14 +25,14 @@ class ServerIpOverridesViewModel( private val _uiSideEffect = Channel<ServerIpOverridesUiSideEffect>() val uiSideEffect = merge(_uiSideEffect.receiveAsFlow()) - val uiState: StateFlow<ServerIpOverridesViewState> = + val uiState: StateFlow<ServerIpOverridesUiState> = relayOverridesRepository.relayOverrides .filterNotNull() - .map { ServerIpOverridesViewState.Loaded(overridesActive = it.isNotEmpty()) } + .map { ServerIpOverridesUiState.Loaded(overridesActive = it.isNotEmpty()) } .stateIn( viewModelScope, SharingStarted.WhileSubscribed(), - ServerIpOverridesViewState.Loading, + ServerIpOverridesUiState.Loading, ) fun importFile(uri: Uri) = @@ -66,11 +66,11 @@ sealed interface ServerIpOverridesUiSideEffect { data class ImportResult(val error: SettingsPatchError?) : ServerIpOverridesUiSideEffect } -sealed interface ServerIpOverridesViewState { +sealed interface ServerIpOverridesUiState { val overridesActive: Boolean? get() = (this as? Loaded)?.overridesActive - data object Loading : ServerIpOverridesViewState + data object Loading : ServerIpOverridesUiState - data class Loaded(override val overridesActive: Boolean) : ServerIpOverridesViewState + data class Loaded(override val overridesActive: Boolean) : ServerIpOverridesUiState } diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListViewModelTest.kt index 5d0ecff5df..34eb77319b 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/EditCustomListViewModelTest.kt @@ -8,7 +8,7 @@ import kotlin.test.assertIs import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runTest import net.mullvad.mullvadvpn.compose.dialog.EditCustomListNameNavArgs -import net.mullvad.mullvadvpn.compose.state.EditCustomListState +import net.mullvad.mullvadvpn.compose.state.EditCustomListUiState import net.mullvad.mullvadvpn.lib.common.test.TestCoroutineRule import net.mullvad.mullvadvpn.lib.model.CustomList import net.mullvad.mullvadvpn.lib.model.CustomListId @@ -34,7 +34,7 @@ class EditCustomListViewModelTest { // Act, Assert viewModel.uiState.test { val item = awaitItem() - assertIs<EditCustomListState.NotFound>(item) + assertIs<EditCustomListUiState.NotFound>(item) } } @@ -50,7 +50,7 @@ class EditCustomListViewModelTest { // Act, Assert viewModel.uiState.test { val item = awaitItem() - assertIs<EditCustomListState.Content>(item) + assertIs<EditCustomListUiState.Content>(item) assertEquals(item.id, customList.id) assertEquals(item.name, customList.name) assertEquals(item.locations, customList.locations) diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ServerIpOverridesViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ServerIpOverridesViewModelTest.kt index 6203d54b63..484a24fc29 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ServerIpOverridesViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/ServerIpOverridesViewModelTest.kt @@ -57,15 +57,15 @@ class ServerIpOverridesViewModelTest { @Test fun `ensure state is loading by default`() = runTest { - viewModel.uiState.test { assertEquals(ServerIpOverridesViewState.Loading, awaitItem()) } + viewModel.uiState.test { assertEquals(ServerIpOverridesUiState.Loading, awaitItem()) } } @Test fun `when server ip overrides are empty ui state overrides should be inactive`() = runTest { viewModel.uiState.test { - assertEquals(ServerIpOverridesViewState.Loading, awaitItem()) + assertEquals(ServerIpOverridesUiState.Loading, awaitItem()) relayOverrides.emit(emptyList()) - assertEquals(ServerIpOverridesViewState.Loaded(false), awaitItem()) + assertEquals(ServerIpOverridesUiState.Loaded(false), awaitItem()) } } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/Port.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/Port.kt index 0f8bf37332..878760c43b 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/Port.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/Port.kt @@ -12,6 +12,8 @@ value class Port(val value: Int) : Parcelable { override fun toString(): String = value.toString() + operator fun rangeTo(other: Port): PortRange = PortRange(value..other.value) + companion object { fun fromString(value: String): Either<ParsePortError, Port> = either { val number = value.toIntOrNull() ?: raise(ParsePortError.NotANumber(value)) |
