diff --git a/lib/blocs/activity/activity_bloc.dart b/lib/blocs/activity/activity_bloc.dart index ad95afb..86beb4c 100644 --- a/lib/blocs/activity/activity_bloc.dart +++ b/lib/blocs/activity/activity_bloc.dart @@ -174,7 +174,11 @@ class ActivityBloc extends Bloc { 'Erreur recherche activités: $e', stackTrace, ); - emit(const ActivityError('Impossible de rechercher les activités')); + // Extraire le message d'erreur si disponible + final errorMessage = e.toString().replaceAll('Exception: ', ''); + emit( + ActivityError('Impossible de rechercher les activités: $errorMessage'), + ); } } diff --git a/lib/services/activity_places_service.dart b/lib/services/activity_places_service.dart index b45351a..2773761 100644 --- a/lib/services/activity_places_service.dart +++ b/lib/services/activity_places_service.dart @@ -37,83 +37,75 @@ class ActivityPlacesService { int maxResults = 20, int offset = 0, }) async { - try { - LoggerService.info( - 'ActivityPlacesService: Recherche d\'activités pour: $destination (max: $maxResults, offset: $offset)', + LoggerService.info( + 'ActivityPlacesService: Recherche d\'activités pour: $destination (max: $maxResults, offset: $offset)', + ); + + // 1. Géocoder la destination + final coordinates = await _geocodeDestination(destination); + + // 2. Rechercher les activités par catégorie ou toutes les catégories + List allActivities = []; + + if (category != null) { + final activities = await _searchByCategory( + coordinates['lat']!, + coordinates['lng']!, + category, + tripId, + radius, ); + allActivities.addAll(activities); + } else { + // Rechercher dans toutes les catégories principales + final mainCategories = [ + ActivityCategory.attraction, + ActivityCategory.museum, + ActivityCategory.restaurant, + ActivityCategory.culture, + ActivityCategory.nature, + ]; - // 1. Géocoder la destination - final coordinates = await _geocodeDestination(destination); - - // 2. Rechercher les activités par catégorie ou toutes les catégories - List allActivities = []; - - if (category != null) { + for (final cat in mainCategories) { final activities = await _searchByCategory( coordinates['lat']!, coordinates['lng']!, - category, + cat, tripId, radius, ); allActivities.addAll(activities); - } else { - // Rechercher dans toutes les catégories principales - final mainCategories = [ - ActivityCategory.attraction, - ActivityCategory.museum, - ActivityCategory.restaurant, - ActivityCategory.culture, - ActivityCategory.nature, - ]; - - for (final cat in mainCategories) { - final activities = await _searchByCategory( - coordinates['lat']!, - coordinates['lng']!, - cat, - tripId, - radius, - ); - allActivities.addAll(activities); - } } + } - // 3. Supprimer les doublons et trier par note - final uniqueActivities = _removeDuplicates(allActivities); - uniqueActivities.sort((a, b) => (b.rating ?? 0).compareTo(a.rating ?? 0)); + // 3. Supprimer les doublons et trier par note + final uniqueActivities = _removeDuplicates(allActivities); + uniqueActivities.sort((a, b) => (b.rating ?? 0).compareTo(a.rating ?? 0)); + LoggerService.info( + 'ActivityPlacesService: ${uniqueActivities.length} activités trouvées au total', + ); + + // 4. Appliquer la pagination + final startIndex = offset; + final endIndex = (startIndex + maxResults).clamp( + 0, + uniqueActivities.length, + ); + + if (startIndex >= uniqueActivities.length) { LoggerService.info( - 'ActivityPlacesService: ${uniqueActivities.length} activités trouvées au total', + 'ActivityPlacesService: Offset $startIndex dépasse le nombre total (${uniqueActivities.length})', ); - - // 4. Appliquer la pagination - final startIndex = offset; - final endIndex = (startIndex + maxResults).clamp( - 0, - uniqueActivities.length, - ); - - if (startIndex >= uniqueActivities.length) { - LoggerService.info( - 'ActivityPlacesService: Offset $startIndex dépasse le nombre total (${uniqueActivities.length})', - ); - return []; - } - - final paginatedResults = uniqueActivities.sublist(startIndex, endIndex); - LoggerService.info( - 'ActivityPlacesService: Retour de ${paginatedResults.length} activités (offset: $offset, max: $maxResults)', - ); - - return paginatedResults; - } catch (e) { - LoggerService.error( - 'ActivityPlacesService: Erreur lors de la recherche: $e', - ); - _errorService.logError('activity_places_service', e); return []; } + + final paginatedResults = uniqueActivities.sublist(startIndex, endIndex); + LoggerService.info( + 'ActivityPlacesService: Retour de ${paginatedResults.length} activités (offset: $offset, max: $maxResults)', + ); + + return paginatedResults; } /// Géocode une destination pour obtenir les coordonnées @@ -191,50 +183,52 @@ class ActivityPlacesService { String tripId, int radius, ) async { - try { - final url = - 'https://maps.googleapis.com/maps/api/place/nearbysearch/json' - '?location=$lat,$lng' - '&radius=$radius' - '&type=${category.googlePlaceType}' - '&key=$_apiKey' - '&language=fr'; + final url = + 'https://maps.googleapis.com/maps/api/place/nearbysearch/json' + '?location=$lat,$lng' + '&radius=$radius' + '&type=${category.googlePlaceType}' + '&key=$_apiKey' + '&language=fr'; - final response = await http.get(Uri.parse(url)); + final response = await http.get(Uri.parse(url)); - if (response.statusCode == 200) { - final data = json.decode(response.body); + if (response.statusCode == 200) { + final data = json.decode(response.body); - if (data['status'] == 'OK') { - final List activities = []; + if (data['status'] == 'OK') { + final List activities = []; - for (final place in data['results']) { - try { - final activity = await _convertPlaceToActivity( - place, - tripId, - category, - ); - if (activity != null) { - activities.add(activity); - } - } catch (e) { - LoggerService.error( - 'ActivityPlacesService: Erreur conversion place: $e', - ); + for (final place in data['results']) { + try { + final activity = await _convertPlaceToActivity( + place, + tripId, + category, + ); + if (activity != null) { + activities.add(activity); } + } catch (e) { + LoggerService.error( + 'ActivityPlacesService: Erreur conversion place: $e', + ); } - - return activities; } - } - return []; - } catch (e) { - LoggerService.error( - 'ActivityPlacesService: Erreur recherche par catégorie: $e', - ); - return []; + return activities; + } else if (data['status'] == 'ZERO_RESULTS') { + return []; + } else { + LoggerService.error( + 'ActivityPlacesService: Erreur API Places: ${data['status']} - ${data['error_message']}', + ); + throw Exception( + 'API Places Error: ${data['status']} - ${data['error_message']}', + ); + } + } else { + throw Exception('Erreur HTTP ${response.statusCode}'); } } @@ -357,62 +351,62 @@ class ActivityPlacesService { required String tripId, int radius = 5000, }) async { - try { - LoggerService.info( - 'ActivityPlacesService: Recherche textuelle: $query à $destination', - ); + LoggerService.info( + 'ActivityPlacesService: Recherche textuelle: $query à $destination', + ); - // Géocoder la destination - final coordinates = await _geocodeDestination(destination); + // Géocoder la destination + final coordinates = await _geocodeDestination(destination); - final encodedQuery = Uri.encodeComponent(query); - final url = - 'https://maps.googleapis.com/maps/api/place/textsearch/json' - '?query=$encodedQuery in $destination' - '&location=${coordinates['lat']},${coordinates['lng']}' - '&radius=$radius' - '&key=$_apiKey' - '&language=fr'; + final encodedQuery = Uri.encodeComponent(query); + final url = + 'https://maps.googleapis.com/maps/api/place/textsearch/json' + '?query=$encodedQuery in $destination' + '&location=${coordinates['lat']},${coordinates['lng']}' + '&radius=$radius' + '&key=$_apiKey' + '&language=fr'; - final response = await http.get(Uri.parse(url)); + final response = await http.get(Uri.parse(url)); - if (response.statusCode == 200) { - final data = json.decode(response.body); + if (response.statusCode == 200) { + final data = json.decode(response.body); - if (data['status'] == 'OK') { - final List activities = []; + if (data['status'] == 'OK') { + final List activities = []; - for (final place in data['results']) { - try { - // Déterminer la catégorie basée sur les types du lieu - final types = List.from(place['types'] ?? []); - final category = _determineCategoryFromTypes(types); + for (final place in data['results']) { + try { + // Déterminer la catégorie basée sur les types du lieu + final types = List.from(place['types'] ?? []); + final category = _determineCategoryFromTypes(types); - final activity = await _convertPlaceToActivity( - place, - tripId, - category, - ); - if (activity != null) { - activities.add(activity); - } - } catch (e) { - LoggerService.error( - 'ActivityPlacesService: Erreur conversion place: $e', - ); + final activity = await _convertPlaceToActivity( + place, + tripId, + category, + ); + if (activity != null) { + activities.add(activity); } + } catch (e) { + LoggerService.error( + 'ActivityPlacesService: Erreur conversion place: $e', + ); } - - return activities; } - } - return []; - } catch (e) { - LoggerService.error( - 'ActivityPlacesService: Erreur recherche textuelle: $e', - ); - return []; + return activities; + } else if (data['status'] == 'ZERO_RESULTS') { + return []; + } else { + LoggerService.error( + 'ActivityPlacesService: Erreur API Places Text Search: ${data['status']}', + ); + throw Exception('API Error: ${data['status']}'); + } + } else { + throw Exception('Erreur HTTP ${response.statusCode}'); } } @@ -523,70 +517,63 @@ class ActivityPlacesService { int pageSize, String? nextPageToken, ) async { - try { - String url = - 'https://maps.googleapis.com/maps/api/place/nearbysearch/json' - '?location=$lat,$lng' - '&radius=$radius' - '&type=${category.googlePlaceType}' - '&key=$_apiKey' - '&language=fr'; + String url = + 'https://maps.googleapis.com/maps/api/place/nearbysearch/json' + '?location=$lat,$lng' + '&radius=$radius' + '&type=${category.googlePlaceType}' + '&key=$_apiKey' + '&language=fr'; - if (nextPageToken != null) { - url += '&pagetoken=$nextPageToken'; - } + if (nextPageToken != null) { + url += '&pagetoken=$nextPageToken'; + } - final response = await http.get(Uri.parse(url)); + final response = await http.get(Uri.parse(url)); - if (response.statusCode == 200) { - final data = json.decode(response.body); + if (response.statusCode == 200) { + final data = json.decode(response.body); - if (data['status'] == 'OK') { - final List activities = []; - final results = data['results'] as List? ?? []; + if (data['status'] == 'OK') { + final List activities = []; + final results = data['results'] as List? ?? []; - // Limiter à pageSize résultats - final limitedResults = results.take(pageSize).toList(); + // Limiter à pageSize résultats + final limitedResults = results.take(pageSize).toList(); - for (final place in limitedResults) { - try { - final activity = await _convertPlaceToActivity( - place, - tripId, - category, - ); - if (activity != null) { - activities.add(activity); - } - } catch (e) { - LoggerService.error( - 'ActivityPlacesService: Erreur conversion place: $e', - ); + for (final place in limitedResults) { + try { + final activity = await _convertPlaceToActivity( + place, + tripId, + category, + ); + if (activity != null) { + activities.add(activity); } + } catch (e) { + LoggerService.error( + 'ActivityPlacesService: Erreur conversion place: $e', + ); } - - return { - 'activities': activities, - 'nextPageToken': data['next_page_token'], - 'hasMoreData': data['next_page_token'] != null, - }; } - } - return { - 'activities': [], - 'nextPageToken': null, - 'hasMoreData': false, - }; - } catch (e) { - LoggerService.error( - 'ActivityPlacesService: Erreur recherche catégorie paginée: $e', - ); - return { - 'activities': [], - 'nextPageToken': null, - 'hasMoreData': false, - }; + return { + 'activities': activities, + 'nextPageToken': data['next_page_token'], + 'hasMoreData': data['next_page_token'] != null, + }; + } else if (data['status'] == 'ZERO_RESULTS') { + return { + 'activities': [], + 'nextPageToken': null, + 'hasMoreData': false, + }; + } else { + throw Exception('API Error: ${data['status']}'); + } + } else { + throw Exception('Erreur HTTP ${response.statusCode}'); } } @@ -599,75 +586,68 @@ class ActivityPlacesService { int pageSize, String? nextPageToken, ) async { - try { - // Pour toutes les catégories, on utilise une recherche plus générale - String url = - 'https://maps.googleapis.com/maps/api/place/nearbysearch/json' - '?location=$lat,$lng' - '&radius=$radius' - '&type=tourist_attraction' - '&key=$_apiKey' - '&language=fr'; + // Pour toutes les catégories, on utilise une recherche plus générale + String url = + 'https://maps.googleapis.com/maps/api/place/nearbysearch/json' + '?location=$lat,$lng' + '&radius=$radius' + '&type=tourist_attraction' + '&key=$_apiKey' + '&language=fr'; - if (nextPageToken != null) { - url += '&pagetoken=$nextPageToken'; - } + if (nextPageToken != null) { + url += '&pagetoken=$nextPageToken'; + } - final response = await http.get(Uri.parse(url)); + final response = await http.get(Uri.parse(url)); - if (response.statusCode == 200) { - final data = json.decode(response.body); + if (response.statusCode == 200) { + final data = json.decode(response.body); - if (data['status'] == 'OK') { - final List activities = []; - final results = data['results'] as List? ?? []; + if (data['status'] == 'OK') { + final List activities = []; + final results = data['results'] as List? ?? []; - // Limiter à pageSize résultats - final limitedResults = results.take(pageSize).toList(); + // Limiter à pageSize résultats + final limitedResults = results.take(pageSize).toList(); - for (final place in limitedResults) { - try { - // Déterminer la catégorie basée sur les types du lieu - final types = List.from(place['types'] ?? []); - final category = _determineCategoryFromTypes(types); + for (final place in limitedResults) { + try { + // Déterminer la catégorie basée sur les types du lieu + final types = List.from(place['types'] ?? []); + final category = _determineCategoryFromTypes(types); - final activity = await _convertPlaceToActivity( - place, - tripId, - category, - ); - if (activity != null) { - activities.add(activity); - } - } catch (e) { - LoggerService.error( - 'ActivityPlacesService: Erreur conversion place: $e', - ); + final activity = await _convertPlaceToActivity( + place, + tripId, + category, + ); + if (activity != null) { + activities.add(activity); } + } catch (e) { + LoggerService.error( + 'ActivityPlacesService: Erreur conversion place: $e', + ); } - - return { - 'activities': activities, - 'nextPageToken': data['next_page_token'], - 'hasMoreData': data['next_page_token'] != null, - }; } - } - return { - 'activities': [], - 'nextPageToken': null, - 'hasMoreData': false, - }; - } catch (e) { - LoggerService.error( - 'ActivityPlacesService: Erreur recherche toutes catégories paginée: $e', - ); - return { - 'activities': [], - 'nextPageToken': null, - 'hasMoreData': false, - }; + return { + 'activities': activities, + 'nextPageToken': data['next_page_token'], + 'hasMoreData': data['next_page_token'] != null, + }; + } else if (data['status'] == 'ZERO_RESULTS') { + return { + 'activities': [], + 'nextPageToken': null, + 'hasMoreData': false, + }; + } else { + throw Exception('API Error: ${data['status']}'); + } + } else { + throw Exception('Erreur HTTP ${response.statusCode}'); } } } diff --git a/pubspec.yaml b/pubspec.yaml index 61eba96..6aff066 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.3+1 +version: 2025.12.1+1 environment: sdk: ^3.9.2