- Updated Group, Trip, User, and other model classes to include comprehensive documentation for better understanding and maintainability. - Improved error handling and logging in services, including AuthService, ErrorService, and StorageService. - Added validation and business logic explanations in ExpenseService and TripService. - Refactored method comments to follow a consistent format across the codebase. - Translated error messages and comments from French to English for consistency.
168 lines
6.1 KiB
Dart
168 lines
6.1 KiB
Dart
/// A BLoC (Business Logic Component) that manages balance-related operations for groups.
|
|
///
|
|
/// This bloc handles the calculation and management of user balances within groups,
|
|
/// including optimal settlement calculations and marking settlements as completed.
|
|
///
|
|
/// The bloc processes three main events:
|
|
/// - [LoadGroupBalances]: Loads and calculates all user balances for a specific group
|
|
/// - [RefreshBalance]: Refreshes the balance data while maintaining the current state when possible
|
|
/// - [MarkSettlementAsCompleted]: Records a settlement transaction between users
|
|
///
|
|
/// Dependencies:
|
|
/// - [BalanceRepository]: Repository for balance data operations
|
|
/// - [BalanceService]: Service for balance calculations and settlement logic
|
|
/// - [ErrorService]: Service for error logging and handling
|
|
///
|
|
/// Example usage:
|
|
/// ```dart
|
|
/// final balanceBloc = BalanceBloc(
|
|
/// balanceRepository: balanceRepository,
|
|
/// expenseRepository: expenseRepository,
|
|
/// );
|
|
///
|
|
/// // Load balances for a group
|
|
/// balanceBloc.add(LoadGroupBalances('groupId123'));
|
|
///
|
|
/// // Mark a settlement as completed
|
|
/// balanceBloc.add(MarkSettlementAsCompleted(
|
|
/// groupId: 'groupId123',
|
|
/// fromUserId: 'user1',
|
|
/// toUserId: 'user2',
|
|
/// amount: 50.0,
|
|
/// ));
|
|
/// ```
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import '../../repositories/balance_repository.dart';
|
|
import '../../repositories/expense_repository.dart';
|
|
import '../../services/balance_service.dart';
|
|
import '../../services/error_service.dart';
|
|
import 'balance_event.dart';
|
|
import 'balance_state.dart';
|
|
|
|
class BalanceBloc extends Bloc<BalanceEvent, BalanceState> {
|
|
final BalanceRepository _balanceRepository;
|
|
final BalanceService _balanceService;
|
|
final ErrorService _errorService;
|
|
|
|
/// Constructor for BalanceBloc.
|
|
///
|
|
/// Initializes the bloc with required repositories and optional services.
|
|
/// Sets up event handlers for balance-related operations.
|
|
///
|
|
/// Args:
|
|
/// [balanceRepository]: Repository for balance data operations
|
|
/// [expenseRepository]: Repository for expense data operations
|
|
/// [balanceService]: Optional service for balance calculations (auto-created if null)
|
|
/// [errorService]: Optional service for error handling (auto-created if null)
|
|
BalanceBloc({
|
|
required BalanceRepository balanceRepository,
|
|
required ExpenseRepository expenseRepository,
|
|
BalanceService? balanceService,
|
|
ErrorService? errorService,
|
|
}) : _balanceRepository = balanceRepository,
|
|
_balanceService = balanceService ?? BalanceService(balanceRepository: balanceRepository, expenseRepository: expenseRepository),
|
|
_errorService = errorService ?? ErrorService(),
|
|
super(BalanceInitial()) {
|
|
on<LoadGroupBalances>(_onLoadGroupBalance);
|
|
on<RefreshBalance>(_onRefreshBalance);
|
|
on<MarkSettlementAsCompleted>(_onMarkSettlementAsCompleted);
|
|
}
|
|
|
|
/// Handles [LoadGroupBalances] events.
|
|
///
|
|
/// Loads and calculates user balances for a specific group along with
|
|
/// optimal settlement recommendations. This provides a complete overview
|
|
/// of who owes money to whom and the most efficient payment strategy.
|
|
///
|
|
/// Args:
|
|
/// [event]: The LoadGroupBalances event containing the group ID
|
|
/// [emit]: State emitter function
|
|
Future<void> _onLoadGroupBalance(
|
|
LoadGroupBalances event,
|
|
Emitter<BalanceState> emit,
|
|
) async {
|
|
try {
|
|
emit(BalanceLoading());
|
|
|
|
// Calculate group user balances
|
|
final userBalances = await _balanceRepository.calculateGroupUserBalances(event.groupId);
|
|
|
|
// Calculate optimal settlements
|
|
final settlements = await _balanceService.calculateOptimalSettlements(event.groupId);
|
|
|
|
emit(GroupBalancesLoaded(
|
|
balances: userBalances,
|
|
settlements: settlements,
|
|
));
|
|
} catch (e) {
|
|
_errorService.logError('BalanceBloc', 'Error loading balance: $e');
|
|
emit(BalanceError(e.toString()));
|
|
}
|
|
}
|
|
|
|
/// Handles [RefreshBalance] events.
|
|
///
|
|
/// Refreshes the balance data for a group while trying to maintain the current
|
|
/// state when possible to provide a smoother user experience. Only shows loading
|
|
/// state if there's no existing balance data.
|
|
///
|
|
/// Args:
|
|
/// [event]: The RefreshBalance event containing the group ID
|
|
/// [emit]: State emitter function
|
|
Future<void> _onRefreshBalance(
|
|
RefreshBalance event,
|
|
Emitter<BalanceState> emit,
|
|
) async {
|
|
try {
|
|
// Keep current state during refresh if possible
|
|
if (state is! GroupBalancesLoaded) {
|
|
emit(BalanceLoading());
|
|
}
|
|
|
|
// Calculate group user balances
|
|
final userBalances = await _balanceRepository.calculateGroupUserBalances(event.groupId);
|
|
|
|
// Calculate optimal settlements
|
|
final settlements = await _balanceService.calculateOptimalSettlements(event.groupId);
|
|
|
|
emit(GroupBalancesLoaded(
|
|
balances: userBalances,
|
|
settlements: settlements,
|
|
));
|
|
} catch (e) {
|
|
_errorService.logError('BalanceBloc', 'Error refreshing balance: $e');
|
|
emit(BalanceError(e.toString()));
|
|
}
|
|
}
|
|
|
|
/// Handles [MarkSettlementAsCompleted] events.
|
|
///
|
|
/// Records a settlement transaction between two users, marking that
|
|
/// a debt has been paid. This updates the balance calculations and
|
|
/// automatically refreshes the group balance data to reflect the change.
|
|
///
|
|
/// Args:
|
|
/// [event]: The MarkSettlementAsCompleted event containing settlement details
|
|
/// [emit]: State emitter function
|
|
Future<void> _onMarkSettlementAsCompleted(
|
|
MarkSettlementAsCompleted event,
|
|
Emitter<BalanceState> emit,
|
|
) async {
|
|
try {
|
|
await _balanceService.markSettlementAsCompleted(
|
|
groupId: event.groupId,
|
|
fromUserId: event.fromUserId,
|
|
toUserId: event.toUserId,
|
|
amount: event.amount,
|
|
);
|
|
|
|
emit(const BalanceOperationSuccess('Settlement marked as completed'));
|
|
|
|
// Reload balance after settlement
|
|
add(RefreshBalance(event.groupId));
|
|
} catch (e) {
|
|
_errorService.logError('BalanceBloc', 'Error marking settlement: $e');
|
|
emit(BalanceError(e.toString()));
|
|
}
|
|
}
|
|
} |