diff options
| author | David Göransson <david.goransson90@gmail.com> | 2023-12-18 12:12:17 +0100 |
|---|---|---|
| committer | Jonathan <jonathan@mullvad.net> | 2023-12-21 13:33:59 +0100 |
| commit | 8ed53a012b6c510a0dfd92925b8b0e742fd79da3 (patch) | |
| tree | c92a6f524fa9f659a0edb2bb702e466d051ddba2 /android/app/src/main | |
| parent | c70509a345b6db8caf12c880b3ee3bf4c70bf79d (diff) | |
| download | mullvadvpn-8ed53a012b6c510a0dfd92925b8b0e742fd79da3.tar.xz mullvadvpn-8ed53a012b6c510a0dfd92925b8b0e742fd79da3.zip | |
Support new tunnel state API in the Android frontend.
Remove `get_current_location` from jni.
Diffstat (limited to 'android/app/src/main')
11 files changed, 35 insertions, 68 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/ConnectionStatusText.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/ConnectionStatusText.kt index 742302ce91..903bb412dc 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/ConnectionStatusText.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/ConnectionStatusText.kt @@ -18,7 +18,7 @@ import net.mullvad.talpid.tunnel.ErrorStateCause private fun PreviewConnectionStatusText() { AppTheme { SpacedColumn { - ConnectionStatusText(TunnelState.Disconnected) + ConnectionStatusText(TunnelState.Disconnected()) ConnectionStatusText(TunnelState.Connecting(null, null)) ConnectionStatusText( state = TunnelState.Error(ErrorState(ErrorStateCause.Ipv6Unavailable, true)) 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 b1de1ad809..646e89c987 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 @@ -19,7 +19,9 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableLongStateOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -108,7 +110,6 @@ fun Connect(navigator: DestinationsNavigator) { onSwitchLocationClick = { navigator.navigate(SelectLocationDestination) { launchSingleTop = true } }, - onToggleTunnelInfo = connectViewModel::toggleTunnelInfoExpansion, onUpdateVersionClick = { val intent = Intent( @@ -137,7 +138,6 @@ fun ConnectScreen( onConnectClick: () -> Unit = {}, onCancelClick: () -> Unit = {}, onSwitchLocationClick: () -> Unit = {}, - onToggleTunnelInfo: () -> Unit = {}, onUpdateVersionClick: () -> Unit = {}, onManageAccountClick: () -> Unit = {}, onSettingsClick: () -> Unit = {}, @@ -233,12 +233,13 @@ fun ConnectScreen( color = MaterialTheme.colorScheme.onPrimary, modifier = Modifier.padding(horizontal = Dimens.sideMargin) ) + var expanded by rememberSaveable { mutableStateOf(false) } LocationInfo( - onToggleTunnelInfo = onToggleTunnelInfo, + onToggleTunnelInfo = { expanded = !expanded }, isVisible = - uiState.tunnelRealState != TunnelState.Disconnected && + uiState.tunnelRealState !is TunnelState.Disconnected && uiState.location?.hostname != null, - isExpanded = uiState.isTunnelInfoExpanded, + isExpanded = expanded, location = uiState.location, inAddress = uiState.inAddress, outAddress = uiState.outAddress, 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 d9071be7d8..d0d0c7460d 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 @@ -62,7 +62,7 @@ private fun PreviewOutOfTimeScreenDisconnected() { OutOfTimeScreen( uiState = OutOfTimeUiState( - tunnelState = TunnelState.Disconnected, + tunnelState = TunnelState.Disconnected(), "Heroic Frog", showSitePayment = true ), diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/ConnectUiState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/ConnectUiState.kt index 54c1a0d7c0..dc26e24741 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/ConnectUiState.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/ConnectUiState.kt @@ -15,7 +15,6 @@ data class ConnectUiState( val outAddress: String, val showLocation: Boolean, val inAppNotification: InAppNotification?, - val isTunnelInfoExpanded: Boolean, val deviceName: String?, val daysLeftUntilExpiry: Int?, val isPlayBuild: Boolean @@ -25,12 +24,11 @@ data class ConnectUiState( ConnectUiState( location = null, relayLocation = null, - tunnelUiState = TunnelState.Disconnected, - tunnelRealState = TunnelState.Disconnected, + tunnelUiState = TunnelState.Disconnected(), + tunnelRealState = TunnelState.Disconnected(), inAddress = null, outAddress = "", showLocation = false, - isTunnelInfoExpanded = false, inAppNotification = null, deviceName = null, daysLeftUntilExpiry = null, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/OutOfTimeUiState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/OutOfTimeUiState.kt index 54fd414f86..d72e015194 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/OutOfTimeUiState.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/OutOfTimeUiState.kt @@ -3,7 +3,7 @@ package net.mullvad.mullvadvpn.compose.state import net.mullvad.mullvadvpn.model.TunnelState data class OutOfTimeUiState( - val tunnelState: TunnelState = TunnelState.Disconnected, + val tunnelState: TunnelState = TunnelState.Disconnected(), val deviceName: String = "", val showSitePayment: Boolean = false, val billingPaymentState: PaymentState? = null, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/WelcomeUiState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/WelcomeUiState.kt index e2673a0ddf..e43cf6bb98 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/WelcomeUiState.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/WelcomeUiState.kt @@ -3,7 +3,7 @@ package net.mullvad.mullvadvpn.compose.state import net.mullvad.mullvadvpn.model.TunnelState data class WelcomeUiState( - val tunnelState: TunnelState = TunnelState.Disconnected, + val tunnelState: TunnelState = TunnelState.Disconnected(), val accountNumber: String? = null, val deviceName: String? = null, val showSitePayment: Boolean = false, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ConnectionProxy.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ConnectionProxy.kt index d51bad461d..bbc267b2fa 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ConnectionProxy.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ConnectionProxy.kt @@ -19,8 +19,8 @@ const val ANTICIPATED_STATE_TIMEOUT_MS = 1500L class ConnectionProxy(private val connection: Messenger, eventDispatcher: EventDispatcher) { private var resetAnticipatedStateJob: Job? = null - val onStateChange = EventNotifier<TunnelState>(TunnelState.Disconnected) - val onUiStateChange = EventNotifier<TunnelState>(TunnelState.Disconnected) + val onStateChange = EventNotifier<TunnelState>(TunnelState.Disconnected()) + val onUiStateChange = EventNotifier<TunnelState>(TunnelState.Disconnected()) var state by onStateChange.notifiable() private set diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/LocationInfoCache.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/LocationInfoCache.kt deleted file mode 100644 index 48f77d397d..0000000000 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/LocationInfoCache.kt +++ /dev/null @@ -1,26 +0,0 @@ -package net.mullvad.mullvadvpn.ui.serviceconnection - -import kotlin.properties.Delegates.observable -import net.mullvad.mullvadvpn.lib.ipc.Event -import net.mullvad.mullvadvpn.lib.ipc.EventDispatcher -import net.mullvad.mullvadvpn.model.GeoIpLocation - -class LocationInfoCache(eventDispatcher: EventDispatcher) { - private var location: GeoIpLocation? by - observable(null) { _, _, newLocation -> onNewLocation?.invoke(newLocation) } - - var onNewLocation by - observable<((GeoIpLocation?) -> Unit)?>(null) { _, _, callback -> - callback?.invoke(location) - } - - init { - eventDispatcher.registerHandler(Event.NewLocation::class) { event -> - location = event.location - } - } - - fun onDestroy() { - onNewLocation = null - } -} diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionContainer.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionContainer.kt index ca156bed66..8aabe6c9f5 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionContainer.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionContainer.kt @@ -28,7 +28,6 @@ class ServiceConnectionContainer( val authTokenCache = AuthTokenCache(connection, dispatcher) val connectionProxy = ConnectionProxy(connection, dispatcher) val deviceDataSource = ServiceConnectionDeviceDataSource(connection, dispatcher) - val locationInfoCache = LocationInfoCache(dispatcher) val settingsListener = SettingsListener(connection, dispatcher) val splitTunneling = SplitTunneling(connection, dispatcher) @@ -62,7 +61,6 @@ class ServiceConnectionContainer( authTokenCache.onDestroy() connectionProxy.onDestroy() - locationInfoCache.onDestroy() settingsListener.onDestroy() voucherRedeemer.onDestroy() diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/TunnelStateNotificationUseCase.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/TunnelStateNotificationUseCase.kt index f228bd7dbe..dec794c86c 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/TunnelStateNotificationUseCase.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/TunnelStateNotificationUseCase.kt @@ -39,7 +39,7 @@ class TunnelStateNotificationUseCase( } is TunnelState.Error -> InAppNotification.TunnelStateError(tunnelUiState.errorState) is TunnelState.Connected, - TunnelState.Disconnected -> null + is TunnelState.Disconnected -> null } private fun ConnectionProxy.tunnelUiStateFlow(): Flow<TunnelState> = 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 3066006083..d25f360b51 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 @@ -5,30 +5,30 @@ import androidx.lifecycle.viewModelScope import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.receiveAsFlow 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.GeoIpLocation import net.mullvad.mullvadvpn.model.TunnelState import net.mullvad.mullvadvpn.repository.AccountRepository import net.mullvad.mullvadvpn.repository.DeviceRepository import net.mullvad.mullvadvpn.repository.InAppNotificationController import net.mullvad.mullvadvpn.ui.serviceconnection.ConnectionProxy -import net.mullvad.mullvadvpn.ui.serviceconnection.LocationInfoCache import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionContainer import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionState @@ -71,48 +71,46 @@ class ConnectViewModel( } .shareIn(viewModelScope, SharingStarted.WhileSubscribed()) - private val _isTunnelInfoExpanded = MutableStateFlow(false) - val uiState: StateFlow<ConnectUiState> = _shared .flatMapLatest { serviceConnection -> combine( - serviceConnection.locationInfoCache.locationCallbackFlow(), relayListUseCase.selectedRelayItem(), inAppNotificationController.notifications, serviceConnection.connectionProxy.tunnelUiStateFlow(), serviceConnection.connectionProxy.tunnelRealStateFlow(), + serviceConnection.connectionProxy.lastKnownDisconnectedLocation(), accountRepository.accountExpiryState, - _isTunnelInfoExpanded, deviceRepository.deviceState.map { it.deviceName() } ) { - location, relayLocation, notifications, tunnelUiState, tunnelRealState, + lastKnownDisconnectedLocation, accountExpiry, - isTunnelInfoExpanded, deviceName -> ConnectUiState( location = when (tunnelRealState) { - is TunnelState.Connected -> tunnelRealState.location + is TunnelState.Disconnected -> tunnelRealState.location() + ?: lastKnownDisconnectedLocation is TunnelState.Connecting -> tunnelRealState.location - else -> null - } - ?: location, + ?: relayLocation?.location?.location + is TunnelState.Connected -> tunnelRealState.location + is TunnelState.Disconnecting -> lastKnownDisconnectedLocation + is TunnelState.Error -> null + }, relayLocation = relayLocation, tunnelUiState = tunnelUiState, tunnelRealState = tunnelRealState, - isTunnelInfoExpanded = isTunnelInfoExpanded, inAddress = when (tunnelRealState) { is TunnelState.Connected -> tunnelRealState.endpoint.toInAddress() is TunnelState.Connecting -> tunnelRealState.endpoint?.toInAddress() else -> null }, - outAddress = location?.toOutAddress() ?: "", + outAddress = tunnelRealState.location()?.toOutAddress() ?: "", showLocation = when (tunnelUiState) { is TunnelState.Disconnected -> true @@ -149,20 +147,18 @@ class ConnectViewModel( } } - private fun LocationInfoCache.locationCallbackFlow() = callbackFlow { - onNewLocation = { this.trySend(it) } - awaitClose { onNewLocation = null } - } - private fun ConnectionProxy.tunnelUiStateFlow(): Flow<TunnelState> = callbackFlowFromNotifier(this.onUiStateChange) private fun ConnectionProxy.tunnelRealStateFlow(): Flow<TunnelState> = callbackFlowFromNotifier(this.onStateChange) - fun toggleTunnelInfoExpansion() { - _isTunnelInfoExpanded.value = _isTunnelInfoExpanded.value.not() - } + private fun ConnectionProxy.lastKnownDisconnectedLocation(): Flow<GeoIpLocation?> = + tunnelRealStateFlow() + .filterIsInstance<TunnelState.Disconnected>() + .filter { it.location != null } + .map { it.location } + .onStart { emit(null) } fun onDisconnectClick() { serviceConnectionManager.connectionProxy()?.disconnect() |
