import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'package:em2rp/config/app_version.dart'; import 'package:url_launcher/url_launcher.dart'; /// Service pour gérer les mises à jour de l'application class UpdateService { // URL de votre version.json déployé sur Firebase Hosting static const String versionUrl = 'https://app.em2events.fr/version.json'; /// Vérifie si une mise à jour est disponible static Future checkForUpdate() async { try { // Récupérer la version actuelle depuis AppVersion final currentVersion = AppVersion.version; if (kDebugMode) { print('[UpdateService] Current version: $currentVersion'); } // Récupérer la version depuis le serveur (avec cache-busting) final timestamp = DateTime.now().millisecondsSinceEpoch; final response = await http.get( Uri.parse('$versionUrl?t=$timestamp'), headers: { 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', }, ).timeout(const Duration(seconds: 10)); if (response.statusCode == 200) { final data = json.decode(response.body); final serverVersion = data['version'] as String; if (kDebugMode) { print('[UpdateService] Server version: $serverVersion'); } // Comparer les versions if (_isNewerVersion(serverVersion, currentVersion)) { return UpdateInfo( currentVersion: currentVersion, newVersion: serverVersion, updateUrl: data['updateUrl'] as String?, releaseNotes: data['releaseNotes'] as String?, forceUpdate: data['forceUpdate'] as bool? ?? false, ); } } return null; } catch (e) { if (kDebugMode) { print('[UpdateService] Error checking for update: $e'); } return null; } } /// Compare deux versions sémantiques (x.y.z) /// Retourne true si newVersion > currentVersion static bool _isNewerVersion(String newVersion, String currentVersion) { final newParts = newVersion.split('.').map(int.parse).toList(); final currentParts = currentVersion.split('.').map(int.parse).toList(); // Comparer major if (newParts[0] > currentParts[0]) return true; if (newParts[0] < currentParts[0]) return false; // Comparer minor if (newParts[1] > currentParts[1]) return true; if (newParts[1] < currentParts[1]) return false; // Comparer patch return newParts[2] > currentParts[2]; } /// Force le rechargement de l'application (vide le cache) static Future reloadApp() async { if (kIsWeb) { // Pour le web, recharger la page en utilisant JavaScript final url = Uri.base; await launchUrl(url, webOnlyWindowName: '_self'); } } /// Vérification automatique au démarrage static Future checkOnStartup() async { // Attendre un peu avant de vérifier (pour ne pas ralentir le démarrage) await Future.delayed(const Duration(seconds: 2)); return await checkForUpdate(); } } /// Informations sur une mise à jour disponible class UpdateInfo { final String currentVersion; final String newVersion; final String? updateUrl; final String? releaseNotes; final bool forceUpdate; UpdateInfo({ required this.currentVersion, required this.newVersion, this.updateUrl, this.releaseNotes, this.forceUpdate = false, }); String get versionDifference { return 'Nouvelle version disponible'; } }