import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../data/models/scan_item.dart'; import '../../domain/usecases/get_scan_history_usecase.dart'; import 'dependency_injection.dart'; /// State for the scanner functionality class ScannerState { final String? currentBarcode; final List history; final bool isLoading; final String? error; const ScannerState({ this.currentBarcode, this.history = const [], this.isLoading = false, this.error, }); ScannerState copyWith({ String? currentBarcode, List? history, bool? isLoading, String? error, }) { return ScannerState( currentBarcode: currentBarcode ?? this.currentBarcode, history: history ?? this.history, isLoading: isLoading ?? this.isLoading, error: error ?? this.error, ); } @override bool operator ==(Object other) => identical(this, other) || other is ScannerState && runtimeType == other.runtimeType && currentBarcode == other.currentBarcode && history == other.history && isLoading == other.isLoading && error == other.error; @override int get hashCode => currentBarcode.hashCode ^ history.hashCode ^ isLoading.hashCode ^ error.hashCode; } /// Scanner state notifier class ScannerNotifier extends StateNotifier { final GetScanHistoryUseCase _getScanHistoryUseCase; ScannerNotifier(this._getScanHistoryUseCase) : super(const ScannerState()) { _loadHistory(); } /// Load scan history from local storage Future _loadHistory() async { state = state.copyWith(isLoading: true, error: null); final result = await _getScanHistoryUseCase(); result.fold( (failure) => state = state.copyWith( isLoading: false, error: failure.message, ), (history) => state = state.copyWith( isLoading: false, history: history.map((entity) => ScanItem.fromEntity(entity)).toList(), ), ); } /// Update current scanned barcode void updateBarcode(String barcode) { if (barcode.trim().isEmpty) return; state = state.copyWith(currentBarcode: barcode); // Add to history if not already present final existingIndex = state.history.indexWhere((item) => item.barcode == barcode); if (existingIndex == -1) { final newScanItem = ScanItem( barcode: barcode, timestamp: DateTime.now(), ); final updatedHistory = [newScanItem, ...state.history]; state = state.copyWith(history: updatedHistory); } else { // Move existing item to top final existingItem = state.history[existingIndex]; final updatedHistory = List.from(state.history); updatedHistory.removeAt(existingIndex); updatedHistory.insert(0, existingItem.copyWith(timestamp: DateTime.now())); state = state.copyWith(history: updatedHistory); } } /// Clear current barcode void clearBarcode() { state = state.copyWith(currentBarcode: null); } /// Refresh history from storage Future refreshHistory() async { await _loadHistory(); } /// Add or update scan item in history void updateScanItem(ScanItem scanItem) { final existingIndex = state.history.indexWhere( (item) => item.barcode == scanItem.barcode, ); List updatedHistory; if (existingIndex != -1) { // Update existing item updatedHistory = List.from(state.history); updatedHistory[existingIndex] = scanItem; } else { // Add new item at the beginning updatedHistory = [scanItem, ...state.history]; } state = state.copyWith(history: updatedHistory); } /// Clear error message void clearError() { state = state.copyWith(error: null); } } /// Provider for scanner state final scannerProvider = StateNotifierProvider( (ref) => ScannerNotifier( ref.watch(getScanHistoryUseCaseProvider), ), ); /// Provider for current barcode (for easy access) final currentBarcodeProvider = Provider((ref) { return ref.watch(scannerProvider).currentBarcode; }); /// Provider for scan history (for easy access) final scanHistoryProvider = Provider>((ref) { return ref.watch(scannerProvider).history; }); /// Provider for scanner loading state final scannerLoadingProvider = Provider((ref) { return ref.watch(scannerProvider).isLoading; }); /// Provider for scanner error state final scannerErrorProvider = Provider((ref) { return ref.watch(scannerProvider).error; });