Skip to content

Commit

Permalink
android: fix navigation bug (#1289)
Browse files Browse the repository at this point in the history
  • Loading branch information
zaneschepke authored Oct 11, 2024
1 parent f545c90 commit 0612337
Show file tree
Hide file tree
Showing 22 changed files with 242 additions and 200 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package net.nymtech.nymvpn.ui

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.navigation.NavHostController
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
Expand All @@ -11,17 +10,13 @@ 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 @@ -33,12 +28,9 @@ constructor(
private val settingsRepository: SettingsRepository,
private val gatewayRepository: GatewayRepository,
@Native private val gatewayService: GatewayService,
private val tunnelManager: TunnelManager,
navigationHostController: NavHostController,
tunnelManager: TunnelManager,
) : ViewModel() {

val navController = navigationHostController

private val _navBarState = MutableStateFlow(NavBarState())
val navBarState = _navBarState.asStateFlow()

Expand Down Expand Up @@ -93,22 +85,6 @@ 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
199 changes: 102 additions & 97 deletions nym-vpn-android/app/src/main/java/net/nymtech/nymvpn/ui/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarData
import androidx.compose.material3.SnackbarHost
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand All @@ -30,6 +31,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.toRoute
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
Expand All @@ -40,6 +42,7 @@ import net.nymtech.nymvpn.R
import net.nymtech.nymvpn.manager.shortcut.ShortcutManager
import net.nymtech.nymvpn.service.notification.NotificationService
import net.nymtech.nymvpn.ui.common.labels.CustomSnackBar
import net.nymtech.nymvpn.ui.common.navigation.LocalNavController
import net.nymtech.nymvpn.ui.common.navigation.NavBar
import net.nymtech.nymvpn.ui.common.snackbar.SnackbarController
import net.nymtech.nymvpn.ui.common.snackbar.SnackbarControllerProvider
Expand Down Expand Up @@ -103,7 +106,7 @@ class MainActivity : ComponentActivity() {
val appState by appViewModel.uiState.collectAsStateWithLifecycle(lifecycle = this.lifecycle)
val navBarState by appViewModel.navBarState.collectAsStateWithLifecycle(lifecycle = this.lifecycle)

val navController = remember { appViewModel.navController }
val navController = rememberNavController()
val navBackStackEntry by navController.currentBackStackEntryAsState()
var navHeight by remember { mutableStateOf(0.dp) }
val density = LocalDensity.current
Expand Down Expand Up @@ -139,9 +142,12 @@ class MainActivity : ComponentActivity() {
SnackbarController.showMessage(StringValue.StringResource(R.string.exception_cred_invalid))
navController.goFromRoot(Route.Credential)
}
} else -> Unit
}

else -> Unit
}
}

else -> Unit
}
}
Expand All @@ -150,104 +156,103 @@ class MainActivity : ComponentActivity() {
return appState.settings.theme ?: theme?.let { Theme.valueOf(it) } ?: Theme.default()
}

SnackbarControllerProvider { host ->
NymVPNTheme(theme = getTheme()) {
Scaffold(
contentWindowInsets = WindowInsets(0.dp),
modifier = Modifier.semantics {
// Enables testTag -> UiAutomator resource id
@OptIn(ExperimentalComposeUiApi::class)
testTagsAsResourceId = true
},
topBar = {
NavBar(
navBarState,
CompositionLocalProvider(LocalNavController provides navController) {
SnackbarControllerProvider { host ->
NymVPNTheme(theme = getTheme()) {
Scaffold(
contentWindowInsets = WindowInsets(0.dp),
modifier = Modifier.semantics {
// Enables testTag -> UiAutomator resource id
@OptIn(ExperimentalComposeUiApi::class)
testTagsAsResourceId = true
},
topBar = {
NavBar(
navBarState,
navController,
Modifier.onGloballyPositioned {
navHeight = with(density) {
it.size.height.toDp()
}
},
)
},
snackbarHost = {
SnackbarHost(host) { snackbarData: SnackbarData ->
CustomSnackBar(message = snackbarData.visuals.message, paddingTop = navHeight)
}
},
) { padding ->
NavHost(
navController,
Modifier.onGloballyPositioned {
navHeight = with(density) {
it.size.height.toDp()
startDestination = if (isAnalyticsShown == true) Route.Main() else Route.Analytics,
modifier =
Modifier
.fillMaxSize()
.padding(padding),
enterTransition = { fadeIn(tween(200)) },
exitTransition = { fadeOut(tween(200)) },
popEnterTransition = { fadeIn(tween(200)) },
popExitTransition = { fadeOut(tween(200)) },
) {
composable<Route.Main> {
val args = it.toRoute<Route.Main>()
MainScreen(appViewModel, appState, args.autoStart)
}
composable<Route.Analytics> { AnalyticsScreen(appViewModel, navController, appState) }
composable<Route.Permission> {
val args = it.toRoute<Route.Permission>()
runCatching {
PermissionScreen(appViewModel, args.permission)
}
},
)
},
snackbarHost = {
SnackbarHost(host) { snackbarData: SnackbarData ->
CustomSnackBar(message = snackbarData.visuals.message, paddingTop = navHeight)
}
},
) { padding ->
NavHost(
navController,
startDestination = if (isAnalyticsShown == true) Route.Main() else Route.Analytics,
modifier =
Modifier
.fillMaxSize()
.padding(padding),
enterTransition = { fadeIn(tween(200)) },
exitTransition = { fadeOut(tween(200)) },
popEnterTransition = { fadeIn(tween(200)) },
popExitTransition = { fadeOut(tween(200)) },
) {
composable<Route.Main> {
val args = it.toRoute<Route.Main>()
MainScreen(appViewModel, appState, args.autoStart)
}
composable<Route.Analytics> { AnalyticsScreen(appViewModel, navController, appState) }
composable<Route.Permission> {
val args = it.toRoute<Route.Permission>()
runCatching {
PermissionScreen(appViewModel, args.permission)
}
}
composable<Route.Settings> {
SettingsScreen(
appViewModel,
navController,
appState,
)
}
composable<Route.EntryLocation> {
HopScreen(
gatewayLocation = GatewayLocation.ENTRY,
appViewModel,
navController,
appState,

)
}
composable<Route.ExitLocation> {
HopScreen(
gatewayLocation = GatewayLocation.EXIT,
appViewModel,
navController,
appState,
)
}
composable<Route.Logs> { LogsScreen(appViewModel) }
composable<Route.Support> { SupportScreen(appViewModel) }
composable<Route.Feedback> { FeedbackScreen(appViewModel) }
composable<Route.Legal> { LegalScreen(appViewModel) }
composable<Route.Credential> {
CredentialScreen(appViewModel)
}
composable<Route.Account> { AccountScreen(appViewModel, appState) }
composable<Route.Licenses> {
LicensesScreen(appViewModel)
}
composable<Route.Appearance> {
AppearanceScreen(appViewModel)
}
composable<Route.Display> {
DisplayScreen(appState, appViewModel)
}
composable<Route.Language> {
LanguageScreen(appViewModel, localeStorage)
}
composable<Route.Environment> {
EnvironmentScreen(appState, appViewModel)
}
composable<Route.CredentialScanner> {
ScannerScreen(appViewModel)
composable<Route.Settings> {
SettingsScreen(
appViewModel,
navController,
appState,
)
}
composable<Route.EntryLocation> {
HopScreen(
gatewayLocation = GatewayLocation.ENTRY,
appViewModel,
appState,
)
}
composable<Route.ExitLocation> {
HopScreen(
gatewayLocation = GatewayLocation.EXIT,
appViewModel,
appState,
)
}
composable<Route.Logs> { LogsScreen(appViewModel) }
composable<Route.Support> { SupportScreen(appViewModel) }
composable<Route.Feedback> { FeedbackScreen(appViewModel) }
composable<Route.Legal> { LegalScreen(appViewModel) }
composable<Route.Credential> {
CredentialScreen(appViewModel)
}
composable<Route.Account> { AccountScreen(appViewModel, appState) }
composable<Route.Licenses> {
LicensesScreen(appViewModel)
}
composable<Route.Appearance> {
AppearanceScreen(appViewModel)
}
composable<Route.Display> {
DisplayScreen(appState, appViewModel)
}
composable<Route.Language> {
LanguageScreen(appViewModel, localeStorage)
}
composable<Route.Environment> {
EnvironmentScreen(appState, appViewModel)
}
composable<Route.CredentialScanner> {
ScannerScreen()
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package net.nymtech.nymvpn.ui.common.navigation

import androidx.compose.runtime.compositionLocalOf
import androidx.navigation.NavHostController

val LocalNavController = compositionLocalOf<NavHostController> {
error("NavController was not provided")
}

This file was deleted.

Loading

0 comments on commit 0612337

Please sign in to comment.