Compare commits

..

2 Commits

Author SHA1 Message Date
Zane Schepke 6d30b9a742 fix: revert dns impl 2025-05-01 07:00:18 -04:00
Zane Schepke 2e98878814 revert: tunnel libs versions 2025-04-30 16:11:54 -04:00
159 changed files with 554 additions and 2021 deletions
+15 -20
View File
@@ -4,9 +4,6 @@ permissions:
packages: write
on:
push:
tags:
- '[0-9]*.[0-9]*.[0-9]*'
workflow_dispatch:
inputs:
track:
@@ -52,19 +49,19 @@ on:
jobs:
build-fdroid:
if: ${{ github.event_name == 'push' || inputs.release_type == 'release' || inputs.flavor == 'fdroid' }}
if: ${{ inputs.release_type == 'release' || inputs.flavor == 'fdroid' }}
uses: ./.github/workflows/build.yml
secrets: inherit
with:
build_type: ${{ github.event_name == 'push' && 'release' || inputs.release_type }}
build_type: ${{ inputs.release_type }}
flavor: fdroid
build-standalone:
if: ${{ github.event_name == 'push' || inputs.release_type == 'release' || inputs.release_type == 'prerelease' || inputs.flavor == 'standalone' }}
if: ${{ inputs.release_type == 'release' || inputs.release_type == 'prerelease' || inputs.flavor == 'standalone' }}
uses: ./.github/workflows/build.yml
secrets: inherit
with:
build_type: ${{ github.event_name == 'push' && 'release' || inputs.release_type }}
build_type: ${{ inputs.release_type }}
flavor: standalone
publish:
@@ -75,7 +72,7 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'push' && github.ref || 'main' }}
ref: main
- name: Install system dependencies
run: |
sudo apt update && sudo apt install -y gh apksigner
@@ -116,7 +113,7 @@ jobs:
merge-multiple: true
- name: Set version release notes
if: ${{ github.event_name == 'push' || inputs.release_type == 'release' }}
if: ${{ inputs.release_type == 'release' }}
run: |
VERSION_NAME=$(grep "const val VERSION_NAME" buildSrc/src/main/kotlin/Constants.kt | awk -F'"' '{print $2}')
RELEASE_NOTES="$(cat ${{ github.workspace }}/fastlane/metadata/android/en-US/changelogs/${VERSION_NAME}.txt || echo "No changelog found for ${VERSION_NAME}")"
@@ -125,7 +122,7 @@ jobs:
echo "EOF" >> $GITHUB_ENV
- name: On prerelease release notes
if: ${{ github.event_name != 'push' && inputs.release_type == 'prerelease' }}
if: ${{ inputs.release_type == 'prerelease' }}
run: |
echo "RELEASE_NOTES=Testing version of app for specific feature." >> $GITHUB_ENV
@@ -159,11 +156,11 @@ jobs:
### Changelog
${{ steps.changelog.outputs.changes }}
tag_name: ${{ github.event_name == 'push' && github.ref_name || github.event.inputs.tag_name }}
name: ${{ github.event_name == 'push' && github.ref_name || github.event.inputs.tag_name }}
tag_name: ${{ github.event.inputs.tag_name }}
name: ${{ github.event.inputs.tag_name }}
draft: false
prerelease: ${{ github.event_name != 'push' && inputs.release_type == 'prerelease' }}
make_latest: ${{ github.event_name == 'push' || inputs.release_type == 'release' }}
prerelease: ${{ inputs.release_type == 'prerelease' }}
make_latest: ${{ inputs.release_type == 'release' }}
files: |
${{ github.workspace }}/temp/**/*.apk
env:
@@ -173,17 +170,17 @@ jobs:
runs-on: ubuntu-latest
needs:
- build-fdroid
if: ${{ github.event_name == 'push' || inputs.release_type == 'release' }}
if: inputs.release_type == 'release'
steps:
- name: Dispatch update for fdroid repo
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.PAT }}
token: ${{ secrets.GITHUB_TOKEN }}
repository: wgtunnel/fdroid
event-type: fdroid-update
publish-play:
if: ${{ github.event_name == 'push' || inputs.track != 'none' }}
if: ${{ inputs.track != 'none' }}
name: Publish to Google Play
runs-on: ubuntu-latest
@@ -233,6 +230,4 @@ jobs:
bundler-cache: true
- name: Distribute app to Prod track 🚀
run: |
track=${{ github.event_name == 'push' && 'production' || inputs.track }}
(cd ${{ github.workspace }} && bundle install && bundle exec fastlane $track)
run: (cd ${{ github.workspace }} && bundle install && bundle exec fastlane ${{ inputs.track }})
+1 -8
View File
@@ -123,7 +123,7 @@ android {
licensee {
Constants.allowedLicenses.forEach { allow(it) }
Constants.allowedLicenseUrls.forEach { allowUrl(it) }
allowUrl(Constants.XZING_LICENSE_URL)
}
applicationVariants.all {
@@ -231,10 +231,3 @@ tasks.register<Copy>("copyLicenseeJsonToAssets") {
}
tasks.named("preBuild") { dependsOn("copyLicenseeJsonToAssets") }
// https://gist.github.com/obfusk/61046e09cee352ae6dd109911534b12e#fix-proposed-by-linsui-disable-baseline-profiles
tasks.whenTaskAdded {
if (name.contains("ArtProfile")) {
enabled = false
}
}
@@ -155,7 +155,9 @@
"columnNames": [
"id"
]
}
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "TunnelConfig",
@@ -225,18 +227,21 @@
"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"
},
{
@@ -270,9 +275,11 @@
"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, 'ae51793c4d09ea3194ecd26f0606f35c')"
@@ -1,295 +0,0 @@
{
"formatVersion": 1,
"database": {
"version": 17,
"identityHash": "380d82359c99933cc9ce783347c4ec31",
"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_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, `is_tunnel_on_unsecure_enabled` INTEGER NOT NULL DEFAULT false, `split_tunnel_apps` TEXT NOT NULL DEFAULT '', `wifi_detection_method` INTEGER NOT NULL DEFAULT 0)",
"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": "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"
},
{
"fieldPath": "isTunnelOnUnsecureEnabled",
"columnName": "is_tunnel_on_unsecure_enabled",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
},
{
"fieldPath": "splitTunnelApps",
"columnName": "split_tunnel_apps",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "''"
},
{
"fieldPath": "wifiDetectionMethod",
"columnName": "wifi_detection_method",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
}
},
{
"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, `is_ipv4_preferred` INTEGER NOT NULL DEFAULT true)",
"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",
"defaultValue": "null"
},
{
"fieldPath": "pingCooldown",
"columnName": "ping_cooldown",
"affinity": "INTEGER",
"defaultValue": "null"
},
{
"fieldPath": "pingIp",
"columnName": "ping_ip",
"affinity": "TEXT",
"defaultValue": "null"
},
{
"fieldPath": "isEthernetTunnel",
"columnName": "is_ethernet_tunnel",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
},
{
"fieldPath": "isIpv4Preferred",
"columnName": "is_ipv4_preferred",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "true"
}
],
"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`)"
}
]
}
],
"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, '380d82359c99933cc9ce783347c4ec31')"
]
}
}
@@ -49,7 +49,6 @@ import com.zaneschepke.wireguardautotunnel.ui.navigation.components.DynamicTopAp
import com.zaneschepke.wireguardautotunnel.ui.navigation.components.currentNavBackStackEntryAsNavBarState
import com.zaneschepke.wireguardautotunnel.ui.screens.autotunnel.AutoTunnelScreen
import com.zaneschepke.wireguardautotunnel.ui.screens.autotunnel.advanced.AutoTunnelAdvancedScreen
import com.zaneschepke.wireguardautotunnel.ui.screens.autotunnel.detection.WifiDetectionMethodScreen
import com.zaneschepke.wireguardautotunnel.ui.screens.autotunnel.disclosure.LocationDisclosureScreen
import com.zaneschepke.wireguardautotunnel.ui.screens.main.MainScreen
import com.zaneschepke.wireguardautotunnel.ui.screens.main.autotunnel.TunnelAutoTunnelScreen
@@ -285,9 +284,6 @@ class MainActivity : AppCompatActivity() {
composable<Route.AutoTunnelAdvanced> {
AutoTunnelAdvancedScreen(appUiState, viewModel)
}
composable<Route.WifiDetectionMethod> {
WifiDetectionMethodScreen(appUiState, viewModel)
}
composable<Route.Logs> { LogsScreen(appViewState, viewModel) }
composable<Route.Config> { backStack ->
val args = backStack.toRoute<Route.Config>()
@@ -14,9 +14,9 @@ import com.zaneschepke.wireguardautotunnel.core.notification.NotificationManager
import com.zaneschepke.wireguardautotunnel.core.notification.WireGuardNotification
import com.zaneschepke.wireguardautotunnel.core.tunnel.TunnelManager
import com.zaneschepke.wireguardautotunnel.di.IoDispatcher
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.enums.NotificationAction
import com.zaneschepke.wireguardautotunnel.domain.enums.TunnelStatus
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.repository.TunnelRepository
import com.zaneschepke.wireguardautotunnel.domain.state.TunnelState
import com.zaneschepke.wireguardautotunnel.util.Constants
@@ -15,12 +15,12 @@ import com.zaneschepke.wireguardautotunnel.core.notification.WireGuardNotificati
import com.zaneschepke.wireguardautotunnel.core.service.ServiceManager
import com.zaneschepke.wireguardautotunnel.core.tunnel.TunnelManager
import com.zaneschepke.wireguardautotunnel.di.IoDispatcher
import com.zaneschepke.wireguardautotunnel.domain.entity.AppSettings
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.enums.BackendState
import com.zaneschepke.wireguardautotunnel.domain.enums.NotificationAction
import com.zaneschepke.wireguardautotunnel.domain.events.AutoTunnelEvent
import com.zaneschepke.wireguardautotunnel.domain.events.KillSwitchEvent
import com.zaneschepke.wireguardautotunnel.domain.model.AppSettings
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.repository.AppDataRepository
import com.zaneschepke.wireguardautotunnel.domain.state.AutoTunnelState
import com.zaneschepke.wireguardautotunnel.domain.state.NetworkState
@@ -33,7 +33,6 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
@@ -73,8 +72,6 @@ class AutoTunnelService : LifecycleService() {
private val binder = LocalBinder(this)
private var isServiceRunning = false
override fun onCreate() {
super.onCreate()
launchWatcherNotification()
@@ -93,8 +90,6 @@ class AutoTunnelService : LifecycleService() {
}
fun start() {
if (isServiceRunning) return
isServiceRunning = true
kotlin
.runCatching {
launchWatcherNotification()
@@ -107,7 +102,6 @@ class AutoTunnelService : LifecycleService() {
}
fun stop() {
isServiceRunning = false
wakeLock?.let { if (it.isHeld) it.release() }
stopSelf()
}
@@ -267,44 +261,18 @@ class AutoTunnelService : LifecycleService() {
lifecycleScope.launch(ioDispatcher) {
Timber.i("Starting auto-tunnel network event watcher")
val settings = appDataRepository.get().settings.get()
var reevaluationJob: Job? = null
Timber.d("Starting with debounce delay of: ${settings.debounceDelaySeconds} seconds")
autoTunnelStateFlow.debounce(settings.debounceDelayMillis()).collect { watcherState ->
if (watcherState == defaultState) return@collect
reevaluationJob?.cancel()
handleAutoTunnelEvent(watcherState)
// schedule one-time re-evaluation
reevaluationJob = launch {
delay(REEVALUATE_CHECK_DELAY)
if (watcherState != defaultState) {
Timber.d("Re-evaluating auto-tunnel state..")
handleAutoTunnelEvent(watcherState)
}
Timber.d("New auto tunnel state emitted ${watcherState.networkState}")
when (val event = watcherState.asAutoTunnelEvent()) {
is AutoTunnelEvent.Start ->
(event.tunnelConf ?: appDataRepository.get().getPrimaryOrFirstTunnel())
?.let { tunnelManager.startTunnel(it) }
// TODO improve this to target specific tunnels to better support multi-tunnel
is AutoTunnelEvent.Stop -> tunnelManager.stopTunnel()
AutoTunnelEvent.DoNothing -> Timber.i("Auto-tunneling: no condition met")
}
}
}
private suspend fun handleAutoTunnelEvent(watcherState: AutoTunnelState) {
Timber.i("Auto-tunnel settings: ${watcherState.settings.toAutoTunnelStateString()}")
Timber.i("Auto-tunnel network state: ${watcherState.networkState}")
when (
val event =
watcherState.asAutoTunnelEvent().also {
Timber.i("Auto-tunnel event: ${it.javaClass.simpleName}")
}
) {
is AutoTunnelEvent.Start ->
(event.tunnelConf ?: appDataRepository.get().getPrimaryOrFirstTunnel())?.let {
tunnelManager.startTunnel(it)
}
is AutoTunnelEvent.Stop -> tunnelManager.stopTunnel()
AutoTunnelEvent.DoNothing -> Timber.i("Auto-tunneling: nothing to do")
}
}
companion object {
const val REEVALUATE_CHECK_DELAY = 5_000L
}
}
@@ -13,7 +13,7 @@ import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel
import com.zaneschepke.wireguardautotunnel.core.service.ServiceManager
import com.zaneschepke.wireguardautotunnel.core.tunnel.TunnelManager
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.repository.AppDataRepository
import com.zaneschepke.wireguardautotunnel.domain.state.TunnelState
import dagger.hilt.android.AndroidEntryPoint
@@ -3,9 +3,9 @@ package com.zaneschepke.wireguardautotunnel.core.tunnel
import com.wireguard.android.backend.Tunnel
import com.zaneschepke.wireguardautotunnel.core.service.ServiceManager
import com.zaneschepke.wireguardautotunnel.di.ApplicationScope
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.enums.BackendError
import com.zaneschepke.wireguardautotunnel.domain.enums.TunnelStatus
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.repository.AppDataRepository
import com.zaneschepke.wireguardautotunnel.domain.state.TunnelState
import com.zaneschepke.wireguardautotunnel.domain.state.TunnelStatistics
@@ -114,16 +114,16 @@ abstract class BaseTunnel(
if (this@BaseTunnel is UserspaceTunnel) stopActiveTunnels()
tunMutex.withLock {
tunThreads[tunnelConf.id] = thread {
try {
runBlocking {
runBlocking {
try {
Timber.d("Starting tunnel ${tunnelConf.id}...")
startTunnelInner(tunnelConf)
Timber.d("Started complete for tunnel ${tunnelConf.name}...")
} catch (e: InterruptedException) {
Timber.w(
"Tunnel start has been interrupted as ${tunnelConf.name} failed to start"
)
}
} catch (e: InterruptedException) {
Timber.w(
"Tunnel start has been interrupted as ${tunnelConf.name} failed to start"
)
}
}
}
@@ -1,7 +1,7 @@
package com.zaneschepke.wireguardautotunnel.core.tunnel
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.enums.TunnelStatus
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.state.TunnelState
import kotlinx.coroutines.flow.MutableStateFlow
@@ -5,9 +5,9 @@ import com.wireguard.android.backend.BackendException
import com.wireguard.android.backend.Tunnel
import com.zaneschepke.wireguardautotunnel.core.service.ServiceManager
import com.zaneschepke.wireguardautotunnel.di.ApplicationScope
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.enums.BackendState
import com.zaneschepke.wireguardautotunnel.domain.enums.TunnelStatus
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.repository.AppDataRepository
import com.zaneschepke.wireguardautotunnel.domain.state.TunnelStatistics
import com.zaneschepke.wireguardautotunnel.domain.state.WireGuardStatistics
@@ -4,10 +4,10 @@ import com.zaneschepke.wireguardautotunnel.di.ApplicationScope
import com.zaneschepke.wireguardautotunnel.di.IoDispatcher
import com.zaneschepke.wireguardautotunnel.di.Kernel
import com.zaneschepke.wireguardautotunnel.di.Userspace
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.enums.BackendError
import com.zaneschepke.wireguardautotunnel.domain.enums.BackendState
import com.zaneschepke.wireguardautotunnel.domain.enums.TunnelStatus
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.repository.AppDataRepository
import com.zaneschepke.wireguardautotunnel.domain.state.TunnelStatistics
import java.util.concurrent.ConcurrentHashMap
@@ -1,9 +1,9 @@
package com.zaneschepke.wireguardautotunnel.core.tunnel
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.enums.BackendError
import com.zaneschepke.wireguardautotunnel.domain.enums.BackendState
import com.zaneschepke.wireguardautotunnel.domain.enums.TunnelStatus
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.state.TunnelState
import com.zaneschepke.wireguardautotunnel.domain.state.TunnelStatistics
import java.util.concurrent.ConcurrentHashMap
@@ -2,9 +2,9 @@ package com.zaneschepke.wireguardautotunnel.core.tunnel
import com.zaneschepke.wireguardautotunnel.core.service.ServiceManager
import com.zaneschepke.wireguardautotunnel.di.ApplicationScope
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.enums.BackendState
import com.zaneschepke.wireguardautotunnel.domain.enums.TunnelStatus
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.repository.AppDataRepository
import com.zaneschepke.wireguardautotunnel.domain.state.AmneziaStatistics
import com.zaneschepke.wireguardautotunnel.domain.state.TunnelStatistics
@@ -8,12 +8,12 @@ import androidx.room.TypeConverters
import androidx.room.migration.AutoMigrationSpec
import com.zaneschepke.wireguardautotunnel.data.dao.SettingsDao
import com.zaneschepke.wireguardautotunnel.data.dao.TunnelConfigDao
import com.zaneschepke.wireguardautotunnel.data.entity.Settings
import com.zaneschepke.wireguardautotunnel.data.entity.TunnelConfig
import com.zaneschepke.wireguardautotunnel.data.model.Settings
import com.zaneschepke.wireguardautotunnel.data.model.TunnelConfig
@Database(
entities = [Settings::class, TunnelConfig::class],
version = 17,
version = 16,
autoMigrations =
[
AutoMigration(from = 1, to = 2),
@@ -31,11 +31,10 @@ import com.zaneschepke.wireguardautotunnel.data.entity.TunnelConfig
AutoMigration(from = 13, to = 14),
AutoMigration(from = 14, to = 15),
AutoMigration(from = 15, to = 16),
AutoMigration(from = 16, to = 17, spec = WifiDetectionMigration::class),
],
exportSchema = true,
)
@TypeConverters(DatabaseConverters::class)
@TypeConverters(DatabaseListConverters::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun settingDao(): SettingsDao
@@ -48,6 +47,3 @@ class RemoveLegacySettingColumnsMigration : AutoMigrationSpec
@DeleteColumn(tableName = "Settings", columnName = "is_auto_tunnel_paused")
class RemoveTunnelPauseMigration : AutoMigrationSpec
@DeleteColumn(tableName = "Settings", columnName = "is_wifi_by_shell_enabled")
class WifiDetectionMigration : AutoMigrationSpec
@@ -1,10 +1,9 @@
package com.zaneschepke.wireguardautotunnel.data
import androidx.room.TypeConverter
import com.zaneschepke.wireguardautotunnel.data.entity.Settings
import kotlinx.serialization.json.Json
class DatabaseConverters {
class DatabaseListConverters {
@TypeConverter
fun listToString(value: MutableList<String>): String {
return Json.encodeToString(value)
@@ -21,10 +20,4 @@ class DatabaseConverters {
Json.decodeFromString<MutableList<String>>(json)
}
}
@TypeConverter fun fromStatus(status: Settings.WifiDetectionMethod): Int = status.value
@TypeConverter
fun toStatus(value: Int): Settings.WifiDetectionMethod =
Settings.WifiDetectionMethod.fromValue(value)
}
@@ -5,7 +5,7 @@ import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.zaneschepke.wireguardautotunnel.data.entity.Settings
import com.zaneschepke.wireguardautotunnel.data.model.Settings
import kotlinx.coroutines.flow.Flow
@Dao
@@ -5,7 +5,7 @@ import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.zaneschepke.wireguardautotunnel.data.entity.TunnelConfig
import com.zaneschepke.wireguardautotunnel.data.model.TunnelConfig
import com.zaneschepke.wireguardautotunnel.util.extensions.TunnelConfigs
import kotlinx.coroutines.flow.Flow
@@ -1,24 +0,0 @@
package com.zaneschepke.wireguardautotunnel.data.entity
import com.zaneschepke.wireguardautotunnel.ui.theme.Theme
data class GeneralState(
val isLocationDisclosureShown: Boolean = LOCATION_DISCLOSURE_SHOWN_DEFAULT,
val isBatteryOptimizationDisableShown: Boolean = BATTERY_OPTIMIZATION_DISABLE_SHOWN_DEFAULT,
val isPinLockEnabled: Boolean = PIN_LOCK_ENABLED_DEFAULT,
val expandedTunnelIds: List<Int> = emptyList(),
val isLocalLogsEnabled: Boolean = IS_LOGS_ENABLED_DEFAULT,
val isRemoteControlEnabled: Boolean = IS_REMOTE_CONTROL_ENABLED,
val remoteKey: String? = null,
val locale: String? = null,
val theme: Theme = Theme.AUTOMATIC,
) {
companion object {
const val LOCATION_DISCLOSURE_SHOWN_DEFAULT = false
const val BATTERY_OPTIMIZATION_DISABLE_SHOWN_DEFAULT = false
const val PIN_LOCK_ENABLED_DEFAULT = false
const val IS_LOGS_ENABLED_DEFAULT = false
const val IS_REMOTE_CONTROL_ENABLED = false
}
}
@@ -1,12 +0,0 @@
package com.zaneschepke.wireguardautotunnel.data.entity
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class GitHubRelease(
@SerialName("tag_name") val tagName: String,
val name: String?,
val body: String?,
val assets: List<Asset>,
)
@@ -1,37 +0,0 @@
package com.zaneschepke.wireguardautotunnel.data.mapper
import com.zaneschepke.wireguardautotunnel.data.entity.GeneralState
import com.zaneschepke.wireguardautotunnel.domain.model.AppState
object GeneralStateMapper {
fun toAppState(generalState: GeneralState): AppState =
with(generalState) {
AppState(
isLocationDisclosureShown,
isBatteryOptimizationDisableShown,
isPinLockEnabled,
expandedTunnelIds,
isLocalLogsEnabled,
isRemoteControlEnabled,
remoteKey,
locale,
theme,
)
}
fun toGeneralState(appState: AppState): GeneralState {
return with(appState) {
GeneralState(
isLocationDisclosureShown,
isBatteryOptimizationDisableShown,
isPinLockEnabled,
expandedTunnelIds,
isLocalLogsEnabled,
isRemoteControlEnabled,
remoteKey,
locale,
theme,
)
}
}
}
@@ -1,20 +0,0 @@
package com.zaneschepke.wireguardautotunnel.data.mapper
import com.zaneschepke.wireguardautotunnel.data.entity.GitHubRelease
import com.zaneschepke.wireguardautotunnel.domain.model.AppUpdate
import kotlin.collections.firstOrNull
object GitHubReleaseMapper {
fun toAppUpdate(gitHubRelease: GitHubRelease, newVersion: String): AppUpdate {
with(gitHubRelease) {
val apkAsset = assets.firstOrNull { it.name.endsWith(".apk") }
return AppUpdate(
version = newVersion,
title = name ?: "Update $tagName",
releaseNotes = body ?: "No release notes provided",
apkUrl = apkAsset?.browserDownloadUrl,
apkFileName = apkAsset?.name,
)
}
}
}
@@ -1,67 +0,0 @@
package com.zaneschepke.wireguardautotunnel.data.mapper
import com.zaneschepke.networkmonitor.AndroidNetworkMonitor
import com.zaneschepke.wireguardautotunnel.data.entity.Settings
import com.zaneschepke.wireguardautotunnel.domain.model.AppSettings
object SettingsMapper {
fun toAppSettings(settings: Settings): AppSettings {
return AppSettings(
id = settings.id,
isAutoTunnelEnabled = settings.isAutoTunnelEnabled,
isTunnelOnMobileDataEnabled = settings.isTunnelOnMobileDataEnabled,
trustedNetworkSSIDs = settings.trustedNetworkSSIDs,
isAlwaysOnVpnEnabled = settings.isAlwaysOnVpnEnabled,
isTunnelOnEthernetEnabled = settings.isTunnelOnEthernetEnabled,
isShortcutsEnabled = settings.isShortcutsEnabled,
isTunnelOnWifiEnabled = settings.isTunnelOnWifiEnabled,
isKernelEnabled = settings.isKernelEnabled,
isRestoreOnBootEnabled = settings.isRestoreOnBootEnabled,
isMultiTunnelEnabled = settings.isMultiTunnelEnabled,
isPingEnabled = settings.isPingEnabled,
isAmneziaEnabled = settings.isAmneziaEnabled,
isWildcardsEnabled = settings.isWildcardsEnabled,
isStopOnNoInternetEnabled = settings.isStopOnNoInternetEnabled,
isVpnKillSwitchEnabled = settings.isVpnKillSwitchEnabled,
isKernelKillSwitchEnabled = settings.isKernelKillSwitchEnabled,
isLanOnKillSwitchEnabled = settings.isLanOnKillSwitchEnabled,
debounceDelaySeconds = settings.debounceDelaySeconds,
isDisableKillSwitchOnTrustedEnabled = settings.isDisableKillSwitchOnTrustedEnabled,
isTunnelOnUnsecureEnabled = settings.isTunnelOnUnsecureEnabled,
splitTunnelApps = settings.splitTunnelApps,
wifiDetectionMethod =
AndroidNetworkMonitor.WifiDetectionMethod.fromValue(
settings.wifiDetectionMethod.value
),
)
}
fun toSettings(appSettings: AppSettings): Settings {
return Settings(
id = appSettings.id,
isAutoTunnelEnabled = appSettings.isAutoTunnelEnabled,
isTunnelOnMobileDataEnabled = appSettings.isTunnelOnMobileDataEnabled,
trustedNetworkSSIDs = appSettings.trustedNetworkSSIDs.toMutableList(),
isAlwaysOnVpnEnabled = appSettings.isAlwaysOnVpnEnabled,
isTunnelOnEthernetEnabled = appSettings.isTunnelOnEthernetEnabled,
isShortcutsEnabled = appSettings.isShortcutsEnabled,
isTunnelOnWifiEnabled = appSettings.isTunnelOnWifiEnabled,
isKernelEnabled = appSettings.isKernelEnabled,
isRestoreOnBootEnabled = appSettings.isRestoreOnBootEnabled,
isMultiTunnelEnabled = appSettings.isMultiTunnelEnabled,
isPingEnabled = appSettings.isPingEnabled,
isAmneziaEnabled = appSettings.isAmneziaEnabled,
isWildcardsEnabled = appSettings.isWildcardsEnabled,
isStopOnNoInternetEnabled = appSettings.isStopOnNoInternetEnabled,
isVpnKillSwitchEnabled = appSettings.isVpnKillSwitchEnabled,
isKernelKillSwitchEnabled = appSettings.isKernelKillSwitchEnabled,
isLanOnKillSwitchEnabled = appSettings.isLanOnKillSwitchEnabled,
debounceDelaySeconds = appSettings.debounceDelaySeconds,
isDisableKillSwitchOnTrustedEnabled = appSettings.isDisableKillSwitchOnTrustedEnabled,
isTunnelOnUnsecureEnabled = appSettings.isTunnelOnUnsecureEnabled,
splitTunnelApps = appSettings.splitTunnelApps.toMutableList(),
wifiDetectionMethod =
Settings.WifiDetectionMethod.fromValue(appSettings.wifiDetectionMethod.value),
)
}
}
@@ -1,48 +0,0 @@
package com.zaneschepke.wireguardautotunnel.data.mapper
import com.zaneschepke.wireguardautotunnel.data.entity.TunnelConfig
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
object TunnelConfigMapper {
fun toTunnelConf(tunnelConfig: TunnelConfig): TunnelConf {
return with(tunnelConfig) {
TunnelConf(
id,
name,
wgQuick,
tunnelNetworks,
isMobileDataTunnel,
isPrimaryTunnel,
amQuick,
isActive,
isPingEnabled,
pingInterval,
pingCooldown,
pingIp,
isEthernetTunnel,
isIpv4Preferred,
)
}
}
fun toTunnelConfig(tunnelConf: TunnelConf): TunnelConfig {
return with(tunnelConf) {
TunnelConfig(
id,
tunName,
wgQuick,
tunnelNetworks.toMutableList(),
isMobileDataTunnel,
isPrimaryTunnel,
amQuick,
isActive,
isPingEnabled,
pingInterval,
pingCooldown,
pingIp,
isEthernetTunnel,
isIpv4Preferred,
)
}
}
}
@@ -1,4 +1,4 @@
package com.zaneschepke.wireguardautotunnel.data.entity
package com.zaneschepke.wireguardautotunnel.data.model
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@@ -0,0 +1,54 @@
package com.zaneschepke.wireguardautotunnel.data.model
import com.zaneschepke.wireguardautotunnel.domain.entity.AppState
import com.zaneschepke.wireguardautotunnel.ui.theme.Theme
data class GeneralState(
val isLocationDisclosureShown: Boolean = LOCATION_DISCLOSURE_SHOWN_DEFAULT,
val isBatteryOptimizationDisableShown: Boolean = BATTERY_OPTIMIZATION_DISABLE_SHOWN_DEFAULT,
val isPinLockEnabled: Boolean = PIN_LOCK_ENABLED_DEFAULT,
val expandedTunnelIds: List<Int> = emptyList(),
val isLocalLogsEnabled: Boolean = IS_LOGS_ENABLED_DEFAULT,
val isRemoteControlEnabled: Boolean = IS_REMOTE_CONTROL_ENABLED,
val remoteKey: String? = null,
val locale: String? = null,
val theme: Theme = Theme.AUTOMATIC,
) {
fun toAppState(): AppState =
AppState(
isLocationDisclosureShown,
isBatteryOptimizationDisableShown,
isPinLockEnabled,
expandedTunnelIds,
isLocalLogsEnabled,
isRemoteControlEnabled,
remoteKey,
locale,
theme,
)
companion object {
fun from(appState: AppState): GeneralState {
return with(appState) {
GeneralState(
isLocationDisclosureShown,
isBatteryOptimizationDisableShown,
isPinLockEnabled,
expandedTunnelIds,
isLocalLogsEnabled,
isRemoteControlEnabled,
remoteKey,
locale,
theme,
)
}
}
const val LOCATION_DISCLOSURE_SHOWN_DEFAULT = false
const val BATTERY_OPTIMIZATION_DISABLE_SHOWN_DEFAULT = false
const val PIN_LOCK_ENABLED_DEFAULT = false
const val IS_LOGS_ENABLED_DEFAULT = false
const val IS_REMOTE_CONTROL_ENABLED = false
}
}
@@ -0,0 +1,24 @@
package com.zaneschepke.wireguardautotunnel.data.model
import com.zaneschepke.wireguardautotunnel.domain.entity.AppUpdate
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class GitHubRelease(
@SerialName("tag_name") val tagName: String,
val name: String?,
val body: String?,
val assets: List<Asset>,
) {
fun toAppUpdate(): AppUpdate {
val apkAsset = assets.firstOrNull { it.name.endsWith(".apk") }
return AppUpdate(
version = tagName.removePrefix("v"),
title = name ?: "Update $tagName",
releaseNotes = body ?: "No release notes provided",
apkUrl = apkAsset?.browserDownloadUrl,
apkFileName = apkAsset?.name,
)
}
}
@@ -1,8 +1,9 @@
package com.zaneschepke.wireguardautotunnel.data.entity
package com.zaneschepke.wireguardautotunnel.data.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.zaneschepke.wireguardautotunnel.domain.entity.AppSettings
@Entity
data class Settings(
@@ -31,6 +32,8 @@ data class Settings(
val isAmneziaEnabled: Boolean = false,
@ColumnInfo(name = "is_wildcards_enabled", defaultValue = "false")
val isWildcardsEnabled: Boolean = false,
@ColumnInfo(name = "is_wifi_by_shell_enabled", defaultValue = "false")
val isWifiNameByShellEnabled: Boolean = false,
@ColumnInfo(name = "is_stop_on_no_internet_enabled", defaultValue = "false")
val isStopOnNoInternetEnabled: Boolean = false,
@ColumnInfo(name = "is_vpn_kill_switch_enabled", defaultValue = "false")
@@ -43,23 +46,61 @@ data class Settings(
val debounceDelaySeconds: Int = 3,
@ColumnInfo(name = "is_disable_kill_switch_on_trusted_enabled", defaultValue = "false")
val isDisableKillSwitchOnTrustedEnabled: Boolean = false,
@ColumnInfo(name = "is_tunnel_on_unsecure_enabled", defaultValue = "false")
val isTunnelOnUnsecureEnabled: Boolean = false,
@ColumnInfo(name = "split_tunnel_apps", defaultValue = "")
val splitTunnelApps: MutableList<String> = mutableListOf(),
@ColumnInfo(name = "wifi_detection_method", defaultValue = "0")
val wifiDetectionMethod: WifiDetectionMethod = WifiDetectionMethod.fromValue(0),
) {
enum class WifiDetectionMethod(val value: Int) {
DEFAULT(0),
LEGACY(1),
ROOT(2),
SHIZUKU(3);
fun toAppSettings(): AppSettings {
return AppSettings(
id,
isAutoTunnelEnabled,
isTunnelOnMobileDataEnabled,
trustedNetworkSSIDs,
isAlwaysOnVpnEnabled,
isTunnelOnEthernetEnabled,
isShortcutsEnabled,
isTunnelOnWifiEnabled,
isKernelEnabled,
isRestoreOnBootEnabled,
isMultiTunnelEnabled,
isPingEnabled,
isAmneziaEnabled,
isWildcardsEnabled,
isWifiNameByShellEnabled,
isStopOnNoInternetEnabled,
isVpnKillSwitchEnabled,
isKernelKillSwitchEnabled,
isLanOnKillSwitchEnabled,
debounceDelaySeconds,
isDisableKillSwitchOnTrustedEnabled,
)
}
companion object {
fun fromValue(value: Int): WifiDetectionMethod =
entries.find { it.value == value } ?: DEFAULT
companion object {
fun from(appSettings: AppSettings): Settings {
return with(appSettings) {
Settings(
id,
isAutoTunnelEnabled,
isTunnelOnMobileDataEnabled,
trustedNetworkSSIDs.toMutableList(),
isAlwaysOnVpnEnabled,
isTunnelOnEthernetEnabled,
isShortcutsEnabled,
isTunnelOnWifiEnabled,
isKernelEnabled,
isRestoreOnBootEnabled,
isMultiTunnelEnabled,
isPingEnabled,
isAmneziaEnabled,
isWildcardsEnabled,
isWifiNameByShellEnabled,
isStopOnNoInternetEnabled,
isVpnKillSwitchEnabled,
isKernelKillSwitchEnabled,
isLanOnKillSwitchEnabled,
debounceDelaySeconds,
isDisableKillSwitchOnTrustedEnabled,
)
}
}
}
}
@@ -1,9 +1,10 @@
package com.zaneschepke.wireguardautotunnel.data.entity
package com.zaneschepke.wireguardautotunnel.data.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
@Entity(indices = [Index(value = ["name"], unique = true)])
data class TunnelConfig(
@@ -29,7 +30,48 @@ data class TunnelConfig(
var isIpv4Preferred: Boolean = true,
) {
fun toTunnel(): TunnelConf {
return TunnelConf(
id,
name,
wgQuick,
tunnelNetworks,
isMobileDataTunnel,
isPrimaryTunnel,
amQuick,
isActive,
isPingEnabled,
pingInterval,
pingCooldown,
pingIp,
isEthernetTunnel,
isIpv4Preferred,
)
}
companion object {
const val AM_QUICK_DEFAULT = ""
fun from(tunnelConf: TunnelConf): TunnelConfig {
return with(tunnelConf) {
return TunnelConfig(
id,
tunName,
wgQuick,
tunnelNetworks.toMutableList(),
isMobileDataTunnel,
isPrimaryTunnel,
amQuick,
isActive,
isPingEnabled,
pingInterval,
pingCooldown,
pingIp,
isEthernetTunnel,
isIpv4Preferred,
)
}
}
}
}
@@ -1,6 +1,6 @@
package com.zaneschepke.wireguardautotunnel.data.network
import com.zaneschepke.wireguardautotunnel.data.entity.GitHubRelease
import com.zaneschepke.wireguardautotunnel.data.model.GitHubRelease
interface GitHubApi {
suspend fun getLatestRelease(owner: String, repo: String): Result<GitHubRelease>
@@ -1,6 +1,6 @@
package com.zaneschepke.wireguardautotunnel.data.network
import com.zaneschepke.wireguardautotunnel.data.entity.GitHubRelease
import com.zaneschepke.wireguardautotunnel.data.model.GitHubRelease
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.plugins.ClientRequestException
@@ -1,6 +1,6 @@
package com.zaneschepke.wireguardautotunnel.data.repository
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.repository.AppDataRepository
import com.zaneschepke.wireguardautotunnel.domain.repository.AppSettingRepository
import com.zaneschepke.wireguardautotunnel.domain.repository.AppStateRepository
@@ -1,9 +1,8 @@
package com.zaneschepke.wireguardautotunnel.data.repository
import com.zaneschepke.wireguardautotunnel.data.DataStoreManager
import com.zaneschepke.wireguardautotunnel.data.entity.GeneralState
import com.zaneschepke.wireguardautotunnel.data.mapper.GeneralStateMapper
import com.zaneschepke.wireguardautotunnel.domain.model.AppState
import com.zaneschepke.wireguardautotunnel.data.model.GeneralState
import com.zaneschepke.wireguardautotunnel.domain.entity.AppState
import com.zaneschepke.wireguardautotunnel.domain.repository.AppStateRepository
import com.zaneschepke.wireguardautotunnel.ui.theme.Theme
import kotlinx.coroutines.flow.Flow
@@ -154,5 +153,5 @@ class DataStoreAppStateRepository(private val dataStoreManager: DataStoreManager
}
} ?: GeneralState()
}
.map(GeneralStateMapper::toAppState)
.map { it.toAppState() }
}
@@ -2,12 +2,10 @@ package com.zaneschepke.wireguardautotunnel.data.repository
import android.content.Context
import com.zaneschepke.wireguardautotunnel.BuildConfig
import com.zaneschepke.wireguardautotunnel.data.mapper.GitHubReleaseMapper
import com.zaneschepke.wireguardautotunnel.data.network.GitHubApi
import com.zaneschepke.wireguardautotunnel.di.IoDispatcher
import com.zaneschepke.wireguardautotunnel.domain.model.AppUpdate
import com.zaneschepke.wireguardautotunnel.domain.entity.AppUpdate
import com.zaneschepke.wireguardautotunnel.domain.repository.UpdateRepository
import com.zaneschepke.wireguardautotunnel.util.Constants
import com.zaneschepke.wireguardautotunnel.util.NumberUtils
import io.ktor.client.HttpClient
import io.ktor.client.request.get
@@ -32,30 +30,24 @@ class GitHubUpdateRepository(
override suspend fun checkForUpdate(currentVersion: String): Result<AppUpdate?> =
withContext(ioDispatcher) {
Timber.i("Checking for update")
val isNightly = BuildConfig.VERSION_NAME.contains("nightly")
val release =
if (isNightly) {
gitHubApi.getNightlyRelease(githubOwner, githubRepo).onFailure(Timber::e)
if (BuildConfig.VERSION_NAME.contains("nightly")) {
gitHubApi.getNightlyRelease(githubOwner, githubRepo)
} else {
gitHubApi.getLatestRelease(githubOwner, githubRepo).onFailure(Timber::e)
gitHubApi.getLatestRelease(githubOwner, githubRepo)
}
release.map { release ->
val apkAsset =
release.assets.find { asset ->
asset.name.startsWith("wgtunnel-${Constants.STANDALONE_FLAVOR}-v") &&
asset.name.endsWith(".apk")
asset.name.startsWith("wgtunnel-full-v") && asset.name.endsWith(".apk")
}
val newVersion =
apkAsset
?.name
?.removePrefix("wgtunnel-${Constants.STANDALONE_FLAVOR}-v")
?.removeSuffix(".apk") ?: return@map null
apkAsset?.name?.removePrefix("wgtunnel-full-v")?.removeSuffix(".apk")
?: return@map null
Timber.i("Latest version: $newVersion, current version: $currentVersion")
if (isNightly && newVersion != currentVersion)
return@map GitHubReleaseMapper.toAppUpdate(release, newVersion)
if (NumberUtils.compareVersions(newVersion, currentVersion) > 0) {
GitHubReleaseMapper.toAppUpdate(release, newVersion)
release.toAppUpdate()
} else {
null
}
@@ -1,10 +1,9 @@
package com.zaneschepke.wireguardautotunnel.data.repository
import com.zaneschepke.wireguardautotunnel.data.dao.SettingsDao
import com.zaneschepke.wireguardautotunnel.data.entity.Settings
import com.zaneschepke.wireguardautotunnel.data.mapper.SettingsMapper
import com.zaneschepke.wireguardautotunnel.data.model.Settings
import com.zaneschepke.wireguardautotunnel.di.IoDispatcher
import com.zaneschepke.wireguardautotunnel.domain.model.AppSettings
import com.zaneschepke.wireguardautotunnel.domain.entity.AppSettings
import com.zaneschepke.wireguardautotunnel.domain.repository.AppSettingRepository
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.flowOn
@@ -17,15 +16,15 @@ class RoomSettingsRepository(
) : AppSettingRepository {
override suspend fun save(appSettings: AppSettings) {
withContext(ioDispatcher) { settingsDoa.save(SettingsMapper.toSettings(appSettings)) }
withContext(ioDispatcher) { settingsDoa.save(Settings.from(appSettings)) }
}
override val flow =
settingsDoa.getSettingsFlow().flowOn(ioDispatcher).map(SettingsMapper::toAppSettings)
settingsDoa.getSettingsFlow().flowOn(ioDispatcher).map { it.toAppSettings() }
override suspend fun get(): AppSettings {
return withContext(ioDispatcher) {
SettingsMapper.toAppSettings(settingsDoa.getAll().firstOrNull() ?: Settings())
(settingsDoa.getAll().firstOrNull() ?: Settings()).toAppSettings()
}
}
}
@@ -1,9 +1,9 @@
package com.zaneschepke.wireguardautotunnel.data.repository
import com.zaneschepke.wireguardautotunnel.data.dao.TunnelConfigDao
import com.zaneschepke.wireguardautotunnel.data.mapper.TunnelConfigMapper
import com.zaneschepke.wireguardautotunnel.data.model.TunnelConfig
import com.zaneschepke.wireguardautotunnel.di.IoDispatcher
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.repository.TunnelRepository
import com.zaneschepke.wireguardautotunnel.util.extensions.Tunnels
import kotlinx.coroutines.CoroutineDispatcher
@@ -17,25 +17,19 @@ class RoomTunnelRepository(
) : TunnelRepository {
override val flow =
tunnelConfigDao.getAllFlow().flowOn(ioDispatcher).map {
it.map(TunnelConfigMapper::toTunnelConf)
}
tunnelConfigDao.getAllFlow().flowOn(ioDispatcher).map { it.map { it.toTunnel() } }
override suspend fun getAll(): Tunnels {
return withContext(ioDispatcher) {
tunnelConfigDao.getAll().map(TunnelConfigMapper::toTunnelConf)
}
return withContext(ioDispatcher) { tunnelConfigDao.getAll().map { it.toTunnel() } }
}
override suspend fun save(tunnelConf: TunnelConf) {
withContext(ioDispatcher) {
tunnelConfigDao.save(TunnelConfigMapper.toTunnelConfig(tunnelConf))
}
withContext(ioDispatcher) { tunnelConfigDao.save(TunnelConfig.from(tunnelConf)) }
}
override suspend fun saveAll(tunnelConfList: List<TunnelConf>) {
withContext(ioDispatcher) {
tunnelConfigDao.saveAll(tunnelConfList.map(TunnelConfigMapper::toTunnelConfig))
tunnelConfigDao.saveAll(tunnelConfList.map(TunnelConfig::from))
}
}
@@ -61,21 +55,15 @@ class RoomTunnelRepository(
}
override suspend fun delete(tunnelConf: TunnelConf) {
withContext(ioDispatcher) {
tunnelConfigDao.delete(TunnelConfigMapper.toTunnelConfig(tunnelConf))
}
withContext(ioDispatcher) { tunnelConfigDao.delete(TunnelConfig.from(tunnelConf)) }
}
override suspend fun getById(id: Int): TunnelConf? {
return withContext(ioDispatcher) {
tunnelConfigDao.getById(id.toLong())?.let(TunnelConfigMapper::toTunnelConf)
}
return withContext(ioDispatcher) { tunnelConfigDao.getById(id.toLong())?.toTunnel() }
}
override suspend fun getActive(): Tunnels {
return withContext(ioDispatcher) {
tunnelConfigDao.getActive().map(TunnelConfigMapper::toTunnelConf)
}
return withContext(ioDispatcher) { tunnelConfigDao.getActive().map { it.toTunnel() } }
}
override suspend fun count(): Int {
@@ -83,26 +71,22 @@ class RoomTunnelRepository(
}
override suspend fun findByTunnelName(name: String): TunnelConf? {
return withContext(ioDispatcher) {
tunnelConfigDao.getByName(name)?.let(TunnelConfigMapper::toTunnelConf)
}
return withContext(ioDispatcher) { tunnelConfigDao.getByName(name)?.toTunnel() }
}
override suspend fun findByTunnelNetworksName(name: String): Tunnels {
return withContext(ioDispatcher) {
tunnelConfigDao.findByTunnelNetworkName(name).map(TunnelConfigMapper::toTunnelConf)
tunnelConfigDao.findByTunnelNetworkName(name).map { it.toTunnel() }
}
}
override suspend fun findByMobileDataTunnel(): Tunnels {
return withContext(ioDispatcher) {
tunnelConfigDao.findByMobileDataTunnel().map(TunnelConfigMapper::toTunnelConf)
tunnelConfigDao.findByMobileDataTunnel().map { it.toTunnel() }
}
}
override suspend fun findPrimary(): Tunnels {
return withContext(ioDispatcher) {
tunnelConfigDao.findByPrimary().map(TunnelConfigMapper::toTunnelConf)
}
return withContext(ioDispatcher) { tunnelConfigDao.findByPrimary().map { it.toTunnel() } }
}
}
@@ -113,11 +113,9 @@ class TunnelModule {
@ApplicationContext context: Context,
settingsRepository: AppSettingRepository,
): NetworkMonitor {
val method = runBlocking { settingsRepository.get().wifiDetectionMethod }
return AndroidNetworkMonitor(
context,
AndroidNetworkMonitor.WifiDetectionMethod.fromValue(method.value),
)
return AndroidNetworkMonitor(context) {
runBlocking { settingsRepository.get().isWifiNameByShellEnabled }
}
}
@Singleton
@@ -1,6 +1,4 @@
package com.zaneschepke.wireguardautotunnel.domain.model
import com.zaneschepke.networkmonitor.AndroidNetworkMonitor
package com.zaneschepke.wireguardautotunnel.domain.entity
data class AppSettings(
val id: Int = 0,
@@ -17,30 +15,15 @@ data class AppSettings(
val isPingEnabled: Boolean = false,
val isAmneziaEnabled: Boolean = false,
val isWildcardsEnabled: Boolean = false,
val isWifiNameByShellEnabled: Boolean = false,
val isStopOnNoInternetEnabled: Boolean = false,
val isVpnKillSwitchEnabled: Boolean = false,
val isKernelKillSwitchEnabled: Boolean = false,
val isLanOnKillSwitchEnabled: Boolean = false,
val debounceDelaySeconds: Int = 3,
val isDisableKillSwitchOnTrustedEnabled: Boolean = false,
val isTunnelOnUnsecureEnabled: Boolean = false,
val splitTunnelApps: List<String> = emptyList(),
val wifiDetectionMethod: AndroidNetworkMonitor.WifiDetectionMethod =
AndroidNetworkMonitor.WifiDetectionMethod.DEFAULT,
) {
fun debounceDelayMillis(): Long {
return debounceDelaySeconds * 1000L
}
fun toAutoTunnelStateString(): String {
return """
TunnelOnWifi: $isTunnelOnWifiEnabled
TunnelOnMobileData: $isTunnelOnMobileDataEnabled
TunnelOnEthernet: $isTunnelOnEthernetEnabled
Wildcards: $isWildcardsEnabled
StopOnNoInternet: $isStopOnNoInternetEnabled
Trusted Networks: $trustedNetworkSSIDs
"""
.trimIndent()
}
}
@@ -1,4 +1,4 @@
package com.zaneschepke.wireguardautotunnel.domain.model
package com.zaneschepke.wireguardautotunnel.domain.entity
import com.zaneschepke.wireguardautotunnel.ui.theme.Theme
@@ -1,4 +1,4 @@
package com.zaneschepke.wireguardautotunnel.domain.model
package com.zaneschepke.wireguardautotunnel.domain.entity
data class AppUpdate(
val version: String,
@@ -1,4 +1,4 @@
package com.zaneschepke.wireguardautotunnel.domain.model
package com.zaneschepke.wireguardautotunnel.domain.entity
import com.wireguard.android.backend.Tunnel
import com.wireguard.config.Config
@@ -26,6 +26,7 @@ data class TunnelConf(
val pingIp: String? = null,
val isEthernetTunnel: Boolean = false,
val isIpv4Preferred: Boolean = true,
val useCache: Boolean = false,
@Transient private var stateChangeCallback: ((Any) -> Unit)? = null,
) : Tunnel, org.amnezia.awg.backend.Tunnel {
@@ -110,6 +111,8 @@ data class TunnelConf(
override fun isIpv4ResolutionPreferred(): Boolean = isIpv4Preferred
override fun useCache(): Boolean = useCache
override fun onStateChange(newState: org.amnezia.awg.backend.Tunnel.State) {
stateChangeCallback?.invoke(newState)
}
@@ -1,6 +1,6 @@
package com.zaneschepke.wireguardautotunnel.domain.events
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
sealed class AutoTunnelEvent {
data class Start(val tunnelConf: TunnelConf? = null) : AutoTunnelEvent()
@@ -1,6 +1,6 @@
package com.zaneschepke.wireguardautotunnel.domain.repository
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
interface AppDataRepository {
suspend fun getPrimaryOrFirstTunnel(): TunnelConf?
@@ -1,6 +1,6 @@
package com.zaneschepke.wireguardautotunnel.domain.repository
import com.zaneschepke.wireguardautotunnel.domain.model.AppSettings
import com.zaneschepke.wireguardautotunnel.domain.entity.AppSettings
import kotlinx.coroutines.flow.Flow
interface AppSettingRepository {
@@ -1,6 +1,6 @@
package com.zaneschepke.wireguardautotunnel.domain.repository
import com.zaneschepke.wireguardautotunnel.domain.model.AppState
import com.zaneschepke.wireguardautotunnel.domain.entity.AppState
import com.zaneschepke.wireguardautotunnel.ui.theme.Theme
import kotlinx.coroutines.flow.Flow
@@ -1,6 +1,6 @@
package com.zaneschepke.wireguardautotunnel.domain.repository
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.util.extensions.Tunnels
import kotlinx.coroutines.flow.Flow
@@ -1,6 +1,6 @@
package com.zaneschepke.wireguardautotunnel.domain.repository
import com.zaneschepke.wireguardautotunnel.domain.model.AppUpdate
import com.zaneschepke.wireguardautotunnel.domain.entity.AppUpdate
import java.io.File
interface UpdateRepository {
@@ -3,10 +3,10 @@ package com.zaneschepke.wireguardautotunnel.domain.state
import com.zaneschepke.wireguardautotunnel.core.tunnel.allDown
import com.zaneschepke.wireguardautotunnel.core.tunnel.hasActive
import com.zaneschepke.wireguardautotunnel.core.tunnel.isUp
import com.zaneschepke.wireguardautotunnel.domain.entity.AppSettings
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.events.AutoTunnelEvent
import com.zaneschepke.wireguardautotunnel.domain.events.KillSwitchEvent
import com.zaneschepke.wireguardautotunnel.domain.model.AppSettings
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.util.extensions.isMatchingToWildcardList
data class AutoTunnelState(
@@ -16,7 +16,6 @@ data class AutoTunnelState(
val tunnels: List<TunnelConf> = emptyList(),
) {
// also need to check for Wi-Fi state as there is some overlap when they are both connected
private fun isMobileDataActive(): Boolean {
return !networkState.isEthernetConnected &&
!networkState.isWifiConnected &&
@@ -51,7 +50,6 @@ data class AutoTunnelState(
return getTunnelWithMatchingTunnelNetwork() ?: tunnels.firstOrNull { it.isPrimaryTunnel }
}
// ignore cellular state as there is overlap where it may still be active, but not prioritized
private fun isWifiActive(): Boolean {
return !networkState.isEthernetConnected && networkState.isWifiConnected
}
@@ -12,7 +12,7 @@ class WireGuardStatistics(private val statistics: Statistics) : TunnelStatistics
txBytes = peerStats.txBytes,
rxBytes = peerStats.rxBytes,
latestHandshakeEpochMillis = peerStats.latestHandshakeEpochMillis,
resolvedEndpoint = peerStats.resolvedEndpoint,
resolvedEndpoint = peerStats.rosolvedEndpoint,
)
}
}
@@ -13,8 +13,6 @@ sealed class Route {
@Serializable data object AutoTunnelAdvanced : Route()
@Serializable data object WifiDetectionMethod : Route()
@Serializable data object LocationDisclosure : Route()
@Serializable data object Appearance : Route()
@@ -73,7 +73,7 @@ fun IconSurfaceButton(
else MaterialTheme.colorScheme.onSurface,
)
}
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
Column {
Text(title, style = MaterialTheme.typography.titleMedium)
description?.let {
Text(
@@ -188,14 +188,6 @@ fun currentNavBackStackEntryAsNavBarState(
route = Route.Display,
)
backStackEntry.isCurrentRoute(Route.WifiDetectionMethod::class) ->
NavBarState(
showTop = true,
showBottom = true,
topTitle = { Text(stringResource(R.string.wifi_detection_method)) },
route = Route.WifiDetectionMethod,
)
backStackEntry.isCurrentRoute(Route.KillSwitch::class) ->
NavBarState(
showTop = true,
@@ -1,9 +1,18 @@
package com.zaneschepke.wireguardautotunnel.ui.screens.autotunnel.components
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
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.*
import androidx.compose.material.icons.outlined.Code
import androidx.compose.material.icons.outlined.Filter1
import androidx.compose.material.icons.outlined.Security
import androidx.compose.material.icons.outlined.VpnKeyOff
import androidx.compose.material.icons.outlined.Wifi
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@@ -17,19 +26,14 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.zaneschepke.networkmonitor.AndroidNetworkMonitor
import com.zaneschepke.networkmonitor.NetworkStatus
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.ui.Route
import com.zaneschepke.wireguardautotunnel.ui.common.button.ForwardButton
import com.zaneschepke.wireguardautotunnel.ui.common.button.ScaledSwitch
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
import com.zaneschepke.wireguardautotunnel.ui.common.functions.rememberClipboardHelper
import com.zaneschepke.wireguardautotunnel.ui.navigation.LocalNavController
import com.zaneschepke.wireguardautotunnel.ui.screens.settings.components.LearnMoreLinkLabel
import com.zaneschepke.wireguardautotunnel.ui.state.AppUiState
import com.zaneschepke.wireguardautotunnel.ui.theme.iconSize
import com.zaneschepke.wireguardautotunnel.util.extensions.asString
import com.zaneschepke.wireguardautotunnel.util.extensions.openWebUrl
import com.zaneschepke.wireguardautotunnel.viewmodel.AppViewModel
import com.zaneschepke.wireguardautotunnel.viewmodel.event.AppEvent
@@ -43,7 +47,6 @@ fun WifiTunnelingItems(
isWifiNameReadable: () -> Boolean,
): List<SelectionItem> {
val context = LocalContext.current
val navController = LocalNavController.current
val clipboardHelper = rememberClipboardHelper()
val baseItems =
@@ -104,40 +107,40 @@ fun WifiTunnelingItems(
}
},
onClick = { viewModel.handleEvent(AppEvent.ToggleAutoTunnelOnWifi) },
)
),
SelectionItem(
leadingIcon = Icons.Outlined.Code,
title = {
Text(
stringResource(R.string.wifi_name_via_shell),
style =
MaterialTheme.typography.bodyMedium.copy(
MaterialTheme.colorScheme.onSurface
),
)
},
description = {
Text(
stringResource(R.string.use_root_shell_for_wifi),
style =
MaterialTheme.typography.bodySmall.copy(
MaterialTheme.colorScheme.outline
),
)
},
trailing = {
ScaledSwitch(
checked = uiState.appSettings.isWifiNameByShellEnabled,
onClick = { viewModel.handleEvent(AppEvent.ToggleRootShellWifi) },
)
},
onClick = { viewModel.handleEvent(AppEvent.ToggleRootShellWifi) },
),
)
return if (uiState.appSettings.isTunnelOnWifiEnabled) {
baseItems +
listOf(
SelectionItem(
leadingIcon = Icons.Outlined.WifiFind,
title = {
Text(
stringResource(R.string.wifi_detection_method),
style =
MaterialTheme.typography.bodyMedium.copy(
MaterialTheme.colorScheme.onSurface
),
)
},
description = {
Text(
stringResource(
R.string.current_template,
uiState.appSettings.wifiDetectionMethod.asString(context),
),
style =
MaterialTheme.typography.bodySmall.copy(
MaterialTheme.colorScheme.outline
),
)
},
trailing = {
ForwardButton { navController.navigate(Route.WifiDetectionMethod) }
},
onClick = { navController.navigate(Route.WifiDetectionMethod) },
),
SelectionItem(
leadingIcon = Icons.Outlined.Filter1,
title = {
@@ -202,8 +205,7 @@ fun WifiTunnelingItems(
currentText = currentText,
onSave = { ssid ->
if (
uiState.appSettings.wifiDetectionMethod ==
AndroidNetworkMonitor.WifiDetectionMethod.ROOT ||
uiState.appSettings.isWifiNameByShellEnabled ||
isWifiNameReadable()
) {
viewModel.handleEvent(AppEvent.SaveTrustedSSID(ssid))
@@ -1,41 +0,0 @@
package com.zaneschepke.wireguardautotunnel.ui.screens.autotunnel.detection
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import com.zaneschepke.networkmonitor.AndroidNetworkMonitor
import com.zaneschepke.wireguardautotunnel.ui.common.button.IconSurfaceButton
import com.zaneschepke.wireguardautotunnel.ui.state.AppUiState
import com.zaneschepke.wireguardautotunnel.util.extensions.asDescriptionString
import com.zaneschepke.wireguardautotunnel.util.extensions.asString
import com.zaneschepke.wireguardautotunnel.viewmodel.AppViewModel
import com.zaneschepke.wireguardautotunnel.viewmodel.event.AppEvent
@Composable
fun WifiDetectionMethodScreen(uiState: AppUiState, viewModel: AppViewModel) {
val context = LocalContext.current
Column(
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(24.dp, Alignment.Top),
modifier = Modifier.fillMaxSize().padding(top = 24.dp).padding(horizontal = 24.dp),
) {
enumValues<AndroidNetworkMonitor.WifiDetectionMethod>().forEach {
val title = it.asString(context)
val description = it.asDescriptionString(context)
// TODO skip shizuku for now
if (it == AndroidNetworkMonitor.WifiDetectionMethod.SHIZUKU) return@forEach
IconSurfaceButton(
title = title,
onClick = { viewModel.handleEvent(AppEvent.SetDetectionMethod(it)) },
selected = uiState.appSettings.wifiDetectionMethod == it,
description = description,
)
}
}
}
@@ -51,8 +51,10 @@ fun MainScreen(appUiState: AppUiState, appViewState: AppViewState, viewModel: Ap
rememberLauncherForActivityResult(
contract = ScanContract(),
onResult = { result ->
if (result != null && result.contents.isNotEmpty())
viewModel.handleEvent(AppEvent.ImportTunnelFromQrCode(result.contents))
{
if (result != null && result.contents.isNotEmpty())
viewModel.handleEvent(AppEvent.ImportTunnelFromQrCode(result.contents))
}
},
)
@@ -67,9 +69,7 @@ fun MainScreen(appUiState: AppUiState, appViewState: AppViewState, viewModel: Ap
)
return@rememberLauncherForActivityResult
}
scanLauncher.launch(
ScanOptions().setDesiredBarcodeFormats(ScanOptions.QR_CODE).setBeepEnabled(false)
)
scanLauncher.launch(ScanOptions().setDesiredBarcodeFormats(ScanOptions.QR_CODE))
}
if (appViewState.showModal == AppViewState.ModalType.DELETE) {
@@ -15,8 +15,8 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.zaneschepke.wireguardautotunnel.domain.model.AppSettings
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.AppSettings
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SurfaceSelectionGroupButton
import com.zaneschepke.wireguardautotunnel.ui.screens.main.autotunnel.components.EthernetTunnelItem
import com.zaneschepke.wireguardautotunnel.ui.screens.main.autotunnel.components.MobileDataTunnelItem
@@ -7,7 +7,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.ui.common.button.ScaledSwitch
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
import com.zaneschepke.wireguardautotunnel.viewmodel.AppViewModel
@@ -7,7 +7,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.ui.common.button.ScaledSwitch
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
import com.zaneschepke.wireguardautotunnel.viewmodel.AppViewModel
@@ -16,8 +16,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.domain.model.AppSettings
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.AppSettings
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
import com.zaneschepke.wireguardautotunnel.ui.screens.autotunnel.components.TrustedNetworkTextBox
import com.zaneschepke.wireguardautotunnel.ui.screens.autotunnel.components.WildcardsLabel
@@ -16,7 +16,7 @@ import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import com.zaneschepke.wireguardautotunnel.core.tunnel.getValueById
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.state.TunnelState
import com.zaneschepke.wireguardautotunnel.ui.Route
import com.zaneschepke.wireguardautotunnel.ui.navigation.LocalIsAndroidTV
@@ -22,7 +22,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.state.TunnelState
import com.zaneschepke.wireguardautotunnel.ui.common.ExpandingRowListItem
import com.zaneschepke.wireguardautotunnel.ui.common.button.ScaledSwitch
@@ -16,7 +16,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.state.TunnelStatistics
import com.zaneschepke.wireguardautotunnel.util.NumberUtils
import com.zaneschepke.wireguardautotunnel.util.extensions.toThreeDecimalPlaceString
@@ -20,7 +20,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.zaneschepke.wireguardautotunnel.MainActivity
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.ui.common.prompt.AuthorizationPrompt
import com.zaneschepke.wireguardautotunnel.ui.screens.main.config.components.AddPeerButton
import com.zaneschepke.wireguardautotunnel.ui.screens.main.config.components.InterfaceSection
@@ -4,7 +4,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.di.IoDispatcher
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.repository.TunnelRepository
import com.zaneschepke.wireguardautotunnel.ui.screens.main.config.state.ConfigUiState
import com.zaneschepke.wireguardautotunnel.ui.state.ConfigProxy
@@ -4,7 +4,7 @@ import android.content.Context
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.repository.TunnelRepository
import com.zaneschepke.wireguardautotunnel.ui.Route
import com.zaneschepke.wireguardautotunnel.ui.screens.main.splittunnel.state.SplitOption
@@ -1,6 +1,6 @@
package com.zaneschepke.wireguardautotunnel.ui.screens.main.splittunnel.state
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
data class SplitTunnelUiState(
val loading: Boolean = true,
@@ -10,7 +10,7 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.ui.common.SectionDivider
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SurfaceSelectionGroupButton
import com.zaneschepke.wireguardautotunnel.ui.navigation.LocalIsAndroidTV
@@ -7,7 +7,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.ui.Route
import com.zaneschepke.wireguardautotunnel.ui.common.button.ForwardButton
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
@@ -9,7 +9,7 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
import com.zaneschepke.wireguardautotunnel.ui.common.config.SubmitConfigurationTextBox
import com.zaneschepke.wireguardautotunnel.util.Constants
@@ -7,7 +7,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.ui.common.button.ScaledSwitch
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
import com.zaneschepke.wireguardautotunnel.viewmodel.AppViewModel
@@ -7,7 +7,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.ui.common.button.ScaledSwitch
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
import com.zaneschepke.wireguardautotunnel.viewmodel.AppViewModel
@@ -35,8 +35,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import com.zaneschepke.wireguardautotunnel.MainActivity
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.enums.ConfigType
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.util.extensions.setScreenBrightness
import io.github.alexzhirkevich.qrose.options.QrBallShape
import io.github.alexzhirkevich.qrose.options.QrBrush
@@ -7,7 +7,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.ui.common.button.ScaledSwitch
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
import com.zaneschepke.wireguardautotunnel.viewmodel.AppViewModel
@@ -7,7 +7,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.ui.Route
import com.zaneschepke.wireguardautotunnel.ui.common.button.ForwardButton
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
@@ -12,12 +12,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextLinkStyles
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.withLink
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -78,41 +72,8 @@ fun SupportScreen(viewModel: SupportViewModel = hiltViewModel(), appViewModel: A
verticalArrangement = Arrangement.spacedBy(12.dp, Alignment.Top),
modifier = Modifier.fillMaxWidth(),
) {
val annotatedString = buildAnnotatedString {
append("${uiState.appUpdate?.version ?: ""}\n")
// Add clickable text for second line
withLink(
link =
LinkAnnotation.Clickable(
tag = stringResource(id = R.string.release_notes),
linkInteractionListener = {
val version =
if (BuildConfig.VERSION_NAME.contains("nightly")) {
"nightly"
} else {
uiState.appUpdate
?.version
?.removePrefix("v")
?.trim() ?: ""
}
val url = "${Constants.BASE_RELEASE_URL}$version".trim()
context.openWebUrl(url)
},
styles =
TextLinkStyles(
style =
SpanStyle(
color = MaterialTheme.colorScheme.primary,
textDecoration = TextDecoration.Underline,
)
),
)
) {
append(stringResource(R.string.release_notes))
}
}
Text(text = annotatedString)
Text(uiState.appUpdate?.version ?: "")
Text(uiState.appUpdate?.releaseNotes ?: "")
if (uiState.isLoading) {
LinearProgressIndicator(
progress = { uiState.downloadProgress },
@@ -1,6 +1,6 @@
package com.zaneschepke.wireguardautotunnel.ui.screens.support
import com.zaneschepke.wireguardautotunnel.domain.model.AppUpdate
import com.zaneschepke.wireguardautotunnel.domain.entity.AppUpdate
import com.zaneschepke.wireguardautotunnel.util.StringValue
data class SupportUiState(
@@ -4,7 +4,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.zaneschepke.wireguardautotunnel.BuildConfig
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.domain.model.AppUpdate
import com.zaneschepke.wireguardautotunnel.domain.entity.AppUpdate
import com.zaneschepke.wireguardautotunnel.domain.repository.UpdateRepository
import com.zaneschepke.wireguardautotunnel.util.FileUtils
import com.zaneschepke.wireguardautotunnel.util.StringValue
@@ -1,18 +1,17 @@
package com.zaneschepke.wireguardautotunnel.ui.state
import com.zaneschepke.networkmonitor.NetworkStatus
import com.zaneschepke.wireguardautotunnel.data.entity.GeneralState
import com.zaneschepke.wireguardautotunnel.data.mapper.GeneralStateMapper
import com.zaneschepke.wireguardautotunnel.domain.model.AppSettings
import com.zaneschepke.wireguardautotunnel.domain.model.AppState
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.data.model.GeneralState
import com.zaneschepke.wireguardautotunnel.domain.entity.AppSettings
import com.zaneschepke.wireguardautotunnel.domain.entity.AppState
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.state.TunnelState
data class AppUiState(
val appSettings: AppSettings = AppSettings(),
val tunnels: List<TunnelConf> = emptyList(),
val activeTunnels: Map<TunnelConf, TunnelState> = emptyMap(),
val appState: AppState = GeneralStateMapper.toAppState(GeneralState()),
val appState: AppState = GeneralState().toAppState(),
val isAutoTunnelActive: Boolean = false,
val appConfigurationChange: Boolean = false,
val isAppLoaded: Boolean = false,
@@ -1,6 +1,6 @@
package com.zaneschepke.wireguardautotunnel.ui.state
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.util.StringValue
data class AppViewState(
@@ -1,7 +1,7 @@
package com.zaneschepke.wireguardautotunnel.ui.state
import com.wireguard.config.Peer
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.util.extensions.joinAndTrim
data class PeerProxy(
@@ -38,6 +38,4 @@ object Constants {
const val GOOGLE_PLAY_FLAVOR = "google"
const val STANDALONE_FLAVOR = "standalone"
const val RELEASE = "release"
const val BASE_RELEASE_URL = "https://github.com/wgtunnel/wgtunnel/releases/tag/"
}
@@ -10,8 +10,8 @@ import android.provider.OpenableColumns
import androidx.annotation.RequiresApi
import androidx.core.content.FileProvider
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.data.entity.TunnelConfig
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.data.model.TunnelConfig
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.util.extensions.getInputStreamFromUri
import com.zaneschepke.wireguardautotunnel.util.extensions.installApk
import com.zaneschepke.wireguardautotunnel.util.extensions.launchShareFile
@@ -1,8 +1,8 @@
package com.zaneschepke.wireguardautotunnel.util.extensions
import android.content.pm.PackageInfo
import com.zaneschepke.wireguardautotunnel.data.entity.TunnelConfig
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.data.model.TunnelConfig
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import java.math.BigDecimal
import java.text.DecimalFormat
@@ -1,9 +1,6 @@
package com.zaneschepke.wireguardautotunnel.util.extensions
import android.content.Context
import androidx.navigation.NavController
import com.zaneschepke.networkmonitor.AndroidNetworkMonitor
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.ui.Route
import com.zaneschepke.wireguardautotunnel.ui.navigation.isCurrentRoute
@@ -14,25 +11,3 @@ fun NavController.goFromRoot(route: Route) {
launchSingleTop = true
}
}
fun AndroidNetworkMonitor.WifiDetectionMethod.asString(context: Context): String {
return when (this) {
AndroidNetworkMonitor.WifiDetectionMethod.DEFAULT -> context.getString(R.string._default)
AndroidNetworkMonitor.WifiDetectionMethod.LEGACY -> context.getString(R.string.legacy)
AndroidNetworkMonitor.WifiDetectionMethod.ROOT -> context.getString(R.string.root)
AndroidNetworkMonitor.WifiDetectionMethod.SHIZUKU -> context.getString(R.string.shizuku)
}
}
fun AndroidNetworkMonitor.WifiDetectionMethod.asDescriptionString(context: Context): String? {
return when (this) {
AndroidNetworkMonitor.WifiDetectionMethod.LEGACY ->
context.getString(R.string.legacy_api_description)
AndroidNetworkMonitor.WifiDetectionMethod.ROOT ->
context.getString(R.string.use_root_shell_for_wifi)
AndroidNetworkMonitor.WifiDetectionMethod.SHIZUKU ->
context.getString(R.string.use_shell_via_shizuku)
AndroidNetworkMonitor.WifiDetectionMethod.DEFAULT ->
context.getString(R.string.use_android_recommended)
}
}
@@ -8,7 +8,6 @@ import com.wireguard.android.backend.WgQuickBackend
import com.wireguard.android.util.RootShell
import com.zaneschepke.logcatter.LogReader
import com.zaneschepke.logcatter.model.LogMessage
import com.zaneschepke.networkmonitor.AndroidNetworkMonitor
import com.zaneschepke.networkmonitor.NetworkMonitor
import com.zaneschepke.networkmonitor.NetworkStatus
import com.zaneschepke.wireguardautotunnel.R
@@ -19,11 +18,11 @@ import com.zaneschepke.wireguardautotunnel.core.tunnel.TunnelManager
import com.zaneschepke.wireguardautotunnel.di.AppShell
import com.zaneschepke.wireguardautotunnel.di.IoDispatcher
import com.zaneschepke.wireguardautotunnel.di.MainDispatcher
import com.zaneschepke.wireguardautotunnel.domain.entity.AppSettings
import com.zaneschepke.wireguardautotunnel.domain.entity.AppState
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.enums.BackendState
import com.zaneschepke.wireguardautotunnel.domain.enums.ConfigType
import com.zaneschepke.wireguardautotunnel.domain.model.AppSettings
import com.zaneschepke.wireguardautotunnel.domain.model.AppState
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.repository.AppDataRepository
import com.zaneschepke.wireguardautotunnel.domain.state.TunnelState
import com.zaneschepke.wireguardautotunnel.ui.state.AppUiState
@@ -178,6 +177,7 @@ constructor(
handleDeleteTrustedSSID(event.ssid, state.appSettings)
AppEvent.ToggleAutoTunnelWildcards ->
handleToggleAutoTunnelWildcards(state.appSettings)
AppEvent.ToggleRootShellWifi -> handleToggleRootShellWifi(state.appSettings)
is AppEvent.SaveTrustedSSID ->
handleSaveTrustedSSID(event.ssid, state.appSettings)
AppEvent.ToggleAutoTunnelOnEthernet ->
@@ -210,31 +210,10 @@ constructor(
AppEvent.ClearSelectedTunnels -> clearSelectedTunnels()
is AppEvent.SetShowModal ->
_appViewState.update { it.copy(showModal = event.modalType) }
is AppEvent.SetDetectionMethod ->
handleSetDetectionMethod(event.detectionMethod, state.appSettings)
}
}
}
private suspend fun handleSetDetectionMethod(
detectionMethod: AndroidNetworkMonitor.WifiDetectionMethod,
appSettings: AppSettings,
) {
if (detectionMethod == appSettings.wifiDetectionMethod) return
when (detectionMethod) {
AndroidNetworkMonitor.WifiDetectionMethod.ROOT -> {
val allowed = requestRoot()
if (!allowed) return
}
// TODO check if shizuku available
AndroidNetworkMonitor.WifiDetectionMethod.SHIZUKU -> Unit
else -> Unit
}
saveSettings(appSettings.copy(wifiDetectionMethod = detectionMethod))
handleShowMessage(StringValue.StringResource(R.string.app_restart_required))
}
private fun handleToggleSelectAllTunnels(tunnels: List<TunnelConf>) =
_appViewState.update { it ->
val remove = tunnels.size == it.selectedTunnels.size
@@ -285,7 +264,6 @@ constructor(
}
}
// TODO
private fun handleTunnelErrors() =
viewModelScope.launch { tunnelManager.errorEvents.collect { errorEvent -> } }
@@ -422,6 +400,7 @@ constructor(
private suspend fun handleClipboardImport(config: String, tunnels: List<TunnelConf>) {
runCatching {
Timber.d("Config: $config")
val amConfig = TunnelConf.configFromAmQuick(config)
val tunnelConf = TunnelConf.tunnelConfigFromAmConfig(amConfig)
saveTunnel(
@@ -652,6 +631,14 @@ constructor(
)
)
private suspend fun handleToggleRootShellWifi(appSettings: AppSettings) {
if (requestRoot()) {
saveSettings(
appSettings.copy(isWifiNameByShellEnabled = !appSettings.isWifiNameByShellEnabled)
)
}
}
private suspend fun handleToggleTunnelOnEthernet(appSettings: AppSettings) =
saveSettings(
appSettings.copy(isTunnelOnEthernetEnabled = !appSettings.isTunnelOnEthernetEnabled)
@@ -1,9 +1,8 @@
package com.zaneschepke.wireguardautotunnel.viewmodel.event
import android.net.Uri
import com.zaneschepke.networkmonitor.AndroidNetworkMonitor
import com.zaneschepke.wireguardautotunnel.domain.entity.TunnelConf
import com.zaneschepke.wireguardautotunnel.domain.enums.ConfigType
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf
import com.zaneschepke.wireguardautotunnel.ui.state.AppViewState
import com.zaneschepke.wireguardautotunnel.ui.theme.Theme
import com.zaneschepke.wireguardautotunnel.util.StringValue
@@ -79,9 +78,6 @@ sealed class AppEvent {
data class SetTheme(val theme: Theme) : AppEvent()
data class SetDetectionMethod(val detectionMethod: AndroidNetworkMonitor.WifiDetectionMethod) :
AppEvent()
data object ToggleAutoTunnelOnWifi : AppEvent()
data object ToggleAutoTunnelOnCellular : AppEvent()
@@ -94,6 +90,8 @@ sealed class AppEvent {
data object ToggleAutoTunnelWildcards : AppEvent()
data object ToggleRootShellWifi : AppEvent()
data class DeleteTrustedSSID(val ssid: String) : AppEvent()
data class SaveTrustedSSID(val ssid: String) : AppEvent()
+1 -71
View File
@@ -82,7 +82,7 @@
<string name="no_browser_detected">Žádný prohlížeč nebyl nalezen</string>
<string name="read_logs">Přečíst si logy</string>
<string name="pin_created">PIN úspěšně vytvořen</string>
<string name="enter_pin">Zadejte Váš PIN</string>
<string name="enter_pin">Vložte Váš PIN</string>
<string name="enable_app_lock">Zapnout zámek aplikace</string>
<string name="restart_on_ping">Restartovat při selhání pingu</string>
<string name="mobile_data_tunnel">Nastavit jako tunel pro mobilní data</string>
@@ -163,74 +163,4 @@
<string name="learn_more">Zjistit více</string>
<string name="stop">zastavit</string>
<string name="server_ipv4">Překlad názvu hostitele IPv4</string>
<string name="select_all">Vybrat vše</string>
<string name="share">Sdílet</string>
<string name="trusted_ssid_value_description">Odeslat SSID</string>
<string name="app_settings">nastavení aplikace</string>
<string name="debounce_delay">Debounce zpoždění</string>
<string name="always_on_message">Autorizace připojení VPN byla zamítnuta. Zkontrolujte prosím</string>
<string name="bio_not_created">Biometrické údaje nebyly vytvořeny</string>
<string name="bio_not_supported">Biometrie není podporována</string>
<string name="bio_subtitle">Přihlášení pomocí biometrických údajů</string>
<string name="config_error">Chybná konfigurace</string>
<string name="prominent_background_location_title">Zpřístupnění stávající polohy na pozadí</string>
<string name="vpn_denied_dialog_title">Povolení zamítnuto</string>
<string name="app_permission_title">Řídicí most pro WG tunely</string>
<string name="app_permission_description">Ovládání funkcí tunelu a automatického tunelu.</string>
<string name="enable_remote_app_control">Povolit vzdálené ovládání aplikace</string>
<string name="tunnel_starting">Spuštění tunelu</string>
<string name="bio_auth_title">Biometrické ověření</string>
<string name="nothing_here_yet">Zatím zde nic není!</string>
<string name="export_success">Export byl úspěšně dokončen</string>
<string name="download">Stáhnout</string>
<string name="check_for_update">Zkontrolovat aktualizaci</string>
<string name="update_check_failed">Kontrola aktualizace se nezdařila.</string>
<string name="version_template">Verze: %1$s</string>
<string name="update_download_failed">Stažení aktualizace se nezdařilo.</string>
<string name="update_available">Dostupná aktualizace!</string>
<string name="download_and_install">Stáhnout a nainstalovat</string>
<string name="allow">Povolit</string>
<string name="permission_required">Je vyžadováno oprávnění</string>
<string name="licenses">Licence</string>
<string name="latest_installed">Již používáte nejnovější verzi.</string>
<string name="install_updated_permission">Tato aplikace potřebuje oprávnění k instalaci aktualizací.</string>
<string name="checking_for_update">Kontrola aktualizací</string>
<string name="add_from_url">Přidat z adresy URL</string>
<string name="inactive">Neaktivní</string>
<string name="auth_error">Chyba: neautorizováno</string>
<string name="kernel_name_error">Chyba názvu modulu jádra</string>
<string name="export_failed">Export se nezdařil</string>
<string name="delete">Smazat</string>
<string name="export_tunnels_wireguard">Exportovat tunely jako WireGuard</string>
<string name="export_tunnels_amnezia">Exportovat tunely jako Amnezia</string>
<string name="remote_key_template">Klíč: %1$s</string>
<string name="active">Aktivní</string>
<string name="service_running_error">Chyba: Služba není spuštěna</string>
<string name="wifi_name_template">Aktivní: %1$s</string>
<string name="tunnel_error_template">Tunel selhal s: %1$s</string>
<string name="camera_permission_required">Vyžadováno oprávnění k použití fotoaparátu</string>
<string name="info">Informace</string>
<string name="copy">Kopírovat</string>
<string name="status">Stav</string>
<string name="launch_app_settings">Spustit nastavení aplikace</string>
<string name="tunnel_running">Tunel je v provozu</string>
<string name="wildcards_active">Wildcards aktivní</string>
<string name="root_accepted">Root shell přijata</string>
<string name="background_location_message">Autorizace povolit vždy polohu a/nebo přesná poloha je vyžadováno pro tuto funkci. Viz</string>
<string name="update_check_unsupported">Kontrola aktualizací není u tohoto typu sestavení podporována.</string>
<string name="background_location_message2">abyste se ujistili, že jsou tato oprávnění povolena</string>
<string name="darker">Tmavší</string>
<string name="amoled">AMOLED</string>
<string name="default_ping_ip">(nepovinné, výchozí hodnota je peers)</string>
<string name="monitoring_state_changes">Monitorování změn stavu</string>
<string name="pre_up">Před aktivací</string>
<string name="pre_down">Před deaktivací</string>
<string name="post_up">Po aktivaci</string>
<string name="optional_default">"nepovinné, výchozí: "</string>
<string name="flavor_template">Varianta: %1$s</string>
<string name="security_template">Zabezpečení: %1$s</string>
<string name="done">Hotovo</string>
<string name="wireguard">WireGuard</string>
<string name="amnezia">Amnezia</string>
<string name="show_qr">Zobrazit QR kód</string>
</resources>
+2 -27
View File
@@ -12,7 +12,7 @@
<string name="turn_on_tunnel">Für diese Aktion muss ein aktiver Tunnel bestehen</string>
<string name="prominent_background_location_message">Diese Funktion erfordert die Erlaubnis zur Standortbestimmung im Hintergrund, um die Überwachung der WLAN SSID zu ermöglichen, auch wenn die Anwendung geschlossen ist. Weitere Einzelheiten in den Datenschutzbestimmungen, die auf dem Support-Bildschirm verlinkt sind.</string>
<string name="prominent_background_location_title">Vereinbarung der Standortberechtigung im Hintergrund</string>
<string name="thank_you">Danke für die Nutzung von WG Tunnel!</string>
<string name="thank_you">Danke fürs Benutzen von WG Tunnel!</string>
<string name="trusted_ssid_value_description">SSID übermitteln</string>
<string name="add_tunnels_text">Von Datei oder ZIP hinzufügen</string>
<string name="open_file">Datei öffnen</string>
@@ -140,7 +140,7 @@
<string name="local_logging">Lokales Logging</string>
<string name="enable_local_logging">Lokales Logging aktivieren</string>
<string name="add_from_clipboard">Aus Zwischenablage einfügen</string>
<string name="kill_switch">Notschalter</string>
<string name="kill_switch">Kill Switch</string>
<string name="automatic">Automatisch</string>
<string name="language">Sprache</string>
<string name="display_theme">Anzeigetheme</string>
@@ -227,29 +227,4 @@
<string name="wifi_name_template">Aktiv: %1$s</string>
<string name="delete">Löschen</string>
<string name="nothing_here_yet">Noch nix hier!</string>
<string name="share">Teilen</string>
<string name="select_all">Alles auswählen</string>
<string name="version_template">Version: %1$s</string>
<string name="export_success">Export Erfolg</string>
<string name="download">Download</string>
<string name="check_for_update">Auf Update prüfen</string>
<string name="update_check_failed">Updateprüfung fehlgeschlagen.</string>
<string name="checking_for_update">Überpüfe auf Updates</string>
<string name="update_download_failed">Updatedownload fehlgeschlagen.</string>
<string name="update_available">Update verfügbar!</string>
<string name="download_and_install">Herunterladen und installieren</string>
<string name="permission_required">Berechtigung erforderlich</string>
<string name="licenses">Lizenzen</string>
<string name="allow">Erlauben</string>
<string name="install_updated_permission">Diese App benötigt die Berechtigung, um Updates zu installieren.</string>
<string name="latest_installed">Du verwendesz bereits die neueste Version.</string>
<string name="security_template">Sicherheit: %1$s</string>
<string name="amoled">AMOLED</string>
<string name="flavor_template">Variante: %1$s</string>
<string name="darker">Dunkler</string>
<string name="update_check_unsupported">Updateprüfung wird bei diesem Build-Typ nicht unterstützt.</string>
<string name="wireguard">WireGuard</string>
<string name="done">Erledigt</string>
<string name="show_qr">QR anzeigen</string>
<string name="amnezia">Amnezia</string>
</resources>
-16
View File
@@ -171,20 +171,4 @@
<string name="quick_actions">Actions rapides</string>
<string name="enable_amnezia_compatibility">Activer la prise en charge d\'Amnezia</string>
<string name="include_lan">Inclure le LAN</string>
<string name="select">Sélectionner</string>
<string name="join_telegram">Rejoindre la communauté Telegram</string>
<string name="join_matrix">Rejoindre la communauté Matrix</string>
<string name="auto_tunnel_channel_description">Un canal pour les notifications de l\'état du tunnel automatique</string>
<string name="tunnel_control">Contrôle du tunnel</string>
<string name="auto_tunnel">Tunnel automatique</string>
<string name="add_tunnel">Ajouter un tunnel</string>
<string name="error_download_failed">Le téléchargement de la configuration a échouée</string>
<string name="multiple">Multiple</string>
<string name="add_from_url">Ajouter depuis un URL</string>
<string name="enter_config_url">Saisissez l\'URL de configuration</string>
<string name="search">Rechercher</string>
<string name="save">Sauvegarder</string>
<string name="copy">Copier</string>
<string name="info">Informations</string>
<string name="prefer_ipv4">Préférer une connexion IPv4</string>
</resources>
+1 -3
View File
@@ -1,4 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">WG Tunnel</string>
</resources>
<resources></resources>
+6 -135
View File
@@ -10,7 +10,7 @@
<string name="comma_separated_list">elenco separato da virgola</string>
<string name="listen_port">Porta d\'ascolto</string>
<string name="error_authorization_failed">Autorizzazione fallita</string>
<string name="error_no_file_explorer">Nessun gestore file installato</string>
<string name="error_no_file_explorer">Nessun esploratore di file installato</string>
<string name="app_name">Tunnel WG</string>
<string name="vpn_channel_name">Canale di notifica VPN</string>
<string name="turn_off_tunnel">L\'operaz. richiede la disatt. del tunnel</string>
@@ -20,7 +20,7 @@
<string name="enabled_app_shortcuts">Abilita le scorciatoie da app</string>
<string name="email_subject">Supporto di Tunnel WG</string>
<string name="email_chooser">Invia un email…</string>
<string name="docs_description">Leggi la documentazione</string>
<string name="docs_description">Read the docs</string>
<string name="email_description">Mandami un\'email (in inglese)</string>
<string name="no_tunnels">Ancora nessun tunnel aggiunto!</string>
<string name="peer">Peer</string>
@@ -53,11 +53,11 @@
<string name="error_ssid_exists">L\'SSID esiste già</string>
<string name="error_root_denied">Shell di root negata</string>
<string name="prominent_background_location_title">Permesso localizzazione in background</string>
<string name="location_services_missing_message">Questa app non rileva alcun servizio di localizzazione attivo sul tuo dispositivo. Indipendentemente dal dispositivo, questo potrebbe causare il fallimento nel recuperare il nome wifi da parte della funzione wifi non fidate. Vuoi continuare comunque?</string>
<string name="location_services_missing_message">Questa app non rileva nessun servizio di localizzazione attiva sul tuo dispositivo. Dipendentemente dal dispositivo, questo potrebbe causare il fallimento a leggere il nome wifi da parte della funzione di wifi non fidate. Vuoi continuare comunque?</string>
<string name="read_logs">Leggi i log</string>
<string name="auto">(auto)</string>
<string name="underload_packet_magic_header">Magic header pacchetto sottocarico</string>
<string name="unsure_how">se non sei sicuro su come procedere</string>
<string name="unsure_how">se non sei sicuro di come procedere</string>
<string name="vpn_settings">Impostazioni sistema VPN</string>
<string name="always_on_message">Permessi connessione VPN negati. Verifica la</string>
<string name="junk_packet_maximum_size">Dimensione massima pacchetti indesiderati</string>
@@ -115,136 +115,7 @@
<string name="enter_pin">Inserisci il tuo PIN</string>
<string name="create_pin">Crea PIN</string>
<string name="transport_packet_magic_header">Magic header pacchetto trasporto</string>
<string name="kill_switch_off">Arresta kill switch su fidate</string>
<string name="kill_switch_off">Ferma interruttore di spegnimento su fidate</string>
<string name="prominent_background_location_message">Questa caratteristica richiede il permesso di localizzazione in background per abilitare il monitoraggio dell\'SSID Wi-fi anche quando l\'applicazione è chiusa. Per più dettagli, verifica la Privacy Policy linkata nella schermata di supporto.</string>
<string name="auto_tunnel_title">Servizio tunnel automatico</string>
<string name="mobile_tunnel">Tunnel dati mobili</string>
<string name="wifi_name_via_shell">Nome wifi via shell</string>
<string name="use_root_shell_for_wifi">Usa una shell di robot per recuperare il nome wifi</string>
<string name="stop_on_internet_loss">Ferma il tunnel in caso di perdita di collegamento internet</string>
<string name="ethernet_tunnel">Tunnel ethernet</string>
<string name="vpn_kill_switch">Kill switch VPN</string>
<string name="kill_switch_options">Opzioni kill switch</string>
<string name="allow_lan_traffic">Abilita traffico LAN</string>
<string name="tunnel_control">Controllo tunnel</string>
<string name="include_lan">Includi la LAN</string>
<string name="appearance">Aspetto</string>
<string name="skip">Salta</string>
<string name="launch_app_settings">Opzioni di avvio della app</string>
<string name="learn_more">Approfondisci</string>
<string name="wildcards_active">Caratteri jolly attivi</string>
<string name="donate">Dona al progetto</string>
<string name="enable_local_logging">Abilita logging locale</string>
<string name="monitoring_state_changes">Monitora i cambi di stato</string>
<string name="stop">arrestato</string>
<string name="tunnel_specific_settings">Configurazioni specifiche del tunnel</string>
<string name="show_scripts">Mostra gli script</string>
<string name="pre_up">Prima di avviarsi</string>
<string name="splt_tunneling">Split tunneling</string>
<string name="quick_actions">Azioni rapide</string>
<string name="debounce_delay">Ritardo debounce</string>
<string name="hide_amnezia_properties">Nascondi le proprietà di Amnezia</string>
<string name="advanced_settings">Configurazioni avanzate</string>
<string name="enable_amnezia_compatibility">Abilita compatibilità Amnezia</string>
<string name="remove_amnezia_compatibility">Disabilita compatibilità Amnezia</string>
<string name="exclude_lan">Escludi la LAN</string>
<string name="share">Condividi</string>
<string name="select_all">Seleziona tutto</string>
<string name="never">mai</string>
<string name="use_wildcards">Usa nomi jolly</string>
<string name="add_from_clipboard">Aggiungi dagli appunti</string>
<string name="trusted_wifi_names">Nomi wifi di fiducia</string>
<string name="add_wifi_name">Aggiungi un nome wifi</string>
<string name="primary_tunnel">Tunnel primario</string>
<string name="sec">sec</string>
<string name="post_down">Dopo essersi arrestato</string>
<string name="pre_down">Prima di arrestarsi</string>
<string name="light">Chiaro</string>
<string name="dark">Scuro</string>
<string name="bio_not_created">Biometria non creata</string>
<string name="search">Cerca</string>
<string name="app_permission_description">Controllo tunnel e funzionalità automatiche.</string>
<string name="enter_config_url">Inserisci un URL di configurazione</string>
<string name="error_download_failed">Download della configurazione fallito</string>
<string name="save">Salva</string>
<string name="active">Attivo</string>
<string name="dropdown">A discesa</string>
<string name="local_logging">Logging locale</string>
<string name="handshake">handshake</string>
<string name="logs">Logs</string>
<string name="notifications">Notifiche</string>
<string name="automatic">Automatico</string>
<string name="kill_switch">Kill switch</string>
<string name="dynamic">Dinamico</string>
<string name="language">Lingua</string>
<string name="display_theme">Tema schermo</string>
<string name="kernel_not_supported">Kernel non supportato</string>
<string name="tunnel_running">Tunnel avviato</string>
<string name="stop_on_no_internet">Ferma se non c\'è internet</string>
<string name="start_auto">Avvia tunnel automatico</string>
<string name="stop_auto">Ferma tunnel automatico</string>
<string name="native_kill_switch">Kill switch nativo</string>
<string name="set_ethernet_tunnel">Configura come tunnel ethernet</string>
<string name="bypass_lan_for_kill_switch">Bypass LAN per kill switch</string>
<string name="vpn_channel_description">Un canale per le notifiche di stato della VPN</string>
<string name="auto_tunnel_channel_name">Canale di notifica del tunnel automatico</string>
<string name="auto_tunnel_channel_description">Un canale per le notifiche di stato del tunnel automatico</string>
<string name="post_up">Dopo essersi avviato</string>
<string name="multiple">Molteplici</string>
<string name="add_from_url">Aggiungi da URL</string>
<string name="join_telegram">Unisciti alla comunità Telegram</string>
<string name="join_matrix">Unisciti alla comunità Matrix</string>
<string name="app_permission_title">WG Tunnel Control Bridge</string>
<string name="select">Seleziona</string>
<string name="hide_scripts">Nascondi gli script</string>
<string name="auto_tunnel">Tunnel automatico</string>
<string name="add_tunnel">Aggiungi tunnel</string>
<string name="export_logs">Esporta i log salvati</string>
<string name="delete_logs">Cancella e pulisci i logs</string>
<string name="copy">Copia</string>
<string name="info">Informazioni</string>
<string name="export_tunnels_amnezia">Esporta i tunnel in modalità Amnezia</string>
<string name="export_tunnels_wireguard">Esporta i tunnel in modalità WireGuard</string>
<string name="delete">Cancella</string>
<string name="camera_permission_required">Permessi telecamera richiesti</string>
<string name="export_failed">Esportazione fallita</string>
<string name="tunnel_error_template">Tunnel interrotto: %1$s</string>
<string name="wifi_name_template">Attivo: %1$s</string>
<string name="auth_error">errore non autorizzato</string>
<string name="service_running_error">errore servizio non avviato</string>
<string name="inactive">Inattivo</string>
<string name="remote_key_template">Chiave: %1$s</string>
<string name="config_error">errore di configurazione</string>
<string name="dns_resolve_error">errore risoluzione dns</string>
<string name="invalid_config_error">invalid_config_error</string>
<string name="bio_not_supported">Biometria non supportata</string>
<string name="bio_subtitle">Il log sta usando la tua autenticazione biometrica</string>
<string name="enable_remote_app_control">Abilita controllo remoto app</string>
<string name="version_template">Versione: %1$s</string>
<string name="flavor_template">Caratteristica: %1$s</string>
<string name="kernel_name_error">nome errato modulo kernel</string>
<string name="status">Stato</string>
<string name="bio_auth_title">Autenticazione Biometrica</string>
<string name="bio_update_required">Aggiornamento richiesto sicurezza biometrica</string>
<string name="tunnel_starting">Il tunnel si sta avviando</string>
<string name="update_available">Aggiornamento disponibile!</string>
<string name="permission_required">Permessi Richiesti</string>
<string name="download_and_install">Scarica e Installa</string>
<string name="latest_installed">Sta già usando la versione più recente.</string>
<string name="update_download_failed">Download aggiornamento fallito.</string>
<string name="install_updated_permission">Questa applicazione richiede i permessi per installare gli aggiornamenti.</string>
<string name="allow">Autorizza</string>
<string name="licenses">Licenze</string>
<string name="update_check_unsupported">Controllo degli aggiornamenti non supportato per questo tipo di build.</string>
<string name="darker">Più scuro</string>
<string name="security_template">Sicurezza: %1$s</string>
<string name="export_success">Esportazione riuscita</string>
<string name="download">Download</string>
<string name="check_for_update">Controlla gli aggiornamenti</string>
<string name="update_check_failed">Controllo aggiornamenti fallito.</string>
<string name="checking_for_update">Controllo gli aggiornamenti</string>
<string name="amoled">AMOLED</string>
<string name="server_ipv4">Risoluzione nomi IPv4</string>
<string name="prefer_ipv4">Preferisci connessioni IPv4</string>
<string name="nothing_here_yet">Non c\'è ancora nulla qui!</string>
<string name="auto_tunnel_title">Servizio auto-tunnel</string>
</resources>
-32
View File
@@ -54,36 +54,4 @@
<string name="turn_on_tunnel">実行に有効なVPNトンネルが必要です</string>
<string name="add_peer">ピアの追加</string>
<string name="delete_tunnel">トンネルの削除</string>
<string name="unsure_how">操作方法がわからない場合</string>
<string name="background_location_message">この機能には『常に許可』の位置情報権限および/または正確な位置情報が必要です。以下をご覧ください</string>
<string name="tunnel_on_ethernet">Ethernetでのトンネルの有効化</string>
<string name="open_issue">問題を報告する</string>
<string name="incorrect_pin">PINが無効です</string>
<string name="read_logs">ログを確認する</string>
<string name="pin_created">PINの登録が完了しました</string>
<string name="settings">設定</string>
<string name="set_custom_ping_internal">Ping間隔 (秒)</string>
<string name="tunnel_mobile_data">モバイルデータでのトンネルの有効化</string>
<string name="tunnel_on_wifi">信頼していないWifiでの有効化</string>
<string name="enter_pin">PINコードを入力</string>
<string name="create_import">最初から作成する</string>
<string name="auto_tunnel_title">自動トンネルサービス</string>
<string name="edit_tunnel">トンネルの編集</string>
<string name="create_pin">新規PINを作成</string>
<string name="use_tunnel_on_wifi_name">指定WiFiでトンネルを適用</string>
<string name="version">バージョン</string>
<string name="mobile_data_tunnel">モバイルデータトンネルに設定</string>
<string name="enable_app_lock">アプリロックを有効にする</string>
<string name="always_on_message">VPN接続の許可が拒否されました。</string>
<string name="always_on_message2">他のすべてのアプリで常時接続VPNがオフになっていることを確認して、再度お試しください</string>
<string name="getting_started_guide">スタートガイド</string>
<string name="error_file_format">無効なトンネル設定フォーマット</string>
<string name="kill_switch">キルスイッチ</string>
<string name="notifications">通知</string>
<string name="logs">ログ</string>
<string name="add_from_clipboard">クリップボードからの追加</string>
<string name="automatic">自動</string>
<string name="add_wifi_name">Wifi名の追加</string>
<string name="language">設定言語</string>
<string name="trusted_wifi_names">信頼されたWifi名</string>
</resources>
-21
View File
@@ -150,25 +150,4 @@
<string name="add_from_url">Toevoegen met link</string>
<string name="stop_on_no_internet">Stoppen wanneer geen internet</string>
<string name="stop_on_internet_loss">Stop tunnel bij verlies van internet</string>
<string name="mobile_tunnel">Mobiele datatunnel</string>
<string name="wildcards_active">Wildcards actief</string>
<string name="wifi_name_via_shell">Wifi naam via shell</string>
<string name="vpn_kill_switch">VPN kill switch</string>
<string name="kill_switch_options">Kill switch opties</string>
<string name="use_root_shell_for_wifi">Gebruik root shell om wifi naam te bepalen</string>
<string name="kernel_not_supported">Kernel niet ondersteund</string>
<string name="start_auto">Start auto-tunnel</string>
<string name="stop_auto">Stop auto-tunnel</string>
<string name="tunnel_running">Tunnel actief</string>
<string name="donate">Doneer aan project</string>
<string name="local_logging">Lokale logboeken</string>
<string name="monitoring_state_changes">Monitor statuswijzigingen</string>
<string name="trusted_wifi_names">Vertrouwde Wifi namen</string>
<string name="add_wifi_name">Wifi naam toevoegen</string>
<string name="launch_app_settings">Open applicatie-instellingen</string>
<string name="use_wildcards">Gebruik wildcards in naam</string>
<string name="learn_more">Lees meer</string>
<string name="app_permission_description">Configureer tunnels een auto-tunnel instellingen.</string>
<string name="skip">Overslaan</string>
<string name="primary_tunnel">Primaire tunnel</string>
</resources>
+5 -30
View File
@@ -81,12 +81,12 @@
<string name="unknown_error">Wystąpił nieznany błąd</string>
<string name="start_auto">Uruchom autotunel</string>
<string name="location_services_not_detected">Usługi lokalizacyjne nie zostały wykryte</string>
<string name="background_location_message">Ta funkcja wymaga zezwolenia na określenie lokalizacji w dowolnym momencie i/lub dokładnej lokalizacji. Sprawdź</string>
<string name="background_location_message">Ta funkcja wymaga pozwolenia na określenie lokalizacji w dowolnym momencie i/lub dokładnej lokalizacji. Sprawdź</string>
<string name="auto_tunnel_title">Usługa autotunelu</string>
<string name="donate">Przekaż darowiznę na rzecz projektu</string>
<string name="trusted_ssid_value_description">Prześlij SSID</string>
<string name="all">wszystkie</string>
<string name="no_email_detected">Nie wykryto aplikacji pocztowej</string>
<string name="no_email_detected">Nie wykryto aplikacji e-mail</string>
<string name="turn_off_tunnel">Czynność wymaga wyłączenia tunelu</string>
<string name="add_from_qr">Dodaj z kodu QR</string>
<string name="qr_scan">Skanuj kod QR</string>
@@ -140,14 +140,14 @@
<string name="stop_auto">Zatrzymaj autotunel</string>
<string name="tunnel_running">Tunel jest uruchomiony</string>
<string name="enable_local_logging">Włącz lokalne rejestrowanie</string>
<string name="email_chooser">Wyślij wiadomość e-mail…</string>
<string name="email_chooser">Wyślij e-mail…</string>
<string name="set_custom_ping_cooldown">Czas odnowienia pingowania (sek.)</string>
<string name="open_file">Otwórz plik</string>
<string name="okay">OK</string>
<string name="no_tunnels">Nie dodano jeszcze żadnych tuneli!</string>
<string name="exclude">Wyklucz</string>
<string name="docs_description">Przeczytaj dokumentację</string>
<string name="email_description">Wyślij mi wiadomość e-mail</string>
<string name="email_description">Wyślij mi e-mail</string>
<string name="set_primary_tunnel">Ustaw jako tunel podstawowy</string>
<string name="mobile_data_tunnel">Ustaw jako tunel mobilnej transmisji danych</string>
<string name="vpn_channel_id">Kanał VPN</string>
@@ -210,7 +210,7 @@
<string name="info">Informacje</string>
<string name="export_tunnels_wireguard">Eksportuj tunele jako WireGuard</string>
<string name="delete">Usuń</string>
<string name="camera_permission_required">Wymagane zezwolenie na dostęp do aparatu</string>
<string name="camera_permission_required">Wymagane pozwolenie na dostęp do aparatu</string>
<string name="tunnel_error_template">Tunel nie powiódł się z powodu: %1$s</string>
<string name="remote_key_template">Klucz: %1$s</string>
<string name="config_error">błąd konfiguracji</string>
@@ -228,29 +228,4 @@
<string name="invalid_config_error">błąd nieprawidłowej konfiguracji</string>
<string name="dns_resolve_error">błąd rozwiązywania DNS</string>
<string name="nothing_here_yet">Jeszcze nic tu nie ma!</string>
<string name="select_all">Wybierz wszystkie</string>
<string name="share">Udostępnij</string>
<string name="download">Pobierz</string>
<string name="version_template">Wersja: %1$s</string>
<string name="check_for_update">Sprawdź aktualizację</string>
<string name="update_check_failed">Sprawdzanie aktualizacji zakończyło się niepowodzeniem.</string>
<string name="checking_for_update">Sprawdzanie aktualizacji</string>
<string name="latest_installed">Używasz już najnowszej wersji.</string>
<string name="update_download_failed">Nie udało się pobrać aktualizacji.</string>
<string name="update_available">Aktualizacja dostępna!</string>
<string name="download_and_install">Pobierz i zainstaluj</string>
<string name="permission_required">Wymagane zezwolenie</string>
<string name="install_updated_permission">Ta aplikacja wymaga zezwolenia na instalowanie aktualizacji.</string>
<string name="allow">Zezwól</string>
<string name="export_success">Eksport zakończony powodzeniem</string>
<string name="licenses">Licencje</string>
<string name="update_check_unsupported">Sprawdzanie aktualizacji nie jest obsługiwane w tym typie kompilacji.</string>
<string name="flavor_template">Wariant: %1$s</string>
<string name="darker">Ciemniejszy</string>
<string name="amoled">AMOLED</string>
<string name="security_template">Zabezpieczenia: %1$s</string>
<string name="show_qr">Pokaż kod QR</string>
<string name="amnezia">Amnezia</string>
<string name="wireguard">WireGuard</string>
<string name="done">Gotowe</string>
</resources>
+5 -30
View File
@@ -112,7 +112,7 @@
<string name="always_on_message2">, чтобы убедиться, что функция «Постоянный VPN» отключена для всех других приложений, и повторите попытку</string>
<string name="background_location_message">Разрешать всё время, пока для работы этой функции требуется доступ на определение местоположения и/или точное местоположение. Смотрите</string>
<string name="vpn_settings">Системные настройки VPN</string>
<string name="vpn_denied_dialog_title">Отказано в доступе</string>
<string name="vpn_denied_dialog_title">Нет разрешения</string>
<string name="set_custom_ping_internal">Интервал пинга (сек.)</string>
<string name="optional_default">"необязательно, по умолчанию: "</string>
<string name="set_custom_ping_ip">Назначить свой IP для пинга</string>
@@ -146,7 +146,7 @@
<string name="use_root_shell_for_wifi">Использовать root-доступ для получения имени сети Wi-Fi</string>
<string name="wifi_name_via_shell">Имя Wi-Fi через root</string>
<string name="start_auto">Запустить автотуннель</string>
<string name="tunnel_running">Работающий туннель</string>
<string name="tunnel_running">Туннель работает</string>
<string name="monitoring_state_changes">Отслеживание изменений состояния</string>
<string name="enable_local_logging">Включить ведение журнала</string>
<string name="add_from_clipboard">Добавить из буфера обмена</string>
@@ -171,7 +171,7 @@
<string name="post_up">После активации</string>
<string name="pre_down">До деактивации</string>
<string name="post_down">После деактивации</string>
<string name="debounce_delay">Задержка изменения сети</string>
<string name="debounce_delay">Задержка отбоя</string>
<string name="remove_amnezia_compatibility">Отключить совместимость с Amnezia</string>
<string name="exclude_lan">Исключить LAN</string>
<string name="hide_scripts">Скрыть сценарии</string>
@@ -179,8 +179,8 @@
<string name="advanced_settings">Дополнительные настройки</string>
<string name="enable_amnezia_compatibility">Включить совместимость с Amnezia</string>
<string name="include_lan">Включить LAN</string>
<string name="auto_tunnel">Авто-туннелирование</string>
<string name="tunnel_control">Управление туннелями</string>
<string name="auto_tunnel">Автотуннель</string>
<string name="tunnel_control">Управление туннелем</string>
<string name="kill_switch_off">Без экстренного отключения в доверенных</string>
<string name="prefer_ipv4">Предпочитать соединение IPv4</string>
<string name="server_ipv4">Получать имя узла IPv4</string>
@@ -227,29 +227,4 @@
<string name="enable_remote_app_control">Удалённое управление приложением</string>
<string name="error_download_failed">Невозможно скачать конфигурацию</string>
<string name="nothing_here_yet">Здесь пока ничего нет!</string>
<string name="select_all">Выбрать все</string>
<string name="share">Поделиться</string>
<string name="export_success">Экспорт успешно выполнен</string>
<string name="check_for_update">Проверить обновление</string>
<string name="update_check_failed">Проверка обновлений не выполнена.</string>
<string name="checking_for_update">Проверка обновления</string>
<string name="latest_installed">Вы уже используете последнюю версию.</string>
<string name="update_available">Доступно обновление!</string>
<string name="install_updated_permission">Этому приложению нужно разрешение на установку обновлений.</string>
<string name="allow">Разрешить</string>
<string name="download">Скачать</string>
<string name="download_and_install">Скачать и установить</string>
<string name="update_download_failed">Невозможно скачать обновление.</string>
<string name="version_template">Версия: %1$s</string>
<string name="licenses">Лицензии</string>
<string name="permission_required">Требуется разрешение</string>
<string name="update_check_unsupported">Проверка обновлений не поддерживается для этого типа сборок.</string>
<string name="flavor_template">Сборка: %1$s</string>
<string name="amoled">AMOLED</string>
<string name="darker">Ночная</string>
<string name="security_template">Защита: %1$s</string>
<string name="wireguard">WireGuard</string>
<string name="done">Готово</string>
<string name="amnezia">Amnezia</string>
<string name="show_qr">Показать QR-код</string>
</resources>
-2
View File
@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
+4 -63
View File
@@ -136,10 +136,10 @@
<string name="splt_tunneling">பிளவு சுரங்கப்பாதை</string>
<string name="tunnel_specific_settings">சுரங்கப்பாதை குறிப்பிட்ட அமைப்புகள்</string>
<string name="show_scripts">ச்கிரிப்ட்களைக் காட்டு</string>
<string name="pre_up">முன் மேல்</string>
<string name="post_up">பின் மேல்</string>
<string name="pre_down">முன் கீழ்</string>
<string name="post_down">பின் கீழ்</string>
<string name="pre_up">முன்</string>
<string name="post_up">இடுகை</string>
<string name="pre_down">முன்</string>
<string name="post_down">இடுகை</string>
<string name="hide_scripts">ச்கிரிப்ட்களை மறைக்கவும்</string>
<string name="enable_amnezia_compatibility">அம்னேசியா பொருந்தக்கூடிய தன்மையை இயக்கவும்</string>
<string name="debounce_delay">நேரந்தவறுகை</string>
@@ -185,63 +185,4 @@
<string name="prefer_ipv4">ஐபிவி 4 இணைப்பை விரும்புங்கள்</string>
<string name="multiple">நான்கு</string>
<string name="kill_switch_off">நம்பகமானதைக் கொலை செய்வதை நிறுத்துங்கள்</string>
<string name="share">பங்கு</string>
<string name="select_all">அனைத்தையும் தெரிவுசெய்</string>
<string name="version_template">பதிப்பு: %1$s</string>
<string name="update_download_failed">புதுப்பிப்பு பதிவிறக்கம் தோல்வியடைந்தது.</string>
<string name="update_available">புதுப்பிப்பு கிடைக்கிறது!</string>
<string name="allow">இசைவு</string>
<string name="inactive">செயலற்றது</string>
<string name="tunnel_error_template">சுரங்கப்பாதை தோல்வியுற்றது: %1$s</string>
<string name="export_tunnels_wireguard">சுரங்கங்களை வயர் கார்டாக ஏற்றுமதி செய்யுங்கள்</string>
<string name="invalid_config_error">Invalitir_config_error</string>
<string name="app_permission_title">WG சுரங்கப்பாதை கட்டுப்பாட்டு பாலம்</string>
<string name="add_tunnel">சுரங்கப்பாதை சேர்க்கவும்</string>
<string name="app_permission_description">சுரங்கங்கள் மற்றும் ஆட்டோ-டன்னல் அம்சங்களைக் கட்டுப்படுத்தவும்.</string>
<string name="enter_config_url">கட்டமைப்பு முகவரி ஐ உள்ளிடவும்</string>
<string name="error_download_failed">கட்டமைப்பைப் பதிவிறக்குவதில் தோல்வி</string>
<string name="search">தேடல்</string>
<string name="select">தேர்ந்தெடு</string>
<string name="join_telegram">தந்தி சமூகத்தில் சேரவும்</string>
<string name="join_matrix">மேட்ரிக்ச் சமூகத்தில் சேரவும்</string>
<string name="dropdown">கீழ்தோன்றும்</string>
<string name="export_logs">சேமிக்கப்பட்ட பதிவுகளை ஏற்றுமதி செய்யுங்கள்</string>
<string name="info">தகவல்</string>
<string name="delete">நீக்கு</string>
<string name="wifi_name_template">செயலில்: %1$s</string>
<string name="export_failed">ஏற்றுமதி தோல்வியடைந்தது</string>
<string name="remote_key_template">விசை: %1$s</string>
<string name="config_error">கட்டமைப்பு பிழை</string>
<string name="dns_resolve_error">டிஎன்எச் தீர்மானம் பிழை</string>
<string name="kernel_name_error">கர்னல் தொகுதி பெயர் பிழை</string>
<string name="auth_error">அங்கீகரிக்கப்பட்ட பிழை இல்லை</string>
<string name="service_running_error">பணி இயங்கும் பிழை</string>
<string name="active">செயலில்</string>
<string name="bio_not_supported">பயோமெட்ரிக்ச் ஆதரிக்கப்படவில்லை</string>
<string name="bio_subtitle">உங்கள் பயோமெட்ரிக் நற்சான்றிதழைப் பயன்படுத்தி உள்நுழைக</string>
<string name="tunnel_starting">சுரங்கப்பாதை தொடங்குகிறது</string>
<string name="enable_remote_app_control">தொலைநிலை பயன்பாட்டுக் கட்டுப்பாட்டை இயக்கவும்</string>
<string name="bio_not_created">பயோமெட்ரிக்ச் உருவாக்கப்படவில்லை</string>
<string name="bio_update_required">பயோமெட்ரிக் பாதுகாப்பு புதுப்பிப்பு தேவை</string>
<string name="flavor_template">சுவை: %1$s</string>
<string name="add_from_url">முகவரி இலிருந்து சேர்க்கவும்</string>
<string name="delete_logs">பதிவுகளை நீக்கவும் அழிக்கவும்</string>
<string name="copy">நகலெடு</string>
<string name="save">சேமி</string>
<string name="export_tunnels_amnezia">அம்னேசியாவாக சுரங்கங்களை ஏற்றுமதி செய்யுங்கள்</string>
<string name="camera_permission_required">கேமரா இசைவு தேவை</string>
<string name="status">நிலை</string>
<string name="bio_auth_title">பயோமெட்ரிக் ஏற்பு</string>
<string name="nothing_here_yet">இன்னும் இங்கே எதுவும் இல்லை!</string>
<string name="export_success">ஏற்றுமதி செய்</string>
<string name="download">பதிவிறக்கம்</string>
<string name="check_for_update">புதுப்பிப்புக்கு சரிபார்க்கவும்</string>
<string name="update_check_failed">புதுப்பிப்பு காசோலை தோல்வியடைந்தது.</string>
<string name="checking_for_update">புதுப்பிப்புகளைச் சரிபார்க்கிறது</string>
<string name="latest_installed">நீங்கள் ஏற்கனவே அண்மைக் கால பதிப்பை இயக்குகிறீர்கள்.</string>
<string name="download_and_install">பதிவிறக்கம் செய்து நிறுவவும்</string>
<string name="permission_required">இசைவு தேவை</string>
<string name="install_updated_permission">புதுப்பிப்புகளை நிறுவ இந்த பயன்பாட்டிற்கு இசைவு தேவை.</string>
<string name="licenses">உரிமங்கள்</string>
<string name="update_check_unsupported">புதுப்பிப்பு காசோலை இந்த உருவாக்க வகையை ஆதரிக்கவில்லை.</string>
</resources>
+32 -53
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="peer">پیر</string>
<string name="add_from_qr">کیو آر کوڈ سے شامل کریں</string>
<string name="add_from_qr">QR کوڈ سے شامل کریں۔</string>
<string name="always_on_vpn_support">ہمیشہ آن VPN کی اجازت دیں۔</string>
<string name="add_peer">ساتھی شامل کریں۔</string>
<string name="turn_off_tunnel">کارروائی کے لیے سرنگ بند کی ضرورت ہے۔</string>
@@ -16,11 +16,11 @@
<string name="app_name">ڈبلیو جی ٹنل</string>
<string name="error_file_extension">فائل conf یا zip نہیں ہے۔</string>
<string name="no_tunnels">ابھی تک کوئی سرنگیں شامل نہیں کی گئیں!</string>
<string name="tunnels">ٹنلز</string>
<string name="tunnel_mobile_data">موبائل ڈیٹا پر ٹنل</string>
<string name="tunnels">سرنگیں۔</string>
<string name="tunnel_mobile_data">موبائل ڈیٹا پر سرنگ</string>
<string name="privacy_policy">رازداری کی پالیسی دیکھیں</string>
<string name="okay">ٹھیک ہے۔</string>
<string name="tunnel_on_ethernet">ایتھرنیٹ پر ٹنل</string>
<string name="tunnel_on_ethernet">ایتھرنیٹ پر سرنگ</string>
<string name="thank_you">ڈبلیو جی ٹنل استعمال کرنے کا شکریہ!</string>
<string name="trusted_ssid_value_description">SSID جمع کروائیں۔</string>
<string name="open_file">فائل کھولیں۔</string>
@@ -37,7 +37,7 @@
<string name="location_services_not_detected">مقام کی خدمات کا پتہ نہیں چلا</string>
<string name="vpn_on">VPN آن</string>
<string name="vpn_off">VPN آف ہے۔</string>
<string name="turn_on_tunnel">کارروائی کے لیے فعال ٹنل کی ضرورت ہے</string>
<string name="turn_on_tunnel">کارروائی کے لیے فعال سرنگ کی ضرورت ہے۔</string>
<string name="interface_">انٹرفیس</string>
<string name="private_key">نجی کلید</string>
<string name="base64_key">بیس 64 کلید</string>
@@ -48,7 +48,7 @@
<string name="error_authentication_failed">تصدیق ناکام ہوگئی</string>
<string name="error_authorization_failed">اجازت دینے میں ناکام</string>
<string name="enabled_app_shortcuts">ایپ شارٹ کٹس کو فعال کریں۔</string>
<string name="tunnel_on_wifi">ناقابل اعتماد وائی فائی پر ٹنل</string>
<string name="tunnel_on_wifi">ناقابل اعتماد وائی فائی پر سرنگ</string>
<string name="email_subject">ڈبلیو جی ٹنل سپورٹ</string>
<string name="docs_description">دستاویزات پڑھیں</string>
<string name="email_description">مجھے ایک ای میل بھیجیں۔</string>
@@ -56,9 +56,9 @@
<string name="error_ssid_exists">SSID پہلے سے موجود ہے۔</string>
<string name="error_root_denied">روٹ شیل سے انکار کر دیا گیا۔</string>
<string name="error_no_file_explorer">کوئی فائل ایکسپلورر انسٹال نہیں ہے۔</string>
<string name="auto_tunnel_title">خودکار ٹنل سروس</string>
<string name="delete_tunnel">ٹنل کو حذف کریں</string>
<string name="delete_tunnel_message">کیا آپ واقعی اس ٹنل کو حذف کرنا چاہیں گے؟</string>
<string name="auto_tunnel_title">آٹو ٹنل سروس</string>
<string name="delete_tunnel">سرنگ کو حذف کریں۔</string>
<string name="delete_tunnel_message">کیا آپ واقعی اس سرنگ کو حذف کرنا چاہیں گے؟</string>
<string name="yes">جی ہاں</string>
<string name="all">تمام</string>
<string name="no_email_detected">کوئی ای میل ایپ نہیں ملی</string>
@@ -70,14 +70,14 @@
<string name="pin_created">پن کامیابی کے ساتھ بن گیا۔</string>
<string name="create_pin">پن بنائیں</string>
<string name="restart_on_ping">پنگ فیل پر دوبارہ شروع کریں (بی ٹا)</string>
<string name="set_primary_tunnel">بنیادی ٹنل کے طور پر سیٹ کریں</string>
<string name="set_primary_tunnel">بنیادی سرنگ کے طور پر سیٹ کریں۔</string>
<string name="version">ورژن</string>
<string name="junk_packet_count">ردی کے پیکٹ کی گنتی</string>
<string name="init_packet_junk_size">Init پیکٹ ردی کا سائز</string>
<string name="init_packet_magic_header">Init پیکٹ میجک ہیڈر</string>
<string name="transport_packet_magic_header">ٹرانسپورٹ پیکٹ میجک ہیڈر</string>
<string name="see_the">دیکھیں</string>
<string name="error_file_format">غلط ٹنل کنفیگریشن فارمیٹ</string>
<string name="error_file_format">غلط سرنگ کنفیگریشن فارمیٹ</string>
<string name="vpn_denied_dialog_title">اجازت نامنظور</string>
<string name="vpn_settings">VPN سسٹم کی ترتیبات</string>
<string name="always_on_message">VPN کنکشن کی اجازت مسترد کر دی گئی ہے۔ براہ کرم چیک کریں۔</string>
@@ -95,17 +95,17 @@
<string name="language">زبان</string>
<string name="display_theme">ڈسپلے تھیم</string>
<string name="trusted_wifi_names">قابل اعتماد وائی فائی نام</string>
<string name="primary_tunnel">بنیادی ٹنل</string>
<string name="primary_tunnel">بنیادی سرنگ</string>
<string name="mobile_tunnel">موبائل ڈیٹا ٹنل</string>
<string name="skip">چھوڑیں۔</string>
<string name="learn_more">مزید جانیں</string>
<string name="kernel_not_supported">کرنل تعاون یافتہ نہیں ہے۔</string>
<string name="start_auto">خودکار ٹنل شروع کریں</string>
<string name="start_auto">آٹو ٹنل شروع کریں۔</string>
<string name="donate">پروجیکٹ کے لیے عطیہ کریں۔</string>
<string name="local_logging">مقامی لاگنگ</string>
<string name="enable_local_logging">مقامی لاگنگ کو فعال کریں۔</string>
<string name="stop_on_no_internet">بغیر انٹرنیٹ پر رکیں۔</string>
<string name="stop_on_internet_loss">انٹرنیٹ بند ہونے پر ٹنل روکیں</string>
<string name="stop_on_internet_loss">انٹرنیٹ کے نقصان پر سرنگ کو روکیں۔</string>
<string name="vpn_kill_switch">VPN کِل سوئچ</string>
<string name="kill_switch_options">کِل سوئچ کے اختیارات</string>
<string name="allow_lan_traffic">LAN ٹریفک کی اجازت دیں۔</string>
@@ -122,22 +122,22 @@
<string name="hide_amnezia_properties">Amnezia کی خصوصیات کو چھپائیں۔</string>
<string name="exclude_lan">LAN کو خارج کریں۔</string>
<string name="include_lan">LAN شامل کریں۔</string>
<string name="auto_tunnel">خودکار ٹنل</string>
<string name="auto_tunnel">خودکار سرنگ</string>
<string name="kill_switch_off">قابل اعتماد پر کِل سوئچ کو بند کریں۔</string>
<string name="server_ipv4">IPv4 میزبان نام کی قرارداد</string>
<string name="multiple">متعدد</string>
<string name="prominent_background_location_message">اس فیچر کو ایپلیکیشن بند ہونے کے باوجود بھی Wi-Fi SSID مانیٹرنگ کو فعال کرنے کے لیے پس منظر کی جگہ کی اجازت درکار ہے۔ مزید تفصیلات کے لیے، براہ کرم سپورٹ اسکرین پر منسلک رازداری کی پالیسی دیکھیں۔</string>
<string name="email_chooser">ای میل بھیجیں…</string>
<string name="add_tunnels_text">فائل یا زپ سے شامل کریں</string>
<string name="add_tunnels_text">فائل یا زپ سے شامل کریں۔</string>
<string name="config_changes_saved">کنفیگریشن تبدیلیاں محفوظ ہو گئیں۔</string>
<string name="auto_tunneling">خودکار ٹنلنگ</string>
<string name="auto_tunneling">خودکار سرنگ</string>
<string name="create_import">شروع سے تخلیق کریں۔</string>
<string name="unknown_error">نامعلوم خرابی پیش آگئی</string>
<string name="seconds">سیکنڈ</string>
<string name="persistent_keepalive">مسلسل زندہ رہنا</string>
<string name="remove_amnezia_compatibility">Amnezia مطابقت کو ہٹا دیں۔</string>
<string name="light">روشنی</string>
<string name="set_ethernet_tunnel">ایتھرنیٹ ٹنل کے طور پر سیٹ کریں</string>
<string name="set_ethernet_tunnel">ایتھرنیٹ ٹنل کے طور پر سیٹ کریں۔</string>
<string name="launch_app_settings">ایپ کی ترتیبات شروع کریں۔</string>
<string name="monitoring_state_changes">ریاستی تبدیلیوں کی نگرانی</string>
<string name="set_custom_ping_internal">پنگ وقفہ (سیکنڈ)</string>
@@ -148,13 +148,13 @@
<string name="handshake">مصافحہ</string>
<string name="response_packet_magic_header">رسپانس پیکٹ میجک ہیڈر</string>
<string name="unsure_how">اگر آپ کو یقین نہیں ہے کہ کیسے آگے بڑھیں۔</string>
<string name="use_tunnel_on_wifi_name">وائی فائی نام پر ٹنل استعمال کریں</string>
<string name="use_tunnel_on_wifi_name">وائی فائی نام پر ٹنل استعمال کریں۔</string>
<string name="optional_default">"اختیاری، ڈیفالٹ: "</string>
<string name="use_root_shell_for_wifi">وائی فائی کا نام حاصل کرنے کے لیے روٹ شیل کا استعمال کریں۔</string>
<string name="response_packet_junk_size">رسپانس پیکٹ ردی کا سائز</string>
<string name="junk_packet_minimum_size">جنک پیکٹ کا کم از کم سائز</string>
<string name="mobile_data_tunnel">موبائل ڈیٹا ٹنل کے طور پر سیٹ کریں</string>
<string name="edit_tunnel">ٹنل میں ترمیم کریں</string>
<string name="mobile_data_tunnel">موبائل ڈیٹا ٹنل کے طور پر سیٹ کریں۔</string>
<string name="edit_tunnel">سرنگ میں ترمیم کریں۔</string>
<string name="enable_app_lock">ایپ لاک کو فعال کریں۔</string>
<string name="logs">نوشتہ جات</string>
<string name="kernel">کرنل</string>
@@ -167,9 +167,9 @@
<string name="kill_switch">کِل سوئچ</string>
<string name="prefer_ipv4">IPv4 کنکشن کو ترجیح دیں۔</string>
<string name="native_kill_switch">مقامی قتل سوئچ</string>
<string name="auto_tunnel_channel_description">خودکار ٹنل اسٹیٹ کی اطلاعات کے لیے ایک چینل</string>
<string name="auto_tunnel_channel_description">خودکار سرنگ ریاست کی اطلاعات کے لیے ایک چینل</string>
<string name="use_wildcards">نام وائلڈ کارڈ استعمال کریں۔</string>
<string name="stop_auto">خودکار ٹنل روکیں</string>
<string name="stop_auto">آٹو ٹنل بند کرو</string>
<string name="add_wifi_name">وائی فائی کا نام شامل کریں۔</string>
<string name="wildcards_active">وائلڈ کارڈز فعال</string>
<string name="bypass_lan_for_kill_switch">کِل سوئچ کے لیے LAN کو بائی پاس کریں۔</string>
@@ -178,9 +178,9 @@
<string name="underload_packet_magic_header">پیکٹ میجک ہیڈر کو انڈر لوڈ کریں۔</string>
<string name="background_location_message">اس خصوصیت کے لیے ہر وقت مقام کی اجازت اور/یا درست مقام کی ضرورت ہے۔ ملاحظہ فرمائیں</string>
<string name="always_on_message2">یہ یقینی بنانے کے لیے کہ ہمیشہ آن VPN دیگر تمام ایپس کے لیے بند ہے اور دوبارہ کوشش کریں۔</string>
<string name="ethernet_tunnel">ایتھرنیٹ ٹنل</string>
<string name="auto_tunnel_channel_name">خودکار ٹنل نوٹیفکیشن چینل</string>
<string name="tunnel_running">ٹنل چل رہا ہے</string>
<string name="ethernet_tunnel">ایتھرنیٹ سرنگ</string>
<string name="auto_tunnel_channel_name">آٹو ٹنل نوٹیفکیشن چینل</string>
<string name="tunnel_running">ٹنل چل رہا ہے۔</string>
<string name="tunnel_control">ٹنل کنٹرول</string>
<string name="vpn_channel_description">VPN ریاستی اطلاعات کے لیے ایک چینل</string>
<string name="hide_scripts">اسکرپٹ چھپائیں۔</string>
@@ -189,7 +189,7 @@
<string name="enable_remote_app_control">ریموٹ ایپ کنٹرول کو فعال کریں۔</string>
<string name="kernel_name_error">کرنل ماڈیول نام کی خرابی۔</string>
<string name="app_permission_title">ڈبلیو جی ٹنل کنٹرول برج</string>
<string name="app_permission_description">ٹنل اور خودکار ٹنل کی خصوصیات کو کنٹرول کریں۔</string>
<string name="app_permission_description">سرنگوں اور خودکار سرنگ کی خصوصیات کو کنٹرول کریں۔</string>
<string name="add_from_url">یو آر ایل سے شامل کریں۔</string>
<string name="enter_config_url">ترتیب یو آر ایل درج کریں۔</string>
<string name="error_download_failed">کنفیگریشن ڈاؤن لوڈ کرنے میں ناکام</string>
@@ -199,15 +199,15 @@
<string name="join_telegram">ٹیلیگرام کمیونٹی میں شامل ہوں۔</string>
<string name="matrix_url">https://matrix.to/#/#wg-tunnel-space:matrix.org</string>
<string name="dropdown">ڈراپ ڈاؤن</string>
<string name="add_tunnel">ٹنل شامل کریں</string>
<string name="add_tunnel">سرنگ شامل کریں۔</string>
<string name="export_logs">ذخیرہ شدہ نوشتہ جات برآمد کریں۔</string>
<string name="copy">نقل</string>
<string name="info">معلومات</string>
<string name="export_tunnels_wireguard">وائر گارڈ کے بطور ٹنلز برآمد کریں</string>
<string name="export_tunnels_wireguard">وائر گارڈ کے بطور سرنگیں برآمد کریں۔</string>
<string name="delete">حذف کریں۔</string>
<string name="camera_permission_required">کیمرے کی اجازت درکار ہے۔</string>
<string name="export_failed">ایکسپورٹ ناکام ہو گیا۔</string>
<string name="tunnel_error_template">ٹنل اس کے ساتھ ناکام ہوگئی: %1$s</string>
<string name="tunnel_error_template">سرنگ اس کے ساتھ ناکام ہوگئی: %1$s</string>
<string name="wifi_name_template">فعال: %1$s</string>
<string name="config_error">کنفگریشن کی خرابی</string>
<string name="dns_resolve_error">ڈی این ایس ریزولوشن کی خرابی۔</string>
@@ -220,32 +220,11 @@
<string name="bio_not_supported">بایومیٹرکس تعاون یافتہ نہیں ہیں۔</string>
<string name="bio_not_created">بائیو میٹرکس نہیں بنائے گئے۔</string>
<string name="bio_update_required">بائیو میٹرک سیکیورٹی اپ ڈیٹ درکار ہے۔</string>
<string name="tunnel_starting">ٹنل چل رہی ہے</string>
<string name="tunnel_starting">سرنگ شروع ہو رہی ہے۔</string>
<string name="nothing_here_yet">ابھی تک یہاں کچھ نہیں!</string>
<string name="join_matrix">میٹرکس کمیونٹی میں شامل ہوں۔</string>
<string name="delete_logs">نوشتہ جات کو حذف اور صاف کریں۔</string>
<string name="export_tunnels_amnezia">ایمنیزیا کے طور پر ٹنلز برآمد کریں</string>
<string name="export_tunnels_amnezia">ایمنیزیا کے طور پر سرنگیں برآمد کریں۔</string>
<string name="bio_subtitle">اپنی بائیو میٹرک اسناد کا استعمال کرتے ہوئے لاگ ان کریں۔</string>
<string name="bio_auth_title">بائیو میٹرک تصدیق</string>
<string name="share">شیئر کریں۔</string>
<string name="select_all">سبھی کو منتخب کریں۔</string>
<string name="check_for_update">اپ ڈیٹ کے لیے چیک کریں۔</string>
<string name="update_check_failed">اپ ڈیٹ چیک ناکام ہو گیا۔</string>
<string name="checking_for_update">اپ ڈیٹس کی جانچ ہو رہی ہے۔</string>
<string name="update_download_failed">اپ ڈیٹ ڈاؤن لوڈ ناکام ہو گیا۔</string>
<string name="update_available">اپ ڈیٹ دستیاب ہے!</string>
<string name="download_and_install">ڈاؤن لوڈ اور انسٹال کریں۔</string>
<string name="permission_required">اجازت درکار ہے۔</string>
<string name="install_updated_permission">اس ایپ کو اپ ڈیٹس انسٹال کرنے کے لیے اجازت درکار ہے۔</string>
<string name="allow">اجازت دیں۔</string>
<string name="licenses">لائسنس</string>
<string name="download">ڈاؤن لوڈ کریں۔</string>
<string name="version_template">ورژن: %1$s</string>
<string name="export_success">برآمد کی کامیابی</string>
<string name="latest_installed">آپ پہلے ہی تازہ ترین ورژن چلا رہے ہیں۔</string>
<string name="darker">گہرا</string>
<string name="amoled">ایمولیڈ</string>
<string name="security_template">سیکیورٹی: %1$s</string>
<string name="update_check_unsupported">اپ ڈیٹ چیک اس قسم کی تعمیر کی حمایت نہیں کرتا ہے۔</string>
<string name="flavor_template">ذائقہ: %1$s</string>
</resources>
+1 -5
View File
@@ -1,6 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="no_tunnels">Chưa có đường nối nào!</string>
<string name="tunnels">Các đường nối</string>
<string name="error_file_extension">Tệp không phải .conf hay .zip</string>
</resources>
<resources></resources>
@@ -227,29 +227,4 @@
<string name="export_logs">导出已保存的日志</string>
<string name="bio_not_supported">生物特征不受支持</string>
<string name="nothing_here_yet">此处还什么都没有!</string>
<string name="select_all">全选</string>
<string name="share">分享</string>
<string name="version_template">当前版本:%1$s</string>
<string name="export_success">导出成功</string>
<string name="download">下载</string>
<string name="check_for_update">检查更新</string>
<string name="update_check_failed">更新检查失败了。</string>
<string name="checking_for_update">正在检查更新</string>
<string name="latest_installed">你已经在运行最新版本。</string>
<string name="update_download_failed">更新下载失败。</string>
<string name="update_available">有更新可用!</string>
<string name="download_and_install">下载并安装</string>
<string name="permission_required">需要权限</string>
<string name="licenses">许可证</string>
<string name="install_updated_permission">本应用需要权限来安装更新。</string>
<string name="allow">允许</string>
<string name="update_check_unsupported">更新检查不支持此构建类型。</string>
<string name="flavor_template">版本架构:%1$s</string>
<string name="security_template">安全性:%1$s</string>
<string name="darker">颜色更深</string>
<string name="amoled">AMOLED</string>
<string name="show_qr">显示二维码</string>
<string name="amnezia">Amnezia</string>
<string name="wireguard">WireGuard</string>
<string name="done">完成</string>
</resources>

Some files were not shown because too many files have changed in this diff Show More