Skip to content

Commit

Permalink
android: qr bug fix (#1243)
Browse files Browse the repository at this point in the history
* fix: android qr scan crash

* fix: nav bar padding

* fix: navigate back bug
  • Loading branch information
zaneschepke authored Oct 4, 2024
1 parent 00adb72 commit 49a0a9c
Show file tree
Hide file tree
Showing 16 changed files with 126 additions and 67 deletions.
6 changes: 6 additions & 0 deletions nym-vpn-android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-feature
android:name="android.hardware.camera"
android:required="false" />

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
<!--start vpn on boot permission-->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<uses-permission android:name="android.permission.CAMERA" />
<application
android:name=".NymVpn"
android:allowBackup="false"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import net.nymtech.nymvpn.R
import net.nymtech.nymvpn.data.GatewayRepository
import net.nymtech.nymvpn.data.SettingsRepository
import net.nymtech.nymvpn.module.qualifiers.Native
import net.nymtech.nymvpn.service.gateway.GatewayService
import net.nymtech.nymvpn.service.tunnel.TunnelManager
import net.nymtech.nymvpn.ui.common.navigation.NavBarState
import net.nymtech.nymvpn.ui.common.snackbar.SnackbarController
import net.nymtech.nymvpn.util.Constants
import net.nymtech.nymvpn.util.StringValue
import net.nymtech.nymvpn.util.extensions.navigateAndForget
import net.nymtech.vpn.model.Country
import timber.log.Timber
import javax.inject.Inject
Expand All @@ -29,7 +33,7 @@ constructor(
private val settingsRepository: SettingsRepository,
private val gatewayRepository: GatewayRepository,
@Native private val gatewayService: GatewayService,
tunnelManager: TunnelManager,
private val tunnelManager: TunnelManager,
navigationHostController: NavHostController,
) : ViewModel() {

Expand Down Expand Up @@ -89,6 +93,22 @@ constructor(
settingsRepository.setAnalytics(!uiState.value.settings.analyticsEnabled)
}

fun onCredentialImport(credential: String) = viewModelScope.launch {
runCatching {
tunnelManager.importCredential(credential).onSuccess {
Timber.d("Imported credential successfully")
it?.let {
settingsRepository.saveCredentialExpiry(it)
}
SnackbarController.showMessage(StringValue.StringResource(R.string.credential_successful))
navController.navigateAndForget(Route.Main())
}.onFailure {
SnackbarController.showMessage(StringValue.StringResource(R.string.credential_failed_message))
navController.popBackStack()
}
}
}

private suspend fun setFirstHopToLowLatencyFromCache() {
runCatching {
gatewayRepository.getLowLatencyEntryCountry()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import net.nymtech.nymvpn.ui.screens.hop.GatewayLocation
import net.nymtech.nymvpn.ui.screens.hop.HopScreen
import net.nymtech.nymvpn.ui.screens.main.MainScreen
import net.nymtech.nymvpn.ui.screens.permission.PermissionScreen
import net.nymtech.nymvpn.ui.screens.scanner.ScannerScreen
import net.nymtech.nymvpn.ui.screens.settings.SettingsScreen
import net.nymtech.nymvpn.ui.screens.settings.account.AccountScreen
import net.nymtech.nymvpn.ui.screens.settings.appearance.AppearanceScreen
Expand All @@ -64,7 +65,7 @@ import net.nymtech.nymvpn.ui.theme.NymVPNTheme
import net.nymtech.nymvpn.ui.theme.Theme
import net.nymtech.nymvpn.util.Constants
import net.nymtech.nymvpn.util.StringValue
import net.nymtech.nymvpn.util.extensions.go
import net.nymtech.nymvpn.util.extensions.goFromRoot
import net.nymtech.nymvpn.util.extensions.isCurrentRoute
import net.nymtech.nymvpn.util.extensions.requestTileServiceStateUpdate
import net.nymtech.nymvpn.util.extensions.resetTile
Expand Down Expand Up @@ -136,7 +137,7 @@ class MainActivity : ComponentActivity() {
is VpnException.InvalidCredential -> {
if (NymVpn.isForeground()) {
SnackbarController.showMessage(StringValue.StringResource(R.string.exception_cred_invalid))
navController.go(Route.Credential)
navController.goFromRoot(Route.Credential)
}
} else -> Unit
}
Expand Down Expand Up @@ -245,6 +246,9 @@ class MainActivity : ComponentActivity() {
composable<Route.Environment> {
EnvironmentScreen(appState, appViewModel)
}
composable<Route.CredentialScanner> {
ScannerScreen(appViewModel)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,7 @@ sealed class Route {

@Serializable
data object ExitLocation : Route()

@Serializable
data object CredentialScanner : Route()
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -158,7 +160,7 @@ fun HopScreen(
verticalArrangement = Arrangement.Top,
modifier =
Modifier
.fillMaxSize(),
.fillMaxSize().windowInsetsPadding(WindowInsets.navigationBars),
) {
item {
Column(
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
}
},
),
Expand All @@ -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()
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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)) },
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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) },
),
),
)
Expand All @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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) },
),
),
)
Expand All @@ -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) },
),
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down
Loading

0 comments on commit 49a0a9c

Please sign in to comment.