From 389eae14478d3b8ffef7cad402dc8328e44d3f55 Mon Sep 17 00:00:00 2001 From: Alberto Ponces Date: Thu, 18 Aug 2022 15:33:33 +0100 Subject: [PATCH] fix: code refactoring (#5) --- android/app/build.gradle | 4 +- assets/i18n/en.json | 8 +- lib/app/app.dart | 10 -- lib/services/github_api.dart | 22 +-- lib/services/manager_api.dart | 47 +------ lib/services/patcher_api.dart | 78 +++-------- lib/services/root_api.dart | 28 ++-- .../views/app_selector/app_selector_view.dart | 14 +- .../app_selector/app_selector_viewmodel.dart | 37 ++--- .../views/contributors/contributors_view.dart | 1 - .../contributors/contributors_viewmodel.dart | 37 +++-- lib/ui/views/home/home_view.dart | 3 +- lib/ui/views/home/home_viewmodel.dart | 68 +++++++--- lib/ui/views/installer/installer_view.dart | 6 +- .../views/installer/installer_viewmodel.dart | 128 ++++++++++-------- lib/ui/views/patcher/patcher_viewmodel.dart | 15 +- .../patches_selector_view.dart | 24 ++-- .../patches_selector_viewmodel.dart | 38 +++--- .../views/root_checker/root_checker_view.dart | 1 - .../root_checker/root_checker_viewmodel.dart | 11 +- lib/ui/views/settings/settings_viewmodel.dart | 2 +- lib/ui/widgets/app_selector_card.dart | 26 ++-- lib/ui/widgets/application_item.dart | 2 +- lib/ui/widgets/available_updates_card.dart | 9 +- lib/ui/widgets/installed_apps_card.dart | 9 +- lib/ui/widgets/latest_commit_card.dart | 16 +-- lib/ui/widgets/magisk_button.dart | 4 +- lib/ui/widgets/patch_item.dart | 8 +- lib/ui/widgets/patch_selector_card.dart | 15 +- lib/ui/widgets/patch_text_button.dart | 4 +- pubspec.yaml | 4 +- 31 files changed, 318 insertions(+), 361 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 4749530e..bf2aac2b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion flutter.compileSdkVersion + compileSdkVersion 33 ndkVersion flutter.ndkVersion compileOptions { @@ -45,7 +45,7 @@ android { defaultConfig { applicationId "app.revanced.manager" minSdkVersion 21 - targetSdkVersion flutter.targetSdkVersion + targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/assets/i18n/en.json b/assets/i18n/en.json index 0ca59e0f..7c7b5fef 100644 --- a/assets/i18n/en.json +++ b/assets/i18n/en.json @@ -9,7 +9,9 @@ "updatesSubtitle": "Updates", "patchedSubtitle": "Patched Applications", "updatesAvailable": "Updates Available", - "installed": "Installed" + "installed": "Installed", + "notificationTitle": "ReVanced Manager was updated!", + "notificationText": "Tap to open the app" }, "applicationItem": { "patchButton": "Patch", @@ -50,7 +52,9 @@ "installerView": { "widgetTitle": "Installer", "fabInstallButton": "Install", - "fabOpenButton": "Open" + "fabOpenButton": "Open", + "notificationTitle": "ReVanced Manager is patching", + "notificationText": "Tap to return to the installer" }, "settingsView": { "widgetTitle": "Settings", diff --git a/lib/app/app.dart b/lib/app/app.dart index 8765ae4f..8a1af862 100644 --- a/lib/app/app.dart +++ b/lib/app/app.dart @@ -1,16 +1,11 @@ import 'package:revanced_manager/main.dart'; -import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/services/patcher_api.dart'; -import 'package:revanced_manager/services/root_api.dart'; import 'package:revanced_manager/ui/views/app_selector/app_selector_view.dart'; -import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart'; import 'package:revanced_manager/ui/views/contributors/contributors_view.dart'; import 'package:revanced_manager/ui/views/home/home_viewmodel.dart'; import 'package:revanced_manager/ui/views/installer/installer_view.dart'; -import 'package:revanced_manager/ui/views/installer/installer_viewmodel.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; import 'package:revanced_manager/ui/views/patches_selector/patches_selector_view.dart'; -import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart'; import 'package:revanced_manager/ui/views/root_checker/root_checker_view.dart'; import 'package:revanced_manager/ui/views/settings/settings_view.dart'; import 'package:stacked/stacked_annotations.dart'; @@ -30,13 +25,8 @@ import 'package:stacked_themes/stacked_themes.dart'; dependencies: [ LazySingleton(classType: NavigationService), LazySingleton(classType: PatcherAPI), - LazySingleton(classType: ManagerAPI), - LazySingleton(classType: RootAPI), LazySingleton(classType: HomeViewModel), LazySingleton(classType: PatcherViewModel), - LazySingleton(classType: AppSelectorViewModel), - LazySingleton(classType: PatchesSelectorViewModel), - LazySingleton(classType: InstallerViewModel), LazySingleton( classType: ThemeService, resolveUsing: ThemeService.getInstance, diff --git a/lib/services/github_api.dart b/lib/services/github_api.dart index 59e6501e..09f461ea 100644 --- a/lib/services/github_api.dart +++ b/lib/services/github_api.dart @@ -1,32 +1,36 @@ +import 'dart:io'; +import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:github/github.dart'; -import 'package:injectable/injectable.dart'; import 'package:revanced_manager/models/patched_application.dart'; import 'package:timeago/timeago.dart'; -@lazySingleton class GithubAPI { - var github = GitHub(); + final GitHub _github = GitHub(); - Future latestRelease(String org, repoName) async { + Future latestRelease(String org, repoName) async { try { - var latestRelease = await github.repositories.getLatestRelease( + var latestRelease = await _github.repositories.getLatestRelease( RepositorySlug(org, repoName), ); - return latestRelease.assets + String? url = latestRelease.assets ?.firstWhere((asset) => asset.name != null && (asset.name!.endsWith('.dex') || asset.name!.endsWith('.apk')) && !asset.name!.contains('-sources') && !asset.name!.contains('-javadoc')) .browserDownloadUrl; + if (url != null) { + return await DefaultCacheManager().getSingleFile(url); + } } on Exception { - return ''; + return null; } + return null; } Future latestCommitTime(String org, repoName) async { try { - var repo = await github.repositories.getRepository( + var repo = await _github.repositories.getRepository( RepositorySlug(org, repoName), ); return repo.pushedAt != null @@ -39,7 +43,7 @@ class GithubAPI { Future> getContributors(String org, repoName) async { try { - var contributors = github.repositories.listContributors( + var contributors = _github.repositories.listContributors( RepositorySlug(org, repoName), ); return contributors.toList(); diff --git a/lib/services/manager_api.dart b/lib/services/manager_api.dart index 2d2223b0..6bde4a76 100644 --- a/lib/services/manager_api.dart +++ b/lib/services/manager_api.dart @@ -1,52 +1,19 @@ import 'dart:io'; -import 'package:dio/dio.dart'; -import 'package:injectable/injectable.dart'; -import 'package:path_provider/path_provider.dart' as p; import 'package:revanced_manager/constants.dart'; import 'package:revanced_manager/services/github_api.dart'; -@lazySingleton class ManagerAPI { - final Dio dio = Dio(); - final GithubAPI githubAPI = GithubAPI(); + final GithubAPI _githubAPI = GithubAPI(); - Future getPath() async { - final path = await p.getApplicationSupportDirectory(); - Directory('${path.path}/revanced').createSync(); - final workDirPath = '${path.path}/revanced'; - return workDirPath; + Future downloadPatches() async { + return await _githubAPI.latestRelease(ghOrg, patchesRepo); } - Future downloadAssets(String repo) async { - try { - final workDir = await getPath(); - final dlUrl = await githubAPI.latestRelease(ghOrg, repo); - final name = dlUrl - ?.split('/') - .lastWhere((element) => element.contains('revanced')); - final assetFile = File('$workDir/$name'); - final response = await dio.get( - dlUrl!, - options: Options( - responseType: ResponseType.bytes, - followRedirects: true, - receiveTimeout: 0, - ), - ); - final raf = assetFile.openSync(mode: FileMode.write); - raf.writeFromSync(response.data); - raf.closeSync(); - return assetFile; - } catch (e) { - return null; - } + Future downloadIntegrations() async { + return await _githubAPI.latestRelease(ghOrg, integrationsRepo); } - Future downloadPatches() async { - await downloadAssets(patchesRepo); - } - - Future downloadIntegrations() async { - await downloadAssets(integrationsRepo); + Future downloadManager() async { + return await _githubAPI.latestRelease(ghOrg, managerRepo); } } diff --git a/lib/services/patcher_api.dart b/lib/services/patcher_api.dart index 7f560d76..5fbedb6b 100644 --- a/lib/services/patcher_api.dart +++ b/lib/services/patcher_api.dart @@ -2,15 +2,12 @@ import 'dart:io'; import 'package:app_installer/app_installer.dart'; import 'package:device_apps/device_apps.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_cache_manager/flutter_cache_manager.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/models/patch.dart'; import 'package:revanced_manager/models/patched_application.dart'; -import 'package:revanced_manager/services/github_api.dart'; +import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/services/root_api.dart'; -import 'package:revanced_manager/ui/views/installer/installer_viewmodel.dart'; import 'package:revanced_manager/utils/string.dart'; import 'package:share_extend/share_extend.dart'; @@ -19,11 +16,8 @@ class PatcherAPI { static const patcherChannel = MethodChannel( 'app.revanced.manager/patcher', ); - static const installerChannel = MethodChannel( - 'app.revanced.manager/installer', - ); - final GithubAPI githubAPI = GithubAPI(); - final RootAPI rootAPI = RootAPI(); + final ManagerAPI _managerAPI = ManagerAPI(); + final RootAPI _rootAPI = RootAPI(); Directory? _tmpDir; Directory? _workDir; Directory? _cacheDir; @@ -33,45 +27,18 @@ class PatcherAPI { File? _patchedFile; File? _outFile; - Future handlePlatformChannelMethods() async { - installerChannel.setMethodCallHandler((call) async { - switch (call.method) { - case 'updateProgress': - if (call.arguments != null) { - locator().updateProgress(call.arguments); - } - break; - case 'updateLog': - if (call.arguments != null) { - locator().updateLog(call.arguments); - } - break; - } - }); - } - - Future loadPatches() async { + Future loadPatches() async { if (_patchBundleFile == null) { - String? dexFileUrl = - await githubAPI.latestRelease('revanced', 'revanced-patches'); - if (dexFileUrl != null && dexFileUrl.isNotEmpty) { - try { - _patchBundleFile = - await DefaultCacheManager().getSingleFile(dexFileUrl); - return await patcherChannel.invokeMethod( - 'loadPatches', - { - 'pathBundlesPaths': [_patchBundleFile!.absolute.path], - }, - ); - } on Exception { - _patchBundleFile = null; - return false; - } + _patchBundleFile = await _managerAPI.downloadPatches(); + if (_patchBundleFile != null) { + await patcherChannel.invokeMethod( + 'loadPatches', + { + 'pathBundlesPaths': [_patchBundleFile!.absolute.path], + }, + ); } - return false; } - return true; } Future> getFilteredInstalledApps() async { @@ -181,20 +148,9 @@ class PatcherAPI { return appliedPatches; } - Future downloadIntegrations() async { - String? apkFileUrl = - await githubAPI.latestRelease('revanced', 'revanced-integrations'); - if (apkFileUrl != null && apkFileUrl.isNotEmpty) { - return await DefaultCacheManager().getSingleFile(apkFileUrl); - } - return null; - } - Future initPatcher(bool mergeIntegrations) async { if (mergeIntegrations) { - _integrations = await downloadIntegrations(); - } else { - _integrations = File(''); + _integrations = await _managerAPI.downloadIntegrations(); } _tmpDir = await getTemporaryDirectory(); _workDir = _tmpDir!.createTempSync('tmp-'); @@ -218,7 +174,7 @@ class PatcherAPI { 'inputFilePath': _inputFile!.path, 'patchedFilePath': _patchedFile!.path, 'outFilePath': _outFile!.path, - 'integrationsPath': _integrations!.path, + 'integrationsPath': _integrations != null ? _integrations!.path : '', 'selectedPatches': selectedPatches.map((p) => p.name).toList(), 'cacheDirPath': _cacheDir!.path, 'mergeIntegrations': mergeIntegrations, @@ -231,7 +187,7 @@ class PatcherAPI { if (_outFile != null) { try { if (patchedApp.isRooted && !patchedApp.isFromStorage) { - return rootAPI.installApp( + return _rootAPI.installApp( patchedApp.packageName, patchedApp.apkFilePath, _outFile!.path, @@ -268,14 +224,14 @@ class PatcherAPI { Future checkOldPatch(PatchedApplication patchedApp) async { if (patchedApp.isRooted) { - return await rootAPI.checkApp(patchedApp.packageName); + return await _rootAPI.checkApp(patchedApp.packageName); } return false; } Future deleteOldPatch(PatchedApplication patchedApp) async { if (patchedApp.isRooted) { - await rootAPI.deleteApp(patchedApp.packageName, patchedApp.apkFilePath); + await _rootAPI.deleteApp(patchedApp.packageName, patchedApp.apkFilePath); } } } diff --git a/lib/services/root_api.dart b/lib/services/root_api.dart index d7a4eed3..b2fa2ec4 100644 --- a/lib/services/root_api.dart +++ b/lib/services/root_api.dart @@ -1,16 +1,14 @@ -import 'package:injectable/injectable.dart'; import 'package:root/root.dart'; -@lazySingleton class RootAPI { - final String managerDirPath = "/data/adb/revanced_manager"; - final String postFsDataDirPath = "/data/adb/post-fs-data.d"; - final String serviceDDirPath = "/data/adb/service.d"; + final String _managerDirPath = "/data/adb/revanced_manager"; + final String _postFsDataDirPath = "/data/adb/post-fs-data.d"; + final String _serviceDDirPath = "/data/adb/service.d"; Future checkApp(String packageName) async { try { String? res = await Root.exec( - cmd: 'ls -la "$managerDirPath/$packageName"', + cmd: 'ls -la "$_managerDirPath/$packageName"', ); return res != null && res.isNotEmpty; } on Exception { @@ -26,13 +24,13 @@ class RootAPI { cmd: 'su -mm -c "umount -l $originalFilePath"', ); await Root.exec( - cmd: 'rm -rf "$managerDirPath/$packageName"', + cmd: 'rm -rf "$_managerDirPath/$packageName"', ); await Root.exec( - cmd: 'rm -rf "$serviceDDirPath/$packageName.sh"', + cmd: 'rm -rf "$_serviceDDirPath/$packageName.sh"', ); await Root.exec( - cmd: 'rm -rf "$postFsDataDirPath/$packageName.sh"', + cmd: 'rm -rf "$_postFsDataDirPath/$packageName.sh"', ); } @@ -43,7 +41,7 @@ class RootAPI { ) async { try { await Root.exec( - cmd: 'mkdir -p "$managerDirPath/$packageName"', + cmd: 'mkdir -p "$_managerDirPath/$packageName"', ); installServiceDScript(packageName); installPostFsDataScript(packageName); @@ -58,10 +56,10 @@ class RootAPI { Future installServiceDScript(String packageName) async { String content = '#!/system/bin/sh\n' 'while [ "\$(getprop sys.boot_completed | tr -d \'"\'"\'\\\\r\'"\'"\')" != "1" ]; do sleep 1; done\n' - 'base_path=$managerDirPath/$packageName/base.apk\n' + 'base_path=$_managerDirPath/$packageName/base.apk\n' 'stock_path=\$(pm path $packageName | grep base | sed \'"\'"\'s/package://g\'"\'"\')\n' '[ ! -z \$stock_path ] && mount -o bind \$base_path \$stock_path'; - String scriptFilePath = '$serviceDDirPath/$packageName.sh'; + String scriptFilePath = '$_serviceDDirPath/$packageName.sh'; await Root.exec( cmd: 'echo \'$content\' > "$scriptFilePath"', ); @@ -74,7 +72,7 @@ class RootAPI { String content = '#!/system/bin/sh\n' 'stock_path=\$(pm path $packageName | grep base | sed \'"\'"\'s/package://g\'"\'"\')\n' '[ ! -z \$stock_path ] && umount -l \$stock_path'; - String scriptFilePath = '$postFsDataDirPath/$packageName.sh'; + String scriptFilePath = '$_postFsDataDirPath/$packageName.sh'; await Root.exec( cmd: 'echo \'$content\' > "$scriptFilePath"', ); @@ -84,7 +82,7 @@ class RootAPI { } Future installApk(String packageName, String patchedFilePath) async { - String newPatchedFilePath = '$managerDirPath/$packageName/base.apk'; + String newPatchedFilePath = '$_managerDirPath/$packageName/base.apk'; await Root.exec( cmd: 'cp "$patchedFilePath" "$newPatchedFilePath"', ); @@ -104,7 +102,7 @@ class RootAPI { String originalFilePath, String patchedFilePath, ) async { - String newPatchedFilePath = '$managerDirPath/$packageName/base.apk'; + String newPatchedFilePath = '$_managerDirPath/$packageName/base.apk'; await Root.exec( cmd: 'am force-stop "$packageName"', ); diff --git a/lib/ui/views/app_selector/app_selector_view.dart b/lib/ui/views/app_selector/app_selector_view.dart index 7b15a4ee..0dd2208e 100644 --- a/lib/ui/views/app_selector/app_selector_view.dart +++ b/lib/ui/views/app_selector/app_selector_view.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; -import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/theme.dart'; import 'package:revanced_manager/ui/widgets/installed_app_item.dart'; import 'package:revanced_manager/ui/widgets/search_bar.dart'; @@ -15,14 +14,13 @@ class AppSelectorView extends StatefulWidget { } class _AppSelectorViewState extends State { - String query = ''; + String _query = ''; @override Widget build(BuildContext context) { return ViewModelBuilder.reactive( - disposeViewModel: false, onModelReady: (model) => model.initialize(), - viewModelBuilder: () => locator(), + viewModelBuilder: () => AppSelectorViewModel(), builder: (context, model, child) => Scaffold( floatingActionButton: FloatingActionButton.extended( onPressed: () { @@ -51,17 +49,17 @@ class _AppSelectorViewState extends State { hintTextColor: Theme.of(context).colorScheme.tertiary, onQueryChanged: (searchQuery) { setState(() { - query = searchQuery; + _query = searchQuery; }); }, ), const SizedBox(height: 12), - query.isEmpty || query.length < 2 + _query.isEmpty || _query.length < 2 ? _getAllResults(model) : _getFilteredResults(model) ], ) - : query.isEmpty || query.length < 2 + : _query.isEmpty || _query.length < 2 ? Center( child: CircularProgressIndicator( color: Theme.of(context).colorScheme.secondary, @@ -105,7 +103,7 @@ class _AppSelectorViewState extends State { itemBuilder: (context, index) { model.apps.sort((a, b) => a.appName.compareTo(b.appName)); if (model.apps[index].appName.toLowerCase().contains( - query.toLowerCase(), + _query.toLowerCase(), )) { return InkWell( onTap: () { diff --git a/lib/ui/views/app_selector/app_selector_viewmodel.dart b/lib/ui/views/app_selector/app_selector_viewmodel.dart index cc7b1a8f..e622f6e7 100644 --- a/lib/ui/views/app_selector/app_selector_viewmodel.dart +++ b/lib/ui/views/app_selector/app_selector_viewmodel.dart @@ -8,30 +8,22 @@ import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/services/patcher_api.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; -import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:stacked/stacked.dart'; class AppSelectorViewModel extends BaseViewModel { - final PatcherAPI patcherAPI = locator(); - bool isRooted = false; - bool isFromStorage = false; - List apps = []; - PatchedApplication? selectedApp; + final PatcherAPI _patcherAPI = locator(); + final List apps = []; + bool _isRooted = false; Future initialize() async { - await getApps(); + apps.addAll(await _patcherAPI.getFilteredInstalledApps()); SharedPreferences prefs = await SharedPreferences.getInstance(); - isRooted = prefs.getBool('isRooted') ?? false; + _isRooted = prefs.getBool('isRooted') ?? false; notifyListeners(); } - Future getApps() async { - apps = await patcherAPI.getFilteredInstalledApps(); - } - void selectApp(ApplicationWithIcon application) async { - isFromStorage = false; PatchedApplication app = PatchedApplication( name: application.appName, packageName: application.packageName, @@ -39,18 +31,16 @@ class AppSelectorViewModel extends BaseViewModel { apkFilePath: application.apkFilePath, icon: application.icon, patchDate: DateTime.now(), - isRooted: isRooted, - isFromStorage: isFromStorage, + isRooted: _isRooted, + isFromStorage: false, appliedPatches: [], ); - locator().selectedApp = app; - locator().selectedPatches.clear(); - locator().notifyListeners(); + locator().selectedApp = app; + locator().selectedPatches.clear(); locator().notifyListeners(); } Future selectAppFromStorage(BuildContext context) async { - isFromStorage = true; try { FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.custom, @@ -69,13 +59,12 @@ class AppSelectorViewModel extends BaseViewModel { apkFilePath: result.files.single.path!, icon: application.icon, patchDate: DateTime.now(), - isRooted: isRooted, - isFromStorage: isFromStorage, + isRooted: _isRooted, + isFromStorage: true, appliedPatches: [], ); - locator().selectedApp = app; - locator().selectedPatches.clear(); - locator().notifyListeners(); + locator().selectedApp = app; + locator().selectedPatches.clear(); locator().notifyListeners(); } } diff --git a/lib/ui/views/contributors/contributors_view.dart b/lib/ui/views/contributors/contributors_view.dart index 0c8b380f..61ca8b36 100644 --- a/lib/ui/views/contributors/contributors_view.dart +++ b/lib/ui/views/contributors/contributors_view.dart @@ -9,7 +9,6 @@ class ContributorsView extends StatelessWidget { @override Widget build(BuildContext context) { return ViewModelBuilder.reactive( - disposeViewModel: false, viewModelBuilder: () => ContributorsViewModel(), onModelReady: (model) => model.getContributors(), builder: (context, model, child) => Scaffold( diff --git a/lib/ui/views/contributors/contributors_viewmodel.dart b/lib/ui/views/contributors/contributors_viewmodel.dart index 3dbdbb80..a3f2549a 100644 --- a/lib/ui/views/contributors/contributors_viewmodel.dart +++ b/lib/ui/views/contributors/contributors_viewmodel.dart @@ -1,27 +1,36 @@ import 'package:github/github.dart'; +import 'package:revanced_manager/constants.dart'; import 'package:revanced_manager/services/github_api.dart'; import 'package:stacked/stacked.dart'; class ContributorsViewModel extends BaseViewModel { - final GithubAPI githubAPI = GithubAPI(); + final GithubAPI _githubAPI = GithubAPI(); List patchesContributors = []; List integrationsContributors = []; List patcherContributors = []; List cliContributors = []; List managerContributors = []; - Future> getContributors() async { - patchesContributors = - await githubAPI.getContributors('revanced', 'revanced-patches'); - integrationsContributors = - await githubAPI.getContributors('revanced', 'revanced-integrations'); - patcherContributors = - await githubAPI.getContributors('revanced', 'revanced-patcher'); - cliContributors = - await githubAPI.getContributors('revanced', 'revanced-cli'); - managerContributors = - await githubAPI.getContributors('revanced', 'revanced-manager'); - - return []; + Future getContributors() async { + patchesContributors = await _githubAPI.getContributors( + ghOrg, + patchesRepo, + ); + integrationsContributors = await _githubAPI.getContributors( + ghOrg, + integrationsRepo, + ); + patcherContributors = await _githubAPI.getContributors( + ghOrg, + patcherRepo, + ); + cliContributors = await _githubAPI.getContributors( + ghOrg, + cliRepo, + ); + managerContributors = await _githubAPI.getContributors( + ghOrg, + managerRepo, + ); } } diff --git a/lib/ui/views/home/home_view.dart b/lib/ui/views/home/home_view.dart index 63fe1270..5659d9ec 100644 --- a/lib/ui/views/home/home_view.dart +++ b/lib/ui/views/home/home_view.dart @@ -55,6 +55,7 @@ class HomeView extends StatelessWidget { ), const SizedBox(height: 10), LatestCommitCard( + onPressed: () => model.updateManager(context), color: Theme.of(context).colorScheme.primary, ), const SizedBox(height: 23), @@ -77,7 +78,7 @@ class HomeView extends StatelessWidget { label: "homeView.updatesAvailable", isSelected: model.showUpdatableApps, onSelected: (value) { - model.toggleUpdatableApps(value); + model.toggleUpdatableApps(true); }, ), const SizedBox(width: 10), diff --git a/lib/ui/views/home/home_viewmodel.dart b/lib/ui/views/home/home_viewmodel.dart index 4a41df6b..95e3669a 100644 --- a/lib/ui/views/home/home_viewmodel.dart +++ b/lib/ui/views/home/home_viewmodel.dart @@ -1,26 +1,41 @@ import 'dart:convert'; +import 'dart:io'; +import 'package:app_installer/app_installer.dart'; +import 'package:device_apps/device_apps.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:injectable/injectable.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/app/app.router.dart'; +import 'package:revanced_manager/constants.dart'; import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/services/github_api.dart'; import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/services/patcher_api.dart'; -import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart'; -import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart'; +import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; @lazySingleton class HomeViewModel extends BaseViewModel { - final _navigationService = locator(); - final GithubAPI githubAPI = GithubAPI(); - final PatcherAPI patcherAPI = locator(); + final NavigationService _navigationService = locator(); + final ManagerAPI _managerAPI = ManagerAPI(); + final GithubAPI _githubAPI = GithubAPI(); + final PatcherAPI _patcherAPI = locator(); + final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = + FlutterLocalNotificationsPlugin(); bool showUpdatableApps = true; Future initialize() async { - await patcherAPI.loadPatches(); + await _patcherAPI.loadPatches(); + await flutterLocalNotificationsPlugin.initialize( + const InitializationSettings( + android: AndroidInitializationSettings('ic_notification'), + ), + onSelectNotification: (p) => DeviceApps.openApp('app.revanced.manager'), + ); } void toggleUpdatableApps(bool value) { @@ -28,13 +43,10 @@ class HomeViewModel extends BaseViewModel { notifyListeners(); } - Future downloadPatches() => locator().downloadPatches(); - Future downloadIntegrations() => locator().downloadIntegrations(); - void navigateToInstaller(PatchedApplication app) async { - locator().selectedApp = app; - locator().selectedPatches = - await patcherAPI.getAppliedPatches(app); + locator().selectedApp = app; + locator().selectedPatches = + await _patcherAPI.getAppliedPatches(app); _navigationService.navigateTo(Routes.installerView); } @@ -44,15 +56,37 @@ class HomeViewModel extends BaseViewModel { List patchedApps = prefs.getStringList('patchedApps') ?? []; for (String str in patchedApps) { PatchedApplication app = PatchedApplication.fromJson(json.decode(str)); - bool hasUpdates = await githubAPI.hasUpdates( - app, - 'revanced', - 'revanced-patches', - ); + bool hasUpdates = await _githubAPI.hasUpdates(app, ghOrg, patchesRepo); if (hasUpdates == isUpdatable) { list.add(app); } } return list; } + + void updateManager(BuildContext context) async { + File? managerApk = await _managerAPI.downloadManager(); + if (managerApk != null) { + flutterLocalNotificationsPlugin.show( + 0, + // ignore: use_build_context_synchronously + FlutterI18n.translate( + context, + 'homeView.notificationTitle', + ), + // ignore: use_build_context_synchronously + FlutterI18n.translate( + context, + 'homeView.notificationText', + ), + const NotificationDetails( + android: AndroidNotificationDetails( + 'revanced_manager_channel', + 'ReVanced Manager Channel', + ), + ), + ); + AppInstaller.installApk(managerApk.path); + } + } } diff --git a/lib/ui/views/installer/installer_view.dart b/lib/ui/views/installer/installer_view.dart index 28bb8517..b7a18657 100644 --- a/lib/ui/views/installer/installer_view.dart +++ b/lib/ui/views/installer/installer_view.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/ui/views/installer/installer_viewmodel.dart'; import 'package:stacked/stacked.dart'; @@ -15,9 +14,8 @@ class InstallerView extends StatelessWidget { (_) => _controller.jumpTo(_controller.position.maxScrollExtent), ); return ViewModelBuilder.reactive( - disposeViewModel: false, - onModelReady: (model) => model.initialize(), - viewModelBuilder: () => locator(), + onModelReady: (model) => model.initialize(context), + viewModelBuilder: () => InstallerViewModel(), builder: (context, model, child) => WillPopScope( child: Scaffold( floatingActionButton: Visibility( diff --git a/lib/ui/views/installer/installer_viewmodel.dart b/lib/ui/views/installer/installer_viewmodel.dart index 5f66e2f9..3058cc11 100644 --- a/lib/ui/views/installer/installer_viewmodel.dart +++ b/lib/ui/views/installer/installer_viewmodel.dart @@ -1,30 +1,43 @@ import 'dart:convert'; import 'package:device_apps/device_apps.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_background/flutter_background.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/models/patch.dart'; import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/services/patcher_api.dart'; -import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; -import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:stacked/stacked.dart'; class InstallerViewModel extends BaseViewModel { + final PatcherAPI _patcherAPI = locator(); + final PatchedApplication? _app = locator().selectedApp; + final List _patches = locator().selectedPatches; + static const _installerChannel = MethodChannel( + 'app.revanced.manager/installer', + ); double? progress = 0.0; String logs = ''; bool isPatching = false; bool isInstalled = false; - Future initialize() async { + Future initialize(BuildContext context) async { try { await FlutterBackground.initialize( - androidConfig: const FlutterBackgroundAndroidConfig( - notificationTitle: 'Patching', - notificationText: 'ReVanced Manager is patching', + androidConfig: FlutterBackgroundAndroidConfig( + notificationTitle: FlutterI18n.translate( + context, + 'installerView.notificationTitle', + ), + notificationText: FlutterI18n.translate( + context, + 'installerView.notificationText', + ), notificationImportance: AndroidNotificationImportance.Default, - notificationIcon: AndroidResource( + notificationIcon: const AndroidResource( name: 'ic_notification', defType: 'drawable', ), @@ -32,11 +45,28 @@ class InstallerViewModel extends BaseViewModel { ); await FlutterBackground.enableBackgroundExecution(); } finally { - await locator().handlePlatformChannelMethods(); + await handlePlatformChannelMethods(); await runPatcher(); } } + Future handlePlatformChannelMethods() async { + _installerChannel.setMethodCallHandler((call) async { + switch (call.method) { + case 'updateProgress': + if (call.arguments != null) { + updateProgress(call.arguments); + } + break; + case 'updateLog': + if (call.arguments != null) { + updateLog(call.arguments); + } + break; + } + }); + } + void updateProgress(double value) { progress = value; isInstalled = false; @@ -59,37 +89,32 @@ class InstallerViewModel extends BaseViewModel { Future runPatcher() async { updateProgress(0.0); - PatchedApplication? selectedApp = - locator().selectedApp; - List selectedPatches = - locator().selectedPatches; - if (selectedApp != null && selectedPatches.isNotEmpty) { - String apkFilePath = selectedApp.apkFilePath; + if (_app != null && _patches.isNotEmpty) { + String apkFilePath = _app!.apkFilePath; try { updateLog('Initializing installer'); - if (selectedApp.isRooted && !selectedApp.isFromStorage) { + if (_app!.isRooted && !_app!.isFromStorage) { updateLog('Checking if an old patched version exists'); - bool oldExists = - await locator().checkOldPatch(selectedApp); + bool oldExists = await _patcherAPI.checkOldPatch(_app!); if (oldExists) { updateLog('Deleting old patched version'); - await locator().deleteOldPatch(selectedApp); + await _patcherAPI.deleteOldPatch(_app!); } } updateLog('Creating working directory'); bool mergeIntegrations = false; bool resourcePatching = false; - if (selectedApp.packageName == 'com.google.android.youtube') { + if (_app!.packageName == 'com.google.android.youtube') { mergeIntegrations = true; resourcePatching = true; - } else if (selectedApp.packageName == + } else if (_app!.packageName == 'com.google.android.apps.youtube.music') { resourcePatching = true; } - await locator().initPatcher(mergeIntegrations); - await locator().runPatcher( + await _patcherAPI.initPatcher(mergeIntegrations); + await _patcherAPI.runPatcher( apkFilePath, - selectedPatches, + _patches, mergeIntegrations, resourcePatching, ); @@ -107,21 +132,16 @@ class InstallerViewModel extends BaseViewModel { } void installResult() async { - PatchedApplication? selectedApp = - locator().selectedApp; - List selectedPatches = - locator().selectedPatches; - if (selectedApp != null) { - updateLog(selectedApp.isRooted + if (_app != null) { + updateLog(_app!.isRooted ? 'Installing patched file using root method' : 'Installing patched file using nonroot method'); - isInstalled = await locator().installPatchedFile(selectedApp); + isInstalled = await _patcherAPI.installPatchedFile(_app!); if (isInstalled) { updateLog('Done'); - selectedApp.patchDate = DateTime.now(); - selectedApp.appliedPatches - .addAll(selectedPatches.map((p) => p.name).toList()); - await saveApp(selectedApp); + _app!.patchDate = DateTime.now(); + _app!.appliedPatches.addAll(_patches.map((p) => p.name).toList()); + await saveApp(); } else { updateLog('An error occurred! Aborting'); } @@ -129,39 +149,33 @@ class InstallerViewModel extends BaseViewModel { } void shareResult() { - PatchedApplication? selectedApp = - locator().selectedApp; - if (selectedApp != null) { - locator().sharePatchedFile( - selectedApp.name, - selectedApp.version, - ); + if (_app != null) { + _patcherAPI.sharePatchedFile(_app!.name, _app!.version); } } Future cleanWorkplace() async { - locator().cleanPatcher(); - locator().selectedApp = null; - locator().selectedPatches.clear(); - locator().notifyListeners(); + _patcherAPI.cleanPatcher(); + locator().selectedApp = null; + locator().selectedPatches.clear(); locator().notifyListeners(); } void openApp() { - PatchedApplication? selectedApp = - locator().selectedApp; - if (selectedApp != null) { - DeviceApps.openApp(selectedApp.packageName); + if (_app != null) { + DeviceApps.openApp(_app!.packageName); } } - Future saveApp(PatchedApplication selectedApp) async { - SharedPreferences prefs = await SharedPreferences.getInstance(); - List patchedApps = prefs.getStringList('patchedApps') ?? []; - String app = json.encode(selectedApp.toJson()); - patchedApps.removeWhere( - (a) => json.decode(a)['packageName'] == selectedApp.packageName); - patchedApps.add(app); - prefs.setStringList('patchedApps', patchedApps); + Future saveApp() async { + if (_app != null) { + SharedPreferences prefs = await SharedPreferences.getInstance(); + List patchedApps = prefs.getStringList('patchedApps') ?? []; + String appStr = json.encode(_app!.toJson()); + patchedApps.removeWhere( + (a) => json.decode(a)['packageName'] == _app!.packageName); + patchedApps.add(appStr); + prefs.setStringList('patchedApps', patchedApps); + } } } diff --git a/lib/ui/views/patcher/patcher_viewmodel.dart b/lib/ui/views/patcher/patcher_viewmodel.dart index 8a87c9d9..18b356b6 100644 --- a/lib/ui/views/patcher/patcher_viewmodel.dart +++ b/lib/ui/views/patcher/patcher_viewmodel.dart @@ -1,12 +1,17 @@ +import 'package:injectable/injectable.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/app/app.router.dart'; -import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart'; -import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart'; +import 'package:revanced_manager/models/patch.dart'; +import 'package:revanced_manager/models/patched_application.dart'; import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; +@lazySingleton class PatcherViewModel extends BaseViewModel { - final _navigationService = locator(); + PatchedApplication? selectedApp; + List selectedPatches = []; + + final NavigationService _navigationService = locator(); void navigateToAppSelector() { _navigationService.navigateTo(Routes.appSelectorView); @@ -21,10 +26,10 @@ class PatcherViewModel extends BaseViewModel { } bool showFabButton() { - return locator().selectedPatches.isNotEmpty; + return selectedPatches.isNotEmpty; } bool dimPatchesCard() { - return locator().selectedApp == null; + return selectedApp == null; } } diff --git a/lib/ui/views/patches_selector/patches_selector_view.dart b/lib/ui/views/patches_selector/patches_selector_view.dart index df63b1bb..3a742a1e 100644 --- a/lib/ui/views/patches_selector/patches_selector_view.dart +++ b/lib/ui/views/patches_selector/patches_selector_view.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; -import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/theme.dart'; import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart'; import 'package:revanced_manager/ui/widgets/patch_item.dart'; @@ -15,16 +14,14 @@ class PatchesSelectorView extends StatefulWidget { } class _PatchesSelectorViewState extends State { - final List patches = []; + final List _items = []; String query = ''; @override Widget build(BuildContext context) { return ViewModelBuilder.reactive( - disposeViewModel: false, - fireOnModelReadyOnce: true, onModelReady: (model) => model.initialize(), - viewModelBuilder: () => locator(), + viewModelBuilder: () => PatchesSelectorViewModel(), builder: (context, model, child) => Scaffold( body: SafeArea( child: Padding( @@ -62,7 +59,10 @@ class _PatchesSelectorViewState extends State { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), - onPressed: () => Navigator.of(context).pop(), + onPressed: () { + model.selectPatches(); + Navigator.of(context).pop(); + }, child: I18nText('patchesSelectorView.fabButton'), ), ], @@ -79,7 +79,7 @@ class _PatchesSelectorViewState extends State { } Widget _getAllResults(PatchesSelectorViewModel model) { - patches.clear(); + _items.clear(); return Expanded( child: ListView.builder( itemCount: model.patches.length, @@ -93,8 +93,10 @@ class _PatchesSelectorViewState extends State { isSelected: model.selectedPatches.any( (element) => element.name == model.patches[index].name, ), + onChanged: (value) => + model.selectPatch(model.patches[index].name, value), ); - patches.add(item); + _items.add(item); return item; }, ), @@ -102,7 +104,7 @@ class _PatchesSelectorViewState extends State { } Widget _getFilteredResults(PatchesSelectorViewModel model) { - patches.clear(); + _items.clear(); return Expanded( child: ListView.builder( itemCount: model.patches.length, @@ -119,8 +121,10 @@ class _PatchesSelectorViewState extends State { isSelected: model.selectedPatches.any( (element) => element.name == model.patches[index].name, ), + onChanged: (value) => + model.selectPatch(model.patches[index].name, value), ); - patches.add(item); + _items.add(item); return item; } else { return const SizedBox(); diff --git a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart index 17e17a8d..960ef4ba 100644 --- a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart +++ b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart @@ -1,38 +1,34 @@ import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/models/patch.dart'; -import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/services/patcher_api.dart'; -import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; -import 'package:revanced_manager/ui/widgets/patch_item.dart'; import 'package:stacked/stacked.dart'; class PatchesSelectorViewModel extends BaseViewModel { - final PatcherAPI patcherAPI = locator(); - List patches = []; - List selectedPatches = []; + final PatcherAPI _patcherAPI = locator(); + final List patches = []; + final List selectedPatches = + locator().selectedPatches; Future initialize() async { - await getPatches(); + patches.addAll(await _patcherAPI.getFilteredPatches( + locator().selectedApp, + )); notifyListeners(); } - Future getPatches() async { - PatchedApplication? app = locator().selectedApp; - patches = await patcherAPI.getFilteredPatches(app); + void selectPatch(String name, bool isSelected) { + Patch patch = patches.firstWhere((p) => p.name == name); + if (isSelected && !selectedPatches.contains(patch)) { + selectedPatches.add(patch); + } else { + selectedPatches.remove(patch); + } + notifyListeners(); } - void selectPatch(PatchItem item) { - Patch patch = locator() - .patches - .firstWhere((p) => p.name == item.name); - if (item.isSelected && - !locator().selectedPatches.contains(patch)) { - locator().selectedPatches.add(patch); - } else { - locator().selectedPatches.remove(patch); - } - locator().notifyListeners(); + void selectPatches() { + locator().selectedPatches = selectedPatches; locator().notifyListeners(); } } diff --git a/lib/ui/views/root_checker/root_checker_view.dart b/lib/ui/views/root_checker/root_checker_view.dart index 9a63230f..034f353f 100644 --- a/lib/ui/views/root_checker/root_checker_view.dart +++ b/lib/ui/views/root_checker/root_checker_view.dart @@ -11,7 +11,6 @@ class RootCheckerView extends StatelessWidget { @override Widget build(BuildContext context) { return ViewModelBuilder.reactive( - disposeViewModel: false, viewModelBuilder: () => RootCheckerViewModel(), builder: (context, model, child) => Scaffold( floatingActionButton: Column( diff --git a/lib/ui/views/root_checker/root_checker_viewmodel.dart b/lib/ui/views/root_checker/root_checker_viewmodel.dart index 3d6f2092..e9fe5083 100644 --- a/lib/ui/views/root_checker/root_checker_viewmodel.dart +++ b/lib/ui/views/root_checker/root_checker_viewmodel.dart @@ -6,12 +6,13 @@ import 'package:root/root.dart'; import 'package:stacked_services/stacked_services.dart'; class RootCheckerViewModel extends BaseViewModel { - final _navigationService = locator(); - bool? isRooted = false; + final NavigationService _navigationService = locator(); + bool isRooted = false; Future checkRoot() async { - isRooted = await Root.isRooted(); - if (isRooted == true) { + bool? res = await Root.isRooted(); + isRooted = res != null && res == true; + if (isRooted) { navigateToHome(); } notifyListeners(); @@ -19,7 +20,7 @@ class RootCheckerViewModel extends BaseViewModel { Future navigateToHome() async { final prefs = await SharedPreferences.getInstance(); - prefs.setBool('isRooted', isRooted!); + prefs.setBool('isRooted', isRooted); _navigationService.navigateTo(Routes.navigation); notifyListeners(); } diff --git a/lib/ui/views/settings/settings_viewmodel.dart b/lib/ui/views/settings/settings_viewmodel.dart index b86eef88..d6567bb2 100644 --- a/lib/ui/views/settings/settings_viewmodel.dart +++ b/lib/ui/views/settings/settings_viewmodel.dart @@ -4,7 +4,7 @@ import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; class SettingsViewModel extends BaseViewModel { - final _navigationService = locator(); + final NavigationService _navigationService = locator(); void setLanguage(String language) { notifyListeners(); diff --git a/lib/ui/widgets/app_selector_card.dart b/lib/ui/widgets/app_selector_card.dart index b23598de..74333307 100644 --- a/lib/ui/widgets/app_selector_card.dart +++ b/lib/ui/widgets/app_selector_card.dart @@ -1,25 +1,21 @@ import 'dart:typed_data'; - import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/constants.dart'; -import 'package:revanced_manager/services/patcher_api.dart'; -import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart'; +import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; class AppSelectorCard extends StatelessWidget { - final Function()? onPressed; + final Function() onPressed; final Color? color; - AppSelectorCard({ + const AppSelectorCard({ Key? key, - this.onPressed, + required this.onPressed, this.color = const Color(0xff1B222B), }) : super(key: key); - final PatcherAPI patcherAPI = locator(); - @override Widget build(BuildContext context) { return GestureDetector( @@ -36,7 +32,7 @@ class AppSelectorCard extends StatelessWidget { children: [ const SizedBox(height: 10), I18nText( - locator().selectedApp == null + locator().selectedApp == null ? 'appSelectorCard.widgetTitle' : 'appSelectorCard.widgetTitleSelected', child: Text( @@ -48,7 +44,7 @@ class AppSelectorCard extends StatelessWidget { ), ), const SizedBox(height: 10), - locator().selectedApp == null + locator().selectedApp == null ? I18nText( 'appSelectorCard.widgetSubtitle', child: Text( @@ -62,11 +58,9 @@ class AppSelectorCard extends StatelessWidget { height: 16.0, child: ClipOval( child: Image.memory( - locator().selectedApp == null + locator().selectedApp == null ? Uint8List(0) - : locator() - .selectedApp! - .icon, + : locator().selectedApp!.icon, fit: BoxFit.cover, ), ), @@ -85,8 +79,8 @@ class AppSelectorCard extends StatelessWidget { } String _getAppSelection() { - String name = locator().selectedApp!.name; - String version = locator().selectedApp!.version; + String name = locator().selectedApp!.name; + String version = locator().selectedApp!.version; return '$name (v$version)'; } } diff --git a/lib/ui/widgets/application_item.dart b/lib/ui/widgets/application_item.dart index 21e3fea8..55830a33 100644 --- a/lib/ui/widgets/application_item.dart +++ b/lib/ui/widgets/application_item.dart @@ -14,7 +14,7 @@ class ApplicationItem extends StatelessWidget { final DateTime patchDate; final String changelog; final bool isUpdatableApp; - final Function()? onPressed; + final Function() onPressed; const ApplicationItem({ Key? key, diff --git a/lib/ui/widgets/available_updates_card.dart b/lib/ui/widgets/available_updates_card.dart index bb3f5ec2..22b1d0c1 100644 --- a/lib/ui/widgets/available_updates_card.dart +++ b/lib/ui/widgets/available_updates_card.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:revanced_manager/app/app.locator.dart'; +import 'package:revanced_manager/constants.dart'; import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/services/github_api.dart'; import 'package:revanced_manager/ui/views/home/home_viewmodel.dart'; @@ -10,7 +11,7 @@ class AvailableUpdatesCard extends StatelessWidget { Key? key, }) : super(key: key); - final GithubAPI githubAPI = GithubAPI(); + final GithubAPI _githubAPI = GithubAPI(); @override Widget build(BuildContext context) { @@ -27,10 +28,10 @@ class AvailableUpdatesCard extends StatelessWidget { physics: const NeverScrollableScrollPhysics(), itemCount: snapshot.data!.length, itemBuilder: (context, index) => FutureBuilder( - future: githubAPI.getChangelog( + future: _githubAPI.getChangelog( snapshot.data![index], - 'revanced', - 'revanced-patches', + ghOrg, + patchesRepo, ), initialData: '', builder: (context, snapshot2) => ApplicationItem( diff --git a/lib/ui/widgets/installed_apps_card.dart b/lib/ui/widgets/installed_apps_card.dart index 5593a3f5..a9c4df2f 100644 --- a/lib/ui/widgets/installed_apps_card.dart +++ b/lib/ui/widgets/installed_apps_card.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:revanced_manager/app/app.locator.dart'; +import 'package:revanced_manager/constants.dart'; import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/services/github_api.dart'; import 'package:revanced_manager/ui/views/home/home_viewmodel.dart'; @@ -10,7 +11,7 @@ class InstalledAppsCard extends StatelessWidget { Key? key, }) : super(key: key); - final GithubAPI githubAPI = GithubAPI(); + final GithubAPI _githubAPI = GithubAPI(); @override Widget build(BuildContext context) { @@ -27,10 +28,10 @@ class InstalledAppsCard extends StatelessWidget { physics: const NeverScrollableScrollPhysics(), itemCount: snapshot.data!.length, itemBuilder: (context, index) => FutureBuilder( - future: githubAPI.getChangelog( + future: _githubAPI.getChangelog( snapshot.data![index], - 'revanced', - 'revanced-patches', + ghOrg, + patchesRepo, ), initialData: '', builder: (context, snapshot2) => ApplicationItem( diff --git a/lib/ui/widgets/latest_commit_card.dart b/lib/ui/widgets/latest_commit_card.dart index b6395ae9..203b9eb8 100644 --- a/lib/ui/widgets/latest_commit_card.dart +++ b/lib/ui/widgets/latest_commit_card.dart @@ -6,9 +6,11 @@ import 'package:revanced_manager/constants.dart'; import 'package:revanced_manager/ui/widgets/patch_text_button.dart'; class LatestCommitCard extends StatefulWidget { + final Function() onPressed; final Color? color; const LatestCommitCard({ Key? key, + required this.onPressed, this.color = const Color(0xff1B222B), }) : super(key: key); @@ -17,7 +19,7 @@ class LatestCommitCard extends StatefulWidget { } class _LatestCommitCardState extends State { - final GithubAPI githubAPI = GithubAPI(); + final GithubAPI _githubAPI = GithubAPI(); @override Widget build(BuildContext context) { @@ -45,10 +47,7 @@ class _LatestCommitCardState extends State { ), ), FutureBuilder( - future: githubAPI.latestCommitTime( - 'revanced', - 'revanced-patcher', - ), + future: _githubAPI.latestCommitTime(ghOrg, patcherRepo), builder: (context, snapshot) => Text( snapshot.hasData && snapshot.data!.isNotEmpty ? FlutterI18n.translate( @@ -78,10 +77,7 @@ class _LatestCommitCardState extends State { ), ), FutureBuilder( - future: githubAPI.latestCommitTime( - 'revanced', - 'revanced-manager', - ), + future: _githubAPI.latestCommitTime(ghOrg, managerRepo), builder: (context, snapshot) => Text( snapshot.hasData && snapshot.data!.isNotEmpty ? FlutterI18n.translate( @@ -105,7 +101,7 @@ class _LatestCommitCardState extends State { context, 'latestCommitCard.updateButton', ), - onPressed: () => {}, + onPressed: widget.onPressed, backgroundColor: Theme.of(context).colorScheme.secondary, borderColor: Theme.of(context).colorScheme.secondary, ), diff --git a/lib/ui/widgets/magisk_button.dart b/lib/ui/widgets/magisk_button.dart index 973eea65..ed26ab30 100644 --- a/lib/ui/widgets/magisk_button.dart +++ b/lib/ui/widgets/magisk_button.dart @@ -5,10 +5,10 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:revanced_manager/theme.dart'; class MagiskButton extends StatelessWidget { - final Function()? onPressed; + final Function() onPressed; const MagiskButton({ Key? key, - this.onPressed, + required this.onPressed, }) : super(key: key); @override diff --git a/lib/ui/widgets/patch_item.dart b/lib/ui/widgets/patch_item.dart index c2a5762c..3acb4426 100644 --- a/lib/ui/widgets/patch_item.dart +++ b/lib/ui/widgets/patch_item.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; -import 'package:revanced_manager/app/app.locator.dart'; -import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart'; // ignore: must_be_immutable class PatchItem extends StatefulWidget { @@ -10,6 +8,7 @@ class PatchItem extends StatefulWidget { final String description; final String version; bool isSelected; + final Function(bool) onChanged; PatchItem({ Key? key, @@ -18,6 +17,7 @@ class PatchItem extends StatefulWidget { required this.description, required this.version, required this.isSelected, + required this.onChanged, }) : super(key: key); @override @@ -30,7 +30,7 @@ class _PatchItemState extends State { return InkWell( onTap: () { setState(() => widget.isSelected = !widget.isSelected); - locator().selectPatch(widget); + widget.onChanged(widget.isSelected); }, child: Container( decoration: BoxDecoration( @@ -82,7 +82,7 @@ class _PatchItemState extends State { activeColor: Colors.blueGrey[500], onChanged: (newValue) { setState(() => widget.isSelected = newValue!); - locator().selectPatch(widget); + widget.onChanged(widget.isSelected); }, ), ) diff --git a/lib/ui/widgets/patch_selector_card.dart b/lib/ui/widgets/patch_selector_card.dart index a4ab8fdc..a70ae7d9 100644 --- a/lib/ui/widgets/patch_selector_card.dart +++ b/lib/ui/widgets/patch_selector_card.dart @@ -4,16 +4,15 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/constants.dart'; import 'package:revanced_manager/models/patch.dart'; -import 'package:revanced_manager/ui/views/app_selector/app_selector_viewmodel.dart'; -import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart'; +import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; class PatchSelectorCard extends StatelessWidget { - final Function()? onPressed; + final Function() onPressed; final Color? color; const PatchSelectorCard({ Key? key, - this.onPressed, + required this.onPressed, this.color = const Color(0xff1B222B), }) : super(key: key); @@ -32,7 +31,7 @@ class PatchSelectorCard extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ I18nText( - locator().selectedPatches.isEmpty + locator().selectedPatches.isEmpty ? 'patchSelectorCard.widgetTitle' : 'patchSelectorCard.widgetTitleSelected', child: Text( @@ -44,7 +43,7 @@ class PatchSelectorCard extends StatelessWidget { ), ), const SizedBox(height: 10), - locator().selectedApp == null + locator().selectedApp == null ? I18nText( 'patchSelectorCard.widgetSubtitle', child: Text( @@ -52,7 +51,7 @@ class PatchSelectorCard extends StatelessWidget { style: robotoTextStyle, ), ) - : locator().selectedPatches.isEmpty + : locator().selectedPatches.isEmpty ? I18nText( 'patchSelectorCard.widgetEmptySubtitle', child: Text( @@ -72,7 +71,7 @@ class PatchSelectorCard extends StatelessWidget { String _getPatchesSelection() { String text = ''; - for (Patch p in locator().selectedPatches) { + for (Patch p in locator().selectedPatches) { text += '${p.simpleName} (v${p.version})\n'; } return text.substring(0, text.length - 1); diff --git a/lib/ui/widgets/patch_text_button.dart b/lib/ui/widgets/patch_text_button.dart index 003a76cb..e042093a 100644 --- a/lib/ui/widgets/patch_text_button.dart +++ b/lib/ui/widgets/patch_text_button.dart @@ -5,13 +5,13 @@ import 'package:revanced_manager/theme.dart'; class PatchTextButton extends StatelessWidget { final String text; - final Function()? onPressed; + final Function() onPressed; final Color borderColor; final Color backgroundColor; const PatchTextButton({ Key? key, required this.text, - this.onPressed, + required this.onPressed, this.borderColor = const Color(0xff7792BA), this.backgroundColor = Colors.transparent, }) : super(key: key); diff --git a/pubspec.yaml b/pubspec.yaml index e924b44b..dc796b32 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ homepage: https://github.com/Aunali321/revanced-manager publish_to: 'none' -version: 1.0.0+1 +version: 0.0.1+1 environment: sdk: ">=2.17.5 <3.0.0" @@ -16,7 +16,6 @@ dependencies: git: url: https://github.com/ponces/flutter_plugin_device_apps ref: appinfo-from-storage - dio: ^4.0.6 expandable: ^5.0.1 file_picker: ^5.0.1 flutter: @@ -24,6 +23,7 @@ dependencies: flutter_background: ^1.1.0 flutter_cache_manager: ^3.3.0 flutter_i18n: ^0.32.4 + flutter_local_notifications: ^9.8.0+1 flutter_svg: ^1.1.1+1 fluttertoast: ^8.0.9 get_it: ^7.2.0