feat(activities): add autocomplete & what's new popup
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:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
68
lib/services/whats_new_service.dart
Normal file
68
lib/services/whats_new_service.dart
Normal file
@@ -0,0 +1,68 @@
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../../services/logger_service.dart';
|
||||
|
||||
class WhatsNewService {
|
||||
static const String _lastVersionKey = 'last_known_version';
|
||||
|
||||
/// Vérifie si le popup "Nouveautés" doit être affiché.
|
||||
///
|
||||
/// Retourne true si:
|
||||
/// - Ce n'est PAS une nouvelle installation
|
||||
/// - ET la version actuelle est plus récente que la version stockée
|
||||
Future<bool> shouldShowWhatsNew() async {
|
||||
try {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final packageInfo = await PackageInfo.fromPlatform();
|
||||
|
||||
final currentVersion = packageInfo.version;
|
||||
final lastVersion = prefs.getString(_lastVersionKey);
|
||||
|
||||
LoggerService.info(
|
||||
'WhatsNewService: Current=$currentVersion, Last=$lastVersion',
|
||||
);
|
||||
|
||||
// Cas 1: Première installation (lastVersion est null)
|
||||
if (lastVersion == null) {
|
||||
// On sauvegarde la version actuelle pour ne pas afficher le popup
|
||||
// la prochaine fois, et on retourne false maintenant.
|
||||
await prefs.setString(_lastVersionKey, currentVersion);
|
||||
LoggerService.info(
|
||||
'WhatsNewService: Fresh install detected. Marking version $currentVersion as read.',
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cas 2: Mise à jour (lastVersion != currentVersion)
|
||||
if (lastVersion != currentVersion) {
|
||||
// C'est une mise à jour, on doit afficher le popup.
|
||||
// On NE met PAS à jour la version ici, on attend que l'utilisateur ait vu le popup.
|
||||
LoggerService.info(
|
||||
'WhatsNewService: Update detected ($lastVersion -> $currentVersion). Showing popup.',
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cas 3: Même version
|
||||
return false;
|
||||
} catch (e) {
|
||||
LoggerService.error('WhatsNewService: Error checking version: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Marque la version actuelle comme "Vue".
|
||||
/// À appeler quand l'utilisateur ferme le popup.
|
||||
Future<void> markCurrentVersionAsSeen() async {
|
||||
try {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final packageInfo = await PackageInfo.fromPlatform();
|
||||
await prefs.setString(_lastVersionKey, packageInfo.version);
|
||||
LoggerService.info(
|
||||
'WhatsNewService: Version ${packageInfo.version} marked as seen.',
|
||||
);
|
||||
} catch (e) {
|
||||
LoggerService.error('WhatsNewService: Error marking seen: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user