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:
157
lib/blocs/activity/google_activities/google_activity_bloc.dart
Normal file
157
lib/blocs/activity/google_activities/google_activity_bloc.dart
Normal 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());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import '../../../models/activity.dart';
|
||||
|
||||
/// Events pour les activités Google Places
|
||||
abstract class GoogleActivityEvent extends Equatable {
|
||||
const GoogleActivityEvent();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
/// Charger les activités Google Places
|
||||
class LoadGoogleActivities extends GoogleActivityEvent {
|
||||
final String tripId;
|
||||
final String destination;
|
||||
final ActivityCategory? category;
|
||||
|
||||
const LoadGoogleActivities({
|
||||
required this.tripId,
|
||||
required this.destination,
|
||||
this.category,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [tripId, destination, category];
|
||||
}
|
||||
|
||||
/// Charger plus d'activités Google (pagination)
|
||||
class LoadMoreGoogleActivities extends GoogleActivityEvent {
|
||||
final String tripId;
|
||||
final String destination;
|
||||
final ActivityCategory? category;
|
||||
final String? nextPageToken;
|
||||
|
||||
const LoadMoreGoogleActivities({
|
||||
required this.tripId,
|
||||
required this.destination,
|
||||
this.category,
|
||||
this.nextPageToken,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [tripId, destination, category, nextPageToken];
|
||||
}
|
||||
|
||||
/// Mettre à jour les activités Google
|
||||
class UpdateGoogleActivities extends GoogleActivityEvent {
|
||||
final List<Activity> activities;
|
||||
final String? nextPageToken;
|
||||
final bool hasMoreData;
|
||||
final String query;
|
||||
|
||||
const UpdateGoogleActivities({
|
||||
required this.activities,
|
||||
this.nextPageToken,
|
||||
required this.hasMoreData,
|
||||
required this.query,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [activities, nextPageToken, hasMoreData, query];
|
||||
}
|
||||
|
||||
/// Ajouter une activité Google à la DB
|
||||
class AddGoogleActivityToDb extends GoogleActivityEvent {
|
||||
final Activity activity;
|
||||
|
||||
const AddGoogleActivityToDb({required this.activity});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [activity];
|
||||
}
|
||||
|
||||
/// Rechercher des activités Google par catégorie
|
||||
class SearchGoogleActivitiesByCategory extends GoogleActivityEvent {
|
||||
final String tripId;
|
||||
final String destination;
|
||||
final ActivityCategory category;
|
||||
|
||||
const SearchGoogleActivitiesByCategory({
|
||||
required this.tripId,
|
||||
required this.destination,
|
||||
required this.category,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [tripId, destination, category];
|
||||
}
|
||||
|
||||
/// Effacer les résultats Google
|
||||
class ClearGoogleActivities extends GoogleActivityEvent {
|
||||
const ClearGoogleActivities();
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import '../../../models/activity.dart';
|
||||
|
||||
/// States pour les activités Google Places
|
||||
abstract class GoogleActivityState extends Equatable {
|
||||
const GoogleActivityState();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
/// État initial
|
||||
class GoogleActivityInitial extends GoogleActivityState {
|
||||
const GoogleActivityInitial();
|
||||
}
|
||||
|
||||
/// État de recherche
|
||||
class GoogleActivitySearching extends GoogleActivityState {
|
||||
const GoogleActivitySearching();
|
||||
}
|
||||
|
||||
/// État avec les activités Google chargées
|
||||
class GoogleActivityLoaded extends GoogleActivityState {
|
||||
final List<Activity> googleActivities;
|
||||
final String? nextPageToken;
|
||||
final bool hasMoreData;
|
||||
final String query;
|
||||
|
||||
const GoogleActivityLoaded({
|
||||
required this.googleActivities,
|
||||
this.nextPageToken,
|
||||
required this.hasMoreData,
|
||||
required this.query,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [googleActivities, nextPageToken, hasMoreData, query];
|
||||
|
||||
/// Créer une copie avec des modifications
|
||||
GoogleActivityLoaded copyWith({
|
||||
List<Activity>? googleActivities,
|
||||
String? nextPageToken,
|
||||
bool? hasMoreData,
|
||||
String? query,
|
||||
}) {
|
||||
return GoogleActivityLoaded(
|
||||
googleActivities: googleActivities ?? this.googleActivities,
|
||||
nextPageToken: nextPageToken ?? this.nextPageToken,
|
||||
hasMoreData: hasMoreData ?? this.hasMoreData,
|
||||
query: query ?? this.query,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// État de chargement de plus d'activités (pagination)
|
||||
class GoogleActivityLoadingMore extends GoogleActivityState {
|
||||
final List<Activity> currentActivities;
|
||||
final String query;
|
||||
|
||||
const GoogleActivityLoadingMore({
|
||||
required this.currentActivities,
|
||||
required this.query,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [currentActivities, query];
|
||||
}
|
||||
|
||||
/// État de succès d'opération
|
||||
class GoogleActivityOperationSuccess extends GoogleActivityState {
|
||||
final String message;
|
||||
|
||||
const GoogleActivityOperationSuccess(this.message);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [message];
|
||||
}
|
||||
|
||||
/// État d'erreur
|
||||
class GoogleActivityError extends GoogleActivityState {
|
||||
final String message;
|
||||
|
||||
const GoogleActivityError(this.message);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [message];
|
||||
}
|
||||
Reference in New Issue
Block a user