feat: Add calendar page, enhance activity search and approval logic, and refactor activity filtering UI.
This commit is contained in:
@@ -17,13 +17,14 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
required ActivityRepository repository,
|
||||
required ActivityPlacesService placesService,
|
||||
required ErrorService errorService,
|
||||
}) : _repository = repository,
|
||||
_placesService = placesService,
|
||||
_errorService = errorService,
|
||||
super(const ActivityInitial()) {
|
||||
|
||||
}) : _repository = repository,
|
||||
_placesService = placesService,
|
||||
_errorService = errorService,
|
||||
super(const ActivityInitial()) {
|
||||
on<LoadActivities>(_onLoadActivities);
|
||||
on<LoadTripActivitiesPreservingSearch>(_onLoadTripActivitiesPreservingSearch);
|
||||
on<LoadTripActivitiesPreservingSearch>(
|
||||
_onLoadTripActivitiesPreservingSearch,
|
||||
);
|
||||
on<SearchActivities>(_onSearchActivities);
|
||||
on<SearchActivitiesWithCoordinates>(_onSearchActivitiesWithCoordinates);
|
||||
on<SearchActivitiesByText>(_onSearchActivitiesByText);
|
||||
@@ -39,6 +40,7 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
on<RestoreCachedSearchResults>(_onRestoreCachedSearchResults);
|
||||
on<RemoveFromSearchResults>(_onRemoveFromSearchResults);
|
||||
on<AddActivityAndRemoveFromSearch>(_onAddActivityAndRemoveFromSearch);
|
||||
on<UpdateActivityDate>(_onUpdateActivityDate);
|
||||
}
|
||||
|
||||
/// Handles loading activities for a trip
|
||||
@@ -48,15 +50,17 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
) async {
|
||||
try {
|
||||
emit(const ActivityLoading());
|
||||
|
||||
|
||||
final activities = await _repository.getActivitiesByTrip(event.tripId);
|
||||
|
||||
emit(ActivityLoaded(
|
||||
activities: activities,
|
||||
filteredActivities: activities,
|
||||
));
|
||||
|
||||
emit(
|
||||
ActivityLoaded(activities: activities, filteredActivities: activities),
|
||||
);
|
||||
} catch (e) {
|
||||
_errorService.logError('activity_bloc', 'Erreur chargement activités: $e');
|
||||
_errorService.logError(
|
||||
'activity_bloc',
|
||||
'Erreur chargement activités: $e',
|
||||
);
|
||||
emit(const ActivityError('Impossible de charger les activités'));
|
||||
}
|
||||
}
|
||||
@@ -68,24 +72,52 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
) 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,
|
||||
));
|
||||
emit(
|
||||
ActivityLoaded(activities: activities, filteredActivities: activities),
|
||||
);
|
||||
} catch (e) {
|
||||
_errorService.logError('activity_bloc', 'Erreur chargement activités: $e');
|
||||
_errorService.logError(
|
||||
'activity_bloc',
|
||||
'Erreur chargement activités: $e',
|
||||
);
|
||||
emit(const ActivityError('Impossible de charger les activités'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onUpdateActivityDate(
|
||||
UpdateActivityDate event,
|
||||
Emitter<ActivityState> emit,
|
||||
) async {
|
||||
try {
|
||||
final activity = await _repository.getActivity(
|
||||
event.tripId,
|
||||
event.activityId,
|
||||
);
|
||||
|
||||
if (activity != null) {
|
||||
final updatedActivity = activity.copyWith(
|
||||
date: event.date,
|
||||
clearDate: event.date == null,
|
||||
);
|
||||
await _repository.updateActivity(updatedActivity);
|
||||
|
||||
// Recharger les activités pour mettre à jour l'UI
|
||||
add(LoadActivities(event.tripId));
|
||||
}
|
||||
} catch (e) {
|
||||
_errorService.logError('activity_bloc', 'Erreur mise à jour date: $e');
|
||||
emit(const ActivityError('Impossible de mettre à jour la date'));
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles searching activities using Google Places API
|
||||
Future<void> _onSearchActivities(
|
||||
SearchActivities event,
|
||||
@@ -99,17 +131,19 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
} else {
|
||||
emit(const ActivitySearching());
|
||||
}
|
||||
|
||||
|
||||
final searchResults = await _placesService.searchActivities(
|
||||
destination: event.destination,
|
||||
tripId: event.tripId,
|
||||
category: event.category,
|
||||
maxResults: event.maxResults ?? 20, // Par défaut 20, ou utiliser la valeur spécifiée
|
||||
maxResults:
|
||||
event.maxResults ??
|
||||
20, // Par défaut 20, ou utiliser la valeur spécifiée
|
||||
offset: event.offset ?? 0, // Par défaut 0
|
||||
);
|
||||
|
||||
|
||||
List<Activity> finalResults;
|
||||
|
||||
|
||||
// Si on doit ajouter aux résultats existants
|
||||
if (event.appendToExisting && state is ActivitySearchResults) {
|
||||
final currentState = state as ActivitySearchResults;
|
||||
@@ -117,15 +151,17 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
} else {
|
||||
finalResults = searchResults;
|
||||
}
|
||||
|
||||
|
||||
// Mettre en cache les résultats
|
||||
ActivityCacheService().setCachedActivities(event.tripId, finalResults);
|
||||
|
||||
emit(ActivitySearchResults(
|
||||
searchResults: finalResults,
|
||||
query: event.category?.displayName ?? 'Toutes les activités',
|
||||
isLoading: false,
|
||||
));
|
||||
|
||||
emit(
|
||||
ActivitySearchResults(
|
||||
searchResults: finalResults,
|
||||
query: event.category?.displayName ?? 'Toutes les activités',
|
||||
isLoading: false,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
_errorService.logError('activity_bloc', 'Erreur recherche activités: $e');
|
||||
emit(const ActivityError('Impossible de rechercher les activités'));
|
||||
@@ -145,7 +181,7 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
} else {
|
||||
emit(const ActivitySearching());
|
||||
}
|
||||
|
||||
|
||||
final searchResults = await _placesService.searchActivitiesPaginated(
|
||||
latitude: event.latitude,
|
||||
longitude: event.longitude,
|
||||
@@ -153,10 +189,10 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
category: event.category,
|
||||
pageSize: event.maxResults ?? 20,
|
||||
);
|
||||
|
||||
|
||||
final activities = searchResults['activities'] as List<Activity>;
|
||||
List<Activity> finalResults;
|
||||
|
||||
|
||||
// Si on doit ajouter aux résultats existants
|
||||
if (event.appendToExisting && state is ActivitySearchResults) {
|
||||
final currentState = state as ActivitySearchResults;
|
||||
@@ -164,17 +200,22 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
} else {
|
||||
finalResults = activities;
|
||||
}
|
||||
|
||||
|
||||
// Mettre en cache les résultats
|
||||
ActivityCacheService().setCachedActivities(event.tripId, finalResults);
|
||||
|
||||
emit(ActivitySearchResults(
|
||||
searchResults: finalResults,
|
||||
query: event.category?.displayName ?? 'Toutes les activités',
|
||||
isLoading: false,
|
||||
));
|
||||
|
||||
emit(
|
||||
ActivitySearchResults(
|
||||
searchResults: finalResults,
|
||||
query: event.category?.displayName ?? 'Toutes les activités',
|
||||
isLoading: false,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
_errorService.logError('activity_bloc', 'Erreur recherche activités avec coordonnées: $e');
|
||||
_errorService.logError(
|
||||
'activity_bloc',
|
||||
'Erreur recherche activités avec coordonnées: $e',
|
||||
);
|
||||
emit(const ActivityError('Impossible de rechercher les activités'));
|
||||
}
|
||||
}
|
||||
@@ -186,20 +227,19 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
) async {
|
||||
try {
|
||||
emit(const ActivitySearching());
|
||||
|
||||
|
||||
final searchResults = await _placesService.searchActivitiesByText(
|
||||
query: event.query,
|
||||
destination: event.destination,
|
||||
tripId: event.tripId,
|
||||
);
|
||||
|
||||
|
||||
// Mettre en cache les résultats
|
||||
ActivityCacheService().setCachedActivities(event.tripId, searchResults);
|
||||
|
||||
emit(ActivitySearchResults(
|
||||
searchResults: searchResults,
|
||||
query: event.query,
|
||||
));
|
||||
|
||||
emit(
|
||||
ActivitySearchResults(searchResults: searchResults, query: event.query),
|
||||
);
|
||||
} catch (e) {
|
||||
_errorService.logError('activity_bloc', 'Erreur recherche textuelle: $e');
|
||||
emit(const ActivityError('Impossible de rechercher les activités'));
|
||||
@@ -218,7 +258,7 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
event.activity.tripId,
|
||||
event.activity.placeId!,
|
||||
);
|
||||
|
||||
|
||||
if (existing != null) {
|
||||
emit(const ActivityError('Cette activité a déjà été ajoutée'));
|
||||
return;
|
||||
@@ -226,20 +266,27 @@ 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
|
||||
final currentState = state as ActivitySearchResults;
|
||||
// On garde l'état de recherche inchangé mais on ajoute l'info de l'activité ajoutée
|
||||
emit(
|
||||
currentState.copyWith(
|
||||
newlyAddedActivity: event.activity.copyWith(id: activityId),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Sinon, émettre l'état d'ajout réussi
|
||||
emit(ActivityAdded(
|
||||
activity: event.activity.copyWith(id: activityId),
|
||||
message: 'Activité ajoutée avec succès',
|
||||
));
|
||||
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 {
|
||||
@@ -263,7 +310,7 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
event.activity.tripId,
|
||||
event.activity.placeId!,
|
||||
);
|
||||
|
||||
|
||||
if (existing != null) {
|
||||
emit(const ActivityError('Cette activité a déjà été ajoutée'));
|
||||
return;
|
||||
@@ -271,7 +318,7 @@ 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
|
||||
// en supprimant l'activité des résultats
|
||||
@@ -280,20 +327,24 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
final updatedResults = currentState.searchResults
|
||||
.where((activity) => activity.id != event.googleActivityId)
|
||||
.toList();
|
||||
|
||||
emit(ActivitySearchResults(
|
||||
searchResults: updatedResults,
|
||||
query: currentState.query,
|
||||
isLoading: false,
|
||||
));
|
||||
|
||||
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',
|
||||
));
|
||||
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 {
|
||||
@@ -313,35 +364,39 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
try {
|
||||
// Filter out existing activities
|
||||
final filteredActivities = <Activity>[];
|
||||
|
||||
emit(ActivityBatchAdding(
|
||||
activitiesToAdd: event.activities,
|
||||
progress: 0,
|
||||
total: event.activities.length,
|
||||
));
|
||||
|
||||
|
||||
emit(
|
||||
ActivityBatchAdding(
|
||||
activitiesToAdd: event.activities,
|
||||
progress: 0,
|
||||
total: event.activities.length,
|
||||
),
|
||||
);
|
||||
|
||||
for (int i = 0; i < event.activities.length; i++) {
|
||||
final activity = event.activities[i];
|
||||
|
||||
|
||||
if (activity.placeId != null) {
|
||||
final existing = await _repository.findExistingActivity(
|
||||
activity.tripId,
|
||||
activity.placeId!,
|
||||
);
|
||||
|
||||
|
||||
if (existing == null) {
|
||||
filteredActivities.add(activity);
|
||||
}
|
||||
} else {
|
||||
filteredActivities.add(activity);
|
||||
}
|
||||
|
||||
|
||||
// Update progress
|
||||
emit(ActivityBatchAdding(
|
||||
activitiesToAdd: event.activities,
|
||||
progress: i + 1,
|
||||
total: event.activities.length,
|
||||
));
|
||||
emit(
|
||||
ActivityBatchAdding(
|
||||
activitiesToAdd: event.activities,
|
||||
progress: i + 1,
|
||||
total: event.activities.length,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (filteredActivities.isEmpty) {
|
||||
@@ -350,12 +405,14 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
}
|
||||
|
||||
final addedIds = await _repository.addActivitiesBatch(filteredActivities);
|
||||
|
||||
|
||||
if (addedIds.isNotEmpty) {
|
||||
emit(ActivityOperationSuccess(
|
||||
'${addedIds.length} activité(s) ajoutée(s) avec succès',
|
||||
operationType: 'batch_add',
|
||||
));
|
||||
emit(
|
||||
ActivityOperationSuccess(
|
||||
'${addedIds.length} activité(s) ajoutée(s) avec succès',
|
||||
operationType: 'batch_add',
|
||||
),
|
||||
);
|
||||
// Reload activities
|
||||
add(LoadActivities(event.activities.first.tripId));
|
||||
} else {
|
||||
@@ -376,10 +433,12 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
// Show voting state
|
||||
if (state is ActivityLoaded) {
|
||||
final currentState = state as ActivityLoaded;
|
||||
emit(ActivityVoting(
|
||||
activityId: event.activityId,
|
||||
activities: currentState.activities,
|
||||
));
|
||||
emit(
|
||||
ActivityVoting(
|
||||
activityId: event.activityId,
|
||||
activities: currentState.activities,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final success = await _repository.voteForActivity(
|
||||
@@ -387,31 +446,35 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
event.userId,
|
||||
event.vote,
|
||||
);
|
||||
|
||||
|
||||
if (success) {
|
||||
emit(ActivityVoteRecorded(
|
||||
activityId: event.activityId,
|
||||
vote: event.vote,
|
||||
userId: event.userId,
|
||||
));
|
||||
|
||||
emit(
|
||||
ActivityVoteRecorded(
|
||||
activityId: event.activityId,
|
||||
vote: event.vote,
|
||||
userId: event.userId,
|
||||
),
|
||||
);
|
||||
|
||||
// Reload activities to reflect the new vote
|
||||
if (state is ActivityLoaded) {
|
||||
final currentState = state as ActivityLoaded;
|
||||
final activities = await _repository.getActivitiesByTrip(
|
||||
currentState.activities.first.tripId,
|
||||
);
|
||||
|
||||
emit(currentState.copyWith(
|
||||
activities: activities,
|
||||
filteredActivities: _applyFilters(
|
||||
activities,
|
||||
currentState.activeFilter,
|
||||
currentState.minRating,
|
||||
currentState.showVotedOnly,
|
||||
event.userId,
|
||||
|
||||
emit(
|
||||
currentState.copyWith(
|
||||
activities: activities,
|
||||
filteredActivities: _applyFilters(
|
||||
activities,
|
||||
currentState.activeFilter,
|
||||
currentState.minRating,
|
||||
currentState.showVotedOnly,
|
||||
event.userId,
|
||||
),
|
||||
),
|
||||
));
|
||||
);
|
||||
}
|
||||
} else {
|
||||
emit(const ActivityError('Impossible d\'enregistrer le vote'));
|
||||
@@ -429,13 +492,15 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
) async {
|
||||
try {
|
||||
final success = await _repository.deleteActivity(event.activityId);
|
||||
|
||||
|
||||
if (success) {
|
||||
emit(ActivityDeleted(
|
||||
activityId: event.activityId,
|
||||
message: 'Activité supprimée avec succès',
|
||||
));
|
||||
|
||||
emit(
|
||||
ActivityDeleted(
|
||||
activityId: event.activityId,
|
||||
message: 'Activité supprimée avec succès',
|
||||
),
|
||||
);
|
||||
|
||||
// Reload if we're on the activity list
|
||||
if (state is ActivityLoaded) {
|
||||
final currentState = state as ActivityLoaded;
|
||||
@@ -459,7 +524,7 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
) async {
|
||||
if (state is ActivityLoaded) {
|
||||
final currentState = state as ActivityLoaded;
|
||||
|
||||
|
||||
final filteredActivities = _applyFilters(
|
||||
currentState.activities,
|
||||
event.category,
|
||||
@@ -467,13 +532,15 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
event.showVotedOnly ?? false,
|
||||
'', // UserId would be needed for showVotedOnly filter
|
||||
);
|
||||
|
||||
emit(currentState.copyWith(
|
||||
filteredActivities: filteredActivities,
|
||||
activeFilter: event.category,
|
||||
minRating: event.minRating,
|
||||
showVotedOnly: event.showVotedOnly ?? false,
|
||||
));
|
||||
|
||||
emit(
|
||||
currentState.copyWith(
|
||||
filteredActivities: filteredActivities,
|
||||
activeFilter: event.category,
|
||||
minRating: event.minRating,
|
||||
showVotedOnly: event.showVotedOnly ?? false,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,20 +570,24 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
try {
|
||||
if (state is ActivityLoaded) {
|
||||
final currentState = state as ActivityLoaded;
|
||||
emit(ActivityUpdating(
|
||||
activityId: event.activity.id,
|
||||
activities: currentState.activities,
|
||||
));
|
||||
emit(
|
||||
ActivityUpdating(
|
||||
activityId: event.activity.id,
|
||||
activities: currentState.activities,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final success = await _repository.updateActivity(event.activity);
|
||||
|
||||
|
||||
if (success) {
|
||||
emit(const ActivityOperationSuccess(
|
||||
'Activité mise à jour avec succès',
|
||||
operationType: 'update',
|
||||
));
|
||||
|
||||
emit(
|
||||
const ActivityOperationSuccess(
|
||||
'Activité mise à jour avec succès',
|
||||
operationType: 'update',
|
||||
),
|
||||
);
|
||||
|
||||
// Reload activities
|
||||
add(LoadActivities(event.activity.tripId));
|
||||
} else {
|
||||
@@ -536,11 +607,13 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
try {
|
||||
// This would require extending the Activity model to include favorites
|
||||
// For now, we'll use the voting system as a favorite system
|
||||
add(VoteForActivity(
|
||||
activityId: event.activityId,
|
||||
userId: event.userId,
|
||||
vote: 1,
|
||||
));
|
||||
add(
|
||||
VoteForActivity(
|
||||
activityId: event.activityId,
|
||||
userId: event.userId,
|
||||
vote: 1,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
_errorService.logError('activity_bloc', 'Erreur favori: $e');
|
||||
emit(const ActivityError('Impossible de modifier les favoris'));
|
||||
@@ -558,7 +631,25 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
var filtered = activities;
|
||||
|
||||
if (category != null) {
|
||||
filtered = filtered.where((a) => a.category == category).toList();
|
||||
filtered = filtered.where((a) {
|
||||
// Check exact match (internal value)
|
||||
if (a.category == category) return true;
|
||||
|
||||
// Check display name match
|
||||
// Find the enum that matches the filter category (which is a display name)
|
||||
try {
|
||||
final categoryEnum = ActivityCategory.values.firstWhere(
|
||||
(e) => e.displayName == category,
|
||||
);
|
||||
// Check if activity category matches the enum's google type or display name
|
||||
return a.category == categoryEnum.googlePlaceType ||
|
||||
a.category == categoryEnum.displayName ||
|
||||
a.category.toLowerCase() == categoryEnum.name.toLowerCase();
|
||||
} catch (_) {
|
||||
// If no matching enum found, fallback to simple string comparison
|
||||
return a.category.toLowerCase() == category.toLowerCase();
|
||||
}
|
||||
}).toList();
|
||||
}
|
||||
|
||||
if (minRating != null) {
|
||||
@@ -580,18 +671,20 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
// 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,
|
||||
));
|
||||
emit(
|
||||
ActivitySearchResults(
|
||||
searchResults: updatedResults,
|
||||
query: currentState.query,
|
||||
isLoading: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -600,10 +693,12 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
||||
RestoreCachedSearchResults event,
|
||||
Emitter<ActivityState> emit,
|
||||
) async {
|
||||
emit(ActivitySearchResults(
|
||||
searchResults: event.searchResults,
|
||||
query: 'cached',
|
||||
isLoading: false,
|
||||
));
|
||||
emit(
|
||||
ActivitySearchResults(
|
||||
searchResults: event.searchResults,
|
||||
query: 'cached',
|
||||
isLoading: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,15 @@ class SearchActivities extends ActivityEvent {
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [tripId, destination, category, maxResults, offset, reset, appendToExisting];
|
||||
List<Object?> get props => [
|
||||
tripId,
|
||||
destination,
|
||||
category,
|
||||
maxResults,
|
||||
offset,
|
||||
reset,
|
||||
appendToExisting,
|
||||
];
|
||||
}
|
||||
|
||||
/// Event to search activities using coordinates directly (bypasses geocoding)
|
||||
@@ -76,7 +84,16 @@ class SearchActivitiesWithCoordinates extends ActivityEvent {
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [tripId, latitude, longitude, category, maxResults, offset, reset, appendToExisting];
|
||||
List<Object?> get props => [
|
||||
tripId,
|
||||
latitude,
|
||||
longitude,
|
||||
category,
|
||||
maxResults,
|
||||
offset,
|
||||
reset,
|
||||
appendToExisting,
|
||||
];
|
||||
}
|
||||
|
||||
/// Event to search activities by text query
|
||||
@@ -95,6 +112,21 @@ class SearchActivitiesByText extends ActivityEvent {
|
||||
List<Object> get props => [tripId, destination, query];
|
||||
}
|
||||
|
||||
class UpdateActivityDate extends ActivityEvent {
|
||||
final String tripId;
|
||||
final String activityId;
|
||||
final DateTime? date;
|
||||
|
||||
const UpdateActivityDate({
|
||||
required this.tripId,
|
||||
required this.activityId,
|
||||
this.date,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [tripId, activityId, date];
|
||||
}
|
||||
|
||||
/// Event to add a single activity to the trip
|
||||
class AddActivity extends ActivityEvent {
|
||||
final Activity activity;
|
||||
@@ -147,11 +179,7 @@ class FilterActivities extends ActivityEvent {
|
||||
final double? minRating;
|
||||
final bool? showVotedOnly;
|
||||
|
||||
const FilterActivities({
|
||||
this.category,
|
||||
this.minRating,
|
||||
this.showVotedOnly,
|
||||
});
|
||||
const FilterActivities({this.category, this.minRating, this.showVotedOnly});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [category, minRating, showVotedOnly];
|
||||
@@ -228,4 +256,4 @@ class AddActivityAndRemoveFromSearch extends ActivityEvent {
|
||||
|
||||
@override
|
||||
List<Object> get props => [activity, googleActivityId];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,9 @@ class ActivityLoaded extends ActivityState {
|
||||
|
||||
/// Gets activities by category
|
||||
List<Activity> getActivitiesByCategory(String category) {
|
||||
return activities.where((activity) => activity.category == category).toList();
|
||||
return activities
|
||||
.where((activity) => activity.category == category)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// Gets top rated activities
|
||||
@@ -77,14 +79,14 @@ class ActivityLoaded extends ActivityState {
|
||||
sorted.sort((a, b) {
|
||||
final aScore = a.totalVotes;
|
||||
final bScore = b.totalVotes;
|
||||
|
||||
|
||||
if (aScore != bScore) {
|
||||
return bScore.compareTo(aScore);
|
||||
}
|
||||
|
||||
|
||||
return (b.rating ?? 0).compareTo(a.rating ?? 0);
|
||||
});
|
||||
|
||||
|
||||
return sorted.take(limit).toList();
|
||||
}
|
||||
}
|
||||
@@ -94,26 +96,35 @@ class ActivitySearchResults extends ActivityState {
|
||||
final List<Activity> searchResults;
|
||||
final String query;
|
||||
final bool isLoading;
|
||||
final Activity? newlyAddedActivity;
|
||||
|
||||
const ActivitySearchResults({
|
||||
required this.searchResults,
|
||||
required this.query,
|
||||
this.isLoading = false,
|
||||
this.newlyAddedActivity,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [searchResults, query, isLoading];
|
||||
List<Object?> get props => [
|
||||
searchResults,
|
||||
query,
|
||||
isLoading,
|
||||
newlyAddedActivity,
|
||||
];
|
||||
|
||||
/// Creates a copy with optional modifications
|
||||
ActivitySearchResults copyWith({
|
||||
List<Activity>? searchResults,
|
||||
String? query,
|
||||
bool? isLoading,
|
||||
Activity? newlyAddedActivity,
|
||||
}) {
|
||||
return ActivitySearchResults(
|
||||
searchResults: searchResults ?? this.searchResults,
|
||||
query: query ?? this.query,
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
newlyAddedActivity: newlyAddedActivity ?? this.newlyAddedActivity,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -123,10 +134,7 @@ class ActivityOperationSuccess extends ActivityState {
|
||||
final String message;
|
||||
final String? operationType;
|
||||
|
||||
const ActivityOperationSuccess(
|
||||
this.message, {
|
||||
this.operationType,
|
||||
});
|
||||
const ActivityOperationSuccess(this.message, {this.operationType});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [message, operationType];
|
||||
@@ -138,11 +146,7 @@ class ActivityError extends ActivityState {
|
||||
final String? errorCode;
|
||||
final dynamic error;
|
||||
|
||||
const ActivityError(
|
||||
this.message, {
|
||||
this.errorCode,
|
||||
this.error,
|
||||
});
|
||||
const ActivityError(this.message, {this.errorCode, this.error});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [message, errorCode, error];
|
||||
@@ -153,10 +157,7 @@ class ActivityVoting extends ActivityState {
|
||||
final String activityId;
|
||||
final List<Activity> activities;
|
||||
|
||||
const ActivityVoting({
|
||||
required this.activityId,
|
||||
required this.activities,
|
||||
});
|
||||
const ActivityVoting({required this.activityId, required this.activities});
|
||||
|
||||
@override
|
||||
List<Object> get props => [activityId, activities];
|
||||
@@ -167,10 +168,7 @@ class ActivityUpdating extends ActivityState {
|
||||
final String activityId;
|
||||
final List<Activity> activities;
|
||||
|
||||
const ActivityUpdating({
|
||||
required this.activityId,
|
||||
required this.activities,
|
||||
});
|
||||
const ActivityUpdating({required this.activityId, required this.activities});
|
||||
|
||||
@override
|
||||
List<Object> get props => [activityId, activities];
|
||||
@@ -200,10 +198,7 @@ class ActivityAdded extends ActivityState {
|
||||
final Activity activity;
|
||||
final String message;
|
||||
|
||||
const ActivityAdded({
|
||||
required this.activity,
|
||||
required this.message,
|
||||
});
|
||||
const ActivityAdded({required this.activity, required this.message});
|
||||
|
||||
@override
|
||||
List<Object> get props => [activity, message];
|
||||
@@ -214,10 +209,7 @@ class ActivityDeleted extends ActivityState {
|
||||
final String activityId;
|
||||
final String message;
|
||||
|
||||
const ActivityDeleted({
|
||||
required this.activityId,
|
||||
required this.message,
|
||||
});
|
||||
const ActivityDeleted({required this.activityId, required this.message});
|
||||
|
||||
@override
|
||||
List<Object> get props => [activityId, message];
|
||||
@@ -237,4 +229,4 @@ class ActivityVoteRecorded extends ActivityState {
|
||||
|
||||
@override
|
||||
List<Object> get props => [activityId, vote, userId];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user