feat: streamline liveness detection flow with improved state management and navigation handling

This commit is contained in:
vergiLgood1 2025-05-25 12:14:41 +07:00
parent 19687320ee
commit e6e0a0ab07
4 changed files with 24 additions and 62 deletions

View File

@ -116,45 +116,18 @@ class SelfieVerificationController extends GetxController {
await Get.delete<FaceLivenessController>(); await Get.delete<FaceLivenessController>();
} }
// Register a new controller (will be done automatically by the widget) // Navigate to liveness detection page and wait for result
final result = await Get.toNamed( await Get.toNamed(
AppRoutes.livenessDetection, AppRoutes.livenessDetection,
preventDuplicates: false, // Allow navigation to same route if needed preventDuplicates: false, // Allow navigation to same route if needed
); );
// Handle the result based on what was returned // When returning here, the image should already be set by CapturedSelfieView
if (result is XFile) { // and automatic verification should be triggered by the listener in onInit
// Liveness check passed and returned an image
dev.log( // Reset liveness check flag since we're back
'Received result from liveness detection, setting selfie image', isPerformingLivenessCheck.value = false;
name: 'SELFIE_VERIFICATION',
);
selfieImage.value = result;
isLivenessCheckPassed.value = true;
isPerformingLivenessCheck.value = false;
// The _processCapturedLivenessImage will be called automatically
// due to the ever() listener we set up in onInit
} else if (result == 'navigation_handled') {
// Special case: navigation was handled by the captured selfie view
// The user was already navigated back to this screen
dev.log(
'Navigation handled by captured selfie view',
name: 'SELFIE_VERIFICATION',
);
isPerformingLivenessCheck.value = false;
// Don't reset other states since they should be set by the captured view
} else {
// User cancelled or something went wrong
dev.log(
'No result from liveness detection, reset states',
name: 'SELFIE_VERIFICATION',
);
isPerformingLivenessCheck.value = false;
isLivenessCheckPassed.value = false;
autoStartVerification = false;
}
} catch (e) { } catch (e) {
dev.log('Error in liveness detection: $e', name: 'SELFIE_VERIFICATION'); dev.log('Error in liveness detection: $e', name: 'SELFIE_VERIFICATION');
isPerformingLivenessCheck.value = false; isPerformingLivenessCheck.value = false;

View File

@ -125,10 +125,11 @@ class LivenessDetectionPage extends StatelessWidget {
icon: const Icon(Icons.arrow_back, color: Colors.black87), icon: const Icon(Icons.arrow_back, color: Colors.black87),
onPressed: () { onPressed: () {
dev.log('Back button pressed', name: 'LIVENESS_DEBUG'); dev.log('Back button pressed', name: 'LIVENESS_DEBUG');
if (selfieController != null) {
dev.log('Handling cancellation', name: 'LIVENESS_DEBUG'); // Ensure we clean up resources when going back
controller.handleCancellation(); controller.handleCancellation();
}
// This allows the user to go back to selfie verification step
Get.back(); Get.back();
}, },
), ),

View File

@ -397,7 +397,13 @@ class SelfieVerificationStep extends StatelessWidget {
), ),
const SizedBox(height: TSizes.spaceBtwItems), const SizedBox(height: TSizes.spaceBtwItems),
ElevatedButton.icon( ElevatedButton.icon(
onPressed: controller.performLivenessDetection, onPressed: () {
// Clear any previous images or states before starting new verification
controller.clearSelfieImage();
controller.resetVerificationState();
// Start liveness detection process
controller.performLivenessDetection();
},
icon: const Icon(Icons.security), icon: const Icon(Icons.security),
label: const Text('Start Face Verification'), label: const Text('Start Face Verification'),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(

View File

@ -666,7 +666,7 @@ class _CapturedSelfieViewState extends State<CapturedSelfieView>
// Set flag to automatically start verification upon returning // Set flag to automatically start verification upon returning
widget.selfieController!.autoStartVerification = true; widget.selfieController!.autoStartVerification = true;
// Set the captured image in the selfie controller - do this last // Set the captured image in the selfie controller
widget.selfieController!.selfieImage.value = xFile; widget.selfieController!.selfieImage.value = xFile;
dev.log( dev.log(
@ -677,30 +677,13 @@ class _CapturedSelfieViewState extends State<CapturedSelfieView>
// Now dispose the camera after we've handled the image // Now dispose the camera after we've handled the image
widget.controller.disposeCamera(); widget.controller.disposeCamera();
// Update the controller to ensure changes propagate // Simply go back to the previous screen (selfie verification step)
widget.selfieController!.update(); Get.back();
// Wait a moment to ensure the image is properly set
await Future.delayed(Duration(milliseconds: 100));
// Navigate back to selfie verification step by removing liveness detection from stack
if (mounted && !isDisposed) {
// Use Get.offAll to clear the entire navigation stack and go to signup page
// The signup page will show the selfie verification step since we've set the image
Get.offAllNamed('/signup'); // Replace with your actual signup route
// Alternative: if you know the exact route name for selfie verification step
// Get.offNamed('/signup/selfie-verification');
}
} else { } else {
widget.controller.disposeCamera(); widget.controller.disposeCamera();
if (mounted && !isDisposed) { if (mounted && !isDisposed) {
Get.back( Get.back(result: widget.controller.capturedImage);
closeOverlays: true,
canPop: true,
result: widget.controller.capturedImage,
);
} }
} }
} catch (e) { } catch (e) {
@ -711,8 +694,7 @@ class _CapturedSelfieViewState extends State<CapturedSelfieView>
if (mounted && !isDisposed) { if (mounted && !isDisposed) {
isComparingWithID.value = false; isComparingWithID.value = false;
errorMessage.value = errorMessage.value = 'Failed to process the captured image: $e';
'Failed to process the captured image: $e';
} }
} }
} }