refactor: navigation

This commit is contained in:
Zane Schepke 2025-01-01 00:08:33 -05:00
parent ab858ab59e
commit 85319ba874
7 changed files with 60 additions and 94 deletions

View File

@ -74,7 +74,9 @@ class WireGuardAutoTunnel : Application() {
tunnelService.setBackendState(BackendState.SERVICE_ACTIVE, emptyList())
}
appStateRepository.getLocale()?.let {
LocaleUtil.changeLocale(it)
withContext(mainDispatcher) {
LocaleUtil.changeLocale(it)
}
}
}
}

View File

@ -222,24 +222,16 @@ class MainActivity : AppCompatActivity() {
}
composable<Route.Config> {
val args = it.toRoute<Route.Config>()
ConfigScreen(
appUiState,
tunnelId = args.id,
appViewModel = viewModel,
)
val config = appUiState.tunnels.firstOrNull { it.id == args.id }
ConfigScreen(config, viewModel)
}
composable<Route.TunnelOptions> {
val args = it.toRoute<Route.TunnelOptions>()
OptionsScreen(
tunnelId = args.id,
appUiState = appUiState,
appViewModel = viewModel,
)
val config = appUiState.tunnels.first { it.id == args.id }
OptionsScreen(config, viewModel)
}
composable<Route.Lock> {
PinLockScreen(
appViewModel = viewModel,
)
PinLockScreen(viewModel)
}
composable<Route.Scanner> {
ScannerScreen()
@ -249,11 +241,13 @@ class MainActivity : AppCompatActivity() {
}
composable<Route.SplitTunnel> {
val args = it.toRoute<Route.SplitTunnel>()
SplitTunnelScreen(appUiState, args.id, viewModel)
val config = appUiState.tunnels.first { it.id == args.id }
SplitTunnelScreen(config,viewModel)
}
composable<Route.TunnelAutoTunnel> {
val args = it.toRoute<Route.SplitTunnel>()
TunnelAutoTunnelScreen(appUiState, args.id)
val args = it.toRoute<Route.TunnelOptions>()
val config = appUiState.tunnels.first { it.id == args.id }
TunnelAutoTunnelScreen(config, appUiState.settings)
}
}
}

View File

@ -26,7 +26,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.ui.AppUiState
import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
import com.zaneschepke.wireguardautotunnel.ui.AppViewModel
import com.zaneschepke.wireguardautotunnel.ui.Route
import com.zaneschepke.wireguardautotunnel.ui.common.button.ScaledSwitch
@ -39,18 +39,17 @@ import com.zaneschepke.wireguardautotunnel.util.extensions.scaledHeight
import com.zaneschepke.wireguardautotunnel.util.extensions.scaledWidth
@Composable
fun OptionsScreen(appViewModel: AppViewModel, appUiState: AppUiState, tunnelId: Int) {
fun OptionsScreen(tunnelConfig: TunnelConfig, appViewModel: AppViewModel) {
val navController = LocalNavController.current
val config = appUiState.tunnels.first { it.id == tunnelId }
var currentText by remember { mutableStateOf("") }
LaunchedEffect(config.tunnelNetworks) {
LaunchedEffect(tunnelConfig.tunnelNetworks) {
currentText = ""
}
Scaffold(
topBar = {
TopNavBar(config.name)
TopNavBar(tunnelConfig.name)
},
) {
Column(
@ -83,11 +82,11 @@ fun OptionsScreen(appViewModel: AppViewModel, appUiState: AppUiState, tunnelId:
},
trailing = {
ScaledSwitch(
config.isPrimaryTunnel,
onClick = { appViewModel.onTogglePrimaryTunnel(config) },
tunnelConfig.isPrimaryTunnel,
onClick = { appViewModel.onTogglePrimaryTunnel(tunnelConfig) },
)
},
onClick = { appViewModel.onTogglePrimaryTunnel(config) },
onClick = { appViewModel.onTogglePrimaryTunnel(tunnelConfig) },
),
SelectionItem(
Icons.Outlined.Bolt,
@ -104,10 +103,10 @@ fun OptionsScreen(appViewModel: AppViewModel, appUiState: AppUiState, tunnelId:
)
},
onClick = {
navController.navigate(Route.TunnelAutoTunnel(id = tunnelId))
navController.navigate(Route.TunnelAutoTunnel(id = tunnelConfig.id))
},
trailing = {
ForwardButton { navController.navigate(Route.TunnelAutoTunnel(id = tunnelId)) }
ForwardButton { navController.navigate(Route.TunnelAutoTunnel(id = tunnelConfig.id)) }
},
),
SelectionItem(
@ -119,10 +118,10 @@ fun OptionsScreen(appViewModel: AppViewModel, appUiState: AppUiState, tunnelId:
)
},
onClick = {
navController.navigate(Route.Config(id = tunnelId))
navController.navigate(Route.Config(id = tunnelConfig.id))
},
trailing = {
ForwardButton { navController.navigate(Route.Config(id = tunnelId)) }
ForwardButton { navController.navigate(Route.Config(id = tunnelConfig.id)) }
},
),
SelectionItem(
@ -134,10 +133,10 @@ fun OptionsScreen(appViewModel: AppViewModel, appUiState: AppUiState, tunnelId:
)
},
onClick = {
navController.navigate(Route.SplitTunnel(id = tunnelId))
navController.navigate(Route.SplitTunnel(id = tunnelConfig.id))
},
trailing = {
ForwardButton { navController.navigate(Route.SplitTunnel(id = tunnelId)) }
ForwardButton { navController.navigate(Route.SplitTunnel(id = tunnelConfig.id)) }
},
),
),

View File

@ -58,6 +58,7 @@ import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
import com.zaneschepke.wireguardautotunnel.ui.AppUiState
import com.zaneschepke.wireguardautotunnel.ui.AppViewModel
import com.zaneschepke.wireguardautotunnel.ui.common.config.ConfigurationTextBox
@ -77,7 +78,7 @@ import com.zaneschepke.wireguardautotunnel.util.extensions.scaledWidth
import org.amnezia.awg.crypto.KeyPair
@Composable
fun ConfigScreen(appUiState: AppUiState, appViewModel: AppViewModel, tunnelId: Int) {
fun ConfigScreen(tunnelConfig: TunnelConfig?, appViewModel: AppViewModel) {
val context = LocalContext.current
val snackbar = SnackbarController.current
val clipboardManager: ClipboardManager = LocalClipboardManager.current
@ -90,8 +91,6 @@ fun ConfigScreen(appUiState: AppUiState, appViewModel: AppViewModel, tunnelId: I
val popBackStack by appViewModel.popBackStack.collectAsStateWithLifecycle(false)
val tunnelConfig = appUiState.tunnels.firstOrNull { it.id == tunnelId }
val configPair = Pair(tunnelConfig?.name ?: "", tunnelConfig?.toAmConfig())
var tunnelName by remember {
@ -261,32 +260,6 @@ fun ConfigScreen(appUiState: AppUiState, appViewModel: AppViewModel, tunnelId: I
}
}
}
// ConfigurationToggle(
// stringResource(id = R.string.show_amnezia_properties),
// checked = showAmneziaValues,
// onCheckChanged = {
// if (appUiState.settings.isKernelEnabled) {
// snackbar.showMessage(context.getString(R.string.amnezia_kernel_message))
// } else {
// showAmneziaValues = it
// }
// },
// )
// ConfigurationToggle(
// stringResource(id = R.string.show_scripts),
// checked = showScripts,
// onCheckChanged = { checked ->
// if (appUiState.settings.isKernelEnabled) {
// showScripts = checked
// } else {
// scope.launch {
// appViewModel.requestRoot().onSuccess {
// showScripts = checked
// }
// }
// }
// },
// )
ConfigurationTextBox(
value = tunnelName,
onValueChange = { tunnelName = it },
@ -297,7 +270,7 @@ fun ConfigScreen(appUiState: AppUiState, appViewModel: AppViewModel, tunnelId: I
Modifier
.fillMaxWidth(),
)
val privateKeyEnabled = (tunnelId == Constants.MANUAL_TUNNEL_CONFIG_ID) || isAuthenticated
val privateKeyEnabled = (tunnelConfig == null) || isAuthenticated
OutlinedTextField(
textStyle = MaterialTheme.typography.labelLarge,
modifier =

View File

@ -48,7 +48,7 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.google.accompanist.drawablepainter.rememberDrawablePainter
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.ui.AppUiState
import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
import com.zaneschepke.wireguardautotunnel.ui.AppViewModel
import com.zaneschepke.wireguardautotunnel.ui.common.button.SelectionItemButton
import com.zaneschepke.wireguardautotunnel.ui.common.navigation.LocalNavController
@ -62,7 +62,7 @@ import java.text.Collator
import java.util.Locale
@Composable
fun SplitTunnelScreen(appUiState: AppUiState, tunnelId: Int, viewModel: AppViewModel) {
fun SplitTunnelScreen(tunnelConfig: TunnelConfig, viewModel: AppViewModel) {
val context = LocalContext.current
val navController = LocalNavController.current
@ -76,8 +76,6 @@ fun SplitTunnelScreen(appUiState: AppUiState, tunnelId: Int, viewModel: AppViewM
if (popBackStack) navController.popBackStack()
}
val config = appUiState.tunnels.first { it.id == tunnelId }
val splitTunnelApps by viewModel.splitTunnelApps.collectAsStateWithLifecycle()
var proxyInterface by remember { mutableStateOf(InterfaceProxy()) }
@ -87,7 +85,7 @@ fun SplitTunnelScreen(appUiState: AppUiState, tunnelId: Int, viewModel: AppViewM
val selectedPackages = remember { mutableStateListOf<String>() }
LaunchedEffect(Unit) {
proxyInterface = InterfaceProxy.from(config.toAmConfig().`interface`)
proxyInterface = InterfaceProxy.from(tunnelConfig.toAmConfig().`interface`)
val pair = when {
proxyInterface.excludedApplications.isNotEmpty() -> Pair(SplitOptions.EXCLUDE, proxyInterface.excludedApplications)
proxyInterface.includedApplications.isNotEmpty() -> Pair(SplitOptions.INCLUDE, proxyInterface.includedApplications)
@ -107,7 +105,7 @@ fun SplitTunnelScreen(appUiState: AppUiState, tunnelId: Int, viewModel: AppViewM
LaunchedEffect(Unit) {
// clean up any split tunnel packages for apps that were uninstalled
viewModel.cleanUpUninstalledApps(config, splitTunnelApps.map { it.`package` })
viewModel.cleanUpUninstalledApps(tunnelConfig, splitTunnelApps.map { it.`package` })
}
Scaffold(
@ -127,7 +125,7 @@ fun SplitTunnelScreen(appUiState: AppUiState, tunnelId: Int, viewModel: AppViewM
}
SplitOptions.ALL -> Unit
}
viewModel.updateExistingTunnelConfig(config, `interface` = proxyInterface)
viewModel.updateExistingTunnelConfig(tunnelConfig, `interface` = proxyInterface)
}) {
val icon = Icons.Outlined.Save
Icon(

View File

@ -33,7 +33,8 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.ui.AppUiState
import com.zaneschepke.wireguardautotunnel.data.domain.Settings
import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
import com.zaneschepke.wireguardautotunnel.ui.common.button.ScaledSwitch
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SurfaceSelectionGroupButton
@ -48,17 +49,16 @@ import com.zaneschepke.wireguardautotunnel.util.extensions.scaledHeight
import com.zaneschepke.wireguardautotunnel.util.extensions.scaledWidth
@Composable
fun TunnelAutoTunnelScreen(appUiState: AppUiState, tunnelId: Int, tunnelAutoTunnelViewModel: TunnelAutoTunnelViewModel = hiltViewModel()) {
val config = appUiState.tunnels.first { it.id == tunnelId }
fun TunnelAutoTunnelScreen(tunnelConfig: TunnelConfig, settings: Settings, tunnelAutoTunnelViewModel: TunnelAutoTunnelViewModel = hiltViewModel()) {
var currentText by remember { mutableStateOf("") }
LaunchedEffect(config.tunnelNetworks) {
LaunchedEffect(tunnelConfig.tunnelNetworks) {
currentText = ""
}
Scaffold(
topBar = {
TopNavBar(config.name)
TopNavBar(tunnelConfig.name)
},
) { padding ->
Column(
@ -92,11 +92,11 @@ fun TunnelAutoTunnelScreen(appUiState: AppUiState, tunnelId: Int, tunnelAutoTunn
},
trailing = {
ScaledSwitch(
config.isMobileDataTunnel,
onClick = { tunnelAutoTunnelViewModel.onToggleIsMobileDataTunnel(config) },
tunnelConfig.isMobileDataTunnel,
onClick = { tunnelAutoTunnelViewModel.onToggleIsMobileDataTunnel(tunnelConfig) },
)
},
onClick = { tunnelAutoTunnelViewModel.onToggleIsMobileDataTunnel(config) },
onClick = { tunnelAutoTunnelViewModel.onToggleIsMobileDataTunnel(tunnelConfig) },
),
SelectionItem(
Icons.Outlined.SettingsEthernet,
@ -114,11 +114,11 @@ fun TunnelAutoTunnelScreen(appUiState: AppUiState, tunnelId: Int, tunnelAutoTunn
},
trailing = {
ScaledSwitch(
config.isEthernetTunnel,
onClick = { tunnelAutoTunnelViewModel.onToggleIsEthernetTunnel(config) },
tunnelConfig.isEthernetTunnel,
onClick = { tunnelAutoTunnelViewModel.onToggleIsEthernetTunnel(tunnelConfig) },
)
},
onClick = { tunnelAutoTunnelViewModel.onToggleIsEthernetTunnel(config) },
onClick = { tunnelAutoTunnelViewModel.onToggleIsEthernetTunnel(tunnelConfig) },
),
SelectionItem(
Icons.Outlined.NetworkPing,
@ -130,27 +130,27 @@ fun TunnelAutoTunnelScreen(appUiState: AppUiState, tunnelId: Int, tunnelAutoTunn
},
trailing = {
ScaledSwitch(
checked = config.isPingEnabled,
onClick = { tunnelAutoTunnelViewModel.onToggleRestartOnPing(config) },
checked = tunnelConfig.isPingEnabled,
onClick = { tunnelAutoTunnelViewModel.onToggleRestartOnPing(tunnelConfig) },
)
},
onClick = { tunnelAutoTunnelViewModel.onToggleRestartOnPing(config) },
onClick = { tunnelAutoTunnelViewModel.onToggleRestartOnPing(tunnelConfig) },
),
),
)
if (config.isPingEnabled || appUiState.settings.isPingEnabled) {
if (tunnelConfig.isPingEnabled || settings.isPingEnabled) {
add(
SelectionItem(
title = {},
description = {
SubmitConfigurationTextBox(
config.pingIp,
tunnelConfig.pingIp,
stringResource(R.string.set_custom_ping_ip),
stringResource(R.string.default_ping_ip),
isErrorValue = { !it.isNullOrBlank() && !it.isValidIpv4orIpv6Address() },
onSubmit = {
tunnelAutoTunnelViewModel.saveTunnelChanges(
config.copy(pingIp = it.ifBlank { null }),
tunnelConfig.copy(pingIp = it.ifBlank { null }),
)
},
)
@ -158,7 +158,7 @@ fun TunnelAutoTunnelScreen(appUiState: AppUiState, tunnelId: Int, tunnelAutoTunn
return seconds?.let { value -> if (value.isBlank()) false else value.toLong() >= Long.MAX_VALUE / 1000 } ?: false
}
SubmitConfigurationTextBox(
config.pingInterval?.let { (it / 1000).toString() },
tunnelConfig.pingInterval?.let { (it / 1000).toString() },
stringResource(R.string.set_custom_ping_internal),
"(${stringResource(R.string.optional_default)} ${Constants.PING_INTERVAL / 1000})",
keyboardOptions = KeyboardOptions(
@ -168,12 +168,12 @@ fun TunnelAutoTunnelScreen(appUiState: AppUiState, tunnelId: Int, tunnelAutoTunn
isErrorValue = ::isSecondsError,
onSubmit = {
tunnelAutoTunnelViewModel.saveTunnelChanges(
config.copy(pingInterval = if (it.isBlank()) null else it.toLong() * 1000),
tunnelConfig.copy(pingInterval = if (it.isBlank()) null else it.toLong() * 1000),
)
},
)
SubmitConfigurationTextBox(
config.pingCooldown?.let { (it / 1000).toString() },
tunnelConfig.pingCooldown?.let { (it / 1000).toString() },
stringResource(R.string.set_custom_ping_cooldown),
"(${stringResource(R.string.optional_default)} ${Constants.PING_COOLDOWN / 1000})",
keyboardOptions = KeyboardOptions(
@ -182,7 +182,7 @@ fun TunnelAutoTunnelScreen(appUiState: AppUiState, tunnelId: Int, tunnelAutoTunn
isErrorValue = ::isSecondsError,
onSubmit = {
tunnelAutoTunnelViewModel.saveTunnelChanges(
config.copy(pingCooldown = if (it.isBlank()) null else it.toLong() * 1000),
tunnelConfig.copy(pingCooldown = if (it.isBlank()) null else it.toLong() * 1000),
)
},
)
@ -229,13 +229,13 @@ fun TunnelAutoTunnelScreen(appUiState: AppUiState, tunnelId: Int, tunnelAutoTunn
},
description = {
TrustedNetworkTextBox(
config.tunnelNetworks,
onDelete = { tunnelAutoTunnelViewModel.onDeleteRunSSID(it, config) },
tunnelConfig.tunnelNetworks,
onDelete = { tunnelAutoTunnelViewModel.onDeleteRunSSID(it, tunnelConfig) },
currentText = currentText,
onSave = { tunnelAutoTunnelViewModel.onSaveRunSSID(it, config) },
onSave = { tunnelAutoTunnelViewModel.onSaveRunSSID(it, tunnelConfig) },
onValueChange = { currentText = it },
supporting = {
if (appUiState.settings.isWildcardsEnabled) {
if (settings.isWildcardsEnabled) {
WildcardsLabel()
}
},

View File

@ -9,7 +9,7 @@ coreKtx = "1.15.0"
datastorePreferences = "1.1.1"
desugar_jdk_libs = "2.1.4"
espressoCore = "3.6.1"
hiltAndroid = "2.53"
hiltAndroid = "2.54"
hiltNavigationCompose = "1.2.0"
junit = "4.13.2"
kotlinx-serialization-json = "1.7.3"