Skip to content
Merged
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 @@ -53,7 +53,6 @@ internal class FaceCaptureViewModel @Inject constructor(
private val licenseRepository: LicenseRepository,
private val resolveFaceBioSdk: ResolveFaceBioSdkUseCase,
private val saveLicenseCheckEvent: SaveLicenseCheckEventUseCase,
private val isUsingAutoCapture: IsUsingAutoCaptureUseCase,
private val shouldShowInstructions: ShouldShowInstructionsScreenUseCase,
@DeviceID private val deviceID: String,
) : ViewModel() {
Expand Down Expand Up @@ -87,10 +86,6 @@ internal class FaceCaptureViewModel @Inject constructor(
get() = _invalidLicense
private val _invalidLicense = MutableLiveData<LiveDataEvent>()

val isAutoCaptureEnabled: LiveData<Boolean>
get() = _isAutoCaptureEnabled
private val _isAutoCaptureEnabled = MutableLiveData<Boolean>()

fun setupCapture(samplesToCapture: Int) {
this.samplesToCapture = samplesToCapture
}
Expand Down Expand Up @@ -142,10 +137,6 @@ internal class FaceCaptureViewModel @Inject constructor(
}
}

fun setupAutoCapture() = viewModelScope.launch {
_isAutoCaptureEnabled.postValue(isUsingAutoCapture())
}

fun shouldShowInstructionsScreen(): Boolean = shouldShowInstructions()

private suspend fun initialize(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,26 +118,18 @@ internal class FaceCaptureControllerFragment : Fragment(R.layout.fragment_face_c
}
}

viewModel.setupAutoCapture()
viewModel.isAutoCaptureEnabled.observe(viewLifecycleOwner) { isAutoCaptureEnabled ->
val graph = internalNavController?.navInflater?.inflate(
if (isAutoCaptureEnabled) {
R.navigation.graph_face_capture_auto_internal
} else {
R.navigation.graph_face_capture_internal
},
)
graph?.setStartDestination(
if (viewModel.shouldShowInstructionsScreen()) {
R.id.facePreparationFragment
} else {
R.id.faceLiveFeedbackFragment
},
)
graph?.let {
internalNavController?.setGraph(graph, null)
}
}
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 @@ -3,7 +3,6 @@ package com.simprints.face.capture.screens.livefeedback
import android.Manifest
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.util.Size
Expand All @@ -17,6 +16,7 @@ import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.lifecycle.awaitInstance
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
Expand Down Expand Up @@ -66,6 +66,9 @@ internal class LiveFeedbackFragment : Fragment(R.layout.fragment_live_feedback)

private var cameraControl: CameraControl? = null

private val validCaptureProgressColor = ContextCompat.getColor(requireContext(), IDR.color.simprints_green_light)
private val defaultCaptureProgressColor = ContextCompat.getColor(requireContext(), IDR.color.simprints_blue_grey_light)

private val launchPermissionRequest = registerForActivityResult(
ActivityResultContracts.RequestPermission(),
) { granted ->
Expand All @@ -90,16 +93,26 @@ internal class LiveFeedbackFragment : Fragment(R.layout.fragment_live_feedback)
private fun initFragment() {
screenSize = with(resources.displayMetrics) { Size(widthPixels, widthPixels) }
bindViewModel()
binding.captureProgress.max = 1 // normalized progress

binding.captureFeedbackBtn.setOnClickListener { vm.startCapture() }
binding.captureProgress.max = mainVm.samplesToCapture
binding.captureFeedbackBtn.setOnClickListener {
vm.startCapture()
if (vm.isAutoCapture) {
binding.captureFeedbackBtn.isClickable = false
}
}

// Wait till the views gets its final size then init frame processor and setup the camera
binding.faceCaptureCamera.post {
if (view != null) {
vm.initCapture(mainVm.bioSDK, mainVm.samplesToCapture, mainVm.attemptNumber)
}
}
if (vm.isAutoCapture) {
// Await until capture button is pressed
vm.holdOffAutoCapture()
binding.captureFeedbackBtn.isClickable = true
}

binding.captureInstructionsBtn.setOnClickListener {
findNavController().navigateSafely(
Expand Down Expand Up @@ -199,11 +212,9 @@ internal class LiveFeedbackFragment : Fragment(R.layout.fragment_live_feedback)
}

vm.capturingState.observe(viewLifecycleOwner) {
@Suppress("WHEN_ENUM_CAN_BE_NULL_IN_JAVA") when (it) {
LiveFeedbackFragmentViewModel.CapturingState.NOT_STARTED -> renderCapturingNotStarted()

when (it) {
LiveFeedbackFragmentViewModel.CapturingState.NOT_STARTED -> renderCaptureNotStarted()
LiveFeedbackFragmentViewModel.CapturingState.CAPTURING -> renderCapturing()

LiveFeedbackFragmentViewModel.CapturingState.FINISHED -> {
mainVm.captureFinished(vm.sortedQualifyingCaptures)
findNavController().navigateSafely(
Expand Down Expand Up @@ -240,39 +251,45 @@ internal class LiveFeedbackFragment : Fragment(R.layout.fragment_live_feedback)
}
}

private fun renderCapturingStateColors() {
with(binding) {
captureOverlay.drawWhiteTarget()
captureFeedbackTxtExplanation.setTextColor(
ContextCompat.getColor(requireContext(), IDR.color.simprints_blue_grey),
)
}
}

private fun renderCapturingNotStarted() {
private fun renderCaptureNotStarted() {
binding.apply {
if (vm.isAutoCapture) {
captureFeedbackBtn.setText(IDR.string.face_capture_start_capture)
captureFeedbackBtn.isChecked = true
} else {
captureFeedbackBtn.setText(IDR.string.face_capture_title_previewing)
}

captureOverlay.drawSemiTransparentTarget()
captureFeedbackBtn.setText(IDR.string.face_capture_title_previewing)
captureFeedbackBtn.isVisible = true
captureFeedbackPermissionButton.isGone = true
setManualCaptureButtonClickable(false)
}
toggleCaptureButtons(false)
}

private fun renderCapturing() {
renderCapturingStateColors()
binding.apply {
captureOverlay.drawWhiteTarget()
captureFeedbackTxtExplanation.setTextColor(
ContextCompat.getColor(requireContext(), IDR.color.simprints_blue_grey),
)

captureProgress.isVisible = true
captureFeedbackBtn.setText(IDR.string.face_capture_prep_begin_button_capturing)
captureFeedbackBtn.isVisible = true
captureFeedbackPermissionButton.isGone = true
setManualCaptureButtonClickable(false)
}
toggleCaptureButtons(false)
}

private fun renderValidFace() {
binding.apply {
captureFeedbackBtn.setText(IDR.string.face_capture_begin_button)
if (vm.isAutoCapture) {
captureFeedbackBtn.setText(IDR.string.face_capture_prep_begin_button_capturing)
} else {
captureFeedbackBtn.setText(IDR.string.face_capture_begin_button)
}

captureFeedbackTxtExplanation.text = null
captureFeedbackBtn.isVisible = true
captureFeedbackPermissionButton.isGone = true
Expand All @@ -281,8 +298,8 @@ internal class LiveFeedbackFragment : Fragment(R.layout.fragment_live_feedback)
true,
ContextCompat.getDrawable(requireContext(), R.drawable.ic_checked_white_18dp),
)
setManualCaptureButtonClickable(false)
}
toggleCaptureButtons(true)
}

private fun renderValidCapturingFace() {
Expand All @@ -296,9 +313,8 @@ internal class LiveFeedbackFragment : Fragment(R.layout.fragment_live_feedback)
true,
ContextCompat.getDrawable(requireContext(), R.drawable.ic_checked_white_18dp),
)
renderProgressBar(false)
}

renderProgressBar(true)
}

private fun renderFaceTooFar() {
Expand All @@ -309,10 +325,9 @@ internal class LiveFeedbackFragment : Fragment(R.layout.fragment_live_feedback)
captureFeedbackPermissionButton.isGone = true

captureFeedbackBtn.setCheckedWithLeftDrawable(false)
setManualCaptureButtonClickable(false)
renderProgressBar(false)
}

toggleCaptureButtons(false)
renderProgressBar(false)
}

private fun renderFaceTooClose() {
Expand All @@ -323,10 +338,9 @@ internal class LiveFeedbackFragment : Fragment(R.layout.fragment_live_feedback)
captureFeedbackPermissionButton.isGone = true

captureFeedbackBtn.setCheckedWithLeftDrawable(false)
setManualCaptureButtonClickable(false)
renderProgressBar(false)
}

toggleCaptureButtons(false)
renderProgressBar(false)
}

private fun renderNoFace() {
Expand All @@ -337,10 +351,9 @@ internal class LiveFeedbackFragment : Fragment(R.layout.fragment_live_feedback)
captureFeedbackPermissionButton.isGone = true

captureFeedbackBtn.setCheckedWithLeftDrawable(false)
setManualCaptureButtonClickable(false)
renderProgressBar(false)
}

toggleCaptureButtons(false)
renderProgressBar(false)
}

private fun renderFaceNotStraight() {
Expand All @@ -351,10 +364,9 @@ internal class LiveFeedbackFragment : Fragment(R.layout.fragment_live_feedback)
captureFeedbackPermissionButton.isGone = true

captureFeedbackBtn.setCheckedWithLeftDrawable(false)
setManualCaptureButtonClickable(false)
renderProgressBar(false)
}

toggleCaptureButtons(false)
renderProgressBar(false)
}

private fun renderBadQuality() {
Expand All @@ -365,31 +377,20 @@ internal class LiveFeedbackFragment : Fragment(R.layout.fragment_live_feedback)
captureFeedbackPermissionButton.isGone = true

captureFeedbackBtn.setCheckedWithLeftDrawable(false)
setManualCaptureButtonClickable(false)
renderProgressBar(false)
}

toggleCaptureButtons(false)
renderProgressBar(false)
}

private fun renderProgressBar(valid: Boolean) {
binding.apply {
val progressColor = if (valid) {
IDR.color.simprints_green_light
} else {
IDR.color.simprints_blue_grey_light
}

captureProgress.progressColor = ContextCompat.getColor(
requireContext(),
progressColor,
)

captureProgress.value = vm.userCaptures.size.toFloat()
}
private fun FragmentLiveFeedbackBinding.renderProgressBar(validCapture: Boolean) {
captureProgress.progressColor = if (validCapture) validCaptureProgressColor else defaultCaptureProgressColor
captureProgress.value = vm.getNormalizedProgress()
}

private fun toggleCaptureButtons(valid: Boolean) {
binding.captureFeedbackBtn.isClickable = valid
private fun FragmentLiveFeedbackBinding.setManualCaptureButtonClickable(clickable: Boolean) {
if (!vm.isAutoCapture) {
captureFeedbackBtn.isClickable = clickable
}
}

private fun renderNoPermission(shouldOpenSettings: Boolean) {
Expand All @@ -403,14 +404,14 @@ internal class LiveFeedbackFragment : Fragment(R.layout.fragment_live_feedback)
requireActivity().startActivity(
Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.parse("package:${requireActivity().packageName}"),
"package:${requireActivity().packageName}".toUri(),
),
)
} else {
launchPermissionRequest.launch(Manifest.permission.CAMERA)
}
}
setManualCaptureButtonClickable(false)
}
toggleCaptureButtons(false)
}
}
Loading