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'; class SettingsViewModel extends ChangeNotifier { final SettingsService settingsService; SettingsViewModel({required this.settingsService}); AppSettings _settings = AppSettings.defaults; bool _isLoading = false; 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; String? get errorMessage => _errorMessage; Future ensureLoaded() async { if (_hasLoaded || _isLoading) return; await load(); } Future load() async { if (_isLoading) return; _isLoading = true; _errorMessage = null; notifyListeners(); try { _settings = await settingsService.getSettings(); } catch (_) { _errorMessage = 'Could not load settings.'; } finally { _hasLoaded = true; _isLoading = false; notifyListeners(); } } Future checkForUpdates() async { if (_checkingForUpdates) return null; _checkingForUpdates = true; notifyListeners(); try { return await _updater.checkForUpdate(); } finally { _checkingForUpdates = false; notifyListeners(); } } Future 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 updatePinRequired(bool value) => _save(_settings.copyWith(pinRequired: value)); Future updateThemeMode(AppThemeMode mode) => _save(_settings.copyWith(themeMode: mode)); Future _save(AppSettings updated) async { final previous = _settings; _settings = updated; _errorMessage = null; notifyListeners(); try { await settingsService.saveSettings(updated); } catch (_) { _settings = previous; _errorMessage = 'Could not save settings.'; notifyListeners(); } } }