Skip to content

Commit

Permalink
Allow users to enable biometric unlock from settings
Browse files Browse the repository at this point in the history
  • Loading branch information
SaintPatrck committed Apr 23, 2024
1 parent 639f4dc commit 3c55825
Show file tree
Hide file tree
Showing 14 changed files with 555 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ class MainActivity : AppCompatActivity() {
theme = state.theme
) {
RootNavScreen(
onSplashScreenRemoved = { shouldShowSplashScreen = false }
onSplashScreenRemoved = { shouldShowSplashScreen = false },
onExitApplication = { finishAffinity() }
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ fun NavController.navigateToAuthenticatorGraph(navOptions: NavOptions? = null) {
*/
fun NavGraphBuilder.authenticatorGraph(
navController: NavController,
onNavigateBack: () -> Unit,
) {
navigation(
startDestination = AUTHENTICATOR_NAV_BAR_ROUTE,
route = AUTHENTICATOR_GRAPH_ROUTE
) {
authenticatorNavBarDestination(
onNavigateBack = onNavigateBack,
onNavigateToSearch = { navController.navigateToSearch() },
onNavigateToQrCodeScanner = { navController.navigateToQrCodeScanScreen() },
onNavigateToManualKeyEntry = { navController.navigateToManualCodeEntryScreen() },
Expand All @@ -43,6 +45,7 @@ fun NavGraphBuilder.authenticatorGraph(
)
itemListingGraph(
navController = navController,
navigateBack = onNavigateBack,
navigateToSearch = {
navController.navigateToSearch()
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const val ITEM_LISTING_GRAPH_ROUTE = "item_listing_graph"
*/
fun NavGraphBuilder.itemListingGraph(
navController: NavController,
navigateBack: () -> Unit,
navigateToSearch: () -> Unit,
navigateToQrCodeScanner: () -> Unit,
navigateToManualKeyEntry: () -> Unit,
Expand All @@ -31,7 +32,7 @@ fun NavGraphBuilder.itemListingGraph(
startDestination = ITEM_LIST_ROUTE,
) {
itemListingDestination(
onNavigateBack = { navController.popBackStack() },
onNavigateBack = navigateBack,
onNavigateToSearch = navigateToSearch,
onNavigateToQrCodeScanner = navigateToQrCodeScanner,
onNavigateToManualKeyEntry = navigateToManualKeyEntry,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const val AUTHENTICATOR_NAV_BAR_ROUTE: String = "AuthenticatorNavBarRoute"
* Add the authenticator nav bar to the nav graph.
*/
fun NavGraphBuilder.authenticatorNavBarDestination(
onNavigateBack: () -> Unit,
onNavigateToSearch: () -> Unit,
onNavigateToQrCodeScanner: () -> Unit,
onNavigateToManualKeyEntry: () -> Unit,
Expand All @@ -20,6 +21,7 @@ fun NavGraphBuilder.authenticatorNavBarDestination(
route = AUTHENTICATOR_NAV_BAR_ROUTE,
) {
AuthenticatorNavBarScreen(
onNavigateBack = onNavigateBack,
onNavigateToQrCodeScanner = onNavigateToQrCodeScanner,
onNavigateToManualKeyEntry = onNavigateToManualKeyEntry,
onNavigateToEditItem = onNavigateToEditItem,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import kotlinx.parcelize.Parcelize
fun AuthenticatorNavBarScreen(
viewModel: AuthenticatorNavBarViewModel = hiltViewModel(),
navController: NavHostController = rememberNavController(),
onNavigateBack: () -> Unit,
onNavigateToSearch: () -> Unit,
onNavigateToQrCodeScanner: () -> Unit,
onNavigateToManualKeyEntry: () -> Unit,
Expand Down Expand Up @@ -106,6 +107,7 @@ fun AuthenticatorNavBarScreen(
settingsTabClickedAction = {
viewModel.trySendAction(AuthenticatorNavBarAction.SettingsTabClick)
},
navigateBack = onNavigateBack,
navigateToSearch = onNavigateToSearch,
navigateToQrCodeScanner = onNavigateToQrCodeScanner,
navigateToManualKeyEntry = onNavigateToManualKeyEntry,
Expand All @@ -121,6 +123,7 @@ private fun AuthenticatorNavBarScaffold(
navController: NavHostController,
verificationTabClickedAction: () -> Unit,
settingsTabClickedAction: () -> Unit,
navigateBack: () -> Unit,
navigateToSearch: () -> Unit,
navigateToQrCodeScanner: () -> Unit,
navigateToManualKeyEntry: () -> Unit,
Expand Down Expand Up @@ -168,6 +171,7 @@ private fun AuthenticatorNavBarScaffold(
) {
itemListingGraph(
navController = navController,
navigateBack = navigateBack,
navigateToSearch = navigateToSearch,
navigateToQrCodeScanner = navigateToQrCodeScanner,
navigateToManualKeyEntry = navigateToManualKeyEntry,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ fun RootNavScreen(
viewModel: RootNavViewModel = hiltViewModel(),
navController: NavHostController = rememberNavController(),
onSplashScreenRemoved: () -> Unit = {},
onExitApplication: () -> Unit,
) {
val state by viewModel.stateFlow.collectAsState()
val previousStateReference = remember { AtomicReference(state) }

val isNotSplashScreen = state !is RootNavState.Splash
val isNotSplashScreen = state.navState !is RootNavState.NavState.Splash
LaunchedEffect(isNotSplashScreen) {
if (isNotSplashScreen) {
onSplashScreenRemoved()
Expand All @@ -64,17 +65,27 @@ fun RootNavScreen(
popEnterTransition = { toEnterTransition()(this) },
popExitTransition = { toExitTransition()(this) },
) {
splashDestination()
splashDestination(
onSplashScreenDismissed = {
viewModel.trySendAction(RootNavAction.Internal.SplashScreenDismissed)
},
onExitApplication = onExitApplication,
)
tutorialDestination(
onTutorialFinished = { navController.navigateToAuthenticatorGraph() }
onTutorialFinished = {
viewModel.trySendAction(RootNavAction.Internal.TutorialFinished)
},
)
authenticatorGraph(
navController = navController,
onNavigateBack = onExitApplication,
)
authenticatorGraph(navController)
}

val targetRoute = when (state) {
RootNavState.ItemListing -> AUTHENTICATOR_GRAPH_ROUTE
RootNavState.Splash -> SPLASH_ROUTE
RootNavState.Tutorial -> TUTORIAL_ROUTE
val targetRoute = when (state.navState) {
RootNavState.NavState.ItemListing -> AUTHENTICATOR_GRAPH_ROUTE
RootNavState.NavState.Splash -> SPLASH_ROUTE
RootNavState.NavState.Tutorial -> TUTORIAL_ROUTE
}

val currentRoute = navController.currentDestination?.rootLevelRoute()
Expand All @@ -100,10 +111,18 @@ fun RootNavScreen(
}

LaunchedEffect(state) {
when (state) {
RootNavState.Splash -> navController.navigateToSplash(rootNavOptions)
RootNavState.Tutorial -> navController.navigateToTutorial(rootNavOptions)
RootNavState.ItemListing -> navController.navigateToAuthenticatorGraph(rootNavOptions)
when (state.navState) {
RootNavState.NavState.Splash -> {
navController.navigateToSplash(rootNavOptions)
}

RootNavState.NavState.Tutorial -> {
navController.navigateToTutorial(rootNavOptions)
}

RootNavState.NavState.ItemListing -> {
navController.navigateToAuthenticatorGraph(rootNavOptions)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
package com.bitwarden.authenticator.ui.platform.feature.rootnav

import android.os.Parcelable
import androidx.lifecycle.viewModelScope
import com.bitwarden.authenticator.data.auth.repository.AuthRepository
import com.bitwarden.authenticator.data.platform.repository.SettingsRepository
import com.bitwarden.authenticator.ui.platform.base.BaseViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize
import javax.inject.Inject

Expand All @@ -19,18 +14,12 @@ class RootNavViewModel @Inject constructor(
private val authRepository: AuthRepository,
private val settingsRepository: SettingsRepository,
) : BaseViewModel<RootNavState, Unit, RootNavAction>(
initialState = RootNavState.Splash
initialState = RootNavState(
hasSeenWelcomeGuide = settingsRepository.hasSeenWelcomeTutorial,
navState = RootNavState.NavState.Splash,
)
) {

init {
viewModelScope.launch {
settingsRepository.hasSeenWelcomeTutorialFlow
.map { RootNavAction.Internal.HasSeenWelcomeTutorialChange(it) }
.onEach(::sendAction)
.launchIn(viewModelScope)
}
}

override fun handleAction(action: RootNavAction) {
when (action) {
RootNavAction.BackStackUpdate -> {
Expand All @@ -40,6 +29,14 @@ class RootNavViewModel @Inject constructor(
is RootNavAction.Internal.HasSeenWelcomeTutorialChange -> {
handleHasSeenWelcomeTutorialChange(action.hasSeenWelcomeGuide)
}

RootNavAction.Internal.TutorialFinished -> {
handleTutorialFinished()
}

RootNavAction.Internal.SplashScreenDismissed -> {
handleSplashScreenDismissed()
}
}
}

Expand All @@ -49,35 +46,54 @@ class RootNavViewModel @Inject constructor(

private fun handleHasSeenWelcomeTutorialChange(hasSeenWelcomeGuide: Boolean) {
if (hasSeenWelcomeGuide) {
mutableStateFlow.update { RootNavState.ItemListing }
mutableStateFlow.update { it.copy(navState = RootNavState.NavState.ItemListing) }
} else {
mutableStateFlow.update { RootNavState.Tutorial }
mutableStateFlow.update { it.copy(navState = RootNavState.NavState.Tutorial) }
}
}

private fun handleTutorialFinished() {
settingsRepository.hasSeenWelcomeTutorial = true
}

private fun handleSplashScreenDismissed() {
if (settingsRepository.hasSeenWelcomeTutorial) {
mutableStateFlow.update { it.copy(navState = RootNavState.NavState.ItemListing) }
} else {
mutableStateFlow.update { it.copy(navState = RootNavState.NavState.Tutorial) }
}
}
}

/**
* Models root level destinations for the app.
*/
sealed class RootNavState : Parcelable {
@Parcelize
data class RootNavState(
val hasSeenWelcomeGuide: Boolean,
val navState: NavState,
) : Parcelable {

/**
* App should display the Splash nav graph.
*/
@Parcelize
data object Splash : RootNavState()
sealed class NavState : Parcelable {
/**
* App should display the Splash nav graph.
*/
@Parcelize
data object Splash : NavState()

/**
* App should display the Tutorial nav graph.
*/
@Parcelize
data object Tutorial : RootNavState()
/**
* App should display the Tutorial nav graph.
*/
@Parcelize
data object Tutorial : NavState()

/**
* App should display the Account List nav graph.
*/
@Parcelize
data object ItemListing : RootNavState()
/**
* App should display the Account List nav graph.
*/
@Parcelize
data object ItemListing : NavState()
}
}

/**
Expand All @@ -94,6 +110,10 @@ sealed class RootNavAction {
*/
sealed class Internal : RootNavAction() {

data object SplashScreenDismissed : Internal()

data object TutorialFinished : Internal()

/**
* Indicates an update in the welcome guide being seen has been received.
*/
Expand Down
Loading

0 comments on commit 3c55825

Please sign in to comment.