Skip to content

Commit

Permalink
Add support for blocking and disconnecting text in notification
Browse files Browse the repository at this point in the history
  • Loading branch information
Rawa committed Jan 7, 2025
1 parent a0e1db7 commit f0b983e
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ sealed interface NotificationTunnelState {

data object Connected : NotificationTunnelState

data object Reconnecting : NotificationTunnelState
data object Blocking : NotificationTunnelState

data object Disconnecting : NotificationTunnelState

sealed interface Error : NotificationTunnelState {
data object DeviceOffline : Error

data object Blocking : Error
data object Blocked : Error

data object VpnPermissionDenied : Error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ private fun NotificationTunnelState.contentTitleResourceId(context: Context): St
}
}
NotificationTunnelState.Disconnecting -> context.getString(R.string.disconnecting)
NotificationTunnelState.Reconnecting -> context.getString(R.string.reconnecting)
NotificationTunnelState.Error.Blocking -> context.getString(R.string.blocking_internet)
NotificationTunnelState.Blocking -> context.getString(R.string.blocking)
NotificationTunnelState.Error.Blocked -> context.getString(R.string.blocking_internet)
is NotificationTunnelState.Error.Critical -> context.getString(R.string.critical_error)
NotificationTunnelState.Error.DeviceOffline ->
context.getString(R.string.blocking_internet_device_offline)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
package net.mullvad.mullvadvpn.service.notifications.tunnelstate

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import net.mullvad.mullvadvpn.lib.model.ActionAfterDisconnect
import net.mullvad.mullvadvpn.lib.model.DeviceState
Expand Down Expand Up @@ -36,22 +31,16 @@ class TunnelStateNotificationProvider(
internal val notificationId = NotificationId(2)

override val notifications: StateFlow<NotificationUpdate<Notification.Tunnel>> =
combine(
connectionProxy.tunnelState,
connectionProxy.tunnelState.actionAfterDisconnect().distinctUntilChanged(),
deviceRepository.deviceState,
) { tunnelState, actionAfterDisconnect, deviceState ->
combine(connectionProxy.tunnelState, deviceRepository.deviceState) {
tunnelState,
deviceState ->
if (
deviceState is DeviceState.LoggedOut && tunnelState is TunnelState.Disconnected
) {
return@combine NotificationUpdate.Cancel(notificationId)
}
val notificationTunnelState =
tunnelState(
tunnelState,
actionAfterDisconnect,
vpnPermissionRepository.invoke().leftOrNull(),
)
tunnelState(tunnelState, vpnPermissionRepository.invoke().leftOrNull())

return@combine NotificationUpdate.Notify(
notificationId,
Expand All @@ -67,36 +56,19 @@ class TunnelStateNotificationProvider(

private fun tunnelState(
tunnelState: TunnelState,
actionAfterDisconnect: ActionAfterDisconnect?,
prepareError: PrepareError?,
): NotificationTunnelState =
tunnelState.toNotificationTunnelState(actionAfterDisconnect, prepareError)
): NotificationTunnelState = tunnelState.toNotificationTunnelState(prepareError)

private fun Flow<TunnelState>.actionAfterDisconnect(): Flow<ActionAfterDisconnect?> =
filterIsInstance<TunnelState.Disconnecting>()
.map<TunnelState.Disconnecting, ActionAfterDisconnect?> { it.actionAfterDisconnect }
.onStart { emit(null) }

private fun TunnelState.toNotificationTunnelState(
actionAfterDisconnect: ActionAfterDisconnect?,
prepareError: PrepareError?,
) =
private fun TunnelState.toNotificationTunnelState(prepareError: PrepareError?) =
when (this) {
is TunnelState.Disconnected -> NotificationTunnelState.Disconnected(prepareError)
is TunnelState.Connecting -> {
if (actionAfterDisconnect == ActionAfterDisconnect.Reconnect) {
NotificationTunnelState.Reconnecting
} else {
NotificationTunnelState.Connecting
}
}
is TunnelState.Disconnecting -> {
if (actionAfterDisconnect == ActionAfterDisconnect.Reconnect) {
NotificationTunnelState.Reconnecting
} else {
NotificationTunnelState.Disconnecting
is TunnelState.Connecting -> NotificationTunnelState.Connecting
is TunnelState.Disconnecting ->
when (actionAfterDisconnect) {
ActionAfterDisconnect.Reconnect -> NotificationTunnelState.Connecting
ActionAfterDisconnect.Block -> NotificationTunnelState.Blocking
ActionAfterDisconnect.Nothing -> NotificationTunnelState.Disconnecting
}
}
is TunnelState.Connected -> NotificationTunnelState.Connected
is TunnelState.Error -> toNotificationTunnelState()
}
Expand All @@ -106,14 +78,14 @@ class TunnelStateNotificationProvider(
return when {
cause is ErrorStateCause.IsOffline && errorState.isBlocking ->
NotificationTunnelState.Error.DeviceOffline
cause is ErrorStateCause.InvalidDnsServers -> NotificationTunnelState.Error.Blocking
cause is ErrorStateCause.InvalidDnsServers -> NotificationTunnelState.Error.Blocked
cause is ErrorStateCause.OtherLegacyAlwaysOnApp ->
NotificationTunnelState.Error.LegacyLockdown
cause is ErrorStateCause.NotPrepared ->
NotificationTunnelState.Error.VpnPermissionDenied
cause is ErrorStateCause.OtherAlwaysOnApp ->
NotificationTunnelState.Error.AlwaysOnVpn(cause.appName)
errorState.isBlocking -> NotificationTunnelState.Error.Blocking
errorState.isBlocking -> NotificationTunnelState.Error.Blocked
else -> NotificationTunnelState.Error.Critical
}
}
Expand All @@ -129,12 +101,12 @@ class TunnelStateNotificationProvider(
}
}
NotificationTunnelState.Disconnecting -> NotificationAction.Tunnel.Connect
NotificationTunnelState.Connected,
NotificationTunnelState.Error.Blocking -> NotificationAction.Tunnel.Disconnect
NotificationTunnelState.Error.Blocked,
NotificationTunnelState.Blocking,
NotificationTunnelState.Error.DeviceOffline,
NotificationTunnelState.Connected -> NotificationAction.Tunnel.Disconnect
NotificationTunnelState.Connecting -> NotificationAction.Tunnel.Cancel
NotificationTunnelState.Reconnecting -> NotificationAction.Tunnel.Cancel
is NotificationTunnelState.Error.Critical,
NotificationTunnelState.Error.DeviceOffline,
NotificationTunnelState.Error.VpnPermissionDenied,
is NotificationTunnelState.Error.AlwaysOnVpn,
NotificationTunnelState.Error.LegacyLockdown -> NotificationAction.Tunnel.Dismiss
Expand Down

0 comments on commit f0b983e

Please sign in to comment.