feat: progress bar for manager updates

This commit is contained in:
Aunali321 2023-04-20 04:45:46 +05:30
parent c9adf1c492
commit f5aafdb7d6
2 changed files with 160 additions and 38 deletions

View File

@ -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,

View File

@ -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 {