parent
3e6a2981cb
commit
f3debcfe45
|
@ -0,0 +1,281 @@
|
||||||
|
{
|
||||||
|
"formatVersion": 1,
|
||||||
|
"database": {
|
||||||
|
"version": 15,
|
||||||
|
"identityHash": "4827f3b1ab5a4e5aa35937a0925d50e4",
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"tableName": "Settings",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `is_tunnel_enabled` INTEGER NOT NULL, `is_tunnel_on_mobile_data_enabled` INTEGER NOT NULL, `trusted_network_ssids` TEXT NOT NULL, `is_always_on_vpn_enabled` INTEGER NOT NULL, `is_tunnel_on_ethernet_enabled` INTEGER NOT NULL, `is_shortcuts_enabled` INTEGER NOT NULL DEFAULT false, `is_tunnel_on_wifi_enabled` INTEGER NOT NULL DEFAULT false, `is_kernel_enabled` INTEGER NOT NULL DEFAULT false, `is_restore_on_boot_enabled` INTEGER NOT NULL DEFAULT false, `is_multi_tunnel_enabled` INTEGER NOT NULL DEFAULT false, `is_ping_enabled` INTEGER NOT NULL DEFAULT false, `is_amnezia_enabled` INTEGER NOT NULL DEFAULT false, `is_wildcards_enabled` INTEGER NOT NULL DEFAULT false, `is_wifi_by_shell_enabled` INTEGER NOT NULL DEFAULT false, `is_stop_on_no_internet_enabled` INTEGER NOT NULL DEFAULT false, `is_vpn_kill_switch_enabled` INTEGER NOT NULL DEFAULT false, `is_kernel_kill_switch_enabled` INTEGER NOT NULL DEFAULT false, `is_lan_on_kill_switch_enabled` INTEGER NOT NULL DEFAULT false, `debounce_delay_seconds` INTEGER NOT NULL DEFAULT 3, `is_disable_kill_switch_on_trusted_enabled` INTEGER NOT NULL DEFAULT false)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isAutoTunnelEnabled",
|
||||||
|
"columnName": "is_tunnel_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isTunnelOnMobileDataEnabled",
|
||||||
|
"columnName": "is_tunnel_on_mobile_data_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "trustedNetworkSSIDs",
|
||||||
|
"columnName": "trusted_network_ssids",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isAlwaysOnVpnEnabled",
|
||||||
|
"columnName": "is_always_on_vpn_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isTunnelOnEthernetEnabled",
|
||||||
|
"columnName": "is_tunnel_on_ethernet_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isShortcutsEnabled",
|
||||||
|
"columnName": "is_shortcuts_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isTunnelOnWifiEnabled",
|
||||||
|
"columnName": "is_tunnel_on_wifi_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isKernelEnabled",
|
||||||
|
"columnName": "is_kernel_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isRestoreOnBootEnabled",
|
||||||
|
"columnName": "is_restore_on_boot_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isMultiTunnelEnabled",
|
||||||
|
"columnName": "is_multi_tunnel_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isPingEnabled",
|
||||||
|
"columnName": "is_ping_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isAmneziaEnabled",
|
||||||
|
"columnName": "is_amnezia_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isWildcardsEnabled",
|
||||||
|
"columnName": "is_wildcards_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isWifiNameByShellEnabled",
|
||||||
|
"columnName": "is_wifi_by_shell_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isStopOnNoInternetEnabled",
|
||||||
|
"columnName": "is_stop_on_no_internet_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isVpnKillSwitchEnabled",
|
||||||
|
"columnName": "is_vpn_kill_switch_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isKernelKillSwitchEnabled",
|
||||||
|
"columnName": "is_kernel_kill_switch_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isLanOnKillSwitchEnabled",
|
||||||
|
"columnName": "is_lan_on_kill_switch_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "debounceDelaySeconds",
|
||||||
|
"columnName": "debounce_delay_seconds",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isDisableKillSwitchOnTrustedEnabled",
|
||||||
|
"columnName": "is_disable_kill_switch_on_trusted_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [],
|
||||||
|
"foreignKeys": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tableName": "TunnelConfig",
|
||||||
|
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `wg_quick` TEXT NOT NULL, `tunnel_networks` TEXT NOT NULL DEFAULT '', `is_mobile_data_tunnel` INTEGER NOT NULL DEFAULT false, `is_primary_tunnel` INTEGER NOT NULL DEFAULT false, `am_quick` TEXT NOT NULL DEFAULT '', `is_Active` INTEGER NOT NULL DEFAULT false, `is_ping_enabled` INTEGER NOT NULL DEFAULT false, `ping_interval` INTEGER DEFAULT null, `ping_cooldown` INTEGER DEFAULT null, `ping_ip` TEXT DEFAULT null, `is_ethernet_tunnel` INTEGER NOT NULL DEFAULT false)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldPath": "id",
|
||||||
|
"columnName": "id",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "name",
|
||||||
|
"columnName": "name",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "wgQuick",
|
||||||
|
"columnName": "wg_quick",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "tunnelNetworks",
|
||||||
|
"columnName": "tunnel_networks",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "''"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isMobileDataTunnel",
|
||||||
|
"columnName": "is_mobile_data_tunnel",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isPrimaryTunnel",
|
||||||
|
"columnName": "is_primary_tunnel",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "amQuick",
|
||||||
|
"columnName": "am_quick",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "''"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isActive",
|
||||||
|
"columnName": "is_Active",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isPingEnabled",
|
||||||
|
"columnName": "is_ping_enabled",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "pingInterval",
|
||||||
|
"columnName": "ping_interval",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false,
|
||||||
|
"defaultValue": "null"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "pingCooldown",
|
||||||
|
"columnName": "ping_cooldown",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": false,
|
||||||
|
"defaultValue": "null"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "pingIp",
|
||||||
|
"columnName": "ping_ip",
|
||||||
|
"affinity": "TEXT",
|
||||||
|
"notNull": false,
|
||||||
|
"defaultValue": "null"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldPath": "isEthernetTunnel",
|
||||||
|
"columnName": "is_ethernet_tunnel",
|
||||||
|
"affinity": "INTEGER",
|
||||||
|
"notNull": true,
|
||||||
|
"defaultValue": "false"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primaryKey": {
|
||||||
|
"autoGenerate": true,
|
||||||
|
"columnNames": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"indices": [
|
||||||
|
{
|
||||||
|
"name": "index_TunnelConfig_name",
|
||||||
|
"unique": true,
|
||||||
|
"columnNames": [
|
||||||
|
"name"
|
||||||
|
],
|
||||||
|
"orders": [],
|
||||||
|
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_TunnelConfig_name` ON `${TABLE_NAME}` (`name`)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"foreignKeys": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"views": [],
|
||||||
|
"setupQueries": [
|
||||||
|
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||||
|
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '4827f3b1ab5a4e5aa35937a0925d50e4')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
|
||||||
|
|
||||||
@Database(
|
@Database(
|
||||||
entities = [Settings::class, TunnelConfig::class],
|
entities = [Settings::class, TunnelConfig::class],
|
||||||
version = 14,
|
version = 15,
|
||||||
autoMigrations =
|
autoMigrations =
|
||||||
[
|
[
|
||||||
AutoMigration(from = 1, to = 2),
|
AutoMigration(from = 1, to = 2),
|
||||||
|
@ -53,6 +53,10 @@ import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
|
||||||
from = 13,
|
from = 13,
|
||||||
to = 14,
|
to = 14,
|
||||||
),
|
),
|
||||||
|
AutoMigration(
|
||||||
|
from = 14,
|
||||||
|
to = 15,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
exportSchema = true,
|
exportSchema = true,
|
||||||
)
|
)
|
||||||
|
|
|
@ -85,6 +85,11 @@ data class Settings(
|
||||||
defaultValue = "3",
|
defaultValue = "3",
|
||||||
)
|
)
|
||||||
val debounceDelaySeconds: Int = 3,
|
val debounceDelaySeconds: Int = 3,
|
||||||
|
@ColumnInfo(
|
||||||
|
name = "is_disable_kill_switch_on_trusted_enabled",
|
||||||
|
defaultValue = "false",
|
||||||
|
)
|
||||||
|
val isDisableKillSwitchOnTrustedEnabled: Boolean = false,
|
||||||
) {
|
) {
|
||||||
fun debounceDelayMillis(): Long {
|
fun debounceDelayMillis(): Long {
|
||||||
return debounceDelaySeconds * 1000L
|
return debounceDelaySeconds * 1000L
|
||||||
|
|
|
@ -17,6 +17,7 @@ import com.zaneschepke.wireguardautotunnel.module.MainImmediateDispatcher
|
||||||
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
|
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
|
||||||
import com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model.AutoTunnelEvent
|
import com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model.AutoTunnelEvent
|
||||||
import com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model.AutoTunnelState
|
import com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model.AutoTunnelState
|
||||||
|
import com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model.KillSwitchEvent
|
||||||
import com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model.NetworkState
|
import com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model.NetworkState
|
||||||
import com.zaneschepke.wireguardautotunnel.service.network.InternetConnectivityService
|
import com.zaneschepke.wireguardautotunnel.service.network.InternetConnectivityService
|
||||||
import com.zaneschepke.wireguardautotunnel.service.network.NetworkService
|
import com.zaneschepke.wireguardautotunnel.service.network.NetworkService
|
||||||
|
@ -24,6 +25,7 @@ import com.zaneschepke.wireguardautotunnel.service.network.NetworkStatus
|
||||||
import com.zaneschepke.wireguardautotunnel.service.notification.NotificationAction
|
import com.zaneschepke.wireguardautotunnel.service.notification.NotificationAction
|
||||||
import com.zaneschepke.wireguardautotunnel.service.notification.NotificationService
|
import com.zaneschepke.wireguardautotunnel.service.notification.NotificationService
|
||||||
import com.zaneschepke.wireguardautotunnel.service.notification.WireGuardNotification
|
import com.zaneschepke.wireguardautotunnel.service.notification.WireGuardNotification
|
||||||
|
import com.zaneschepke.wireguardautotunnel.service.tunnel.BackendState
|
||||||
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
|
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
|
||||||
import com.zaneschepke.wireguardautotunnel.util.Constants
|
import com.zaneschepke.wireguardautotunnel.util.Constants
|
||||||
import com.zaneschepke.wireguardautotunnel.util.extensions.TunnelConfigs
|
import com.zaneschepke.wireguardautotunnel.util.extensions.TunnelConfigs
|
||||||
|
@ -111,6 +113,7 @@ class AutoTunnelService : LifecycleService() {
|
||||||
}
|
}
|
||||||
startAutoTunnelJob()
|
startAutoTunnelJob()
|
||||||
startAutoTunnelStateJob()
|
startAutoTunnelStateJob()
|
||||||
|
startKillSwitchJob()
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
Timber.e(it)
|
Timber.e(it)
|
||||||
}
|
}
|
||||||
|
@ -181,7 +184,6 @@ class AutoTunnelService : LifecycleService() {
|
||||||
) { double, networkState ->
|
) { double, networkState ->
|
||||||
AutoTunnelState(tunnelService.get().vpnState.value, networkState, double.first, double.second)
|
AutoTunnelState(tunnelService.get().vpnState.value, networkState, double.first, double.second)
|
||||||
}.collect { state ->
|
}.collect { state ->
|
||||||
Timber.d("Network state: ${state.networkState}")
|
|
||||||
autoTunnelStateFlow.update {
|
autoTunnelStateFlow.update {
|
||||||
it.copy(vpnState = state.vpnState, networkState = state.networkState, settings = state.settings, tunnels = state.tunnels)
|
it.copy(vpnState = state.vpnState, networkState = state.networkState, settings = state.settings, tunnels = state.tunnels)
|
||||||
}
|
}
|
||||||
|
@ -209,6 +211,23 @@ class AutoTunnelService : LifecycleService() {
|
||||||
}.distinctUntilChanged()
|
}.distinctUntilChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun startKillSwitchJob() = lifecycleScope.launch(ioDispatcher) {
|
||||||
|
autoTunnelStateFlow.collect {
|
||||||
|
if (it == defaultState) return@collect
|
||||||
|
when (val event = it.asKillSwitchEvent()) {
|
||||||
|
KillSwitchEvent.DoNothing -> Unit
|
||||||
|
is KillSwitchEvent.Start -> {
|
||||||
|
Timber.d("Starting kill switch")
|
||||||
|
tunnelService.get().setBackendState(BackendState.KILL_SWITCH_ACTIVE, event.allowedIps)
|
||||||
|
}
|
||||||
|
KillSwitchEvent.Stop -> {
|
||||||
|
Timber.d("Stopping kill switch")
|
||||||
|
tunnelService.get().setBackendState(BackendState.SERVICE_ACTIVE, emptySet())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(FlowPreview::class)
|
@OptIn(FlowPreview::class)
|
||||||
private fun startAutoTunnelJob() = lifecycleScope.launch(ioDispatcher) {
|
private fun startAutoTunnelJob() = lifecycleScope.launch(ioDispatcher) {
|
||||||
Timber.i("Starting auto-tunnel network event watcher")
|
Timber.i("Starting auto-tunnel network event watcher")
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model
|
||||||
|
|
||||||
import com.zaneschepke.wireguardautotunnel.data.domain.Settings
|
import com.zaneschepke.wireguardautotunnel.data.domain.Settings
|
||||||
import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
|
import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
|
||||||
|
import com.zaneschepke.wireguardautotunnel.service.tunnel.BackendState
|
||||||
import com.zaneschepke.wireguardautotunnel.service.tunnel.VpnState
|
import com.zaneschepke.wireguardautotunnel.service.tunnel.VpnState
|
||||||
import com.zaneschepke.wireguardautotunnel.util.extensions.TunnelConfigs
|
import com.zaneschepke.wireguardautotunnel.util.extensions.TunnelConfigs
|
||||||
import com.zaneschepke.wireguardautotunnel.util.extensions.isMatchingToWildcardList
|
import com.zaneschepke.wireguardautotunnel.util.extensions.isMatchingToWildcardList
|
||||||
|
@ -52,6 +53,14 @@ data class AutoTunnelState(
|
||||||
return networkState.isEthernetConnected && !settings.isTunnelOnEthernetEnabled && vpnState.status.isUp()
|
return networkState.isEthernetConnected && !settings.isTunnelOnEthernetEnabled && vpnState.status.isUp()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun stopKillSwitchOnTrusted(): Boolean {
|
||||||
|
return networkState.isWifiConnected && settings.isVpnKillSwitchEnabled && settings.isDisableKillSwitchOnTrustedEnabled && isCurrentSSIDTrusted() && vpnState.backendState == BackendState.KILL_SWITCH_ACTIVE
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startKillSwitch(): Boolean {
|
||||||
|
return settings.isVpnKillSwitchEnabled && vpnState.backendState != BackendState.KILL_SWITCH_ACTIVE && (!settings.isDisableKillSwitchOnTrustedEnabled || !isCurrentSSIDTrusted())
|
||||||
|
}
|
||||||
|
|
||||||
fun isNoConnectivity(): Boolean {
|
fun isNoConnectivity(): Boolean {
|
||||||
return !networkState.isEthernetConnected && !networkState.isWifiConnected && !networkState.isMobileDataConnected
|
return !networkState.isEthernetConnected && !networkState.isWifiConnected && !networkState.isMobileDataConnected
|
||||||
}
|
}
|
||||||
|
@ -116,6 +125,17 @@ data class AutoTunnelState(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun asKillSwitchEvent(): KillSwitchEvent {
|
||||||
|
return when {
|
||||||
|
stopKillSwitchOnTrusted() -> KillSwitchEvent.Stop
|
||||||
|
startKillSwitch() -> {
|
||||||
|
val allowedIps = if (settings.isLanOnKillSwitchEnabled) TunnelConfig.LAN_BYPASS_ALLOWED_IPS else emptySet()
|
||||||
|
KillSwitchEvent.Start(allowedIps)
|
||||||
|
}
|
||||||
|
else -> KillSwitchEvent.DoNothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun isCurrentSSIDTrusted(): Boolean {
|
private fun isCurrentSSIDTrusted(): Boolean {
|
||||||
return networkState.wifiName?.let {
|
return networkState.wifiName?.let {
|
||||||
hasTrustedWifiName(it)
|
hasTrustedWifiName(it)
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.model
|
||||||
|
|
||||||
|
sealed class KillSwitchEvent {
|
||||||
|
data class Start(val allowedIps: Set<String>) : KillSwitchEvent()
|
||||||
|
data object Stop : KillSwitchEvent()
|
||||||
|
data object DoNothing : KillSwitchEvent()
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import com.zaneschepke.wireguardautotunnel.service.tunnel.statistics.TunnelStati
|
||||||
|
|
||||||
data class VpnState(
|
data class VpnState(
|
||||||
val status: TunnelState = TunnelState.DOWN,
|
val status: TunnelState = TunnelState.DOWN,
|
||||||
|
val backendState: BackendState = BackendState.INACTIVE,
|
||||||
val tunnelConfig: TunnelConfig? = null,
|
val tunnelConfig: TunnelConfig? = null,
|
||||||
val statistics: TunnelStatistics? = null,
|
val statistics: TunnelStatistics? = null,
|
||||||
)
|
)
|
||||||
|
|
|
@ -222,6 +222,9 @@ constructor(
|
||||||
when (val backend = backend()) {
|
when (val backend = backend()) {
|
||||||
is org.amnezia.awg.backend.Backend -> {
|
is org.amnezia.awg.backend.Backend -> {
|
||||||
backend.setBackendState(backendState.asAmBackendState(), allowedIps)
|
backend.setBackendState(backendState.asAmBackendState(), allowedIps)
|
||||||
|
_vpnState.update {
|
||||||
|
it.copy(backendState = backendState)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is Backend -> {
|
is Backend -> {
|
||||||
// TODO not yet implemented
|
// TODO not yet implemented
|
||||||
|
|
|
@ -198,7 +198,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
composable<Route.AutoTunnel> {
|
composable<Route.AutoTunnel> {
|
||||||
AutoTunnelScreen(
|
AutoTunnelScreen(
|
||||||
appUiState,
|
appUiState.settings,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
composable<Route.Appearance> {
|
composable<Route.Appearance> {
|
||||||
|
@ -214,7 +214,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
SupportScreen(appUiState, viewModel)
|
SupportScreen(appUiState, viewModel)
|
||||||
}
|
}
|
||||||
composable<Route.AutoTunnelAdvanced> {
|
composable<Route.AutoTunnelAdvanced> {
|
||||||
AdvancedScreen(appUiState, viewModel)
|
AdvancedScreen(appUiState.settings, viewModel)
|
||||||
}
|
}
|
||||||
composable<Route.Logs> {
|
composable<Route.Logs> {
|
||||||
LogsScreen()
|
LogsScreen()
|
||||||
|
|
|
@ -21,6 +21,7 @@ import androidx.compose.material.icons.outlined.Security
|
||||||
import androidx.compose.material.icons.outlined.Settings
|
import androidx.compose.material.icons.outlined.Settings
|
||||||
import androidx.compose.material.icons.outlined.SettingsEthernet
|
import androidx.compose.material.icons.outlined.SettingsEthernet
|
||||||
import androidx.compose.material.icons.outlined.SignalCellular4Bar
|
import androidx.compose.material.icons.outlined.SignalCellular4Bar
|
||||||
|
import androidx.compose.material.icons.outlined.VpnKeyOff
|
||||||
import androidx.compose.material.icons.outlined.Wifi
|
import androidx.compose.material.icons.outlined.Wifi
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
@ -42,7 +43,7 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||||
import com.google.accompanist.permissions.isGranted
|
import com.google.accompanist.permissions.isGranted
|
||||||
import com.google.accompanist.permissions.rememberPermissionState
|
import com.google.accompanist.permissions.rememberPermissionState
|
||||||
import com.zaneschepke.wireguardautotunnel.R
|
import com.zaneschepke.wireguardautotunnel.R
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.AppUiState
|
import com.zaneschepke.wireguardautotunnel.data.domain.Settings
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.Route
|
import com.zaneschepke.wireguardautotunnel.ui.Route
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.common.button.ScaledSwitch
|
import com.zaneschepke.wireguardautotunnel.ui.common.button.ScaledSwitch
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
|
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
|
||||||
|
@ -64,7 +65,7 @@ import com.zaneschepke.wireguardautotunnel.util.extensions.scaledWidth
|
||||||
|
|
||||||
@OptIn(ExperimentalPermissionsApi::class, ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalPermissionsApi::class, ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun AutoTunnelScreen(uiState: AppUiState, viewModel: AutoTunnelViewModel = hiltViewModel()) {
|
fun AutoTunnelScreen(settings: Settings, viewModel: AutoTunnelViewModel = hiltViewModel()) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val navController = LocalNavController.current
|
val navController = LocalNavController.current
|
||||||
|
|
||||||
|
@ -103,7 +104,7 @@ fun AutoTunnelScreen(uiState: AppUiState, viewModel: AutoTunnelViewModel = hiltV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(uiState.settings.trustedNetworkSSIDs) {
|
LaunchedEffect(settings.trustedNetworkSSIDs) {
|
||||||
currentText = ""
|
currentText = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,15 +155,15 @@ fun AutoTunnelScreen(uiState: AppUiState, viewModel: AutoTunnelViewModel = hiltV
|
||||||
},
|
},
|
||||||
trailing = {
|
trailing = {
|
||||||
ScaledSwitch(
|
ScaledSwitch(
|
||||||
enabled = !uiState.settings.isAlwaysOnVpnEnabled,
|
enabled = !settings.isAlwaysOnVpnEnabled,
|
||||||
checked = uiState.settings.isTunnelOnWifiEnabled,
|
checked = settings.isTunnelOnWifiEnabled,
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.onToggleTunnelOnWifi()
|
viewModel.onToggleTunnelOnWifi(settings)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.onToggleTunnelOnWifi()
|
viewModel.onToggleTunnelOnWifi(settings)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SelectionItem(
|
SelectionItem(
|
||||||
|
@ -181,19 +182,19 @@ fun AutoTunnelScreen(uiState: AppUiState, viewModel: AutoTunnelViewModel = hiltV
|
||||||
},
|
},
|
||||||
trailing = {
|
trailing = {
|
||||||
ScaledSwitch(
|
ScaledSwitch(
|
||||||
checked = uiState.settings.isWifiNameByShellEnabled,
|
checked = settings.isWifiNameByShellEnabled,
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.onRootShellWifiToggle()
|
viewModel.onRootShellWifiToggle(settings)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.onRootShellWifiToggle()
|
viewModel.onRootShellWifiToggle(settings)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if (uiState.settings.isTunnelOnWifiEnabled) {
|
if (settings.isTunnelOnWifiEnabled) {
|
||||||
addAll(
|
addAll(
|
||||||
listOf(
|
listOf(
|
||||||
SelectionItem(
|
SelectionItem(
|
||||||
|
@ -209,14 +210,14 @@ fun AutoTunnelScreen(uiState: AppUiState, viewModel: AutoTunnelViewModel = hiltV
|
||||||
},
|
},
|
||||||
trailing = {
|
trailing = {
|
||||||
ScaledSwitch(
|
ScaledSwitch(
|
||||||
checked = uiState.settings.isWildcardsEnabled,
|
checked = settings.isWildcardsEnabled,
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.onToggleWildcards()
|
viewModel.onToggleWildcards(settings)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.onToggleWildcards()
|
viewModel.onToggleWildcards(settings)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SelectionItem(
|
SelectionItem(
|
||||||
|
@ -255,21 +256,44 @@ fun AutoTunnelScreen(uiState: AppUiState, viewModel: AutoTunnelViewModel = hiltV
|
||||||
},
|
},
|
||||||
description = {
|
description = {
|
||||||
TrustedNetworkTextBox(
|
TrustedNetworkTextBox(
|
||||||
uiState.settings.trustedNetworkSSIDs,
|
settings.trustedNetworkSSIDs,
|
||||||
onDelete = viewModel::onDeleteTrustedSSID,
|
onDelete = { viewModel.onDeleteTrustedSSID(it, settings) },
|
||||||
currentText = currentText,
|
currentText = currentText,
|
||||||
onSave = { ssid ->
|
onSave = { ssid ->
|
||||||
if (uiState.settings.isWifiNameByShellEnabled || isWifiNameReadable()) viewModel.onSaveTrustedSSID(ssid)
|
if (settings.isWifiNameByShellEnabled || isWifiNameReadable()) viewModel.onSaveTrustedSSID(ssid, settings)
|
||||||
},
|
},
|
||||||
onValueChange = { currentText = it },
|
onValueChange = { currentText = it },
|
||||||
supporting = {
|
supporting = {
|
||||||
if (uiState.settings.isWildcardsEnabled) {
|
if (settings.isWildcardsEnabled) {
|
||||||
WildcardsLabel()
|
WildcardsLabel()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
SelectionItem(
|
||||||
|
Icons.Outlined.VpnKeyOff,
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.kill_switch_off),
|
||||||
|
style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
description = {
|
||||||
|
},
|
||||||
|
trailing = {
|
||||||
|
ScaledSwitch(
|
||||||
|
enabled = settings.isVpnKillSwitchEnabled,
|
||||||
|
checked = settings.isDisableKillSwitchOnTrustedEnabled,
|
||||||
|
onClick = {
|
||||||
|
viewModel.onToggleStopKillSwitchOnTrusted(settings)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
viewModel.onToggleStopKillSwitchOnTrusted(settings)
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -287,13 +311,13 @@ fun AutoTunnelScreen(uiState: AppUiState, viewModel: AutoTunnelViewModel = hiltV
|
||||||
},
|
},
|
||||||
trailing = {
|
trailing = {
|
||||||
ScaledSwitch(
|
ScaledSwitch(
|
||||||
enabled = !uiState.settings.isAlwaysOnVpnEnabled,
|
enabled = !settings.isAlwaysOnVpnEnabled,
|
||||||
checked = uiState.settings.isTunnelOnMobileDataEnabled,
|
checked = settings.isTunnelOnMobileDataEnabled,
|
||||||
onClick = { viewModel.onToggleTunnelOnMobileData() },
|
onClick = { viewModel.onToggleTunnelOnMobileData(settings) },
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.onToggleTunnelOnMobileData()
|
viewModel.onToggleTunnelOnMobileData(settings)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SelectionItem(
|
SelectionItem(
|
||||||
|
@ -306,13 +330,13 @@ fun AutoTunnelScreen(uiState: AppUiState, viewModel: AutoTunnelViewModel = hiltV
|
||||||
},
|
},
|
||||||
trailing = {
|
trailing = {
|
||||||
ScaledSwitch(
|
ScaledSwitch(
|
||||||
enabled = !uiState.settings.isAlwaysOnVpnEnabled,
|
enabled = !settings.isAlwaysOnVpnEnabled,
|
||||||
checked = uiState.settings.isTunnelOnEthernetEnabled,
|
checked = settings.isTunnelOnEthernetEnabled,
|
||||||
onClick = { viewModel.onToggleTunnelOnEthernet() },
|
onClick = { viewModel.onToggleTunnelOnEthernet(settings) },
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.onToggleTunnelOnEthernet()
|
viewModel.onToggleTunnelOnEthernet(settings)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SelectionItem(
|
SelectionItem(
|
||||||
|
@ -331,12 +355,12 @@ fun AutoTunnelScreen(uiState: AppUiState, viewModel: AutoTunnelViewModel = hiltV
|
||||||
},
|
},
|
||||||
trailing = {
|
trailing = {
|
||||||
ScaledSwitch(
|
ScaledSwitch(
|
||||||
checked = uiState.settings.isStopOnNoInternetEnabled,
|
checked = settings.isStopOnNoInternetEnabled,
|
||||||
onClick = { viewModel.onToggleStopOnNoInternet() },
|
onClick = { viewModel.onToggleStopOnNoInternet(settings) },
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.onToggleStopOnNoInternet()
|
viewModel.onToggleStopOnNoInternet(settings)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -12,8 +12,6 @@ import com.zaneschepke.wireguardautotunnel.ui.common.snackbar.SnackbarController
|
||||||
import com.zaneschepke.wireguardautotunnel.util.StringValue
|
import com.zaneschepke.wireguardautotunnel.util.StringValue
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -28,11 +26,8 @@ constructor(
|
||||||
@IoDispatcher private val ioDispatcher: CoroutineDispatcher,
|
@IoDispatcher private val ioDispatcher: CoroutineDispatcher,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val settings = appDataRepository.settings.getSettingsFlow()
|
fun onToggleTunnelOnWifi(settings: Settings) = viewModelScope.launch {
|
||||||
.stateIn(viewModelScope, SharingStarted.Eagerly, Settings())
|
with(settings) {
|
||||||
|
|
||||||
fun onToggleTunnelOnWifi() = viewModelScope.launch {
|
|
||||||
with(settings.value) {
|
|
||||||
appDataRepository.settings.save(
|
appDataRepository.settings.save(
|
||||||
copy(
|
copy(
|
||||||
isTunnelOnWifiEnabled = !isTunnelOnWifiEnabled,
|
isTunnelOnWifiEnabled = !isTunnelOnWifiEnabled,
|
||||||
|
@ -41,8 +36,8 @@ constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onToggleTunnelOnMobileData() = viewModelScope.launch {
|
fun onToggleTunnelOnMobileData(settings: Settings) = viewModelScope.launch {
|
||||||
with(settings.value) {
|
with(settings) {
|
||||||
appDataRepository.settings.save(
|
appDataRepository.settings.save(
|
||||||
copy(
|
copy(
|
||||||
isTunnelOnMobileDataEnabled = !isTunnelOnMobileDataEnabled,
|
isTunnelOnMobileDataEnabled = !isTunnelOnMobileDataEnabled,
|
||||||
|
@ -51,8 +46,8 @@ constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onToggleWildcards() = viewModelScope.launch {
|
fun onToggleWildcards(settings: Settings) = viewModelScope.launch {
|
||||||
with(settings.value) {
|
with(settings) {
|
||||||
appDataRepository.settings.save(
|
appDataRepository.settings.save(
|
||||||
copy(
|
copy(
|
||||||
isWildcardsEnabled = !isWildcardsEnabled,
|
isWildcardsEnabled = !isWildcardsEnabled,
|
||||||
|
@ -61,8 +56,8 @@ constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onDeleteTrustedSSID(ssid: String) = viewModelScope.launch {
|
fun onDeleteTrustedSSID(ssid: String, settings: Settings) = viewModelScope.launch {
|
||||||
with(settings.value) {
|
with(settings) {
|
||||||
appDataRepository.settings.save(
|
appDataRepository.settings.save(
|
||||||
copy(
|
copy(
|
||||||
trustedNetworkSSIDs = (trustedNetworkSSIDs - ssid).toMutableList(),
|
trustedNetworkSSIDs = (trustedNetworkSSIDs - ssid).toMutableList(),
|
||||||
|
@ -71,9 +66,9 @@ constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onRootShellWifiToggle() = viewModelScope.launch {
|
fun onRootShellWifiToggle(settings: Settings) = viewModelScope.launch {
|
||||||
requestRoot().onSuccess {
|
requestRoot().onSuccess {
|
||||||
with(settings.value) {
|
with(settings) {
|
||||||
appDataRepository.settings.save(
|
appDataRepository.settings.save(
|
||||||
copy(isWifiNameByShellEnabled = !isWifiNameByShellEnabled),
|
copy(isWifiNameByShellEnabled = !isWifiNameByShellEnabled),
|
||||||
)
|
)
|
||||||
|
@ -92,8 +87,8 @@ constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onToggleTunnelOnEthernet() = viewModelScope.launch {
|
fun onToggleTunnelOnEthernet(settings: Settings) = viewModelScope.launch {
|
||||||
with(settings.value) {
|
with(settings) {
|
||||||
appDataRepository.settings.save(
|
appDataRepository.settings.save(
|
||||||
copy(
|
copy(
|
||||||
isTunnelOnEthernetEnabled = !isTunnelOnEthernetEnabled,
|
isTunnelOnEthernetEnabled = !isTunnelOnEthernetEnabled,
|
||||||
|
@ -102,13 +97,16 @@ constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onSaveTrustedSSID(ssid: String) = viewModelScope.launch {
|
fun onSaveTrustedSSID(ssid: String, settings: Settings) = viewModelScope.launch {
|
||||||
if (ssid.isEmpty()) return@launch
|
if (ssid.isEmpty()) return@launch
|
||||||
val trimmed = ssid.trim()
|
val trimmed = ssid.trim()
|
||||||
with(settings.value) {
|
with(settings) {
|
||||||
if (!trustedNetworkSSIDs.contains(trimmed)) {
|
if (!trustedNetworkSSIDs.contains(trimmed)) {
|
||||||
this.trustedNetworkSSIDs.add(ssid)
|
appDataRepository.settings.save(
|
||||||
appDataRepository.settings.save(this)
|
settings.copy(
|
||||||
|
trustedNetworkSSIDs = (trustedNetworkSSIDs + ssid).toMutableList(),
|
||||||
|
),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
SnackbarController.showMessage(
|
SnackbarController.showMessage(
|
||||||
StringValue.StringResource(
|
StringValue.StringResource(
|
||||||
|
@ -119,11 +117,19 @@ constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onToggleStopOnNoInternet() = viewModelScope.launch {
|
fun onToggleStopOnNoInternet(settings: Settings) = viewModelScope.launch {
|
||||||
with(settings.value) {
|
with(settings) {
|
||||||
appDataRepository.settings.save(
|
appDataRepository.settings.save(
|
||||||
copy(isStopOnNoInternetEnabled = !isStopOnNoInternetEnabled),
|
copy(isStopOnNoInternetEnabled = !isStopOnNoInternetEnabled),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onToggleStopKillSwitchOnTrusted(settings: Settings) = viewModelScope.launch {
|
||||||
|
with(settings) {
|
||||||
|
appDataRepository.settings.save(
|
||||||
|
copy(isDisableKillSwitchOnTrustedEnabled = !isDisableKillSwitchOnTrustedEnabled),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,7 @@ import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
@ -29,7 +27,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.zaneschepke.wireguardautotunnel.R
|
import com.zaneschepke.wireguardautotunnel.R
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.AppUiState
|
import com.zaneschepke.wireguardautotunnel.data.domain.Settings
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.AppViewModel
|
import com.zaneschepke.wireguardautotunnel.ui.AppViewModel
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
|
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SurfaceSelectionGroupButton
|
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SurfaceSelectionGroupButton
|
||||||
|
@ -38,21 +36,11 @@ import com.zaneschepke.wireguardautotunnel.util.extensions.scaledHeight
|
||||||
import com.zaneschepke.wireguardautotunnel.util.extensions.scaledWidth
|
import com.zaneschepke.wireguardautotunnel.util.extensions.scaledWidth
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AdvancedScreen(appUiState: AppUiState, appViewModel: AppViewModel) {
|
fun AdvancedScreen(settings: Settings, appViewModel: AppViewModel) {
|
||||||
var isDropDownExpanded by remember {
|
var isDropDownExpanded by remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
var selected by remember { mutableIntStateOf(appUiState.settings.debounceDelaySeconds) }
|
|
||||||
|
|
||||||
LaunchedEffect(selected) {
|
|
||||||
if (selected == appUiState.settings.debounceDelaySeconds) return@LaunchedEffect
|
|
||||||
appViewModel.saveSettings(appUiState.settings.copy(debounceDelaySeconds = selected))
|
|
||||||
if (appUiState.settings.isAutoTunnelEnabled) {
|
|
||||||
appViewModel.bounceAutoTunnel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopNavBar(stringResource(R.string.advanced_settings))
|
TopNavBar(stringResource(R.string.advanced_settings))
|
||||||
|
@ -87,7 +75,7 @@ fun AdvancedScreen(appUiState: AppUiState, appViewModel: AppViewModel) {
|
||||||
horizontalArrangement = Arrangement.spacedBy(5.dp, Alignment.CenterHorizontally),
|
horizontalArrangement = Arrangement.spacedBy(5.dp, Alignment.CenterHorizontally),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Text(text = selected.toString(), style = MaterialTheme.typography.bodyMedium)
|
Text(text = settings.debounceDelaySeconds.toString(), style = MaterialTheme.typography.bodyMedium)
|
||||||
val icon = Icons.Default.ArrowDropDown
|
val icon = Icons.Default.ArrowDropDown
|
||||||
Icon(icon, icon.name)
|
Icon(icon, icon.name)
|
||||||
}
|
}
|
||||||
|
@ -107,7 +95,9 @@ fun AdvancedScreen(appUiState: AppUiState, appViewModel: AppViewModel) {
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
isDropDownExpanded = false
|
isDropDownExpanded = false
|
||||||
selected = num
|
appViewModel.saveSettings(
|
||||||
|
settings.copy(debounceDelaySeconds = num),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,4 +205,5 @@
|
||||||
<string name="error_tunnel_start">Failed to starting tunnel</string>
|
<string name="error_tunnel_start">Failed to starting tunnel</string>
|
||||||
<string name="tunnel_control">Tunnel control</string>
|
<string name="tunnel_control">Tunnel control</string>
|
||||||
<string name="auto_tunnel">Auto-tunnel</string>
|
<string name="auto_tunnel">Auto-tunnel</string>
|
||||||
|
<string name="kill_switch_off">Stop kill switch on trusted</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue