diff options
| author | David Göransson <david.goransson@mullvad.net> | 2024-03-11 13:26:33 +0100 |
|---|---|---|
| committer | David Göransson <david.goransson@mullvad.net> | 2024-03-11 15:56:57 +0100 |
| commit | c6b1744b673644eaec26c93da9beadec4344a575 (patch) | |
| tree | 92c296ac643d3e5061434138279bfa1ddd208c31 /android/app/src | |
| parent | 5560072b52fd1fc883ce3864328c5751ac778528 (diff) | |
| download | mullvadvpn-c6b1744b673644eaec26c93da9beadec4344a575.tar.xz mullvadvpn-c6b1744b673644eaec26c93da9beadec4344a575.zip | |
Revert navigation logic on Welcome to handle bad clocks better
Diffstat (limited to 'android/app/src')
3 files changed, 22 insertions, 29 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt index 942ad8aa39..f36e579a52 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt @@ -154,7 +154,7 @@ val uiModule = module { viewModel { SplashViewModel(get(), get(), get()) } viewModel { VoucherDialogViewModel(get(), get()) } viewModel { VpnSettingsViewModel(get(), get(), get(), get(), get()) } - viewModel { WelcomeViewModel(get(), get(), get(), get(), get(), isPlayBuild = IS_PLAY_BUILD) } + viewModel { WelcomeViewModel(get(), get(), get(), get(), isPlayBuild = IS_PLAY_BUILD) } viewModel { ReportProblemViewModel(get(), get()) } viewModel { ViewLogsViewModel(get()) } viewModel { OutOfTimeViewModel(get(), get(), get(), get(), get(), isPlayBuild = IS_PLAY_BUILD) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModel.kt index 66b41a17c7..0f6b23a306 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModel.kt @@ -14,7 +14,9 @@ import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @@ -27,7 +29,6 @@ import net.mullvad.mullvadvpn.ui.serviceconnection.ConnectionProxy import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionState import net.mullvad.mullvadvpn.ui.serviceconnection.authTokenCache -import net.mullvad.mullvadvpn.usecase.OutOfTimeUseCase import net.mullvad.mullvadvpn.usecase.PaymentUseCase import net.mullvad.mullvadvpn.util.UNKNOWN_STATE_DEBOUNCE_DELAY_MILLISECONDS import net.mullvad.mullvadvpn.util.addDebounceForUnknownState @@ -40,12 +41,11 @@ class WelcomeViewModel( private val deviceRepository: DeviceRepository, private val serviceConnectionManager: ServiceConnectionManager, private val paymentUseCase: PaymentUseCase, - private val outOfTimeUseCase: OutOfTimeUseCase, private val pollAccountExpiry: Boolean = true, private val isPlayBuild: Boolean ) : ViewModel() { private val _uiSideEffect = Channel<UiSideEffect>() - val uiSideEffect = merge(_uiSideEffect.receiveAsFlow(), notOutOfTimeEffect()) + val uiSideEffect = merge(_uiSideEffect.receiveAsFlow(), hasAddedTimeEffect()) val uiState = serviceConnectionManager.connectionState @@ -86,13 +86,12 @@ class WelcomeViewModel( fetchPaymentAvailability() } - private fun notOutOfTimeEffect() = - outOfTimeUseCase.isOutOfTime - .filter { it == false } - .map { - paymentUseCase.resetPurchaseResult() - UiSideEffect.OpenConnectScreen - } + private fun hasAddedTimeEffect() = + accountRepository.accountExpiryState + .mapNotNull { it.date() } + .filter { it.minusHours(MIN_HOURS_PAST_ACCOUNT_EXPIRY).isAfterNow } + .onEach { paymentUseCase.resetPurchaseResult() } + .map { UiSideEffect.OpenConnectScreen } private fun ConnectionProxy.tunnelUiStateFlow(): Flow<TunnelState> = callbackFlowFromNotifier(this.onUiStateChange) @@ -144,4 +143,8 @@ class WelcomeViewModel( data object OpenConnectScreen : UiSideEffect } + + companion object { + private const val MIN_HOURS_PAST_ACCOUNT_EXPIRY = 20 + } } diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt index c52dd3a103..91554193bc 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt @@ -32,11 +32,9 @@ import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionContainer import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionState import net.mullvad.mullvadvpn.ui.serviceconnection.authTokenCache -import net.mullvad.mullvadvpn.usecase.OutOfTimeUseCase import net.mullvad.mullvadvpn.usecase.PaymentUseCase import net.mullvad.talpid.util.EventNotifier import org.joda.time.DateTime -import org.joda.time.ReadableInstant import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -51,7 +49,6 @@ class WelcomeViewModelTest { private val accountExpiryStateFlow = MutableStateFlow<AccountExpiry>(AccountExpiry.Missing) private val purchaseResultFlow = MutableStateFlow<PurchaseResult?>(null) private val paymentAvailabilityFlow = MutableStateFlow<PaymentAvailability?>(null) - private val outOfTimeFlow = MutableStateFlow(true) // Service connections private val mockServiceConnectionContainer: ServiceConnectionContainer = mockk() @@ -64,7 +61,6 @@ class WelcomeViewModelTest { private val mockDeviceRepository: DeviceRepository = mockk() private val mockServiceConnectionManager: ServiceConnectionManager = mockk() private val mockPaymentUseCase: PaymentUseCase = mockk(relaxed = true) - private val mockOutOfTimeUseCase: OutOfTimeUseCase = mockk(relaxed = true) private lateinit var viewModel: WelcomeViewModel @@ -87,15 +83,12 @@ class WelcomeViewModelTest { coEvery { mockPaymentUseCase.paymentAvailability } returns paymentAvailabilityFlow - coEvery { mockOutOfTimeUseCase.isOutOfTime } returns outOfTimeFlow - viewModel = WelcomeViewModel( accountRepository = mockAccountRepository, deviceRepository = mockDeviceRepository, serviceConnectionManager = mockServiceConnectionManager, paymentUseCase = mockPaymentUseCase, - outOfTimeUseCase = mockOutOfTimeUseCase, pollAccountExpiry = false, isPlayBuild = false ) @@ -164,19 +157,16 @@ class WelcomeViewModelTest { } @Test - fun `when OutOfTimeUseCase return false uiSideEffect should emit OpenConnectScreen`() = - runTest { - // Arrange - val mockExpiryDate: DateTime = mockk() - every { mockExpiryDate.isAfter(any<ReadableInstant>()) } returns true + fun `when user has added time then uiSideEffect should emit OpenConnectScreen`() = runTest { + // Arrange + accountExpiryStateFlow.emit(AccountExpiry.Available(DateTime().plusDays(1))) - // Act, Assert - viewModel.uiSideEffect.test { - outOfTimeFlow.value = false - val action = awaitItem() - assertIs<WelcomeViewModel.UiSideEffect.OpenConnectScreen>(action) - } + // Act, Assert + viewModel.uiSideEffect.test { + val action = awaitItem() + assertIs<WelcomeViewModel.UiSideEffect.OpenConnectScreen>(action) } + } @Test fun `when paymentAvailability emits ProductsUnavailable uiState should include state NoPayment`() = |
