refactor
This commit is contained in:
parent
f0ec661223
commit
408d88390b
|
@ -22,6 +22,9 @@ interface SettingsDoa {
|
||||||
@Query("SELECT * FROM settings")
|
@Query("SELECT * FROM settings")
|
||||||
suspend fun getAll(): List<Settings>
|
suspend fun getAll(): List<Settings>
|
||||||
|
|
||||||
|
@Query("SELECT * FROM settings LIMIT 1")
|
||||||
|
fun getSettingsFlow(): Flow<Settings>
|
||||||
|
|
||||||
@Query("SELECT * FROM settings")
|
@Query("SELECT * FROM settings")
|
||||||
fun getAllFlow(): Flow<MutableList<Settings>>
|
fun getAllFlow(): Flow<MutableList<Settings>>
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,12 @@ class DataStoreManager(private val context: Context) {
|
||||||
context.dataStore.edit {
|
context.dataStore.edit {
|
||||||
it[key] = value
|
it[key] = value
|
||||||
}
|
}
|
||||||
|
fun <T> getFromStoreFlow(key: Preferences.Key<T>) = context.dataStore.data.map {
|
||||||
fun <T> getFromStore(key: Preferences.Key<T>) =
|
|
||||||
context.dataStore.data.map {
|
|
||||||
it[key]
|
it[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun <T> getFromStore(key: Preferences.Key<T>) = context.dataStore.data.first { it.contains(key) }[key]
|
||||||
|
|
||||||
val locationDisclosureFlow: Flow<Boolean?> = context.dataStore.data.map {
|
val locationDisclosureFlow: Flow<Boolean?> = context.dataStore.data.map {
|
||||||
it[LOCATION_DISCLOSURE_SHOWN]
|
it[LOCATION_DISCLOSURE_SHOWN]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,19 @@
|
||||||
package com.zaneschepke.wireguardautotunnel.ui
|
package com.zaneschepke.wireguardautotunnel.ui
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.zaneschepke.wireguardautotunnel.repository.SettingsDoa
|
||||||
|
import com.zaneschepke.wireguardautotunnel.repository.model.Settings
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class ActivityViewModel @Inject constructor() : ViewModel() {
|
@HiltViewModel
|
||||||
// TODO move shared logic to shared viewmodel
|
class ActivityViewModel @Inject constructor(
|
||||||
|
private val settingsRepo: SettingsDoa,
|
||||||
|
) : ViewModel() {
|
||||||
|
// val settings = settingsRepo.getSettingsFlow().stateIn(viewModelScope,
|
||||||
|
// SharingStarted.WhileSubscribed(5000L), Settings()
|
||||||
|
// )
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.input.key.onKeyEvent
|
import androidx.compose.ui.input.key.onKeyEvent
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
|
@ -64,8 +65,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContent {
|
setContent {
|
||||||
// TODO move shared logic to shared viewmodel
|
// val activityViewModel = hiltViewModel<ActivityViewModel>()
|
||||||
// val sharedViewModel = hiltViewModel<ActivityViewModel>()
|
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focusRequester = remember { FocusRequester() }
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ import android.os.Build
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.animation.slideInVertically
|
import androidx.compose.animation.slideInVertically
|
||||||
import androidx.compose.animation.slideOutVertically
|
import androidx.compose.animation.slideOutVertically
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
@ -84,6 +86,7 @@ import com.zaneschepke.wireguardautotunnel.R
|
||||||
import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel
|
import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel
|
||||||
import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig
|
import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig
|
||||||
import com.zaneschepke.wireguardautotunnel.service.tunnel.HandshakeStatus
|
import com.zaneschepke.wireguardautotunnel.service.tunnel.HandshakeStatus
|
||||||
|
import com.zaneschepke.wireguardautotunnel.ui.ActivityViewModel
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.CaptureActivityPortrait
|
import com.zaneschepke.wireguardautotunnel.ui.CaptureActivityPortrait
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.Routes
|
import com.zaneschepke.wireguardautotunnel.ui.Routes
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.common.RowListItem
|
import com.zaneschepke.wireguardautotunnel.ui.common.RowListItem
|
||||||
|
@ -212,7 +215,7 @@ fun MainScreen(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (showPrimaryChangeAlertDialog) {
|
AnimatedVisibility(showPrimaryChangeAlertDialog) {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = {
|
onDismissRequest = {
|
||||||
showPrimaryChangeAlertDialog = false
|
showPrimaryChangeAlertDialog = false
|
||||||
|
@ -288,7 +291,7 @@ fun MainScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
if (tunnels.isEmpty()) {
|
AnimatedVisibility(tunnels.isEmpty(), exit = fadeOut(), enter = fadeIn()) {
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.Center,
|
||||||
|
|
|
@ -38,11 +38,13 @@ import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.SideEffect
|
import androidx.compose.runtime.SideEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
|
@ -71,6 +73,7 @@ import com.wireguard.android.backend.WgQuickBackend
|
||||||
import com.zaneschepke.wireguardautotunnel.R
|
import com.zaneschepke.wireguardautotunnel.R
|
||||||
import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel
|
import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel
|
||||||
import com.zaneschepke.wireguardautotunnel.repository.datastore.DataStoreManager
|
import com.zaneschepke.wireguardautotunnel.repository.datastore.DataStoreManager
|
||||||
|
import com.zaneschepke.wireguardautotunnel.ui.ActivityViewModel
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.common.ClickableIconButton
|
import com.zaneschepke.wireguardautotunnel.ui.common.ClickableIconButton
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.common.config.ConfigurationToggle
|
import com.zaneschepke.wireguardautotunnel.ui.common.config.ConfigurationToggle
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.common.prompt.AuthorizationPrompt
|
import com.zaneschepke.wireguardautotunnel.ui.common.prompt.AuthorizationPrompt
|
||||||
|
@ -95,31 +98,29 @@ fun SettingsScreen(
|
||||||
val scope = rememberCoroutineScope { Dispatchers.IO }
|
val scope = rememberCoroutineScope { Dispatchers.IO }
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val focusManager = LocalFocusManager.current
|
val focusManager = LocalFocusManager.current
|
||||||
|
val scrollState = rememberScrollState()
|
||||||
val keyboardController = LocalSoftwareKeyboardController.current
|
val keyboardController = LocalSoftwareKeyboardController.current
|
||||||
val interactionSource = remember { MutableInteractionSource() }
|
val interactionSource = remember { MutableInteractionSource() }
|
||||||
|
|
||||||
val settings by viewModel.settings.collectAsStateWithLifecycle()
|
val settings by viewModel.settings.collectAsStateWithLifecycle()
|
||||||
val trustedSSIDs by viewModel.trustedSSIDs.collectAsStateWithLifecycle()
|
val tunnels by viewModel.tunnels.collectAsStateWithLifecycle()
|
||||||
val tunnels by viewModel.tunnels.collectAsStateWithLifecycle(mutableListOf())
|
val vpnState = viewModel.vpnState.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
val fineLocationState = rememberPermissionState(Manifest.permission.ACCESS_FINE_LOCATION)
|
val fineLocationState = rememberPermissionState(Manifest.permission.ACCESS_FINE_LOCATION)
|
||||||
var currentText by remember { mutableStateOf("") }
|
var currentText by remember { mutableStateOf("") }
|
||||||
val scrollState = rememberScrollState()
|
|
||||||
var isBackgroundLocationGranted by remember { mutableStateOf(true) }
|
var isBackgroundLocationGranted by remember { mutableStateOf(true) }
|
||||||
var showAuthPrompt by remember { mutableStateOf(false) }
|
|
||||||
var didExportFiles by remember { mutableStateOf(false) }
|
var didExportFiles by remember { mutableStateOf(false) }
|
||||||
val isLocationDisclosureShown by viewModel.disclosureShown.collectAsStateWithLifecycle(
|
var showAuthPrompt by remember { mutableStateOf(false) }
|
||||||
null
|
var isLocationDisclosureShown by rememberSaveable {
|
||||||
)
|
mutableStateOf(false)
|
||||||
val vpnState = viewModel.vpnState.collectAsStateWithLifecycle(initialValue = Tunnel.State.DOWN)
|
}
|
||||||
|
|
||||||
val screenPadding = 5.dp
|
val screenPadding = 5.dp
|
||||||
val fillMaxWidth = .85f
|
val fillMaxWidth = .85f
|
||||||
|
|
||||||
fun setLocationDisclosureShown() = scope.launch {
|
|
||||||
viewModel.dataStoreManager.saveToDataStore(
|
LaunchedEffect(Unit) {
|
||||||
DataStoreManager.LOCATION_DISCLOSURE_SHOWN,
|
isLocationDisclosureShown = viewModel.isLocationDisclosureShown()
|
||||||
true
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exportAllConfigs() {
|
fun exportAllConfigs() {
|
||||||
|
@ -175,25 +176,25 @@ fun SettingsScreen(
|
||||||
isBackgroundLocationGranted = if (!backgroundLocationState.status.isGranted) {
|
isBackgroundLocationGranted = if (!backgroundLocationState.status.isGranted) {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
SideEffect {
|
if(!isLocationDisclosureShown) {
|
||||||
setLocationDisclosureShown()
|
viewModel.setLocationDisclosureShown()
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
|
||||||
if (!fineLocationState.status.isGranted) {
|
isBackgroundLocationGranted = if (!fineLocationState.status.isGranted) {
|
||||||
isBackgroundLocationGranted = false
|
false
|
||||||
} else {
|
} else {
|
||||||
SideEffect {
|
SideEffect {
|
||||||
setLocationDisclosureShown()
|
viewModel.setLocationDisclosureShown()
|
||||||
}
|
}
|
||||||
isBackgroundLocationGranted = true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLocationDisclosureShown != true) {
|
AnimatedVisibility(!isLocationDisclosureShown) {
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.Top,
|
verticalArrangement = Arrangement.Top,
|
||||||
|
@ -238,22 +239,21 @@ fun SettingsScreen(
|
||||||
horizontalArrangement = Arrangement.SpaceEvenly
|
horizontalArrangement = Arrangement.SpaceEvenly
|
||||||
) {
|
) {
|
||||||
TextButton(onClick = {
|
TextButton(onClick = {
|
||||||
setLocationDisclosureShown()
|
viewModel.setLocationDisclosureShown()
|
||||||
}) {
|
}) {
|
||||||
Text(stringResource(id = R.string.no_thanks))
|
Text(stringResource(id = R.string.no_thanks))
|
||||||
}
|
}
|
||||||
TextButton(modifier = Modifier.focusRequester(focusRequester), onClick = {
|
TextButton(modifier = Modifier.focusRequester(focusRequester), onClick = {
|
||||||
openSettings()
|
openSettings()
|
||||||
setLocationDisclosureShown()
|
viewModel.setLocationDisclosureShown()
|
||||||
}) {
|
}) {
|
||||||
Text(stringResource(id = R.string.turn_on))
|
Text(stringResource(id = R.string.turn_on))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showAuthPrompt) {
|
AnimatedVisibility(showAuthPrompt) {
|
||||||
AuthorizationPrompt(
|
AuthorizationPrompt(
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
showAuthPrompt = false
|
showAuthPrompt = false
|
||||||
|
@ -348,7 +348,7 @@ fun SettingsScreen(
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.spacedBy(5.dp)
|
horizontalArrangement = Arrangement.spacedBy(5.dp)
|
||||||
) {
|
) {
|
||||||
trustedSSIDs.forEach { ssid ->
|
settings.trustedNetworkSSIDs.forEach { ssid ->
|
||||||
ClickableIconButton(
|
ClickableIconButton(
|
||||||
onIconClick = {
|
onIconClick = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
@ -360,7 +360,7 @@ fun SettingsScreen(
|
||||||
enabled = !(settings.isAutoTunnelEnabled || settings.isAlwaysOnVpnEnabled)
|
enabled = !(settings.isAutoTunnelEnabled || settings.isAlwaysOnVpnEnabled)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (trustedSSIDs.isEmpty()) {
|
if (settings.trustedNetworkSSIDs.isEmpty()) {
|
||||||
Text(
|
Text(
|
||||||
stringResource(R.string.none),
|
stringResource(R.string.none),
|
||||||
fontStyle = FontStyle.Italic,
|
fontStyle = FontStyle.Italic,
|
||||||
|
@ -535,7 +535,8 @@ fun SettingsScreen(
|
||||||
shape = RoundedCornerShape(12.dp),
|
shape = RoundedCornerShape(12.dp),
|
||||||
color = MaterialTheme.colorScheme.surface,
|
color = MaterialTheme.colorScheme.surface,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth(fillMaxWidth).padding(vertical = 10.dp)
|
.fillMaxWidth(fillMaxWidth)
|
||||||
|
.padding(vertical = 10.dp)
|
||||||
.padding(bottom = 140.dp)
|
.padding(bottom = 140.dp)
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
|
|
|
@ -6,22 +6,19 @@ import android.location.LocationManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.wireguard.android.backend.Tunnel
|
||||||
import com.wireguard.android.util.RootShell
|
import com.wireguard.android.util.RootShell
|
||||||
import com.zaneschepke.wireguardautotunnel.repository.SettingsDoa
|
import com.zaneschepke.wireguardautotunnel.repository.SettingsDoa
|
||||||
import com.zaneschepke.wireguardautotunnel.repository.TunnelConfigDao
|
import com.zaneschepke.wireguardautotunnel.repository.TunnelConfigDao
|
||||||
import com.zaneschepke.wireguardautotunnel.repository.datastore.DataStoreManager
|
import com.zaneschepke.wireguardautotunnel.repository.datastore.DataStoreManager
|
||||||
import com.zaneschepke.wireguardautotunnel.repository.model.Settings
|
import com.zaneschepke.wireguardautotunnel.repository.model.Settings
|
||||||
import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig
|
|
||||||
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
|
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
|
||||||
import com.zaneschepke.wireguardautotunnel.service.tunnel.VpnService
|
import com.zaneschepke.wireguardautotunnel.service.tunnel.VpnService
|
||||||
import com.zaneschepke.wireguardautotunnel.util.WgTunnelException
|
import com.zaneschepke.wireguardautotunnel.util.WgTunnelException
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import kotlinx.coroutines.flow.filter
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
|
@ -32,110 +29,87 @@ constructor(
|
||||||
private val application: Application,
|
private val application: Application,
|
||||||
private val tunnelRepo: TunnelConfigDao,
|
private val tunnelRepo: TunnelConfigDao,
|
||||||
private val settingsRepo: SettingsDoa,
|
private val settingsRepo: SettingsDoa,
|
||||||
val dataStoreManager: DataStoreManager,
|
private val dataStoreManager: DataStoreManager,
|
||||||
private val rootShell: RootShell,
|
private val rootShell: RootShell,
|
||||||
private val vpnService: VpnService
|
private val vpnService: VpnService
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _trustedSSIDs = MutableStateFlow(emptyList<String>())
|
val settings = settingsRepo.getSettingsFlow().stateIn(viewModelScope,
|
||||||
val trustedSSIDs = _trustedSSIDs.asStateFlow()
|
SharingStarted.WhileSubscribed(5_000L), Settings())
|
||||||
private val _settings = MutableStateFlow(Settings())
|
val tunnels = tunnelRepo.getAllFlow().stateIn(viewModelScope,
|
||||||
val settings get() = _settings.asStateFlow()
|
SharingStarted.WhileSubscribed(5_000L), emptyList())
|
||||||
val vpnState get() = vpnService.state
|
val vpnState get() = vpnService.state.stateIn(viewModelScope,
|
||||||
val tunnels get() = tunnelRepo.getAllFlow()
|
SharingStarted.WhileSubscribed(5_000L), Tunnel.State.DOWN)
|
||||||
val disclosureShown = dataStoreManager.locationDisclosureFlow
|
|
||||||
|
|
||||||
init {
|
|
||||||
isLocationServicesEnabled()
|
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
|
||||||
settingsRepo.getAllFlow().filter { it.isNotEmpty() }.collect {
|
|
||||||
val settings = it.first()
|
|
||||||
_settings.emit(settings)
|
|
||||||
_trustedSSIDs.emit(settings.trustedNetworkSSIDs.toList())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
suspend fun onSaveTrustedSSID(ssid: String) {
|
suspend fun onSaveTrustedSSID(ssid: String) {
|
||||||
val trimmed = ssid.trim()
|
val trimmed = ssid.trim()
|
||||||
if (!_settings.value.trustedNetworkSSIDs.contains(trimmed)) {
|
if (!settings.value.trustedNetworkSSIDs.contains(trimmed)) {
|
||||||
_settings.value.trustedNetworkSSIDs.add(trimmed)
|
settings.value.trustedNetworkSSIDs.add(trimmed)
|
||||||
settingsRepo.save(_settings.value)
|
settingsRepo.save(settings.value)
|
||||||
} else {
|
} else {
|
||||||
throw WgTunnelException("SSID already exists.")
|
throw WgTunnelException("SSID already exists.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun isLocationDisclosureShown() : Boolean {
|
||||||
|
return dataStoreManager.getFromStore(DataStoreManager.LOCATION_DISCLOSURE_SHOWN) ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setLocationDisclosureShown() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
dataStoreManager.saveToDataStore(DataStoreManager.LOCATION_DISCLOSURE_SHOWN, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun onToggleTunnelOnMobileData() {
|
suspend fun onToggleTunnelOnMobileData() {
|
||||||
settingsRepo.save(
|
settingsRepo.save(
|
||||||
_settings.value.copy(
|
settings.value.copy(
|
||||||
isTunnelOnMobileDataEnabled = !_settings.value.isTunnelOnMobileDataEnabled
|
isTunnelOnMobileDataEnabled = !settings.value.isTunnelOnMobileDataEnabled
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun onDeleteTrustedSSID(ssid: String) {
|
suspend fun onDeleteTrustedSSID(ssid: String) {
|
||||||
_settings.value.trustedNetworkSSIDs.remove(ssid)
|
settings.value.trustedNetworkSSIDs.remove(ssid)
|
||||||
settingsRepo.save(_settings.value)
|
settingsRepo.save(settings.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun emitFirstTunnelAsDefault() =
|
private suspend fun getDefaultTunnelOrFirst() : String {
|
||||||
viewModelScope.async {
|
return settings.value.defaultTunnel ?: tunnelRepo.getAll().first().wgQuick
|
||||||
_settings.emit(_settings.value.copy(defaultTunnel = getFirstTunnelConfig().toString()))
|
}
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun toggleAutoTunnel() {
|
suspend fun toggleAutoTunnel() {
|
||||||
if (_settings.value.isAutoTunnelEnabled) {
|
val defaultTunnel = getDefaultTunnelOrFirst()
|
||||||
|
if (settings.value.isAutoTunnelEnabled) {
|
||||||
ServiceManager.stopWatcherService(application)
|
ServiceManager.stopWatcherService(application)
|
||||||
} else {
|
} else {
|
||||||
if (_settings.value.defaultTunnel == null) {
|
ServiceManager.startWatcherService(application, defaultTunnel)
|
||||||
emitFirstTunnelAsDefault().await()
|
|
||||||
}
|
|
||||||
val defaultTunnel = _settings.value.defaultTunnel
|
|
||||||
ServiceManager.startWatcherService(application, defaultTunnel!!)
|
|
||||||
}
|
}
|
||||||
settingsRepo.save(
|
saveSettings(
|
||||||
_settings.value.copy(
|
settings.value.copy(
|
||||||
isAutoTunnelEnabled = !_settings.value.isAutoTunnelEnabled
|
isAutoTunnelEnabled = settings.value.isAutoTunnelEnabled,
|
||||||
|
defaultTunnel = defaultTunnel
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getFirstTunnelConfig(): TunnelConfig {
|
|
||||||
return tunnelRepo.getAll().first()
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun onToggleAlwaysOnVPN() {
|
suspend fun onToggleAlwaysOnVPN() {
|
||||||
if (_settings.value.defaultTunnel == null) {
|
|
||||||
emitFirstTunnelAsDefault().await()
|
|
||||||
}
|
|
||||||
val updatedSettings =
|
val updatedSettings =
|
||||||
_settings.value.copy(
|
settings.value.copy(
|
||||||
isAlwaysOnVpnEnabled = !_settings.value.isAlwaysOnVpnEnabled
|
isAlwaysOnVpnEnabled = !settings.value.isAlwaysOnVpnEnabled,
|
||||||
|
defaultTunnel = getDefaultTunnelOrFirst()
|
||||||
)
|
)
|
||||||
emitSettings(updatedSettings)
|
|
||||||
saveSettings(updatedSettings)
|
saveSettings(updatedSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun emitSettings(settings: Settings) {
|
|
||||||
_settings.emit(
|
|
||||||
settings
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun saveSettings(settings: Settings) {
|
private suspend fun saveSettings(settings: Settings) {
|
||||||
settingsRepo.save(settings)
|
settingsRepo.save(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun onToggleTunnelOnEthernet() {
|
suspend fun onToggleTunnelOnEthernet() {
|
||||||
if (_settings.value.defaultTunnel == null) {
|
saveSettings(settings.value.copy(
|
||||||
emitFirstTunnelAsDefault().await()
|
isTunnelOnEthernetEnabled = !settings.value.isTunnelOnEthernetEnabled
|
||||||
}
|
))
|
||||||
_settings.emit(
|
|
||||||
_settings.value.copy(
|
|
||||||
isTunnelOnEthernetEnabled = !_settings.value.isTunnelOnEthernetEnabled
|
|
||||||
)
|
|
||||||
)
|
|
||||||
settingsRepo.save(_settings.value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isLocationServicesEnabled(): Boolean {
|
private fun isLocationServicesEnabled(): Boolean {
|
||||||
|
@ -149,31 +123,39 @@ constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun onToggleShortcutsEnabled() {
|
suspend fun onToggleShortcutsEnabled() {
|
||||||
settingsRepo.save(
|
saveSettings(
|
||||||
_settings.value.copy(
|
settings.value.copy(
|
||||||
isShortcutsEnabled = !_settings.value.isShortcutsEnabled
|
isShortcutsEnabled = !settings.value.isShortcutsEnabled
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun onToggleBatterySaver() {
|
suspend fun onToggleBatterySaver() {
|
||||||
settingsRepo.save(
|
saveSettings(
|
||||||
_settings.value.copy(
|
settings.value.copy(
|
||||||
isBatterySaverEnabled = !_settings.value.isBatterySaverEnabled
|
isBatterySaverEnabled = !settings.value.isBatterySaverEnabled
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun saveKernelMode(on: Boolean) {
|
private suspend fun saveKernelMode(on: Boolean) {
|
||||||
settingsRepo.save(
|
saveSettings(
|
||||||
_settings.value.copy(
|
settings.value.copy(
|
||||||
isKernelEnabled = on
|
isKernelEnabled = on
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun onToggleTunnelOnWifi() {
|
||||||
|
saveSettings(
|
||||||
|
settings.value.copy(
|
||||||
|
isTunnelOnWifiEnabled = !settings.value.isTunnelOnWifiEnabled
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun onToggleKernelMode() {
|
suspend fun onToggleKernelMode() {
|
||||||
if (!_settings.value.isKernelEnabled) {
|
if (!settings.value.isKernelEnabled) {
|
||||||
try {
|
try {
|
||||||
rootShell.start()
|
rootShell.start()
|
||||||
Timber.d("Root shell accepted!")
|
Timber.d("Root shell accepted!")
|
||||||
|
@ -186,12 +168,4 @@ constructor(
|
||||||
saveKernelMode(on = false)
|
saveKernelMode(on = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun onToggleTunnelOnWifi() {
|
|
||||||
settingsRepo.save(
|
|
||||||
_settings.value.copy(
|
|
||||||
isTunnelOnWifiEnabled = !_settings.value.isTunnelOnWifiEnabled
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue