253 lines
6.3 KiB
Dart
253 lines
6.3 KiB
Dart
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));
|
|
});
|
|
} |