Skip to content

Commit 252a810

Browse files
committed
Revert navigation logic on Welcome to handle bad clocks better
1 parent 76f8d36 commit 252a810

File tree

3 files changed

+20
-25
lines changed

3 files changed

+20
-25
lines changed

android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ val uiModule = module {
154154
viewModel { SplashViewModel(get(), get(), get()) }
155155
viewModel { VoucherDialogViewModel(get(), get()) }
156156
viewModel { VpnSettingsViewModel(get(), get(), get(), get(), get()) }
157-
viewModel { WelcomeViewModel(get(), get(), get(), get(), get(), isPlayBuild = IS_PLAY_BUILD) }
157+
viewModel { WelcomeViewModel(get(), get(), get(), get(), isPlayBuild = IS_PLAY_BUILD) }
158158
viewModel { ReportProblemViewModel(get(), get()) }
159159
viewModel { ViewLogsViewModel(get()) }
160160
viewModel { OutOfTimeViewModel(get(), get(), get(), get(), get(), isPlayBuild = IS_PLAY_BUILD) }

android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModel.kt

+11-6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import kotlinx.coroutines.flow.combine
1111
import kotlinx.coroutines.flow.debounce
1212
import kotlinx.coroutines.flow.emptyFlow
1313
import kotlinx.coroutines.flow.filter
14+
import kotlinx.coroutines.flow.filterNotNull
1415
import kotlinx.coroutines.flow.flatMapLatest
1516
import kotlinx.coroutines.flow.flowOf
1617
import kotlinx.coroutines.flow.map
@@ -27,7 +28,6 @@ import net.mullvad.mullvadvpn.ui.serviceconnection.ConnectionProxy
2728
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager
2829
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionState
2930
import net.mullvad.mullvadvpn.ui.serviceconnection.authTokenCache
30-
import net.mullvad.mullvadvpn.usecase.OutOfTimeUseCase
3131
import net.mullvad.mullvadvpn.usecase.PaymentUseCase
3232
import net.mullvad.mullvadvpn.util.UNKNOWN_STATE_DEBOUNCE_DELAY_MILLISECONDS
3333
import net.mullvad.mullvadvpn.util.addDebounceForUnknownState
@@ -40,12 +40,11 @@ class WelcomeViewModel(
4040
private val deviceRepository: DeviceRepository,
4141
private val serviceConnectionManager: ServiceConnectionManager,
4242
private val paymentUseCase: PaymentUseCase,
43-
private val outOfTimeUseCase: OutOfTimeUseCase,
4443
private val pollAccountExpiry: Boolean = true,
4544
private val isPlayBuild: Boolean
4645
) : ViewModel() {
4746
private val _uiSideEffect = Channel<UiSideEffect>()
48-
val uiSideEffect = merge(_uiSideEffect.receiveAsFlow(), notOutOfTimeEffect())
47+
val uiSideEffect = merge(_uiSideEffect.receiveAsFlow(), hasAddedTime())
4948

5049
val uiState =
5150
serviceConnectionManager.connectionState
@@ -86,9 +85,11 @@ class WelcomeViewModel(
8685
fetchPaymentAvailability()
8786
}
8887

89-
private fun notOutOfTimeEffect() =
90-
outOfTimeUseCase.isOutOfTime
91-
.filter { it == false }
88+
private fun hasAddedTime() =
89+
accountRepository.accountExpiryState
90+
.map { it.date() }
91+
.filterNotNull()
92+
.filter { it.minusHours(MIN_TIME_PAST_ACCOUNT_EXPIRY).isAfterNow }
9293
.map {
9394
paymentUseCase.resetPurchaseResult()
9495
UiSideEffect.OpenConnectScreen
@@ -144,4 +145,8 @@ class WelcomeViewModel(
144145

145146
data object OpenConnectScreen : UiSideEffect
146147
}
148+
149+
companion object {
150+
private const val MIN_TIME_PAST_ACCOUNT_EXPIRY = 20
151+
}
147152
}

android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/WelcomeViewModelTest.kt

+8-18
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,9 @@ import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionContainer
3232
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager
3333
import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionState
3434
import net.mullvad.mullvadvpn.ui.serviceconnection.authTokenCache
35-
import net.mullvad.mullvadvpn.usecase.OutOfTimeUseCase
3635
import net.mullvad.mullvadvpn.usecase.PaymentUseCase
3736
import net.mullvad.talpid.util.EventNotifier
3837
import org.joda.time.DateTime
39-
import org.joda.time.ReadableInstant
4038
import org.junit.jupiter.api.AfterEach
4139
import org.junit.jupiter.api.BeforeEach
4240
import org.junit.jupiter.api.Test
@@ -51,7 +49,6 @@ class WelcomeViewModelTest {
5149
private val accountExpiryStateFlow = MutableStateFlow<AccountExpiry>(AccountExpiry.Missing)
5250
private val purchaseResultFlow = MutableStateFlow<PurchaseResult?>(null)
5351
private val paymentAvailabilityFlow = MutableStateFlow<PaymentAvailability?>(null)
54-
private val outOfTimeFlow = MutableStateFlow(true)
5552

5653
// Service connections
5754
private val mockServiceConnectionContainer: ServiceConnectionContainer = mockk()
@@ -64,7 +61,6 @@ class WelcomeViewModelTest {
6461
private val mockDeviceRepository: DeviceRepository = mockk()
6562
private val mockServiceConnectionManager: ServiceConnectionManager = mockk()
6663
private val mockPaymentUseCase: PaymentUseCase = mockk(relaxed = true)
67-
private val mockOutOfTimeUseCase: OutOfTimeUseCase = mockk(relaxed = true)
6864

6965
private lateinit var viewModel: WelcomeViewModel
7066

@@ -87,15 +83,12 @@ class WelcomeViewModelTest {
8783

8884
coEvery { mockPaymentUseCase.paymentAvailability } returns paymentAvailabilityFlow
8985

90-
coEvery { mockOutOfTimeUseCase.isOutOfTime } returns outOfTimeFlow
91-
9286
viewModel =
9387
WelcomeViewModel(
9488
accountRepository = mockAccountRepository,
9589
deviceRepository = mockDeviceRepository,
9690
serviceConnectionManager = mockServiceConnectionManager,
9791
paymentUseCase = mockPaymentUseCase,
98-
outOfTimeUseCase = mockOutOfTimeUseCase,
9992
pollAccountExpiry = false,
10093
isPlayBuild = false
10194
)
@@ -164,19 +157,16 @@ class WelcomeViewModelTest {
164157
}
165158

166159
@Test
167-
fun `when OutOfTimeUseCase return false uiSideEffect should emit OpenConnectScreen`() =
168-
runTest {
169-
// Arrange
170-
val mockExpiryDate: DateTime = mockk()
171-
every { mockExpiryDate.isAfter(any<ReadableInstant>()) } returns true
160+
fun `when user has added time then uiSideEffect should emit OpenConnectScreen`() = runTest {
161+
// Arrange
162+
accountExpiryStateFlow.emit(AccountExpiry.Available(DateTime().plusDays(1)))
172163

173-
// Act, Assert
174-
viewModel.uiSideEffect.test {
175-
outOfTimeFlow.value = false
176-
val action = awaitItem()
177-
assertIs<WelcomeViewModel.UiSideEffect.OpenConnectScreen>(action)
178-
}
164+
// Act, Assert
165+
viewModel.uiSideEffect.test {
166+
val action = awaitItem()
167+
assertIs<WelcomeViewModel.UiSideEffect.OpenConnectScreen>(action)
179168
}
169+
}
180170

181171
@Test
182172
fun `when paymentAvailability emits ProductsUnavailable uiState should include state NoPayment`() =

0 commit comments

Comments
 (0)