import 'package:flutter/foundation.dart'; import 'package:ota_update/ota_update.dart'; import '../models/app_error.dart'; import '../models/settings.dart'; import '../services/settings_service.dart'; import '../utils/app_config.dart'; import '../utils/app_update_util.dart'; class SettingsViewModel extends ChangeNotifier { final SettingsService settingsService; SettingsViewModel({required this.settingsService}); AppSettings _settings = AppSettings.defaults; bool _isLoading = false; bool _hasLoaded = false; AppError? _error; final AppUpdateUtil _updater = AppUpdateUtil(serverUrl: kUpdateServerUrl); bool _checkingForUpdates = false; bool get checkingForUpdates => _checkingForUpdates; AppSettings get settings => _settings; bool get isLoading => _isLoading; bool get hasLoaded => _hasLoaded; AppError? get error => _error; Future ensureLoaded() async { if (_hasLoaded || _isLoading) return; await load(); } Future load() async { if (_isLoading) return; _isLoading = true; _error = null; notifyListeners(); try { _settings = await settingsService.getSettings(); } catch (e) { debugPrint('SettingsViewModel: load error: $e'); _error = AppError.loadSettings; } 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 : '$kUpdateServerUrl${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}'); } } } Future updatePinRequired(bool value) => _save(_settings.copyWith(pinRequired: value)); Future updateAutoLockEnabled(bool value) => _save(_settings.copyWith(autoLockEnabled: value)); Future updateThemeMode(AppThemeMode mode) => _save(_settings.copyWith(themeMode: mode)); Future updateLanguage(AppLanguage language) => _save(_settings.copyWith(language: language)); Future updateBarGridRows(int rows) => _save(_settings.copyWith(barGridRows: rows.clamp(2, 6).toInt())); Future _save(AppSettings updated) async { final previous = _settings; _settings = updated; _error = null; notifyListeners(); try { await settingsService.saveSettings(updated); } catch (e) { debugPrint('SettingsViewModel: save error: $e'); _settings = previous; _error = AppError.saveSettings; notifyListeners(); } } }