From 236327f6fa17ec4a67e263b9ba41796b8a29391f Mon Sep 17 00:00:00 2001 From: Dayron Date: Thu, 13 Nov 2025 09:27:37 +0100 Subject: [PATCH] Presearch google activities. --- lib/blocs/activity/activity_bloc.dart | 23 +++++++ lib/blocs/activity/activity_event.dart | 10 +++ .../activities/activities_page.dart | 15 ++++- lib/components/activities/activity_card.dart | 4 +- .../home/show_trip_details_content.dart | 45 ++++++++++++++ lib/services/activity_cache_service.dart | 62 +++++++++++++++++++ 6 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 lib/services/activity_cache_service.dart diff --git a/lib/blocs/activity/activity_bloc.dart b/lib/blocs/activity/activity_bloc.dart index 494574c..1ea7318 100644 --- a/lib/blocs/activity/activity_bloc.dart +++ b/lib/blocs/activity/activity_bloc.dart @@ -2,6 +2,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import '../../models/activity.dart'; import '../../repositories/activity_repository.dart'; import '../../services/activity_places_service.dart'; +import '../../services/activity_cache_service.dart'; import '../../services/error_service.dart'; import 'activity_event.dart'; import 'activity_state.dart'; @@ -34,6 +35,7 @@ class ActivityBloc extends Bloc { on(_onClearSearchResults); on(_onUpdateActivity); on(_onToggleActivityFavorite); + on(_onRestoreCachedSearchResults); } /// Handles loading activities for a trip @@ -88,6 +90,9 @@ class ActivityBloc extends Bloc { 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', @@ -132,6 +137,9 @@ class ActivityBloc extends Bloc { 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', @@ -157,6 +165,9 @@ class ActivityBloc extends Bloc { tripId: event.tripId, ); + // Mettre en cache les résultats + ActivityCacheService().setCachedActivities(event.tripId, searchResults); + emit(ActivitySearchResults( searchResults: searchResults, query: event.query, @@ -470,4 +481,16 @@ class ActivityBloc extends Bloc { return filtered; } + + /// Restores cached search results + Future _onRestoreCachedSearchResults( + RestoreCachedSearchResults event, + Emitter emit, + ) async { + emit(ActivitySearchResults( + searchResults: event.searchResults, + query: 'cached', + isLoading: false, + )); + } } diff --git a/lib/blocs/activity/activity_event.dart b/lib/blocs/activity/activity_event.dart index 858da9e..44b54eb 100644 --- a/lib/blocs/activity/activity_event.dart +++ b/lib/blocs/activity/activity_event.dart @@ -184,4 +184,14 @@ class ToggleActivityFavorite extends ActivityEvent { @override List get props => [activityId, userId]; +} + +/// Event to restore cached search results +class RestoreCachedSearchResults extends ActivityEvent { + final List searchResults; + + const RestoreCachedSearchResults({required this.searchResults}); + + @override + List get props => [searchResults]; } \ No newline at end of file diff --git a/lib/components/activities/activities_page.dart b/lib/components/activities/activities_page.dart index 68f736f..b9ee78f 100644 --- a/lib/components/activities/activities_page.dart +++ b/lib/components/activities/activities_page.dart @@ -5,6 +5,7 @@ import '../../blocs/activity/activity_event.dart'; import '../../blocs/activity/activity_state.dart'; import '../../models/trip.dart'; import '../../models/activity.dart'; +import '../../services/activity_cache_service.dart'; import '../activities/add_activity_bottom_sheet.dart'; class ActivitiesPage extends StatefulWidget { @@ -20,6 +21,7 @@ class _ActivitiesPageState extends State with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin { late TabController _tabController; final TextEditingController _searchController = TextEditingController(); + final ActivityCacheService _cacheService = ActivityCacheService(); String _selectedCategory = 'Toutes les catégories'; String _selectedPrice = 'Prix'; String _selectedRating = 'Note'; @@ -79,7 +81,18 @@ class _ActivitiesPageState extends State void _handleTabChange() { // Si on va sur l'onglet suggestions Google et qu'aucune recherche n'a été faite if (_tabController.index == 2 && !_googleSearchPerformed) { - _searchGoogleActivities(); + // Vérifier si on a des activités en cache + final cachedActivities = _cacheService.getCachedActivities(widget.trip.id!); + if (cachedActivities != null && cachedActivities.isNotEmpty) { + // Restaurer les activités en cache dans le BLoC + context.read().add( + RestoreCachedSearchResults(searchResults: cachedActivities), + ); + _googleSearchPerformed = true; + } else { + // Sinon, faire une nouvelle recherche + _searchGoogleActivities(); + } } } diff --git a/lib/components/activities/activity_card.dart b/lib/components/activities/activity_card.dart index 0418de2..d511a2d 100644 --- a/lib/components/activities/activity_card.dart +++ b/lib/components/activities/activity_card.dart @@ -29,7 +29,7 @@ class ActivityCard extends StatelessWidget { borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.05), + color: Colors.black.withValues(alpha: 0.05), blurRadius: 8, offset: const Offset(0, 2), ), @@ -74,7 +74,7 @@ class ActivityCard extends StatelessWidget { child: Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( - color: Colors.black.withOpacity(0.7), + color: Colors.black.withValues(alpha: 0.7), borderRadius: BorderRadius.circular(8), ), child: Text( diff --git a/lib/components/home/show_trip_details_content.dart b/lib/components/home/show_trip_details_content.dart index 2b79a32..f8df749 100644 --- a/lib/components/home/show_trip_details_content.dart +++ b/lib/components/home/show_trip_details_content.dart @@ -1,11 +1,15 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:travel_mate/blocs/trip/trip_bloc.dart'; import 'package:travel_mate/blocs/trip/trip_event.dart'; +import 'package:travel_mate/blocs/activity/activity_bloc.dart'; +import 'package:travel_mate/blocs/activity/activity_event.dart'; import 'package:travel_mate/components/home/create_trip_content.dart'; import 'package:travel_mate/models/trip.dart'; import 'package:travel_mate/components/map/map_content.dart'; import 'package:travel_mate/services/error_service.dart'; +import 'package:travel_mate/services/activity_cache_service.dart'; import 'package:travel_mate/components/activities/activities_page.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -19,6 +23,47 @@ class ShowTripDetailsContent extends StatefulWidget { class _ShowTripDetailsContentState extends State { final ErrorService _errorService = ErrorService(); + final ActivityCacheService _cacheService = ActivityCacheService(); + + @override + void initState() { + super.initState(); + // Lancer la recherche d'activités Google en arrière-plan + _preloadGoogleActivities(); + } + + /// Précharger les activités Google en arrière-plan + void _preloadGoogleActivities() { + // Attendre un moment avant de lancer la recherche pour ne pas bloquer l'UI + Future.delayed(const Duration(milliseconds: 500), () { + if (mounted && widget.trip.id != null) { + // Vérifier si on a déjà des activités en cache + if (_cacheService.hasCachedActivities(widget.trip.id!)) { + return; // Utiliser le cache + } + + // Sinon, lancer la recherche + context.read().add( + widget.trip.hasCoordinates + ? SearchActivitiesWithCoordinates( + tripId: widget.trip.id!, + latitude: widget.trip.latitude!, + longitude: widget.trip.longitude!, + category: null, + maxResults: 6, + reset: true, + ) + : SearchActivities( + tripId: widget.trip.id!, + destination: widget.trip.location, + category: null, + maxResults: 6, + reset: true, + ), + ); + } + }); + } // Calculer les jours restants avant le voyage int get daysUntilTrip { diff --git a/lib/services/activity_cache_service.dart b/lib/services/activity_cache_service.dart new file mode 100644 index 0000000..12f4924 --- /dev/null +++ b/lib/services/activity_cache_service.dart @@ -0,0 +1,62 @@ +import '../models/activity.dart'; + +class ActivityCacheService { + static final ActivityCacheService _instance = ActivityCacheService._internal(); + + factory ActivityCacheService() { + return _instance; + } + + ActivityCacheService._internal(); + + // Cache : tripId -> liste d'activités + final Map> _cache = {}; + + // Timestamps pour invalider le cache après 30 minutes + final Map _cacheTimestamps = {}; + + static const Duration _cacheValidityDuration = Duration(minutes: 30); + + /// Stocker les activités Google pour un voyage + void setCachedActivities(String tripId, List activities) { + _cache[tripId] = activities; + _cacheTimestamps[tripId] = DateTime.now(); + } + + /// Récupérer les activités en cache si elles sont toujours valides + List? getCachedActivities(String tripId) { + if (!_cache.containsKey(tripId)) { + return null; + } + + final timestamp = _cacheTimestamps[tripId]; + if (timestamp != null) { + final age = DateTime.now().difference(timestamp); + if (age > _cacheValidityDuration) { + // Cache expiré, nettoyer + _cache.remove(tripId); + _cacheTimestamps.remove(tripId); + return null; + } + } + + return _cache[tripId]; + } + + /// Vérifier si des activités sont en cache pour ce voyage + bool hasCachedActivities(String tripId) { + return getCachedActivities(tripId) != null; + } + + /// Nettoyer le cache pour un voyage spécifique + void clearCache(String tripId) { + _cache.remove(tripId); + _cacheTimestamps.remove(tripId); + } + + /// Nettoyer tout le cache + void clearAllCache() { + _cache.clear(); + _cacheTimestamps.clear(); + } +}