import 'dart:async'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../data/models/expense.dart'; import '../../services/count_service.dart'; import '../../repositories/count_repository.dart'; import 'count_event.dart'; import 'count_state.dart'; class CountBloc extends Bloc { final CountService _countService; StreamSubscription>? _expensesSubscription; Map _exchangeRates = {}; CountBloc({CountService? countService}) : _countService = countService ?? CountService( countRepository: CountRepository(), ), super(CountInitial()) { on(_onLoadExpenses); on(_onCreateExpense); on(_onUpdateExpense); on(_onDeleteExpense); on(_onArchiveExpense); on(_onMarkSplitAsPaid); on(_onLoadExchangeRates); on<_ExpensesUpdated>(_onExpensesUpdated); } Future _onLoadExpenses( LoadExpenses event, Emitter emit, ) async { emit(CountLoading()); // Charger les taux de change if (_exchangeRates.isEmpty) { _exchangeRates = await _countService.getExchangeRates(); } await _expensesSubscription?.cancel(); _expensesSubscription = _countService .getExpensesStream(event.groupId, includeArchived: event.includeArchived) .listen( (expenses) { add(_ExpensesUpdated( groupId: event.groupId, expenses: expenses, )); }, onError: (error) { add(_ExpensesError('Erreur lors du chargement des dépenses: $error')); }, ); } void _onExpensesUpdated( _ExpensesUpdated event, Emitter emit, ) { // Récupérer les membres du groupe et calculer les balances final memberIds = {}; final memberNames = {}; for (final expense in event.expenses) { memberIds.add(expense.paidById); memberNames[expense.paidById] = expense.paidByName; for (final split in expense.splits) { memberIds.add(split.userId); memberNames[split.userId] = split.userName; } } final balances = _countService.calculateBalances( event.expenses, memberIds.toList(), memberNames, ); final settlements = _countService.calculateOptimizedSettlements(balances); emit(ExpensesLoaded( groupId: event.groupId, expenses: event.expenses, balances: balances, settlements: settlements, exchangeRates: _exchangeRates, )); } Future _onCreateExpense( CreateExpense event, Emitter emit, ) async { try { await _countService.createExpense( event.expense, receiptImage: event.receiptImage, ); } catch (e) { emit(CountError('Erreur lors de la création de la dépense: $e')); } } Future _onUpdateExpense( UpdateExpense event, Emitter emit, ) async { try { await _countService.updateExpense( event.expense, newReceiptImage: event.newReceiptImage, ); } catch (e) { emit(CountError('Erreur lors de la modification de la dépense: $e')); } } Future _onDeleteExpense( DeleteExpense event, Emitter emit, ) async { try { await _countService.deleteExpense(event.groupId, event.expenseId); } catch (e) { emit(CountError('Erreur lors de la suppression de la dépense: $e')); } } Future _onArchiveExpense( ArchiveExpense event, Emitter emit, ) async { try { await _countService.archiveExpense(event.groupId, event.expenseId); } catch (e) { emit(CountError('Erreur lors de l\'archivage de la dépense: $e')); } } Future _onMarkSplitAsPaid( MarkSplitAsPaid event, Emitter emit, ) async { try { await _countService.markSplitAsPaid( event.groupId, event.expenseId, event.userId, ); } catch (e) { emit(CountError('Erreur lors du marquage du paiement: $e')); } } Future _onLoadExchangeRates( LoadExchangeRates event, Emitter emit, ) async { try { _exchangeRates = await _countService.getExchangeRates(); } catch (e) { emit(CountError('Erreur lors du chargement des taux de change: $e')); } } @override Future close() { _expensesSubscription?.cancel(); return super.close(); } } // Events internes class _ExpensesUpdated extends CountEvent { final String groupId; final List expenses; const _ExpensesUpdated({ required this.groupId, required this.expenses, }); @override List get props => [groupId, expenses]; } class _ExpensesError extends CountEvent { final String error; const _ExpensesError(this.error); @override List get props => [error]; }