feat: auto-updater

This commit is contained in:
2026-07-29 00:26:38 +02:00
parent e53bdf1c38
commit 4f9781e3ff
11 changed files with 461 additions and 195 deletions
+68
View File
@@ -1,4 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:kooltab2/utils/app_update_util.dart';
import 'package:ota_update/ota_update.dart';
import '../models/settings.dart';
import '../services/settings_service.dart';
@@ -13,6 +15,14 @@ class SettingsViewModel extends ChangeNotifier {
bool _hasLoaded = false;
String? _errorMessage;
final AppUpdateUtil _updater = AppUpdateUtil(
serverUrl: "https://updater.brammie15.dev",
);
bool _checkingForUpdates = false;
bool get checkingForUpdates => _checkingForUpdates;
AppSettings get settings => _settings;
bool get isLoading => _isLoading;
bool get hasLoaded => _hasLoaded;
@@ -41,6 +51,64 @@ class SettingsViewModel extends ChangeNotifier {
}
}
Future<UpdateInfo?> checkForUpdates() async {
if (_checkingForUpdates) return null;
_checkingForUpdates = true;
notifyListeners();
try {
return await _updater.checkForUpdate();
} finally {
_checkingForUpdates = false;
notifyListeners();
}
}
Future<void> installUpdate(
UpdateInfo update, {
void Function(double progress)? onProgress,
}) async {
final url = update.download.startsWith("http")
? update.download
: "https://updater.brammie15.dev${update.download}";
debugPrint("Download Url: ${url}");
final stream = OtaUpdate().execute(
url,
destinationFilename: "update.apk",
sha256checksum: update.sha256,
);
await for (final event in stream) {
debugPrint(
"OTA: ${event.status} ${event.value}",
);
if (event.status == OtaStatus.DOWNLOADING) {
final progress =
double.tryParse(event.value ?? "0") ?? 0;
onProgress?.call(progress / 100);
}
if (event.status == OtaStatus.DOWNLOAD_ERROR) {
throw Exception(
"Download failed: ${event.value}",
);
}
if (event.status == OtaStatus.INSTALLATION_ERROR) {
throw Exception(
"Installation failed: ${event.value}",
);
}
}
}
/// Just flips the preference flag. Caller is responsible for having
/// already set/verified the actual PIN via PinLockViewModel first.
Future<void> updatePinRequired(bool value) =>