From 5bd497c8bb91aab9f737fb94249244668ec2132f Mon Sep 17 00:00:00 2001 From: Zane Schepke Date: Mon, 8 Sep 2025 21:28:10 -0400 Subject: [PATCH] refactor: disbale unsupported features on mode changes, copy app version closes #930 --- .../core/tunnel/BaseTunnel.kt | 4 +- .../ui/common/button/surface/SelectionItem.kt | 7 +- .../surface/SurfaceSelectionGroupButton.kt | 118 ++++++++++++------ .../ui/screens/settings/SettingsScreen.kt | 52 ++++++-- .../settings/components/appearanceItem.kt | 8 +- .../settings/components/dnsSettingsItem.kt | 23 +++- .../settings/components/proxySettingsItem.kt | 8 +- .../settings/components/readLogsItem.kt | 8 +- .../settings/components/systemFeaturesItem.kt | 8 +- .../components/tunnelMonitoringItem.kt | 27 +++- .../ui/screens/support/SupportScreen.kt | 2 +- .../support/components/UpdateSection.kt | 16 ++- .../util/extensions/UiExtensions.kt | 17 ++- app/src/main/res/values/strings.xml | 5 +- 14 files changed, 211 insertions(+), 92 deletions(-) diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/core/tunnel/BaseTunnel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/core/tunnel/BaseTunnel.kt index b5075a26..a3f1cc93 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/core/tunnel/BaseTunnel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/core/tunnel/BaseTunnel.kt @@ -12,6 +12,8 @@ import com.zaneschepke.wireguardautotunnel.domain.state.LogHealthState import com.zaneschepke.wireguardautotunnel.domain.state.PingState import com.zaneschepke.wireguardautotunnel.domain.state.TunnelState import com.zaneschepke.wireguardautotunnel.domain.state.TunnelStatistics +import java.util.concurrent.ConcurrentHashMap +import kotlin.coroutines.cancellation.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.flow.* @@ -20,8 +22,6 @@ import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import org.amnezia.awg.crypto.Key import timber.log.Timber -import java.util.concurrent.ConcurrentHashMap -import kotlin.coroutines.cancellation.CancellationException abstract class BaseTunnel( @ApplicationScope protected val applicationScope: CoroutineScope, diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/button/surface/SelectionItem.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/button/surface/SelectionItem.kt index 883bfc3d..97f1d81b 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/button/surface/SelectionItem.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/button/surface/SelectionItem.kt @@ -3,6 +3,7 @@ package com.zaneschepke.wireguardautotunnel.ui.common.button.surface import androidx.compose.foundation.layout.height import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp data class SelectionItem( @@ -11,5 +12,9 @@ data class SelectionItem( val title: (@Composable () -> Unit), val description: (@Composable () -> Unit)? = null, val onClick: (() -> Unit)? = null, - val modifier: Modifier = Modifier.height(64.dp), + val isEnabled: Boolean = true, + val disabledReason: String? = null, + val modifier: Modifier = Modifier.height(48.dp), + val padding: Dp = if (description == null && disabledReason == null) 16.dp else 6.dp, + val onLongPress: (() -> Unit)? = null, ) diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/button/surface/SurfaceSelectionGroupButton.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/button/surface/SurfaceSelectionGroupButton.kt index 61b74af4..70babda3 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/button/surface/SurfaceSelectionGroupButton.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/button/surface/SurfaceSelectionGroupButton.kt @@ -1,65 +1,113 @@ package com.zaneschepke.wireguardautotunnel.ui.common.button.surface -import androidx.compose.foundation.clickable +import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.stateDescription import androidx.compose.ui.unit.dp +import com.zaneschepke.wireguardautotunnel.R @Composable fun SurfaceSelectionGroupButton(items: List, modifier: Modifier = Modifier) { - + if (items.isEmpty()) return + val context = LocalContext.current Card( modifier = modifier.fillMaxWidth(), shape = RoundedCornerShape(8.dp), colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface), ) { - items.map { item -> - Box( - contentAlignment = Alignment.Center, - modifier = - modifier - .fillMaxWidth() - .clip(RoundedCornerShape(8.dp)) - .then(item.onClick?.let { modifier.clickable { it() } } ?: modifier), - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.fillMaxWidth().padding(horizontal = 12.dp), + Column( + verticalArrangement = Arrangement.spacedBy(0.dp), + modifier = Modifier.fillMaxWidth(), + ) { + items.forEach { item -> + Box( + contentAlignment = Alignment.Center, + modifier = + Modifier.fillMaxWidth() + .clip(RoundedCornerShape(8.dp)) + .alpha(if (item.isEnabled) 1f else 0.6f) + .semantics { + if (!item.isEnabled) { + stateDescription = + item.disabledReason ?: context.getString(R.string.disabled) + } + } + .combinedClickable( + onClick = { item.onClick?.invoke() }, + onLongClick = { item.onLongPress?.invoke() }, + enabled = true, + ), ) { Row( verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.weight(4f, false).fillMaxWidth(), + modifier = Modifier.fillMaxWidth().padding(horizontal = 12.dp), ) { - item.leading?.invoke() - Column( - horizontalAlignment = Alignment.Start, - verticalArrangement = - Arrangement.spacedBy(2.dp, Alignment.CenterVertically), + Row( + verticalAlignment = Alignment.CenterVertically, modifier = - Modifier.fillMaxWidth() - .padding(start = if (item.leading != null) 16.dp else 0.dp) - .weight(1f) - .padding( - vertical = if (item.description == null) 16.dp else 6.dp - ), + Modifier.weight(4f, false) + .fillMaxWidth() + .padding(vertical = item.padding), ) { - item.title() - item.description?.let { it() } + item.leading?.let { + Box(modifier = Modifier.alpha(if (item.isEnabled) 1f else 0.6f)) { + it() + } + } + Column( + horizontalAlignment = Alignment.Start, + verticalArrangement = + Arrangement.spacedBy(2.dp, Alignment.CenterVertically), + modifier = + Modifier.fillMaxWidth() + .padding(start = if (item.leading != null) 16.dp else 0.dp) + .weight(1f), + ) { + Box(modifier = Modifier.alpha(if (item.isEnabled) 1f else 0.6f)) { + item.title() + } + item.description?.invoke() + if (!item.isEnabled && item.disabledReason != null) { + Text( + text = item.disabledReason, + style = MaterialTheme.typography.bodySmall, + color = + MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f), + ) + } + } } - } - item.trailing?.let { - Box( - contentAlignment = Alignment.CenterEnd, - modifier = Modifier.padding(start = 16.dp), - ) { - it() + item.trailing?.let { + Box( + contentAlignment = Alignment.CenterEnd, + modifier = + Modifier.padding(start = 16.dp) + .alpha(if (item.isEnabled) 1f else 0.6f) + .run { + if (!item.isEnabled) { + semantics { + stateDescription = + context.getString(R.string.disabled) + } + } else { + this + } + }, + ) { + it() + } } } } 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 245859f6..625c1418 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 @@ -17,6 +17,7 @@ import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.data.model.AppMode import com.zaneschepke.wireguardautotunnel.ui.LocalIsAndroidTV import com.zaneschepke.wireguardautotunnel.ui.LocalNavController @@ -27,6 +28,8 @@ import com.zaneschepke.wireguardautotunnel.ui.navigation.Route import com.zaneschepke.wireguardautotunnel.ui.screens.settings.components.* import com.zaneschepke.wireguardautotunnel.ui.screens.settings.proxy.compoents.AppModeBottomSheet import com.zaneschepke.wireguardautotunnel.ui.sideeffect.LocalSideEffect +import com.zaneschepke.wireguardautotunnel.util.StringValue +import com.zaneschepke.wireguardautotunnel.util.extensions.asString import com.zaneschepke.wireguardautotunnel.viewmodel.SettingsViewModel import org.orbitmvi.orbit.compose.collectSideEffect import xyz.teamgravity.pin_lock_compose.PinManager @@ -45,6 +48,11 @@ fun SettingsScreen(viewModel: SettingsViewModel = hiltViewModel()) { var showBackupSheet by rememberSaveable { mutableStateOf(false) } var showAppModeSheet by rememberSaveable { mutableStateOf(false) } + val appMode by + rememberSaveable(settingsState.settings.appMode) { + mutableStateOf(settingsState.settings.appMode) + } + if (!settingsState.stateInitialized) return sharedViewModel.collectSideEffect { sideEffect -> @@ -91,40 +99,62 @@ fun SettingsScreen(viewModel: SettingsViewModel = hiltViewModel()) { ), ) { SurfaceSelectionGroupButton( - buildList { - add(appModeItem(settingsState.settings.appMode) { showAppModeSheet = true }) - } + listOf(appModeItem(settingsState.settings.appMode) { showAppModeSheet = true }) ) SectionDivider() SurfaceSelectionGroupButton( items = buildList { - if (settingsState.settings.appMode == AppMode.LOCK_DOWN) { + if (appMode == AppMode.LOCK_DOWN) { add( lanTrafficItem(settingsState.settings.isLanOnKillSwitchEnabled) { viewModel.setLanKillSwitchEnabled(it) } ) } - add(tunnelMonitoringItem(navController)) - add(dnsSettingsItem(navController)) - // TODO changing these settings won't work in certain app states - if (showProxySettings) add(proxYSettingsItem(navController)) + add( + tunnelMonitoringItem( + appMode, + onClick = { navController.navigate(Route.TunnelMonitoring) }, + ) { + sharedViewModel.showSnackMessage( + StringValue.StringResource( + R.string.mode_disabled_template, + appMode.asString(context), + ) + ) + } + ) + add( + dnsSettingsItem(appMode, onClick = { navController.navigate(Route.Dns) }) { + sharedViewModel.showSnackMessage( + StringValue.StringResource( + R.string.mode_disabled_template, + appMode.asString(context), + ) + ) + } + ) + if (showProxySettings) + add(proxYSettingsItem() { navController.navigate(Route.ProxySettings) }) } ) SectionDivider() - SurfaceSelectionGroupButton(listOf(systemFeaturesItem(navController))) + SurfaceSelectionGroupButton( + listOf(systemFeaturesItem() { navController.navigate(Route.SystemFeatures) }) + ) SectionDivider() SurfaceSelectionGroupButton( items = buildList { - add(appearanceItem(navController)) + add(appearanceItem() { navController.navigate(Route.Appearance) }) add( localLoggingItem(settingsState.isLocalLoggingEnabled) { viewModel.setLocalLogging(it) } ) - if (settingsState.isLocalLoggingEnabled) add(readLogsItem(navController)) + if (settingsState.isLocalLoggingEnabled) + add(readLogsItem() { navController.navigate(Route.Logs) }) add( pinLockItem(settingsState.isPinLockEnabled) { enabled -> if (enabled) { diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/appearanceItem.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/appearanceItem.kt index 5593d3e5..78945139 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/appearanceItem.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/appearanceItem.kt @@ -7,14 +7,12 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource -import androidx.navigation.NavController import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.ui.common.button.ForwardButton import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem -import com.zaneschepke.wireguardautotunnel.ui.navigation.Route @Composable -fun appearanceItem(navController: NavController): SelectionItem { +fun appearanceItem(onClick: () -> Unit): SelectionItem { return SelectionItem( leading = { Icon(Icons.AutoMirrored.Outlined.ViewQuilt, contentDescription = null) }, title = { @@ -24,7 +22,7 @@ fun appearanceItem(navController: NavController): SelectionItem { MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface), ) }, - trailing = { ForwardButton { navController.navigate(Route.Appearance) } }, - onClick = { navController.navigate(Route.Appearance) }, + trailing = { ForwardButton { onClick() } }, + onClick = onClick, ) } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/dnsSettingsItem.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/dnsSettingsItem.kt index b0eed072..1513a7cb 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/dnsSettingsItem.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/dnsSettingsItem.kt @@ -6,18 +6,29 @@ import androidx.compose.material3.Icon 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.saveable.rememberSaveable +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import androidx.navigation.NavController import com.zaneschepke.wireguardautotunnel.R +import com.zaneschepke.wireguardautotunnel.data.model.AppMode import com.zaneschepke.wireguardautotunnel.ui.common.button.ForwardButton import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem -import com.zaneschepke.wireguardautotunnel.ui.navigation.Route +import com.zaneschepke.wireguardautotunnel.util.extensions.asString @Composable -fun dnsSettingsItem(navController: NavController): SelectionItem { +fun dnsSettingsItem( + appMode: AppMode, + onClick: () -> Unit, + onDisabledClick: () -> Unit, +): SelectionItem { + val context = LocalContext.current + val enabled by rememberSaveable(appMode) { mutableStateOf(appMode != AppMode.KERNEL) } + val click = if (enabled) onClick else onDisabledClick return SelectionItem( leading = { Icon(Icons.Outlined.Dns, null) }, - trailing = { ForwardButton { navController.navigate(Route.Dns) } }, + trailing = { ForwardButton { click() } }, title = { Text( text = stringResource(R.string.dns_settings), @@ -25,6 +36,8 @@ fun dnsSettingsItem(navController: NavController): SelectionItem { MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface), ) }, - onClick = { navController.navigate(Route.Dns) }, + onClick = click, + disabledReason = + context.getString(R.string.mode_disabled_template, appMode.asString(context)), ) } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/proxySettingsItem.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/proxySettingsItem.kt index 3936b19f..fb052f2f 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/proxySettingsItem.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/proxySettingsItem.kt @@ -7,17 +7,15 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource -import androidx.navigation.NavController import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.ui.common.button.ForwardButton import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem -import com.zaneschepke.wireguardautotunnel.ui.navigation.Route @Composable -fun proxYSettingsItem(navController: NavController): SelectionItem { +fun proxYSettingsItem(onClick: () -> Unit): SelectionItem { return SelectionItem( leading = { Icon(ImageVector.vectorResource(R.drawable.proxy), null) }, - trailing = { ForwardButton { navController.navigate(Route.ProxySettings) } }, + trailing = { ForwardButton { onClick() } }, title = { Text( text = stringResource(R.string.proxy_settings), @@ -25,6 +23,6 @@ fun proxYSettingsItem(navController: NavController): SelectionItem { MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface), ) }, - onClick = { navController.navigate(Route.ProxySettings) }, + onClick = onClick, ) } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/readLogsItem.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/readLogsItem.kt index 7e63afd0..bf116a3f 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/readLogsItem.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/readLogsItem.kt @@ -5,22 +5,20 @@ import androidx.compose.material.icons.filled.ViewTimeline import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource -import androidx.navigation.NavController import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.ui.common.button.ForwardButton import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItemLabel import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionLabelType -import com.zaneschepke.wireguardautotunnel.ui.navigation.Route @Composable -fun readLogsItem(navController: NavController): SelectionItem { +fun readLogsItem(onClick: () -> Unit): SelectionItem { return SelectionItem( leading = { Icon(Icons.Filled.ViewTimeline, contentDescription = null) }, title = { SelectionItemLabel(stringResource(R.string.read_logs), SelectionLabelType.TITLE) }, - trailing = { ForwardButton { navController.navigate(Route.Logs) } }, - onClick = { navController.navigate(Route.Logs) }, + trailing = { ForwardButton { onClick() } }, + onClick = onClick, ) } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/systemFeaturesItem.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/systemFeaturesItem.kt index db4115d9..ab60108e 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/systemFeaturesItem.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/systemFeaturesItem.kt @@ -7,17 +7,15 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource -import androidx.navigation.NavController import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.ui.common.button.ForwardButton import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem -import com.zaneschepke.wireguardautotunnel.ui.navigation.Route @Composable -fun systemFeaturesItem(navController: NavController): SelectionItem { +fun systemFeaturesItem(onClick: () -> Unit): SelectionItem { return SelectionItem( leading = { Icon(Icons.Outlined.Android, null) }, - trailing = { ForwardButton { navController.navigate(Route.SystemFeatures) } }, + trailing = { ForwardButton { onClick.invoke() } }, title = { Text( text = stringResource(R.string.system_features), @@ -25,6 +23,6 @@ fun systemFeaturesItem(navController: NavController): SelectionItem { MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface), ) }, - onClick = { navController.navigate(Route.SystemFeatures) }, + onClick = onClick, ) } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/tunnelMonitoringItem.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/tunnelMonitoringItem.kt index 00271efe..919d04b5 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/tunnelMonitoringItem.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/components/tunnelMonitoringItem.kt @@ -6,18 +6,32 @@ import androidx.compose.material3.Icon 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.saveable.rememberSaveable +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import androidx.navigation.NavController import com.zaneschepke.wireguardautotunnel.R +import com.zaneschepke.wireguardautotunnel.data.model.AppMode import com.zaneschepke.wireguardautotunnel.ui.common.button.ForwardButton import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem -import com.zaneschepke.wireguardautotunnel.ui.navigation.Route +import com.zaneschepke.wireguardautotunnel.util.extensions.asString @Composable -fun tunnelMonitoringItem(navController: NavController): SelectionItem { +fun tunnelMonitoringItem( + appMode: AppMode, + onClick: () -> Unit, + onDisabledClick: () -> Unit, +): SelectionItem { + val context = LocalContext.current + val enabled by + rememberSaveable(appMode) { + mutableStateOf(appMode == AppMode.VPN || appMode == AppMode.KERNEL) + } + val click = if (enabled) onClick else onDisabledClick return SelectionItem( leading = { Icon(Icons.Outlined.MonitorHeart, null) }, - trailing = { ForwardButton { navController.navigate(Route.TunnelMonitoring) } }, + trailing = { ForwardButton { click() } }, title = { Text( text = stringResource(R.string.tunnel_monitoring), @@ -25,6 +39,9 @@ fun tunnelMonitoringItem(navController: NavController): SelectionItem { MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface), ) }, - onClick = { navController.navigate(Route.TunnelMonitoring) }, + isEnabled = enabled, + onClick = click, + disabledReason = + context.getString(R.string.mode_disabled_template, appMode.asString(context)), ) } 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 5b474ce0..4d2bad25 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 @@ -134,7 +134,7 @@ fun SupportScreen(viewModel: SupportViewModel) { stringResource(R.string.thank_you), modifier = Modifier.padding(horizontal = 12.dp).padding(bottom = 12.dp), ) - UpdateSection(onUpdateCheck = { viewModel.checkForUpdate() }) + UpdateSection() { viewModel.checkForUpdate() } SectionDivider() GeneralSupportOptions(navController) SectionDivider() diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/support/components/UpdateSection.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/support/components/UpdateSection.kt index 6b79e904..debecc6e 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/support/components/UpdateSection.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/support/components/UpdateSection.kt @@ -5,6 +5,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.CloudDownload import androidx.compose.material3.Icon import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.res.stringResource import com.zaneschepke.wireguardautotunnel.BuildConfig import com.zaneschepke.wireguardautotunnel.R @@ -12,9 +13,15 @@ import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionIte import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItemLabel import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionLabelType import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SurfaceSelectionGroupButton +import com.zaneschepke.wireguardautotunnel.ui.common.functions.rememberClipboardHelper @Composable -fun UpdateSection(onUpdateCheck: () -> Unit = {}) { +fun UpdateSection(onUpdateCheck: () -> Unit) { + val clipboardManager = rememberClipboardHelper() + val version = remember { + "v${BuildConfig.VERSION_NAME + + if(BuildConfig.DEBUG) "-debug" else "" }" + } SurfaceSelectionGroupButton( listOf( SelectionItem( @@ -28,11 +35,7 @@ fun UpdateSection(onUpdateCheck: () -> Unit = {}) { description = { Column { SelectionItemLabel( - stringResource( - R.string.version_template, - "v${BuildConfig.VERSION_NAME + - if(BuildConfig.DEBUG) "-debug" else "" }", - ), + stringResource(R.string.version_template, version), SelectionLabelType.DESCRIPTION, ) SelectionItemLabel( @@ -42,6 +45,7 @@ fun UpdateSection(onUpdateCheck: () -> Unit = {}) { } }, onClick = onUpdateCheck, + onLongPress = { clipboardManager.copy(version) }, ) ) ) diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/extensions/UiExtensions.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/extensions/UiExtensions.kt index 77b641a0..ff002064 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/extensions/UiExtensions.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/extensions/UiExtensions.kt @@ -70,13 +70,20 @@ fun WifiDetectionMethod.asDescriptionString(context: Context): String? { } fun AppMode.asTitleString(context: Context): String { + return when (this) { + AppMode.VPN -> asString(context) + AppMode.PROXY -> context.getString(R.string.expiremental_template, asString(context)) + AppMode.KERNEL -> context.getString(R.string.root_required_template, asString(context)) + AppMode.LOCK_DOWN -> context.getString(R.string.expiremental_template, asString(context)) + } +} + +fun AppMode.asString(context: Context): String { return when (this) { AppMode.VPN -> context.getString(R.string.vpn) - AppMode.PROXY -> - context.getString(R.string.expiremental_template, context.getString(R.string.proxy)) - AppMode.KERNEL -> - context.getString(R.string.root_required_template, context.getString(R.string.kernel)) - AppMode.LOCK_DOWN -> context.getString(R.string.expiremental_template, "Lockdown") + AppMode.PROXY -> context.getString(R.string.proxy) + AppMode.KERNEL -> context.getString(R.string.kernel) + AppMode.LOCK_DOWN -> context.getString(R.string.lockdown) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3585e1e2..5db787fe 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -291,7 +291,7 @@ Move Down Tunnel name must be 15 characters or fewer in kernel mode tunnel - 1$s, %2$s, %3$s + %1$s, %2$s, %3$s Warning Location Permissions In order to read Wi-Fi names in the background with your current detection @@ -386,4 +386,7 @@ Auto-updates IP on DDNS changes Prefer IPv6 peer resolution IPv4 peer auto-fallback + Disabled + Feature unavailable in %1$s mode. + Lockdown