From 830e4e94f3ac3ef354ab33487bbf547c7b90a644 Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 10 Apr 2026 09:51:07 +0300 Subject: [PATCH 1/3] #1212: adding support for wg:// config URIs --- app/src/main/AndroidManifest.xml | 7 +++++++ .../wireguardautotunnel/MainActivity.kt | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3ca3a2edd..727a8c7a4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -73,6 +73,13 @@ + + + + + + + diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/MainActivity.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/MainActivity.kt index 3165f059d..4cef9a827 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/MainActivity.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/MainActivity.kt @@ -151,6 +151,8 @@ class MainActivity : AppCompatActivity() { roomBackup = RoomBackup(this) + handleWgIntent(intent) + installSplashScreen().apply { setKeepOnScreenCondition { !viewModel.container.stateFlow.value.isAppLoaded } } @@ -514,6 +516,21 @@ class MainActivity : AppCompatActivity() { } } + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + handleWgIntent(intent) + } + + private fun handleWgIntent(intent: Intent) { + if (intent.action == Intent.ACTION_VIEW) { + val uri = intent.data ?: return + if (uri.scheme == "wg") { + val httpsUrl = uri.toString().replaceFirst("wg://", "https://") + viewModel.importFromUrl(httpsUrl) + } + } + } + override fun onResume() { super.onResume() networkMonitor.checkPermissionsAndUpdateState() From 409883135de01f10fc821a213b321991ea185620 Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 10 Apr 2026 10:30:44 +0300 Subject: [PATCH 2/3] #1212: adding confirmation dialog before import from wg:// --- .../wireguardautotunnel/MainActivity.kt | 21 ++++++++++++++++++- .../ui/state/GlobalAppUiState.kt | 1 + .../viewmodel/SharedAppViewModel.kt | 8 +++++++ app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 6 files changed, 32 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/MainActivity.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/MainActivity.kt index 4cef9a827..31ac4cab5 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/MainActivity.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/MainActivity.kt @@ -3,6 +3,7 @@ package com.zaneschepke.wireguardautotunnel import ProxySettingsScreen import android.content.Intent import android.graphics.Color +import android.net.Uri import android.net.VpnService import android.os.Build import android.os.Bundle @@ -29,6 +30,7 @@ import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect @@ -69,6 +71,7 @@ import com.zaneschepke.wireguardautotunnel.domain.sideeffect.GlobalSideEffect import com.zaneschepke.wireguardautotunnel.ui.LocalIsAndroidTV import com.zaneschepke.wireguardautotunnel.ui.LocalNavController import com.zaneschepke.wireguardautotunnel.ui.common.banner.AppAlertBanner +import com.zaneschepke.wireguardautotunnel.ui.common.dialog.InfoDialog import com.zaneschepke.wireguardautotunnel.ui.common.dialog.VpnDeniedDialog import com.zaneschepke.wireguardautotunnel.ui.common.snackbar.CustomSnackBar import com.zaneschepke.wireguardautotunnel.ui.common.snackbar.SnackbarInfo @@ -268,6 +271,22 @@ class MainActivity : AppCompatActivity() { }, ) + uiState.pendingWgImportUrl?.let { url -> + val host = Uri.parse(url).host ?: url + InfoDialog( + onDismiss = { viewModel.dismissWgImport() }, + onAttest = { + viewModel.dismissWgImport() + viewModel.importFromUrl(url) + }, + title = stringResource(R.string.add_from_url), + body = { + Text(stringResource(R.string.wg_url_confirm_message, host)) + }, + confirmText = stringResource(R.string.okay), + ) + } + val annotatedMessage = buildAnnotatedString { append(context.getString(R.string.donation_prompt_prefix)) append(" ") @@ -526,7 +545,7 @@ class MainActivity : AppCompatActivity() { val uri = intent.data ?: return if (uri.scheme == "wg") { val httpsUrl = uri.toString().replaceFirst("wg://", "https://") - viewModel.importFromUrl(httpsUrl) + viewModel.promptWgImport(httpsUrl) } } } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/state/GlobalAppUiState.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/state/GlobalAppUiState.kt index 42f708258..3d963e742 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/state/GlobalAppUiState.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/state/GlobalAppUiState.kt @@ -18,4 +18,5 @@ data class GlobalAppUiState( val selectedTunnelCount: Int = 0, val alreadyDonated: Boolean = false, val isPinVerified: Boolean = false, + val pendingWgImportUrl: String? = null, ) diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/viewmodel/SharedAppViewModel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/viewmodel/SharedAppViewModel.kt index ce326db19..fdfe2367c 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/viewmodel/SharedAppViewModel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/viewmodel/SharedAppViewModel.kt @@ -300,6 +300,14 @@ class SharedAppViewModel( fun importFromQr(conf: String) = intent { importFromClipboard(conf) } + fun promptWgImport(url: String) = intent { + reduce { state.copy(pendingWgImportUrl = url) } + } + + fun dismissWgImport() = intent { + reduce { state.copy(pendingWgImportUrl = null) } + } + fun importFromUrl(url: String) = intent { try { httpClient.prepareGet(url).execute { response -> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 7f48eb0d4..760b208d5 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -156,6 +156,7 @@ Ungültige Konfiguration Matrix-Community beitreten Download der Konfiguration fehlgeschlagen + Möchtest du wirklich Tunnel von %1$s hinzufügen? Verbinde dich niemals mit einem nicht vertrauenswürdigen VPN! Von URL hinzufügen Gespeicherte Logs exportieren Steuere Tunnel und Auto-Tunnel Funktionen. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 0d75ff504..1b3b51d21 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -182,6 +182,7 @@ Экспорт туннелей как WireGuard Удалённое управление приложением Невозможно скачать конфигурацию + Добавить туннели от %1$s? Никогда не подключайтесь к неизвестному VPN! Здесь пока ничего нет! Выбрать все Экспорт успешно выполнен diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f2797ec25..0474cc71b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -170,6 +170,7 @@ Add from URL Enter config URL Failed to download config + Are you sure you want to add tunnels from %1$s? Never connect to an untrusted VPN! Save Search Select From ee4f1f0c19cfe296a3a2dd91fd344df91986e24e Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 10 Apr 2026 10:39:24 +0300 Subject: [PATCH 3/3] #1212: tweaking wg:// confirmation dialog --- .../java/com/zaneschepke/wireguardautotunnel/MainActivity.kt | 5 +---- .../wireguardautotunnel/viewmodel/SharedAppViewModel.kt | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/MainActivity.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/MainActivity.kt index 31ac4cab5..e76b33aee 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/MainActivity.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/MainActivity.kt @@ -275,10 +275,7 @@ class MainActivity : AppCompatActivity() { val host = Uri.parse(url).host ?: url InfoDialog( onDismiss = { viewModel.dismissWgImport() }, - onAttest = { - viewModel.dismissWgImport() - viewModel.importFromUrl(url) - }, + onAttest = { viewModel.importFromUrl(url) }, title = stringResource(R.string.add_from_url), body = { Text(stringResource(R.string.wg_url_confirm_message, host)) diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/viewmodel/SharedAppViewModel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/viewmodel/SharedAppViewModel.kt index fdfe2367c..4cb9515a2 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/viewmodel/SharedAppViewModel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/viewmodel/SharedAppViewModel.kt @@ -309,6 +309,7 @@ class SharedAppViewModel( } fun importFromUrl(url: String) = intent { + reduce { state.copy(pendingWgImportUrl = null) } try { httpClient.prepareGet(url).execute { response -> if (response.status.value in 200..299) {