Presearch google activities.
This commit is contained in:
@@ -2,6 +2,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import '../../models/activity.dart';
|
import '../../models/activity.dart';
|
||||||
import '../../repositories/activity_repository.dart';
|
import '../../repositories/activity_repository.dart';
|
||||||
import '../../services/activity_places_service.dart';
|
import '../../services/activity_places_service.dart';
|
||||||
|
import '../../services/activity_cache_service.dart';
|
||||||
import '../../services/error_service.dart';
|
import '../../services/error_service.dart';
|
||||||
import 'activity_event.dart';
|
import 'activity_event.dart';
|
||||||
import 'activity_state.dart';
|
import 'activity_state.dart';
|
||||||
@@ -34,6 +35,7 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
|||||||
on<ClearSearchResults>(_onClearSearchResults);
|
on<ClearSearchResults>(_onClearSearchResults);
|
||||||
on<UpdateActivity>(_onUpdateActivity);
|
on<UpdateActivity>(_onUpdateActivity);
|
||||||
on<ToggleActivityFavorite>(_onToggleActivityFavorite);
|
on<ToggleActivityFavorite>(_onToggleActivityFavorite);
|
||||||
|
on<RestoreCachedSearchResults>(_onRestoreCachedSearchResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles loading activities for a trip
|
/// Handles loading activities for a trip
|
||||||
@@ -88,6 +90,9 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
|||||||
finalResults = searchResults;
|
finalResults = searchResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mettre en cache les résultats
|
||||||
|
ActivityCacheService().setCachedActivities(event.tripId, finalResults);
|
||||||
|
|
||||||
emit(ActivitySearchResults(
|
emit(ActivitySearchResults(
|
||||||
searchResults: finalResults,
|
searchResults: finalResults,
|
||||||
query: event.category?.displayName ?? 'Toutes les activités',
|
query: event.category?.displayName ?? 'Toutes les activités',
|
||||||
@@ -132,6 +137,9 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
|||||||
finalResults = activities;
|
finalResults = activities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mettre en cache les résultats
|
||||||
|
ActivityCacheService().setCachedActivities(event.tripId, finalResults);
|
||||||
|
|
||||||
emit(ActivitySearchResults(
|
emit(ActivitySearchResults(
|
||||||
searchResults: finalResults,
|
searchResults: finalResults,
|
||||||
query: event.category?.displayName ?? 'Toutes les activités',
|
query: event.category?.displayName ?? 'Toutes les activités',
|
||||||
@@ -157,6 +165,9 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
|||||||
tripId: event.tripId,
|
tripId: event.tripId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Mettre en cache les résultats
|
||||||
|
ActivityCacheService().setCachedActivities(event.tripId, searchResults);
|
||||||
|
|
||||||
emit(ActivitySearchResults(
|
emit(ActivitySearchResults(
|
||||||
searchResults: searchResults,
|
searchResults: searchResults,
|
||||||
query: event.query,
|
query: event.query,
|
||||||
@@ -470,4 +481,16 @@ class ActivityBloc extends Bloc<ActivityEvent, ActivityState> {
|
|||||||
|
|
||||||
return filtered;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Restores cached search results
|
||||||
|
Future<void> _onRestoreCachedSearchResults(
|
||||||
|
RestoreCachedSearchResults event,
|
||||||
|
Emitter<ActivityState> emit,
|
||||||
|
) async {
|
||||||
|
emit(ActivitySearchResults(
|
||||||
|
searchResults: event.searchResults,
|
||||||
|
query: 'cached',
|
||||||
|
isLoading: false,
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -185,3 +185,13 @@ class ToggleActivityFavorite extends ActivityEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object> get props => [activityId, userId];
|
List<Object> get props => [activityId, userId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Event to restore cached search results
|
||||||
|
class RestoreCachedSearchResults extends ActivityEvent {
|
||||||
|
final List<Activity> searchResults;
|
||||||
|
|
||||||
|
const RestoreCachedSearchResults({required this.searchResults});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [searchResults];
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import '../../blocs/activity/activity_event.dart';
|
|||||||
import '../../blocs/activity/activity_state.dart';
|
import '../../blocs/activity/activity_state.dart';
|
||||||
import '../../models/trip.dart';
|
import '../../models/trip.dart';
|
||||||
import '../../models/activity.dart';
|
import '../../models/activity.dart';
|
||||||
|
import '../../services/activity_cache_service.dart';
|
||||||
import '../activities/add_activity_bottom_sheet.dart';
|
import '../activities/add_activity_bottom_sheet.dart';
|
||||||
|
|
||||||
class ActivitiesPage extends StatefulWidget {
|
class ActivitiesPage extends StatefulWidget {
|
||||||
@@ -20,6 +21,7 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin {
|
with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin {
|
||||||
late TabController _tabController;
|
late TabController _tabController;
|
||||||
final TextEditingController _searchController = TextEditingController();
|
final TextEditingController _searchController = TextEditingController();
|
||||||
|
final ActivityCacheService _cacheService = ActivityCacheService();
|
||||||
String _selectedCategory = 'Toutes les catégories';
|
String _selectedCategory = 'Toutes les catégories';
|
||||||
String _selectedPrice = 'Prix';
|
String _selectedPrice = 'Prix';
|
||||||
String _selectedRating = 'Note';
|
String _selectedRating = 'Note';
|
||||||
@@ -79,7 +81,18 @@ class _ActivitiesPageState extends State<ActivitiesPage>
|
|||||||
void _handleTabChange() {
|
void _handleTabChange() {
|
||||||
// Si on va sur l'onglet suggestions Google et qu'aucune recherche n'a été faite
|
// Si on va sur l'onglet suggestions Google et qu'aucune recherche n'a été faite
|
||||||
if (_tabController.index == 2 && !_googleSearchPerformed) {
|
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<ActivityBloc>().add(
|
||||||
|
RestoreCachedSearchResults(searchResults: cachedActivities),
|
||||||
|
);
|
||||||
|
_googleSearchPerformed = true;
|
||||||
|
} else {
|
||||||
|
// Sinon, faire une nouvelle recherche
|
||||||
|
_searchGoogleActivities();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class ActivityCard extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black.withOpacity(0.05),
|
color: Colors.black.withValues(alpha: 0.05),
|
||||||
blurRadius: 8,
|
blurRadius: 8,
|
||||||
offset: const Offset(0, 2),
|
offset: const Offset(0, 2),
|
||||||
),
|
),
|
||||||
@@ -74,7 +74,7 @@ class ActivityCard extends StatelessWidget {
|
|||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.black.withOpacity(0.7),
|
color: Colors.black.withValues(alpha: 0.7),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.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_bloc.dart';
|
||||||
import 'package:travel_mate/blocs/trip/trip_event.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/components/home/create_trip_content.dart';
|
||||||
import 'package:travel_mate/models/trip.dart';
|
import 'package:travel_mate/models/trip.dart';
|
||||||
import 'package:travel_mate/components/map/map_content.dart';
|
import 'package:travel_mate/components/map/map_content.dart';
|
||||||
import 'package:travel_mate/services/error_service.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:travel_mate/components/activities/activities_page.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
@@ -19,6 +23,47 @@ class ShowTripDetailsContent extends StatefulWidget {
|
|||||||
|
|
||||||
class _ShowTripDetailsContentState extends State<ShowTripDetailsContent> {
|
class _ShowTripDetailsContentState extends State<ShowTripDetailsContent> {
|
||||||
final ErrorService _errorService = ErrorService();
|
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<ActivityBloc>().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
|
// Calculer les jours restants avant le voyage
|
||||||
int get daysUntilTrip {
|
int get daysUntilTrip {
|
||||||
|
|||||||
62
lib/services/activity_cache_service.dart
Normal file
62
lib/services/activity_cache_service.dart
Normal file
@@ -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<String, List<Activity>> _cache = {};
|
||||||
|
|
||||||
|
// Timestamps pour invalider le cache après 30 minutes
|
||||||
|
final Map<String, DateTime> _cacheTimestamps = {};
|
||||||
|
|
||||||
|
static const Duration _cacheValidityDuration = Duration(minutes: 30);
|
||||||
|
|
||||||
|
/// Stocker les activités Google pour un voyage
|
||||||
|
void setCachedActivities(String tripId, List<Activity> activities) {
|
||||||
|
_cache[tripId] = activities;
|
||||||
|
_cacheTimestamps[tripId] = DateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Récupérer les activités en cache si elles sont toujours valides
|
||||||
|
List<Activity>? 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user