import 'dart:io'; import 'package:flutter/material.dart'; import 'package:kooltab2/utils/app_update_util.dart'; import 'package:ota_update/ota_update.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'app_config.dart'; class UpdateChecker { static bool _hasChecked = false; static Future check(BuildContext context) async { if (!Platform.isAndroid) return; if (_hasChecked) { debugPrint("Update already checked this boot"); return; } _hasChecked = true; final updater = AppUpdateUtil(serverUrl: kUpdateServerUrl); try { final update = await updater.checkForUpdate(); if (update == null) { debugPrint("No update available"); return; } debugPrint("Update available: ${update.version}"); if (!context.mounted) return; _showUpdateDialog(context, update); } catch (e) { debugPrint("Update check failed: $e"); } } static void _showUpdateDialog(BuildContext context, UpdateInfo update) { showDialog( context: context, barrierDismissible: !update.mandatory, builder: (_) => AlertDialog( title: const Text("Update available"), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Version ${update.version} is available."), const SizedBox(height: 12), Text(update.notes), ], ), actions: [ if (!update.mandatory) TextButton( onPressed: () => Navigator.pop(context), child: const Text("Later"), ), FilledButton( onPressed: () async { Navigator.pop(context); await _downloadAndInstall(update); }, child: const Text("Update"), ), ], ), ); } } Future _downloadAndInstall(UpdateInfo update) async { try { final url = update.download.startsWith("http") ? update.download : "$kUpdateServerUrl${update.download}"; OtaUpdate() .execute( url, destinationFilename: "update.apk", sha256checksum: update.sha256, ) .listen((OtaEvent event) { debugPrint("OTA status: ${event.status}"); debugPrint("OTA value: ${event.value}"); switch (event.status) { case OtaStatus.DOWNLOADING: final progress = double.tryParse(event.value ?? "0") ?? 0; debugPrint("Downloading ${progress.toStringAsFixed(0)}%"); break; case OtaStatus.INSTALLING: debugPrint("Installing update"); break; case OtaStatus.INSTALLATION_ERROR: debugPrint("Installation error: ${event.value}"); break; case OtaStatus.DOWNLOAD_ERROR: debugPrint("Download error: ${event.value}"); break; default: break; } }, onError: (e, stack) { debugPrint("OTA stream error: $e"); Sentry.captureException(e, stackTrace: stack); }); } catch (e, stack) { debugPrint("OTA update failed: $e"); Sentry.captureException(e, stackTrace: stack); } }