diff --git a/README.md b/README.md
index 1345ae7..0fb627e 100644
--- a/README.md
+++ b/README.md
@@ -69,15 +69,16 @@ and on while on different networks. This app was created to offer a free solutio
Want updates faster?
-Check out my personal [fdroid repository](https://github.com/zaneschepke/fdroid) to get updates the moment they are released.
+Check out my personal [fdroid repository](https://github.com/zaneschepke/fdroid) to get updates the
+moment they are released.
## Docs
-Information about features, behaviors, and answers to common questions can be found in the app [documentation](https://zaneschepke.com/wgtunnel-docs/overview.html).
+Information about features, behaviors, and answers to common questions can be found in the
+app [documentation](https://zaneschepke.com/wgtunnel-docs/overview.html).
The repository for these docs can be found [here](https://github.com/zaneschepke/wgtunnel-docs).
-
## Translation
This app is using [Weblate](https://weblate.org) to assist with translations.
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index b4a4b1b..bfcfb0c 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -112,9 +112,6 @@ android {
}
create("general") {
dimension = Constants.TYPE
- if (BuildHelper.isReleaseBuild(gradle) && BuildHelper.isGeneralFlavor(gradle)) {
- //any plugins general specific
- }
}
}
compileOptions {
@@ -211,4 +208,7 @@ dependencies {
// shortcuts
implementation(libs.androidx.core)
implementation(libs.androidx.core.google.shortcuts)
+
+ // splash
+ implementation(libs.androidx.core.splashscreen)
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f9ad73d..cf86fcb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -60,31 +60,36 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
- android:theme="@style/Theme.WireguardAutoTunnel"
+ android:theme="@style/Theme.AppSplashScreen"
tools:targetApi="tiramisu">
+ android:theme="@style/Theme.AppSplashScreen">
-
+ android:name=".ui.MainActivity"
+ android:exported="true"
+ android:screenOrientation="portrait"
+ android:theme="@style/Theme.WireguardAutoTunnel">
+
+
+
+
+
try {
GeneralState(
- locationDisclosureShown = pref[DataStoreManager.LOCATION_DISCLOSURE_SHOWN]
+ isLocationDisclosureShown = pref[DataStoreManager.LOCATION_DISCLOSURE_SHOWN]
?: GeneralState.LOCATION_DISCLOSURE_SHOWN_DEFAULT,
- batteryOptimizationDisableShown = pref[DataStoreManager.BATTERY_OPTIMIZE_DISABLE_SHOWN]
+ isBatteryOptimizationDisableShown = pref[DataStoreManager.BATTERY_OPTIMIZE_DISABLE_SHOWN]
?: GeneralState.BATTERY_OPTIMIZATION_DISABLE_SHOWN_DEFAULT,
- tunnelRunningFromManualStart = pref[DataStoreManager.TUNNEL_RUNNING_FROM_MANUAL_START]
+ isTunnelRunningFromManualStart = pref[DataStoreManager.TUNNEL_RUNNING_FROM_MANUAL_START]
+ ?: GeneralState.TUNNELING_RUNNING_FROM_MANUAL_START_DEFAULT,
+ isPinLockEnabled = pref[DataStoreManager.IS_PIN_LOCK_ENABLED]
?: GeneralState.TUNNELING_RUNNING_FROM_MANUAL_START_DEFAULT,
)
} catch (e: IllegalArgumentException) {
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/BootReceiver.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/BootReceiver.kt
index 589aa8e..63381d8 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/BootReceiver.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/BootReceiver.kt
@@ -4,9 +4,11 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.zaneschepke.wireguardautotunnel.data.repository.AppDataRepository
+import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
-import com.zaneschepke.wireguardautotunnel.util.goAsync
import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
@@ -19,27 +21,36 @@ class BootReceiver : BroadcastReceiver() {
@Inject
lateinit var serviceManager: ServiceManager
- override fun onReceive(context: Context?, intent: Intent?) = goAsync {
- if (Intent.ACTION_BOOT_COMPLETED != intent?.action) return@goAsync
+ @Inject
+ @ApplicationScope
+ lateinit var applicationScope: CoroutineScope
+
+ override fun onReceive(context: Context?, intent: Intent?) {
+ if (Intent.ACTION_BOOT_COMPLETED != intent?.action) return
context?.run {
- val settings = appDataRepository.settings.getSettings()
- if (settings.isAutoTunnelEnabled) {
- Timber.i("Starting watcher service from boot")
- serviceManager.startWatcherServiceForeground(context)
- }
- if (appDataRepository.appState.isTunnelRunningFromManualStart()) {
- appDataRepository.appState.getActiveTunnelId()?.let {
- Timber.i("Starting tunnel that was active before reboot")
- serviceManager.startVpnServiceForeground(
- context,
- appDataRepository.tunnels.getById(it)?.id,
- )
+ applicationScope.launch {
+ val settings = appDataRepository.settings.getSettings()
+ if(settings.isRestoreOnBootEnabled) {
+ if (settings.isAutoTunnelEnabled) {
+ Timber.i("Starting watcher service from boot")
+ serviceManager.startWatcherServiceForeground(context)
+ }
+ if (appDataRepository.appState.isTunnelRunningFromManualStart()) {
+ appDataRepository.appState.getActiveTunnelId()?.let {
+ Timber.i("Starting tunnel that was active before reboot")
+ serviceManager.startVpnServiceForeground(
+ context,
+ appDataRepository.tunnels.getById(it)?.id,
+ )
+ return@launch
+ }
+ }
+ if (settings.isAlwaysOnVpnEnabled) {
+ Timber.i("Starting vpn service from boot AOVPN")
+ serviceManager.startVpnServiceForeground(context)
+ }
}
}
- if (settings.isAlwaysOnVpnEnabled) {
- Timber.i("Starting vpn service from boot AOVPN")
- serviceManager.startVpnServiceForeground(context)
- }
}
}
}
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/NotificationActionReceiver.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/NotificationActionReceiver.kt
index 812da89..cad50de 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/NotificationActionReceiver.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/NotificationActionReceiver.kt
@@ -4,12 +4,14 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.zaneschepke.wireguardautotunnel.data.repository.SettingsRepository
+import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
import com.zaneschepke.wireguardautotunnel.util.Constants
-import com.zaneschepke.wireguardautotunnel.util.goAsync
import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
@@ -21,16 +23,22 @@ class NotificationActionReceiver : BroadcastReceiver() {
@Inject
lateinit var serviceManager: ServiceManager
- override fun onReceive(context: Context, intent: Intent?) = goAsync {
- try {
- //TODO fix for manual start changes when enabled
- serviceManager.stopVpnServiceForeground(context)
- delay(Constants.TOGGLE_TUNNEL_DELAY)
- serviceManager.startVpnServiceForeground(context)
- } catch (e: Exception) {
- Timber.e(e)
- } finally {
- cancel()
+ @Inject
+ @ApplicationScope
+ lateinit var applicationScope: CoroutineScope
+
+ override fun onReceive(context: Context, intent: Intent?) {
+ applicationScope.launch {
+ try {
+ //TODO fix for manual start changes when enabled
+ serviceManager.stopVpnServiceForeground(context)
+ delay(Constants.TOGGLE_TUNNEL_DELAY)
+ serviceManager.startVpnServiceForeground(context)
+ } catch (e: Exception) {
+ Timber.e(e)
+ } finally {
+ cancel()
+ }
}
}
}
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tile/TunnelControlTile.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tile/TunnelControlTile.kt
index 7cc3c6f..b9d8abc 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tile/TunnelControlTile.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tile/TunnelControlTile.kt
@@ -11,7 +11,6 @@ import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelState
import com.zaneschepke.wireguardautotunnel.service.tunnel.VpnService
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import timber.log.Timber
@@ -35,32 +34,27 @@ class TunnelControlTile : TileService() {
private var manualStartConfig: TunnelConfig? = null
- private var job: Job? = null;
-
override fun onStartListening() {
super.onStartListening()
Timber.d("On start listening called")
- //TODO Fix this
- if (job == null || job?.isCancelled == true) job = applicationScope.launch {
- vpnService.vpnState.collect { it ->
- when (it.status) {
- TunnelState.UP -> {
- setActive()
- it.tunnelConfig?.name?.let { name -> setTileDescription(name) }
- }
-
- TunnelState.DOWN -> {
- setInactive()
- val config = appDataRepository.getStartTunnelConfig()?.also { config ->
- manualStartConfig = config
- } ?: appDataRepository.getPrimaryOrFirstTunnel()
- config?.let {
- setTileDescription(it.name)
- } ?: setUnavailable()
- }
-
- else -> setInactive()
+ applicationScope.launch {
+ when (vpnService.getState()) {
+ TunnelState.UP -> {
+ setActive()
+ setTileDescription(vpnService.name)
}
+
+ TunnelState.DOWN -> {
+ setInactive()
+ val config = appDataRepository.getStartTunnelConfig()?.also { config ->
+ manualStartConfig = config
+ } ?: appDataRepository.getPrimaryOrFirstTunnel()
+ config?.let {
+ setTileDescription(it.name)
+ } ?: setUnavailable()
+ }
+
+ else -> setInactive()
}
}
}
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/WireGuardTunnel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/WireGuardTunnel.kt
index c8edafe..72309ff 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/WireGuardTunnel.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/WireGuardTunnel.kt
@@ -45,24 +45,19 @@ constructor(
private var statsJob: Job? = null
- private lateinit var backend: Backend;
-
private var backendIsWgUserspace = true
private var backendIsAmneziaUserspace = false
init {
applicationScope.launch(ioDispatcher) {
- backend = userspaceBackend.get()
appDataRepository.settings.getSettingsFlow().collect {
if (it.isKernelEnabled && (backendIsWgUserspace || backendIsAmneziaUserspace)) {
Timber.i("Setting kernel backend")
- backend = kernelBackend.get()
backendIsWgUserspace = false
backendIsAmneziaUserspace = false
} else if (!it.isKernelEnabled && !it.isAmneziaEnabled && !backendIsWgUserspace) {
Timber.i("Setting WireGuard userspace backend")
- backend = userspaceBackend.get()
backendIsWgUserspace = true
backendIsAmneziaUserspace = false
} else if (it.isAmneziaEnabled && !backendIsAmneziaUserspace) {
@@ -89,7 +84,7 @@ constructor(
} else {
Timber.i("Using Wg backend")
val wgConfig = tunnelConfig?.let { TunnelConfig.configFromWgQuick(it.wgQuick) }
- val state = backend.setState(
+ val state = backend().setState(
this,
tunnelState.toWgState(),
wgConfig,
@@ -102,6 +97,7 @@ constructor(
return withContext(ioDispatcher) {
try {
//TODO we need better error handling here
+ // need to bubble up these errors to the UI
val config = tunnelConfig ?: appDataRepository.getPrimaryOrFirstTunnel()
if (config != null) {
emitTunnelConfig(config)
@@ -114,6 +110,22 @@ constructor(
}
}
+ private fun backend(): Backend {
+ return when {
+ backendIsWgUserspace -> {
+ userspaceBackend.get()
+ }
+
+ !backendIsWgUserspace && !backendIsAmneziaUserspace -> {
+ kernelBackend.get()
+ }
+
+ else -> {
+ userspaceBackend.get()
+ }
+ }
+ }
+
private fun emitTunnelState(state: TunnelState) {
_vpnState.tryEmit(
_vpnState.value.copy(
@@ -162,7 +174,7 @@ constructor(
return if (backendIsAmneziaUserspace) TunnelState.from(
userspaceAmneziaBackend.get().getState(this),
)
- else TunnelState.from(backend.getState(this))
+ else TunnelState.from(backend().getState(this))
}
override fun getName(): String {
@@ -198,7 +210,7 @@ constructor(
),
)
} else {
- emitBackendStatistics(WireGuardStatistics(backend.getStatistics(this@WireGuardTunnel)))
+ emitBackendStatistics(WireGuardStatistics(backend().getStatistics(this@WireGuardTunnel)))
}
delay(Constants.VPN_STATISTIC_CHECK_INTERVAL)
}
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/CaptureActivityPortrait.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/CaptureActivityPortrait.kt
deleted file mode 100644
index 029ade5..0000000
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/CaptureActivityPortrait.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.zaneschepke.wireguardautotunnel.ui
-
-import com.journeyapps.barcodescanner.CaptureActivity
-
-class CaptureActivityPortrait : CaptureActivity()
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/MainActivity.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/MainActivity.kt
index 584c864..e8e3fdf 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/MainActivity.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/MainActivity.kt
@@ -43,7 +43,7 @@ import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel
-import com.zaneschepke.wireguardautotunnel.data.datastore.DataStoreManager
+import com.zaneschepke.wireguardautotunnel.data.repository.AppStateRepository
import com.zaneschepke.wireguardautotunnel.data.repository.SettingsRepository
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
import com.zaneschepke.wireguardautotunnel.ui.common.navigation.BottomNavBar
@@ -61,14 +61,13 @@ import com.zaneschepke.wireguardautotunnel.util.StringValue
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import xyz.teamgravity.pin_lock_compose.PinManager
import javax.inject.Inject
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
- lateinit var dataStoreManager: DataStoreManager
+ lateinit var appStateRepository: AppStateRepository
@Inject
lateinit var settingsRepository: SettingsRepository
@@ -82,17 +81,18 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ val isPinLockEnabled = intent.extras?.getBoolean(SplashActivity.IS_PIN_LOCK_ENABLED_KEY)
+
enableEdgeToEdge(navigationBarStyle = SystemBarStyle.dark(Color.Transparent.toArgb()))
- // load preferences into memory and init data
lifecycleScope.launch {
- dataStoreManager.init()
WireGuardAutoTunnel.requestTunnelTileServiceStateUpdate()
val settings = settingsRepository.getSettings()
if (settings.isAutoTunnelEnabled) {
serviceManager.startWatcherService(application.applicationContext)
}
}
+
setContent {
val appViewModel = hiltViewModel()
val appUiState by appViewModel.appUiState.collectAsStateWithLifecycle()
@@ -201,12 +201,8 @@ class MainActivity : AppCompatActivity() {
) { padding ->
NavHost(
navController,
- startDestination =
- //TODO disable pin lock
- //(if (PinManager.pinExists()) Screen.Lock.route else Screen.Main.route),
- Screen.Main.route,
- modifier =
- Modifier
+ startDestination = (if (isPinLockEnabled == true) Screen.Lock.route else Screen.Main.route),
+ modifier = Modifier
.padding(padding)
.fillMaxSize(),
) {
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/SplashActivity.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/SplashActivity.kt
new file mode 100644
index 0000000..58ef902
--- /dev/null
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/SplashActivity.kt
@@ -0,0 +1,68 @@
+package com.zaneschepke.wireguardautotunnel.ui
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import com.zaneschepke.logcatter.LocalLogCollector
+import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel
+import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel.Companion.isRunningOnAndroidTv
+import com.zaneschepke.wireguardautotunnel.data.repository.AppStateRepository
+import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import xyz.teamgravity.pin_lock_compose.PinManager
+import javax.inject.Inject
+
+@SuppressLint("CustomSplashScreen")
+@AndroidEntryPoint
+class SplashActivity : ComponentActivity() {
+
+ @Inject
+ lateinit var appStateRepository: AppStateRepository
+
+ @Inject
+ lateinit var localLogCollector: LocalLogCollector
+
+ @Inject
+ @ApplicationScope
+ lateinit var applicationScope: CoroutineScope
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ val splashScreen = installSplashScreen()
+ splashScreen.setKeepOnScreenCondition { true }
+ }
+ super.onCreate(savedInstanceState)
+
+ applicationScope.launch {
+ if (!isRunningOnAndroidTv()) localLogCollector.start()
+ }
+
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ val pinLockEnabled = appStateRepository.isPinLockEnabled()
+ if (pinLockEnabled) {
+ PinManager.initialize(WireGuardAutoTunnel.instance)
+ }
+
+ val intent = Intent(this@SplashActivity, MainActivity::class.java).apply {
+ putExtra(IS_PIN_LOCK_ENABLED_KEY, pinLockEnabled)
+ }
+ startActivity(intent)
+ finish()
+ }
+ }
+ }
+
+ companion object {
+ const val IS_PIN_LOCK_ENABLED_KEY = "is_pin_lock_enabled"
+ }
+}
+
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 a70c0de..e142d93 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
@@ -101,7 +101,6 @@ import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
import com.zaneschepke.wireguardautotunnel.service.tunnel.HandshakeStatus
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelState
import com.zaneschepke.wireguardautotunnel.ui.AppViewModel
-import com.zaneschepke.wireguardautotunnel.ui.CaptureActivityPortrait
import com.zaneschepke.wireguardautotunnel.ui.Screen
import com.zaneschepke.wireguardautotunnel.ui.common.RowListItem
import com.zaneschepke.wireguardautotunnel.ui.common.screen.LoadingScreen
@@ -262,8 +261,6 @@ fun MainScreen(
context.getString(R.string.scanning_qr),
)
scanOptions.setBeepEnabled(false)
- scanOptions.captureActivity =
- CaptureActivityPortrait::class.java
scanLauncher.launch(scanOptions)
}
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 8db979b..fa187c6 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
@@ -84,7 +84,6 @@ import com.zaneschepke.wireguardautotunnel.ui.common.text.SectionTitle
import com.zaneschepke.wireguardautotunnel.util.getMessage
import kotlinx.coroutines.launch
import timber.log.Timber
-import xyz.teamgravity.pin_lock_compose.PinManager
import java.io.File
@OptIn(
@@ -652,21 +651,29 @@ fun SettingsScreen(
onCheckChanged = { viewModel.onToggleShortcutsEnabled() },
)
}
- // TODO disable for now
-// ConfigurationToggle(
-// stringResource(R.string.enable_app_lock),
-// enabled = true,
-// checked = pinExists.value,
-// padding = screenPadding,
-// onCheckChanged = {
-// if (pinExists.value) {
-// PinManager.clearPin()
-// pinExists.value = PinManager.pinExists()
-// } else {
-// navController.navigate(Screen.Lock.route)
-// }
-// },
-// )
+ ConfigurationToggle(
+ stringResource(R.string.restart_at_boot),
+ enabled = true,
+ checked = uiState.settings.isRestoreOnBootEnabled,
+ padding = screenPadding,
+ onCheckChanged = {
+ viewModel.onToggleRestartAtBoot()
+ },
+ )
+ ConfigurationToggle(
+ stringResource(R.string.enable_app_lock),
+ enabled = true,
+ checked = uiState.isPinLockEnabled,
+ padding = screenPadding,
+ onCheckChanged = {
+ if (uiState.isPinLockEnabled) {
+ viewModel.onPinLockDisabled()
+ } else {
+ viewModel.onPinLockEnabled()
+ navController.navigate(Screen.Lock.route)
+ }
+ },
+ )
if (!WireGuardAutoTunnel.isRunningOnAndroidTv()) {
Row(
verticalAlignment = Alignment.CenterVertically,
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsUiState.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsUiState.kt
index 39b5db3..f51b98c 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsUiState.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsUiState.kt
@@ -10,4 +10,5 @@ data class SettingsUiState(
val vpnState: VpnState = VpnState(),
val isLocationDisclosureShown: Boolean = true,
val isBatteryOptimizeDisableShown: Boolean = false,
+ val isPinLockEnabled: Boolean = false
)
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 9be2d67..828ed32 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
@@ -27,6 +27,7 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
+import xyz.teamgravity.pin_lock_compose.PinManager
import java.io.File
import javax.inject.Inject
import javax.inject.Provider
@@ -57,8 +58,9 @@ constructor(
settings,
tunnels,
tunnelState,
- generalState.locationDisclosureShown,
- generalState.batteryOptimizationDisableShown,
+ generalState.isLocationDisclosureShown,
+ generalState.isBatteryOptimizationDisableShown,
+ generalState.isPinLockEnabled,
)
}
.stateIn(
@@ -234,4 +236,22 @@ constructor(
kernelSupport
}
}
+
+ fun onPinLockDisabled() = viewModelScope.launch {
+ PinManager.clearPin()
+ appDataRepository.appState.setPinLockEnabled(false)
+ }
+
+ fun onPinLockEnabled() = viewModelScope.launch {
+ PinManager.initialize(WireGuardAutoTunnel.instance)
+ appDataRepository.appState.setPinLockEnabled(true)
+ }
+
+ fun onToggleRestartAtBoot() = viewModelScope.launch {
+ saveSettings(
+ uiState.value.settings.copy(
+ isRestoreOnBootEnabled = !uiState.value.settings.isRestoreOnBootEnabled
+ )
+ )
+ }
}
diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/Extensions.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/Extensions.kt
index 6c165c0..f53e5ac 100644
--- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/Extensions.kt
+++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/Extensions.kt
@@ -1,6 +1,5 @@
package com.zaneschepke.wireguardautotunnel.util
-import android.content.BroadcastReceiver
import android.content.Context
import android.content.pm.PackageInfo
import com.zaneschepke.wireguardautotunnel.R
@@ -10,7 +9,6 @@ import com.zaneschepke.wireguardautotunnel.service.tunnel.statistics.TunnelStati
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.channels.ClosedReceiveChannelException
import kotlinx.coroutines.channels.ReceiveChannel
@@ -19,7 +17,6 @@ import kotlinx.coroutines.channels.ticker
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
-import kotlinx.coroutines.launch
import kotlinx.coroutines.selects.whileSelect
import org.amnezia.awg.config.Config
import timber.log.Timber
@@ -27,25 +24,8 @@ import java.math.BigDecimal
import java.text.DecimalFormat
import java.time.Duration
import java.util.concurrent.ConcurrentLinkedQueue
-import kotlin.coroutines.CoroutineContext
-import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.cancellation.CancellationException
-fun BroadcastReceiver.goAsync(
- context: CoroutineContext = EmptyCoroutineContext,
- block: suspend CoroutineScope.() -> Unit
-) {
- val pendingResult = goAsync()
- @OptIn(DelicateCoroutinesApi::class) // Must run globally; there's no teardown callback.
- GlobalScope.launch(context) {
- try {
- block()
- } finally {
- pendingResult.finish()
- }
- }
-}
-
fun BigDecimal.toThreeDecimalPlaceString(): String {
val df = DecimalFormat("#.###")
return df.format(this)
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e69a230..9f136bf 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -176,4 +176,5 @@
Amnezia
WireGuard
Invalid tunnel config format
+ Restart on boot
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index b703e9d..58e567b 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -4,4 +4,12 @@
-
\ No newline at end of file
+
+
+
diff --git a/buildSrc/src/main/kotlin/Constants.kt b/buildSrc/src/main/kotlin/Constants.kt
index 8484b92..55f9662 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.4.6"
+ const val VERSION_NAME = "3.4.7"
const val JVM_TARGET = "17"
- const val VERSION_CODE = 34600
+ const val VERSION_CODE = 34700
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/34700.txt b/fastlane/metadata/android/en-US/changelogs/34700.txt
new file mode 100644
index 0000000..b74851c
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/34700.txt
@@ -0,0 +1,6 @@
+What's new:
+- Fix crashing issues
+- Improve tile performance
+- Re-enable pin lock
+- Make restart on boot a setting
+- Various performance and bug fixes
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 2128c20..68de9e1 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -22,12 +22,13 @@ pinLockCompose = "1.0.3"
roomVersion = "2.6.1"
timber = "5.0.1"
tunnel = "1.0.20230706"
-androidGradlePlugin = "8.4.1"
+androidGradlePlugin = "8.5.0"
kotlin = "1.9.24"
ksp = "1.9.24-1.0.20"
-composeBom = "2024.05.00"
-compose = "1.6.7"
+composeBom = "2024.06.00"
+compose = "1.6.8"
zxingAndroidEmbedded = "4.3.0"
+coreSplashscreen = "1.0.1"
#plugins
gradlePlugins-kotlinxSerialization = "1.9.24"
@@ -74,6 +75,7 @@ androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "coreKtx"
androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espressoCore" }
androidx-hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hiltNavigationCompose" }
androidx-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-junit" }
+androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashscreen" }
androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle-runtime-compose" }
androidx-material3 = { module = "androidx.compose.material3:material3", version.ref = "material3" }
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" }