Files
umbrix/lib/features/common/app_update_notifier.dart

126 lines
4.7 KiB
Dart
Raw Normal View History

2023-11-06 22:00:44 +03:30
import 'package:flutter/foundation.dart';
2023-09-20 22:38:38 +03:30
import 'package:freezed_annotation/freezed_annotation.dart';
2023-09-12 15:22:58 +03:30
import 'package:hiddify/core/core_providers.dart';
2023-09-20 22:38:38 +03:30
import 'package:hiddify/core/prefs/prefs.dart';
2023-09-12 15:22:58 +03:30
import 'package:hiddify/data/data_providers.dart';
import 'package:hiddify/domain/app/app.dart';
2023-11-06 22:00:44 +03:30
import 'package:hiddify/domain/constants.dart';
2023-10-05 21:49:36 +03:30
import 'package:hiddify/utils/pref_notifier.dart';
2023-09-12 15:22:58 +03:30
import 'package:hiddify/utils/utils.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
2023-11-06 22:00:44 +03:30
import 'package:upgrader/upgrader.dart';
2023-11-10 12:17:51 +03:30
import 'package:version/version.dart';
2023-09-12 15:22:58 +03:30
2023-09-20 22:38:38 +03:30
part 'app_update_notifier.freezed.dart';
2023-09-12 15:22:58 +03:30
part 'app_update_notifier.g.dart';
2023-11-06 22:00:44 +03:30
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(localeNotifierProvider).languageCode,
),
);
2023-09-20 22:38:38 +03:30
@freezed
class AppUpdateState with _$AppUpdateState {
const factory AppUpdateState.initial() = AppUpdateStateInitial;
const factory AppUpdateState.disabled() = AppUpdateStateDisabled;
const factory AppUpdateState.checking() = AppUpdateStateChecking;
const factory AppUpdateState.error(AppFailure error) = AppUpdateStateError;
const factory AppUpdateState.available(RemoteVersionInfo versionInfo) =
AppUpdateStateAvailable;
2023-10-05 21:49:36 +03:30
const factory AppUpdateState.ignored(RemoteVersionInfo versionInfo) =
AppUpdateStateIgnored;
2023-09-20 22:38:38 +03:30
const factory AppUpdateState.notAvailable() = AppUpdateStateNotAvailable;
}
2023-09-12 15:22:58 +03:30
@Riverpod(keepAlive: true)
class AppUpdateNotifier extends _$AppUpdateNotifier with AppLogger {
@override
2023-09-20 22:38:38 +03:30
AppUpdateState build() {
2023-11-06 22:00:44 +03:30
// _schedule();
2023-09-20 22:38:38 +03:30
return const AppUpdateState.initial();
}
2023-10-05 21:49:36 +03:30
Pref<String?, dynamic> get _ignoreReleasePref => Pref(
ref.read(sharedPreferencesProvider),
'ignored_release_version',
null,
);
2023-09-20 22:38:38 +03:30
Future<AppUpdateState> check() async {
2023-09-12 15:22:58 +03:30
loggy.debug("checking for update");
2023-09-20 22:38:38 +03:30
state = const AppUpdateState.checking();
final appInfo = ref.watch(appInfoProvider);
// TODO use market-specific update checkers
if (!appInfo.release.allowCustomUpdateChecker) {
loggy.debug(
"custom update checkers are not allowed for [${appInfo.release.name}] release",
);
2023-09-20 22:38:38 +03:30
return state = const AppUpdateState.disabled();
}
2023-11-10 14:53:12 +03:30
return ref.watch(appRepositoryProvider).getLatestVersion().match(
2023-09-20 22:38:38 +03:30
(err) {
2023-10-03 21:12:14 +03:30
loggy.warning("failed to get latest version", err);
2023-09-20 22:38:38 +03:30
return state = AppUpdateState.error(err);
2023-09-12 15:22:58 +03:30
},
(remote) {
2023-11-10 12:17:51 +03:30
try {
final latestVersion = Version.parse(remote.version);
final currentVersion = Version.parse(appInfo.version);
if (latestVersion > currentVersion) {
if (remote.version == _ignoreReleasePref.getValue()) {
loggy.debug("ignored release [${remote.version}]");
return state = AppUpdateStateIgnored(remote);
}
loggy.debug("new version available: $remote");
return state = AppUpdateState.available(remote);
2023-10-07 20:22:21 +03:30
}
2023-11-10 12:17:51 +03:30
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(
AppFailure.unexpected(error, stackTrace),
);
2023-09-12 15:22:58 +03:30
}
},
).run();
}
2023-09-20 22:38:38 +03:30
2023-10-05 21:49:36 +03:30
Future<void> ignoreRelease(RemoteVersionInfo versionInfo) async {
loggy.debug("ignoring release [${versionInfo.version}]");
await _ignoreReleasePref.update(versionInfo.version);
state = AppUpdateStateIgnored(versionInfo);
}
2023-11-06 22:00:44 +03:30
// Future<void> _schedule() async {
// loggy.debug("scheduling app update checker");
// return ref.read(cronServiceProvider).schedule(
// key: 'app_update',
// duration: const Duration(hours: 8),
// callback: () async {
// await Future.delayed(const Duration(seconds: 5));
// final updateState = await check();
// final context = rootNavigatorKey.currentContext;
// if (context != null && context.mounted) {
// if (updateState
// case AppUpdateStateAvailable(:final versionInfo)) {
// await NewVersionDialog(
// ref.read(appInfoProvider).presentVersion,
// versionInfo,
// ).show(context);
// }
// }
// },
// );
// }
2023-09-12 15:22:58 +03:30
}