feat(activities): add autocomplete & what's new popup
All checks were successful
Deploy TravelMate (Full Mobile) / deploy-android (push) Successful in 2m6s
Deploy TravelMate (Full Mobile) / deploy-ios (push) Successful in 4m3s

Features:
- Add autocomplete support for Activity search with Google Places API.
- Add "What's New" popup system to showcase new features on app update.
- Implement logic to detect fresh installs vs updates.

Fixes:
- Switch API key handling to use Firebase config for Release mode support.
- Refactor map pins to be consistent (red pins).
- UI fixes on Create Trip page (overflow issues).

Refactor:
- Make WhatsNewDialog reusable by accepting features list as parameter.
This commit is contained in:
Van Leemput Dayron
2026-01-13 17:36:51 +01:00
parent b511ec5df0
commit e665dea82a
6 changed files with 522 additions and 30 deletions

View File

@@ -654,4 +654,72 @@ class ActivityPlacesService {
throw Exception('Erreur HTTP ${response.statusCode}');
}
}
/// Récupère des suggestions d'autocomplétion
Future<List<Map<String, String>>> fetchSuggestions({
required String query,
double? lat,
double? lng,
}) async {
if (query.isEmpty) return [];
try {
String url =
'https://maps.googleapis.com/maps/api/place/autocomplete/json'
'?input=${Uri.encodeComponent(query)}'
'&key=$_apiKey'
'&language=fr';
if (lat != null && lng != null) {
url += '&location=$lat,$lng&radius=50000'; // 50km bias
}
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
final data = json.decode(response.body);
if (data['status'] == 'OK') {
return (data['predictions'] as List).map<Map<String, String>>((p) {
return {
'description': p['description'] as String,
'placeId': p['place_id'] as String,
};
}).toList();
}
}
return [];
} catch (e) {
LoggerService.error('ActivityPlacesService: Erreur autocomplete: $e');
return [];
}
}
/// Récupère une activité via son Place ID
Future<Activity?> getActivityByPlaceId({
required String placeId,
required String tripId,
}) async {
try {
final details = await _getPlaceDetails(placeId);
if (details == null) return null;
// Créer une map simulant la structure "place" attendue par _convertPlaceToActivity
// Note: _getPlaceDetails retourne "result", qui est déjà ce qu'on veut,
// mais _convertPlaceToActivity attend le format "search result" qui a geometry au premier niveau.
// Heureusement _getPlaceDetails retourne une structure compatible pour geometry/photos etc.
// On doit s'assurer d'avoir les types pour déterminer la catégorie
final types = List<String>.from(details['types'] ?? []);
final category = _determineCategoryFromTypes(types);
return await _convertPlaceToActivity(
details, // details a la structure nécessaire (geometry, name, etc)
tripId,
category,
);
} catch (e) {
LoggerService.error('ActivityPlacesService: Erreur get details: $e');
return null;
}
}
}