Refactor ActivityCard UI and improve voting functionality

- Updated ActivityCard layout for better visual consistency and responsiveness.
- Simplified the category badge and adjusted styles for better readability.
- Enhanced the voting section with a progress bar and improved button designs.
- Added a new method in Activity model to check if all trip participants approved an activity.
- Improved error handling and validation in ActivityRepository for voting and fetching activities.
- Implemented pagination in ActivityPlacesService for activity searches.
- Removed outdated scripts for cleaning up duplicate images.
This commit is contained in:
Dayron
2025-11-04 20:21:54 +01:00
parent 8ff9e12fd4
commit f6c8432335
19 changed files with 2902 additions and 961 deletions

View File

@@ -0,0 +1,157 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../models/activity.dart';
import '../../../repositories/activity_repository.dart';
import '../../../services/activity_places_service.dart';
import '../../../services/error_service.dart';
import 'google_activity_event.dart';
import 'google_activity_state.dart';
/// BLoC pour gérer les activités Google Places
class GoogleActivityBloc extends Bloc<GoogleActivityEvent, GoogleActivityState> {
final ActivityPlacesService _placesService;
final ActivityRepository _repository;
final ErrorService _errorService;
GoogleActivityBloc({
required ActivityPlacesService placesService,
required ActivityRepository repository,
required ErrorService errorService,
}) : _placesService = placesService,
_repository = repository,
_errorService = errorService,
super(const GoogleActivityInitial()) {
on<LoadGoogleActivities>(_onLoadGoogleActivities);
on<LoadMoreGoogleActivities>(_onLoadMoreGoogleActivities);
on<UpdateGoogleActivities>(_onUpdateGoogleActivities);
on<AddGoogleActivityToDb>(_onAddGoogleActivityToDb);
on<SearchGoogleActivitiesByCategory>(_onSearchGoogleActivitiesByCategory);
on<ClearGoogleActivities>(_onClearGoogleActivities);
}
/// Charger les activités Google Places avec pagination (6 par page)
Future<void> _onLoadGoogleActivities(
LoadGoogleActivities event,
Emitter<GoogleActivityState> emit,
) async {
try {
emit(const GoogleActivitySearching());
final result = await _placesService.searchActivitiesPaginated(
destination: event.destination,
tripId: event.tripId,
category: event.category,
pageSize: 6,
);
emit(GoogleActivityLoaded(
googleActivities: result['activities'] as List<Activity>,
nextPageToken: result['nextPageToken'] as String?,
hasMoreData: result['hasMoreData'] as bool? ?? false,
query: event.category?.displayName ?? 'Toutes les activités',
));
} catch (e) {
_errorService.logError('google_activity_bloc', 'Erreur chargement activités Google: $e');
emit(const GoogleActivityError('Impossible de charger les activités Google'));
}
}
/// Charger plus d'activités (pagination)
Future<void> _onLoadMoreGoogleActivities(
LoadMoreGoogleActivities event,
Emitter<GoogleActivityState> emit,
) async {
if (state is! GoogleActivityLoaded) return;
final currentState = state as GoogleActivityLoaded;
if (!currentState.hasMoreData || currentState.nextPageToken == null) return;
try {
emit(GoogleActivityLoadingMore(
currentActivities: currentState.googleActivities,
query: currentState.query,
));
final result = await _placesService.searchActivitiesPaginated(
destination: event.destination,
tripId: event.tripId,
category: event.category,
pageSize: 6,
nextPageToken: currentState.nextPageToken,
);
final newActivities = result['activities'] as List<Activity>;
final allActivities = [...currentState.googleActivities, ...newActivities];
emit(GoogleActivityLoaded(
googleActivities: allActivities,
nextPageToken: result['nextPageToken'] as String?,
hasMoreData: result['hasMoreData'] as bool? ?? false,
query: currentState.query,
));
} catch (e) {
_errorService.logError('google_activity_bloc', 'Erreur chargement plus activités: $e');
emit(const GoogleActivityError('Impossible de charger plus d\'activités'));
}
}
/// Mettre à jour les activités Google
Future<void> _onUpdateGoogleActivities(
UpdateGoogleActivities event,
Emitter<GoogleActivityState> emit,
) async {
emit(GoogleActivityLoaded(
googleActivities: event.activities,
nextPageToken: event.nextPageToken,
hasMoreData: event.hasMoreData,
query: event.query,
));
}
/// Ajouter une activité Google à la base de données
Future<void> _onAddGoogleActivityToDb(
AddGoogleActivityToDb event,
Emitter<GoogleActivityState> emit,
) async {
try {
// Vérifier si l'activité existe déjà
if (event.activity.placeId != null) {
final existingActivity = await _repository.findExistingActivity(
event.activity.tripId,
event.activity.placeId!,
);
if (existingActivity != null) {
emit(const GoogleActivityOperationSuccess('Cette activité est déjà dans votre voyage'));
return;
}
}
await _repository.addActivity(event.activity);
emit(const GoogleActivityOperationSuccess('Activité ajoutée au voyage'));
} catch (e) {
_errorService.logError('google_activity_bloc', 'Erreur ajout activité: $e');
emit(const GoogleActivityError('Impossible d\'ajouter l\'activité'));
}
}
/// Rechercher par catégorie
Future<void> _onSearchGoogleActivitiesByCategory(
SearchGoogleActivitiesByCategory event,
Emitter<GoogleActivityState> emit,
) async {
add(LoadGoogleActivities(
tripId: event.tripId,
destination: event.destination,
category: event.category,
));
}
/// Effacer les activités Google
Future<void> _onClearGoogleActivities(
ClearGoogleActivities event,
Emitter<GoogleActivityState> emit,
) async {
emit(const GoogleActivityInitial());
}
}