Skip to content

Commit 69f66c7

Browse files
PM-27703: Update Authenticator navigation
1 parent 8de3a07 commit 69f66c7

File tree

26 files changed

+205
-226
lines changed

26 files changed

+205
-226
lines changed

app/src/main/kotlin/com/x8bit/bitwarden/MainActivity.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import com.x8bit.bitwarden.ui.platform.composition.LocalManagerProvider
3636
import com.x8bit.bitwarden.ui.platform.feature.debugmenu.debugMenuDestination
3737
import com.x8bit.bitwarden.ui.platform.feature.debugmenu.manager.DebugMenuLaunchManager
3838
import com.x8bit.bitwarden.ui.platform.feature.debugmenu.navigateToDebugMenuScreen
39-
import com.x8bit.bitwarden.ui.platform.feature.rootnav.ROOT_ROUTE
39+
import com.x8bit.bitwarden.ui.platform.feature.rootnav.RootNavigationRoute
4040
import com.x8bit.bitwarden.ui.platform.feature.rootnav.rootNavDestination
4141
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppLanguage
4242
import com.x8bit.bitwarden.ui.platform.model.AuthTabLaunchers
@@ -119,7 +119,7 @@ class MainActivity : AppCompatActivity() {
119119
) {
120120
NavHost(
121121
navController = navController,
122-
startDestination = ROOT_ROUTE,
122+
startDestination = RootNavigationRoute,
123123
) {
124124
// Nothing else should end up at this top level, we just want the ability
125125
// to have the debug menu appear on top of the rest of the app without

app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/rootnav/RootNavNavigation.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,21 @@ package com.x8bit.bitwarden.ui.platform.feature.rootnav
22

33
import androidx.navigation.NavGraphBuilder
44
import androidx.navigation.compose.composable
5+
import kotlinx.serialization.Serializable
56

67
/**
7-
* The route for the root navigation screen.
8+
* The type-safe route for the root navigation screen.
89
*/
9-
const val ROOT_ROUTE: String = "root"
10+
@Serializable
11+
data object RootNavigationRoute
1012

1113
/**
1214
* Add the root navigation screen to the nav graph.
1315
*/
1416
fun NavGraphBuilder.rootNavDestination(
1517
onSplashScreenRemoved: () -> Unit,
1618
) {
17-
composable(route = ROOT_ROUTE) {
19+
composable<RootNavigationRoute> {
1820
RootNavScreen(onSplashScreenRemoved = onSplashScreenRemoved)
1921
}
2022
}

app/src/main/kotlin/com/x8bit/bitwarden/ui/platform/feature/vaultunlockednavbar/VaultUnlockedNavBarScreen.kt

Lines changed: 5 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,12 @@ import androidx.compose.ui.unit.dp
1111
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
1212
import androidx.lifecycle.compose.collectAsStateWithLifecycle
1313
import androidx.navigation.NavBackStackEntry
14-
import androidx.navigation.NavController
1514
import androidx.navigation.NavDestination.Companion.hierarchy
16-
import androidx.navigation.NavGraph.Companion.findStartDestination
1715
import androidx.navigation.NavHostController
18-
import androidx.navigation.NavOptions
1916
import androidx.navigation.compose.NavHost
2017
import androidx.navigation.compose.currentBackStackEntryAsState
21-
import androidx.navigation.navOptions
2218
import com.bitwarden.ui.platform.base.util.EventsEffect
19+
import com.bitwarden.ui.platform.base.util.navigateToTabOrRoot
2320
import com.bitwarden.ui.platform.components.navigation.model.NavigationItem
2421
import com.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
2522
import com.bitwarden.ui.platform.components.scaffold.model.ScaffoldNavigationData
@@ -86,31 +83,31 @@ fun VaultUnlockedNavBarScreen(
8683
is VaultUnlockedNavBarEvent.Shortcut.NavigateToVaultScreen,
8784
is VaultUnlockedNavBarEvent.NavigateToVaultScreen,
8885
-> {
89-
navigateToTabOrRoot(tabToNavigateTo = event.tab) {
86+
navigateToTabOrRoot(target = event.tab) {
9087
navigateToVaultGraph(navOptions = it)
9188
}
9289
}
9390

9491
VaultUnlockedNavBarEvent.Shortcut.NavigateToSendScreen,
9592
VaultUnlockedNavBarEvent.NavigateToSendScreen,
9693
-> {
97-
navigateToTabOrRoot(tabToNavigateTo = event.tab) {
94+
navigateToTabOrRoot(target = event.tab) {
9895
navigateToSendGraph(navOptions = it)
9996
}
10097
}
10198

10299
VaultUnlockedNavBarEvent.Shortcut.NavigateToGeneratorScreen,
103100
VaultUnlockedNavBarEvent.NavigateToGeneratorScreen,
104101
-> {
105-
navigateToTabOrRoot(tabToNavigateTo = event.tab) {
102+
navigateToTabOrRoot(target = event.tab) {
106103
navigateToGeneratorGraph(navOptions = it)
107104
}
108105
}
109106

110107
VaultUnlockedNavBarEvent.Shortcut.NavigateToSettingsScreen,
111108
VaultUnlockedNavBarEvent.NavigateToSettingsScreen,
112109
-> {
113-
navigateToTabOrRoot(tabToNavigateTo = event.tab) {
110+
navigateToTabOrRoot(target = event.tab) {
114111
navigateToSettingsGraph(navOptions = it)
115112
}
116113
}
@@ -279,37 +276,6 @@ private fun VaultUnlockedNavBarScaffold(
279276
}
280277
}
281278

282-
/**
283-
* Helper function to determine how to navigate to a specified [VaultUnlockedNavBarTab].
284-
* If direct navigation is required, the [navigate] lambda will be invoked with the appropriate
285-
* [NavOptions].
286-
*/
287-
@Suppress("MaxLineLength")
288-
private fun NavController.navigateToTabOrRoot(
289-
tabToNavigateTo: VaultUnlockedNavBarTab,
290-
navigate: (NavOptions) -> Unit,
291-
) {
292-
if (tabToNavigateTo.startDestinationRoute.toObjectNavigationRoute() == currentDestination?.route) {
293-
// We are at the start destination already, so nothing to do.
294-
return
295-
} else if (currentDestination?.parent?.route == tabToNavigateTo.graphRoute.toObjectNavigationRoute()) {
296-
// We are not at the start destination but we are in the correct graph,
297-
// so lets pop up to the start destination.
298-
popBackStack(route = tabToNavigateTo.startDestinationRoute, inclusive = false)
299-
} else {
300-
// We are not in correct graph at all, so navigate there.
301-
navigate(
302-
navOptions {
303-
popUpTo(id = graph.findStartDestination().id) {
304-
saveState = true
305-
}
306-
launchSingleTop = true
307-
restoreState = true
308-
},
309-
)
310-
}
311-
}
312-
313279
/**
314280
* Determine if the current destination is the same as the given tab.
315281
*/
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources>
3-
<dimen name="dialogDimBackgroundAmount" format="float">0.75</dimen>
43
<color name="windowBackground">@android:color/transparent</color>
54
</resources>

app/src/main/res/values/values.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources>
3-
<dimen name="dialogDimBackgroundAmount" format="float">0.55</dimen>
43
<!-- default -->
54
<integer name="displayCutoutMode">0</integer>
65
<color name="windowBackground">@android:color/transparent</color>

authenticator/src/main/kotlin/com/bitwarden/authenticator/MainActivity.kt

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,26 @@ import androidx.activity.compose.setContent
1010
import androidx.activity.viewModels
1111
import androidx.appcompat.app.AppCompatActivity
1212
import androidx.appcompat.app.AppCompatDelegate
13+
import androidx.compose.runtime.Composable
1314
import androidx.compose.runtime.getValue
1415
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
1516
import androidx.lifecycle.compose.collectAsStateWithLifecycle
16-
import androidx.lifecycle.lifecycleScope
1717
import androidx.navigation.NavHostController
18+
import androidx.navigation.compose.NavHost
1819
import androidx.navigation.compose.rememberNavController
1920
import com.bitwarden.authenticator.data.platform.repository.SettingsRepository
2021
import com.bitwarden.authenticator.ui.platform.composition.LocalManagerProvider
22+
import com.bitwarden.authenticator.ui.platform.feature.debugmenu.debugMenuDestination
2123
import com.bitwarden.authenticator.ui.platform.feature.debugmenu.manager.DebugMenuLaunchManager
2224
import com.bitwarden.authenticator.ui.platform.feature.debugmenu.navigateToDebugMenuScreen
23-
import com.bitwarden.authenticator.ui.platform.feature.rootnav.RootNavScreen
25+
import com.bitwarden.authenticator.ui.platform.feature.rootnav.RootNavigationRoute
26+
import com.bitwarden.authenticator.ui.platform.feature.rootnav.rootNavDestination
27+
import com.bitwarden.ui.platform.base.util.EventsEffect
2428
import com.bitwarden.ui.platform.theme.BitwardenTheme
2529
import com.bitwarden.ui.platform.util.setupEdgeToEdge
2630
import com.bitwarden.ui.platform.util.validate
2731
import dagger.hilt.android.AndroidEntryPoint
28-
import kotlinx.coroutines.flow.launchIn
2932
import kotlinx.coroutines.flow.map
30-
import kotlinx.coroutines.flow.onEach
3133
import javax.inject.Inject
3234

3335
/**
@@ -61,20 +63,28 @@ class MainActivity : AppCompatActivity() {
6163
AppCompatDelegate.setDefaultNightMode(settingsRepository.appTheme.osValue)
6264
setupEdgeToEdge(appThemeFlow = mainViewModel.stateFlow.map { it.theme })
6365
setContent {
66+
val navController = rememberNavController()
67+
SetupEventsEffect(navController = navController)
6468
val state by mainViewModel.stateFlow.collectAsStateWithLifecycle()
6569
updateScreenCapture(isScreenCaptureAllowed = state.isScreenCaptureAllowed)
66-
val navController = rememberNavController()
67-
observeViewModelEvents(navController)
6870
LocalManagerProvider {
6971
BitwardenTheme(
7072
theme = state.theme,
7173
dynamicColor = state.isDynamicColorsEnabled,
7274
) {
73-
RootNavScreen(
75+
NavHost(
7476
navController = navController,
75-
onSplashScreenRemoved = { shouldShowSplashScreen = false },
76-
onExitApplication = { finishAffinity() },
77-
)
77+
startDestination = RootNavigationRoute,
78+
) {
79+
// Nothing else should end up at this top level, we just want the ability
80+
// to have the debug menu appear on top of the rest of the app without
81+
// interacting with the state-based navigation used by the RootNavScreen.
82+
rootNavDestination { shouldShowSplashScreen = false }
83+
debugMenuDestination(
84+
onNavigateBack = { navController.popBackStack() },
85+
onSplashScreenRemoved = { shouldShowSplashScreen = false },
86+
)
87+
}
7888
}
7989
}
8090
}
@@ -92,18 +102,16 @@ class MainActivity : AppCompatActivity() {
92102
mainViewModel.trySendAction(MainAction.ReceiveNewIntent(intent = newIntent))
93103
}
94104

95-
private fun observeViewModelEvents(navController: NavHostController) {
96-
mainViewModel
97-
.eventFlow
98-
.onEach { event ->
99-
when (event) {
100-
MainEvent.NavigateToDebugMenu -> navController.navigateToDebugMenuScreen()
101-
is MainEvent.UpdateAppTheme -> {
102-
AppCompatDelegate.setDefaultNightMode(event.osTheme)
103-
}
105+
@Composable
106+
private fun SetupEventsEffect(navController: NavHostController) {
107+
EventsEffect(viewModel = mainViewModel) { event ->
108+
when (event) {
109+
MainEvent.NavigateToDebugMenu -> navController.navigateToDebugMenuScreen()
110+
is MainEvent.UpdateAppTheme -> {
111+
AppCompatDelegate.setDefaultNightMode(event.osTheme)
104112
}
105113
}
106-
.launchIn(lifecycleScope)
114+
}
107115
}
108116

109117
override fun dispatchTouchEvent(event: MotionEvent): Boolean = debugLaunchManager

authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/authenticator/AuthenticatorNavigation.kt

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,18 @@ import androidx.navigation.NavController
44
import androidx.navigation.NavGraphBuilder
55
import androidx.navigation.NavOptions
66
import androidx.navigation.navigation
7+
import com.bitwarden.authenticator.ui.authenticator.feature.edititem.editItemDestination
78
import com.bitwarden.authenticator.ui.authenticator.feature.edititem.navigateToEditItem
8-
import com.bitwarden.authenticator.ui.authenticator.feature.itemlisting.itemListingGraph
9+
import com.bitwarden.authenticator.ui.authenticator.feature.manualcodeentry.manualCodeEntryDestination
910
import com.bitwarden.authenticator.ui.authenticator.feature.manualcodeentry.navigateToManualCodeEntryScreen
1011
import com.bitwarden.authenticator.ui.authenticator.feature.navbar.AuthenticatorNavbarRoute
1112
import com.bitwarden.authenticator.ui.authenticator.feature.navbar.authenticatorNavBarDestination
1213
import com.bitwarden.authenticator.ui.authenticator.feature.qrcodescan.navigateToQrCodeScanScreen
14+
import com.bitwarden.authenticator.ui.authenticator.feature.qrcodescan.qrCodeScanDestination
15+
import com.bitwarden.authenticator.ui.authenticator.feature.search.itemSearchDestination
1316
import com.bitwarden.authenticator.ui.authenticator.feature.search.navigateToSearch
14-
import com.bitwarden.authenticator.ui.platform.feature.settings.export.navigateToExport
15-
import com.bitwarden.authenticator.ui.platform.feature.settings.importing.navigateToImporting
1617
import com.bitwarden.authenticator.ui.platform.feature.tutorial.navigateToSettingsTutorial
18+
import com.bitwarden.authenticator.ui.platform.feature.tutorial.tutorialSettingsDestination
1719
import kotlinx.serialization.Serializable
1820

1921
/**
@@ -34,39 +36,41 @@ fun NavController.navigateToAuthenticatorGraph(navOptions: NavOptions? = null) {
3436
*/
3537
fun NavGraphBuilder.authenticatorGraph(
3638
navController: NavController,
37-
onNavigateBack: () -> Unit,
3839
) {
3940
navigation<AuthenticatorGraphRoute>(
4041
startDestination = AuthenticatorNavbarRoute,
4142
) {
4243
authenticatorNavBarDestination(
43-
onNavigateBack = onNavigateBack,
44+
onNavigateBack = { navController.popBackStack() },
4445
onNavigateToSearch = { navController.navigateToSearch() },
4546
onNavigateToQrCodeScanner = { navController.navigateToQrCodeScanScreen() },
4647
onNavigateToManualKeyEntry = { navController.navigateToManualCodeEntryScreen() },
4748
onNavigateToEditItem = { navController.navigateToEditItem(itemId = it) },
48-
onNavigateToExport = { navController.navigateToExport() },
49-
onNavigateToImport = { navController.navigateToImporting() },
5049
onNavigateToTutorial = { navController.navigateToSettingsTutorial() },
5150
)
52-
itemListingGraph(
53-
navController = navController,
54-
navigateBack = onNavigateBack,
55-
navigateToSearch = {
56-
navController.navigateToSearch()
57-
},
58-
navigateToQrCodeScanner = {
59-
navController.navigateToQrCodeScanScreen()
60-
},
61-
navigateToManualKeyEntry = {
51+
editItemDestination(
52+
onNavigateBack = { navController.popBackStack() },
53+
)
54+
itemSearchDestination(
55+
onNavigateBack = { navController.popBackStack() },
56+
onNavigateToEdit = { navController.navigateToEditItem(itemId = it) },
57+
)
58+
qrCodeScanDestination(
59+
onNavigateBack = { navController.popBackStack() },
60+
onNavigateToManualCodeEntryScreen = {
61+
navController.popBackStack()
6262
navController.navigateToManualCodeEntryScreen()
6363
},
64-
navigateToEditItem = {
65-
navController.navigateToEditItem(itemId = it)
64+
)
65+
manualCodeEntryDestination(
66+
onNavigateBack = { navController.popBackStack() },
67+
onNavigateToQrCodeScreen = {
68+
navController.popBackStack()
69+
navController.navigateToQrCodeScanScreen()
6670
},
67-
navigateToExport = { navController.navigateToExport() },
68-
navigateToImport = { navController.navigateToImporting() },
69-
navigateToTutorial = { navController.navigateToSettingsTutorial() },
71+
)
72+
tutorialSettingsDestination(
73+
onTutorialFinished = { navController.popBackStack() },
7074
)
7175
}
7276
}

authenticator/src/main/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/edititem/EditItemNavigation.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import androidx.navigation.NavController
55
import androidx.navigation.NavGraphBuilder
66
import androidx.navigation.NavOptions
77
import androidx.navigation.toRoute
8-
import com.bitwarden.ui.platform.base.util.composableWithPushTransitions
8+
import com.bitwarden.ui.platform.base.util.composableWithSlideTransitions
99
import kotlinx.serialization.Serializable
1010

1111
/**
@@ -37,7 +37,7 @@ fun SavedStateHandle.toEditItemArgs(): EditItemArgs {
3737
fun NavGraphBuilder.editItemDestination(
3838
onNavigateBack: () -> Unit = { },
3939
) {
40-
composableWithPushTransitions<EditItemRoute> {
40+
composableWithSlideTransitions<EditItemRoute> {
4141
EditItemScreen(
4242
onNavigateBack = onNavigateBack,
4343
)

0 commit comments

Comments
 (0)