mirror of
https://github.com/wgtunnel/android.git
synced 2026-06-02 08:33:40 +02:00
refactor: add restart to lockdown on config change
This commit is contained in:
+10
-5
@@ -2,6 +2,7 @@ package com.zaneschepke.wireguardautotunnel.ui.common.dialog
|
||||
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
@@ -11,22 +12,26 @@ import com.zaneschepke.wireguardautotunnel.R
|
||||
fun InfoDialog(
|
||||
onAttest: () -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
title: @Composable () -> Unit,
|
||||
body: @Composable () -> Unit,
|
||||
confirmText: @Composable () -> Unit,
|
||||
title: String,
|
||||
body: @Composable (() -> Unit),
|
||||
confirmText: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
MaterialTheme(colorScheme = MaterialTheme.colorScheme.copy()) {
|
||||
Surface(color = MaterialTheme.colorScheme.surface, tonalElevation = 0.dp) {
|
||||
AlertDialog(
|
||||
modifier = modifier,
|
||||
onDismissRequest = { onDismiss() },
|
||||
confirmButton = { TextButton(onClick = { onAttest() }) { confirmText() } },
|
||||
confirmButton = {
|
||||
TextButton(onClick = { onAttest() }) { Text(text = confirmText) }
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = { onDismiss() }) {
|
||||
Text(text = stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
containerColor = MaterialTheme.colorScheme.surface,
|
||||
title = { title() },
|
||||
title = { Text(text = title) },
|
||||
text = { body() },
|
||||
properties = DialogProperties(usePlatformDefaultWidth = true),
|
||||
)
|
||||
|
||||
+2
-2
@@ -34,7 +34,7 @@ fun VpnDeniedDialog(show: Boolean, onDismiss: () -> Unit) {
|
||||
InfoDialog(
|
||||
onDismiss = { onDismiss() },
|
||||
onAttest = { onDismiss() },
|
||||
title = { Text(text = stringResource(R.string.vpn_denied_dialog_title)) },
|
||||
title = stringResource(R.string.vpn_denied_dialog_title),
|
||||
body = {
|
||||
Text(
|
||||
text = alwaysOnDescription,
|
||||
@@ -44,7 +44,7 @@ fun VpnDeniedDialog(show: Boolean, onDismiss: () -> Unit) {
|
||||
),
|
||||
)
|
||||
},
|
||||
confirmText = { Text(text = stringResource(R.string.okay)) },
|
||||
confirmText = stringResource(R.string.okay),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -125,6 +125,16 @@ fun currentRouteAsNavbarState(
|
||||
},
|
||||
showBottomItems = true,
|
||||
topTitle = context.getString(R.string.lockdown_settings),
|
||||
topTrailing = {
|
||||
IconButton(
|
||||
onClick = {
|
||||
keyboardController?.hide()
|
||||
sharedViewModel.postSideEffect(LocalSideEffect.SaveChanges)
|
||||
}
|
||||
) {
|
||||
Icon(Icons.Rounded.Save, stringResource(R.string.save))
|
||||
}
|
||||
},
|
||||
)
|
||||
License ->
|
||||
NavbarState(
|
||||
|
||||
+2
-2
@@ -88,9 +88,9 @@ fun WifiSettingsScreen(viewModel: AutoTunnelViewModel = hiltViewModel()) {
|
||||
showLocationDialog = false
|
||||
},
|
||||
onDismiss = { showLocationDialog = false },
|
||||
title = { Text(stringResource(R.string.location_permissions)) },
|
||||
title = stringResource(R.string.location_permissions),
|
||||
body = { Text(stringResource(R.string.location_justification)) },
|
||||
confirmText = { Text(stringResource(R.string.open_settings)) },
|
||||
confirmText = stringResource(R.string.open_settings),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+51
-22
@@ -14,6 +14,9 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
@@ -23,18 +26,58 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.zaneschepke.wireguardautotunnel.R
|
||||
import com.zaneschepke.wireguardautotunnel.ui.LocalSharedVm
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.button.SurfaceRow
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.button.ThemedSwitch
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.dialog.InfoDialog
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.label.GroupLabel
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.text.DescriptionText
|
||||
import com.zaneschepke.wireguardautotunnel.ui.sideeffect.LocalSideEffect
|
||||
import com.zaneschepke.wireguardautotunnel.viewmodel.LockdownViewModel
|
||||
import org.orbitmvi.orbit.compose.collectSideEffect
|
||||
|
||||
@Composable
|
||||
fun LockdownSettingsScreen(viewModel: LockdownViewModel = hiltViewModel()) {
|
||||
|
||||
val sharedViewModel = LocalSharedVm.current
|
||||
|
||||
val uiState by viewModel.container.stateFlow.collectAsStateWithLifecycle()
|
||||
|
||||
var metered by remember { mutableStateOf(uiState.lockdownSettings.metered) }
|
||||
var dualStack by remember { mutableStateOf(uiState.lockdownSettings.dualStack) }
|
||||
var bypassLan by remember { mutableStateOf(uiState.lockdownSettings.bypassLan) }
|
||||
|
||||
sharedViewModel.collectSideEffect {
|
||||
if (it is LocalSideEffect.SaveChanges) viewModel.setShowSaveModal(true)
|
||||
}
|
||||
|
||||
if (uiState.isLoading) return
|
||||
|
||||
if (uiState.showSaveModal) {
|
||||
InfoDialog(
|
||||
onDismiss = { viewModel.setShowSaveModal(false) },
|
||||
onAttest = {
|
||||
viewModel.setLockdownSettings(
|
||||
uiState.lockdownSettings.copy(
|
||||
metered = metered,
|
||||
dualStack = dualStack,
|
||||
bypassLan = bypassLan,
|
||||
)
|
||||
)
|
||||
},
|
||||
title = stringResource(R.string.save_changes),
|
||||
body = {
|
||||
Text(
|
||||
stringResource(
|
||||
R.string.restart_message_template,
|
||||
stringResource(R.string.kill_switch),
|
||||
)
|
||||
)
|
||||
},
|
||||
confirmText = stringResource(R.string._continue),
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.Start,
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp, Alignment.Top),
|
||||
@@ -57,37 +100,23 @@ fun LockdownSettingsScreen(viewModel: LockdownViewModel = hiltViewModel()) {
|
||||
),
|
||||
)
|
||||
},
|
||||
trailing = {
|
||||
ThemedSwitch(
|
||||
checked = uiState.lockdownSettings.bypassLan,
|
||||
onClick = { viewModel.setBypassLan(it) },
|
||||
)
|
||||
},
|
||||
onClick = { viewModel.setBypassLan(!uiState.lockdownSettings.bypassLan) },
|
||||
trailing = { ThemedSwitch(checked = bypassLan, onClick = { bypassLan = it }) },
|
||||
onClick = { bypassLan = !bypassLan },
|
||||
)
|
||||
SurfaceRow(
|
||||
leading = { Icon(Icons.Outlined.DataUsage, contentDescription = null) },
|
||||
title = stringResource(R.string.metered_tunnel),
|
||||
trailing = {
|
||||
ThemedSwitch(
|
||||
checked = uiState.lockdownSettings.metered,
|
||||
onClick = { viewModel.setMetered(it) },
|
||||
)
|
||||
},
|
||||
onClick = { viewModel.setMetered(!uiState.lockdownSettings.metered) },
|
||||
trailing = { ThemedSwitch(checked = metered, onClick = { metered = it }) },
|
||||
onClick = { metered = !metered },
|
||||
)
|
||||
SurfaceRow(
|
||||
leading = {
|
||||
Icon(ImageVector.vectorResource(R.drawable.host), contentDescription = null)
|
||||
},
|
||||
title = "Dual-stack",
|
||||
trailing = {
|
||||
ThemedSwitch(
|
||||
checked = uiState.lockdownSettings.dualStack,
|
||||
onClick = { viewModel.setDualStack(it) },
|
||||
)
|
||||
},
|
||||
onClick = { viewModel.setDualStack(!uiState.lockdownSettings.dualStack) },
|
||||
title = stringResource(R.string.dual_stack),
|
||||
description = { DescriptionText(stringResource(R.string.dual_stack_description)) },
|
||||
trailing = { ThemedSwitch(checked = dualStack, onClick = { dualStack = it }) },
|
||||
onClick = { dualStack = !dualStack },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -16,8 +16,8 @@ fun PermissionDialog(context: Context, onDismiss: () -> Unit) {
|
||||
context.requestInstallPackagesPermission()
|
||||
onDismiss()
|
||||
},
|
||||
title = { Text(stringResource(R.string.permission_required)) },
|
||||
title = stringResource(R.string.permission_required),
|
||||
body = { Text(stringResource(R.string.install_updated_permission)) },
|
||||
confirmText = { Text(stringResource(R.string.allow)) },
|
||||
confirmText = stringResource(R.string.allow),
|
||||
)
|
||||
}
|
||||
|
||||
+4
-8
@@ -46,7 +46,7 @@ fun UpdateDialog(viewModel: SupportViewModel, context: Context, onPermissionNeed
|
||||
onPermissionNeeded()
|
||||
}
|
||||
},
|
||||
title = { Text(stringResource(R.string.update_available)) },
|
||||
title = stringResource(R.string.update_available),
|
||||
body = {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.Start,
|
||||
@@ -89,12 +89,8 @@ fun UpdateDialog(viewModel: SupportViewModel, context: Context, onPermissionNeed
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmText = {
|
||||
Text(
|
||||
if (BuildConfig.FLAVOR != Constants.STANDALONE_FLAVOR)
|
||||
stringResource(R.string.download)
|
||||
else stringResource(R.string.download_and_install)
|
||||
)
|
||||
},
|
||||
confirmText =
|
||||
if (BuildConfig.FLAVOR != Constants.STANDALONE_FLAVOR) stringResource(R.string.download)
|
||||
else stringResource(R.string.download_and_install),
|
||||
)
|
||||
}
|
||||
|
||||
+3
-2
@@ -12,6 +12,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.journeyapps.barcodescanner.ScanContract
|
||||
import com.journeyapps.barcodescanner.ScanOptions
|
||||
import com.zaneschepke.wireguardautotunnel.R
|
||||
@@ -94,9 +95,9 @@ fun TunnelsScreen() {
|
||||
viewModel.deleteSelectedTunnels()
|
||||
showDeleteModal = false
|
||||
},
|
||||
title = { Text(text = stringResource(R.string.delete_tunnel)) },
|
||||
title = stringResource(R.string.delete_tunnel),
|
||||
body = { Text(text = stringResource(R.string.delete_tunnel_message)) },
|
||||
confirmText = { Text(text = stringResource(R.string.yes)) },
|
||||
confirmText = stringResource(R.string.yes),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -5,4 +5,5 @@ import com.zaneschepke.wireguardautotunnel.domain.model.LockdownSettings
|
||||
data class LockdownSettingsUiState(
|
||||
val lockdownSettings: LockdownSettings = LockdownSettings(),
|
||||
val isLoading: Boolean = true,
|
||||
val showSaveModal: Boolean = false,
|
||||
)
|
||||
|
||||
+33
-9
@@ -1,8 +1,16 @@
|
||||
package com.zaneschepke.wireguardautotunnel.viewmodel
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.zaneschepke.wireguardautotunnel.R
|
||||
import com.zaneschepke.wireguardautotunnel.core.tunnel.TunnelManager
|
||||
import com.zaneschepke.wireguardautotunnel.domain.enums.BackendMode
|
||||
import com.zaneschepke.wireguardautotunnel.domain.model.LockdownSettings
|
||||
import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConfig
|
||||
import com.zaneschepke.wireguardautotunnel.domain.repository.GlobalEffectRepository
|
||||
import com.zaneschepke.wireguardautotunnel.domain.repository.LockdownSettingsRepository
|
||||
import com.zaneschepke.wireguardautotunnel.domain.sideeffect.GlobalSideEffect
|
||||
import com.zaneschepke.wireguardautotunnel.ui.state.LockdownSettingsUiState
|
||||
import com.zaneschepke.wireguardautotunnel.util.StringValue
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
import org.orbitmvi.orbit.ContainerHost
|
||||
@@ -11,8 +19,11 @@ import org.orbitmvi.orbit.viewmodel.container
|
||||
@HiltViewModel
|
||||
class LockdownViewModel
|
||||
@Inject
|
||||
constructor(private val lockdownSettingsRepository: LockdownSettingsRepository) :
|
||||
ContainerHost<LockdownSettingsUiState, Nothing>, ViewModel() {
|
||||
constructor(
|
||||
private val lockdownSettingsRepository: LockdownSettingsRepository,
|
||||
private val tunnelManager: TunnelManager,
|
||||
private val globalEffectRepository: GlobalEffectRepository,
|
||||
) : ContainerHost<LockdownSettingsUiState, Nothing>, ViewModel() {
|
||||
|
||||
override val container =
|
||||
container<LockdownSettingsUiState, Nothing>(
|
||||
@@ -24,15 +35,28 @@ constructor(private val lockdownSettingsRepository: LockdownSettingsRepository)
|
||||
}
|
||||
}
|
||||
|
||||
fun setBypassLan(to: Boolean) = intent {
|
||||
lockdownSettingsRepository.upsert(state.lockdownSettings.copy(bypassLan = to))
|
||||
fun setLockdownSettings(lockdownSettings: LockdownSettings) = intent {
|
||||
reduce { state.copy(showSaveModal = false) }
|
||||
lockdownSettingsRepository.upsert(lockdownSettings)
|
||||
tunnelManager.setBackendMode(BackendMode.Inactive)
|
||||
val allowedIps =
|
||||
if (lockdownSettings.bypassLan) TunnelConfig.LAN_BYPASS_ALLOWED_IPS else emptySet()
|
||||
tunnelManager.setBackendMode(
|
||||
BackendMode.KillSwitch(
|
||||
allowedIps = allowedIps,
|
||||
isMetered = lockdownSettings.metered,
|
||||
dualStack = lockdownSettings.dualStack,
|
||||
)
|
||||
)
|
||||
postSideEffect(GlobalSideEffect.PopBackStack)
|
||||
postSideEffect(
|
||||
GlobalSideEffect.Toast(StringValue.StringResource(R.string.config_changes_saved))
|
||||
)
|
||||
}
|
||||
|
||||
fun setMetered(to: Boolean) = intent {
|
||||
lockdownSettingsRepository.upsert(state.lockdownSettings.copy(metered = to))
|
||||
suspend fun postSideEffect(globalSideEffect: GlobalSideEffect) {
|
||||
globalEffectRepository.post(globalSideEffect)
|
||||
}
|
||||
|
||||
fun setDualStack(to: Boolean) = intent {
|
||||
lockdownSettingsRepository.upsert(state.lockdownSettings.copy(dualStack = to))
|
||||
}
|
||||
fun setShowSaveModal(to: Boolean) = intent { reduce { state.copy(showSaveModal = to) } }
|
||||
}
|
||||
|
||||
@@ -422,4 +422,10 @@
|
||||
<string name="unavailable_in_mode">Unavailable in current mode</string>
|
||||
<string name="global_split_tunneling">Global split tunneling</string>
|
||||
<string name="global_dns_servers">Global DNS servers</string>
|
||||
<string name="dual_stack">Dual-stack</string>
|
||||
<string name="dual_stack_description">Tunnels must support IPv4 and IPv6</string>
|
||||
<string name="save_changes">Save changes</string>
|
||||
<string name="restart_message_template">Saving changes will cause the %1$s to restart, do you wish to continue?</string>
|
||||
<string name="_continue">Continue</string>
|
||||
<string name="kill_switch">kill switch</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user