Files
umbrix/lib/features/app_update/notifier/app_update_notifier.dart
2026-01-20 13:44:26 +03:00

106 lines
4.3 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/foundation.dart';
import 'package:umbrix/core/app_info/app_info_provider.dart';
import 'package:umbrix/core/localization/locale_preferences.dart';
import 'package:umbrix/core/model/constants.dart';
import 'package:umbrix/core/preferences/preferences_provider.dart';
import 'package:umbrix/core/utils/preferences_utils.dart';
import 'package:umbrix/features/app_update/data/app_update_data_providers.dart';
import 'package:umbrix/features/app_update/model/app_update_failure.dart';
import 'package:umbrix/features/app_update/model/remote_version_entity.dart';
import 'package:umbrix/features/app_update/notifier/app_update_state.dart';
import 'package:umbrix/utils/utils.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:upgrader/upgrader.dart';
import 'package:version/version.dart';
part 'app_update_notifier.g.dart';
const _debugUpgrader = true;
@riverpod
Upgrader upgrader(UpgraderRef ref) => Upgrader(
appcastConfig: AppcastConfiguration(url: Constants.appCastUrl),
debugLogging: _debugUpgrader && kDebugMode,
durationUntilAlertAgain: const Duration(hours: 12),
messages: UpgraderMessages(
code: ref.watch(localePreferencesProvider).languageCode,
),
);
@Riverpod(keepAlive: true)
class AppUpdateNotifier extends _$AppUpdateNotifier with AppLogger {
@override
AppUpdateState build() => const AppUpdateState.initial();
PreferencesEntry<String?, dynamic> get _ignoreReleasePref => PreferencesEntry(
preferences: ref.read(sharedPreferencesProvider).requireValue,
key: 'ignored_release_version',
defaultValue: null,
);
Future<AppUpdateState> check() async {
loggy.debug("checking for update");
state = const AppUpdateState.checking();
final appInfo = ref.watch(appInfoProvider).requireValue;
if (!appInfo.release.allowCustomUpdateChecker) {
loggy.debug(
"custom update checkers are not allowed for [${appInfo.release.name}] release",
);
return state = const AppUpdateState.disabled();
}
return ref.watch(appUpdateRepositoryProvider).getLatestVersion().match(
(err) {
loggy.warning("failed to get latest version", err);
return state = AppUpdateState.error(err);
},
(remote) {
try {
final latestVersion = Version.parse(remote.version);
final currentVersion = Version.parse(appInfo.version);
if (latestVersion > currentVersion) {
if (remote.version == _ignoreReleasePref.read()) {
loggy.debug("ignored release [${remote.version}]");
return state = AppUpdateStateIgnored(remote);
}
loggy.debug("new version available: $remote");
return state = AppUpdateState.available(remote);
}
loggy.info(
"already using latest version[$currentVersion], remote: [${remote.version}]",
);
return state = const AppUpdateState.notAvailable();
} catch (error, stackTrace) {
loggy.warning("error parsing versions", error, stackTrace);
return state = AppUpdateState.error(
AppUpdateFailure.unexpected(error, stackTrace),
);
}
},
).run();
}
Future<void> ignoreRelease(RemoteVersionEntity version) async {
loggy.debug("ignoring release [${version.version}]");
await _ignoreReleasePref.write(version.version);
state = AppUpdateStateIgnored(version);
}
/// Тихая проверка обновлений (без изменения UI состояния если нет обновлений)
/// Используется при запуске приложения
Future<void> checkSilently() async {
loggy.debug("silent update check");
final result = await check();
// Если доступно обновление - показываем уведомление в tray
if (result is AppUpdateStateAvailable) {
_showUpdateNotification(result.versionInfo);
}
}
void _showUpdateNotification(RemoteVersionEntity version) {
loggy.warning("🚀 ДОСТУПНО ОБНОВЛЕНИЕ: ${version.version}");
loggy.warning("📦 Перейдите в Настройки → О программе для установки");
// TODO: Добавить уведомление в system tray
}
}