diff --git a/nym-vpn-android/app/src/main/AndroidManifest.xml b/nym-vpn-android/app/src/main/AndroidManifest.xml index ad5ff574f0..0a3ad92c16 100644 --- a/nym-vpn-android/app/src/main/AndroidManifest.xml +++ b/nym-vpn-android/app/src/main/AndroidManifest.xml @@ -2,12 +2,18 @@ + + + + { if (NymVpn.isForeground()) { SnackbarController.showMessage(StringValue.StringResource(R.string.exception_cred_invalid)) - navController.go(Route.Credential) + navController.goFromRoot(Route.Credential) } } else -> Unit } @@ -245,6 +246,9 @@ class MainActivity : ComponentActivity() { composable { EnvironmentScreen(appState, appViewModel) } + composable { + ScannerScreen(appViewModel) + } } } } diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/Route.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/Route.kt index 4418843ef8..1bf1ea83c8 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/Route.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/Route.kt @@ -56,4 +56,7 @@ sealed class Route { @Serializable data object ExitLocation : Route() + + @Serializable + data object CredentialScanner : Route() } diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/hop/HopScreen.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/hop/HopScreen.kt index e9d1620160..615a92566d 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/hop/HopScreen.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/hop/HopScreen.kt @@ -5,11 +5,14 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape @@ -54,7 +57,6 @@ import net.nymtech.nymvpn.ui.theme.CustomColors import net.nymtech.nymvpn.ui.theme.CustomTypography import net.nymtech.nymvpn.ui.theme.iconSize import net.nymtech.nymvpn.util.extensions.getFlagImageVectorByName -import net.nymtech.nymvpn.util.extensions.go import net.nymtech.nymvpn.util.extensions.openWebUrl import net.nymtech.nymvpn.util.extensions.scaledHeight import net.nymtech.nymvpn.util.extensions.scaledWidth @@ -158,7 +160,7 @@ fun HopScreen( verticalArrangement = Arrangement.Top, modifier = Modifier - .fillMaxSize(), + .fillMaxSize().windowInsetsPadding(WindowInsets.navigationBars), ) { item { Column( @@ -284,7 +286,7 @@ fun HopScreen( buttonText = it.name, onClick = { viewModel.onSelected(it, gatewayLocation) - navController.go(Route.Main()) + navController.navigate(Route.Main()) }, trailing = { if (it.isoCode == selectedCountry.isoCode) { diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/main/MainScreen.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/main/MainScreen.kt index 512c2ba78e..b379cb7bcb 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/main/MainScreen.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/main/MainScreen.kt @@ -72,7 +72,7 @@ import net.nymtech.nymvpn.ui.theme.Theme import net.nymtech.nymvpn.ui.theme.iconSize import net.nymtech.nymvpn.util.Constants import net.nymtech.nymvpn.util.extensions.buildCountryNameString -import net.nymtech.nymvpn.util.extensions.go +import net.nymtech.nymvpn.util.extensions.goFromRoot import net.nymtech.nymvpn.util.extensions.isInvalid import net.nymtech.nymvpn.util.extensions.openWebUrl import net.nymtech.nymvpn.util.extensions.scaledHeight @@ -97,7 +97,7 @@ fun MainScreen(appViewModel: AppViewModel, appUiState: AppUiState, autoStart: Bo title = { MainTitle(appUiState.settings.theme ?: Theme.default()) }, trailing = { NavIcon(Icons.Outlined.Settings) { - appViewModel.navController.go(Route.Settings) + appViewModel.navController.goFromRoot(Route.Settings) } }, ), @@ -110,7 +110,7 @@ fun MainScreen(appViewModel: AppViewModel, appUiState: AppUiState, autoStart: Bo onResult = { val accepted = (it.resultCode == RESULT_OK) if (!accepted) { - appViewModel.navController.go(Route.Permission(Permission.VPN)) + appViewModel.navController.goFromRoot(Route.Permission(Permission.VPN)) } else { viewModel.onConnect() } @@ -273,7 +273,7 @@ fun MainScreen(appViewModel: AppViewModel, appUiState: AppUiState, autoStart: Bo indication = if (selectionEnabled) ripple() else null, ) { if (selectionEnabled) { - appViewModel.navController.go( + appViewModel.navController.goFromRoot( Route.EntryLocation, ) } else { @@ -303,7 +303,7 @@ fun MainScreen(appViewModel: AppViewModel, appUiState: AppUiState, autoStart: Bo .defaultMinSize(minHeight = 1.dp, minWidth = 1.dp) .clickable(remember { MutableInteractionSource() }, indication = if (selectionEnabled) ripple() else null) { if (selectionEnabled) { - appViewModel.navController.go( + appViewModel.navController.goFromRoot( Route.ExitLocation, ) } else { @@ -321,7 +321,7 @@ fun MainScreen(appViewModel: AppViewModel, appUiState: AppUiState, autoStart: Bo scope.launch { if (appUiState.settings.credentialExpiry.isInvalid() ) { - return@launch appViewModel.navController.go(Route.Credential) + return@launch appViewModel.navController.goFromRoot(Route.Credential) } onConnectPressed() } diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/scanner/ScannerScreen.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/scanner/ScannerScreen.kt new file mode 100644 index 0000000000..fd6270a42d --- /dev/null +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/scanner/ScannerScreen.kt @@ -0,0 +1,36 @@ +package net.nymtech.nymvpn.ui.screens.scanner + +import android.app.Activity +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.viewinterop.AndroidView +import com.google.accompanist.permissions.ExperimentalPermissionsApi +import com.journeyapps.barcodescanner.CompoundBarcodeView +import net.nymtech.nymvpn.ui.AppViewModel + +@OptIn(ExperimentalPermissionsApi::class) +@Composable +fun ScannerScreen(appViewModel: AppViewModel) { + val context = LocalContext.current + + val barcodeView = remember { + CompoundBarcodeView(context).apply { + this.initializeFromIntent((context as Activity).intent) + this.setStatusText("") + this.decodeSingle { result -> + result.text?.let { barCodeOrQr -> + appViewModel.onCredentialImport(barCodeOrQr) + } + } + } + } + AndroidView(factory = { barcodeView }) + DisposableEffect(Unit) { + barcodeView.resume() + onDispose { + barcodeView.pause() + } + } +} diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/SettingsScreen.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/SettingsScreen.kt index 31ed8cbc1f..c3a2f5a6b8 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/SettingsScreen.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/SettingsScreen.kt @@ -55,7 +55,6 @@ import net.nymtech.nymvpn.ui.common.navigation.NavIcon import net.nymtech.nymvpn.ui.common.navigation.NavTitle import net.nymtech.nymvpn.ui.theme.CustomTypography import net.nymtech.nymvpn.util.extensions.durationFromNow -import net.nymtech.nymvpn.util.extensions.go import net.nymtech.nymvpn.util.extensions.isInvalid import net.nymtech.nymvpn.util.extensions.launchNotificationSettings import net.nymtech.nymvpn.util.extensions.launchVpnSettings @@ -100,7 +99,7 @@ fun SettingsScreen( ) { if (appUiState.settings.credentialExpiry.isInvalid()) { MainStyledButton( - onClick = { navController.go(Route.Credential) }, + onClick = { navController.navigate(Route.Credential) }, content = { Text( stringResource(id = R.string.add_cred_to_connect), @@ -133,7 +132,7 @@ fun SettingsScreen( SelectionItem( Icons.Filled.AccountCircle, onClick = { - navController.go(Route.Account) + navController.navigate(Route.Account) }, title = { Text(stringResource(R.string.credential), style = MaterialTheme.typography.bodyLarge.copy(MaterialTheme.colorScheme.onSurface)) }, description = { Text(accountDescription.text, style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.outline)) }, @@ -198,7 +197,7 @@ fun SettingsScreen( SelectionItem( Icons.AutoMirrored.Outlined.ViewQuilt, title = { Text(stringResource(R.string.appearance), style = MaterialTheme.typography.bodyLarge.copy(MaterialTheme.colorScheme.onSurface)) }, - onClick = { navController.go(Route.Appearance) }, + onClick = { navController.navigate(Route.Appearance) }, ), SelectionItem( Icons.Outlined.Notifications, @@ -251,17 +250,17 @@ fun SettingsScreen( SelectionItem( ImageVector.vectorResource(R.drawable.feedback), title = { Text(stringResource(R.string.feedback), style = MaterialTheme.typography.bodyLarge.copy(MaterialTheme.colorScheme.onSurface)) }, - onClick = { navController.go(Route.Feedback) }, + onClick = { navController.navigate(Route.Feedback) }, ), SelectionItem( ImageVector.vectorResource(R.drawable.support), title = { Text(stringResource(R.string.support), style = MaterialTheme.typography.bodyLarge.copy(MaterialTheme.colorScheme.onSurface)) }, - onClick = { navController.go(Route.Support) }, + onClick = { navController.navigate(Route.Support) }, ), SelectionItem( ImageVector.vectorResource(R.drawable.logs), title = { Text(stringResource(R.string.logs), style = MaterialTheme.typography.bodyLarge.copy(MaterialTheme.colorScheme.onSurface)) }, - onClick = { navController.go(Route.Logs) }, + onClick = { navController.navigate(Route.Logs) }, ), SelectionItem( Icons.Outlined.BugReport, @@ -321,7 +320,7 @@ fun SettingsScreen( listOf( SelectionItem( title = { Text(stringResource(R.string.legal), style = MaterialTheme.typography.bodyLarge.copy(MaterialTheme.colorScheme.onSurface)) }, - onClick = { navController.go(Route.Legal) }, + onClick = { navController.navigate(Route.Legal) }, ), ), ) @@ -339,7 +338,7 @@ fun SettingsScreen( color = MaterialTheme.colorScheme.secondary, modifier = Modifier.clickable { if (BuildConfig.DEBUG || BuildConfig.BUILD_TYPE == "prerelease") { - navController.go(Route.Environment) + navController.navigate(Route.Environment) } else { clipboardManager.setText( annotatedString = AnnotatedString(BuildConfig.VERSION_NAME), diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/account/AccountScreen.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/account/AccountScreen.kt index b1a0164835..6193e731e3 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/account/AccountScreen.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/account/AccountScreen.kt @@ -45,7 +45,6 @@ import net.nymtech.nymvpn.ui.screens.settings.account.model.Device import net.nymtech.nymvpn.ui.theme.CustomTypography import net.nymtech.nymvpn.util.Constants import net.nymtech.nymvpn.util.extensions.durationFromNow -import net.nymtech.nymvpn.util.extensions.go import net.nymtech.nymvpn.util.extensions.scaledHeight import net.nymtech.nymvpn.util.extensions.scaledWidth import net.nymtech.nymvpn.util.extensions.showToast @@ -137,7 +136,7 @@ fun AccountScreen(appViewModel: AppViewModel, appUiState: AppUiState) { Box(modifier = Modifier.width(100.dp.scaledWidth())) { MainStyledButton( onClick = { - appViewModel.navController.go(Route.Credential) + appViewModel.navController.navigate(Route.Credential) }, content = { Text( diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/appearance/AppearanceScreen.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/appearance/AppearanceScreen.kt index 95de399000..eca8ad554f 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/appearance/AppearanceScreen.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/appearance/AppearanceScreen.kt @@ -24,7 +24,6 @@ import net.nymtech.nymvpn.ui.common.buttons.surface.SurfaceSelectionGroupButton import net.nymtech.nymvpn.ui.common.navigation.NavBarState import net.nymtech.nymvpn.ui.common.navigation.NavIcon import net.nymtech.nymvpn.ui.common.navigation.NavTitle -import net.nymtech.nymvpn.util.extensions.go import net.nymtech.nymvpn.util.extensions.scaledHeight import net.nymtech.nymvpn.util.extensions.scaledWidth @@ -57,7 +56,7 @@ fun AppearanceScreen(appViewModel: AppViewModel) { SelectionItem( Icons.Outlined.Translate, title = { Text(stringResource(R.string.language), style = MaterialTheme.typography.bodyLarge.copy(MaterialTheme.colorScheme.onSurface)) }, - onClick = { appViewModel.navController.go(Route.Language) }, + onClick = { appViewModel.navController.navigate(Route.Language) }, ), ), ) @@ -66,7 +65,7 @@ fun AppearanceScreen(appViewModel: AppViewModel) { SelectionItem( Icons.Outlined.Contrast, title = { Text(stringResource(R.string.display_theme), style = MaterialTheme.typography.bodyLarge.copy(MaterialTheme.colorScheme.onSurface)) }, - onClick = { appViewModel.navController.go(Route.Display) }, + onClick = { appViewModel.navController.navigate(Route.Display) }, ), ), ) diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/appearance/language/LanguageScreen.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/appearance/language/LanguageScreen.kt index a958e5fff0..d2e60d916a 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/appearance/language/LanguageScreen.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/appearance/language/LanguageScreen.kt @@ -27,7 +27,6 @@ import net.nymtech.nymvpn.ui.common.navigation.NavBarState import net.nymtech.nymvpn.ui.common.navigation.NavIcon import net.nymtech.nymvpn.ui.common.navigation.NavTitle import net.nymtech.nymvpn.util.extensions.capitalize -import net.nymtech.nymvpn.util.extensions.go import net.nymtech.nymvpn.util.extensions.scaledHeight import net.nymtech.nymvpn.util.extensions.scaledWidth import timber.log.Timber @@ -73,7 +72,7 @@ fun LanguageScreen(appViewModel: AppViewModel, localeStorage: LocaleStorage) { Timber.d("Setting preferred locale: $locale") localeStorage.setPreferredLocale(locale) LocaleUtil.applyLocalizedContext(context, locale) - appViewModel.navController.go(Route.Main(changeLanguage = true)) + appViewModel.navController.navigate(Route.Main(changeLanguage = true)) } LazyColumn( diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/credential/CredentialScreen.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/credential/CredentialScreen.kt index 33cf8e4f4c..0786ed4960 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/credential/CredentialScreen.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/credential/CredentialScreen.kt @@ -1,6 +1,7 @@ package net.nymtech.nymvpn.ui.screens.settings.credential import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -39,13 +40,14 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.journeyapps.barcodescanner.ScanContract -import com.journeyapps.barcodescanner.ScanOptions +import com.google.accompanist.permissions.ExperimentalPermissionsApi import net.nymtech.nymvpn.R import net.nymtech.nymvpn.ui.AppViewModel +import net.nymtech.nymvpn.ui.Route import net.nymtech.nymvpn.ui.common.buttons.MainStyledButton import net.nymtech.nymvpn.ui.common.functions.rememberImeState import net.nymtech.nymvpn.ui.common.navigation.NavBarState +import net.nymtech.nymvpn.ui.common.snackbar.SnackbarController import net.nymtech.nymvpn.ui.common.textbox.CustomTextField import net.nymtech.nymvpn.ui.theme.CustomTypography import net.nymtech.nymvpn.ui.theme.iconSize @@ -53,16 +55,24 @@ import net.nymtech.nymvpn.util.Constants import net.nymtech.nymvpn.util.extensions.scaledHeight import net.nymtech.nymvpn.util.extensions.scaledWidth +@OptIn(ExperimentalPermissionsApi::class) @Composable fun CredentialScreen(appViewModel: AppViewModel, viewModel: CredentialViewModel = hiltViewModel()) { - val context = LocalContext.current - + val snackbar = SnackbarController.current val imeState = rememberImeState() val scrollState = rememberScrollState() val padding = WindowInsets.systemBars.asPaddingValues() + val context = LocalContext.current val error = viewModel.error.collectAsStateWithLifecycle() + val requestPermissionLauncher = rememberLauncherForActivityResult( + ActivityResultContracts.RequestPermission(), + ) { isGranted -> + if (!isGranted) return@rememberLauncherForActivityResult snackbar.showMessage(context.getString(R.string.permission_required)) + appViewModel.navController.navigate(Route.CredentialScanner) + } + LaunchedEffect(Unit) { appViewModel.onNavBarStateChange( NavBarState( @@ -75,35 +85,12 @@ fun CredentialScreen(appViewModel: AppViewModel, viewModel: CredentialViewModel mutableStateOf("") } - val scanLauncher = - rememberLauncherForActivityResult( - contract = ScanContract(), - onResult = { - if (it.contents != null) { - credential = "" - credential = it.contents - viewModel.onImportCredential(credential) - } - }, - ) - LaunchedEffect(imeState.value) { if (imeState.value) { scrollState.animateScrollTo(scrollState.viewportSize) } } - fun launchQrScanner() { - val scanOptions = ScanOptions() - scanOptions.setDesiredBarcodeFormats(ScanOptions.QR_CODE) - scanOptions.setOrientationLocked(true) - scanOptions.setPrompt( - context.getString(R.string.scan_nym_vpn_credential), - ) - scanOptions.setBeepEnabled(false) - scanLauncher.launch(scanOptions) - } - Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(40.dp.scaledHeight(), Alignment.Bottom), @@ -208,7 +195,7 @@ fun CredentialScreen(appViewModel: AppViewModel, viewModel: CredentialViewModel Box(modifier = Modifier.width(56.dp.scaledWidth())) { MainStyledButton( onClick = { - launchQrScanner() + requestPermissionLauncher.launch(android.Manifest.permission.CAMERA) }, content = { val icon = Icons.Outlined.QrCodeScanner diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/legal/LegalScreen.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/legal/LegalScreen.kt index 8fd1c0cd4b..46cde5ee0e 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/legal/LegalScreen.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/legal/LegalScreen.kt @@ -25,7 +25,6 @@ import net.nymtech.nymvpn.ui.common.buttons.surface.SurfaceSelectionGroupButton import net.nymtech.nymvpn.ui.common.navigation.NavBarState import net.nymtech.nymvpn.ui.common.navigation.NavIcon import net.nymtech.nymvpn.ui.common.navigation.NavTitle -import net.nymtech.nymvpn.util.extensions.go import net.nymtech.nymvpn.util.extensions.openWebUrl import net.nymtech.nymvpn.util.extensions.scaledHeight import net.nymtech.nymvpn.util.extensions.scaledWidth @@ -76,7 +75,7 @@ fun LegalScreen(appViewModel: AppViewModel) { SelectionItem( title = { Text(stringResource(R.string.licenses), style = MaterialTheme.typography.bodyLarge.copy(MaterialTheme.colorScheme.onSurface)) }, onClick = { - appViewModel.navController.go(Route.Licenses) + appViewModel.navController.navigate(Route.Licenses) }, ), ), diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/legal/licenses/LicensesScreen.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/legal/licenses/LicensesScreen.kt index 663dc11ca5..f8e9ddd5d3 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/legal/licenses/LicensesScreen.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/screens/settings/legal/licenses/LicensesScreen.kt @@ -2,8 +2,11 @@ package net.nymtech.nymvpn.ui.screens.settings.legal.licenses import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material.icons.Icons @@ -75,7 +78,7 @@ fun LicensesScreen(appViewModel: AppViewModel, viewModel: LicensesViewModel = hi modifier = Modifier .fillMaxSize() - .padding(horizontal = 24.dp.scaledWidth()), + .padding(horizontal = 24.dp.scaledWidth()).windowInsetsPadding(WindowInsets.navigationBars), ) { item { Row(modifier = Modifier.padding(bottom = 24.dp.scaledHeight())) {} diff --git a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/util/extensions/UiExtensions.kt b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/util/extensions/UiExtensions.kt index c66faa5981..ad8fdea393 100644 --- a/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/util/extensions/UiExtensions.kt +++ b/nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/util/extensions/UiExtensions.kt @@ -1,5 +1,6 @@ package net.nymtech.nymvpn.util.extensions +import android.annotation.SuppressLint import android.content.Context import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.TextUnit @@ -7,6 +8,7 @@ import androidx.navigation.NavBackStackEntry import androidx.navigation.NavController import androidx.navigation.NavDestination.Companion.hasRoute import androidx.navigation.NavDestination.Companion.hierarchy +import androidx.navigation.NavGraph.Companion.findStartDestination import net.nymtech.nymvpn.NymVpn import net.nymtech.nymvpn.R import net.nymtech.nymvpn.ui.Route @@ -31,21 +33,22 @@ fun NavController.navigateAndForget(route: Route) { } } +@SuppressLint("RestrictedApi") fun NavBackStackEntry?.isCurrentRoute(cls: KClass): Boolean { return this?.destination?.hierarchy?.any { it.hasRoute(route = cls) } == true } -fun NavController.go(route: Route) { +fun NavController.goFromRoot(route: Route) { if (currentBackStackEntry?.isCurrentRoute(route::class) == true) return this.navigate(route) { // Pop up to the start destination of the graph to // avoid building up a large stack of destinations // on the back stack as users select items -// popUpTo(graph.findStartDestination().id) { -// saveState = true -// } + popUpTo(graph.findStartDestination().id) { + saveState = true + } // Avoid multiple copies of the same destination when // reselecting the same item launchSingleTop = true diff --git a/nym-vpn-android/gradle/libs.versions.toml b/nym-vpn-android/gradle/libs.versions.toml index 08cae0cbf1..7dccf82b56 100644 --- a/nym-vpn-android/gradle/libs.versions.toml +++ b/nym-vpn-android/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] accompanist = "0.36.0" -agp = "8.7.0-rc01" +agp = "8.7.0" coreSplashscreen = "1.0.1" detektRulesCompose = "1.4.0" jna = "5.15.0" @@ -10,12 +10,12 @@ coreKtx = "1.13.1" junit = "4.13.2" junitVersion = "1.2.1" espressoCore = "3.6.1" -materialIconsExtended = "1.7.2" -navigationCompose = "2.8.1" +materialIconsExtended = "1.7.3" +navigationCompose = "2.8.2" hiltNavigationCompose = "1.2.0" lifecycle-compose = "2.8.6" activityCompose = "1.9.2" -composeBom = "2024.09.02" +composeBom = "2024.09.03" datastorePreferences = "1.1.1" relinker = "1.4.5" securityCrypto = "1.1.0-alpha06"