import 'dart:collection'; import 'package:flutter/material.dart'; import 'package:pshared/models/payment/operation.dart'; import 'package:pshared/models/payment/status.dart'; import 'package:pshared/provider/payment/payments.dart'; import 'package:pweb/models/state/load_more_state.dart'; import 'package:pweb/utils/report/operations.dart'; import 'package:pweb/utils/report/payment_mapper.dart'; class ReportOperationsController extends ChangeNotifier { PaymentsProvider? _payments; DateTimeRange? _selectedRange; final Set _selectedStatuses = {}; List _operations = const []; List _filtered = const []; List get operations => _operations; List get filteredOperations => _filtered; DateTimeRange? get selectedRange => _selectedRange; Set get selectedStatuses => UnmodifiableSetView(_selectedStatuses); bool get isLoading => _payments?.isLoading ?? false; Exception? get error => _payments?.error; LoadMoreState get loadMoreState { if (_payments?.isLoadingMore ?? false) { return LoadMoreState.loading; } if (_payments?.canLoadMore ?? false) { return LoadMoreState.available; } return LoadMoreState.hidden; } void update(PaymentsProvider provider) { if (!identical(_payments, provider)) { _payments = provider; } _rebuildOperations(); } void setRange(DateTimeRange? range) { if (_isSameRange(_selectedRange, range)) return; _selectedRange = range; _rebuildFiltered(); } void toggleStatus(OperationStatus status) { if (_selectedStatuses.contains(status)) { _selectedStatuses.remove(status); } else { _selectedStatuses.add(status); } _rebuildFiltered(); } void clearFilters() { if (_selectedRange == null && _selectedStatuses.isEmpty) return; _selectedRange = null; _selectedStatuses.clear(); _rebuildFiltered(); } Future refresh() async { await _payments?.refresh(); } Future loadMore() async { await _payments?.loadMore(); } void _rebuildOperations() { final items = _payments?.payments ?? const []; _operations = items.map(mapPaymentToOperation).toList(); _rebuildFiltered(notify: true); } void _rebuildFiltered({bool notify = true}) { _filtered = _applyFilters(_operations); if (notify) { notifyListeners(); } } List _applyFilters(List operations) { if (_selectedRange == null && _selectedStatuses.isEmpty) { return sortOperations(operations); } final filtered = operations.where((op) { final statusMatch = _selectedStatuses.isEmpty || _selectedStatuses.contains(op.status); final dateMatch = _selectedRange == null || isUnknownDate(op.date) || (op.date.isAfter( _selectedRange!.start.subtract(const Duration(seconds: 1)), ) && op.date.isBefore( _selectedRange!.end.add(const Duration(seconds: 1)), )); return statusMatch && dateMatch; }).toList(); return sortOperations(filtered); } bool _isSameRange(DateTimeRange? left, DateTimeRange? right) { if (left == null && right == null) return true; if (left == null || right == null) return false; return left.start.isAtSameMomentAs(right.start) && left.end.isAtSameMomentAs(right.end); } }