diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
index 25d575d..a42d733 100644
--- a/.github/workflows/android.yml
+++ b/.github/workflows/android.yml
@@ -70,7 +70,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
# fix hardcode changelog file name
- body_path: ${{ github.workspace }}/fastlane/metadata/android/en-US/changelogs/32200.txt
+ body_path: ${{ github.workspace }}/fastlane/metadata/android/en-US/changelogs/32300.txt
tag_name: ${{ github.ref_name }}
name: Release ${{ github.ref_name }}
draft: false
diff --git a/app/schemas/com.zaneschepke.wireguardautotunnel.repository.AppDatabase/3.json b/app/schemas/com.zaneschepke.wireguardautotunnel.repository.AppDatabase/3.json
new file mode 100644
index 0000000..d5d93a3
--- /dev/null
+++ b/app/schemas/com.zaneschepke.wireguardautotunnel.repository.AppDatabase/3.json
@@ -0,0 +1,133 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 3,
+ "identityHash": "6b30daba29bb95f8ddc4d26206329d4f",
+ "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, `default_tunnel` TEXT, `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_battery_saver_enabled` INTEGER NOT NULL DEFAULT false, `is_tunnel_on_wifi_enabled` INTEGER NOT NULL DEFAULT false)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isAutoTunnelEnabled",
+ "columnName": "is_tunnel_enabled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isTunnelOnMobileDataEnabled",
+ "columnName": "is_tunnel_on_mobile_data_enabled",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "trustedNetworkSSIDs",
+ "columnName": "trusted_network_ssids",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "defaultTunnel",
+ "columnName": "default_tunnel",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "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": "isBatterySaverEnabled",
+ "columnName": "is_battery_saver_enabled",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "false"
+ },
+ {
+ "fieldPath": "isTunnelOnWifiEnabled",
+ "columnName": "is_tunnel_on_wifi_enabled",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "false"
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "TunnelConfig",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `wg_quick` TEXT NOT NULL)",
+ "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
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_TunnelConfig_name",
+ "unique": true,
+ "columnNames": [
+ "name"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_TunnelConfig_name` ON `${TABLE_NAME}` (`name`)"
+ }
+ ],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '6b30daba29bb95f8ddc4d26206329d4f')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/Constants.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/Constants.kt
index 39cd44f..f7305ef 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/Constants.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/Constants.kt
@@ -16,4 +16,5 @@ object Constants {
const val ALLOWED_FILE_TYPES = "*/*"
const val GOOGLE_TV_EXPLORER_STUB = "com.google.android.tv.frameworkpackagestubs"
const val ANDROID_TV_EXPLORER_STUB = "com.android.tv.frameworkpackagestubs"
+ const val EMAIL_MIME_TYPE = "message/rfc822"
}
\ No newline at end of file
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/AppDatabase.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/AppDatabase.kt
index ebfff9f..e56968f 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/AppDatabase.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/AppDatabase.kt
@@ -7,8 +7,8 @@ import androidx.room.TypeConverters
import com.zaneschepke.wireguardautotunnel.repository.model.Settings
import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig
-@Database(entities = [Settings::class, TunnelConfig::class], version = 2, autoMigrations = [
- AutoMigration(from = 1, to = 2)
+@Database(entities = [Settings::class, TunnelConfig::class], version = 3, autoMigrations = [
+ AutoMigration(from = 1, to = 2), AutoMigration(from = 2, to = 3)
], exportSchema = true)
@TypeConverters(DatabaseListConverters::class)
abstract class AppDatabase : RoomDatabase() {
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/model/Settings.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/model/Settings.kt
index 68d6aab..77bcb3f 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/model/Settings.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/model/Settings.kt
@@ -15,6 +15,7 @@ data class Settings(
@ColumnInfo(name = "is_tunnel_on_ethernet_enabled") var isTunnelOnEthernetEnabled : Boolean = false,
@ColumnInfo(name = "is_shortcuts_enabled", defaultValue = "false") var isShortcutsEnabled : Boolean = false,
@ColumnInfo(name = "is_battery_saver_enabled", defaultValue = "false") var isBatterySaverEnabled : Boolean = false,
+ @ColumnInfo(name = "is_tunnel_on_wifi_enabled", defaultValue = "false") var isTunnelOnWifiEnabled : Boolean = false,
) {
fun isTunnelConfigDefault(tunnelConfig: TunnelConfig) : Boolean {
return if (defaultTunnel != null) {
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/WireGuardConnectivityWatcherService.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/WireGuardConnectivityWatcherService.kt
index dcb204e..73af37d 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/WireGuardConnectivityWatcherService.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/WireGuardConnectivityWatcherService.kt
@@ -261,6 +261,7 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
ServiceManager.stopVpnService(this)
} else if (!isEthernetConnected && isWifiConnected &&
!setting.trustedNetworkSSIDs.contains(currentNetworkSSID) &&
+ setting.isTunnelOnWifiEnabled &&
(vpnService.getState() != Tunnel.State.UP)
) {
ServiceManager.startVpnService(this, tunnelConfig)
@@ -269,6 +270,11 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
(vpnService.getState() == Tunnel.State.UP)
) {
ServiceManager.stopVpnService(this)
+ } else if (!isEthernetConnected && (isWifiConnected &&
+ !setting.isTunnelOnWifiEnabled &&
+ (vpnService.getState() == Tunnel.State.UP)
+ )) {
+ ServiceManager.stopVpnService(this)
}
delay(Constants.VPN_CONNECTIVITY_CHECK_INTERVAL)
}
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt
index de8f802..e66e843 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt
@@ -440,10 +440,12 @@ fun MainScreen(
}
}
} else {
+ val checked = state == Tunnel.State.UP && tunnel.name == tunnelName
+ if(!checked) expanded.value = false
@Composable
fun TunnelSwitch() = Switch(
modifier = Modifier.focusRequester(focusRequester),
- checked = (state == Tunnel.State.UP && tunnel.name == tunnelName),
+ checked = checked,
onCheckedChange = { checked ->
if(!checked) expanded.value = false
onTunnelToggle(checked, tunnel)
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsScreen.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsScreen.kt
index 6044634..de88650 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsScreen.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsScreen.kt
@@ -5,6 +5,7 @@ import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.Settings
+import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
@@ -104,6 +105,8 @@ fun SettingsScreen(
var showAuthPrompt by remember { mutableStateOf(false) }
var didExportFiles by remember { mutableStateOf(false) }
+
+
val screenPadding = 5.dp
val fillMaxWidth = .85f
@@ -276,8 +279,11 @@ fun SettingsScreen(
modifier = (if (WireGuardAutoTunnel.isRunningOnAndroidTv(context))
Modifier
.height(IntrinsicSize.Min)
- .fillMaxWidth(fillMaxWidth).padding(top = 10.dp)
- else Modifier.fillMaxWidth(fillMaxWidth).padding(top = 60.dp)).padding(bottom = 25.dp)
+ .fillMaxWidth(fillMaxWidth)
+ .padding(top = 10.dp)
+ else Modifier
+ .fillMaxWidth(fillMaxWidth)
+ .padding(top = 60.dp)).padding(bottom = 25.dp)
) {
Column(
horizontalAlignment = Alignment.Start,
@@ -285,66 +291,77 @@ fun SettingsScreen(
modifier = Modifier.padding(15.dp)
) {
SectionTitle(title = stringResource(id = R.string.auto_tunneling), padding = screenPadding)
- Text(
- stringResource(R.string.trusted_ssid),
- textAlign = TextAlign.Center,
- modifier = Modifier.padding(screenPadding, bottom = 5.dp, top = 5.dp)
+ ConfigurationToggle(
+ stringResource(id = R.string.tunnel_on_wifi),
+ enabled = !(settings.isAutoTunnelEnabled || settings.isAlwaysOnVpnEnabled),
+ checked = settings.isTunnelOnWifiEnabled,
+ padding = screenPadding,
+ onCheckChanged = {
+ scope.launch {
+ viewModel.onToggleTunnelOnWifi()
+ }
+ },
+ modifier = Modifier.focusRequester(focusRequester)
)
- val focus = Modifier.focusRequester(focusRequester)
- FlowRow(
- modifier = (if(trustedSSIDs.isEmpty()) Modifier else
- focus).padding(screenPadding),
- horizontalArrangement = Arrangement.spacedBy(8.dp),
- verticalArrangement = Arrangement.SpaceEvenly
- ) {
- trustedSSIDs.forEach { ssid ->
- ClickableIconButton(
- onIconClick = {
- scope.launch {
- viewModel.onDeleteTrustedSSID(ssid)
+ AnimatedVisibility(visible = settings.isTunnelOnWifiEnabled) {
+ Column {
+ FlowRow(
+ modifier = Modifier.padding(screenPadding),
+ horizontalArrangement = Arrangement.spacedBy(8.dp),
+ verticalArrangement = Arrangement.SpaceEvenly
+ ) {
+ trustedSSIDs.forEach { ssid ->
+ ClickableIconButton(
+ onIconClick = {
+ scope.launch {
+ viewModel.onDeleteTrustedSSID(ssid)
+ }
+ },
+ text = ssid,
+ icon = Icons.Filled.Close,
+ enabled = !(settings.isAutoTunnelEnabled || settings.isAlwaysOnVpnEnabled)
+ )
+ }
+ if(trustedSSIDs.isEmpty()) {
+ Text(stringResource(R.string.none), fontStyle = FontStyle.Italic, color = Color.Gray)
+ }
+ }
+ OutlinedTextField(
+ enabled = !(settings.isAutoTunnelEnabled || settings.isAlwaysOnVpnEnabled),
+ value = currentText,
+ onValueChange = { currentText = it },
+ label = { Text(stringResource(R.string.add_trusted_ssid)) },
+ modifier = Modifier
+ .padding(start = screenPadding, top = 5.dp, bottom = 10.dp)
+ .onFocusChanged {
+ if (WireGuardAutoTunnel.isRunningOnAndroidTv(context)) {
+ keyboardController?.hide()
+ }
+ },
+ maxLines = 1,
+ keyboardOptions = KeyboardOptions(
+ capitalization = KeyboardCapitalization.None,
+ imeAction = ImeAction.Done
+ ),
+ keyboardActions = KeyboardActions(
+ onDone = {
+ saveTrustedSSID()
+ }
+ ),
+ trailingIcon = {
+ IconButton(onClick = { saveTrustedSSID() }) {
+ Icon(
+ imageVector = Icons.Outlined.Add,
+ contentDescription = if (currentText == "") stringResource(id = R.string.trusted_ssid_empty_description) else stringResource(
+ id = R.string.trusted_ssid_value_description
+ ),
+ tint = if (currentText == "") Color.Transparent else MaterialTheme.colorScheme.primary
+ )
}
},
- text = ssid,
- icon = Icons.Filled.Close,
- enabled = !(settings.isAutoTunnelEnabled || settings.isAlwaysOnVpnEnabled)
)
}
- if(trustedSSIDs.isEmpty()) {
- Text(stringResource(R.string.none), fontStyle = FontStyle.Italic, color = Color.Gray)
- }
}
- OutlinedTextField(
- enabled = !(settings.isAutoTunnelEnabled || settings.isAlwaysOnVpnEnabled),
- value = currentText,
- onValueChange = { currentText = it },
- label = { Text(stringResource(R.string.add_trusted_ssid)) },
- modifier = (if(trustedSSIDs.isEmpty()) focus else Modifier).padding(start = screenPadding, top = 5.dp).onFocusChanged {
- if(WireGuardAutoTunnel.isRunningOnAndroidTv(context)) {
- keyboardController?.hide()
- }
- },
- maxLines = 1,
- keyboardOptions = KeyboardOptions(
- capitalization = KeyboardCapitalization.None,
- imeAction = ImeAction.Done
- ),
- keyboardActions = KeyboardActions(
- onDone = {
- saveTrustedSSID()
- }
- ),
- trailingIcon = {
- IconButton(onClick = { saveTrustedSSID() }) {
- Icon(
- imageVector = Icons.Outlined.Add,
- contentDescription = if (currentText == "") stringResource(id = R.string.trusted_ssid_empty_description) else stringResource(
- id = R.string.trusted_ssid_value_description
- ),
- tint = if (currentText == "") Color.Transparent else MaterialTheme.colorScheme.primary
- )
- }
- },
- )
ConfigurationToggle(stringResource(R.string.tunnel_mobile_data),
enabled = !(settings.isAutoTunnelEnabled || settings.isAlwaysOnVpnEnabled),
checked = settings.isTunnelOnMobileDataEnabled,
@@ -376,27 +393,36 @@ fun SettingsScreen(
}
}
)
- ConfigurationToggle(stringResource(R.string.enable_auto_tunnel),
- enabled = !settings.isAlwaysOnVpnEnabled,
- checked = settings.isAutoTunnelEnabled,
- padding = screenPadding,
- onCheckChanged = {
- if(!isAllAutoTunnelPermissionsEnabled()) {
- val message = if(viewModel.isLocationServicesNeeded()){
- context.getString(R.string.location_services_required)
- } else if(!isBackgroundLocationGranted){
- context.getString(R.string.background_location_required)
- } else {
- context.getString(R.string.precise_location_required)
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(top = 5.dp),
+ horizontalArrangement = Arrangement.Center
+ ) {
+ TextButton(
+ enabled = !settings.isAlwaysOnVpnEnabled,
+ onClick = {
+ //TODO fix logic for mobile only
+ if(!isAllAutoTunnelPermissionsEnabled() && settings.isTunnelOnWifiEnabled) {
+ val message = if(!isBackgroundLocationGranted) {
+ context.getString(R.string.background_location_required)
+ } else if(viewModel.isLocationServicesNeeded()) {
+ context.getString(R.string.location_services_required)
+ } else {
+ context.getString(R.string.precise_location_required)
+ }
+ showSnackbarMessage(message)
+ } else scope.launch {
+ viewModel.toggleAutoTunnel()
}
- showSnackbarMessage(message)
- } else scope.launch {
- viewModel.toggleAutoTunnel()
- }
+ }) {
+ val autoTunnelButtonText = if(settings.isAutoTunnelEnabled) stringResource(R.string.disable_auto_tunnel)
+ else stringResource(id = R.string.enable_auto_tunnel)
+ Text(autoTunnelButtonText)
}
- )
+ }
}
-
}
if(!WireGuardAutoTunnel.isRunningOnAndroidTv(context)) {
Surface(
@@ -404,7 +430,8 @@ fun SettingsScreen(
shadowElevation = 2.dp,
shape = RoundedCornerShape(12.dp),
color = MaterialTheme.colorScheme.surface,
- modifier = Modifier.fillMaxWidth(fillMaxWidth)
+ modifier = Modifier
+ .fillMaxWidth(fillMaxWidth)
.height(IntrinsicSize.Min)
.padding(bottom = 180.dp)
) {
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsViewModel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsViewModel.kt
index a72dd95..f7c4672 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsViewModel.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsViewModel.kt
@@ -137,4 +137,10 @@ class SettingsViewModel @Inject constructor(private val application : Applicatio
isBatterySaverEnabled = !_settings.value.isBatterySaverEnabled
))
}
+
+ suspend fun onToggleTunnelOnWifi() {
+ settingsRepo.save(_settings.value.copy(
+ isTunnelOnWifiEnabled = !_settings.value.isTunnelOnWifiEnabled
+ ))
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/support/SupportScreen.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/support/SupportScreen.kt
index 59d53c4..58a6eed 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/support/SupportScreen.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/support/SupportScreen.kt
@@ -1,22 +1,34 @@
package com.zaneschepke.wireguardautotunnel.ui.screens.support
import android.content.Intent
+import android.content.Intent.createChooser
import android.net.Uri
import androidx.compose.foundation.clickable
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.rounded.ArrowForward
+import androidx.compose.material.icons.rounded.Book
+import androidx.compose.material.icons.rounded.Mail
+import androidx.compose.material3.Divider
import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -31,18 +43,32 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
+import androidx.core.content.ContextCompat.startActivity
+import com.zaneschepke.wireguardautotunnel.BuildConfig
+import com.zaneschepke.wireguardautotunnel.Constants
import com.zaneschepke.wireguardautotunnel.R
+import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel
@Composable
fun SupportScreen(padding : PaddingValues, focusRequester: FocusRequester) {
val context = LocalContext.current
+ val fillMaxWidth = .85f
fun openWebPage(url: String) {
val webpage: Uri = Uri.parse(url)
val intent = Intent(Intent.ACTION_VIEW, webpage)
context.startActivity(intent)
}
+
+ fun launchEmail() {
+ val intent = Intent(Intent.ACTION_SEND).apply {
+ type = Constants.EMAIL_MIME_TYPE
+ putExtra(Intent.EXTRA_EMAIL, context.getString(R.string.my_email))
+ putExtra(Intent.EXTRA_SUBJECT, context.getString(R.string.email_subject))
+ }
+ startActivity(context,createChooser(intent, context.getString(R.string.email_chooser)),null)
+ }
Column(horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Top,
@@ -51,23 +77,65 @@ fun SupportScreen(padding : PaddingValues, focusRequester: FocusRequester) {
.verticalScroll(rememberScrollState())
.focusable()
.padding(padding)) {
- Text(stringResource(R.string.support_text), textAlign = TextAlign.Center, modifier = Modifier.padding(30.dp), fontSize = 15.sp)
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .padding(14.dp),
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.SpaceEvenly
+ Surface(
+ tonalElevation = 2.dp,
+ shadowElevation = 2.dp,
+ shape = RoundedCornerShape(12.dp),
+ color = MaterialTheme.colorScheme.surface,
+ modifier = (if (WireGuardAutoTunnel.isRunningOnAndroidTv(context))
+ Modifier
+ .height(IntrinsicSize.Min)
+ .fillMaxWidth(fillMaxWidth)
+ .padding(top = 10.dp)
+ else Modifier
+ .fillMaxWidth(fillMaxWidth)
+ .padding(top = 20.dp)).padding(bottom = 25.dp)
) {
- IconButton(onClick = {
- openWebPage(context.resources.getString(R.string.discord_url))
- }) {
- Icon(imageVector = ImageVector.vectorResource(R.drawable.discord), "Discord")
- }
- IconButton(modifier = Modifier.focusRequester(focusRequester),onClick = {
- openWebPage(context.resources.getString(R.string.github_url))
- }) {
- Icon(imageVector = ImageVector.vectorResource(R.drawable.github), "Github")
+ Column(modifier = Modifier.padding(20.dp)) {
+ Text(stringResource(R.string.thank_you), textAlign = TextAlign.Start, modifier = Modifier.padding(bottom = 20.dp), fontSize = 16.sp)
+ Text(stringResource(id = R.string.support_help_text), textAlign = TextAlign.Start, fontSize = 16.sp, modifier = Modifier.padding(bottom = 20.dp))
+ TextButton(onClick = { openWebPage(context.resources.getString(R.string.docs_url)) }, modifier = Modifier.padding(vertical = 5.dp).focusRequester(focusRequester)) {
+ Row(horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
+ Row {
+ Icon(Icons.Rounded.Book, stringResource(id = R.string.docs))
+ Text(stringResource(id = R.string.docs_description), textAlign = TextAlign.Justify, modifier = Modifier.padding(start = 10.dp))
+ }
+ Icon(Icons.Rounded.ArrowForward, stringResource(id = R.string.go))
+ }
+ }
+ Divider(color = MaterialTheme.colorScheme.onBackground, thickness = 0.5.dp)
+ TextButton(onClick = { openWebPage(context.resources.getString(R.string.discord_url)) }, modifier = Modifier.padding(vertical = 5.dp)) {
+ Row(horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
+ Row {
+ Icon(imageVector = ImageVector.vectorResource(R.drawable.discord), stringResource(
+ id = R.string.discord), Modifier.size(25.dp))
+ Text(stringResource(id = R.string.discord_description), textAlign = TextAlign.Justify, modifier = Modifier.padding(start = 10.dp))
+ }
+ Icon(Icons.Rounded.ArrowForward, stringResource(id = R.string.go))
+ }
+ }
+ Divider(color = MaterialTheme.colorScheme.onBackground, thickness = 0.5.dp)
+ TextButton(onClick = { openWebPage(context.resources.getString(R.string.github_url)) }, modifier = Modifier.padding(vertical = 5.dp)) {
+ Row(horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
+ Row {
+ Icon(imageVector = ImageVector.vectorResource(R.drawable.github), stringResource(
+ id = R.string.github
+ ), Modifier.size(25.dp))
+ Text("Open an issue", textAlign = TextAlign.Justify, modifier = Modifier.padding(start = 10.dp))
+ }
+ Icon(Icons.Rounded.ArrowForward, stringResource(id = R.string.go))
+ }
+ }
+ Divider(color = MaterialTheme.colorScheme.onBackground, thickness = 0.5.dp)
+ TextButton(onClick = { launchEmail() }, modifier = Modifier.padding(vertical = 5.dp)) {
+ Row(horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
+ Row {
+ Icon(Icons.Rounded.Mail, stringResource(id = R.string.email))
+ Text(stringResource(id = R.string.email_description), textAlign = TextAlign.Justify, modifier = Modifier.padding(start = 10.dp))
+ }
+ Icon(Icons.Rounded.ArrowForward, stringResource(id = R.string.go))
+ }
+ }
}
}
Spacer(modifier = Modifier.weight(1f))
@@ -75,6 +143,6 @@ fun SupportScreen(padding : PaddingValues, focusRequester: FocusRequester) {
modifier = Modifier.clickable {
openWebPage(context.resources.getString(R.string.privacy_policy_url))
})
- Text("App version: ${com.zaneschepke.wireguardautotunnel.BuildConfig.VERSION_NAME}", Modifier.padding(25.dp))
+ Text("App version: ${BuildConfig.VERSION_NAME}", Modifier.padding(25.dp))
}
}
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 50ca691..5c19c08 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -6,8 +6,9 @@
Watcher Channel
Watcher Notification Channel
FOREGROUND_FILE
- https://github.com/zaneschepke/wgtunnel
- https://zaneschepke.github.io/wgtunnel/
+ https://github.com/zaneschepke/wgtunnel/issues
+ https://zaneschepke.com/wgtunnel-docs/overview.html
+ https://zaneschepke.com/wgtunnel-docs/privacypolicy.html
File is not a .conf or .zip
Turn off tunnel before editing
No tunnels added yet!
@@ -20,10 +21,10 @@
VPN permission is required for the app to work properly. If this permission is not launching, please disable \"Always-on VPN\" in your phone settings for the official WireGuard mobile app and try again.
Notifications permission is required for the app to work properly.
Open Settings
- Add Trusted SSID
- Trusted SSIDs
+ Add trusted wifi name
Tunnels
- Enable auto-tunneling
+ Start auto-tunneling
+ Stop auto-tunneling
Tunnel on mobile data
\"Allow all the time\" location permission is required for retrieving Wi-Fi SSID in the background. Permission is needed for this feature.
Location permission is required for this feature to work properly.
@@ -34,7 +35,7 @@
Tunnel on ethernet
This feature requires background location permission to enable Wi-Fi SSID monitoring even while the application is closed. For more details, please see the Privacy Policy linked on the Support screen.
Background Location Disclosure
- Thank you for using WG Tunnel! If you are experiencing issues with the app, please reach out on Discord or create an issue on GitHub. I will try to address the issue as quickly as possible. Thank you!
+ Thank you for using WG Tunnel!
Enter SSID
Submit SSID
[Interface]
@@ -92,7 +93,7 @@
wg-tunnel-db
Scanning for QR
QR scan failed
- None
+ No trusted wifi names
Never
Failed to open file stream.
An unknown error occurred.
@@ -138,4 +139,18 @@
Exported configs to downloads
No file explorer installed
status
+ Tunnel on untrusted wifi
+ zanecschepke@gmail.com
+ WG Tunnel Support
+ Send an email…
+ go
+ Read the docs (WIP)
+ Join the community
+ Discord
+ Docs
+ GitHub
+ Email
+ Send me an email
+ If you are experiencing issues, have improvement ideas, or just want to engage, the following resources are available:
+
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/Constants.kt b/buildSrc/src/main/kotlin/Constants.kt
index 03a81e3..c2f75e9 100644
--- a/buildSrc/src/main/kotlin/Constants.kt
+++ b/buildSrc/src/main/kotlin/Constants.kt
@@ -1,7 +1,7 @@
object Constants {
- const val VERSION_NAME = "3.2.2"
+ const val VERSION_NAME = "3.2.3"
const val JVM_TARGET = "17"
- const val VERSION_CODE = 32200
+ const val VERSION_CODE = 32300
const val TARGET_SDK = 34
const val MIN_SDK = 26
const val APP_ID = "com.zaneschepke.wireguardautotunnel"
diff --git a/fastlane/metadata/android/en-US/changelogs/32300.txt b/fastlane/metadata/android/en-US/changelogs/32300.txt
new file mode 100644
index 0000000..d3687e1
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/32300.txt
@@ -0,0 +1,5 @@
+Enhancements:
+- Add support for mobile data only auto-tunneling
+- Improve support screen UI
+- Update resource links
+- Various other bug fixes
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 630199c..acb883d 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -10,18 +10,18 @@ desugar_jdk_libs = "2.0.4"
espressoCore = "3.5.1"
firebase-crashlytics-gradle = "2.9.9"
google-services = "4.4.0"
-hiltAndroid = "2.48.1"
+hiltAndroid = "2.49"
hiltNavigationCompose = "1.1.0"
junit = "4.13.2"
-kotlinx-serialization-json = "1.6.0"
+kotlinx-serialization-json = "1.6.2"
lifecycle-runtime-compose = "2.6.2"
material-icons-extended = "1.5.4"
material3 = "1.1.2"
navigationCompose = "2.7.5"
-roomVersion = "2.6.0"
+roomVersion = "2.6.1"
timber = "5.0.1"
tunnel = "1.0.20230706"
-androidGradlePlugin = "8.2.0-rc03"
+androidGradlePlugin = "8.2.0"
kotlin="1.9.10"
ksp="1.9.10-1.0.13"
composeBom="2023.10.01"