feat: Add TripImageService for automatic trip image management
- Implemented TripImageService to load missing images for trips, reload images, and clean up unused images. - Added functionality to get image statistics and clean up duplicate images. - Created utility scripts for manual image cleanup and diagnostics in Firebase Storage. - Introduced tests for image loading optimization and photo quality algorithms. - Updated dependencies in pubspec.yaml and pubspec.lock for image handling.
This commit is contained in:
150
lib/services/trip_image_service.dart
Normal file
150
lib/services/trip_image_service.dart
Normal file
@@ -0,0 +1,150 @@
|
||||
import 'package:travel_mate/models/trip.dart';
|
||||
import 'package:travel_mate/services/place_image_service.dart';
|
||||
import 'package:travel_mate/repositories/trip_repository.dart';
|
||||
import 'package:travel_mate/services/error_service.dart';
|
||||
|
||||
/// Service pour gérer le chargement automatique des images des voyages
|
||||
class TripImageService {
|
||||
final PlaceImageService _placeImageService = PlaceImageService();
|
||||
final TripRepository _tripRepository = TripRepository();
|
||||
final ErrorService _errorService = ErrorService();
|
||||
|
||||
/// Charge les images manquantes pour une liste de voyages
|
||||
Future<void> loadMissingImages(List<Trip> trips) async {
|
||||
final tripsWithoutImage = trips.where(
|
||||
(trip) => trip.imageUrl == null || trip.imageUrl!.isEmpty
|
||||
).toList();
|
||||
|
||||
if (tripsWithoutImage.isEmpty) {
|
||||
return;
|
||||
}
|
||||
for (final trip in tripsWithoutImage) {
|
||||
try {
|
||||
await _loadImageForTrip(trip);
|
||||
|
||||
// Petite pause entre les requêtes pour éviter de surcharger l'API
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
} catch (e) {
|
||||
_errorService.logError(
|
||||
'TripImageService',
|
||||
'Erreur lors du chargement d\'image pour ${trip.title}: $e',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Charge l'image pour un voyage spécifique
|
||||
Future<void> _loadImageForTrip(Trip trip) async {
|
||||
print('TripImageService: Recherche d\'image pour ${trip.title} (${trip.location})');
|
||||
|
||||
// D'abord vérifier si une image existe déjà dans le Storage
|
||||
String? imageUrl = await _placeImageService.getExistingImageUrl(trip.location);
|
||||
|
||||
// Si aucune image n'existe, en télécharger une nouvelle
|
||||
if (imageUrl == null) {
|
||||
print('TripImageService: Aucune image existante, téléchargement via Google Places...');
|
||||
imageUrl = await _placeImageService.getPlaceImageUrl(trip.location);
|
||||
}
|
||||
|
||||
if (imageUrl != null && trip.id != null) {
|
||||
// Mettre à jour le voyage avec l'image (existante ou nouvelle)
|
||||
final updatedTrip = trip.copyWith(
|
||||
imageUrl: imageUrl,
|
||||
updatedAt: DateTime.now(),
|
||||
);
|
||||
|
||||
await _tripRepository.updateTrip(trip.id!, updatedTrip);
|
||||
print('TripImageService: Image mise à jour pour ${trip.title}: $imageUrl');
|
||||
} else {
|
||||
print('TripImageService: Aucune image trouvée pour ${trip.title}');
|
||||
}
|
||||
}
|
||||
|
||||
/// Recharge l'image d'un voyage spécifique (force le rechargement)
|
||||
Future<String?> reloadImageForTrip(Trip trip) async {
|
||||
try {
|
||||
final imageUrl = await _placeImageService.getPlaceImageUrl(trip.location);
|
||||
|
||||
if (imageUrl != null && trip.id != null) {
|
||||
final updatedTrip = trip.copyWith(
|
||||
imageUrl: imageUrl,
|
||||
updatedAt: DateTime.now(),
|
||||
);
|
||||
|
||||
await _tripRepository.updateTrip(trip.id!, updatedTrip);
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (e) {
|
||||
_errorService.logError(
|
||||
'TripImageService',
|
||||
'Erreur lors du rechargement d\'image pour ${trip.title}: $e',
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Nettoie les images inutilisées du stockage
|
||||
Future<void> cleanupUnusedImages(String userId) async {
|
||||
try {
|
||||
// Récupérer tous les voyages de l'utilisateur
|
||||
final tripsStream = _tripRepository.getTripsByUserId(userId);
|
||||
final trips = await tripsStream.first;
|
||||
|
||||
// Extraire toutes les URLs d'images utilisées
|
||||
final usedImageUrls = trips
|
||||
.where((trip) => trip.imageUrl != null && trip.imageUrl!.isNotEmpty)
|
||||
.map((trip) => trip.imageUrl!)
|
||||
.toList();
|
||||
|
||||
// Nettoyer les images inutilisées
|
||||
await _placeImageService.cleanupUnusedImages(usedImageUrls);
|
||||
|
||||
} catch (e) {
|
||||
_errorService.logError(
|
||||
'TripImageService',
|
||||
'Erreur lors du nettoyage des images: $e',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtient des statistiques sur les images stockées
|
||||
Future<Map<String, dynamic>> getImageStatistics(String userId) async {
|
||||
try {
|
||||
final tripsStream = _tripRepository.getTripsByUserId(userId);
|
||||
final trips = await tripsStream.first;
|
||||
|
||||
final tripsWithImages = trips.where((trip) => trip.imageUrl != null && trip.imageUrl!.isNotEmpty).length;
|
||||
final tripsWithoutImages = trips.length - tripsWithImages;
|
||||
|
||||
return {
|
||||
'totalTrips': trips.length,
|
||||
'tripsWithImages': tripsWithImages,
|
||||
'tripsWithoutImages': tripsWithoutImages,
|
||||
'timestamp': DateTime.now().toIso8601String(),
|
||||
};
|
||||
} catch (e) {
|
||||
_errorService.logError('TripImageService', 'Erreur lors de l\'obtention des statistiques: $e');
|
||||
return {
|
||||
'error': e.toString(),
|
||||
'timestamp': DateTime.now().toIso8601String(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Nettoie spécifiquement les doublons d'images
|
||||
Future<void> cleanupDuplicateImages() async {
|
||||
try {
|
||||
print('TripImageService: Début du nettoyage des doublons...');
|
||||
await _placeImageService.cleanupDuplicateImages();
|
||||
print('TripImageService: Nettoyage des doublons terminé');
|
||||
} catch (e) {
|
||||
print('TripImageService: Erreur lors du nettoyage des doublons: $e');
|
||||
_errorService.logError(
|
||||
'TripImageService',
|
||||
'Erreur lors du nettoyage des doublons: $e',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user