feat: Add logger service and improve expense dialog with enhanced receipt management and calculation logic.

This commit is contained in:
Van Leemput Dayron
2025-11-28 12:54:54 +01:00
parent cad9d42128
commit fd710b8cb8
35 changed files with 2148 additions and 1296 deletions

View File

@@ -19,10 +19,10 @@
/// balanceRepository: balanceRepository,
/// expenseRepository: expenseRepository,
/// );
///
///
/// // Load balances for a group
/// balanceBloc.add(LoadGroupBalances('groupId123'));
///
///
/// // Mark a settlement as completed
/// balanceBloc.add(MarkSettlementAsCompleted(
/// groupId: 'groupId123',
@@ -32,6 +32,7 @@
/// ));
/// ```
library;
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../repositories/balance_repository.dart';
import '../../repositories/expense_repository.dart';
@@ -46,10 +47,10 @@ class BalanceBloc extends Bloc<BalanceEvent, BalanceState> {
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
@@ -61,7 +62,12 @@ class BalanceBloc extends Bloc<BalanceEvent, BalanceState> {
BalanceService? balanceService,
ErrorService? errorService,
}) : _balanceRepository = balanceRepository,
_balanceService = balanceService ?? BalanceService(balanceRepository: balanceRepository, expenseRepository: expenseRepository),
_balanceService =
balanceService ??
BalanceService(
balanceRepository: balanceRepository,
expenseRepository: expenseRepository,
),
_errorService = errorService ?? ErrorService(),
super(BalanceInitial()) {
on<LoadGroupBalances>(_onLoadGroupBalance);
@@ -70,11 +76,11 @@ class BalanceBloc extends Bloc<BalanceEvent, BalanceState> {
}
/// 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
@@ -83,18 +89,22 @@ class BalanceBloc extends Bloc<BalanceEvent, BalanceState> {
Emitter<BalanceState> emit,
) async {
try {
emit(BalanceLoading());
// Emit empty state initially to avoid infinite spinner
emit(const GroupBalancesLoaded(balances: [], settlements: []));
// Calculate group user balances
final userBalances = await _balanceRepository.calculateGroupUserBalances(event.groupId);
final userBalances = await _balanceRepository.calculateGroupUserBalances(
event.groupId,
);
// Calculate optimal settlements
final settlements = await _balanceService.calculateOptimalSettlements(event.groupId);
emit(GroupBalancesLoaded(
balances: userBalances,
settlements: 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()));
@@ -102,11 +112,11 @@ class BalanceBloc extends Bloc<BalanceEvent, BalanceState> {
}
/// 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
@@ -119,17 +129,20 @@ class BalanceBloc extends Bloc<BalanceEvent, BalanceState> {
if (state is! GroupBalancesLoaded) {
emit(BalanceLoading());
}
// Calculate group user balances
final userBalances = await _balanceRepository.calculateGroupUserBalances(event.groupId);
final userBalances = await _balanceRepository.calculateGroupUserBalances(
event.groupId,
);
// Calculate optimal settlements
final settlements = await _balanceService.calculateOptimalSettlements(event.groupId);
emit(GroupBalancesLoaded(
balances: userBalances,
settlements: 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()));
@@ -137,11 +150,11 @@ class BalanceBloc extends Bloc<BalanceEvent, BalanceState> {
}
/// 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
@@ -156,9 +169,9 @@ class BalanceBloc extends Bloc<BalanceEvent, BalanceState> {
toUserId: event.toUserId,
amount: event.amount,
);
emit(const BalanceOperationSuccess('Settlement marked as completed'));
// Reload balance after settlement
add(RefreshBalance(event.groupId));
} catch (e) {
@@ -166,4 +179,4 @@ class BalanceBloc extends Bloc<BalanceEvent, BalanceState> {
emit(BalanceError(e.toString()));
}
}
}
}