summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJonatan Rhodin <jonatan.rhodin@mullvad.net>2024-01-04 14:59:25 +0100
committerJonatan Rhodin <jonatan.rhodin@mullvad.net>2024-01-04 14:59:25 +0100
commitaa98204d5e3ab402b9006ca2ddffb33397739ec0 (patch)
treedffd97d37b1bf9efb9005f587aec32694ab12eb7
parent268bde60ec57ddc85d81ca33ca10b8c11443f707 (diff)
parent301d8a76a7781c6db0b170c1455c80253d221c69 (diff)
downloadmullvadvpn-aa98204d5e3ab402b9006ca2ddffb33397739ec0.tar.xz
mullvadvpn-aa98204d5e3ab402b9006ca2ddffb33397739ec0.zip
Merge branch 'device-revoked-is-not-handled-on-connectscreen-droid-600'
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt7
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceRevokedScreen.kt24
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/ConnectViewModel.kt11
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModel.kt16
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModelTest.kt3
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