Files
minhthu/lib/features/scanner/presentation/providers/scanner_provider.dart
2025-09-16 23:14:35 +07:00

163 lines
4.5 KiB
Dart

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<ScanItem> history;
final bool isLoading;
final String? error;
const ScannerState({
this.currentBarcode,
this.history = const [],
this.isLoading = false,
this.error,
});
ScannerState copyWith({
String? currentBarcode,
List<ScanItem>? 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<ScannerState> {
final GetScanHistoryUseCase _getScanHistoryUseCase;
ScannerNotifier(this._getScanHistoryUseCase) : super(const ScannerState()) {
_loadHistory();
}
/// Load scan history from local storage
Future<void> _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<ScanItem>.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<void> 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<ScanItem> updatedHistory;
if (existingIndex != -1) {
// Update existing item
updatedHistory = List<ScanItem>.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<ScannerNotifier, ScannerState>(
(ref) => ScannerNotifier(
ref.watch(getScanHistoryUseCaseProvider),
),
);
/// Provider for current barcode (for easy access)
final currentBarcodeProvider = Provider<String?>((ref) {
return ref.watch(scannerProvider).currentBarcode;
});
/// Provider for scan history (for easy access)
final scanHistoryProvider = Provider<List<ScanItem>>((ref) {
return ref.watch(scannerProvider).history;
});
/// Provider for scanner loading state
final scannerLoadingProvider = Provider<bool>((ref) {
return ref.watch(scannerProvider).isLoading;
});
/// Provider for scanner error state
final scannerErrorProvider = Provider<String?>((ref) {
return ref.watch(scannerProvider).error;
});