import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../data/models/scan_item.dart'; import '../../domain/usecases/save_scan_usecase.dart'; import 'dependency_injection.dart'; import 'scanner_provider.dart'; /// State for the form functionality class FormDetailState { final String barcode; final String field1; final String field2; final String field3; final String field4; final bool isLoading; final bool isSaveSuccess; final String? error; const FormDetailState({ required this.barcode, this.field1 = '', this.field2 = '', this.field3 = '', this.field4 = '', this.isLoading = false, this.isSaveSuccess = false, this.error, }); FormDetailState copyWith({ String? barcode, String? field1, String? field2, String? field3, String? field4, bool? isLoading, bool? isSaveSuccess, String? error, }) { return FormDetailState( barcode: barcode ?? this.barcode, field1: field1 ?? this.field1, field2: field2 ?? this.field2, field3: field3 ?? this.field3, field4: field4 ?? this.field4, isLoading: isLoading ?? this.isLoading, isSaveSuccess: isSaveSuccess ?? this.isSaveSuccess, error: error, ); } /// Check if all required fields are filled bool get isValid { return barcode.trim().isNotEmpty && field1.trim().isNotEmpty && field2.trim().isNotEmpty && field3.trim().isNotEmpty && field4.trim().isNotEmpty; } /// Get validation error messages List get validationErrors { final errors = []; if (barcode.trim().isEmpty) { errors.add('Barcode is required'); } if (field1.trim().isEmpty) { errors.add('Field 1 is required'); } if (field2.trim().isEmpty) { errors.add('Field 2 is required'); } if (field3.trim().isEmpty) { errors.add('Field 3 is required'); } if (field4.trim().isEmpty) { errors.add('Field 4 is required'); } return errors; } @override bool operator ==(Object other) => identical(this, other) || other is FormDetailState && runtimeType == other.runtimeType && barcode == other.barcode && field1 == other.field1 && field2 == other.field2 && field3 == other.field3 && field4 == other.field4 && isLoading == other.isLoading && isSaveSuccess == other.isSaveSuccess && error == other.error; @override int get hashCode => barcode.hashCode ^ field1.hashCode ^ field2.hashCode ^ field3.hashCode ^ field4.hashCode ^ isLoading.hashCode ^ isSaveSuccess.hashCode ^ error.hashCode; } /// Form state notifier class FormNotifier extends StateNotifier { final SaveScanUseCase _saveScanUseCase; final Ref _ref; FormNotifier( this._saveScanUseCase, this._ref, String barcode, ) : super(FormDetailState(barcode: barcode)); /// Update field 1 void updateField1(String value) { state = state.copyWith(field1: value, error: null); } /// Update field 2 void updateField2(String value) { state = state.copyWith(field2: value, error: null); } /// Update field 3 void updateField3(String value) { state = state.copyWith(field3: value, error: null); } /// Update field 4 void updateField4(String value) { state = state.copyWith(field4: value, error: null); } /// Update barcode void updateBarcode(String value) { state = state.copyWith(barcode: value, error: null); } /// Clear all fields void clearFields() { state = FormDetailState(barcode: state.barcode); } /// Populate form with existing scan data void populateWithScanItem(ScanItem scanItem) { state = state.copyWith( barcode: scanItem.barcode, field1: scanItem.field1, field2: scanItem.field2, field3: scanItem.field3, field4: scanItem.field4, error: null, ); } /// Save form data to server and local storage Future saveData() async { if (!state.isValid) { final errors = state.validationErrors; state = state.copyWith(error: errors.join(', ')); return; } state = state.copyWith(isLoading: true, error: null, isSaveSuccess: false); final params = SaveScanParams( barcode: state.barcode, field1: state.field1, field2: state.field2, field3: state.field3, field4: state.field4, ); final result = await _saveScanUseCase.call(params); result.fold( (failure) => state = state.copyWith( isLoading: false, error: failure.message, isSaveSuccess: false, ), (_) { state = state.copyWith( isLoading: false, isSaveSuccess: true, error: null, ); // Update the scanner history with saved data final savedScanItem = ScanItem( barcode: state.barcode, timestamp: DateTime.now(), field1: state.field1, field2: state.field2, field3: state.field3, field4: state.field4, ); _ref.read(scannerProvider.notifier).updateScanItem(savedScanItem); }, ); } /// Print form data Future printData() async { try { } catch (e) { state = state.copyWith(error: 'Failed to print: ${e.toString()}'); } } /// Clear error message void clearError() { state = state.copyWith(error: null); } /// Reset save success state void resetSaveSuccess() { state = state.copyWith(isSaveSuccess: false); } } /// Provider factory for form state (requires barcode parameter) final formProviderFamily = StateNotifierProvider.family( (ref, barcode) => FormNotifier( ref.watch(saveScanUseCaseProvider), ref, barcode, ), ); /// Convenience provider for accessing form state with a specific barcode /// This should be used with Provider.of or ref.watch(formProvider(barcode)) Provider formProvider(String barcode) { return Provider((ref) { return ref.watch(formProviderFamily(barcode).notifier); }); } /// Convenience provider for accessing form state Provider formStateProvider(String barcode) { return Provider((ref) { return ref.watch(formProviderFamily(barcode)); }); }