diff options
| author | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2025-05-13 15:49:39 +0200 |
|---|---|---|
| committer | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2025-05-13 15:49:39 +0200 |
| commit | 2beec9cb917cc274c4326345ae10ff041c665db0 (patch) | |
| tree | a1f8dfe32fd7cd097b39a8aaecf39dd5acdc7014 /android/app/src/main | |
| parent | ce62828a21cb65f2b0d1710b7d92b4e55a518408 (diff) | |
| parent | 95d302c41f11f2b8090c955c59eab3e616430ee7 (diff) | |
| download | mullvadvpn-2beec9cb917cc274c4326345ae10ff041c665db0.tar.xz mullvadvpn-2beec9cb917cc274c4326345ae10ff041c665db0.zip | |
Merge branch 'add-error-message-for-when-a-configured-port-is-invalid-droid-1982'
Diffstat (limited to 'android/app/src/main')
4 files changed, 70 insertions, 2 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/notificationbanner/NotificationBanner.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/notificationbanner/NotificationBanner.kt index 9ff9ec5a00..1605b83cdb 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/notificationbanner/NotificationBanner.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/notificationbanner/NotificationBanner.kt @@ -55,6 +55,7 @@ private fun PreviewNotificationBanner() { onClickShowChangelog = {}, onClickDismissChangelog = {}, onClickDismissNewDevice = {}, + onClickShowWireguardPortSettings = {}, ) Spacer(modifier = Modifier.size(16.dp)) } @@ -72,6 +73,7 @@ fun NotificationBanner( onClickShowChangelog: () -> Unit, onClickDismissChangelog: () -> Unit, onClickDismissNewDevice: () -> Unit, + onClickShowWireguardPortSettings: () -> Unit, ) { if (isTv()) { NotificationBannerTv( @@ -83,6 +85,7 @@ fun NotificationBanner( onClickShowChangelog = onClickShowChangelog, onClickDismissChangelog = onClickDismissChangelog, onClickDismissNewDevice = onClickDismissNewDevice, + onClickShowWireguardPortSettings = onClickShowWireguardPortSettings, ) } else { AnimatedNotificationBanner( @@ -95,6 +98,7 @@ fun NotificationBanner( onClickShowChangelog = onClickShowChangelog, onClickDismissChangelog = onClickDismissChangelog, onClickDismissNewDevice = onClickDismissNewDevice, + onClickShowWireguardPortSettings = onClickShowWireguardPortSettings, ) } } 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 94db024b41..26c08e4841 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 @@ -164,6 +164,7 @@ private fun PreviewAccountScreen( {}, {}, {}, + {}, ) } } @@ -304,12 +305,15 @@ fun Connect( dropUnlessResumed { feature: FeatureIndicator -> navigator.navigate(feature.destination()) }, + onClickShowWireguardPortSettings = + dropUnlessResumed { navigator.navigate(VpnSettingsDestination()) }, ) } } @OptIn(ExperimentalComposeUiApi::class) @Composable +@Suppress("LongParameterList") fun ConnectScreen( state: ConnectUiState, snackbarHostState: SnackbarHostState = remember { SnackbarHostState() }, @@ -326,6 +330,7 @@ fun ConnectScreen( onAccountClick: () -> Unit, onDismissNewDeviceClick: () -> Unit, onNavigateToFeature: (FeatureIndicator) -> Unit, + onClickShowWireguardPortSettings: () -> Unit, ) { val contentFocusRequester = remember { FocusRequester() } @@ -346,6 +351,7 @@ fun ConnectScreen( onDismissChangelogClick, onDismissNewDeviceClick, onNavigateToFeature, + onClickShowWireguardPortSettings, ) } @@ -384,6 +390,7 @@ fun ConnectScreen( } @Composable +@Suppress("LongParameterList") private fun Content( focusRequester: FocusRequester, paddingValues: PaddingValues, @@ -399,6 +406,7 @@ private fun Content( onDismissChangelogClick: () -> Unit, onDismissNewDeviceClick: () -> Unit, onNavigateToFeature: (FeatureIndicator) -> Unit, + onClickShowWireguardPortSettings: () -> Unit, ) { val screenHeight = LocalWindowInfo.current.containerSize.height.dp val indicatorPercentOffset = @@ -446,6 +454,7 @@ private fun Content( onClickShowChangelog = onChangelogClick, onClickDismissChangelog = onDismissChangelogClick, onClickDismissNewDevice = onDismissNewDeviceClick, + onClickShowWireguardPortSettings = onClickShowWireguardPortSettings, ) ConnectionCard( state = state, 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 c44aedd890..c9c1f1e78a 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 @@ -153,7 +153,7 @@ val uiModule = module { single { WireguardConstraintsRepository(get()) } single { AccountExpiryInAppNotificationUseCase(get()) } - single { TunnelStateNotificationUseCase(get()) } + single { TunnelStateNotificationUseCase(get(), get(), get()) } single { VersionNotificationUseCase(get(), BuildConfig.ENABLE_IN_APP_VERSION_NOTIFICATIONS) } single { NewDeviceNotificationUseCase(get(), get()) } single { NewChangelogNotificationUseCase(get()) } 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 85ea7cf11a..753f8c1eef 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 @@ -1,18 +1,46 @@ package net.mullvad.mullvadvpn.usecase +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import net.mullvad.mullvadvpn.lib.model.ActionAfterDisconnect +import net.mullvad.mullvadvpn.lib.model.Constraint +import net.mullvad.mullvadvpn.lib.model.ErrorState +import net.mullvad.mullvadvpn.lib.model.ErrorStateCause import net.mullvad.mullvadvpn.lib.model.InAppNotification +import net.mullvad.mullvadvpn.lib.model.ParameterGenerationError +import net.mullvad.mullvadvpn.lib.model.Port +import net.mullvad.mullvadvpn.lib.model.PortRange +import net.mullvad.mullvadvpn.lib.model.Settings import net.mullvad.mullvadvpn.lib.model.TunnelState import net.mullvad.mullvadvpn.lib.shared.ConnectionProxy +import net.mullvad.mullvadvpn.repository.RelayListRepository +import net.mullvad.mullvadvpn.repository.SettingsRepository +import net.mullvad.mullvadvpn.util.inAnyOf -class TunnelStateNotificationUseCase(private val connectionProxy: ConnectionProxy) { +class TunnelStateNotificationUseCase( + private val connectionProxy: ConnectionProxy, + private val relayListRepository: RelayListRepository, + private val settingsRepository: SettingsRepository, +) { + @OptIn(ExperimentalCoroutinesApi::class) operator fun invoke(): Flow<List<InAppNotification>> = connectionProxy.tunnelState .distinctUntilChanged() .map(::tunnelStateNotification) + .flatMapLatest { inAppNotification -> + combine(relayListRepository.portRanges, settingsRepository.settingsUpdates) { + portRanges, + settings -> + inAppNotification?.maybeUpdateWithPortError( + wireguardPort = settings.wireguardPort(), + availablePorts = portRanges, + ) + } + } .map(::listOfNotNull) .distinctUntilChanged() @@ -31,4 +59,31 @@ class TunnelStateNotificationUseCase(private val connectionProxy: ConnectionProx is TunnelState.Connected, is TunnelState.Disconnected -> null } + + private fun InAppNotification.maybeUpdateWithPortError( + wireguardPort: Constraint<Port>, + availablePorts: List<PortRange>, + ): InAppNotification = + if (this is InAppNotification.TunnelStateError && error.isPossiblePortError()) { + wireguardPort.invalidPortOrNull(availablePorts)?.let { + copy( + error = + ErrorState( + cause = ErrorStateCause.NoRelaysMatchSelectedPort(port = it), + isBlocking = error.isBlocking, + ) + ) + } ?: this + } else this + + private fun ErrorState.isPossiblePortError(): Boolean = + cause is ErrorStateCause.TunnelParameterError && + (cause as ErrorStateCause.TunnelParameterError).error == + ParameterGenerationError.NoMatchingRelay + + private fun Constraint<Port>.invalidPortOrNull(availablePortRanges: List<PortRange>): Port? = + getOrNull()?.takeIf { !it.inAnyOf(availablePortRanges) } + + private fun Settings?.wireguardPort() = + this?.relaySettings?.relayConstraints?.wireguardConstraints?.port ?: Constraint.Any } |
