fix: new condition flag for idCardType

This commit is contained in:
vergiLgood1 2025-05-26 05:06:35 +07:00
parent dd2bb57e42
commit a7652aadfb
2 changed files with 156 additions and 21 deletions

View File

@ -3,11 +3,13 @@ import 'dart:io';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:logger/logger.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:sigap/src/cores/services/azure_ocr_service.dart'; import 'package:sigap/src/cores/services/azure_ocr_service.dart';
import 'package:sigap/src/features/auth/data/models/face_model.dart'; import 'package:sigap/src/features/auth/data/models/face_model.dart';
import 'package:sigap/src/features/auth/data/models/kta_model.dart'; import 'package:sigap/src/features/auth/data/models/kta_model.dart';
import 'package:sigap/src/features/auth/data/models/ktp_model.dart'; import 'package:sigap/src/features/auth/data/models/ktp_model.dart';
import 'package:sigap/src/features/auth/data/repositories/authentication_repository.dart';
class IdCardVerificationController extends GetxController { class IdCardVerificationController extends GetxController {
// Singleton instance // Singleton instance
@ -16,12 +18,49 @@ class IdCardVerificationController extends GetxController {
// Services // Services
final AzureOCRService _ocrService = AzureOCRService(); final AzureOCRService _ocrService = AzureOCRService();
final bool isOfficer; // Store isOfficer as a reactive variable instead of a final field
final RxBool _isOfficer = RxBool(false);
bool get isOfficer => _isOfficer.value;
// Maximum allowed file size in bytes (4MB) // Maximum allowed file size in bytes (4MB)
final int maxFileSizeBytes = 4 * 1024 * 1024; // 4MB in bytes final int maxFileSizeBytes = 4 * 1024 * 1024; // 4MB in bytes
IdCardVerificationController({required this.isOfficer}); // Constructor that accepts initial isOfficer value but will be updated from user data
IdCardVerificationController({bool isOfficer = false}) {
_isOfficer.value = isOfficer;
Logger().i(
'IdCardVerificationController initialized with isOfficer: $_isOfficer',
);
// Fetch current user role when controller is created
fetchCurrentUserRole();
}
// Method to fetch current user role and update isOfficer flag
Future<void> fetchCurrentUserRole() async {
try {
final metadata = AuthenticationRepository.instance.authUser?.userMetadata;
if (metadata == null) {
Logger().w('User metadata is null, cannot determine role');
return;
}
// Ambil nilai is_officer
final bool isOfficer = metadata['is_officer'] == true;
// Simpan ke variabel observasi jika perlu
_isOfficer.value = isOfficer;
Logger().i('Updated isOfficer flag from user role: $isOfficer');
// Tampilkan jenis kartu identitas yang perlu diverifikasi
final String idCardType = isOfficer ? 'KTA' : 'KTP';
Logger().i('User should verify $idCardType based on role');
} catch (e) {
Logger().e('Error fetching current user role: $e');
// Keep the initial value if there's an error
}
}
// Local storage keys // Local storage keys
static const String _kOcrResultsKey = 'ocr_results'; static const String _kOcrResultsKey = 'ocr_results';
@ -64,26 +103,34 @@ class IdCardVerificationController extends GetxController {
try { try {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
final String jsonData = jsonEncode(results); final String jsonData = jsonEncode(results);
final String idCardType = isOfficer ? 'KTA' : 'KTP';
Logger().i(
'Saving to local storage for ID card type: $idCardType (isOfficer=$isOfficer)',
);
await prefs.setString(_kOcrResultsKey, jsonData); await prefs.setString(_kOcrResultsKey, jsonData);
await prefs.setString(_kIdCardTypeKey, isOfficer ? 'KTA' : 'KTP'); await prefs.setString(_kIdCardTypeKey, idCardType);
// Also save the model // Also save the model
if (isOfficer && ktaModel.value != null) { if (isOfficer && ktaModel.value != null) {
Logger().i('Saving KTA model to storage');
await prefs.setString( await prefs.setString(
_kOcrModelKey, _kOcrModelKey,
jsonEncode(ktaModel.value!.toJson()), jsonEncode(ktaModel.value!.toJson()),
); );
} else if (!isOfficer && ktpModel.value != null) { } else if (!isOfficer && ktpModel.value != null) {
Logger().i('Saving KTP model to storage');
await prefs.setString( await prefs.setString(
_kOcrModelKey, _kOcrModelKey,
jsonEncode(ktpModel.value!.toJson()), jsonEncode(ktpModel.value!.toJson()),
); );
} }
print('OCR results saved to local storage: ${results.length} items'); Logger().i('OCR results saved to local storage: ${results.length} items');
print('ID Card Type saved: ${isOfficer ? 'KTA' : 'KTP'}'); Logger().i('ID Card Type saved: $idCardType');
} catch (e) { } catch (e) {
print('Error saving OCR results to local storage: $e'); Logger().e('Error saving OCR results to local storage: $e');
} }
} }
@ -97,7 +144,7 @@ class IdCardVerificationController extends GetxController {
return decodedData.map((key, value) => MapEntry(key, value.toString())); return decodedData.map((key, value) => MapEntry(key, value.toString()));
} }
} catch (e) { } catch (e) {
print('Error loading OCR results from local storage: $e'); Logger().e('Error loading OCR results from local storage: $e');
} }
return {}; return {};
} }
@ -191,41 +238,72 @@ class IdCardVerificationController extends GetxController {
} }
try { try {
// Make sure we have the latest user role before proceeding
await fetchCurrentUserRole();
isVerifying.value = true; isVerifying.value = true;
final idCardType = isOfficer ? 'KTA' : 'KTP'; final idCardType = isOfficer ? 'KTA' : 'KTP';
Logger().i(
'Starting ID card validation for ${isOfficer ? "KTA (Officer)" : "KTP (Citizen)"} - isOfficer flag: $isOfficer',
);
// Basic validation to check if the image is clear enough for OCR // Basic validation to check if the image is clear enough for OCR
bool isImageValid = false; bool isImageValid = false;
try { try {
// Process the ID card with OCR (still using Azure OCR) Logger().i(
'About to process ID card image with OCR service - isOfficer flag: $isOfficer',
);
// Process the ID card with OCR
final result = await _ocrService.processIdCard( final result = await _ocrService.processIdCard(
idCardImage.value!, idCardImage.value!,
isOfficer, isOfficer,
); );
Logger().i(
'OCR processing completed for $idCardType - Data received: ${result.length} fields',
);
// Store the extraction results // Store the extraction results
extractedInfo.assignAll(result); extractedInfo.assignAll(result);
hasExtractedInfo.value = result.isNotEmpty; hasExtractedInfo.value = result.isNotEmpty;
// Save the OCR results to local storage // Save the OCR results to local storage
if (result.isNotEmpty) { if (result.isNotEmpty) {
print('Saving OCR results to local storage...'); Logger().i('Saving $idCardType OCR results to local storage...');
await _saveOcrResultsToLocalStorage(result); await _saveOcrResultsToLocalStorage(result);
} }
// Debug the extracted data
Logger().i('Card type being validated: $idCardType');
Logger().i('isOfficer flag: $isOfficer');
Logger().i('Extracted data: $result');
// Check if the extracted information is valid using our validation methods // Check if the extracted information is valid using our validation methods
if (isOfficer) { if (isOfficer) {
Logger().i('Validating as KTA (Officer card)');
isImageValid = _ocrService.isKtaValid(result); isImageValid = _ocrService.isKtaValid(result);
} else { Logger().i('KTA validation result: $isImageValid');
isImageValid = _ocrService.isKtpValid(result);
}
// Create model from extracted data // Create KTA model from extracted data
if (isOfficer) {
ktaModel.value = _ocrService.createKtaModel(result); ktaModel.value = _ocrService.createKtaModel(result);
Logger().i('KTA model created: ${ktaModel.value != null}');
// Ensure KTP model is null
ktpModel.value = null;
} else { } else {
Logger().i('Validating as KTP (Citizen card)');
isImageValid = _ocrService.isKtpValid(result);
Logger().i('KTP validation result: $isImageValid');
// Create KTP model from extracted data
ktpModel.value = _ocrService.createKtpModel(result); ktpModel.value = _ocrService.createKtpModel(result);
Logger().i('KTP model created: ${ktpModel.value != null}');
// Ensure KTA model is null
ktaModel.value = null;
} }
if (isImageValid) { if (isImageValid) {
@ -233,10 +311,14 @@ class IdCardVerificationController extends GetxController {
isIdCardValid.value = true; isIdCardValid.value = true;
idCardValidationMessage.value = idCardValidationMessage.value =
'$idCardType image looks valid. Please confirm this is your $idCardType.'; '$idCardType image looks valid. Please confirm this is your $idCardType.';
Logger().i('$idCardType validation successful');
} else { } else {
isIdCardValid.value = false; isIdCardValid.value = false;
idCardValidationMessage.value = idCardValidationMessage.value =
'Unable to verify your $idCardType clearly. Please ensure all text is visible and try again.'; 'Unable to verify your $idCardType clearly. Please ensure all text is visible and try again.';
Logger().i(
'$idCardType validation failed - unable to verify clearly',
);
} }
} on SocketException catch (e) { } on SocketException catch (e) {
isIdCardValid.value = false; isIdCardValid.value = false;
@ -248,10 +330,16 @@ class IdCardVerificationController extends GetxController {
idCardValidationMessage.value = idCardValidationMessage.value =
'Network error occurred. Please try again later.'; 'Network error occurred. Please try again later.';
} }
Logger().e(
'Network error during $idCardType validation: ${e.toString()}',
);
} catch (processingError) { } catch (processingError) {
isIdCardValid.value = false; isIdCardValid.value = false;
idCardValidationMessage.value = idCardValidationMessage.value =
'We\'re having trouble processing your $idCardType. Please try again with a clearer image.'; 'We\'re having trouble processing your $idCardType. Please try again with a clearer image.';
Logger().e(
'Processing error during $idCardType validation: ${processingError.toString()}',
);
} }
} catch (e) { } catch (e) {
isIdCardValid.value = false; isIdCardValid.value = false;
@ -265,14 +353,22 @@ class IdCardVerificationController extends GetxController {
'The verification is taking too long. Please try again later when the connection is better.'; 'The verification is taking too long. Please try again later when the connection is better.';
} else { } else {
// Generic but still user-friendly error message // Generic but still user-friendly error message
final idCardType = isOfficer ? 'KTA' : 'KTP';
idCardValidationMessage.value = idCardValidationMessage.value =
'We encountered an issue during verification. Please try again later.'; 'We encountered an issue during $idCardType verification. Please try again later.';
} }
// Log the actual error for debugging (wouldn't be shown to the user) // Log the actual error for debugging (wouldn't be shown to the user)
print('ID Card validation error: ${e.toString()}'); Logger().e('ID Card validation error: ${e.toString()}');
} finally { } finally {
isVerifying.value = false; isVerifying.value = false;
// Final verification of which model is set
Logger().i(
'Final verification - Card type: ${isOfficer ? "KTA" : "KTP"}',
);
Logger().i('KTP model is null: ${ktpModel.value == null}');
Logger().i('KTA model is null: ${ktaModel.value == null}');
} }
} }
@ -304,7 +400,7 @@ class IdCardVerificationController extends GetxController {
await prefs.remove(_kOcrModelKey); await prefs.remove(_kOcrModelKey);
await prefs.remove(_kIdCardTypeKey); await prefs.remove(_kIdCardTypeKey);
} catch (e) { } catch (e) {
print('Error clearing OCR results from local storage: $e'); Logger().e('Error clearing OCR results from local storage: $e');
} }
} }
@ -315,14 +411,14 @@ class IdCardVerificationController extends GetxController {
// Log storage data for debugging // Log storage data for debugging
SharedPreferences.getInstance().then((prefs) { SharedPreferences.getInstance().then((prefs) {
print('Storage check on confirmation:'); Logger().i('Storage check on confirmation:');
print( Logger().i(
'OCR results: ${prefs.getString(_kOcrResultsKey)?.substring(0, 50)}...', 'OCR results: ${prefs.getString(_kOcrResultsKey)?.substring(0, 50)}...',
); );
print( Logger().i(
'OCR model: ${prefs.getString(_kOcrModelKey)?.substring(0, 50)}...', 'OCR model: ${prefs.getString(_kOcrModelKey)?.substring(0, 50)}...',
); );
print('ID card type: ${prefs.getString(_kIdCardTypeKey)}'); Logger().i('ID card type: ${prefs.getString(_kIdCardTypeKey)}');
}); });
} }
} }
@ -331,4 +427,25 @@ class IdCardVerificationController extends GetxController {
dynamic get verifiedIdCardModel { dynamic get verifiedIdCardModel {
return isOfficer ? ktaModel.value : ktpModel.value; return isOfficer ? ktaModel.value : ktpModel.value;
} }
// Debug helper method - can be called from UI for troubleshooting
void debugControllerState() {
Logger().i('======= ID CARD VERIFICATION CONTROLLER STATE =======');
Logger().i('isOfficer: $isOfficer');
Logger().i('Current ID card type: ${isOfficer ? "KTA" : "KTP"}');
Logger().i('Has ID card image: ${idCardImage.value != null}');
Logger().i('Is ID card valid: ${isIdCardValid.value}');
Logger().i('Has confirmed ID card: ${hasConfirmedIdCard.value}');
Logger().i('Has extracted info: ${hasExtractedInfo.value}');
Logger().i('Extracted info fields: ${extractedInfo.length}');
Logger().i('KTP model null: ${ktpModel.value == null}');
Logger().i('KTA model null: ${ktaModel.value == null}');
Logger().i('================================================');
}
// Method to force update the isOfficer flag (useful for testing or if user role changes)
void updateIsOfficerFlag(bool value) {
Logger().i('Manually updating isOfficer flag from $isOfficer to $value');
_isOfficer.value = value;
}
} }

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:logger/logger.dart';
import 'package:sigap/src/features/auth/data/models/kta_model.dart'; import 'package:sigap/src/features/auth/data/models/kta_model.dart';
import 'package:sigap/src/features/auth/data/models/ktp_model.dart'; import 'package:sigap/src/features/auth/data/models/ktp_model.dart';
import 'package:sigap/src/features/auth/presentasion/controllers/signup/main/registration_form_controller.dart'; import 'package:sigap/src/features/auth/presentasion/controllers/signup/main/registration_form_controller.dart';
@ -25,8 +26,25 @@ class IdCardVerificationStep extends StatelessWidget {
mainController.formKey = formKey; mainController.formKey = formKey;
final isOfficer = mainController.selectedRole.value?.isOfficer ?? false; final isOfficer = mainController.selectedRole.value?.isOfficer ?? false;
// Ensure controller's isOfficer flag matches mainController's selected role
if (controller.isOfficer != isOfficer) {
controller.updateIsOfficerFlag(isOfficer);
Logger().i(
'Updated controller isOfficer flag to match selected role: $isOfficer',
);
}
final String idCardType = isOfficer ? 'KTA' : 'KTP'; final String idCardType = isOfficer ? 'KTA' : 'KTP';
Logger().i(
'Building IdCardVerificationStep with isOfficer: $isOfficer (Card type: $idCardType)',
);
Logger().i('Controller isOfficer flag: ${controller.isOfficer}');
// Call the debug method to print full controller state
controller.debugControllerState();
return Form( return Form(
key: formKey, key: formKey,
child: Column( child: Column(