Add new activity events and enhance ActivityBloc for better state management

- Introduced LoadTripActivitiesPreservingSearch event to load trip activities while preserving search results.
- Added RemoveFromSearchResults and AddActivityAndRemoveFromSearch events for improved activity handling.
- Updated ActivitiesPage to show loading dialog during activity addition and provide user feedback.
- Increased maxResults for activity search to load more activities.
This commit is contained in:
Dayron
2025-11-13 10:46:36 +01:00
parent 236327f6fa
commit dd8de46e71
4 changed files with 209 additions and 41 deletions

View File

@@ -23,6 +23,7 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
super(const ActivityInitial()) {
on<LoadActivities>(_onLoadActivities);
on<LoadTripActivitiesPreservingSearch>(_onLoadTripActivitiesPreservingSearch);
on<SearchActivities>(_onSearchActivities);
on<SearchActivitiesWithCoordinates>(_onSearchActivitiesWithCoordinates);
on<SearchActivitiesByText>(_onSearchActivitiesByText);
@@ -36,6 +37,8 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
on<UpdateActivity>(_onUpdateActivity);
on<ToggleActivityFavorite>(_onToggleActivityFavorite);
on<RestoreCachedSearchResults>(_onRestoreCachedSearchResults);
on<RemoveFromSearchResults>(_onRemoveFromSearchResults);
on<AddActivityAndRemoveFromSearch>(_onAddActivityAndRemoveFromSearch);
}
/// Handles loading activities for a trip
@@ -58,6 +61,31 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
}
}
/// Handles loading trip activities while preserving search results state
Future<void> _onLoadTripActivitiesPreservingSearch(
LoadTripActivitiesPreservingSearch event,
Emitter<ActivityState> emit,
) async {
try {
final activities = await _repository.getActivitiesByTrip(event.tripId);
// Si on a un état de recherche actif, on le préserve
if (state is ActivitySearchResults) {
// On garde l'état de recherche inchangé, pas besoin d'émettre
return;
}
// Sinon, on charge normalement
emit(ActivityLoaded(
activities: activities,
filteredActivities: activities,
));
} catch (e) {
_errorService.logError('activity_bloc', 'Erreur chargement activités: $e');
emit(const ActivityError('Impossible de charger les activités'));
}
}
/// Handles searching activities using Google Places API
Future<void> _onSearchActivities(
SearchActivities event,
@@ -200,12 +228,74 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
final activityId = await _repository.addActivity(event.activity);
if (activityId != null) {
// Si on est en état de recherche (suggestions Google), préserver cet état
if (state is ActivitySearchResults) {
// On ne change rien à l'état de recherche, on le garde tel quel
// La suppression de l'activité des résultats se fait dans _onRemoveFromSearchResults
return;
}
// Sinon, émettre l'état d'ajout réussi
emit(ActivityAdded(
activity: event.activity.copyWith(id: activityId),
message: 'Activité ajoutée avec succès',
));
// Reload activities
add(LoadActivities(event.activity.tripId));
// Reload activities while preserving search results
add(LoadTripActivitiesPreservingSearch(event.activity.tripId));
} else {
emit(const ActivityError('Impossible d\'ajouter l\'activité'));
}
} catch (e) {
_errorService.logError('activity_bloc', 'Erreur ajout activité: $e');
emit(const ActivityError('Impossible d\'ajouter l\'activité'));
}
}
/// Handles adding an activity and removing it from search results in one action
Future<void> _onAddActivityAndRemoveFromSearch(
AddActivityAndRemoveFromSearch event,
Emitter<ActivityState> emit,
) async {
try {
// Check if activity already exists
if (event.activity.placeId != null) {
final existing = await _repository.findExistingActivity(
event.activity.tripId,
event.activity.placeId!,
);
if (existing != null) {
emit(const ActivityError('Cette activité a déjà été ajoutée'));
return;
}
}
final activityId = await _repository.addActivity(event.activity);
if (activityId != null) {
// Si on est en état de recherche (suggestions Google), préserver cet état
// en supprimant l'activité des résultats
if (state is ActivitySearchResults) {
final currentState = state as ActivitySearchResults;
final updatedResults = currentState.searchResults
.where((activity) => activity.id != event.googleActivityId)
.toList();
emit(ActivitySearchResults(
searchResults: updatedResults,
query: currentState.query,
isLoading: false,
));
return;
}
// Sinon, émettre l'état d'ajout réussi
emit(ActivityAdded(
activity: event.activity.copyWith(id: activityId),
message: 'Activité ajoutée avec succès',
));
// Reload activities while preserving search results
add(LoadTripActivitiesPreservingSearch(event.activity.tripId));
} else {
emit(const ActivityError('Impossible d\'ajouter l\'activité'));
}
@@ -482,6 +572,29 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
return filtered;
}
/// Removes an activity from search results
Future<void> _onRemoveFromSearchResults(
RemoveFromSearchResults event,
Emitter<ActivityState> emit,
) async {
// Si on est actuellement dans un état de résultats de recherche
if (state is ActivitySearchResults) {
final currentState = state as ActivitySearchResults;
// Filtrer l'activité à retirer
final updatedResults = currentState.searchResults
.where((activity) => activity.id != event.activityId)
.toList();
// Émettre le nouvel état avec l'activité retirée
emit(ActivitySearchResults(
searchResults: updatedResults,
query: currentState.query,
isLoading: false,
));
}
}
/// Restores cached search results
Future<void> _onRestoreCachedSearchResults(
RestoreCachedSearchResults event,