From aa91abb022705cf8c77c4fda4fd7d7bf57befd4c Mon Sep 17 00:00:00 2001 From: festry0 <153519925+festry0@users.noreply.github.com> Date: Thu, 14 Dec 2023 10:54:14 +0300 Subject: [PATCH 01/23] docs(readme): Correct grammar mistake (#1569) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6db2ff9b..c4484d98 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ ReVanced Manager is an Android application that uses ReVanced Patcher to add, re ## 💪 Features -We provide the some of the features are: +Some of the features we provide are: * 📱 **Portable**: ReVanced Patcher that fit in your pocket; * 🤗 **Intuitive UI**: Help you manage your patched applications with easy-to-use interface; From dcaf1f54e4bafc38d9d75626fe2ba0f88abf64fd Mon Sep 17 00:00:00 2001 From: validcube Date: Sun, 17 Dec 2023 20:16:46 +0700 Subject: [PATCH 02/23] build(gradle): bump Gradle to v8.5 Signed-off-by: validcube --- android/gradle/wrapper/gradle-wrapper.properties | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 744c64d1..db8c3baa 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,8 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From c06d15de5f4ff004fc14690058fb1aa3c3338002 Mon Sep 17 00:00:00 2001 From: Radon Rosborough Date: Thu, 21 Dec 2023 20:50:10 -0800 Subject: [PATCH 03/23] docs: Improve troubleshooting solutions (#1543) Co-authored-by: oSumAtrIX --- docs/3_troubleshooting.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/3_troubleshooting.md b/docs/3_troubleshooting.md index 3c1fe03b..1573e508 100644 --- a/docs/3_troubleshooting.md +++ b/docs/3_troubleshooting.md @@ -5,14 +5,16 @@ In case you encounter any issues while using ReVanced Manager, please refer to t - 💉 Patching fails with an error Make sure ReVanced Manager is up to date by following [🔄 Updating ReVanced Manager](2_3_updating.md) and select the **Default** button when choosing patches. - + - 🚫 App not installed as package conflicts with an existing package - An existing installation of the app you're trying to patch is conflicting with the patched app. Uninstall the existing app before installing the patched app. + An existing installation of the app you're trying to patch conflicts with the patched app (i.e., signature mismatch or downgrade). Uninstall the existing app before installing the patched app. - ❗️ Error code `135`, `139` or `1` when patching the app - Your device is not supported. Refer to the [Prerequisites](0_prerequisites.md) page for supported devices. + You may be trying to patch a split APK[^1]. This may not work under certain circumstances. In such a case, patch a full APK. + + Your device may otherwise be unsupported. Please look at the [Prerequisites](0_prerequisites.md) page for supported devices. Alternatively, you can use [ReVanced CLI](https://github.com/revanced/revanced-cli) to patch the app. @@ -25,3 +27,5 @@ In case you encounter any issues while using ReVanced Manager, please refer to t The next page will teach you how to build ReVanced Manager from source. Continue: [🔨 Building from source](4_building.md) + +[^1]: https://developer.android.com/guide/app-bundle/app-bundle-format From f8d086a7438d20ebb99c8bb3310cd471d811673e Mon Sep 17 00:00:00 2001 From: Pun Butrach Date: Fri, 22 Dec 2023 20:34:03 +0700 Subject: [PATCH 04/23] feat: dialogs correctly follows Material 3 specifications (#1560) Signed-off-by: validcube --- lib/services/manager_api.dart | 9 +- .../app_selector/app_selector_viewmodel.dart | 18 ++- lib/ui/views/home/home_viewmodel.dart | 27 ++-- .../views/installer/installer_viewmodel.dart | 21 ++- .../patch_options/patch_options_view.dart | 8 +- .../patch_options_viewmodel.dart | 30 ++--- lib/ui/views/patcher/patcher_viewmodel.dart | 31 ++--- .../patches_selector_viewmodel.dart | 16 +-- .../settings_manage_api_url.dart | 21 ++- .../settings_manage_keystore_password.dart | 11 +- .../settings_manage_sources.dart | 21 ++- .../settings_update_language.dart | 1 - .../settings_update_theme.dart | 15 +-- lib/ui/views/settings/settings_viewmodel.dart | 39 +++--- .../appInfoView/app_info_viewmodel.dart | 21 ++- .../widgets/homeView/latest_commit_card.dart | 9 +- .../homeView/update_confirmation_dialog.dart | 6 +- .../patchesSelectorView/patch_item.dart | 11 +- .../settingsView/settings_export_section.dart | 21 ++- lib/ui/widgets/shared/application_item.dart | 6 +- .../shared/custom_material_button.dart | 126 ------------------ 21 files changed, 135 insertions(+), 333 deletions(-) delete mode 100644 lib/ui/widgets/shared/custom_material_button.dart diff --git a/lib/services/manager_api.dart b/lib/services/manager_api.dart index 7a9e091d..06d87f43 100644 --- a/lib/services/manager_api.dart +++ b/lib/services/manager_api.dart @@ -15,7 +15,6 @@ import 'package:revanced_manager/services/github_api.dart'; import 'package:revanced_manager/services/patcher_api.dart'; import 'package:revanced_manager/services/revanced_api.dart'; import 'package:revanced_manager/services/root_api.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:revanced_manager/utils/check_for_supported_patch.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:timeago/timeago.dart'; @@ -62,7 +61,8 @@ class ManagerAPI { Future initialize() async { _prefs = await SharedPreferences.getInstance(); isRooted = await _rootAPI.isRooted(); - isDynamicThemeAvailable = (await getSdkVersion()) >= 31; // ANDROID_12_SDK_VERSION = 31 + isDynamicThemeAvailable = + (await getSdkVersion()) >= 31; // ANDROID_12_SDK_VERSION = 31 storedPatchesFile = (await getApplicationDocumentsDirectory()).path + storedPatchesFile; } @@ -585,7 +585,6 @@ class ManagerAPI { builder: (context) => WillPopScope( onWillPop: () async => false, child: AlertDialog( - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, title: I18nText('warning'), content: ValueListenableBuilder( valueListenable: noShow, @@ -620,12 +619,12 @@ class ManagerAPI { }, ), actions: [ - CustomMaterialButton( - label: I18nText('okButton'), + FilledButton( onPressed: () { setPatchesChangeWarning(noShow.value); Navigator.of(context).pop(); }, + child: I18nText('okButton'), ), ], ), diff --git a/lib/ui/views/app_selector/app_selector_viewmodel.dart b/lib/ui/views/app_selector/app_selector_viewmodel.dart index 7961ceb9..5b94eee7 100644 --- a/lib/ui/views/app_selector/app_selector_viewmodel.dart +++ b/lib/ui/views/app_selector/app_selector_viewmodel.dart @@ -13,7 +13,6 @@ import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/services/patcher_api.dart'; import 'package:revanced_manager/services/toast.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:revanced_manager/utils/check_for_supported_patch.dart'; import 'package:stacked/stacked.dart'; @@ -105,7 +104,8 @@ class AppSelectorViewModel extends BaseViewModel { ]) async { final String suggestedVersion = getSuggestedVersion(application.packageName); - if (application.versionName != suggestedVersion && suggestedVersion.isNotEmpty) { + if (application.versionName != suggestedVersion && + suggestedVersion.isNotEmpty) { _managerAPI.suggestedAppVersionSelected = false; if (_managerAPI.isRequireSuggestedAppVersionEnabled() && context.mounted) { @@ -168,7 +168,6 @@ class AppSelectorViewModel extends BaseViewModel { return showDialog( context: context, builder: (context) => AlertDialog( - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, title: I18nText('warning'), content: I18nText( 'appSelectorView.requireSuggestedAppVersionDialogText', @@ -185,9 +184,9 @@ class AppSelectorViewModel extends BaseViewModel { ), ), actions: [ - CustomMaterialButton( - label: I18nText('okButton'), + FilledButton( onPressed: () => Navigator.of(context).pop(), + child: I18nText('okButton'), ), ], ), @@ -232,12 +231,12 @@ class AppSelectorViewModel extends BaseViewModel { ), ), const SizedBox(height: 30), - CustomMaterialButton( + FilledButton( onPressed: () async { Navigator.pop(innerContext); await selectAppFromStorage(context); }, - label: Row( + child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.sd_card), @@ -247,12 +246,11 @@ class AppSelectorViewModel extends BaseViewModel { ), ), const SizedBox(height: 10), - CustomMaterialButton( - isFilled: false, + TextButton( onPressed: () { Navigator.pop(innerContext); }, - label: Row( + child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const SizedBox(width: 10), diff --git a/lib/ui/views/home/home_viewmodel.dart b/lib/ui/views/home/home_viewmodel.dart index b85e49da..8df23910 100644 --- a/lib/ui/views/home/home_viewmodel.dart +++ b/lib/ui/views/home/home_viewmodel.dart @@ -21,7 +21,6 @@ import 'package:revanced_manager/services/toast.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/widgets/homeView/update_confirmation_dialog.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; @@ -65,8 +64,8 @@ class HomeViewModel extends BaseViewModel { .resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin>() ?.requestNotificationsPermission(); - final bool isConnected = await Connectivity().checkConnectivity() != - ConnectivityResult.none; + final bool isConnected = + await Connectivity().checkConnectivity() != ConnectivityResult.none; if (!isConnected) { _toast.showBottom('homeView.noConnection'); } @@ -223,21 +222,20 @@ class HomeViewModel extends BaseViewModel { }, ), actions: [ - CustomMaterialButton( - isFilled: false, + TextButton( onPressed: () async { await _managerAPI.setPatchesConsent(false); SystemNavigator.pop(); }, - label: I18nText('quitButton'), + child: I18nText('quitButton'), ), - CustomMaterialButton( + FilledButton( onPressed: () async { await _managerAPI.setPatchesConsent(true); await _managerAPI.setPatchesAutoUpdate(autoUpdate.value); Navigator.of(context).pop(); }, - label: I18nText('okButton'), + child: I18nText('okButton'), ), ], ), @@ -324,12 +322,12 @@ class HomeViewModel extends BaseViewModel { const SizedBox(height: 16.0), Align( alignment: Alignment.centerRight, - child: CustomMaterialButton( - label: I18nText('cancelButton'), + child: FilledButton( onPressed: () { _revancedAPI.disposeManagerUpdateProgress(); Navigator.of(context).pop(); }, + child: I18nText('cancelButton'), ), ), ], @@ -355,24 +353,23 @@ class HomeViewModel extends BaseViewModel { children: [ Align( alignment: Alignment.centerRight, - child: CustomMaterialButton( - isFilled: false, - label: I18nText('cancelButton'), + child: TextButton( onPressed: () { Navigator.of(context).pop(); }, + child: I18nText('cancelButton'), ), ), const SizedBox(width: 8.0), Align( alignment: Alignment.centerRight, - child: CustomMaterialButton( - label: I18nText('updateButton'), + child: FilledButton( onPressed: () async { await InstallPlugin.installApk( downloadedApk!.path, ); }, + child: I18nText('updateButton'), ), ), ], diff --git a/lib/ui/views/installer/installer_viewmodel.dart b/lib/ui/views/installer/installer_viewmodel.dart index d16f1309..32a30197 100644 --- a/lib/ui/views/installer/installer_viewmodel.dart +++ b/lib/ui/views/installer/installer_viewmodel.dart @@ -14,7 +14,6 @@ import 'package:revanced_manager/services/patcher_api.dart'; import 'package:revanced_manager/services/root_api.dart'; import 'package:revanced_manager/services/toast.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:revanced_manager/utils/about_info.dart'; import 'package:screenshot_callback/screenshot_callback.dart'; import 'package:stacked/stacked.dart'; @@ -287,26 +286,24 @@ class InstallerViewModel extends BaseViewModel { title: I18nText( 'warning', ), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, icon: const Icon(Icons.warning), content: SingleChildScrollView( child: I18nText('installerView.screenshotDetected'), ), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('noButton'), + TextButton( onPressed: () { Navigator.of(context).pop(); }, + child: I18nText('noButton'), ), - CustomMaterialButton( - label: I18nText('yesButton'), + FilledButton( onPressed: () { copyLogs(); showPopupScreenshotWarning = true; Navigator.of(context).pop(); }, + child: I18nText('yesButton'), ), ], ), @@ -323,7 +320,6 @@ class InstallerViewModel extends BaseViewModel { title: I18nText( 'installerView.installType', ), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, icon: const Icon(Icons.file_download_outlined), contentPadding: const EdgeInsets.symmetric(vertical: 16), content: SingleChildScrollView( @@ -377,19 +373,18 @@ class InstallerViewModel extends BaseViewModel { ), ), actions: [ - CustomMaterialButton( - label: I18nText('cancelButton'), - isFilled: false, + TextButton( onPressed: () { Navigator.of(context).pop(); }, + child: I18nText('cancelButton'), ), - CustomMaterialButton( - label: I18nText('installerView.installButton'), + FilledButton( onPressed: () { Navigator.of(context).pop(); installResult(context, installType.value == 1); }, + child: I18nText('installerView.installButton'), ), ], ), diff --git a/lib/ui/views/patch_options/patch_options_view.dart b/lib/ui/views/patch_options/patch_options_view.dart index e35b849d..e6ac1bb2 100644 --- a/lib/ui/views/patch_options/patch_options_view.dart +++ b/lib/ui/views/patch_options/patch_options_view.dart @@ -4,7 +4,6 @@ import 'package:google_fonts/google_fonts.dart'; import 'package:revanced_manager/models/patch.dart'; import 'package:revanced_manager/ui/views/patch_options/patch_options_viewmodel.dart'; import 'package:revanced_manager/ui/widgets/patchesSelectorView/patch_options_fields.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:stacked/stacked.dart'; class PatchOptionsView extends StatelessWidget { @@ -82,8 +81,7 @@ class PatchOptionsView extends StatelessWidget { model.modifyOptions(value, option); }, ) - else if (option.valueType == - 'StringArray' || + else if (option.valueType == 'StringArray' || option.valueType == 'IntArray' || option.valueType == 'LongArray') IntStringLongListPatchOption( @@ -104,11 +102,11 @@ class PatchOptionsView extends StatelessWidget { const SizedBox( height: 8, ), - CustomMaterialButton( + FilledButton( onPressed: () { model.showAddOptionDialog(context); }, - label: Row( + child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.add), diff --git a/lib/ui/views/patch_options/patch_options_viewmodel.dart b/lib/ui/views/patch_options/patch_options_viewmodel.dart index 520fd9c6..2dbaef7b 100644 --- a/lib/ui/views/patch_options/patch_options_viewmodel.dart +++ b/lib/ui/views/patch_options/patch_options_viewmodel.dart @@ -6,7 +6,6 @@ import 'package:revanced_manager/services/manager_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:revanced_manager/ui/widgets/shared/custom_card.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:stacked/stacked.dart'; class PatchOptionsViewModel extends BaseViewModel { @@ -32,13 +31,11 @@ class PatchOptionsViewModel extends BaseViewModel { if (savedOptions.isNotEmpty) { visibleOptions = [ ...savedOptions, - ...options - .where( - (option) => - option.required && - !savedOptions.any((sOption) => sOption.key == option.key), - ) - , + ...options.where( + (option) => + option.required && + !savedOptions.any((sOption) => sOption.key == option.key), + ), ]; } else { visibleOptions = [ @@ -136,7 +133,6 @@ class PatchOptionsViewModel extends BaseViewModel { await showDialog( context: context, builder: (context) => AlertDialog( - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, title: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, @@ -154,11 +150,11 @@ class PatchOptionsViewModel extends BaseViewModel { ], ), actions: [ - CustomMaterialButton( - label: I18nText('cancelButton'), + FilledButton( onPressed: () { Navigator.of(context).pop(); }, + child: I18nText('cancelButton'), ), ], contentPadding: const EdgeInsets.all(8), @@ -227,14 +223,9 @@ Future showRequiredOptionNullDialog( await showDialog( context: context, builder: (context) => AlertDialog( - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, title: I18nText('notice'), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText( - 'patchOptionsView.deselectPatch', - ), + TextButton( onPressed: () async { if (managerAPI.isPatchesChangeEnabled()) { locator() @@ -256,12 +247,13 @@ Future showRequiredOptionNullDialog( PatchesSelectorViewModel().showPatchesChangeDialog(context); } }, + child: I18nText('patchOptionsView.deselectPatch'), ), - CustomMaterialButton( - label: I18nText('okButton'), + FilledButton( onPressed: () { Navigator.of(context).pop(); }, + child: I18nText('okButton'), ), ], content: I18nText( diff --git a/lib/ui/views/patcher/patcher_viewmodel.dart b/lib/ui/views/patcher/patcher_viewmodel.dart index 480babec..2c3940fd 100644 --- a/lib/ui/views/patcher/patcher_viewmodel.dart +++ b/lib/ui/views/patcher/patcher_viewmodel.dart @@ -13,7 +13,6 @@ import 'package:revanced_manager/models/patch.dart'; import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/services/patcher_api.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:revanced_manager/utils/about_info.dart'; import 'package:revanced_manager/utils/check_for_supported_patch.dart'; import 'package:stacked/stacked.dart'; @@ -56,25 +55,23 @@ class PatcherViewModel extends BaseViewModel { context: context, builder: (context) => AlertDialog( title: I18nText('notice'), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: I18nText( 'patcherView.removedPatchesWarningDialogText', translationParams: {'patches': removedPatches.join('\n')}, ), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('noButton'), + TextButton( onPressed: () { Navigator.of(context).pop(); }, + child: I18nText('noButton'), ), - CustomMaterialButton( - label: I18nText('yesButton'), + FilledButton( onPressed: () { Navigator.of(context).pop(); showArmv7WarningDialog(context); }, + child: I18nText('yesButton'), ), ], ), @@ -98,22 +95,20 @@ class PatcherViewModel extends BaseViewModel { context: context ?? ctx, builder: (context) => AlertDialog( title: I18nText('notice'), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: I18nText('patcherView.requiredOptionDialogText'), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('cancelButton'), + TextButton( onPressed: () => { Navigator.of(context).pop(), }, + child: I18nText('cancelButton'), ), - CustomMaterialButton( - label: I18nText('okButton'), + FilledButton( onPressed: () => { Navigator.pop(context), navigateToPatchesSelector(), }, + child: I18nText('okButton'), ), ], ), @@ -131,20 +126,18 @@ class PatcherViewModel extends BaseViewModel { context: context, builder: (context) => AlertDialog( title: I18nText('warning'), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: I18nText('patcherView.armv7WarningDialogText'), actions: [ - CustomMaterialButton( - label: I18nText('noButton'), + FilledButton( onPressed: () => Navigator.of(context).pop(), + child: I18nText('noButton'), ), - CustomMaterialButton( - label: I18nText('yesButton'), - isFilled: false, + TextButton( onPressed: () { Navigator.of(context).pop(); navigateToInstaller(); }, + child: I18nText('yesButton'), ), ], ), diff --git a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart index 71d073a9..6886e0a0 100644 --- a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart +++ b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart @@ -10,7 +10,6 @@ import 'package:revanced_manager/services/patcher_api.dart'; import 'package:revanced_manager/services/toast.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; import 'package:revanced_manager/ui/widgets/patchesSelectorView/patch_item.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:revanced_manager/utils/check_for_supported_patch.dart'; import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; @@ -94,7 +93,6 @@ class PatchesSelectorViewModel extends BaseViewModel { context: context, builder: (context) => AlertDialog( title: I18nText('notice'), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: I18nText( 'patchesSelectorView.setRequiredOption', translationParams: { @@ -102,11 +100,11 @@ class PatchesSelectorViewModel extends BaseViewModel { }, ), actions: [ - CustomMaterialButton( - label: I18nText('okButton'), + FilledButton( onPressed: () => { Navigator.of(context).pop(), }, + child: I18nText('okButton'), ), ], ), @@ -130,7 +128,6 @@ class PatchesSelectorViewModel extends BaseViewModel { return showDialog( context: context, builder: (context) => AlertDialog( - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, title: I18nText('warning'), content: I18nText( 'patchItem.patchesChangeWarningDialogText', @@ -143,18 +140,17 @@ class PatchesSelectorViewModel extends BaseViewModel { ), ), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('okButton'), + TextButton( onPressed: () => Navigator.of(context).pop(), + child: I18nText('okButton'), ), - CustomMaterialButton( - label: I18nText('patchItem.patchesChangeWarningDialogButton'), + FilledButton( onPressed: () { Navigator.of(context) ..pop() ..pop(); }, + child: I18nText('patchItem.patchesChangeWarningDialogButton'), ), ], ), diff --git a/lib/ui/views/settings/settingsFragment/settings_manage_api_url.dart b/lib/ui/views/settings/settingsFragment/settings_manage_api_url.dart index 6fa1ccc1..5669a073 100644 --- a/lib/ui/views/settings/settingsFragment/settings_manage_api_url.dart +++ b/lib/ui/views/settings/settingsFragment/settings_manage_api_url.dart @@ -7,7 +7,6 @@ import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/services/toast.dart'; import 'package:revanced_manager/ui/widgets/settingsView/custom_text_field.dart'; import 'package:revanced_manager/ui/widgets/settingsView/settings_tile_dialog.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:stacked/stacked.dart'; class SManageApiUrl extends BaseViewModel { @@ -33,7 +32,6 @@ class SManageApiUrl extends BaseViewModel { ), ], ), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: SingleChildScrollView( child: Column( children: [ @@ -51,16 +49,14 @@ class SManageApiUrl extends BaseViewModel { ), ), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('cancelButton'), + TextButton( onPressed: () { _apiUrlController.clear(); Navigator.of(context).pop(); }, + child: I18nText('cancelButton'), ), - CustomMaterialButton( - label: I18nText('okButton'), + FilledButton( onPressed: () { String apiUrl = _apiUrlController.text; if (!apiUrl.startsWith('https')) { @@ -70,6 +66,7 @@ class SManageApiUrl extends BaseViewModel { _toast.showBottom('settingsView.restartAppForChanges'); Navigator.of(context).pop(); }, + child: I18nText('okButton'), ), ], ), @@ -81,16 +78,13 @@ class SManageApiUrl extends BaseViewModel { context: context, builder: (context) => AlertDialog( title: I18nText('settingsView.sourcesResetDialogTitle'), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: I18nText('settingsView.apiURLResetDialogText'), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('noButton'), + TextButton( onPressed: () => Navigator.of(context).pop(), + child: I18nText('noButton'), ), - CustomMaterialButton( - label: I18nText('yesButton'), + FilledButton( onPressed: () { _managerAPI.setApiUrl(''); _toast.showBottom('settingsView.restartAppForChanges'); @@ -98,6 +92,7 @@ class SManageApiUrl extends BaseViewModel { ..pop() ..pop(); }, + child: I18nText('yesButton'), ), ], ), diff --git a/lib/ui/views/settings/settingsFragment/settings_manage_keystore_password.dart b/lib/ui/views/settings/settingsFragment/settings_manage_keystore_password.dart index 4ac4689b..fb717f64 100644 --- a/lib/ui/views/settings/settingsFragment/settings_manage_keystore_password.dart +++ b/lib/ui/views/settings/settingsFragment/settings_manage_keystore_password.dart @@ -6,7 +6,6 @@ import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/ui/widgets/settingsView/custom_text_field.dart'; import 'package:revanced_manager/ui/widgets/settingsView/settings_tile_dialog.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:stacked/stacked.dart'; class SManageKeystorePassword extends BaseViewModel { @@ -33,7 +32,6 @@ class SManageKeystorePassword extends BaseViewModel { ), ], ), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: SingleChildScrollView( child: Column( children: [ @@ -47,21 +45,20 @@ class SManageKeystorePassword extends BaseViewModel { ), ), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('cancelButton'), + TextButton( onPressed: () { _keystorePasswordController.clear(); Navigator.of(context).pop(); }, + child: I18nText('cancelButton'), ), - CustomMaterialButton( - label: I18nText('okButton'), + FilledButton( onPressed: () { final String passwd = _keystorePasswordController.text; _managerAPI.setKeystorePassword(passwd); Navigator.of(context).pop(); }, + child: I18nText('okButton'), ), ], ), diff --git a/lib/ui/views/settings/settingsFragment/settings_manage_sources.dart b/lib/ui/views/settings/settingsFragment/settings_manage_sources.dart index 76e3171b..52c30ff0 100644 --- a/lib/ui/views/settings/settingsFragment/settings_manage_sources.dart +++ b/lib/ui/views/settings/settingsFragment/settings_manage_sources.dart @@ -7,7 +7,6 @@ import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/services/toast.dart'; import 'package:revanced_manager/ui/widgets/settingsView/custom_text_field.dart'; import 'package:revanced_manager/ui/widgets/settingsView/settings_tile_dialog.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:stacked/stacked.dart'; class SManageSources extends BaseViewModel { @@ -43,7 +42,6 @@ class SManageSources extends BaseViewModel { ), ], ), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: SingleChildScrollView( child: Column( children: [ @@ -107,9 +105,7 @@ class SManageSources extends BaseViewModel { ), ), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('cancelButton'), + TextButton( onPressed: () { _orgPatSourceController.clear(); _patSourceController.clear(); @@ -117,9 +113,9 @@ class SManageSources extends BaseViewModel { _intSourceController.clear(); Navigator.of(context).pop(); }, + child: I18nText('cancelButton'), ), - CustomMaterialButton( - label: I18nText('okButton'), + FilledButton( onPressed: () { _managerAPI.setRepoUrl(_hostSourceController.text.trim()); _managerAPI.setPatchesRepo( @@ -133,6 +129,7 @@ class SManageSources extends BaseViewModel { _toast.showBottom('settingsView.restartAppForChanges'); Navigator.of(context).pop(); }, + child: I18nText('okButton'), ), ], ), @@ -144,16 +141,13 @@ class SManageSources extends BaseViewModel { context: context, builder: (context) => AlertDialog( title: I18nText('settingsView.sourcesResetDialogTitle'), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: I18nText('settingsView.sourcesResetDialogText'), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('noButton'), + TextButton( onPressed: () => Navigator.of(context).pop(), + child: I18nText('noButton'), ), - CustomMaterialButton( - label: I18nText('yesButton'), + FilledButton( onPressed: () { _managerAPI.setRepoUrl(''); _managerAPI.setPatchesRepo(''); @@ -165,6 +159,7 @@ class SManageSources extends BaseViewModel { ..pop() ..pop(); }, + child: I18nText('yesButton'), ), ], ), diff --git a/lib/ui/views/settings/settingsFragment/settings_update_language.dart b/lib/ui/views/settings/settingsFragment/settings_update_language.dart index 66bb2c3e..1e7b4a72 100644 --- a/lib/ui/views/settings/settingsFragment/settings_update_language.dart +++ b/lib/ui/views/settings/settingsFragment/settings_update_language.dart @@ -51,7 +51,6 @@ class SUpdateLanguage extends BaseViewModel { context: parentContext, builder: (context) => SimpleDialog( title: I18nText('settingsView.languageLabel'), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, children: [ SizedBox( height: 500, diff --git a/lib/ui/views/settings/settingsFragment/settings_update_theme.dart b/lib/ui/views/settings/settingsFragment/settings_update_theme.dart index 66fa6830..09c1b28b 100644 --- a/lib/ui/views/settings/settingsFragment/settings_update_theme.dart +++ b/lib/ui/views/settings/settingsFragment/settings_update_theme.dart @@ -7,7 +7,6 @@ import 'package:flutter_i18n/widgets/I18nText.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; class SUpdateThemeUI extends StatefulWidget { const SUpdateThemeUI({super.key}); @@ -36,9 +35,9 @@ class _SUpdateThemeUIState extends State { ), ), ), - trailing: CustomMaterialButton( - label: getThemeModeName(), + trailing: FilledButton( onPressed: () => {showThemeDialog(context)}, + child: getThemeModeName(), ), onTap: () => {showThemeDialog(context)}, ), @@ -122,7 +121,6 @@ class _SUpdateThemeUIState extends State { title: I18nText('settingsView.themeModeLabel'), icon: const Icon(Icons.palette), contentPadding: const EdgeInsets.symmetric(vertical: 16), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: SingleChildScrollView( child: ValueListenableBuilder( valueListenable: newTheme, @@ -164,19 +162,18 @@ class _SUpdateThemeUIState extends State { ), ), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('cancelButton'), + TextButton( onPressed: () { Navigator.of(context).pop(); }, + child: I18nText('cancelButton'), ), - CustomMaterialButton( - label: I18nText('okButton'), + FilledButton( onPressed: () { setThemeMode(context, newTheme.value); Navigator.of(context).pop(); }, + child: I18nText('okButton'), ), ], ), diff --git a/lib/ui/views/settings/settings_viewmodel.dart b/lib/ui/views/settings/settings_viewmodel.dart index e51b1382..6fa85730 100644 --- a/lib/ui/views/settings/settings_viewmodel.dart +++ b/lib/ui/views/settings/settings_viewmodel.dart @@ -12,7 +12,6 @@ import 'package:revanced_manager/services/toast.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:revanced_manager/ui/views/settings/settingsFragment/settings_update_language.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:share_plus/share_plus.dart'; import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; @@ -52,7 +51,6 @@ class SettingsViewModel extends BaseViewModel { return showDialog( context: context, builder: (context) => AlertDialog( - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, title: I18nText('warning'), content: I18nText( 'settingsView.enablePatchesSelectionWarningText', @@ -65,20 +63,19 @@ class SettingsViewModel extends BaseViewModel { ), ), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('yesButton'), + TextButton( onPressed: () { _managerAPI.setChangingToggleModified(true); _managerAPI.setPatchesChangeEnabled(true); Navigator.of(context).pop(); }, + child: I18nText('yesButton'), ), - CustomMaterialButton( - label: I18nText('noButton'), + FilledButton( onPressed: () { Navigator.of(context).pop(); }, + child: I18nText('noButton'), ), ], ), @@ -87,7 +84,6 @@ class SettingsViewModel extends BaseViewModel { return showDialog( context: context, builder: (context) => AlertDialog( - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, title: I18nText('warning'), content: I18nText( 'settingsView.disablePatchesSelectionWarningText', @@ -100,21 +96,20 @@ class SettingsViewModel extends BaseViewModel { ), ), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('noButton'), + TextButton( onPressed: () { Navigator.of(context).pop(); }, + child: I18nText('noButton'), ), - CustomMaterialButton( - label: I18nText('yesButton'), + FilledButton( onPressed: () { _managerAPI.setChangingToggleModified(true); _patchesSelectorViewModel.selectDefaultPatches(); _managerAPI.setPatchesChangeEnabled(false); Navigator.of(context).pop(); }, + child: I18nText('yesButton'), ), ], ), @@ -145,12 +140,13 @@ class SettingsViewModel extends BaseViewModel { } Future? showRequireSuggestedAppVersionDialog( - BuildContext context, bool value,) { + BuildContext context, + bool value, + ) { if (!value) { return showDialog( context: context, builder: (context) => AlertDialog( - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, title: I18nText('warning'), content: I18nText( 'settingsView.requireSuggestedAppVersionDialogText', @@ -163,19 +159,18 @@ class SettingsViewModel extends BaseViewModel { ), ), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('yesButton'), + TextButton( onPressed: () { _managerAPI.enableRequireSuggestedAppVersionStatus(false); Navigator.of(context).pop(); }, + child: I18nText('yesButton'), ), - CustomMaterialButton( - label: I18nText('noButton'), + FilledButton( onPressed: () { Navigator.of(context).pop(); }, + child: I18nText('noButton'), ), ], ), @@ -210,7 +205,7 @@ class SettingsViewModel extends BaseViewModel { final String dateTime = DateTime.now().toString().replaceAll(' ', '_').split('.').first; await FlutterFileDialog.saveFile( - params: SaveFileDialogParams( + params: SaveFileDialogParams( sourceFilePath: outFile.path, fileName: 'selected_patches_$dateTime.json', ), @@ -261,7 +256,7 @@ class SettingsViewModel extends BaseViewModel { final String dateTime = DateTime.now().toString().replaceAll(' ', '_').split('.').first; await FlutterFileDialog.saveFile( - params: SaveFileDialogParams( + params: SaveFileDialogParams( sourceFilePath: outFile.path, fileName: 'keystore_$dateTime.keystore', ), diff --git a/lib/ui/widgets/appInfoView/app_info_viewmodel.dart b/lib/ui/widgets/appInfoView/app_info_viewmodel.dart index 32441567..60b9681a 100644 --- a/lib/ui/widgets/appInfoView/app_info_viewmodel.dart +++ b/lib/ui/widgets/appInfoView/app_info_viewmodel.dart @@ -12,7 +12,6 @@ import 'package:revanced_manager/services/toast.dart'; import 'package:revanced_manager/ui/views/home/home_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/widgets/shared/custom_material_button.dart'; import 'package:stacked/stacked.dart'; class AppInfoViewModel extends BaseViewModel { @@ -67,12 +66,11 @@ class AppInfoViewModel extends BaseViewModel { context: context, builder: (context) => AlertDialog( title: I18nText('appInfoView.rootDialogTitle'), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: I18nText('appInfoView.rootDialogText'), actions: [ - CustomMaterialButton( - label: I18nText('okButton'), + FilledButton( onPressed: () => Navigator.of(context).pop(), + child: I18nText('okButton'), ), ], ), @@ -85,23 +83,21 @@ class AppInfoViewModel extends BaseViewModel { title: I18nText( 'appInfoView.unpatchButton', ), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: I18nText( 'appInfoView.unpatchDialogText', ), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('noButton'), + TextButton( onPressed: () => Navigator.of(context).pop(), + child: I18nText('noButton'), ), - CustomMaterialButton( - label: I18nText('yesButton'), + FilledButton( onPressed: () { uninstallApp(context, app, onlyUnpatch); Navigator.of(context).pop(); Navigator.of(context).pop(); }, + child: I18nText('yesButton'), ), ], ), @@ -131,14 +127,13 @@ class AppInfoViewModel extends BaseViewModel { context: context, builder: (context) => AlertDialog( title: I18nText('appInfoView.appliedPatchesLabel'), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: SingleChildScrollView( child: Text(getAppliedPatchesString(app.appliedPatches)), ), actions: [ - CustomMaterialButton( - label: I18nText('okButton'), + FilledButton( onPressed: () => Navigator.of(context).pop(), + child: I18nText('okButton'), ), ], ), diff --git a/lib/ui/widgets/homeView/latest_commit_card.dart b/lib/ui/widgets/homeView/latest_commit_card.dart index 9d0625ce..55252698 100644 --- a/lib/ui/widgets/homeView/latest_commit_card.dart +++ b/lib/ui/widgets/homeView/latest_commit_card.dart @@ -3,7 +3,6 @@ import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/ui/views/home/home_viewmodel.dart'; import 'package:revanced_manager/ui/widgets/shared/custom_card.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; class LatestCommitCard extends StatefulWidget { const LatestCommitCard({ @@ -58,14 +57,14 @@ class _LatestCommitCardState extends State { initialData: false, builder: (context, snapshot) => Opacity( opacity: snapshot.hasData && snapshot.data! ? 1.0 : 0.25, - child: CustomMaterialButton( - label: I18nText('updateButton'), + child: FilledButton( onPressed: snapshot.hasData && snapshot.data! ? () => widget.model.showUpdateConfirmationDialog( widget.parentContext, false, ) : () => {}, + child: I18nText('updateButton'), ), ), ), @@ -113,14 +112,14 @@ class _LatestCommitCardState extends State { initialData: false, builder: (context, snapshot) => Opacity( opacity: snapshot.hasData && snapshot.data! ? 1.0 : 0.25, - child: CustomMaterialButton( - label: I18nText('updateButton'), + child: FilledButton( onPressed: snapshot.hasData && snapshot.data! ? () => widget.model.showUpdateConfirmationDialog( widget.parentContext, true, ) : () => {}, + child: I18nText('updateButton'), ), ), ), diff --git a/lib/ui/widgets/homeView/update_confirmation_dialog.dart b/lib/ui/widgets/homeView/update_confirmation_dialog.dart index 7839536a..de5b72a0 100644 --- a/lib/ui/widgets/homeView/update_confirmation_dialog.dart +++ b/lib/ui/widgets/homeView/update_confirmation_dialog.dart @@ -3,7 +3,6 @@ import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/ui/views/home/home_viewmodel.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; class UpdateConfirmationDialog extends StatelessWidget { const UpdateConfirmationDialog({super.key, required this.isPatches}); @@ -86,15 +85,14 @@ class UpdateConfirmationDialog extends StatelessWidget { ], ), ), - CustomMaterialButton( - isExpanded: true, - label: I18nText('updateButton'), + FilledButton( onPressed: () { Navigator.of(context).pop(); isPatches ? model.updatePatches(context) : model.updateManager(context); }, + child: I18nText('updateButton'), ), ], ), diff --git a/lib/ui/widgets/patchesSelectorView/patch_item.dart b/lib/ui/widgets/patchesSelectorView/patch_item.dart index 11fd0839..70692ab2 100644 --- a/lib/ui/widgets/patchesSelectorView/patch_item.dart +++ b/lib/ui/widgets/patchesSelectorView/patch_item.dart @@ -5,7 +5,6 @@ import 'package:revanced_manager/models/patch.dart'; import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/services/toast.dart'; import 'package:revanced_manager/ui/widgets/shared/custom_card.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; // ignore: must_be_immutable class PatchItem extends StatefulWidget { @@ -216,7 +215,6 @@ class _PatchItemState extends State { context: context, builder: (context) => AlertDialog( title: I18nText('warning'), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: I18nText( 'patchItem.unsupportedDialogText', translationParams: { @@ -226,9 +224,9 @@ class _PatchItemState extends State { }, ), actions: [ - CustomMaterialButton( - label: I18nText('okButton'), + FilledButton( onPressed: () => Navigator.of(context).pop(), + child: I18nText('okButton'), ), ], ), @@ -240,14 +238,13 @@ class _PatchItemState extends State { context: context, builder: (context) => AlertDialog( title: I18nText('notice'), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: I18nText( 'patchItem.unsupportedRequiredOption', ), actions: [ - CustomMaterialButton( - label: I18nText('okButton'), + FilledButton( onPressed: () => Navigator.of(context).pop(), + child: I18nText('okButton'), ), ], ), diff --git a/lib/ui/widgets/settingsView/settings_export_section.dart b/lib/ui/widgets/settingsView/settings_export_section.dart index 70aaf9b0..2f7e4aa7 100644 --- a/lib/ui/widgets/settingsView/settings_export_section.dart +++ b/lib/ui/widgets/settingsView/settings_export_section.dart @@ -3,7 +3,6 @@ import 'package:flutter_i18n/widgets/I18nText.dart'; import 'package:revanced_manager/ui/views/settings/settingsFragment/settings_manage_keystore_password.dart'; import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart'; import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; final _settingsViewModel = SettingsViewModel(); @@ -151,20 +150,18 @@ class SExportSection extends StatelessWidget { context: context, builder: (context) => AlertDialog( title: I18nText(dialogTitle), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: I18nText(dialogText), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('noButton'), + TextButton( onPressed: () => Navigator.of(context).pop(), + child: I18nText('noButton'), ), - CustomMaterialButton( - label: I18nText('yesButton'), + FilledButton( onPressed: () => { Navigator.of(context).pop(), dialogAction(), }, + child: I18nText('yesButton'), ), ], ), @@ -176,20 +173,18 @@ class SExportSection extends StatelessWidget { context: context, builder: (context) => AlertDialog( title: I18nText('settingsView.regenerateKeystoreDialogTitle'), - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, content: I18nText('settingsView.regenerateKeystoreDialogText'), actions: [ - CustomMaterialButton( - isFilled: false, - label: I18nText('noButton'), + TextButton( onPressed: () => Navigator.of(context).pop(), + child: I18nText('noButton'), ), - CustomMaterialButton( - label: I18nText('yesButton'), + FilledButton( onPressed: () => { Navigator.of(context).pop(), _settingsViewModel.deleteKeystore(), }, + child: I18nText('yesButton'), ), ], ), diff --git a/lib/ui/widgets/shared/application_item.dart b/lib/ui/widgets/shared/application_item.dart index 5f527eb1..ce432138 100644 --- a/lib/ui/widgets/shared/application_item.dart +++ b/lib/ui/widgets/shared/application_item.dart @@ -3,7 +3,6 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:revanced_manager/ui/widgets/shared/custom_card.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:timeago/timeago.dart'; class ApplicationItem extends StatefulWidget { @@ -24,7 +23,6 @@ class ApplicationItem extends StatefulWidget { } class _ApplicationItemState extends State { - @override void initState() { super.initState(); @@ -81,9 +79,9 @@ class _ApplicationItemState extends State { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: [ - CustomMaterialButton( - label: I18nText('applicationItem.infoButton'), + FilledButton( onPressed: widget.onPressed, + child: I18nText('applicationItem.infoButton'), ), ], ), diff --git a/lib/ui/widgets/shared/custom_material_button.dart b/lib/ui/widgets/shared/custom_material_button.dart deleted file mode 100644 index c861a709..00000000 --- a/lib/ui/widgets/shared/custom_material_button.dart +++ /dev/null @@ -1,126 +0,0 @@ -import 'package:flutter/material.dart'; - -class CustomMaterialButton extends StatelessWidget { - const CustomMaterialButton({ - super.key, - required this.label, - this.isFilled = true, - this.isExpanded = false, - required this.onPressed, - }); - final Widget label; - final bool isFilled; - final bool isExpanded; - final Function()? onPressed; - - @override - Widget build(BuildContext context) { - return TextButton( - style: ButtonStyle( - padding: MaterialStateProperty.all( - isExpanded - ? const EdgeInsets.symmetric(horizontal: 24, vertical: 12) - : const EdgeInsets.symmetric(horizontal: 20, vertical: 12), - ), - shape: MaterialStateProperty.all( - StadiumBorder( - side: isFilled - ? BorderSide.none - : BorderSide( - color: Theme.of(context).colorScheme.primary, - ), - ), - ), - backgroundColor: MaterialStateProperty.all( - isFilled ? Theme.of(context).colorScheme.primary : Colors.transparent, - ), - foregroundColor: MaterialStateProperty.all( - isFilled - ? Theme.of(context).colorScheme.surface - : Theme.of(context).colorScheme.primary, - ), - ), - onPressed: onPressed, - child: label, - ); - } -} - -// ignore: must_be_immutable -class TimerButton extends StatefulWidget { - TimerButton({ - super.key, - required this.seconds, - required this.isRunning, - required this.onTimerEnd, - this.label = const Text(''), - this.isFilled = true, - }); - Widget label; - bool isFilled; - int seconds; - final bool isRunning; - final Function()? onTimerEnd; - - @override - State createState() => _TimerButtonState(); -} - -class _TimerButtonState extends State { - void timer(int seconds) { - Future.delayed(const Duration(seconds: 1), () { - if (seconds > 0) { - setState(() { - seconds--; - }); - timer(seconds); - } else { - widget.onTimerEnd!(); - } - }); - } - - @override - void initState() { - //decrement seconds - if (widget.isRunning) { - timer(widget.seconds); - } - super.initState(); - } - - @override - Widget build(BuildContext build) { - return TextButton( - style: ButtonStyle( - shape: MaterialStateProperty.all( - StadiumBorder( - side: widget.isFilled - ? BorderSide.none - : BorderSide( - color: Theme.of(context).colorScheme.primary, - ), - ), - ), - backgroundColor: MaterialStateProperty.all( - widget.isFilled - ? Theme.of(context).colorScheme.primary - : Colors.transparent, - ), - foregroundColor: MaterialStateProperty.all( - widget.isFilled - ? Theme.of(context).colorScheme.surface - : Theme.of(context).colorScheme.primary, - ), - ), - onPressed: widget.isRunning ? null : widget.onTimerEnd, - child: Text( - widget.isRunning ? '${widget.seconds}' : 'Install', - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - ); - } -} From 8b28a33b73a98372df7f0ac6c373624d0ac2f46b Mon Sep 17 00:00:00 2001 From: Pun Butrach Date: Fri, 22 Dec 2023 20:39:21 +0700 Subject: [PATCH 05/23] ci(security): resolve arbitrary code execution --- .github/workflows/pr-build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index 009cef0d..08cb344c 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -45,10 +45,10 @@ jobs: env: GH_TOKEN: ${{ github.token }} run: | - gh repo clone ${{ github.repository }} + gh repo clone "${{ github.repository }}" cd revanced-manager - gh repo set-default ${{ github.repository }} - gh pr checkout ${{ inputs.pr-number }} + gh repo set-default "${{ github.repository }}" + gh pr checkout "${{ inputs.pr-number }}" echo "DATETIME=$( TZ='UTC+0' date --rfc-email )" >> $GITHUB_ENV echo "COMMIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV @@ -83,7 +83,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - flutter build apk --${{ inputs.app-flavour }}; + flutter build apk --"${{ inputs.app-flavour }}"; - name: Prepare to comment run: | From c23275f2fe2f00f6afc1a52e2b15cdb2d4b2a16b Mon Sep 17 00:00:00 2001 From: aAbed <39409020+TheAabedKhan@users.noreply.github.com> Date: Sat, 23 Dec 2023 09:01:28 +0545 Subject: [PATCH 06/23] feat: Improve installation robustness (#1528) Co-authored-by: oSumAtrIX Co-authored-by: Ushie Co-authored-by: Dhruvan Bhalara <53393418+dhruvanbhalara@users.noreply.github.com> Co-authored-by: Pun Butrach --- android/app/src/main/AndroidManifest.xml | 33 +- .../revanced/manager/flutter/MainActivity.kt | 59 ++- .../packageInstaller/InstallerReceiver.kt | 32 ++ .../packageInstaller/UninstallerReceiver.kt | 24 + assets/i18n/en_US.json | 31 ++ lib/main.dart | 8 + lib/services/download_manager.dart | 1 - lib/services/patcher_api.dart | 429 +++++++++++++----- lib/services/root_api.dart | 132 ++---- lib/ui/views/home/home_viewmodel.dart | 13 +- .../views/installer/installer_viewmodel.dart | 88 +++- .../patches_selector_viewmodel.dart | 4 - .../appInfoView/app_info_viewmodel.dart | 4 +- pubspec.yaml | 4 - 14 files changed, 610 insertions(+), 252 deletions(-) create mode 100644 android/app/src/main/kotlin/app/revanced/manager/flutter/utils/packageInstaller/InstallerReceiver.kt create mode 100644 android/app/src/main/kotlin/app/revanced/manager/flutter/utils/packageInstaller/UninstallerReceiver.kt diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 7fade03b..782ef780 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -32,17 +32,17 @@ android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> + android:name="io.flutter.embedding.android.NormalTheme" + android:resource="@style/NormalTheme" /> - - + + - - + + @@ -55,5 +55,22 @@ android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/app/revanced/manager/flutter/MainActivity.kt b/android/app/src/main/kotlin/app/revanced/manager/flutter/MainActivity.kt index 10ff238e..6fe5438e 100644 --- a/android/app/src/main/kotlin/app/revanced/manager/flutter/MainActivity.kt +++ b/android/app/src/main/kotlin/app/revanced/manager/flutter/MainActivity.kt @@ -1,11 +1,16 @@ package app.revanced.manager.flutter +import android.app.PendingIntent import android.app.SearchManager import android.content.Intent +import android.content.pm.PackageInstaller +import android.os.Build import android.os.Handler import android.os.Looper import app.revanced.manager.flutter.utils.Aapt import app.revanced.manager.flutter.utils.aligning.ZipAligner +import app.revanced.manager.flutter.utils.packageInstaller.InstallerReceiver +import app.revanced.manager.flutter.utils.packageInstaller.UninstallerReceiver import app.revanced.manager.flutter.utils.signing.Signer import app.revanced.manager.flutter.utils.zip.ZipFile import app.revanced.manager.flutter.utils.zip.structures.ZipEntry @@ -184,12 +189,24 @@ class MainActivity : FlutterActivity() { }.toString().let(result::success) } + "installApk" -> { + val apkPath = call.argument("apkPath")!! + PackageInstallerManager.result = result + installApk(apkPath) + } + + "uninstallApp" -> { + val packageName = call.argument("packageName")!! + uninstallApp(packageName) + PackageInstallerManager.result = result + } + else -> result.notImplemented() } } } - fun openBrowser(query: String?) { + private fun openBrowser(query: String?) { val intent = Intent(Intent.ACTION_WEB_SEARCH).apply { putExtra(SearchManager.QUERY, query) } @@ -407,4 +424,44 @@ class MainActivity : FlutterActivity() { handler.post { result.success(null) } }.start() } + + private fun installApk(apkPath: String) { + val packageInstaller: PackageInstaller = applicationContext.packageManager.packageInstaller + val sessionParams = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL) + val sessionId: Int = packageInstaller.createSession(sessionParams) + val session: PackageInstaller.Session = packageInstaller.openSession(sessionId) + session.use { activeSession -> + val sessionOutputStream = activeSession.openWrite(applicationContext.packageName, 0, -1) + sessionOutputStream.use { outputStream -> + val apkFile = File(apkPath) + apkFile.inputStream().use { inputStream -> + inputStream.copyTo(outputStream) + } + } + } + val receiverIntent = Intent(applicationContext, InstallerReceiver::class.java).apply { + action = "APP_INSTALL_ACTION" + } + val receiverPendingIntent = PendingIntent.getBroadcast(context, sessionId, receiverIntent, PackageInstallerManager.flags) + session.commit(receiverPendingIntent.intentSender) + session.close() + } + + private fun uninstallApp(packageName: String) { + val packageInstaller: PackageInstaller = applicationContext.packageManager.packageInstaller + val receiverIntent = Intent(applicationContext, UninstallerReceiver::class.java).apply { + action = "APP_UNINSTALL_ACTION" + } + val receiverPendingIntent = PendingIntent.getBroadcast(context, 0, receiverIntent, PackageInstallerManager.flags) + packageInstaller.uninstall(packageName, receiverPendingIntent.intentSender) + } + + object PackageInstallerManager { + var result: MethodChannel.Result? = null + val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT + } else { + PendingIntent.FLAG_UPDATE_CURRENT + } + } } diff --git a/android/app/src/main/kotlin/app/revanced/manager/flutter/utils/packageInstaller/InstallerReceiver.kt b/android/app/src/main/kotlin/app/revanced/manager/flutter/utils/packageInstaller/InstallerReceiver.kt new file mode 100644 index 00000000..d14a9daa --- /dev/null +++ b/android/app/src/main/kotlin/app/revanced/manager/flutter/utils/packageInstaller/InstallerReceiver.kt @@ -0,0 +1,32 @@ +package app.revanced.manager.flutter.utils.packageInstaller + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.pm.PackageInstaller +import app.revanced.manager.flutter.MainActivity + +class InstallerReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + when (val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -1)) { + PackageInstaller.STATUS_PENDING_USER_ACTION -> { + val confirmationIntent = intent.getParcelableExtra(Intent.EXTRA_INTENT) + if (confirmationIntent != null) { + context.startActivity(confirmationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)) + } + } + + else -> { + val packageName = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME) + val message = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + val otherPackageName = intent.getStringExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME) + MainActivity.PackageInstallerManager.result!!.success(mapOf( + "status" to status, + "packageName" to packageName, + "message" to message, + "otherPackageName" to otherPackageName + )) + } + } + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/app/revanced/manager/flutter/utils/packageInstaller/UninstallerReceiver.kt b/android/app/src/main/kotlin/app/revanced/manager/flutter/utils/packageInstaller/UninstallerReceiver.kt new file mode 100644 index 00000000..84dec3cc --- /dev/null +++ b/android/app/src/main/kotlin/app/revanced/manager/flutter/utils/packageInstaller/UninstallerReceiver.kt @@ -0,0 +1,24 @@ +package app.revanced.manager.flutter.utils.packageInstaller + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.pm.PackageInstaller +import app.revanced.manager.flutter.MainActivity + +class UninstallerReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + when (val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -1)) { + PackageInstaller.STATUS_PENDING_USER_ACTION -> { + val confirmationIntent = intent.getParcelableExtra(Intent.EXTRA_INTENT) + if (confirmationIntent != null) { + context.startActivity(confirmationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)) + } + } + + else -> { + MainActivity.PackageInstallerManager.result!!.success(status) + } + } + } +} \ No newline at end of file diff --git a/assets/i18n/en_US.json b/assets/i18n/en_US.json index 511cd9c4..dde2237a 100644 --- a/assets/i18n/en_US.json +++ b/assets/i18n/en_US.json @@ -170,6 +170,8 @@ "installRootType": "Mount", "installNonRootType": "Normal", + "warning": "Disable auto updates after installing the app to avoid unexpected issues.", + "pressBackAgain": "Press back again to cancel", "openButton": "Open", "shareButton": "Share file", @@ -327,5 +329,34 @@ "integrationsContributors": "Integrations contributors", "cliContributors": "CLI contributors", "managerContributors": "Manager contributors" + }, + "installErrorDialog": { + "mount_version_mismatch": "Version mismatch", + "mount_no_root": "No root access", + "mount_missing_installation": "Installation not found", + + "status_failure_blocked": "Installation blocked", + "install_failed_verification_failure": "Verification failed", + "status_failure_invalid": "Installation invalid", + "install_failed_version_downgrade": "Can't downgrade", + "status_failure_conflict": "Installation conflict", + "status_failure_storage": "Installation storage issue", + "status_failure_incompatible": "Installation incompatible", + "status_failure_timeout": "Installation timeout", + "status_unknown": "Installation failed", + + "mount_version_mismatch_description": "The installation failed due to the installed app being a different version than the patched app.\n\nInstall the version of the app you are mounting and try again.", + "mount_no_root_description": "The installation failed due to root access not being granted.\n\nGrant root access to ReVanced Manager and try again.", + "mount_missing_installation_description": "The installation failed due to the unpatched app not being installed on this device.\n\nInstall the app and try again.", + + "status_failure_timeout_description": "The installation took too long to finish.\n\nWould you like to try again?", + "status_failure_storage_description": "The installation failed due to insufficient storage.\n\nFree up some space and try again.", + "status_failure_invalid_description": "The installation failed due to the patched app being invalid.\n\nUninstall the app and try again?", + "status_failure_incompatible_description": "The app is incompatible with this device.\n\nContact the developer of the app and ask for support.", + "status_failure_conflict_description": "The installation was prevented by an existing installation of the app.\n\nUninstall the app and try again?", + "status_failure_blocked_description": "The installation was blocked by {packageName}.\n\nAdjust your security settings and try again.", + "install_failed_verification_failure_description": "The installation failed due to a verification issue.\n\nAdjust your security settings and try again.", + "install_failed_version_downgrade_description": "The installation failed due to the patched app being a lower version than the installed app.\n\nUninstall the app and try again?", + "status_unknown_description": "The installation failed due to an unknown reason. Please try again." } } diff --git a/lib/main.dart b/lib/main.dart index b38cb4c7..5b8df919 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,6 +8,7 @@ import 'package:revanced_manager/services/download_manager.dart'; import 'package:revanced_manager/services/github_api.dart'; import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/services/revanced_api.dart'; +import 'package:revanced_manager/services/root_api.dart'; import 'package:revanced_manager/ui/theme/dynamic_theme_builder.dart'; import 'package:revanced_manager/ui/views/navigation/navigation_view.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -24,6 +25,13 @@ Future main() async { final String repoUrl = locator().getRepoUrl(); locator().initialize(repoUrl); tz.initializeTimeZones(); + + // TODO(aAbed): remove in the future, keep it for now during migration. + final rootAPI = RootAPI(); + if (await rootAPI.hasRootPermissions()) { + await rootAPI.removeOrphanedFiles(); + } + prefs = await SharedPreferences.getInstance(); runApp(const MyApp()); diff --git a/lib/services/download_manager.dart b/lib/services/download_manager.dart index 4c0919b9..1aa9fc2b 100644 --- a/lib/services/download_manager.dart +++ b/lib/services/download_manager.dart @@ -72,4 +72,3 @@ class DownloadManager { ); } } - diff --git a/lib/services/patcher_api.dart b/lib/services/patcher_api.dart index f79d02e5..a22c610b 100644 --- a/lib/services/patcher_api.dart +++ b/lib/services/patcher_api.dart @@ -3,22 +3,24 @@ import 'dart:io'; import 'package:collection/collection.dart'; import 'package:device_apps/device_apps.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_file_dialog/flutter_file_dialog.dart'; +import 'package:flutter_i18n/widgets/I18nText.dart'; import 'package:injectable/injectable.dart'; -import 'package:install_plugin/install_plugin.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/manager_api.dart'; import 'package:revanced_manager/services/root_api.dart'; +import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:share_plus/share_plus.dart'; @lazySingleton class PatcherAPI { static const patcherChannel = - MethodChannel('app.revanced.manager.flutter/patcher'); + MethodChannel('app.revanced.manager.flutter/patcher'); final ManagerAPI _managerAPI = locator(); final RootAPI _rootAPI = RootAPI(); late Directory _dataDir; @@ -79,7 +81,8 @@ class PatcherAPI { } Future> getFilteredInstalledApps( - bool showUniversalPatches,) async { + bool showUniversalPatches, + ) async { final List filteredApps = []; final bool allAppsIncluded = _universalPatches.isNotEmpty && showUniversalPatches; @@ -121,11 +124,11 @@ class PatcherAPI { final List patches = _patches .where( (patch) => - patch.compatiblePackages.isEmpty || - !patch.name.contains('settings') && - patch.compatiblePackages - .any((pack) => pack.name == packageName), - ) + patch.compatiblePackages.isEmpty || + !patch.name.contains('settings') && + patch.compatiblePackages + .any((pack) => pack.name == packageName), + ) .toList(); if (!_managerAPI.areUniversalPatchesEnabled()) { filteredPatches[packageName] = patches @@ -137,22 +140,27 @@ class PatcherAPI { return filteredPatches[packageName]; } - Future> getAppliedPatches(List appliedPatches,) async { + Future> getAppliedPatches( + List appliedPatches, + ) async { return _patches .where((patch) => appliedPatches.contains(patch.name)) .toList(); } - Future runPatcher(String packageName, - String apkFilePath, - List selectedPatches,) async { + Future runPatcher( + String packageName, + String apkFilePath, + List selectedPatches, + ) async { final File? integrationsFile = await _managerAPI.downloadIntegrations(); final Map> options = {}; for (final patch in selectedPatches) { if (patch.options.isNotEmpty) { final Map patchOptions = {}; for (final option in patch.options) { - final patchOption = _managerAPI.getPatchOption(packageName, patch.name, option.key); + final patchOption = + _managerAPI.getPatchOption(packageName, patch.name, option.key); if (patchOption != null) { patchOptions[patchOption.key] = patchOption.value; } @@ -194,133 +202,308 @@ class PatcherAPI { } } } -} + } -Future stopPatcher() async { - try { - await patcherChannel.invokeMethod('stopPatcher'); - } on Exception catch (e) { - if (kDebugMode) { - print(e); + Future stopPatcher() async { + try { + await patcherChannel.invokeMethod('stopPatcher'); + } on Exception catch (e) { + if (kDebugMode) { + print(e); + } } } -} -Future installPatchedFile(PatchedApplication patchedApp) async { - if (outFile != null) { - try { - if (patchedApp.isRooted) { - final bool hasRootPermissions = await _rootAPI.hasRootPermissions(); - if (hasRootPermissions) { - return _rootAPI.installApp( - patchedApp.packageName, - patchedApp.apkFilePath, - outFile!.path, - ); + Future installPatchedFile( + BuildContext context, + PatchedApplication patchedApp, + ) async { + if (outFile != null) { + _managerAPI.ctx = context; + try { + if (patchedApp.isRooted) { + final bool hasRootPermissions = await _rootAPI.hasRootPermissions(); + final packageVersion = await DeviceApps.getApp(patchedApp.packageName) + .then((app) => app?.versionName); + if (!hasRootPermissions) { + installErrorDialog(1); + } else if (packageVersion == null) { + installErrorDialog(1.2); + } else if (packageVersion == patchedApp.version) { + return await _rootAPI.installApp( + patchedApp.packageName, + patchedApp.apkFilePath, + outFile!.path, + ) + ? 0 + : 1; + } else { + installErrorDialog(1.1); + } + } else { + if (await _rootAPI.hasRootPermissions()) { + await _rootAPI.unmount(patchedApp.packageName); + } + if (context.mounted) { + return await installApk( + context, + outFile!.path, + ); + } } + } on Exception catch (e) { + if (kDebugMode) { + print(e); + } + } + } + return 1; + } + + Future installApk( + BuildContext context, + String apkPath, + ) async { + try { + final status = await patcherChannel.invokeMethod('installApk', { + 'apkPath': apkPath, + }); + final int statusCode = status['status']; + final String message = status['message']; + final bool hasExtra = + message.contains('INSTALL_FAILED_VERIFICATION_FAILURE') || + message.contains('INSTALL_FAILED_VERSION_DOWNGRADE'); + if (statusCode == 0 || (statusCode == 3 && !hasExtra)) { + return statusCode; } else { - final install = await InstallPlugin.installApk(outFile!.path); - return install['isSuccess']; + _managerAPI.ctx = context; + return await installErrorDialog( + statusCode, + status, + hasExtra, + ); } } on Exception catch (e) { if (kDebugMode) { print(e); } - return false; + return 3; } } - return false; -} -void exportPatchedFile(String appName, String version) { - try { - if (outFile != null) { - final String newName = _getFileName(appName, version); - FlutterFileDialog.saveFile( - params: SaveFileDialogParams( - sourceFilePath: outFile!.path, - fileName: newName, - mimeTypesFilter: ['application/vnd.android.package-archive'], - ), - ); - } - } on Exception catch (e) { - if (kDebugMode) { - print(e); - } - } -} - -void sharePatchedFile(String appName, String version) { - try { - if (outFile != null) { - final String newName = _getFileName(appName, version); - final int lastSeparator = outFile!.path.lastIndexOf('/'); - final String newPath = - outFile!.path.substring(0, lastSeparator + 1) + newName; - final File shareFile = outFile!.copySync(newPath); - Share.shareXFiles([XFile(shareFile.path)]); - } - } on Exception catch (e) { - if (kDebugMode) { - print(e); - } - } -} - -String _getFileName(String appName, String version) { - final String patchVersion = _managerAPI.patchesVersion!; - final String prefix = appName.toLowerCase().replaceAll(' ', '-'); - final String newName = '$prefix-revanced_v$version-patches_$patchVersion.apk'; - return newName; -} - -Future exportPatcherLog(String logs) async { - final Directory appCache = await getTemporaryDirectory(); - final Directory logDir = Directory('${appCache.path}/logs'); - logDir.createSync(); - final String dateTime = DateTime.now() - .toIso8601String() - .replaceAll('-', '') - .replaceAll(':', '') - .replaceAll('T', '') - .replaceAll('.', ''); - final String fileName = 'revanced-manager_patcher_$dateTime.txt'; - final File log = File('${logDir.path}/$fileName'); - log.writeAsStringSync(logs); - FlutterFileDialog.saveFile( - params:SaveFileDialogParams( - sourceFilePath: log.path, - fileName: fileName, - ), - ); -} - -String getSuggestedVersion(String packageName) { - final Map versions = {}; - for (final Patch patch in _patches) { - final Package? package = patch.compatiblePackages.firstWhereOrNull( - (pack) => pack.name == packageName, + Future installErrorDialog( + num statusCode, [ + status, + bool hasExtra = false, + ]) async { + final String statusValue = InstallStatus.byCode( + hasExtra ? double.parse('$statusCode.1') : statusCode, ); - if (package != null) { - for (final String version in package.versions) { - versions.update( - version, - (value) => versions[version]! + 1, - ifAbsent: () => 1, + bool cleanInstall = false; + final bool isFixable = statusCode == 4 || statusCode == 5; + await showDialog( + context: _managerAPI.ctx!, + builder: (context) => AlertDialog( + backgroundColor: Theme.of(context).colorScheme.secondaryContainer, + title: I18nText('installErrorDialog.$statusValue'), + content: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + I18nText( + 'installErrorDialog.${statusValue}_description', + translationParams: statusCode == 2 + ? { + 'packageName': status['otherPackageName'], + } + : null, + ), + ], + ), + actions: (status == null) + ? [ + CustomMaterialButton( + label: I18nText('okButton'), + onPressed: () async { + Navigator.pop(context); + }, + ), + ] + : [ + CustomMaterialButton( + isFilled: !isFixable, + label: I18nText('cancelButton'), + onPressed: () { + Navigator.pop(context); + }, + ), + if (isFixable) + CustomMaterialButton( + label: I18nText('okButton'), + onPressed: () async { + final int response = await patcherChannel.invokeMethod( + 'uninstallApp', + {'packageName': status['packageName']}, + ); + if (response == 0 && context.mounted) { + cleanInstall = true; + Navigator.pop(context); + } + }, + ), + ], + ), + ); + return cleanInstall ? 10 : 1; + } + + void exportPatchedFile(String appName, String version) { + try { + if (outFile != null) { + final String newName = _getFileName(appName, version); + FlutterFileDialog.saveFile( + params: SaveFileDialogParams( + sourceFilePath: outFile!.path, + fileName: newName, + mimeTypesFilter: ['application/vnd.android.package-archive'], + ), ); } + } on Exception catch (e) { + if (kDebugMode) { + print(e); + } } } - if (versions.isNotEmpty) { - final entries = versions.entries.toList() - ..sort((a, b) => a.value.compareTo(b.value)); - versions - ..clear() - ..addEntries(entries); - versions.removeWhere((key, value) => value != versions.values.last); - return (versions.keys.toList() - ..sort()).last; + + void sharePatchedFile(String appName, String version) { + try { + if (outFile != null) { + final String newName = _getFileName(appName, version); + final int lastSeparator = outFile!.path.lastIndexOf('/'); + final String newPath = + outFile!.path.substring(0, lastSeparator + 1) + newName; + final File shareFile = outFile!.copySync(newPath); + Share.shareXFiles([XFile(shareFile.path)]); + } + } on Exception catch (e) { + if (kDebugMode) { + print(e); + } + } } - return ''; -}} + + String _getFileName(String appName, String version) { + final String patchVersion = _managerAPI.patchesVersion!; + final String prefix = appName.toLowerCase().replaceAll(' ', '-'); + final String newName = + '$prefix-revanced_v$version-patches_$patchVersion.apk'; + return newName; + } + + Future exportPatcherLog(String logs) async { + final Directory appCache = await getTemporaryDirectory(); + final Directory logDir = Directory('${appCache.path}/logs'); + logDir.createSync(); + final String dateTime = DateTime.now() + .toIso8601String() + .replaceAll('-', '') + .replaceAll(':', '') + .replaceAll('T', '') + .replaceAll('.', ''); + final String fileName = 'revanced-manager_patcher_$dateTime.txt'; + final File log = File('${logDir.path}/$fileName'); + log.writeAsStringSync(logs); + FlutterFileDialog.saveFile( + params: SaveFileDialogParams( + sourceFilePath: log.path, + fileName: fileName, + ), + ); + } + + String getSuggestedVersion(String packageName) { + final Map versions = {}; + for (final Patch patch in _patches) { + final Package? package = patch.compatiblePackages.firstWhereOrNull( + (pack) => pack.name == packageName, + ); + if (package != null) { + for (final String version in package.versions) { + versions.update( + version, + (value) => versions[version]! + 1, + ifAbsent: () => 1, + ); + } + } + } + if (versions.isNotEmpty) { + final entries = versions.entries.toList() + ..sort((a, b) => a.value.compareTo(b.value)); + versions + ..clear() + ..addEntries(entries); + versions.removeWhere((key, value) => value != versions.values.last); + return (versions.keys.toList()..sort()).last; + } + return ''; + } +} + +enum InstallStatus { + mountNoRoot(1), + mountVersionMismatch(1.1), + mountMissingInstallation(1.2), + + statusFailureBlocked(2), + installFailedVerificationFailure(3.1), + statusFailureInvalid(4), + installFailedVersionDowngrade(4.1), + statusFailureConflict(5), + statusFailureStorage(6), + statusFailureIncompatible(7), + statusFailureTimeout(8); + + const InstallStatus(this.statusCode); + final double statusCode; + + static String byCode(num code) { + try { + return InstallStatus.values + .firstWhere((flag) => flag.statusCode == code) + .status; + } catch (e) { + return 'status_unknown'; + } + } +} + +extension InstallStatusExtension on InstallStatus { + String get status { + switch (this) { + case InstallStatus.mountNoRoot: + return 'mount_no_root'; + case InstallStatus.mountVersionMismatch: + return 'mount_version_mismatch'; + case InstallStatus.mountMissingInstallation: + return 'mount_missing_installation'; + case InstallStatus.statusFailureBlocked: + return 'status_failure_blocked'; + case InstallStatus.installFailedVerificationFailure: + return 'install_failed_verification_failure'; + case InstallStatus.statusFailureInvalid: + return 'status_failure_invalid'; + case InstallStatus.installFailedVersionDowngrade: + return 'install_failed_version_downgrade'; + case InstallStatus.statusFailureConflict: + return 'status_failure_conflict'; + case InstallStatus.statusFailureStorage: + return 'status_failure_storage'; + case InstallStatus.statusFailureIncompatible: + return 'status_failure_incompatible'; + case InstallStatus.statusFailureTimeout: + return 'status_failure_timeout'; + } + } +} diff --git a/lib/services/root_api.dart b/lib/services/root_api.dart index f0c7d917..2b3f4cf2 100644 --- a/lib/services/root_api.dart +++ b/lib/services/root_api.dart @@ -2,10 +2,10 @@ import 'package:flutter/foundation.dart'; import 'package:root/root.dart'; class RootAPI { - // TODO(ponces): remove in the future, keep it for now during migration. - final String _revancedOldDirPath = '/data/local/tmp/revanced-manager'; - final String _revancedDirPath = '/data/adb/revanced'; + // TODO(aAbed): remove in the future, keep it for now during migration. final String _postFsDataDirPath = '/data/adb/post-fs-data.d'; + + final String _revancedDirPath = '/data/adb/revanced'; final String _serviceDDirPath = '/data/adb/service.d'; Future isRooted() async { @@ -75,7 +75,7 @@ class RootAPI { Future> getInstalledApps() async { final List apps = List.empty(growable: true); try { - String? res = await Root.exec( + final String? res = await Root.exec( cmd: 'ls "$_revancedDirPath"', ); if (res != null) { @@ -83,15 +83,6 @@ class RootAPI { list.removeWhere((pack) => pack.isEmpty); apps.addAll(list.map((pack) => pack.trim()).toList()); } - // TODO(ponces): remove in the future, keep it for now during migration. - res = await Root.exec( - cmd: 'ls "$_revancedOldDirPath"', - ); - if (res != null) { - final List list = res.split('\n'); - list.removeWhere((pack) => pack.isEmpty); - apps.addAll(list.map((pack) => pack.trim()).toList()); - } } on Exception catch (e) { if (kDebugMode) { print(e); @@ -100,16 +91,9 @@ class RootAPI { return apps; } - Future deleteApp(String packageName, String originalFilePath) async { + Future unmount(String packageName) async { await Root.exec( - cmd: 'am force-stop "$packageName"', - ); - await Root.exec( - cmd: 'su -mm -c "umount -l $originalFilePath"', - ); - // TODO(ponces): remove in the future, keep it for now during migration. - await Root.exec( - cmd: 'rm -rf "$_revancedOldDirPath/$packageName"', + cmd: 'grep $packageName /proc/mounts | while read -r line; do echo \$line | cut -d " " -f 2 | sed "s/apk.*/apk/" | xargs -r umount -l; done', ); await Root.exec( cmd: 'rm -rf "$_revancedDirPath/$packageName"', @@ -117,8 +101,21 @@ class RootAPI { await Root.exec( cmd: 'rm -rf "$_serviceDDirPath/$packageName.sh"', ); + } + + // TODO(aAbed): remove in the future, keep it for now during migration. + Future removeOrphanedFiles() async { await Root.exec( - cmd: 'rm -rf "$_postFsDataDirPath/$packageName.sh"', + cmd: ''' + find "$_revancedDirPath" -type f -name original.apk -delete + for file in "$_serviceDDirPath"/*; do + filename=\$(basename "\$file") + if [ -f "$_postFsDataDirPath/\$filename" ]; then + rm "$_postFsDataDirPath/\$filename" + fi + done + ''' + .trim(), ); } @@ -128,7 +125,6 @@ class RootAPI { String patchedFilePath, ) async { try { - await deleteApp(packageName, originalFilePath); await Root.exec( cmd: 'mkdir -p "$_revancedDirPath/$packageName"', ); @@ -138,11 +134,9 @@ class RootAPI { '', '$_revancedDirPath/$packageName', ); - await saveOriginalFilePath(packageName, originalFilePath); await installServiceDScript(packageName); - await installPostFsDataScript(packageName); await installApk(packageName, patchedFilePath); - await mountApk(packageName, originalFilePath); + await mountApk(packageName); return true; } on Exception catch (e) { if (kDebugMode) { @@ -156,26 +150,25 @@ class RootAPI { await Root.exec( cmd: 'mkdir -p "$_serviceDDirPath"', ); - final String content = '#!/system/bin/sh\n' - 'while [ "\$(getprop sys.boot_completed | tr -d \'"\'"\'\\\\r\'"\'"\')" != "1" ]; do sleep 3; done\n' - 'base_path=$_revancedDirPath/$packageName/base.apk\n' - 'stock_path=\$(pm path $packageName | grep base | sed \'"\'"\'s/package://g\'"\'"\')\n' - r'[ ! -z $stock_path ] && mount -o bind $base_path $stock_path'; - final String scriptFilePath = '$_serviceDDirPath/$packageName.sh'; - await Root.exec( - cmd: 'echo \'$content\' > "$scriptFilePath"', - ); - await setPermissions('0744', '', '', scriptFilePath); - } + final String content = ''' + #!/system/bin/sh + MAGISKTMP="\$(magisk --path)" || MAGISKTMP=/sbin + MIRROR="\$MAGISKTMP/.magisk/mirror" - Future installPostFsDataScript(String packageName) async { - await Root.exec( - cmd: 'mkdir -p "$_postFsDataDirPath"', - ); - final String content = '#!/system/bin/sh\n' - 'stock_path=\$(pm path $packageName | grep base | sed \'"\'"\'s/package://g\'"\'"\')\n' - r'[ ! -z $stock_path ] && umount -l $stock_path'; - final String scriptFilePath = '$_postFsDataDirPath/$packageName.sh'; + until [ "\$(getprop sys.boot_completed)" = 1 ]; do sleep 3; done + until [ -d "/sdcard/Android" ]; do sleep 1; done + + base_path=$_revancedDirPath/$packageName/base.apk + stock_path=\$(pm path $packageName | grep base | sed 's/package://g' ) + + chcon u:object_r:apk_data_file:s0 \$base_path + mount -o bind \$MIRROR\$base_path \$stock_path + + # Kill the app to force it to restart the mounted APK in case it's already running + am force-stop $packageName + ''' + .trim(); + final String scriptFilePath = '$_serviceDDirPath/$packageName.sh'; await Root.exec( cmd: 'echo \'$content\' > "$scriptFilePath"', ); @@ -195,49 +188,12 @@ class RootAPI { ); } - Future mountApk(String packageName, String originalFilePath) async { - final String newPatchedFilePath = '$_revancedDirPath/$packageName/base.apk'; + Future mountApk(String packageName,) async { await Root.exec( - cmd: 'am force-stop "$packageName"', - ); - await Root.exec( - cmd: 'su -mm -c "umount -l $originalFilePath"', - ); - await Root.exec( - cmd: 'su -mm -c "mount -o bind $newPatchedFilePath $originalFilePath"', - ); - } - - Future isMounted(String packageName) async { - final String? res = await Root.exec( - cmd: 'cat /proc/mounts | grep $packageName', - ); - return res != null && res.isNotEmpty; - } - - Future saveOriginalFilePath( - String packageName, - String originalFilePath, - ) async { - final String originalRootPath = - '$_revancedDirPath/$packageName/original.apk'; - await Root.exec( - cmd: 'mkdir -p "$_revancedDirPath/$packageName"', - ); - await setPermissions( - '0755', - 'shell:shell', - '', - '$_revancedDirPath/$packageName', - ); - await Root.exec( - cmd: 'cp "$originalFilePath" "$originalRootPath"', - ); - await setPermissions( - '0644', - 'shell:shell', - 'u:object_r:apk_data_file:s0', - originalFilePath, + cmd: ''' + grep $packageName /proc/mounts | while read -r line; do echo \$line | cut -d " " -f 2 | sed "s/apk.*/apk/" | xargs -r umount -l; done + .$_serviceDDirPath/$packageName.sh + '''.trim(), ); } diff --git a/lib/ui/views/home/home_viewmodel.dart b/lib/ui/views/home/home_viewmodel.dart index 8df23910..a93fb16f 100644 --- a/lib/ui/views/home/home_viewmodel.dart +++ b/lib/ui/views/home/home_viewmodel.dart @@ -8,7 +8,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:injectable/injectable.dart'; -import 'package:install_plugin/install_plugin.dart'; import 'package:path_provider/path_provider.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/app/app.router.dart'; @@ -53,7 +52,7 @@ class HomeViewModel extends BaseViewModel { _toast.showBottom('homeView.installingMessage'); final File? managerApk = await _managerAPI.downloadManager(); if (managerApk != null) { - await InstallPlugin.installApk(managerApk.path); + await _patcherAPI.installApk(context, managerApk.path); } else { _toast.showBottom('homeView.errorDownloadMessage'); } @@ -75,7 +74,7 @@ class HomeViewModel extends BaseViewModel { _toast.showBottom('homeView.installingMessage'); final File? managerApk = await _managerAPI.downloadManager(); if (managerApk != null) { - await InstallPlugin.installApk(managerApk.path); + await _patcherAPI.installApk(context, managerApk.path); } else { _toast.showBottom('homeView.errorDownloadMessage'); } @@ -84,6 +83,7 @@ class HomeViewModel extends BaseViewModel { _managerAPI.reAssessSavedApps().then((_) => _getPatchedApps()); } + void navigateToAppInfo(PatchedApplication app) { _navigationService.navigateTo( Routes.appInfoView, @@ -268,6 +268,7 @@ class HomeViewModel extends BaseViewModel { valueListenable: downloaded, builder: (context, value, child) { return SimpleDialog( + backgroundColor: Theme.of(context).colorScheme.secondaryContainer, contentPadding: const EdgeInsets.all(16.0), title: I18nText( !value @@ -365,9 +366,7 @@ class HomeViewModel extends BaseViewModel { alignment: Alignment.centerRight, child: FilledButton( onPressed: () async { - await InstallPlugin.installApk( - downloadedApk!.path, - ); + await _patcherAPI.installApk(context, downloadedApk!.path); }, child: I18nText('updateButton'), ), @@ -412,7 +411,7 @@ class HomeViewModel extends BaseViewModel { // UILocalNotificationDateInterpretation.absoluteTime, // ); _toast.showBottom('homeView.installingMessage'); - await InstallPlugin.installApk(managerApk.path); + await _patcherAPI.installApk(context, managerApk.path); } else { _toast.showBottom('homeView.errorDownloadMessage'); } diff --git a/lib/ui/views/installer/installer_viewmodel.dart b/lib/ui/views/installer/installer_viewmodel.dart index 32a30197..039af2b4 100644 --- a/lib/ui/views/installer/installer_viewmodel.dart +++ b/lib/ui/views/installer/installer_viewmodel.dart @@ -316,7 +316,7 @@ class InstallerViewModel extends BaseViewModel { await showDialog( context: context, barrierDismissible: false, - builder: (context) => AlertDialog( + builder: (innerContext) => AlertDialog( title: I18nText( 'installerView.installType', ), @@ -367,6 +367,19 @@ class InstallerViewModel extends BaseViewModel { installType.value = selected!; }, ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: I18nText( + 'installerView.warning', + child: Text( + '', + style: TextStyle( + fontWeight: FontWeight.w500, + color: Theme.of(context).colorScheme.error, + ), + ), + ), + ), ], ); }, @@ -375,13 +388,13 @@ class InstallerViewModel extends BaseViewModel { actions: [ TextButton( onPressed: () { - Navigator.of(context).pop(); + Navigator.of(innerContext).pop(); }, child: I18nText('cancelButton'), ), FilledButton( onPressed: () { - Navigator.of(context).pop(); + Navigator.of(innerContext).pop(); installResult(context, installType.value == 1); }, child: I18nText('installerView.installButton'), @@ -390,7 +403,32 @@ class InstallerViewModel extends BaseViewModel { ), ); } else { - installResult(context, false); + await showDialog( + context: context, + barrierDismissible: false, + builder: (innerContext) => AlertDialog( + title: I18nText( + 'warning', + ), + contentPadding: const EdgeInsets.all(16), + content: I18nText('installerView.warning'), + actions: [ + TextButton( + onPressed: () { + Navigator.of(innerContext).pop(); + }, + child: I18nText('cancelButton'), + ), + FilledButton( + onPressed: () { + Navigator.of(innerContext).pop(); + installResult(context, false); + }, + child: I18nText('installerView.installButton'), + ), + ], + ), + ); } } @@ -411,15 +449,18 @@ class InstallerViewModel extends BaseViewModel { Future installResult(BuildContext context, bool installAsRoot) async { try { _app.isRooted = installAsRoot; - update( - 1.0, - 'Installing...', - _app.isRooted - ? 'Installing patched file using root method' - : 'Installing patched file using nonroot method', - ); - isInstalled = await _patcherAPI.installPatchedFile(_app); - if (isInstalled) { + if (headerLogs != 'Installing...') { + update( + 1.0, + 'Installing...', + _app.isRooted + ? 'Mounting patched app' + : 'Installing patched app', + ); + } + final int response = await _patcherAPI.installPatchedFile(context, _app); + if (response == 0) { + isInstalled = true; _app.isFromStorage = false; _app.patchDate = DateTime.now(); _app.appliedPatches = _patches.map((p) => p.name).toList(); @@ -435,9 +476,26 @@ class InstallerViewModel extends BaseViewModel { await _managerAPI.savePatchedApp(_app); - update(1.0, 'Installed!', 'Installed!'); + update(1.0, 'Installed', 'Installed'); + } else if (response == 3) { + update( + 1.0, + 'Installation canceled', + 'Installation canceled', + ); + } else if (response == 10) { + installResult(context, installAsRoot); + update( + 1.0, + '', + 'Starting installer', + ); } else { - // TODO(aabed): Show error message. + update( + 1.0, + 'Installation failed', + 'Installation failed', + ); } } on Exception catch (e) { if (kDebugMode) { diff --git a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart index 6886e0a0..82f330b5 100644 --- a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart +++ b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart @@ -184,10 +184,6 @@ class PatchesSelectorViewModel extends BaseViewModel { void selectPatches() { locator().selectedPatches = selectedPatches; saveSelectedPatches(); - if (_managerAPI.ctx != null) { - Navigator.pop(_managerAPI.ctx!); - _managerAPI.ctx = null; - } locator().notifyListeners(); } diff --git a/lib/ui/widgets/appInfoView/app_info_viewmodel.dart b/lib/ui/widgets/appInfoView/app_info_viewmodel.dart index 60b9681a..d4652f44 100644 --- a/lib/ui/widgets/appInfoView/app_info_viewmodel.dart +++ b/lib/ui/widgets/appInfoView/app_info_viewmodel.dart @@ -29,7 +29,9 @@ class AppInfoViewModel extends BaseViewModel { if (app.isRooted) { final bool hasRootPermissions = await _rootAPI.hasRootPermissions(); if (hasRootPermissions) { - await _rootAPI.deleteApp(app.packageName, app.apkFilePath); + await _rootAPI.unmount( + app.packageName, + ); if (!onlyUnpatch) { await DeviceApps.uninstallApp(app.packageName); } diff --git a/pubspec.yaml b/pubspec.yaml index 9f4c120e..9b1af650 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -65,10 +65,6 @@ dependencies: flutter_dotenv: ^5.0.2 flutter_markdown: ^0.6.14 dio_cache_interceptor: ^3.4.0 - install_plugin: - git: # remove once https://github.com/hui-z/flutter_install_plugin/pull/67 is merged - url: https://github.com/BenjaminHalko/flutter_install_plugin - ref: 5f9b1a8c956fc3355ae655eefcbcadb457bd10f7 # Branch: master screenshot_callback: git: # remove once https://github.com/flutter-moum/flutter_screenshot_callback/pull/81 is merged url: https://github.com/BenjaminHalko/flutter_screenshot_callback From c56c445fb7bcce9e160ae3dbaff9068f62dab34c Mon Sep 17 00:00:00 2001 From: validcube Date: Sat, 23 Dec 2023 10:36:59 +0700 Subject: [PATCH 07/23] fix: migration latest changes to native buttons Signed-off-by: validcube --- lib/services/patcher_api.dart | 20 +++++++++++++------- pubspec.yaml | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/services/patcher_api.dart b/lib/services/patcher_api.dart index a22c610b..fda603d9 100644 --- a/lib/services/patcher_api.dart +++ b/lib/services/patcher_api.dart @@ -322,24 +322,29 @@ class PatcherAPI { ), actions: (status == null) ? [ - CustomMaterialButton( - label: I18nText('okButton'), + FilledButton( onPressed: () async { Navigator.pop(context); }, + child: I18nText('okButton'), ), ] : [ - CustomMaterialButton( - isFilled: !isFixable, - label: I18nText('cancelButton'), + if (!isFixable) + FilledButton( + onPressed: () { + Navigator.pop(context); + }, + child: I18nText('cancelButton'), + ), + TextButton( onPressed: () { Navigator.pop(context); }, + child: I18nText('cancelButton'), ), if (isFixable) - CustomMaterialButton( - label: I18nText('okButton'), + FilledButton( onPressed: () async { final int response = await patcherChannel.invokeMethod( 'uninstallApp', @@ -350,6 +355,7 @@ class PatcherAPI { Navigator.pop(context); } }, + child: I18nText('okButton'), ), ], ), diff --git a/pubspec.yaml b/pubspec.yaml index 9b1af650..8384ee21 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,7 +46,7 @@ dependencies: git: url: https://github.com/BenjaminHalko/logcat ref: 4a6d5e0e22292c8eb160cfb9365b9ea29735fd43 # Branch: master - package_info_plus: ^4.2.0 + package_info_plus: ^5.0.1 path_provider: ^2.0.14 permission_handler: ^11.0.1 pull_to_refresh: ^2.0.0 From a0b673c138a88520ac4bee527f7b11fb6c0d321e Mon Sep 17 00:00:00 2001 From: validcube Date: Sat, 23 Dec 2023 10:47:12 +0700 Subject: [PATCH 08/23] refactor: apply suggestions from analyser Signed-off-by: validcube --- lib/models/patch.dart | 5 +-- lib/services/download_manager.dart | 3 +- lib/services/patcher_api.dart | 1 - lib/services/root_api.dart | 10 +++-- lib/ui/theme/dynamic_theme_builder.dart | 37 ++++++++++++------- .../views/app_selector/app_selector_view.dart | 18 +++------ lib/ui/views/home/home_viewmodel.dart | 6 ++- .../views/installer/installer_viewmodel.dart | 28 ++++++++------ lib/ui/views/patcher/patcher_view.dart | 2 +- .../patches_selector_view.dart | 35 ++++++++++++++---- .../patcherView/patch_selector_card.dart | 3 +- .../patch_options_fields.dart | 7 +++- .../settings_advanced_section.dart | 1 - .../settings_enable_patches_selection.dart | 3 +- ...ettings_require_suggested_app_version.dart | 13 +++++-- .../settings_universal_patches.dart | 6 +-- .../settings_version_compatibility_check.dart | 6 ++- lib/utils/check_for_supported_patch.dart | 15 ++++---- 18 files changed, 120 insertions(+), 79 deletions(-) diff --git a/lib/models/patch.dart b/lib/models/patch.dart index ebcebf59..1b86ba5b 100644 --- a/lib/models/patch.dart +++ b/lib/models/patch.dart @@ -75,9 +75,8 @@ class Option { if (json['valueType'] == null) { final type = json['optionClassType']; if (type is String) { - json['valueType'] = type - .replaceAll('PatchOption', '') - .replaceAll('List', 'Array'); + json['valueType'] = + type.replaceAll('PatchOption', '').replaceAll('List', 'Array'); json['optionClassType'] = null; } diff --git a/lib/services/download_manager.dart b/lib/services/download_manager.dart index 1aa9fc2b..caa705d7 100644 --- a/lib/services/download_manager.dart +++ b/lib/services/download_manager.dart @@ -19,7 +19,8 @@ class DownloadManager { ); Future initialize() async { - _userAgent = 'ReVanced-Manager/${await _managerAPI.getCurrentManagerVersion()}'; + _userAgent = + 'ReVanced-Manager/${await _managerAPI.getCurrentManagerVersion()}'; } Dio initDio(String url) { diff --git a/lib/services/patcher_api.dart b/lib/services/patcher_api.dart index fda603d9..8efd18b0 100644 --- a/lib/services/patcher_api.dart +++ b/lib/services/patcher_api.dart @@ -14,7 +14,6 @@ import 'package:revanced_manager/models/patch.dart'; import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/services/root_api.dart'; -import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:share_plus/share_plus.dart'; @lazySingleton diff --git a/lib/services/root_api.dart b/lib/services/root_api.dart index 2b3f4cf2..41691d30 100644 --- a/lib/services/root_api.dart +++ b/lib/services/root_api.dart @@ -93,7 +93,8 @@ class RootAPI { Future unmount(String packageName) async { await Root.exec( - cmd: 'grep $packageName /proc/mounts | while read -r line; do echo \$line | cut -d " " -f 2 | sed "s/apk.*/apk/" | xargs -r umount -l; done', + cmd: + 'grep $packageName /proc/mounts | while read -r line; do echo \$line | cut -d " " -f 2 | sed "s/apk.*/apk/" | xargs -r umount -l; done', ); await Root.exec( cmd: 'rm -rf "$_revancedDirPath/$packageName"', @@ -188,12 +189,15 @@ class RootAPI { ); } - Future mountApk(String packageName,) async { + Future mountApk( + String packageName, + ) async { await Root.exec( cmd: ''' grep $packageName /proc/mounts | while read -r line; do echo \$line | cut -d " " -f 2 | sed "s/apk.*/apk/" | xargs -r umount -l; done .$_serviceDDirPath/$packageName.sh - '''.trim(), + ''' + .trim(), ); } diff --git a/lib/ui/theme/dynamic_theme_builder.dart b/lib/ui/theme/dynamic_theme_builder.dart index 8f9fc98b..9ec2d1bd 100644 --- a/lib/ui/theme/dynamic_theme_builder.dart +++ b/lib/ui/theme/dynamic_theme_builder.dart @@ -25,7 +25,8 @@ class DynamicThemeBuilder extends StatefulWidget { State createState() => _DynamicThemeBuilderState(); } -class _DynamicThemeBuilderState extends State with WidgetsBindingObserver { +class _DynamicThemeBuilderState extends State + with WidgetsBindingObserver { Brightness brightness = PlatformDispatcher.instance.platformBrightness; final ManagerAPI _managerAPI = locator(); @@ -43,8 +44,9 @@ class _DynamicThemeBuilderState extends State with WidgetsB if (_managerAPI.getThemeMode() < 2) { SystemChrome.setSystemUIOverlayStyle( SystemUiOverlayStyle( - systemNavigationBarIconBrightness: - brightness == Brightness.light ? Brightness.dark : Brightness.light, + systemNavigationBarIconBrightness: brightness == Brightness.light + ? Brightness.dark + : Brightness.light, ), ); } @@ -83,24 +85,31 @@ class _DynamicThemeBuilderState extends State with WidgetsB return DynamicTheme( themeCollection: ThemeCollection( themes: { - 0: brightness == Brightness.light ? lightCustomTheme : darkCustomTheme, - 1: brightness == Brightness.light ? lightDynamicTheme : darkDynamicTheme, + 0: brightness == Brightness.light + ? lightCustomTheme + : darkCustomTheme, + 1: brightness == Brightness.light + ? lightDynamicTheme + : darkDynamicTheme, 2: lightCustomTheme, 3: lightDynamicTheme, 4: darkCustomTheme, 5: darkDynamicTheme, }, - fallbackTheme: PlatformDispatcher.instance.platformBrightness == Brightness.light ? lightCustomTheme : darkCustomTheme, + fallbackTheme: PlatformDispatcher.instance.platformBrightness == + Brightness.light + ? lightCustomTheme + : darkCustomTheme, ), builder: (context, theme) => MaterialApp( - debugShowCheckedModeBanner: false, - title: widget.title, - navigatorKey: StackedService.navigatorKey, - onGenerateRoute: StackedRouter().onGenerateRoute, - theme: theme, - home: widget.home, - localizationsDelegates: widget.localizationsDelegates, - ), + debugShowCheckedModeBanner: false, + title: widget.title, + navigatorKey: StackedService.navigatorKey, + onGenerateRoute: StackedRouter().onGenerateRoute, + theme: theme, + home: widget.home, + localizationsDelegates: widget.localizationsDelegates, + ), ); }, ); diff --git a/lib/ui/views/app_selector/app_selector_view.dart b/lib/ui/views/app_selector/app_selector_view.dart index 09f6dacc..a4c60149 100644 --- a/lib/ui/views/app_selector/app_selector_view.dart +++ b/lib/ui/views/app_selector/app_selector_view.dart @@ -40,8 +40,8 @@ class _AppSelectorViewState extends State { ), titleTextStyle: TextStyle( fontSize: 22.0, - color: Theme.of(context).textTheme.titleLarge!.color, - ), + color: Theme.of(context).textTheme.titleLarge!.color, + ), leading: IconButton( icon: Icon( Icons.arrow_back, @@ -94,9 +94,7 @@ class _AppSelectorViewState extends State { ), child: Column( children: [ - ...model - .getFilteredApps(_query) - .map( + ...model.getFilteredApps(_query).map( (app) => InstalledAppItem( name: app.appName, pkgName: app.packageName, @@ -117,11 +115,8 @@ class _AppSelectorViewState extends State { packageName: app.packageName, ), ), - ) - , - ...model - .getFilteredAppsNames(_query) - .map( + ), + ...model.getFilteredAppsNames(_query).map( (app) => NotInstalledAppItem( name: app, patchesCount: model.patchesCount(app), @@ -135,8 +130,7 @@ class _AppSelectorViewState extends State { packageName: app, ), ), - ) - , + ), const SizedBox(height: 70.0), ], ), diff --git a/lib/ui/views/home/home_viewmodel.dart b/lib/ui/views/home/home_viewmodel.dart index a93fb16f..c9356a56 100644 --- a/lib/ui/views/home/home_viewmodel.dart +++ b/lib/ui/views/home/home_viewmodel.dart @@ -83,7 +83,6 @@ class HomeViewModel extends BaseViewModel { _managerAPI.reAssessSavedApps().then((_) => _getPatchedApps()); } - void navigateToAppInfo(PatchedApplication app) { _navigationService.navigateTo( Routes.appInfoView, @@ -366,7 +365,10 @@ class HomeViewModel extends BaseViewModel { alignment: Alignment.centerRight, child: FilledButton( onPressed: () async { - await _patcherAPI.installApk(context, downloadedApk!.path); + await _patcherAPI.installApk( + context, + downloadedApk!.path, + ); }, child: I18nText('updateButton'), ), diff --git a/lib/ui/views/installer/installer_viewmodel.dart b/lib/ui/views/installer/installer_viewmodel.dart index 039af2b4..4985159b 100644 --- a/lib/ui/views/installer/installer_viewmodel.dart +++ b/lib/ui/views/installer/installer_viewmodel.dart @@ -183,7 +183,9 @@ class InstallerViewModel extends BaseViewModel { final index = logLines.indexWhere((line) => line.endsWith(keyword)); if (newString != null && lineCount > 0) { logLines.insert( - index, newString.replaceAll('{lineCount}', lineCount.toString())); + index, + newString.replaceAll('{lineCount}', lineCount.toString()), + ); } logLines.removeWhere((lines) => lines.endsWith(keyword)); } @@ -203,11 +205,13 @@ class InstallerViewModel extends BaseViewModel { return 'None'; } return patches - .map((p) => - p.name + - (p.options.isEmpty - ? '' - : ' [${p.options.map((o) => '${o.title}: ${_getPatchOptionValue(p.name, o)}').join(", ")}]')) + .map( + (p) => + p.name + + (p.options.isEmpty + ? '' + : ' [${p.options.map((o) => '${o.title}: ${_getPatchOptionValue(p.name, o)}').join(", ")}]'), + ) .toList() .join(', '); } @@ -242,9 +246,11 @@ class InstallerViewModel extends BaseViewModel { // Options changed final patchesChanged = defaultPatches - .where((p) => - _patches.contains(p) && - p.options.any((o) => _getPatchOptionValue(p.name, o) != o.value)) + .where( + (p) => + _patches.contains(p) && + p.options.any((o) => _getPatchOptionValue(p.name, o) != o.value), + ) .toList(); // Add Info @@ -453,9 +459,7 @@ class InstallerViewModel extends BaseViewModel { update( 1.0, 'Installing...', - _app.isRooted - ? 'Mounting patched app' - : 'Installing patched app', + _app.isRooted ? 'Mounting patched app' : 'Installing patched app', ); } final int response = await _patcherAPI.installPatchedFile(context, _app); diff --git a/lib/ui/views/patcher/patcher_view.dart b/lib/ui/views/patcher/patcher_view.dart index 0921bb1d..9def6c05 100644 --- a/lib/ui/views/patcher/patcher_view.dart +++ b/lib/ui/views/patcher/patcher_view.dart @@ -22,7 +22,7 @@ class PatcherView extends StatelessWidget { child: FloatingActionButton.extended( label: I18nText('patcherView.patchButton'), icon: const Icon(Icons.build), - onPressed: () async{ + onPressed: () async { if (model.checkRequiredPatchOption(context)) { final bool proceed = model.showRemovedPatchesDialog(context); if (proceed && context.mounted) { diff --git a/lib/ui/views/patches_selector/patches_selector_view.dart b/lib/ui/views/patches_selector/patches_selector_view.dart index 29489078..71e90d79 100644 --- a/lib/ui/views/patches_selector/patches_selector_view.dart +++ b/lib/ui/views/patches_selector/patches_selector_view.dart @@ -180,11 +180,16 @@ class _PatchesSelectorViewState extends State { ), ], ), - if (model.getQueriedPatches(_query).any((patch) => model.isPatchNew(patch))) + if (model + .getQueriedPatches(_query) + .any((patch) => model.isPatchNew(patch))) Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - model.getPatchCategory(context, 'patchesSelectorView.newPatches'), + model.getPatchCategory( + context, + 'patchesSelectorView.newPatches', + ), ...model.getQueriedPatches(_query).map((patch) { if (model.isPatchNew(patch)) { return model.getPatchItem(context, patch); @@ -192,26 +197,40 @@ class _PatchesSelectorViewState extends State { return Container(); } }), - if (model.getQueriedPatches(_query).any((patch) => !model.isPatchNew(patch) && patch.compatiblePackages.isNotEmpty)) - model.getPatchCategory(context, 'patchesSelectorView.patches'), + if (model.getQueriedPatches(_query).any( + (patch) => + !model.isPatchNew(patch) && + patch.compatiblePackages.isNotEmpty, + )) + model.getPatchCategory( + context, + 'patchesSelectorView.patches', + ), ], ), ...model.getQueriedPatches(_query).map( (patch) { - if (patch.compatiblePackages.isNotEmpty && !model.isPatchNew(patch)) { + if (patch.compatiblePackages.isNotEmpty && + !model.isPatchNew(patch)) { return model.getPatchItem(context, patch); } else { return Container(); } }, ), - if (model.getQueriedPatches(_query).any((patch) => patch.compatiblePackages.isEmpty)) + if (model + .getQueriedPatches(_query) + .any((patch) => patch.compatiblePackages.isEmpty)) Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - model.getPatchCategory(context, 'patchesSelectorView.universalPatches'), + model.getPatchCategory( + context, + 'patchesSelectorView.universalPatches', + ), ...model.getQueriedPatches(_query).map((patch) { - if (patch.compatiblePackages.isEmpty && !model.isPatchNew(patch)) { + if (patch.compatiblePackages.isEmpty && + !model.isPatchNew(patch)) { return model.getPatchItem(context, patch); } else { return Container(); diff --git a/lib/ui/widgets/patcherView/patch_selector_card.dart b/lib/ui/widgets/patcherView/patch_selector_card.dart index ceea41c9..9dd48686 100644 --- a/lib/ui/widgets/patcherView/patch_selector_card.dart +++ b/lib/ui/widgets/patcherView/patch_selector_card.dart @@ -58,7 +58,8 @@ class PatchSelectorCard extends StatelessWidget { String _getPatchesSelection() { String text = ''; - final List selectedPatches = locator().selectedPatches; + final List selectedPatches = + locator().selectedPatches; selectedPatches.sort((a, b) => a.name.compareTo(b.name)); for (final Patch p in selectedPatches) { text += '• ${p.getSimpleName()}\n'; diff --git a/lib/ui/widgets/patchesSelectorView/patch_options_fields.dart b/lib/ui/widgets/patchesSelectorView/patch_options_fields.dart index ae026cb7..2d5d2dfd 100644 --- a/lib/ui/widgets/patchesSelectorView/patch_options_fields.dart +++ b/lib/ui/widgets/patchesSelectorView/patch_options_fields.dart @@ -400,7 +400,9 @@ class _TextFieldForPatchOptionState extends State { final bool isStringOption = widget.optionType.contains('String'); final bool isArrayOption = widget.optionType.contains('Array'); selectedKey ??= widget.selectedKey; - controller.text = !isStringOption && isArrayOption && selectedKey == '' && + controller.text = !isStringOption && + isArrayOption && + selectedKey == '' && (widget.value != null && widget.value.toString().startsWith('[')) ? '' : widget.value ?? ''; @@ -519,7 +521,8 @@ class _TextFieldForPatchOptionState extends State { } break; case 'patchOptionsView.selectFolder': - final DirectoryLocation? result = await FlutterFileDialog.pickDirectory(); + final DirectoryLocation? result = + await FlutterFileDialog.pickDirectory(); if (result != null) { controller.text = result.toString(); widget.onChanged(controller.text); diff --git a/lib/ui/widgets/settingsView/settings_advanced_section.dart b/lib/ui/widgets/settingsView/settings_advanced_section.dart index 53b3cadf..4182b7a0 100644 --- a/lib/ui/widgets/settingsView/settings_advanced_section.dart +++ b/lib/ui/widgets/settingsView/settings_advanced_section.dart @@ -10,7 +10,6 @@ import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart'; import 'package:revanced_manager/ui/widgets/settingsView/settings_universal_patches.dart'; import 'package:revanced_manager/ui/widgets/settingsView/settings_version_compatibility_check.dart'; - class SAdvancedSection extends StatelessWidget { const SAdvancedSection({super.key}); diff --git a/lib/ui/widgets/settingsView/settings_enable_patches_selection.dart b/lib/ui/widgets/settingsView/settings_enable_patches_selection.dart index a0c5b463..a2fcc86b 100644 --- a/lib/ui/widgets/settingsView/settings_enable_patches_selection.dart +++ b/lib/ui/widgets/settingsView/settings_enable_patches_selection.dart @@ -6,7 +6,8 @@ class SEnablePatchesSelection extends StatefulWidget { const SEnablePatchesSelection({super.key}); @override - State createState() => _SEnablePatchesSelectionState(); + State createState() => + _SEnablePatchesSelectionState(); } final _settingsViewModel = SettingsViewModel(); diff --git a/lib/ui/widgets/settingsView/settings_require_suggested_app_version.dart b/lib/ui/widgets/settingsView/settings_require_suggested_app_version.dart index 1d431e60..da583a97 100644 --- a/lib/ui/widgets/settingsView/settings_require_suggested_app_version.dart +++ b/lib/ui/widgets/settingsView/settings_require_suggested_app_version.dart @@ -6,12 +6,14 @@ class SRequireSuggestedAppVersion extends StatefulWidget { const SRequireSuggestedAppVersion({super.key}); @override - State createState() => _SRequireSuggestedAppVersionState(); + State createState() => + _SRequireSuggestedAppVersionState(); } final _settingsViewModel = SettingsViewModel(); -class _SRequireSuggestedAppVersionState extends State { +class _SRequireSuggestedAppVersionState + extends State { @override Widget build(BuildContext context) { return SwitchListTile( @@ -29,8 +31,11 @@ class _SRequireSuggestedAppVersionState extends State createState() => - _SUniversalPatchesState(); + State createState() => _SUniversalPatchesState(); } final _settingsViewModel = SettingsViewModel(); final _patchesSelectorViewModel = PatchesSelectorViewModel(); final _patcherViewModel = PatcherViewModel(); -class _SUniversalPatchesState - extends State { +class _SUniversalPatchesState extends State { @override Widget build(BuildContext context) { return SwitchListTile( diff --git a/lib/ui/widgets/settingsView/settings_version_compatibility_check.dart b/lib/ui/widgets/settingsView/settings_version_compatibility_check.dart index ead3b070..a17fcb3b 100644 --- a/lib/ui/widgets/settingsView/settings_version_compatibility_check.dart +++ b/lib/ui/widgets/settingsView/settings_version_compatibility_check.dart @@ -9,14 +9,16 @@ class SVersionCompatibilityCheck extends StatefulWidget { const SVersionCompatibilityCheck({super.key}); @override - State createState() => _SVersionCompatibilityCheckState(); + State createState() => + _SVersionCompatibilityCheckState(); } final _settingsViewModel = SettingsViewModel(); final _patchesSelectorViewModel = PatchesSelectorViewModel(); final _patcherViewModel = PatcherViewModel(); -class _SVersionCompatibilityCheckState extends State { +class _SVersionCompatibilityCheckState + extends State { @override Widget build(BuildContext context) { return SwitchListTile( diff --git a/lib/utils/check_for_supported_patch.dart b/lib/utils/check_for_supported_patch.dart index 19bd30c1..5cb311c6 100644 --- a/lib/utils/check_for_supported_patch.dart +++ b/lib/utils/check_for_supported_patch.dart @@ -27,12 +27,12 @@ bool hasUnsupportedRequiredOption(List