mirror of
https://github.com/revanced/revanced-manager
synced 2024-05-14 13:56:57 +02:00
feat: progress bar for manager updates
This commit is contained in:
parent
c9adf1c492
commit
f5aafdb7d6
@ -1,3 +1,4 @@
|
|||||||
|
import 'dart:async';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ import 'package:timeago/timeago.dart';
|
|||||||
@lazySingleton
|
@lazySingleton
|
||||||
class RevancedAPI {
|
class RevancedAPI {
|
||||||
late Dio _dio = Dio();
|
late Dio _dio = Dio();
|
||||||
|
|
||||||
final _cacheOptions = CacheOptions(
|
final _cacheOptions = CacheOptions(
|
||||||
store: MemCacheStore(),
|
store: MemCacheStore(),
|
||||||
maxStale: const Duration(days: 1),
|
maxStale: const Duration(days: 1),
|
||||||
@ -164,6 +165,43 @@ class RevancedAPI {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StreamController<double> managerUpdateProgress = StreamController<double>();
|
||||||
|
|
||||||
|
void updateManagerDownloadProgress(int progress) {
|
||||||
|
managerUpdateProgress.add(progress.toDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<double> getManagerUpdateProgress() {
|
||||||
|
return managerUpdateProgress.stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void disposeManagerUpdateProgress() {
|
||||||
|
managerUpdateProgress.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<File?> downloadManager() async {
|
||||||
|
final Map<String, dynamic>? release = await _getLatestRelease(
|
||||||
|
'.apk',
|
||||||
|
'revanced/revanced-manager',
|
||||||
|
);
|
||||||
|
File? outputFile;
|
||||||
|
await for (final result in DefaultCacheManager().getFileStream(
|
||||||
|
release!['browser_download_url'] as String,
|
||||||
|
withProgress: true,
|
||||||
|
)) {
|
||||||
|
if (result is DownloadProgress) {
|
||||||
|
final totalSize = result.totalSize ?? 10000000;
|
||||||
|
final progress = (result.downloaded / totalSize * 100).round();
|
||||||
|
|
||||||
|
updateManagerDownloadProgress(progress);
|
||||||
|
} else if (result is FileInfo) {
|
||||||
|
// The download is complete; convert the FileInfo object to a File object
|
||||||
|
outputFile = File(result.file.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outputFile;
|
||||||
|
}
|
||||||
|
|
||||||
Future<String?> getLatestReleaseTime(
|
Future<String?> getLatestReleaseTime(
|
||||||
String extension,
|
String extension,
|
||||||
String repoName,
|
String repoName,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// ignore_for_file: use_build_context_synchronously
|
// ignore_for_file: use_build_context_synchronously
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:app_installer/app_installer.dart';
|
import 'package:app_installer/app_installer.dart';
|
||||||
@ -8,36 +9,43 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_i18n/flutter_i18n.dart';
|
import 'package:flutter_i18n/flutter_i18n.dart';
|
||||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
import 'package:injectable/injectable.dart';
|
import 'package:injectable/injectable.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:revanced_manager/app/app.locator.dart';
|
import 'package:revanced_manager/app/app.locator.dart';
|
||||||
import 'package:revanced_manager/app/app.router.dart';
|
import 'package:revanced_manager/app/app.router.dart';
|
||||||
import 'package:revanced_manager/models/patched_application.dart';
|
import 'package:revanced_manager/models/patched_application.dart';
|
||||||
import 'package:revanced_manager/services/github_api.dart';
|
import 'package:revanced_manager/services/github_api.dart';
|
||||||
import 'package:revanced_manager/services/manager_api.dart';
|
import 'package:revanced_manager/services/manager_api.dart';
|
||||||
import 'package:revanced_manager/services/patcher_api.dart';
|
import 'package:revanced_manager/services/patcher_api.dart';
|
||||||
|
import 'package:revanced_manager/services/revanced_api.dart';
|
||||||
import 'package:revanced_manager/services/toast.dart';
|
import 'package:revanced_manager/services/toast.dart';
|
||||||
import 'package:revanced_manager/ui/views/navigation/navigation_viewmodel.dart';
|
import 'package:revanced_manager/ui/views/navigation/navigation_viewmodel.dart';
|
||||||
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
|
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
|
||||||
import 'package:revanced_manager/ui/widgets/homeView/update_confirmation_dialog.dart';
|
import 'package:revanced_manager/ui/widgets/homeView/update_confirmation_dialog.dart';
|
||||||
|
import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart';
|
||||||
|
import 'package:revanced_manager/utils/about_info.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
import 'package:stacked_services/stacked_services.dart';
|
import 'package:stacked_services/stacked_services.dart';
|
||||||
import 'package:timezone/timezone.dart' as tz;
|
|
||||||
|
|
||||||
@lazySingleton
|
@lazySingleton
|
||||||
class HomeViewModel extends BaseViewModel {
|
class HomeViewModel extends BaseViewModel {
|
||||||
final NavigationService _navigationService =
|
final NavigationService _navigationService = locator<NavigationService>();
|
||||||
locator<NavigationService>();
|
|
||||||
final ManagerAPI _managerAPI = locator<ManagerAPI>();
|
final ManagerAPI _managerAPI = locator<ManagerAPI>();
|
||||||
final PatcherAPI _patcherAPI = locator<PatcherAPI>();
|
final PatcherAPI _patcherAPI = locator<PatcherAPI>();
|
||||||
final GithubAPI _githubAPI = locator<GithubAPI>();
|
final GithubAPI _githubAPI = locator<GithubAPI>();
|
||||||
|
final RevancedAPI _revancedAPI = locator<RevancedAPI>();
|
||||||
final Toast _toast = locator<Toast>();
|
final Toast _toast = locator<Toast>();
|
||||||
final flutterLocalNotificationsPlugin =
|
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
|
||||||
FlutterLocalNotificationsPlugin();
|
|
||||||
DateTime? _lastUpdate;
|
DateTime? _lastUpdate;
|
||||||
bool showUpdatableApps = false;
|
bool showUpdatableApps = false;
|
||||||
List<PatchedApplication> patchedInstalledApps = [];
|
List<PatchedApplication> patchedInstalledApps = [];
|
||||||
List<PatchedApplication> patchedUpdatableApps = [];
|
List<PatchedApplication> patchedUpdatableApps = [];
|
||||||
|
String _managerVersion = '';
|
||||||
|
|
||||||
Future<void> initialize(BuildContext context) async {
|
Future<void> initialize(BuildContext context) async {
|
||||||
|
_managerVersion = await AboutInfo.getInfo().then(
|
||||||
|
(value) => value.keys.contains('version') ? value['version']! : '',
|
||||||
|
);
|
||||||
|
_managerVersion = await _managerAPI.getCurrentManagerVersion();
|
||||||
await flutterLocalNotificationsPlugin.initialize(
|
await flutterLocalNotificationsPlugin.initialize(
|
||||||
const InitializationSettings(
|
const InitializationSettings(
|
||||||
android: AndroidInitializationSettings('ic_notification'),
|
android: AndroidInitializationSettings('ic_notification'),
|
||||||
@ -63,10 +71,8 @@ class HomeViewModel extends BaseViewModel {
|
|||||||
_toast.showBottom('homeView.noConnection');
|
_toast.showBottom('homeView.noConnection');
|
||||||
}
|
}
|
||||||
final NotificationAppLaunchDetails? notificationAppLaunchDetails =
|
final NotificationAppLaunchDetails? notificationAppLaunchDetails =
|
||||||
await flutterLocalNotificationsPlugin
|
await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
|
||||||
.getNotificationAppLaunchDetails();
|
if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
|
||||||
if (notificationAppLaunchDetails?.didNotificationLaunchApp ??
|
|
||||||
false) {
|
|
||||||
_toast.showBottom('homeView.installingMessage');
|
_toast.showBottom('homeView.installingMessage');
|
||||||
final File? managerApk = await _managerAPI.downloadManager();
|
final File? managerApk = await _managerAPI.downloadManager();
|
||||||
if (managerApk != null) {
|
if (managerApk != null) {
|
||||||
@ -109,10 +115,8 @@ class HomeViewModel extends BaseViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> hasManagerUpdates() async {
|
Future<bool> hasManagerUpdates() async {
|
||||||
final String? latestVersion =
|
final String? latestVersion = await _managerAPI.getLatestManagerVersion();
|
||||||
await _managerAPI.getLatestManagerVersion();
|
final String currentVersion = await _managerAPI.getCurrentManagerVersion();
|
||||||
final String currentVersion =
|
|
||||||
await _managerAPI.getCurrentManagerVersion();
|
|
||||||
if (latestVersion != null) {
|
if (latestVersion != null) {
|
||||||
try {
|
try {
|
||||||
final int latestVersionInt =
|
final int latestVersionInt =
|
||||||
@ -150,35 +154,115 @@ class HomeViewModel extends BaseViewModel {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<File?> downloadManager() async {
|
||||||
|
try {
|
||||||
|
final response = await _revancedAPI.downloadManager();
|
||||||
|
final bytes = await response!.readAsBytes();
|
||||||
|
final tempDir = await getTemporaryDirectory();
|
||||||
|
final tempFile = File('${tempDir.path}/revanced-manager.apk');
|
||||||
|
await tempFile.writeAsBytes(bytes);
|
||||||
|
return tempFile;
|
||||||
|
} on Exception catch (e) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> updateManager(BuildContext context) async {
|
Future<void> updateManager(BuildContext context) async {
|
||||||
try {
|
try {
|
||||||
_toast.showBottom('homeView.downloadingMessage');
|
_toast.showBottom('homeView.downloadingMessage');
|
||||||
final File? managerApk = await _managerAPI.downloadManager();
|
showDialog(
|
||||||
if (managerApk != null) {
|
context: context,
|
||||||
await flutterLocalNotificationsPlugin.zonedSchedule(
|
builder: (context) => SimpleDialog(
|
||||||
0,
|
contentPadding: const EdgeInsets.all(16.0),
|
||||||
FlutterI18n.translate(
|
title: I18nText(
|
||||||
context,
|
'homeView.downloadingMessage',
|
||||||
'homeView.notificationTitle',
|
child: Text(
|
||||||
),
|
'',
|
||||||
FlutterI18n.translate(
|
style: TextStyle(
|
||||||
context,
|
fontSize: 20,
|
||||||
'homeView.notificationText',
|
fontWeight: FontWeight.w500,
|
||||||
),
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
tz.TZDateTime.now(tz.local).add(const Duration(seconds: 5)),
|
),
|
||||||
const NotificationDetails(
|
|
||||||
android: AndroidNotificationDetails(
|
|
||||||
'revanced_manager_channel',
|
|
||||||
'ReVanced Manager Channel',
|
|
||||||
importance: Importance.max,
|
|
||||||
priority: Priority.high,
|
|
||||||
ticker: 'ticker',
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
androidAllowWhileIdle: true,
|
children: [
|
||||||
uiLocalNotificationDateInterpretation:
|
Column(
|
||||||
UILocalNotificationDateInterpretation.absoluteTime,
|
children: [
|
||||||
);
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.new_releases_outlined,
|
||||||
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8.0),
|
||||||
|
Text(
|
||||||
|
'v$_managerVersion',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16.0),
|
||||||
|
StreamBuilder<double>(
|
||||||
|
initialData: 0.0,
|
||||||
|
stream: _revancedAPI.managerUpdateProgress.stream,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
return LinearProgressIndicator(
|
||||||
|
value: snapshot.data! * 0.01,
|
||||||
|
valueColor: AlwaysStoppedAnimation<Color>(
|
||||||
|
Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16.0),
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
child: CustomMaterialButton(
|
||||||
|
label: I18nText('cancelButton'),
|
||||||
|
onPressed: () {
|
||||||
|
_revancedAPI.disposeManagerUpdateProgress();
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final File? managerApk = await downloadManager();
|
||||||
|
if (managerApk != null) {
|
||||||
|
// await flutterLocalNotificationsPlugin.zonedSchedule(
|
||||||
|
// 0,
|
||||||
|
// FlutterI18n.translate(
|
||||||
|
// context,
|
||||||
|
// 'homeView.notificationTitle',
|
||||||
|
// ),
|
||||||
|
// FlutterI18n.translate(
|
||||||
|
// context,
|
||||||
|
// 'homeView.notificationText',
|
||||||
|
// ),
|
||||||
|
// tz.TZDateTime.now(tz.local).add(const Duration(seconds: 5)),
|
||||||
|
// const NotificationDetails(
|
||||||
|
// android: AndroidNotificationDetails(
|
||||||
|
// 'revanced_manager_channel',
|
||||||
|
// 'ReVanced Manager Channel',
|
||||||
|
// importance: Importance.max,
|
||||||
|
// priority: Priority.high,
|
||||||
|
// ticker: 'ticker',
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// androidAllowWhileIdle: true,
|
||||||
|
// uiLocalNotificationDateInterpretation:
|
||||||
|
// UILocalNotificationDateInterpretation.absoluteTime,
|
||||||
|
// );
|
||||||
_toast.showBottom('homeView.installingMessage');
|
_toast.showBottom('homeView.installingMessage');
|
||||||
await AppInstaller.installApk(managerApk.path);
|
await AppInstaller.installApk(managerApk.path);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user