runable
This commit is contained in:
253
lib/features/scanner/presentation/providers/form_provider.dart
Normal file
253
lib/features/scanner/presentation/providers/form_provider.dart
Normal file
@@ -0,0 +1,253 @@
|
||||
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<String> get validationErrors {
|
||||
final errors = <String>[];
|
||||
|
||||
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<FormDetailState> {
|
||||
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<void> 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<void> 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<FormNotifier, FormDetailState, String>(
|
||||
(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<FormNotifier> formProvider(String barcode) {
|
||||
return Provider<FormNotifier>((ref) {
|
||||
return ref.watch(formProviderFamily(barcode).notifier);
|
||||
});
|
||||
}
|
||||
|
||||
/// Convenience provider for accessing form state
|
||||
Provider<FormDetailState> formStateProvider(String barcode) {
|
||||
return Provider<FormDetailState>((ref) {
|
||||
return ref.watch(formProviderFamily(barcode));
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user