diff --git a/app/schemas/com.zaneschepke.wireguardautotunnel.data.AppDatabase/12.json b/app/schemas/com.zaneschepke.wireguardautotunnel.data.AppDatabase/12.json
new file mode 100644
index 00000000..dc6d0c9e
--- /dev/null
+++ b/app/schemas/com.zaneschepke.wireguardautotunnel.data.AppDatabase/12.json
@@ -0,0 +1,246 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 12,
+ "identityHash": "acf79ac5defacda5be6c3f976e777de3",
+ "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)",
+ "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"
+ }
+ ],
+ "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, 'acf79ac5defacda5be6c3f976e777de3')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/AppDatabase.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/AppDatabase.kt
index 052a5d7e..0df62b46 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/AppDatabase.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/AppDatabase.kt
@@ -11,7 +11,7 @@ import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
@Database(
entities = [Settings::class, TunnelConfig::class],
- version = 11,
+ version = 12,
autoMigrations =
[
AutoMigration(from = 1, to = 2),
@@ -41,6 +41,10 @@ import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
to = 11,
spec = RemoveTunnelPauseMigration::class,
),
+ AutoMigration(
+ from = 11,
+ to = 12,
+ ),
],
exportSchema = true,
)
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/TunnelConfigDao.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/TunnelConfigDao.kt
index cbb520a6..f3fb52e6 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/TunnelConfigDao.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/TunnelConfigDao.kt
@@ -44,6 +44,9 @@ interface TunnelConfigDao {
@Query("UPDATE TunnelConfig SET is_mobile_data_tunnel = 0 WHERE is_mobile_data_tunnel =1")
suspend fun resetMobileDataTunnel()
+ @Query("UPDATE TunnelConfig SET is_ethernet_tunnel = 0 WHERE is_ethernet_tunnel =1")
+ suspend fun resetEthernetTunnel()
+
@Query("SELECT * FROM TUNNELCONFIG WHERE is_primary_tunnel=1")
suspend fun findByPrimary(): TunnelConfigs
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/domain/Settings.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/domain/Settings.kt
index aceda142..345198ba 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/domain/Settings.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/domain/Settings.kt
@@ -60,4 +60,9 @@ data class Settings(
defaultValue = "false",
)
val isWifiNameByShellEnabled: Boolean = false,
+ @ColumnInfo(
+ name = "is_stop_on_no_internet_enabled",
+ defaultValue = "false",
+ )
+ val isStopOnNoInternetEnabled: Boolean = false,
)
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/domain/TunnelConfig.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/domain/TunnelConfig.kt
index 028ebc7f..77b899a0 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/domain/TunnelConfig.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/domain/TunnelConfig.kt
@@ -58,6 +58,11 @@ data class TunnelConfig(
defaultValue = "null",
)
var pingIp: String? = null,
+ @ColumnInfo(
+ name = "is_ethernet_tunnel",
+ defaultValue = "false",
+ )
+ var isEthernetTunnel: Boolean = false,
) {
fun toAmConfig(): org.amnezia.awg.config.Config {
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/repository/RoomTunnelConfigRepository.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/repository/RoomTunnelConfigRepository.kt
index eeae7d59..1f058990 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/repository/RoomTunnelConfigRepository.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/repository/RoomTunnelConfigRepository.kt
@@ -53,6 +53,19 @@ class RoomTunnelConfigRepository(
}
}
+ override suspend fun updateEthernetTunnel(tunnelConfig: TunnelConfig?) {
+ withContext(ioDispatcher) {
+ tunnelConfigDao.resetEthernetTunnel()
+ tunnelConfig?.let {
+ save(
+ it.copy(
+ isEthernetTunnel = true,
+ ),
+ )
+ }
+ }
+ }
+
override suspend fun delete(tunnelConfig: TunnelConfig) {
withContext(ioDispatcher) {
tunnelConfigDao.delete(tunnelConfig)
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/repository/TunnelConfigRepository.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/repository/TunnelConfigRepository.kt
index a823af51..66a464f1 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/repository/TunnelConfigRepository.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/data/repository/TunnelConfigRepository.kt
@@ -15,6 +15,8 @@ interface TunnelConfigRepository {
suspend fun updateMobileDataTunnel(tunnelConfig: TunnelConfig?)
+ suspend fun updateEthernetTunnel(tunnelConfig: TunnelConfig?)
+
suspend fun delete(tunnelConfig: TunnelConfig)
suspend fun getById(id: Int): TunnelConfig?
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/autotunnel/AutoTunnelEvent.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/autotunnel/AutoTunnelEvent.kt
index dbe7c14a..5a08de33 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/autotunnel/AutoTunnelEvent.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/autotunnel/AutoTunnelEvent.kt
@@ -4,6 +4,6 @@ import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
sealed class AutoTunnelEvent {
data class Start(val tunnelConfig: TunnelConfig? = null) : AutoTunnelEvent()
- data class Stop(val tunnelConfig: TunnelConfig?) : AutoTunnelEvent()
+ data object Stop : AutoTunnelEvent()
data object DoNothing : AutoTunnelEvent()
}
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/autotunnel/AutoTunnelState.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/autotunnel/AutoTunnelState.kt
index b1c9b249..de9b1039 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/autotunnel/AutoTunnelState.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/autotunnel/AutoTunnelState.kt
@@ -26,10 +26,19 @@ data class AutoTunnelState(
vpnState.status.isUp() && preferredTunnel.id != vpnState.tunnelConfig?.id
}
+ private fun isEthernetTunnelChangeNeeded(): Boolean {
+ val preferredTunnel = preferredEthernetTunnel()
+ return preferredTunnel != null && vpnState.status.isUp() && preferredTunnel.id != vpnState.tunnelConfig?.id
+ }
+
private fun preferredMobileDataTunnel(): TunnelConfig? {
return tunnels.firstOrNull { it.isMobileDataTunnel } ?: tunnels.firstOrNull { it.isPrimaryTunnel }
}
+ private fun preferredEthernetTunnel(): TunnelConfig? {
+ return tunnels.firstOrNull { it.isEthernetTunnel } ?: tunnels.firstOrNull { it.isPrimaryTunnel }
+ }
+
private fun preferredWifiTunnel(): TunnelConfig? {
return getTunnelWithMatchingTunnelNetwork() ?: tunnels.firstOrNull { it.isPrimaryTunnel }
}
@@ -42,6 +51,14 @@ data class AutoTunnelState(
return isEthernetConnected && settings.isTunnelOnEthernetEnabled && vpnState.status.isDown()
}
+ private fun stopOnEthernet() : Boolean {
+ return isEthernetConnected && !settings.isTunnelOnEthernetEnabled && vpnState.status.isUp()
+ }
+
+ private fun isNoConnectivity(): Boolean {
+ return !isEthernetConnected && !isWifiConnected && !isMobileDataConnected
+ }
+
private fun stopOnMobileData(): Boolean {
return isMobileDataActive() && !settings.isTunnelOnMobileDataEnabled && vpnState.status.isUp()
}
@@ -54,6 +71,10 @@ data class AutoTunnelState(
return isMobileDataActive() && settings.isTunnelOnMobileDataEnabled && isMobileTunnelDataChangeNeeded()
}
+ private fun changeOnEthernet(): Boolean {
+ return isEthernetConnected && settings.isTunnelOnEthernetEnabled && isEthernetTunnelChangeNeeded()
+ }
+
private fun stopOnWifi(): Boolean {
return isWifiActive() && !settings.isTunnelOnWifiEnabled && vpnState.status.isUp()
}
@@ -75,25 +96,23 @@ data class AutoTunnelState(
val vpnTunnel = vpnState.tunnelConfig
return if (preferred != null && vpnTunnel != null) {
preferred.id == vpnTunnel.id
- } else {
- true
- }
+ } else true
}
- // TODO add shutdown on no connectivity
fun asAutoTunnelEvent(): AutoTunnelEvent {
return when {
// ethernet scenarios
- startOnEthernet() -> AutoTunnelEvent.Start()
+ stopOnEthernet() -> AutoTunnelEvent.Stop
+ startOnEthernet() || changeOnEthernet() -> AutoTunnelEvent.Start(preferredEthernetTunnel())
// mobile data scenarios
- stopOnMobileData() -> AutoTunnelEvent.Stop(vpnState.tunnelConfig)
- startOnMobileData() -> AutoTunnelEvent.Start(tunnels.firstOrNull { it.isMobileDataTunnel })
- changeOnMobileData() -> AutoTunnelEvent.Start(preferredMobileDataTunnel())
+ stopOnMobileData() -> AutoTunnelEvent.Stop
+ startOnMobileData() || changeOnMobileData() -> AutoTunnelEvent.Start(preferredMobileDataTunnel())
// wifi scenarios
- stopOnWifi() -> AutoTunnelEvent.Stop(vpnState.tunnelConfig)
- stopOnTrustedWifi() -> AutoTunnelEvent.Stop(vpnState.tunnelConfig)
- startOnUntrustedWifi() -> AutoTunnelEvent.Start(preferredWifiTunnel())
- changeOnUntrustedWifi() -> AutoTunnelEvent.Start(preferredWifiTunnel())
+ stopOnWifi() -> AutoTunnelEvent.Stop
+ stopOnTrustedWifi() -> AutoTunnelEvent.Stop
+ startOnUntrustedWifi() || changeOnUntrustedWifi() -> AutoTunnelEvent.Start(preferredWifiTunnel())
+ // no connectivity
+ isNoConnectivity() && settings.isStopOnNoInternetEnabled -> AutoTunnelEvent.Stop
else -> AutoTunnelEvent.DoNothing
}
}
@@ -101,18 +120,14 @@ data class AutoTunnelState(
private fun isCurrentSSIDTrusted(): Boolean {
return if (settings.isWildcardsEnabled) {
settings.trustedNetworkSSIDs.isMatchingToWildcardList(currentNetworkSSID)
- } else {
- settings.trustedNetworkSSIDs.contains(currentNetworkSSID)
- }
+ } else settings.trustedNetworkSSIDs.contains(currentNetworkSSID)
}
private fun getTunnelWithMatchingTunnelNetwork(): TunnelConfig? {
return tunnels.firstOrNull {
if (settings.isWildcardsEnabled) {
it.tunnelNetworks.isMatchingToWildcardList(currentNetworkSSID)
- } else {
- it.tunnelNetworks.contains(currentNetworkSSID)
- }
+ } else it.tunnelNetworks.contains(currentNetworkSSID)
}
}
}
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/components/TunnelRowItem.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/components/TunnelRowItem.kt
index 11e2cd4d..741cb084 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/components/TunnelRowItem.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/components/TunnelRowItem.kt
@@ -9,6 +9,7 @@ import androidx.compose.material.icons.rounded.CopyAll
import androidx.compose.material.icons.rounded.Delete
import androidx.compose.material.icons.rounded.Info
import androidx.compose.material.icons.rounded.Settings
+import androidx.compose.material.icons.rounded.SettingsEthernet
import androidx.compose.material.icons.rounded.Smartphone
import androidx.compose.material.icons.rounded.Star
import androidx.compose.material3.Icon
@@ -55,14 +56,12 @@ fun TunnelRowItem(
val itemFocusRequester = remember { FocusRequester() }
ExpandingRowListItem(
leading = {
- val icon =
- if (tunnel.isPrimaryTunnel) {
- Icons.Rounded.Star
- } else if (tunnel.isMobileDataTunnel) {
- Icons.Rounded.Smartphone
- } else {
- Icons.Rounded.Circle
- }
+ val icon = when {
+ tunnel.isPrimaryTunnel -> Icons.Rounded.Star
+ tunnel.isMobileDataTunnel -> Icons.Rounded.Smartphone
+ tunnel.isEthernetTunnel -> Icons.Rounded.SettingsEthernet
+ else -> Icons.Rounded.Circle
+ }
Icon(
icon,
icon.name,
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/options/OptionsScreen.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/options/OptionsScreen.kt
index 480a811c..3bd321eb 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/options/OptionsScreen.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/options/OptionsScreen.kt
@@ -15,6 +15,7 @@ import androidx.compose.material.icons.outlined.Edit
import androidx.compose.material.icons.outlined.NetworkPing
import androidx.compose.material.icons.outlined.PhoneAndroid
import androidx.compose.material.icons.outlined.Security
+import androidx.compose.material.icons.outlined.SettingsEthernet
import androidx.compose.material.icons.outlined.Star
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@@ -139,6 +140,28 @@ fun OptionsScreen(optionsViewModel: OptionsViewModel = hiltViewModel(), appUiSta
},
onClick = { optionsViewModel.onToggleIsMobileDataTunnel(config) },
),
+ SelectionItem(
+ Icons.Outlined.SettingsEthernet,
+ title = {
+ Text(
+ stringResource(R.string.ethernet_tunnel),
+ style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
+ )
+ },
+ description = {
+ Text(
+ stringResource(R.string.set_ethernet_tunnel),
+ style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.outline),
+ )
+ },
+ trailing = {
+ ScaledSwitch(
+ config.isEthernetTunnel,
+ onClick = { optionsViewModel.onToggleIsEthernetTunnel(config) },
+ )
+ },
+ onClick = { optionsViewModel.onToggleIsEthernetTunnel(config) },
+ ),
SelectionItem(
Icons.Outlined.NetworkPing,
title = {
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/options/OptionsViewModel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/options/OptionsViewModel.kt
index 6fc4f967..e1bfaa5c 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/options/OptionsViewModel.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/options/OptionsViewModel.kt
@@ -77,4 +77,12 @@ constructor(
),
)
}
+
+ fun onToggleIsEthernetTunnel(tunnelConfig: TunnelConfig) = viewModelScope.launch {
+ if (tunnelConfig.isEthernetTunnel) {
+ appDataRepository.tunnels.updateEthernetTunnel(null)
+ } else {
+ appDataRepository.tunnels.updateEthernetTunnel(tunnelConfig)
+ }
+ }
}
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/autotunnel/AutoTunnelScreen.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/autotunnel/AutoTunnelScreen.kt
index a6094c6c..6a741277 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/autotunnel/AutoTunnelScreen.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/autotunnel/AutoTunnelScreen.kt
@@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.AirplanemodeActive
import androidx.compose.material.icons.outlined.Code
import androidx.compose.material.icons.outlined.Filter1
import androidx.compose.material.icons.outlined.NetworkPing
@@ -323,6 +324,30 @@ fun AutoTunnelScreen(uiState: AppUiState, viewModel: AutoTunnelViewModel = hiltV
viewModel.onToggleRestartOnPing()
},
),
+ SelectionItem(
+ Icons.Outlined.AirplanemodeActive,
+ title = {
+ Text(
+ stringResource(R.string.stop_on_no_internet),
+ style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
+ )
+ },
+ description = {
+ Text(
+ stringResource(R.string.stop_on_internet_loss),
+ style = MaterialTheme.typography.bodySmall.copy(MaterialTheme.colorScheme.outline),
+ )
+ },
+ trailing = {
+ ScaledSwitch(
+ checked = uiState.settings.isStopOnNoInternetEnabled,
+ onClick = { viewModel.onToggleStopOnNoInternet() },
+ )
+ },
+ onClick = {
+ viewModel.onToggleStopOnNoInternet()
+ },
+ ),
),
)
}
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/autotunnel/AutoTunnelViewModel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/autotunnel/AutoTunnelViewModel.kt
index 83104ba2..2ea86423 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/autotunnel/AutoTunnelViewModel.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/autotunnel/AutoTunnelViewModel.kt
@@ -128,4 +128,12 @@ constructor(
)
}
}
+
+ fun onToggleStopOnNoInternet() = viewModelScope.launch {
+ with(settings.value) {
+ appDataRepository.settings.save(
+ copy(isStopOnNoInternetEnabled = !isStopOnNoInternetEnabled),
+ )
+ }
+ }
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 904803b4..299aa92b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -178,4 +178,8 @@
Configuration change
This change requires an app relaunch. Would you like to proceed?
Add from clipboard
+ Stop on no internet
+ Stop tunnel on internet loss
+ Ethernet tunnel
+ Set as ethernet tunnel