Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,19 @@ internal class FaceCaptureControllerFragment : Fragment(R.layout.fragment_face_c
super.onViewCreated(view, savedInstanceState)
Simber.i("FaceCaptureControllerFragment started", tag = ORCHESTRATION)

internalNavController
?.navInflater
?.inflate(R.navigation.graph_face_capture_internal)
?.also {
it.setStartDestination(
if (viewModel.shouldShowInstructionsScreen()) {
R.id.facePreparationFragment
} else {
R.id.faceLiveFeedbackFragment
},
)
}?.let { internalNavController?.setGraph(it, null) }

findNavController().handleResult<ExitFormResult>(
this,
R.id.faceCaptureControllerFragment,
Expand Down Expand Up @@ -117,19 +130,6 @@ internal class FaceCaptureControllerFragment : Fragment(R.layout.fragment_face_c
else -> findNavController().popBackStack()
}
}

internalNavController
?.navInflater
?.inflate(R.navigation.graph_face_capture_internal)
?.also {
it.setStartDestination(
if (viewModel.shouldShowInstructionsScreen()) {
R.id.facePreparationFragment
} else {
R.id.faceLiveFeedbackFragment
},
)
}?.let { internalNavController?.setGraph(it, null) }
}

private fun initFaceBioSdk() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ internal class ExternalCredentialControllerFragment : Fragment(R.layout.fragment

viewModel.init(params)

internalNavController?.setGraph(R.navigation.graph_external_credential_internal)

findNavController().handleResult<ExitFormResult>(
this,
R.id.externalCredentialControllerFragment,
Expand All @@ -57,7 +59,6 @@ internal class ExternalCredentialControllerFragment : Fragment(R.layout.fragment
)
}
}
internalNavController?.setGraph(R.navigation.graph_external_credential_internal)

initObservers()
initListeners()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,32 +173,27 @@ private fun NavController.navigateIfPossible(
}

/**
* Only one navigation request needs to be processed from the fragment. This method checks if the
* no other navigation is scheduled in the [NavController]. It does so by checking whether the
* class name in the [NavController.currentDestination] is null or equals to the current fragment
* name.
* Checks whether the [NavController] is in a state that allows navigation from [currentFragment].
* This prevents duplicate navigation requests when a fragment triggers navigation more than once.
*
* - On the app startup, the [NavController.currentDestination] is null, since there were no
* navigation requests.
* - When the first navigation request to the target 'A' happens, then the field 'className' in the
* [NavController.currentDestination] becomes 'A'.
* - When the [currentFragment] 'A' wants to navigate to the destination 'B', this method checks if
* the current value of the [NavController.currentDestination] is still 'A' (it was set to 'A'
* during the previous navigation request).
* - If the name of the [currentFragment] is different to the 'className' in the
* [NavController.currentDestination], it means that the the current fragment has a navigation
* request scheduled already, and the navigation cannot be executed.
* - If [NavController.currentDestination] is null (no graph set), navigation is not possible.
* - When the [currentFragment] 'A' wants to navigate to destination 'B', this method checks if
* the 'className' in [NavController.currentDestination] still matches 'A'.
* - If it doesn't match, another navigation request has already been processed and navigation
* is rejected to prevent double-navigation.
*
* @param currentFragment - currently displayed fragment in the [NavController]
* @return true if the class name of the [currentFragment] is equal to the 'className' field in the
* [NavController.currentDestination], or if the [NavController.currentDestination] is null. false
* otherwise.
* @return true if [NavController.currentDestination] is set and its class name matches
* [currentFragment], or if [NavController.currentDestination] is not a [FragmentNavigator.Destination].
* false if [currentFragment] is null, [NavController.currentDestination] is null, or the
* destination class name does not match [currentFragment] (indicating a navigation already occurred).
*/
@ExcludedFromGeneratedTestCoverageReports("There is no reasonable way to test this")
private fun NavController.canNavigate(currentFragment: Fragment?): Boolean {
val fragmentName = currentFragment?.let { it::class.java.name }
val targetClassName = (currentDestination as? FragmentNavigator.Destination)?.className
return currentFragment != null && (targetClassName == null || targetClassName == fragmentName)
currentFragment ?: return false
val currentDest = currentDestination ?: return false
val targetClassName = (currentDest as? FragmentNavigator.Destination)?.className
return targetClassName == null || targetClassName == currentFragment::class.java.name
Comment on lines +193 to +196
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

canNavigate() now returns false when currentDestination is null. That will route more cases through navigateIfPossible’s failure branch, which logs a Simber.w(..., IllegalStateException(...)). In release builds, Simber.w is forwarded to Crashlytics and records the exception, so this change can create noisy non-fatal Crashlytics issues during state restoration/graph setup races. Consider special-casing the currentDestination == null path to log without a throwable (or at info) and/or include a clearer message like “Nav graph not set yet” so it’s actionable without polluting Crashlytics.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's an exceptional situation that we do want to get informed about.

}

/**
Expand Down
Loading