feat: integrate ErrorService for consistent error display and standardize bloc error messages.

This commit is contained in:
Van Leemput Dayron
2025-12-02 13:59:40 +01:00
parent 1e70b9e09f
commit 6757cb013a
24 changed files with 927 additions and 608 deletions

View File

@@ -22,6 +22,7 @@
/// accountBloc.close();
/// ```
library;
import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:travel_mate/services/error_service.dart';
@@ -51,17 +52,23 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
try {
emit(AccountLoading());
await _accountsSubscription?.cancel();
_accountsSubscription = _repository.getAccountByUserId(event.userId).listen(
(accounts) {
add(_AccountsUpdated(accounts));
},
onError: (error) {
add(_AccountsUpdated([], error: error.toString()));
},
);
_accountsSubscription = _repository
.getAccountByUserId(event.userId)
.listen(
(accounts) {
add(_AccountsUpdated(accounts));
},
onError: (error) {
add(_AccountsUpdated([], error: error.toString()));
},
);
} catch (e, stackTrace) {
_errorService.logError(e.toString(), stackTrace);
emit(AccountError(e.toString()));
_errorService.logError(
'AccountBloc',
'Error loading accounts: $e',
stackTrace,
);
emit(const AccountError('Impossible de charger les comptes'));
}
}
@@ -89,8 +96,12 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
);
emit(AccountOperationSuccess('Compte créé avec succès. ID: $accountId'));
} catch (e, stackTrace) {
_errorService.logError(e.toString(), stackTrace);
emit(AccountError('Erreur lors de la création du compte: ${e.toString()}'));
_errorService.logError(
'AccountBloc',
'Error creating account: $e',
stackTrace,
);
emit(const AccountError('Impossible de créer le compte'));
}
}
@@ -98,7 +109,7 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
CreateAccountWithMembers event,
Emitter<AccountState> emit,
) async {
try{
try {
emit(AccountLoading());
final accountId = await _repository.createAccountWithMembers(
account: event.account,
@@ -106,8 +117,12 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
);
emit(AccountOperationSuccess('Compte créé avec succès. ID: $accountId'));
} catch (e, stackTrace) {
_errorService.logError(e.toString(), stackTrace);
emit(AccountError('Erreur lors de la création du compte: ${e.toString()}'));
_errorService.logError(
'AccountBloc',
'Error creating account with members: $e',
stackTrace,
);
emit(const AccountError('Impossible de créer le compte'));
}
}
@@ -120,8 +135,12 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
await _repository.addMemberToAccount(event.accountId, event.member);
emit(AccountOperationSuccess('Membre ajouté avec succès'));
} catch (e, stackTrace) {
_errorService.logError(e.toString(), stackTrace);
emit(AccountError('Erreur lors de l\'ajout du membre: ${e.toString()}'));
_errorService.logError(
'AccountBloc',
'Error adding member: $e',
stackTrace,
);
emit(const AccountError('Impossible d\'ajouter le membre'));
}
}
@@ -131,11 +150,18 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
) async {
try {
emit(AccountLoading());
await _repository.removeMemberFromAccount(event.accountId, event.memberId);
await _repository.removeMemberFromAccount(
event.accountId,
event.memberId,
);
emit(AccountOperationSuccess('Membre supprimé avec succès'));
} catch (e, stackTrace) {
_errorService.logError(e.toString(), stackTrace);
emit(AccountError('Erreur lors de la suppression du membre: ${e.toString()}'));
_errorService.logError(
'AccountBloc',
'Error removing member: $e',
stackTrace,
);
emit(const AccountError('Impossible de supprimer le membre'));
}
}

View File

@@ -56,10 +56,11 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
emit(
ActivityLoaded(activities: activities, filteredActivities: activities),
);
} catch (e) {
} catch (e, stackTrace) {
_errorService.logError(
'activity_bloc',
'Erreur chargement activités: $e',
stackTrace,
);
emit(const ActivityError('Impossible de charger les activités'));
}
@@ -83,10 +84,11 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
emit(
ActivityLoaded(activities: activities, filteredActivities: activities),
);
} catch (e) {
} catch (e, stackTrace) {
_errorService.logError(
'activity_bloc',
'Erreur chargement activités: $e',
stackTrace,
);
emit(const ActivityError('Impossible de charger les activités'));
}
@@ -112,8 +114,12 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
// Recharger les activités pour mettre à jour l'UI
add(LoadActivities(event.tripId));
}
} catch (e) {
_errorService.logError('activity_bloc', 'Erreur mise à jour date: $e');
} catch (e, stackTrace) {
_errorService.logError(
'activity_bloc',
'Erreur mise à jour date: $e',
stackTrace,
);
emit(const ActivityError('Impossible de mettre à jour la date'));
}
}
@@ -162,8 +168,12 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
isLoading: false,
),
);
} catch (e) {
_errorService.logError('activity_bloc', 'Erreur recherche activités: $e');
} catch (e, stackTrace) {
_errorService.logError(
'activity_bloc',
'Erreur recherche activités: $e',
stackTrace,
);
emit(const ActivityError('Impossible de rechercher les activités'));
}
}
@@ -211,10 +221,11 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
isLoading: false,
),
);
} catch (e) {
} catch (e, stackTrace) {
_errorService.logError(
'activity_bloc',
'Erreur recherche activités avec coordonnées: $e',
stackTrace,
);
emit(const ActivityError('Impossible de rechercher les activités'));
}
@@ -240,8 +251,12 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
emit(
ActivitySearchResults(searchResults: searchResults, query: event.query),
);
} catch (e) {
_errorService.logError('activity_bloc', 'Erreur recherche textuelle: $e');
} catch (e, stackTrace) {
_errorService.logError(
'activity_bloc',
'Erreur recherche textuelle: $e',
stackTrace,
);
emit(const ActivityError('Impossible de rechercher les activités'));
}
}
@@ -292,8 +307,12 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
} else {
emit(const ActivityError('Impossible d\'ajouter l\'activité'));
}
} catch (e) {
_errorService.logError('activity_bloc', 'Erreur ajout activité: $e');
} catch (e, stackTrace) {
_errorService.logError(
'activity_bloc',
'Erreur ajout activité: $e',
stackTrace,
);
emit(const ActivityError('Impossible d\'ajouter l\'activité'));
}
}
@@ -350,8 +369,12 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
} else {
emit(const ActivityError('Impossible d\'ajouter l\'activité'));
}
} catch (e) {
_errorService.logError('activity_bloc', 'Erreur ajout activité: $e');
} catch (e, stackTrace) {
_errorService.logError(
'activity_bloc',
'Erreur ajout activité: $e',
stackTrace,
);
emit(const ActivityError('Impossible d\'ajouter l\'activité'));
}
}
@@ -418,8 +441,12 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
} else {
emit(const ActivityError('Impossible d\'ajouter les activités'));
}
} catch (e) {
_errorService.logError('activity_bloc', 'Erreur ajout en lot: $e');
} catch (e, stackTrace) {
_errorService.logError(
'activity_bloc',
'Erreur ajout en lot: $e',
stackTrace,
);
emit(const ActivityError('Impossible d\'ajouter les activités'));
}
}
@@ -479,8 +506,8 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
} else {
emit(const ActivityError('Impossible d\'enregistrer le vote'));
}
} catch (e) {
_errorService.logError('activity_bloc', 'Erreur vote: $e');
} catch (e, stackTrace) {
_errorService.logError('activity_bloc', 'Erreur vote: $e', stackTrace);
emit(const ActivityError('Impossible d\'enregistrer le vote'));
}
}
@@ -511,8 +538,12 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
} else {
emit(const ActivityError('Impossible de supprimer l\'activité'));
}
} catch (e) {
_errorService.logError('activity_bloc', 'Erreur suppression: $e');
} catch (e, stackTrace) {
_errorService.logError(
'activity_bloc',
'Erreur suppression: $e',
stackTrace,
);
emit(const ActivityError('Impossible de supprimer l\'activité'));
}
}
@@ -593,8 +624,12 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
} else {
emit(const ActivityError('Impossible de mettre à jour l\'activité'));
}
} catch (e) {
_errorService.logError('activity_bloc', 'Erreur mise à jour: $e');
} catch (e, stackTrace) {
_errorService.logError(
'activity_bloc',
'Erreur mise à jour: $e',
stackTrace,
);
emit(const ActivityError('Impossible de mettre à jour l\'activité'));
}
}
@@ -614,8 +649,8 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
vote: 1,
),
);
} catch (e) {
_errorService.logError('activity_bloc', 'Erreur favori: $e');
} catch (e, stackTrace) {
_errorService.logError('activity_bloc', 'Erreur favori: $e', stackTrace);
emit(const ActivityError('Impossible de modifier les favoris'));
}
}

View File

@@ -77,7 +77,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
emit(AuthUnauthenticated());
}
} catch (e) {
emit(AuthError(message: e.toString()));
emit(AuthError(message: e.toString().replaceAll('Exception: ', '')));
}
}
@@ -103,7 +103,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
emit(const AuthError(message: 'Invalid email or password'));
}
} catch (e) {
emit(AuthError(message: e.toString()));
emit(AuthError(message: e.toString().replaceAll('Exception: ', '')));
}
}
@@ -132,7 +132,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
emit(const AuthError(message: 'Failed to create account'));
}
} catch (e) {
emit(AuthError(message: e.toString()));
emit(AuthError(message: e.toString().replaceAll('Exception: ', '')));
}
}
@@ -160,7 +160,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
);
}
} catch (e) {
emit(AuthError(message: e.toString()));
emit(AuthError(message: e.toString().replaceAll('Exception: ', '')));
}
}
@@ -183,7 +183,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
emit(const AuthError(message: 'Failed to create account with Google'));
}
} catch (e) {
emit(AuthError(message: e.toString()));
emit(AuthError(message: e.toString().replaceAll('Exception: ', '')));
}
}
@@ -206,7 +206,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
emit(const AuthError(message: 'Failed to create account with Apple'));
}
} catch (e) {
emit(AuthError(message: e.toString()));
emit(AuthError(message: e.toString().replaceAll('Exception: ', '')));
}
}
@@ -234,7 +234,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
);
}
} catch (e) {
emit(AuthError(message: e.toString()));
emit(AuthError(message: e.toString().replaceAll('Exception: ', '')));
}
}
@@ -261,7 +261,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
await _authRepository.resetPassword(event.email);
emit(AuthPasswordResetSent(email: event.email));
} catch (e) {
emit(AuthError(message: e.toString()));
emit(AuthError(message: e.toString().replaceAll('Exception: ', '')));
}
}
}

View File

@@ -105,9 +105,13 @@ class BalanceBloc extends Bloc<BalanceEvent, BalanceState> {
emit(
GroupBalancesLoaded(balances: userBalances, settlements: settlements),
);
} catch (e) {
_errorService.logError('BalanceBloc', 'Error loading balance: $e');
emit(BalanceError(e.toString()));
} catch (e, stackTrace) {
_errorService.logError(
'BalanceBloc',
'Error loading balance: $e',
stackTrace,
);
emit(const BalanceError('Impossible de charger la balance'));
}
}
@@ -143,9 +147,13 @@ class BalanceBloc extends Bloc<BalanceEvent, BalanceState> {
emit(
GroupBalancesLoaded(balances: userBalances, settlements: settlements),
);
} catch (e) {
_errorService.logError('BalanceBloc', 'Error refreshing balance: $e');
emit(BalanceError(e.toString()));
} catch (e, stackTrace) {
_errorService.logError(
'BalanceBloc',
'Error refreshing balance: $e',
stackTrace,
);
emit(const BalanceError('Impossible de rafraîchir la balance'));
}
}
@@ -174,9 +182,15 @@ class BalanceBloc extends Bloc<BalanceEvent, BalanceState> {
// Reload balance after settlement
add(RefreshBalance(event.groupId));
} catch (e) {
_errorService.logError('BalanceBloc', 'Error marking settlement: $e');
emit(BalanceError(e.toString()));
} catch (e, stackTrace) {
_errorService.logError(
'BalanceBloc',
'Error marking settlement: $e',
stackTrace,
);
emit(
const BalanceError('Impossible de marquer le règlement comme terminé'),
);
}
}
}

View File

@@ -72,7 +72,7 @@ class ExpenseBloc extends Bloc<ExpenseEvent, ExpenseState> {
);
} catch (e) {
_errorService.logError('ExpenseBloc', 'Error loading expenses: $e');
emit(ExpenseError(e.toString()));
emit(const ExpenseError('Impossible de charger les dépenses'));
}
}
@@ -116,7 +116,7 @@ class ExpenseBloc extends Bloc<ExpenseEvent, ExpenseState> {
emit(const ExpenseOperationSuccess('Expense created successfully'));
} catch (e) {
_errorService.logError('ExpenseBloc', 'Error creating expense: $e');
emit(ExpenseError(e.toString()));
emit(const ExpenseError('Impossible de créer la dépense'));
}
}
@@ -141,7 +141,7 @@ class ExpenseBloc extends Bloc<ExpenseEvent, ExpenseState> {
emit(const ExpenseOperationSuccess('Expense updated successfully'));
} catch (e) {
_errorService.logError('ExpenseBloc', 'Error updating expense: $e');
emit(ExpenseError(e.toString()));
emit(const ExpenseError('Impossible de mettre à jour la dépense'));
}
}
@@ -162,7 +162,7 @@ class ExpenseBloc extends Bloc<ExpenseEvent, ExpenseState> {
emit(const ExpenseOperationSuccess('Expense deleted successfully'));
} catch (e) {
_errorService.logError('ExpenseBloc', 'Error deleting expense: $e');
emit(ExpenseError(e.toString()));
emit(const ExpenseError('Impossible de supprimer la dépense'));
}
}
@@ -184,7 +184,7 @@ class ExpenseBloc extends Bloc<ExpenseEvent, ExpenseState> {
emit(const ExpenseOperationSuccess('Payment marked as completed'));
} catch (e) {
_errorService.logError('ExpenseBloc', 'Error marking split as paid: $e');
emit(ExpenseError(e.toString()));
emit(const ExpenseError('Impossible de marquer comme payé'));
}
}
@@ -206,7 +206,7 @@ class ExpenseBloc extends Bloc<ExpenseEvent, ExpenseState> {
emit(const ExpenseOperationSuccess('Expense archived successfully'));
} catch (e) {
_errorService.logError('ExpenseBloc', 'Error archiving expense: $e');
emit(ExpenseError(e.toString()));
emit(const ExpenseError('Impossible d\'archiver la dépense'));
}
}

View File

@@ -32,6 +32,7 @@
/// ));
/// ```
library;
import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:travel_mate/services/error_service.dart';
@@ -85,17 +86,23 @@ class GroupBloc extends Bloc<GroupEvent, GroupState> {
try {
emit(GroupLoading());
await _groupsSubscription?.cancel();
_groupsSubscription = _repository.getGroupsByUserId(event.userId).listen(
(groups) {
add(_GroupsUpdated(groups));
},
onError: (error) {
add(_GroupsUpdated([], error: error.toString()));
},
);
_groupsSubscription = _repository
.getGroupsByUserId(event.userId)
.listen(
(groups) {
add(_GroupsUpdated(groups));
},
onError: (error) {
add(_GroupsUpdated([], error: error.toString()));
},
);
} catch (e, stackTrace) {
_errorService.logError(e.toString(), stackTrace);
emit(GroupError(e.toString()));
_errorService.logError(
'GroupBloc',
'Error loading groups: $e',
stackTrace,
);
emit(const GroupError('Impossible de charger les groupes'));
}
}
@@ -139,8 +146,13 @@ class GroupBloc extends Bloc<GroupEvent, GroupState> {
} else {
emit(const GroupsLoaded([]));
}
} catch (e) {
emit(GroupError(e.toString()));
} catch (e, stackTrace) {
_errorService.logError(
'GroupBloc',
'Error loading group by trip: $e',
stackTrace,
);
emit(const GroupError('Impossible de charger le groupe du voyage'));
}
}
@@ -164,8 +176,13 @@ class GroupBloc extends Bloc<GroupEvent, GroupState> {
);
emit(GroupCreated(groupId: groupId));
emit(const GroupOperationSuccess('Group created successfully'));
} catch (e) {
emit(GroupError('Error during creation: $e'));
} catch (e, stackTrace) {
_errorService.logError(
'GroupBloc',
'Error creating group: $e',
stackTrace,
);
emit(const GroupError('Impossible de créer le groupe'));
}
}
@@ -189,8 +206,13 @@ class GroupBloc extends Bloc<GroupEvent, GroupState> {
members: event.members,
);
emit(GroupCreated(groupId: groupId));
} catch (e) {
emit(GroupError('Error during creation: $e'));
} catch (e, stackTrace) {
_errorService.logError(
'GroupBloc',
'Error creating group with members: $e',
stackTrace,
);
emit(const GroupError('Impossible de créer le groupe'));
}
}
@@ -209,8 +231,13 @@ class GroupBloc extends Bloc<GroupEvent, GroupState> {
try {
await _repository.addMember(event.groupId, event.member);
emit(const GroupOperationSuccess('Member added'));
} catch (e) {
emit(GroupError('Error during addition: $e'));
} catch (e, stackTrace) {
_errorService.logError(
'GroupBloc',
'Error adding member: $e',
stackTrace,
);
emit(const GroupError('Impossible d\'ajouter le membre'));
}
}
@@ -229,8 +256,13 @@ class GroupBloc extends Bloc<GroupEvent, GroupState> {
try {
await _repository.removeMember(event.groupId, event.userId);
emit(const GroupOperationSuccess('Member removed'));
} catch (e) {
emit(GroupError('Error during removal: $e'));
} catch (e, stackTrace) {
_errorService.logError(
'GroupBloc',
'Error removing member: $e',
stackTrace,
);
emit(const GroupError('Impossible de supprimer le membre'));
}
}
@@ -249,8 +281,13 @@ class GroupBloc extends Bloc<GroupEvent, GroupState> {
try {
await _repository.updateGroup(event.groupId, event.group);
emit(const GroupOperationSuccess('Group updated'));
} catch (e) {
emit(GroupError('Error during update: $e'));
} catch (e, stackTrace) {
_errorService.logError(
'GroupBloc',
'Error updating group: $e',
stackTrace,
);
emit(const GroupError('Impossible de mettre à jour le groupe'));
}
}
@@ -269,8 +306,13 @@ class GroupBloc extends Bloc<GroupEvent, GroupState> {
try {
await _repository.deleteGroup(event.tripId);
emit(const GroupOperationSuccess('Group deleted'));
} catch (e) {
emit(GroupError('Error during deletion: $e'));
} catch (e, stackTrace) {
_errorService.logError(
'GroupBloc',
'Error deleting group: $e',
stackTrace,
);
emit(const GroupError('Impossible de supprimer le groupe'));
}
}

View File

@@ -40,6 +40,7 @@
/// ));
/// ```
library;
import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../models/message.dart';
@@ -65,10 +66,10 @@ class MessageBloc extends Bloc<MessageEvent, MessageState> {
/// Args:
/// [messageService]: Optional service for message operations (auto-created if null)
MessageBloc({MessageService? messageService})
: _messageService = messageService ?? MessageService(
messageRepository: MessageRepository(),
),
super(MessageInitial()) {
: _messageService =
messageService ??
MessageService(messageRepository: MessageRepository()),
super(MessageInitial()) {
on<LoadMessages>(_onLoadMessages);
on<SendMessage>(_onSendMessage);
on<DeleteMessage>(_onDeleteMessage);
@@ -101,7 +102,7 @@ class MessageBloc extends Bloc<MessageEvent, MessageState> {
add(_MessagesUpdated(messages: messages, groupId: event.groupId));
},
onError: (error) {
add(_MessagesError('Error loading messages: $error'));
add(const _MessagesError('Impossible de charger les messages'));
},
);
}
@@ -114,10 +115,7 @@ class MessageBloc extends Bloc<MessageEvent, MessageState> {
/// Args:
/// [event]: The _MessagesUpdated event containing messages and group ID
/// [emit]: State emitter function
void _onMessagesUpdated(
_MessagesUpdated event,
Emitter<MessageState> emit,
) {
void _onMessagesUpdated(_MessagesUpdated event, Emitter<MessageState> emit) {
emit(MessagesLoaded(messages: event.messages, groupId: event.groupId));
}
@@ -142,7 +140,7 @@ class MessageBloc extends Bloc<MessageEvent, MessageState> {
senderName: event.senderName,
);
} catch (e) {
emit(MessageError('Error sending message: $e'));
emit(const MessageError('Impossible d\'envoyer le message'));
}
}
@@ -166,7 +164,7 @@ class MessageBloc extends Bloc<MessageEvent, MessageState> {
messageId: event.messageId,
);
} catch (e) {
emit(MessageError('Error deleting message: $e'));
emit(const MessageError('Impossible de supprimer le message'));
}
}
@@ -191,7 +189,7 @@ class MessageBloc extends Bloc<MessageEvent, MessageState> {
newText: event.newText,
);
} catch (e) {
emit(MessageError('Error updating message: $e'));
emit(const MessageError('Impossible de modifier le message'));
}
}
@@ -217,7 +215,7 @@ class MessageBloc extends Bloc<MessageEvent, MessageState> {
reaction: event.reaction,
);
} catch (e) {
emit(MessageError('Error adding reaction: $e'));
emit(const MessageError('Impossible d\'ajouter la réaction'));
}
}
@@ -242,7 +240,7 @@ class MessageBloc extends Bloc<MessageEvent, MessageState> {
userId: event.userId,
);
} catch (e) {
emit(MessageError('Error removing reaction: $e'));
emit(const MessageError('Impossible de supprimer la réaction'));
}
}
@@ -273,10 +271,7 @@ class _MessagesUpdated extends MessageEvent {
/// Args:
/// [messages]: List of messages from the stream update
/// [groupId]: ID of the group these messages belong to
const _MessagesUpdated({
required this.messages,
required this.groupId,
});
const _MessagesUpdated({required this.messages, required this.groupId});
@override
List<Object?> get props => [messages, groupId];

View File

@@ -36,17 +36,20 @@
/// tripBloc.add(TripDeleteRequested(tripId: 'tripId456'));
/// ```
library;
import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:travel_mate/models/trip.dart';
import 'trip_event.dart';
import 'trip_state.dart';
import '../../repositories/trip_repository.dart';
import '../../services/error_service.dart';
/// BLoC that manages trip-related operations and state.
class TripBloc extends Bloc<TripEvent, TripState> {
/// Repository for trip data operations
final TripRepository _repository;
final _errorService = ErrorService();
/// Subscription to trip stream for real-time updates
StreamSubscription? _tripsSubscription;
@@ -88,14 +91,21 @@ class TripBloc extends Bloc<TripEvent, TripState> {
_currentUserId = event.userId;
await _tripsSubscription?.cancel();
_tripsSubscription = _repository.getTripsByUserId(event.userId).listen(
(trips) {
add(_TripsUpdated(trips));
},
onError: (error) {
emit(TripError(error.toString()));
},
);
_tripsSubscription = _repository
.getTripsByUserId(event.userId)
.listen(
(trips) {
add(_TripsUpdated(trips));
},
onError: (error, stackTrace) {
_errorService.logError(
'TripBloc',
'Error loading trips: $error',
stackTrace,
);
emit(const TripError('Impossible de charger les voyages'));
},
);
}
/// Handles [_TripsUpdated] events.
@@ -106,10 +116,7 @@ class TripBloc extends Bloc<TripEvent, TripState> {
/// Args:
/// [event]: The _TripsUpdated event containing the updated trip list
/// [emit]: State emitter function
void _onTripsUpdated(
_TripsUpdated event,
Emitter<TripState> emit,
) {
void _onTripsUpdated(_TripsUpdated event, Emitter<TripState> emit) {
emit(TripLoaded(event.trips));
}
@@ -137,9 +144,9 @@ class TripBloc extends Bloc<TripEvent, TripState> {
if (_currentUserId != null) {
add(LoadTripsByUserId(userId: _currentUserId!));
}
} catch (e) {
emit(TripError('Error during creation: $e'));
} catch (e, stackTrace) {
_errorService.logError('TripBloc', 'Error creating trip: $e', stackTrace);
emit(const TripError('Impossible de créer le voyage'));
}
}
@@ -163,9 +170,9 @@ class TripBloc extends Bloc<TripEvent, TripState> {
if (_currentUserId != null) {
add(LoadTripsByUserId(userId: _currentUserId!));
}
} catch (e) {
emit(TripError('Error during update: $e'));
} catch (e, stackTrace) {
_errorService.logError('TripBloc', 'Error updating trip: $e', stackTrace);
emit(const TripError('Impossible de mettre à jour le voyage'));
}
}
@@ -191,9 +198,9 @@ class TripBloc extends Bloc<TripEvent, TripState> {
if (_currentUserId != null) {
add(LoadTripsByUserId(userId: _currentUserId!));
}
} catch (e) {
emit(TripError('Error during deletion: $e'));
} catch (e, stackTrace) {
_errorService.logError('TripBloc', 'Error deleting trip: $e', stackTrace);
emit(const TripError('Impossible de supprimer le voyage'));
}
}
@@ -206,10 +213,7 @@ class TripBloc extends Bloc<TripEvent, TripState> {
/// Args:
/// [event]: The ResetTrips event
/// [emit]: State emitter function
Future<void> _onResetTrips(
ResetTrips event,
Emitter<TripState> emit,
) async {
Future<void> _onResetTrips(ResetTrips event, Emitter<TripState> emit) async {
await _tripsSubscription?.cancel();
_currentUserId = null;
emit(TripInitial());

View File

@@ -2,6 +2,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:travel_mate/services/notification_service.dart';
import 'package:travel_mate/services/logger_service.dart';
import 'package:travel_mate/services/error_service.dart';
import 'user_event.dart' as event;
import 'user_state.dart' as state;
@@ -17,6 +19,8 @@ class UserBloc extends Bloc<event.UserEvent, state.UserState> {
/// Firestore instance for user data operations.
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final _errorService = ErrorService();
/// Creates a new [UserBloc] with initial state.
///
/// Registers event handlers for all user-related events.
@@ -50,7 +54,7 @@ class UserBloc extends Bloc<event.UserEvent, state.UserState> {
final notificationService = NotificationService();
await notificationService.initialize();
final fcmToken = await notificationService.getFCMToken();
print('DEBUG: UserBloc - FCM Token retrieved: $fcmToken');
LoggerService.info('UserBloc - FCM Token retrieved: $fcmToken');
// Fetch user data from Firestore
final userDoc = await _firestore
@@ -81,21 +85,22 @@ class UserBloc extends Bloc<event.UserEvent, state.UserState> {
// Update FCM token if it changed
if (fcmToken != null && user.fcmToken != fcmToken) {
print('DEBUG: UserBloc - Updating FCM token in Firestore');
LoggerService.info('UserBloc - Updating FCM token in Firestore');
await _firestore.collection('users').doc(currentUser.uid).update({
'fcmToken': fcmToken,
});
print('DEBUG: UserBloc - FCM token updated');
LoggerService.info('UserBloc - FCM token updated');
} else {
print(
'DEBUG: UserBloc - FCM token not updated. Local: $fcmToken, Firestore: ${user.fcmToken}',
LoggerService.info(
'UserBloc - FCM token not updated. Local: $fcmToken, Firestore: ${user.fcmToken}',
);
}
emit(state.UserLoaded(user));
}
} catch (e) {
emit(state.UserError('Error loading user: $e'));
} catch (e, stackTrace) {
_errorService.logError('UserBloc', 'Error loading user: $e', stackTrace);
emit(state.UserError('Impossible de charger l\'utilisateur'));
}
}
@@ -124,8 +129,9 @@ class UserBloc extends Bloc<event.UserEvent, state.UserState> {
} else {
emit(state.UserError('User not found'));
}
} catch (e) {
emit(state.UserError('Error loading user: $e'));
} catch (e, stackTrace) {
_errorService.logError('UserBloc', 'Error loading user: $e', stackTrace);
emit(state.UserError('Impossible de charger l\'utilisateur'));
}
}
@@ -158,8 +164,13 @@ class UserBloc extends Bloc<event.UserEvent, state.UserState> {
});
emit(state.UserLoaded(updatedUser));
} catch (e) {
emit(state.UserError('Error updating user: $e'));
} catch (e, stackTrace) {
_errorService.logError(
'UserBloc',
'Error updating user: $e',
stackTrace,
);
emit(state.UserError('Impossible de mettre à jour l\'utilisateur'));
}
}
}

View File

@@ -19,7 +19,9 @@
/// The component automatically loads account data when initialized and
/// provides a clean interface for managing group-based expenses.
library;
import 'package:flutter/material.dart';
import '../../services/error_service.dart';
import 'package:travel_mate/blocs/user/user_bloc.dart';
import '../../models/account.dart';
import '../../blocs/account/account_bloc.dart';
@@ -70,10 +72,7 @@ class _AccountContentState extends State<AccountContent> {
throw Exception('User not connected');
}
} catch (e) {
ErrorContent(
message: 'Error loading accounts: $e',
onRetry: () {},
);
ErrorContent(message: 'Error loading accounts: $e', onRetry: () {});
}
}
@@ -94,30 +93,18 @@ class _AccountContentState extends State<AccountContent> {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => GroupExpensesPage(
account: account,
group: group,
),
builder: (context) =>
GroupExpensesPage(account: account, group: group),
),
);
} else {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Group not found for this account'),
backgroundColor: Colors.red,
),
);
ErrorService().showError(message: 'Group not found for this account');
}
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error loading group: $e'),
backgroundColor: Colors.red,
),
);
ErrorService().showError(message: 'Error loading group: $e');
}
}
}
@@ -139,9 +126,12 @@ class _AccountContentState extends State<AccountContent> {
listener: (context, accountState) {
if (accountState is AccountError) {
ErrorContent(
message: 'Erreur de chargement des comptes : ${accountState.message}',
message:
'Erreur de chargement des comptes : ${accountState.message}',
onRetry: () {
context.read<AccountBloc>().add(LoadAccountsByUserId(user.id));
context.read<AccountBloc>().add(
LoadAccountsByUserId(user.id),
);
},
);
}
@@ -156,10 +146,7 @@ class _AccountContentState extends State<AccountContent> {
loadingWidget: const Scaffold(
body: Center(child: CircularProgressIndicator()),
),
errorWidget: ErrorContent(
message: 'User error',
onRetry: () {},
),
errorWidget: ErrorContent(message: 'User error', onRetry: () {}),
noUserWidget: const Scaffold(
body: Center(child: Text('Utilisateur non connecté')),
),
@@ -241,7 +228,11 @@ class _AccountContentState extends State<AccountContent> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.account_balance_wallet, size: 80, color: Colors.grey),
const Icon(
Icons.account_balance_wallet,
size: 80,
color: Colors.grey,
),
const SizedBox(height: 16),
const Text(
'No accounts found',
@@ -280,14 +271,14 @@ class _AccountContentState extends State<AccountContent> {
child: ListView(
padding: const EdgeInsets.all(16),
children: [
...accounts.map((account) {
...accounts.map((account) {
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: _buildSimpleAccountCard(account),
);
})
}),
],
)
),
);
}
@@ -309,9 +300,10 @@ class _AccountContentState extends State<AccountContent> {
final colors = [Colors.blue, Colors.purple, Colors.green, Colors.orange];
final color = colors[account.name.hashCode.abs() % colors.length];
String memberInfo = '${account.members.length} member${account.members.length > 1 ? 's' : ''}';
String memberInfo =
'${account.members.length} member${account.members.length > 1 ? 's' : ''}';
if(account.members.isNotEmpty){
if (account.members.isNotEmpty) {
final names = account.members
.take(2)
.map((m) => m.pseudo.isNotEmpty ? m.pseudo : m.firstName)
@@ -324,7 +316,10 @@ class _AccountContentState extends State<AccountContent> {
child: ListTile(
leading: CircleAvatar(
backgroundColor: color,
child: const Icon(Icons.account_balance_wallet, color: Colors.white),
child: const Icon(
Icons.account_balance_wallet,
color: Colors.white,
),
),
title: Text(
account.name,
@@ -332,7 +327,8 @@ class _AccountContentState extends State<AccountContent> {
),
subtitle: Text(memberInfo),
trailing: const Icon(Icons.chevron_right),
onTap: () => _navigateToGroupExpenses(account), // Navigate to group expenses
onTap: () =>
_navigateToGroupExpenses(account), // Navigate to group expenses
),
);
} catch (e) {
@@ -341,7 +337,7 @@ class _AccountContentState extends State<AccountContent> {
child: const ListTile(
leading: Icon(Icons.error, color: Colors.red),
title: Text('Display error'),
)
),
);
}
}

View File

@@ -10,6 +10,7 @@ import '../../services/activity_cache_service.dart';
import '../loading/laoding_content.dart';
import '../../blocs/user/user_bloc.dart';
import '../../blocs/user/user_state.dart';
import '../../services/error_service.dart';
class ActivitiesPage extends StatefulWidget {
final Trip trip;
@@ -120,22 +121,15 @@ class _ActivitiesPageState extends State<ActivitiesPage>
return BlocListener<ActivityBloc, ActivityState>(
listener: (context, state) {
if (state is ActivityError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.message),
backgroundColor: Colors.red,
action: SnackBarAction(
label: 'Réessayer',
textColor: Colors.white,
onPressed: () {
if (_tabController.index == 2) {
_searchGoogleActivities();
} else {
_loadActivities();
}
},
),
),
ErrorService().showError(
message: state.message,
onRetry: () {
if (_tabController.index == 2) {
_searchGoogleActivities();
} else {
_loadActivities();
}
},
);
}
@@ -152,20 +146,14 @@ class _ActivitiesPageState extends State<ActivitiesPage>
});
// Afficher un feedback de succès
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('${state.activity.name} ajoutée au voyage !'),
duration: const Duration(seconds: 2),
backgroundColor: Colors.green,
action: SnackBarAction(
label: 'Voir',
textColor: Colors.white,
onPressed: () {
// Revenir à l'onglet des activités du voyage
_tabController.animateTo(0);
},
),
),
// Afficher un feedback de succès
ErrorService().showSnackbar(
message: '${state.activity.name} ajoutée au voyage !',
isError: false,
onRetry: () {
// Revenir à l'onglet des activités du voyage
_tabController.animateTo(0);
},
);
});
}
@@ -217,21 +205,13 @@ class _ActivitiesPageState extends State<ActivitiesPage>
_tripActivities.add(state.newlyAddedActivity!);
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
ErrorService().showSnackbar(
message:
'${state.newlyAddedActivity!.name} ajoutée au voyage !',
),
duration: const Duration(seconds: 2),
backgroundColor: Colors.green,
action: SnackBarAction(
label: 'Voir',
textColor: Colors.white,
onPressed: () {
_tabController.animateTo(0);
},
),
),
isError: false,
onRetry: () {
_tabController.animateTo(0);
},
);
});
}
@@ -1026,12 +1006,9 @@ class _ActivitiesPageState extends State<ActivitiesPage>
// Si l'activité a été trouvée et que l'utilisateur a déjà voté
if (currentActivity.id.isNotEmpty && currentActivity.hasUserVoted(userId)) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Vous avez déjà voté pour cette activité'),
backgroundColor: Colors.orange,
duration: Duration(seconds: 2),
),
ErrorService().showSnackbar(
message: 'Vous avez déjà voté pour cette activité',
isError: true,
);
return;
}
@@ -1044,13 +1021,7 @@ class _ActivitiesPageState extends State<ActivitiesPage>
final message = vote == 1
? 'Vote positif ajouté !'
: 'Vote négatif ajouté !';
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
duration: const Duration(seconds: 1),
backgroundColor: vote == 1 ? Colors.green : Colors.orange,
),
);
ErrorService().showSnackbar(message: message, isError: false);
}
void _addGoogleActivityToTrip(Activity activity) {

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:travel_mate/components/error/error_content.dart';
import '../../services/error_service.dart';
import 'package:travel_mate/components/group/chat_group_content.dart';
import 'package:travel_mate/components/widgets/user_state_widget.dart';
import '../../blocs/user/user_bloc.dart';
@@ -50,19 +50,12 @@ class _GroupContentState extends State<GroupContent> {
return BlocConsumer<GroupBloc, GroupState>(
listener: (context, groupState) {
if (groupState is GroupOperationSuccess) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(groupState.message),
backgroundColor: Colors.green,
),
ErrorService().showSnackbar(
message: groupState.message,
isError: false,
);
} else if (groupState is GroupError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(groupState.message),
backgroundColor: Colors.red,
),
);
ErrorService().showError(message: groupState.message);
}
},
builder: (context, groupState) {
@@ -209,8 +202,7 @@ class _GroupContentState extends State<GroupContent> {
if (mounted) {
if (retry) {
if (userId == '') {
showErrorDialog(
context,
ErrorService().showError(
title: 'Erreur utilisateur',
message: 'Utilisateur non connecté. Veuillez vous reconnecter.',
icon: Icons.error,
@@ -220,8 +212,7 @@ class _GroupContentState extends State<GroupContent> {
},
);
} else {
showErrorDialog(
context,
ErrorService().showError(
title: 'Erreur de chargement',
message: error,
icon: Icons.cloud_off,
@@ -232,8 +223,7 @@ class _GroupContentState extends State<GroupContent> {
);
}
} else {
showErrorDialog(
context,
ErrorService().showError(
title: 'Erreur',
message: error,
icon: Icons.error,

View File

@@ -11,6 +11,7 @@ import '../blocs/user/user_bloc.dart';
import '../blocs/user/user_event.dart';
import '../blocs/auth/auth_bloc.dart';
import '../blocs/auth/auth_event.dart';
import '../services/error_service.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@@ -119,12 +120,7 @@ class _HomePageState extends State<HomePage> {
);
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Erreur lors de la déconnexion: $e'),
backgroundColor: Colors.red,
),
);
ErrorService().showError(message: 'Erreur lors de la déconnexion: $e');
}
}
}
@@ -132,9 +128,7 @@ class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(titles[_currentIndex]),
),
appBar: AppBar(title: Text(titles[_currentIndex])),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
@@ -142,28 +136,43 @@ class _HomePageState extends State<HomePage> {
DrawerHeader(
decoration: BoxDecoration(
color: Theme.of(context).brightness == Brightness.dark
? Colors.black
: Colors.white,
? Colors.black
: Colors.white,
),
child: Text(
"Travel Mate",
style: TextStyle(
color: Theme.of(context).brightness == Brightness.dark
? Colors.white
: Colors.black,
? Colors.white
: Colors.black,
fontSize: 24,
),
),
),
_buildDrawerItem(icon: Icons.home, title: "Mes voyages", index: 0),
_buildDrawerItem(icon: Icons.settings, title: "Paramètres", index: 1),
_buildDrawerItem(
icon: Icons.settings,
title: "Paramètres",
index: 1,
),
_buildDrawerItem(icon: Icons.map, title: "Carte", index: 2),
_buildDrawerItem(icon: Icons.group, title: "Chat de groupe", index: 3),
_buildDrawerItem(icon: Icons.account_balance_wallet, title: "Comptes", index: 4),
_buildDrawerItem(
icon: Icons.group,
title: "Chat de groupe",
index: 3,
),
_buildDrawerItem(
icon: Icons.account_balance_wallet,
title: "Comptes",
index: 4,
),
const Divider(),
ListTile(
leading: const Icon(Icons.logout, color: Colors.red),
title: const Text("Déconnexion", style: TextStyle(color: Colors.red)),
title: const Text(
"Déconnexion",
style: TextStyle(color: Colors.red),
),
onTap: _handleLogout, // Utiliser la nouvelle méthode
),
],
@@ -191,7 +200,9 @@ class _HomePageState extends State<HomePage> {
leading: Icon(icon),
title: Text(title),
selected: _currentIndex == index,
selectedTileColor: Theme.of(context).colorScheme.primary.withValues(alpha: 0.1),
selectedTileColor: Theme.of(
context,
).colorScheme.primary.withValues(alpha: 0.1),
onTap: () => _onNavigationTap(index),
);
}

View File

@@ -4,6 +4,7 @@ import '../blocs/auth/auth_bloc.dart';
import '../blocs/auth/auth_event.dart';
import '../blocs/auth/auth_state.dart';
import 'package:sign_in_button/sign_in_button.dart';
import '../services/error_service.dart';
/// Login page widget for user authentication.
///
@@ -89,12 +90,7 @@ class _LoginPageState extends State<LoginPage> {
if (state is AuthAuthenticated) {
Navigator.pushReplacementNamed(context, '/home');
} else if (state is AuthError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.message),
backgroundColor: Colors.red,
),
);
ErrorService().showError(message: state.message);
}
},
builder: (context, state) {

View File

@@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import '../blocs/auth/auth_bloc.dart';
import '../blocs/auth/auth_event.dart';
import '../blocs/auth/auth_state.dart';
import '../services/error_service.dart';
class ForgotPasswordPage extends StatefulWidget {
const ForgotPasswordPage({super.key});
@@ -56,20 +57,13 @@ class _ForgotPasswordPageState extends State<ForgotPasswordPage> {
body: BlocListener<AuthBloc, AuthState>(
listener: (context, state) {
if (state is AuthPasswordResetSent) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Email de réinitialisation envoyé !'),
backgroundColor: Colors.green,
),
ErrorService().showSnackbar(
message: 'Email de réinitialisation envoyé !',
isError: false,
);
Navigator.pop(context);
} else if (state is AuthError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.message),
backgroundColor: Colors.red,
),
);
ErrorService().showError(message: state.message);
}
},
child: SafeArea(

View File

@@ -117,9 +117,7 @@ class _SignUpPageState extends State<SignUpPage> {
);
Navigator.pushReplacementNamed(context, '/home');
} else if (state is AuthError) {
_errorService.showError(
message: 'Erreur lors de la création du compte',
);
_errorService.showError(message: state.message);
}
},
builder: (context, state) {

View File

@@ -7,7 +7,8 @@ class AccountRepository {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final _errorService = ErrorService();
CollectionReference get _accountCollection => _firestore.collection('accounts');
CollectionReference get _accountCollection =>
_firestore.collection('accounts');
CollectionReference _membersCollection(String accountId) {
return _accountCollection.doc(accountId).collection('members');
@@ -32,8 +33,13 @@ class AccountRepository {
return accountRef.id;
});
} catch (e) {
throw Exception('Erreur lors de la création du compte: $e');
} catch (e, stackTrace) {
_errorService.logError(
'account_repository.dart',
'Erreur lors de la création du compte: $e',
stackTrace,
);
throw Exception('Impossible de créer le compte');
}
}
@@ -41,7 +47,6 @@ class AccountRepository {
return _accountCollection
.snapshots()
.asyncMap((snapshot) async {
List<Account> userAccounts = [];
for (var accountDoc in snapshot.docs) {
@@ -54,14 +59,24 @@ class AccountRepository {
.get();
if (memberDoc.exists) {
final accountData = accountDoc.data() as Map<String, dynamic>;
final account = Account.fromMap(accountData, accountId); // ✅ Ajout de l'ID
final account = Account.fromMap(
accountData,
accountId,
); // ✅ Ajout de l'ID
final members = await getAccountMembers(accountId);
userAccounts.add(account.copyWith(members: members));
} else {
_errorService.logInfo('account_repository.dart', 'Utilisateur NON membre de $accountId');
_errorService.logInfo(
'account_repository.dart',
'Utilisateur NON membre de $accountId',
);
}
} catch (e, stackTrace) {
_errorService.logError(e.toString(), stackTrace);
_errorService.logError(
'account_repository.dart',
'Erreur processing account doc: $e',
stackTrace,
);
}
}
return userAccounts;
@@ -71,13 +86,18 @@ class AccountRepository {
final prevIds = prev.map((a) => a.id).toSet();
final nextIds = next.map((a) => a.id).toSet();
final identical = prevIds.difference(nextIds).isEmpty &&
nextIds.difference(prevIds).isEmpty;
final identical =
prevIds.difference(nextIds).isEmpty &&
nextIds.difference(prevIds).isEmpty;
return identical;
})
.handleError((error, stackTrace) {
_errorService.logError(error, stackTrace);
_errorService.logError(
'account_repository.dart',
'Erreur stream accounts: $error',
stackTrace,
);
return <Account>[];
});
}
@@ -85,16 +105,16 @@ class AccountRepository {
Future<List<GroupMember>> getAccountMembers(String accountId) async {
try {
final snapshot = await _membersCollection(accountId).get();
return snapshot.docs
.map((doc) {
return GroupMember.fromMap(
doc.data() as Map<String, dynamic>,
doc.id,
);
})
.toList();
} catch (e) {
throw Exception('Erreur lors de la récupération des membres: $e');
return snapshot.docs.map((doc) {
return GroupMember.fromMap(doc.data() as Map<String, dynamic>, doc.id);
}).toList();
} catch (e, stackTrace) {
_errorService.logError(
'account_repository.dart',
'Erreur lors de la récupération des membres: $e',
stackTrace,
);
throw Exception('Impossible de récupérer les membres');
}
}
@@ -105,8 +125,13 @@ class AccountRepository {
return Account.fromMap(doc.data() as Map<String, dynamic>, doc.id);
}
return null;
} catch (e) {
throw Exception('Erreur lors de la récupération du compte: $e');
} catch (e, stackTrace) {
_errorService.logError(
'account_repository.dart',
'Erreur lors de la récupération du compte: $e',
stackTrace,
);
throw Exception('Impossible de récupérer le compte');
}
}
@@ -123,8 +148,13 @@ class AccountRepository {
return Account.fromMap(doc.data(), doc.id);
}
return null;
} catch (e) {
throw Exception('Erreur lors de la récupération du compte: $e');
} catch (e, stackTrace) {
_errorService.logError(
'account_repository.dart',
'Erreur lors de la récupération du compte: $e',
stackTrace,
);
throw Exception('Impossible de récupérer le compte');
}
}
@@ -132,10 +162,17 @@ class AccountRepository {
try {
// Mettre à jour la date de modification
final updatedAccount = account.copyWith(updatedAt: DateTime.now());
await _firestore.collection('accounts').doc(accountId).update(updatedAccount.toMap());
} catch (e) {
_errorService.logError('account_repository.dart', 'Erreur lors de la mise à jour du compte: $e');
throw Exception('Erreur lors de la mise à jour du compte: $e');
await _firestore
.collection('accounts')
.doc(accountId)
.update(updatedAccount.toMap());
} catch (e, stackTrace) {
_errorService.logError(
'account_repository.dart',
'Erreur lors de la mise à jour du compte: $e',
stackTrace,
);
throw Exception('Impossible de mettre à jour le compte');
}
}
@@ -159,21 +196,25 @@ class AccountRepository {
// Supprimer le compte
await _accountCollection.doc(docId).delete();
} catch (e) {
_errorService.logError('account_repository.dart', 'Erreur lors de la suppression du compte: $e');
throw Exception('Erreur lors de la suppression du compte: $e');
} catch (e, stackTrace) {
_errorService.logError(
'account_repository.dart',
'Erreur lors de la suppression du compte: $e',
stackTrace,
);
throw Exception('Impossible de supprimer le compte');
}
}
Stream<List<GroupMember>> watchGroupMembers(String accountId) {
return _membersCollection(accountId).snapshots().map(
(snapshot) => snapshot.docs
.map((doc) => GroupMember.fromMap(
doc.data() as Map<String, dynamic>,
doc.id,
))
.toList(),
);
(snapshot) => snapshot.docs
.map(
(doc) =>
GroupMember.fromMap(doc.data() as Map<String, dynamic>, doc.id),
)
.toList(),
);
}
Stream<Account?> watchAccount(String accountId) {
@@ -201,19 +242,32 @@ class AccountRepository {
Future<void> addMemberToAccount(String accountId, GroupMember member) async {
try {
await _membersCollection(accountId).doc(member.userId).set(member.toMap());
} catch (e) {
_errorService.logError('account_repository.dart', 'Erreur lors de l\'ajout du membre: $e');
throw Exception('Erreur lors de l\'ajout du membre: $e');
await _membersCollection(
accountId,
).doc(member.userId).set(member.toMap());
} catch (e, stackTrace) {
_errorService.logError(
'account_repository.dart',
'Erreur lors de l\'ajout du membre: $e',
stackTrace,
);
throw Exception('Impossible d\'ajouter le membre');
}
}
Future<void> removeMemberFromAccount(String accountId, String memberId) async {
Future<void> removeMemberFromAccount(
String accountId,
String memberId,
) async {
try {
await _membersCollection(accountId).doc(memberId).delete();
} catch (e) {
_errorService.logError('account_repository.dart', 'Erreur lors de la suppression du membre: $e');
throw Exception('Erreur lors de la suppression du membre: $e');
} catch (e, stackTrace) {
_errorService.logError(
'account_repository.dart',
'Erreur lors de la suppression du membre: $e',
stackTrace,
);
throw Exception('Impossible de supprimer le membre');
}
}
}

View File

@@ -60,10 +60,10 @@ class AuthRepository {
);
await _saveFCMToken(firebaseUser.user!.uid);
return await getUserFromFirestore(firebaseUser.user!.uid);
} catch (e) {
_errorService.showError(message: 'Utilisateur ou mot de passe incorrect');
} catch (e, stackTrace) {
_errorService.logError('AuthRepository', 'SignIn error: $e', stackTrace);
throw Exception('Utilisateur ou mot de passe incorrect');
}
return null;
}
/// Creates a new user account with email and password.
@@ -108,10 +108,10 @@ class AuthRepository {
await _saveFCMToken(user.id!);
}
return user;
} catch (e) {
_errorService.showError(message: 'Erreur lors de la création du compte');
} catch (e, stackTrace) {
_errorService.logError('AuthRepository', 'SignUp error: $e', stackTrace);
throw Exception('Erreur lors de la création du compte');
}
return null;
}
/// Signs in a user using Google authentication.
@@ -160,10 +160,14 @@ class AuthRepository {
return user;
}
return null;
} catch (e) {
_errorService.showError(message: 'Erreur lors de la connexion Google');
} catch (e, stackTrace) {
_errorService.logError(
'AuthRepository',
'Google SignUp error: $e',
stackTrace,
);
throw Exception('Erreur lors de la connexion Google');
}
return null;
}
Future<User?> signInWithGoogle() async {
@@ -178,10 +182,14 @@ class AuthRepository {
} else {
throw Exception('Utilisateur non trouvé');
}
} catch (e) {
_errorService.showError(message: 'Erreur lors de la connexion Google');
} catch (e, stackTrace) {
_errorService.logError(
'AuthRepository',
'Google SignIn error: $e',
stackTrace,
);
throw Exception('Erreur lors de la connexion Google');
}
return null;
}
/// Signs in a user using Apple authentication.
@@ -228,10 +236,14 @@ class AuthRepository {
return user;
}
return null;
} catch (e) {
_errorService.showError(message: 'Erreur lors de la connexion Apple');
} catch (e, stackTrace) {
_errorService.logError(
'AuthRepository',
'Apple SignUp error: $e',
stackTrace,
);
throw Exception('Erreur lors de la connexion Apple');
}
return null;
}
Future<User?> signInWithApple() async {
@@ -246,10 +258,14 @@ class AuthRepository {
} else {
throw Exception('Utilisateur non trouvé');
}
} catch (e) {
_errorService.showError(message: 'Erreur lors de la connexion Apple');
} catch (e, stackTrace) {
_errorService.logError(
'AuthRepository',
'Apple SignIn error: $e',
stackTrace,
);
throw Exception('Erreur lors de la connexion Apple');
}
return null;
}
/// Signs out the current user.
@@ -298,9 +314,13 @@ class AuthRepository {
'fcmToken': token,
}, SetOptions(merge: true));
}
} catch (e) {
} catch (e, stackTrace) {
// Non-blocking error
print('Error saving FCM token: $e');
_errorService.logError(
'AuthRepository',
'Error saving FCM token: $e',
stackTrace,
);
}
}
}

View File

@@ -37,9 +37,13 @@ class BalanceRepository {
totalExpenses: totalExpenses,
calculatedAt: DateTime.now(),
);
} catch (e) {
_errorService.logError('BalanceRepository', 'Erreur calcul balance: $e');
rethrow;
} catch (e, stackTrace) {
_errorService.logError(
'BalanceRepository',
'Erreur calcul balance: $e',
stackTrace,
);
throw Exception('Impossible de calculer la balance');
}
}
@@ -50,9 +54,13 @@ class BalanceRepository {
.first;
return _calculateUserBalances(expenses);
} catch (e) {
_errorService.logError('BalanceRepository', 'Erreur calcul user balances: $e');
rethrow;
} catch (e, stackTrace) {
_errorService.logError(
'BalanceRepository',
'Erreur calcul user balances: $e',
stackTrace,
);
throw Exception('Impossible de calculer les balances utilisateurs');
}
}
@@ -65,19 +73,17 @@ class BalanceRepository {
if (expense.isArchived) continue;
// Ajouter le payeur
userBalanceMap.putIfAbsent(expense.paidById, () => {
'name': expense.paidByName,
'paid': 0.0,
'owed': 0.0,
});
userBalanceMap.putIfAbsent(
expense.paidById,
() => {'name': expense.paidByName, 'paid': 0.0, 'owed': 0.0},
);
// Ajouter les participants
for (final split in expense.splits) {
userBalanceMap.putIfAbsent(split.userId, () => {
'name': split.userName,
'paid': 0.0,
'owed': 0.0,
});
userBalanceMap.putIfAbsent(
split.userId,
() => {'name': split.userName, 'paid': 0.0, 'owed': 0.0},
);
}
}
@@ -125,10 +131,10 @@ class BalanceRepository {
// Créer des copies mutables des montants
final creditorsRemaining = Map.fromEntries(
creditors.map((c) => MapEntry(c.userId, c.balance))
creditors.map((c) => MapEntry(c.userId, c.balance)),
);
final debtorsRemaining = Map.fromEntries(
debtors.map((d) => MapEntry(d.userId, -d.balance))
debtors.map((d) => MapEntry(d.userId, -d.balance)),
);
// Algorithme glouton pour minimiser le nombre de transactions
@@ -139,15 +145,20 @@ class BalanceRepository {
if (creditAmount <= 0.01 || debtAmount <= 0.01) continue;
final settlementAmount = [creditAmount, debtAmount].reduce((a, b) => a < b ? a : b);
final settlementAmount = [
creditAmount,
debtAmount,
].reduce((a, b) => a < b ? a : b);
settlements.add(Settlement(
fromUserId: debtor.userId,
fromUserName: debtor.userName,
toUserId: creditor.userId,
toUserName: creditor.userName,
amount: settlementAmount,
));
settlements.add(
Settlement(
fromUserId: debtor.userId,
fromUserName: debtor.userName,
toUserId: creditor.userId,
toUserName: creditor.userName,
amount: settlementAmount,
),
);
creditorsRemaining[creditor.userId] = creditAmount - settlementAmount;
debtorsRemaining[debtor.userId] = debtAmount - settlementAmount;

View File

@@ -35,8 +35,13 @@ class GroupRepository {
return groupRef.id;
});
} catch (e) {
throw Exception('Erreur lors de la création du groupe: $e');
} catch (e, stackTrace) {
_errorService.logError(
'GroupRepository',
'Erreur création groupe: $e',
stackTrace,
);
throw Exception('Impossible de créer le groupe');
}
}
@@ -51,7 +56,11 @@ class GroupRepository {
}).toList();
})
.handleError((error, stackTrace) {
_errorService.logError(error, stackTrace);
_errorService.logError(
'GroupRepository',
'Erreur stream groups: $error',
stackTrace,
);
return <Group>[];
});
}
@@ -66,8 +75,13 @@ class GroupRepository {
final members = await getGroupMembers(groupId);
return group.copyWith(members: members);
} catch (e) {
throw Exception('Erreur lors de la récupération du groupe: $e');
} catch (e, stackTrace) {
_errorService.logError(
'GroupRepository',
'Erreur get group: $e',
stackTrace,
);
throw Exception('Impossible de récupérer le groupe');
}
}
@@ -104,8 +118,13 @@ class GroupRepository {
final members = await getGroupMembers(doc.id);
return group.copyWith(members: members);
} catch (e) {
throw Exception('Erreur lors de la récupération du groupe: $e');
} catch (e, stackTrace) {
_errorService.logError(
'GroupRepository',
'Erreur get group by trip: $e',
stackTrace,
);
throw Exception('Impossible de récupérer le groupe du voyage');
}
}
@@ -122,10 +141,11 @@ class GroupRepository {
'Migration réussie pour le groupe $groupId',
);
}
} catch (e) {
} catch (e, stackTrace) {
_errorService.logError(
'GroupRepository',
'Erreur de migration pour le groupe $groupId: $e',
stackTrace,
);
}
}
@@ -136,8 +156,13 @@ class GroupRepository {
return snapshot.docs.map((doc) {
return GroupMember.fromMap(doc.data() as Map<String, dynamic>, doc.id);
}).toList();
} catch (e) {
throw Exception('Erreur lors de la récupération des membres: $e');
} catch (e, stackTrace) {
_errorService.logError(
'GroupRepository',
'Erreur get members: $e',
stackTrace,
);
throw Exception('Impossible de récupérer les membres');
}
}
@@ -160,8 +185,13 @@ class GroupRepository {
await _firestore.collection('trips').doc(group.tripId).update({
'participants': FieldValue.arrayUnion([member.userId]),
});
} catch (e) {
throw Exception('Erreur lors de l\'ajout du membre: $e');
} catch (e, stackTrace) {
_errorService.logError(
'GroupRepository',
'Erreur add member: $e',
stackTrace,
);
throw Exception('Impossible d\'ajouter le membre');
}
}
@@ -184,8 +214,13 @@ class GroupRepository {
await _firestore.collection('trips').doc(group.tripId).update({
'participants': FieldValue.arrayRemove([userId]),
});
} catch (e) {
throw Exception('Erreur lors de la suppression du membre: $e');
} catch (e, stackTrace) {
_errorService.logError(
'GroupRepository',
'Erreur remove member: $e',
stackTrace,
);
throw Exception('Impossible de supprimer le membre');
}
}
@@ -197,8 +232,13 @@ class GroupRepository {
group.toMap()
..['updatedAt'] = DateTime.now().millisecondsSinceEpoch,
);
} catch (e) {
throw Exception('Erreur lors de la mise à jour du groupe: $e');
} catch (e, stackTrace) {
_errorService.logError(
'GroupRepository',
'Erreur update group: $e',
stackTrace,
);
throw Exception('Impossible de mettre à jour le groupe');
}
}
@@ -226,8 +266,13 @@ class GroupRepository {
}
await _groupsCollection.doc(groupId).delete();
} catch (e) {
throw Exception('Erreur lors de la suppression du groupe: $e');
} catch (e, stackTrace) {
_errorService.logError(
'GroupRepository',
'Erreur delete group: $e',
stackTrace,
);
throw Exception('Impossible de supprimer le groupe');
}
}

View File

@@ -1,8 +1,10 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import '../models/trip.dart';
import '../services/error_service.dart';
class TripRepository {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final _errorService = ErrorService();
CollectionReference get _tripsCollection => _firestore.collection('trips');
@@ -13,21 +15,31 @@ class TripRepository {
.where('participants', arrayContains: userId)
.snapshots()
.map((snapshot) {
final trips = snapshot.docs
.map((doc) {
try {
final data = doc.data() as Map<String, dynamic>;
return Trip.fromMap(data, doc.id);
} catch (e) {
return null;
}
})
.whereType<Trip>()
.toList();
return trips;
});
} catch (e) {
throw Exception('Erreur lors de la récupération des voyages: $e');
final trips = snapshot.docs
.map((doc) {
try {
final data = doc.data() as Map<String, dynamic>;
return Trip.fromMap(data, doc.id);
} catch (e, stackTrace) {
_errorService.logError(
'TripRepository',
'Erreur parsing trip ${doc.id}: $e',
stackTrace,
);
return null;
}
})
.whereType<Trip>()
.toList();
return trips;
});
} catch (e, stackTrace) {
_errorService.logError(
'TripRepository',
'Erreur stream trips: $e',
stackTrace,
);
throw Exception('Impossible de récupérer les voyages');
}
}
@@ -38,8 +50,13 @@ class TripRepository {
// Ne pas modifier les timestamps ici, ils sont déjà au bon format
final docRef = await _tripsCollection.add(tripData);
return docRef.id;
} catch (e) {
throw Exception('Erreur lors de la création du voyage: $e');
} catch (e, stackTrace) {
_errorService.logError(
'TripRepository',
'Erreur création trip: $e',
stackTrace,
);
throw Exception('Impossible de créer le voyage');
}
}
@@ -53,8 +70,13 @@ class TripRepository {
}
return Trip.fromMap(doc.data() as Map<String, dynamic>, doc.id);
} catch (e) {
throw Exception('Erreur lors de la récupération du voyage: $e');
} catch (e, stackTrace) {
_errorService.logError(
'TripRepository',
'Erreur get trip: $e',
stackTrace,
);
throw Exception('Impossible de récupérer le voyage');
}
}
@@ -66,8 +88,13 @@ class TripRepository {
tripData['updatedAt'] = Timestamp.now();
await _tripsCollection.doc(tripId).update(tripData);
} catch (e) {
throw Exception('Erreur lors de la mise à jour du voyage: $e');
} catch (e, stackTrace) {
_errorService.logError(
'TripRepository',
'Erreur update trip: $e',
stackTrace,
);
throw Exception('Impossible de mettre à jour le voyage');
}
}
@@ -75,8 +102,13 @@ class TripRepository {
Future<void> deleteTrip(String tripId) async {
try {
await _tripsCollection.doc(tripId).delete();
} catch (e) {
throw Exception('Erreur lors de la suppression du voyage: $e');
} catch (e, stackTrace) {
_errorService.logError(
'TripRepository',
'Erreur delete trip: $e',
stackTrace,
);
throw Exception('Impossible de supprimer le voyage');
}
}
}

View File

@@ -1,6 +1,7 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import '../models/user.dart';
import '../services/auth_service.dart';
import '../services/error_service.dart';
/// Repository for user data operations in Firestore.
///
@@ -14,14 +15,14 @@ class UserRepository {
/// Authentication service for user-related operations.
final AuthService _authService;
final _errorService = ErrorService();
/// Creates a new [UserRepository] with optional dependencies.
///
/// If [firestore] or [authService] are not provided, default instances will be used.
UserRepository({
FirebaseFirestore? firestore,
AuthService? authService,
}) : _firestore = firestore ?? FirebaseFirestore.instance,
_authService = authService ?? AuthService();
UserRepository({FirebaseFirestore? firestore, AuthService? authService})
: _firestore = firestore ?? FirebaseFirestore.instance,
_authService = authService ?? AuthService();
/// Retrieves a user by their unique ID.
///
@@ -39,8 +40,13 @@ class UserRepository {
return User.fromMap({...data, 'id': uid});
}
return null;
} catch (e) {
throw Exception('Error retrieving user: $e');
} catch (e, stackTrace) {
_errorService.logError(
'UserRepository',
'Error retrieving user: $e',
stackTrace,
);
throw Exception('Impossible de récupérer l\'utilisateur');
}
}
@@ -67,8 +73,13 @@ class UserRepository {
return User.fromMap({...data, 'id': doc.id});
}
return null;
} catch (e) {
throw Exception('Error searching for user: $e');
} catch (e, stackTrace) {
_errorService.logError(
'UserRepository',
'Error searching for user: $e',
stackTrace,
);
throw Exception('Impossible de trouver l\'utilisateur');
}
}
@@ -87,8 +98,13 @@ class UserRepository {
await _authService.updateDisplayName(displayName: user.fullName);
return true;
} catch (e) {
throw Exception('Erreur lors de la mise à jour: $e');
} catch (e, stackTrace) {
_errorService.logError(
'UserRepository',
'Erreur lors de la mise à jour: $e',
stackTrace,
);
throw Exception('Impossible de mettre à jour l\'utilisateur');
}
}
@@ -98,8 +114,13 @@ class UserRepository {
await _firestore.collection('users').doc(uid).delete();
// Note: Vous devrez également supprimer le compte Firebase Auth
return true;
} catch (e) {
throw Exception('Erreur lors de la suppression: $e');
} catch (e, stackTrace) {
_errorService.logError(
'UserRepository',
'Erreur lors de la suppression: $e',
stackTrace,
);
throw Exception('Impossible de supprimer l\'utilisateur');
}
}
@@ -120,8 +141,13 @@ class UserRepository {
newPassword: newPassword,
);
return true;
} catch (e) {
throw Exception('Erreur lors du changement de mot de passe: $e');
} catch (e, stackTrace) {
_errorService.logError(
'UserRepository',
'Erreur lors du changement de mot de passe: $e',
stackTrace,
);
throw Exception('Impossible de changer le mot de passe');
}
}
}

View File

@@ -171,18 +171,35 @@ class AuthService {
}
} on GoogleSignInException catch (e) {
_errorService.logError('Google Sign-In error: $e', StackTrace.current);
_errorService.showError(
message: 'La connexion avec Google a échoué. Veuillez réessayer.',
);
rethrow;
} on FirebaseAuthException catch (e) {
_errorService.logError(
'Firebase error during Google Sign-In initialization: $e',
StackTrace.current,
);
if (e.code == 'account-exists-with-different-credential') {
_errorService.showError(
message:
'Un compte existe déjà avec cette adresse email. Veuillez vous connecter avec la méthode utilisée précédemment.',
);
} else {
_errorService.showError(
message:
'Une erreur est survenue lors de la connexion avec Google. Veuillez réessayer plus tard.',
);
}
rethrow;
} catch (e) {
_errorService.logError(
'Unknown error during Google Sign-In initialization: $e',
StackTrace.current,
);
_errorService.showError(
message: 'Une erreur inattendue est survenue. Veuillez réessayer.',
);
rethrow;
}
}
@@ -216,9 +233,9 @@ class AuthService {
],
// Configuration for Android/Web
webAuthenticationOptions: WebAuthenticationOptions(
clientId: 'be.devdayronvl.TravelMate',
clientId: 'be.devdayronvl.TravelMate.service',
redirectUri: Uri.parse(
'https://your-project-id.firebaseapp.com/__/auth/handler',
'https://travelmate-a47f5.firebaseapp.com/__/auth/handler',
),
),
);
@@ -247,24 +264,49 @@ class AuthService {
return userCredential;
} on SignInWithAppleException catch (e) {
_errorService.logError('Apple Sign-In error: $e', StackTrace.current);
_errorService.showError(
message: 'La connexion avec Apple a échoué. Veuillez réessayer.',
);
throw FirebaseAuthException(
code: 'ERROR_APPLE_SIGNIN_FAILED',
message: 'Apple Sign-In failed: ${e.toString()}',
message: 'Apple Sign-In failed',
);
} on FirebaseAuthException catch (e) {
_errorService.logError(
'Firebase error during Apple Sign-In: $e',
StackTrace.current,
);
if (e.code == 'account-exists-with-different-credential') {
_errorService.showError(
message:
'Un compte existe déjà avec cette adresse email. Veuillez vous connecter avec la méthode utilisée précédemment.',
);
} else if (e.code == 'invalid-credential') {
_errorService.showError(
message: 'Les informations de connexion sont invalides.',
);
} else if (e.code == 'user-disabled') {
_errorService.showError(
message: 'Ce compte utilisateur a été désactivé.',
);
} else {
_errorService.showError(
message:
'Une erreur est survenue lors de la connexion avec Apple. Veuillez réessayer plus tard.',
);
}
rethrow;
} catch (e) {
_errorService.logError(
'Unknown error during Apple Sign-In: $e',
StackTrace.current,
);
_errorService.showError(
message: 'Une erreur inattendue est survenue. Veuillez réessayer.',
);
throw FirebaseAuthException(
code: 'ERROR_APPLE_SIGNIN_UNKNOWN',
message: 'Unknown error during Apple Sign-In: $e',
message: 'Unknown error during Apple Sign-In',
);
}
}

View File

@@ -9,8 +9,8 @@ class MessageService {
MessageService({
required MessageRepository messageRepository,
ErrorService? errorService,
}) : _messageRepository = messageRepository,
_errorService = errorService ?? ErrorService();
}) : _messageRepository = messageRepository,
_errorService = errorService ?? ErrorService();
// Envoyer un message
Future<void> sendMessage({
@@ -30,12 +30,13 @@ class MessageService {
senderId: senderId,
senderName: senderName,
);
} catch (e) {
} catch (e, stackTrace) {
_errorService.logError(
'message_service.dart',
'Erreur lors de l\'envoi du message: $e',
stackTrace,
);
rethrow;
throw Exception('Impossible d\'envoyer le message');
}
}
@@ -43,12 +44,13 @@ class MessageService {
Stream<List<Message>> getMessagesStream(String groupId) {
try {
return _messageRepository.getMessagesStream(groupId);
} catch (e) {
} catch (e, stackTrace) {
_errorService.logError(
'message_service.dart',
'Erreur lors de la récupération des messages: $e',
stackTrace,
);
rethrow;
throw Exception('Impossible de récupérer les messages');
}
}
@@ -62,12 +64,13 @@ class MessageService {
groupId: groupId,
messageId: messageId,
);
} catch (e) {
} catch (e, stackTrace) {
_errorService.logError(
'message_service.dart',
'Erreur lors de la suppression du message: $e',
stackTrace,
);
rethrow;
throw Exception('Impossible de supprimer le message');
}
}
@@ -87,12 +90,13 @@ class MessageService {
messageId: messageId,
newText: newText.trim(),
);
} catch (e) {
} catch (e, stackTrace) {
_errorService.logError(
'message_service.dart',
'Erreur lors de la modification du message: $e',
stackTrace,
);
rethrow;
throw Exception('Impossible de modifier le message');
}
}
@@ -110,12 +114,13 @@ class MessageService {
userId: userId,
reaction: reaction,
);
} catch (e) {
} catch (e, stackTrace) {
_errorService.logError(
'message_service.dart',
'Erreur lors de l\'ajout de la réaction: $e',
stackTrace,
);
rethrow;
throw Exception('Impossible d\'ajouter la réaction');
}
}
@@ -131,12 +136,13 @@ class MessageService {
messageId: messageId,
userId: userId,
);
} catch (e) {
} catch (e, stackTrace) {
_errorService.logError(
'message_service.dart',
'Erreur lors de la suppression de la réaction: $e',
stackTrace,
);
rethrow;
throw Exception('Impossible de supprimer la réaction');
}
}
}