diff options
| author | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2024-01-04 14:59:25 +0100 |
|---|---|---|
| committer | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2024-01-04 14:59:25 +0100 |
| commit | aa98204d5e3ab402b9006ca2ddffb33397739ec0 (patch) | |
| tree | dffd97d37b1bf9efb9005f587aec32694ab12eb7 | |
| parent | 268bde60ec57ddc85d81ca33ca10b8c11443f707 (diff) | |
| parent | 301d8a76a7781c6db0b170c1455c80253d221c69 (diff) | |
| download | mullvadvpn-aa98204d5e3ab402b9006ca2ddffb33397739ec0.tar.xz mullvadvpn-aa98204d5e3ab402b9006ca2ddffb33397739ec0.zip | |
Merge branch 'device-revoked-is-not-handled-on-connectscreen-droid-600'
5 files changed, 52 insertions, 9 deletions
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 646e89c987..f626191b4c 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 @@ -43,6 +43,7 @@ import net.mullvad.mullvadvpn.compose.component.ScaffoldWithTopBarAndDeviceName import net.mullvad.mullvadvpn.compose.component.drawVerticalScrollbar import net.mullvad.mullvadvpn.compose.component.notificationbanner.NotificationBanner import net.mullvad.mullvadvpn.compose.destinations.AccountDestination +import net.mullvad.mullvadvpn.compose.destinations.DeviceRevokedDestination import net.mullvad.mullvadvpn.compose.destinations.OutOfTimeDestination import net.mullvad.mullvadvpn.compose.destinations.SelectLocationDestination import net.mullvad.mullvadvpn.compose.destinations.SettingsDestination @@ -98,6 +99,12 @@ fun Connect(navigator: DestinationsNavigator) { popUpTo(NavGraphs.root) { inclusive = true } } } + ConnectViewModel.UiSideEffect.RevokedDevice -> { + navigator.navigate(DeviceRevokedDestination) { + launchSingleTop = true + popUpTo(NavGraphs.root) { inclusive = true } + } + } } } } 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 11e929c905..71ec904de5 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 @@ -6,10 +6,10 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier @@ -34,6 +34,7 @@ import net.mullvad.mullvadvpn.compose.destinations.SettingsDestination import net.mullvad.mullvadvpn.compose.state.DeviceRevokedUiState import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.lib.theme.Dimens +import net.mullvad.mullvadvpn.viewmodel.DeviceRevokedSideEffect import net.mullvad.mullvadvpn.viewmodel.DeviceRevokedViewModel import org.koin.androidx.compose.koinViewModel @@ -49,15 +50,24 @@ fun DeviceRevoked(navigator: DestinationsNavigator) { val viewModel = koinViewModel<DeviceRevokedViewModel>() val state by viewModel.uiState.collectAsState() + + LaunchedEffect(Unit) { + viewModel.uiSideEffect.collect { sideEffect -> + when (sideEffect) { + DeviceRevokedSideEffect.NavigateToLogin -> { + navigator.navigate(LoginDestination()) { + launchSingleTop = true + popUpTo(NavGraphs.root) { inclusive = true } + } + } + } + } + } + DeviceRevokedScreen( state = state, onSettingsClicked = { navigator.navigate(SettingsDestination) { launchSingleTop = true } }, - onGoToLoginClicked = { - navigator.navigate(LoginDestination(null)) { - launchSingleTop = true - popUpTo(NavGraphs.root) { inclusive = true } - } - } + onGoToLoginClicked = viewModel::onGoToLoginClicked ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt index d25f360b51..69a75bea7f 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt @@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.ConnectUiState +import net.mullvad.mullvadvpn.model.DeviceState import net.mullvad.mullvadvpn.model.GeoIpLocation import net.mullvad.mullvadvpn.model.TunnelState import net.mullvad.mullvadvpn.repository.AccountRepository @@ -137,12 +138,18 @@ class ConnectViewModel( init { viewModelScope.launch { - // This once we get isOutOfTime true we will navigate to OutOfTime view. + // When we get isOutOfTime true we will navigate to OutOfTime view. outOfTimeUseCase.isOutOfTime().first { it == true } _uiSideEffect.send(UiSideEffect.OutOfTime) } viewModelScope.launch { + // When we get a revoked DeviceState we navigate to the RevokedDevice screen. + deviceRepository.deviceState.filterIsInstance<DeviceState.Revoked>().first() + _uiSideEffect.send(UiSideEffect.RevokedDevice) + } + + viewModelScope.launch { paymentUseCase.verifyPurchases { accountRepository.fetchAccountExpiry() } } } @@ -194,6 +201,8 @@ class ConnectViewModel( data class OpenAccountManagementPageInBrowser(val token: String) : UiSideEffect data object OutOfTime : UiSideEffect + + data object RevokedDevice : UiSideEffect } companion object { diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModel.kt index f5e9024c58..fed7399050 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModel.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModel.kt @@ -1,14 +1,19 @@ package net.mullvad.mullvadvpn.viewmodel import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.state.DeviceRevokedUiState import net.mullvad.mullvadvpn.repository.AccountRepository import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager @@ -42,12 +47,21 @@ class DeviceRevokedViewModel( initialValue = DeviceRevokedUiState.UNKNOWN ) + private val _uiSideEffect = Channel<DeviceRevokedSideEffect>(1, BufferOverflow.DROP_OLDEST) + val uiSideEffect = _uiSideEffect.receiveAsFlow() + fun onGoToLoginClicked() { serviceConnectionManager.connectionProxy()?.let { proxy -> if (proxy.state.isSecured()) { proxy.disconnect() } - accountRepository.logout() } + accountRepository.logout() + + viewModelScope.launch { _uiSideEffect.send(DeviceRevokedSideEffect.NavigateToLogin) } } } + +sealed interface DeviceRevokedSideEffect { + data object NavigateToLogin : DeviceRevokedSideEffect +} diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModelTest.kt index a73ecfc4e7..0fcf684afc 100644 --- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModelTest.kt +++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModelTest.kt @@ -16,6 +16,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest import net.mullvad.mullvadvpn.compose.state.DeviceRevokedUiState +import net.mullvad.mullvadvpn.lib.common.test.TestCoroutineRule import net.mullvad.mullvadvpn.model.TunnelState import net.mullvad.mullvadvpn.repository.AccountRepository import net.mullvad.mullvadvpn.ui.serviceconnection.ConnectionProxy @@ -26,9 +27,11 @@ import net.mullvad.talpid.util.EventNotifier import net.mullvad.talpid.util.callbackFlowFromSubscription import org.junit.After import org.junit.Before +import org.junit.Rule import org.junit.Test class DeviceRevokedViewModelTest { + @get:Rule val testCoroutineRule = TestCoroutineRule() @MockK private lateinit var mockedAccountRepository: AccountRepository |
