diff --git a/assets/i18n/en_US.json b/assets/i18n/en_US.json index de6e660a..2f7e1b64 100644 --- a/assets/i18n/en_US.json +++ b/assets/i18n/en_US.json @@ -10,6 +10,7 @@ "yesButton": "Yes", "noButton": "No", "warning": "Warning", + "notice": "Notice", "new": "New", "navigationView": { "dashboardTab": "Dashboard", @@ -71,7 +72,8 @@ "patchDialogText": "You have selected a resource patch and a split APK installation has been detected, so patching errors may occur.\nAre you sure you want to proceed?", "armv7WarningDialogText": "Patching on ARMv7 devices is not yet supported and might fail. Proceed anyways?", - "splitApkWarningDialogText": "Patching a split APK is not yet supported and might fail. Proceed anyways?" + "splitApkWarningDialogText": "Patching a split APK is not yet supported and might fail. Proceed anyways?", + "removedPatchesWarningDialogText": "The following patches have been removed since the last time you used them.\n\n{patches}\n\nProceed anyways?" }, "appSelectorCard": { "widgetTitle": "Select an application", @@ -198,6 +200,7 @@ "logsLabel": "Logs", "logsHint": "Share Manager's logs", + "autoUpdatePatchesLabel": "Auto update patches", "autoUpdatePatchesHint": "Automatically update ReVanced Patches to the latest version", "experimentalUniversalPatchesLabel": "Experimental universal patches support", "experimentalUniversalPatchesHint": "Display all applications to use with universal patches, loading list of apps may be slower", diff --git a/lib/services/manager_api.dart b/lib/services/manager_api.dart index a2eed1b4..28b2b8fa 100644 --- a/lib/services/manager_api.dart +++ b/lib/services/manager_api.dart @@ -104,7 +104,8 @@ class ManagerAPI { } List getSavedPatches(String packageName) { - final List patchesJson = _prefs.getStringList('savedPatches-$packageName') ?? []; + final List patchesJson = + _prefs.getStringList('savedPatches-$packageName') ?? []; final List patches = patchesJson.map((String patchJson) { return Patch.fromJson(jsonDecode(patchJson)); }).toList(); @@ -118,6 +119,22 @@ class ManagerAPI { await _prefs.setStringList('savedPatches-$packageName', patchesJson); } + List getUsedPatches(String packageName) { + final List patchesJson = + _prefs.getStringList('usedPatches-$packageName') ?? []; + final List patches = patchesJson.map((String patchJson) { + return Patch.fromJson(jsonDecode(patchJson)); + }).toList(); + return patches; + } + + Future setUsedPatches(List patches, String packageName) async { + final List patchesJson = patches.map((Patch patch) { + return jsonEncode(patch.toJson()); + }).toList(); + await _prefs.setStringList('usedPatches-$packageName', patchesJson); + } + String getIntegrationsRepo() { return _prefs.getString('integrationsRepo') ?? defaultIntegrationsRepo; } diff --git a/lib/services/root_api.dart b/lib/services/root_api.dart index 4b97900a..f0c7d917 100644 --- a/lib/services/root_api.dart +++ b/lib/services/root_api.dart @@ -153,6 +153,9 @@ class RootAPI { } Future installServiceDScript(String packageName) async { + 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' @@ -166,6 +169,9 @@ class RootAPI { } 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'; diff --git a/lib/ui/views/installer/installer_viewmodel.dart b/lib/ui/views/installer/installer_viewmodel.dart index 162de9e1..3258e9ba 100644 --- a/lib/ui/views/installer/installer_viewmodel.dart +++ b/lib/ui/views/installer/installer_viewmodel.dart @@ -101,6 +101,7 @@ class InstallerViewModel extends BaseViewModel { _patcherAPI.getFilteredPatches(_app.packageName), _app.packageName, ); + await _managerAPI.setUsedPatches(_patches, _app.packageName); } else if (value == -100.0) { isPatching = false; hasErrors = true; diff --git a/lib/ui/views/patcher/patcher_view.dart b/lib/ui/views/patcher/patcher_view.dart index 38af615d..ec593d18 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: () => model.showPatchConfirmationDialog(context), + onPressed: () => model.showRemovedPatchesDialog(context), ), ), body: CustomScrollView( diff --git a/lib/ui/views/patcher/patcher_viewmodel.dart b/lib/ui/views/patcher/patcher_viewmodel.dart index 1087a078..843ee6a7 100644 --- a/lib/ui/views/patcher/patcher_viewmodel.dart +++ b/lib/ui/views/patcher/patcher_viewmodel.dart @@ -22,6 +22,7 @@ class PatcherViewModel extends BaseViewModel { final PatcherAPI _patcherAPI = locator(); PatchedApplication? selectedApp; List selectedPatches = []; + List removedPatches = []; void navigateToAppSelector() { _navigationService.navigateTo(Routes.appSelectorView); @@ -86,6 +87,38 @@ class PatcherViewModel extends BaseViewModel { } } + Future showRemovedPatchesDialog(BuildContext context) async { + if (removedPatches.isNotEmpty) { + return showDialog( + 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'), + onPressed: () => Navigator.of(context).pop(), + ), + CustomMaterialButton( + label: I18nText('yesButton'), + onPressed: () { + Navigator.of(context).pop(); + navigateToInstaller(); + }, + ), + ], + ), + ); + } else { + showArmv7WarningDialog(context); + } + } + Future showArmv7WarningDialog(BuildContext context) async { final bool armv7 = await AboutInfo.getInfo().then((info) { final List archs = info['supportedArch']; @@ -150,6 +183,7 @@ class PatcherViewModel extends BaseViewModel { Future loadLastSelectedPatches() async { this.selectedPatches.clear(); + removedPatches.clear(); final List selectedPatches = await _managerAPI.getSelectedPatches(selectedApp!.originalPackageName); final List patches = @@ -165,6 +199,12 @@ class PatcherViewModel extends BaseViewModel { .selectedPatches .removeWhere((patch) => patch.compatiblePackages.isEmpty); } + final usedPatches = _managerAPI.getUsedPatches(selectedApp!.originalPackageName); + for (final patch in usedPatches){ + if (!patches.any((p) => p.name == patch.name)){ + removedPatches.add('\u2022 ${patch.name}'); + } + } notifyListeners(); } } diff --git a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart index 744b3e07..f333887d 100644 --- a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart +++ b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart @@ -117,7 +117,7 @@ class PatchesSelectorViewModel extends BaseViewModel { return false; } else { return !savedPatches - .any((p) => p.name == patch.name.toLowerCase().replaceAll(' ', '-')); + .any((p) => p.getSimpleName() == patch.getSimpleName()); } } diff --git a/lib/ui/widgets/settingsView/settings_auto_update_patches.dart b/lib/ui/widgets/settingsView/settings_auto_update_patches.dart index 438882c8..2063d658 100644 --- a/lib/ui/widgets/settingsView/settings_auto_update_patches.dart +++ b/lib/ui/widgets/settingsView/settings_auto_update_patches.dart @@ -17,7 +17,7 @@ class _SAutoUpdatePatchesState extends State { return SwitchListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 20.0), title: I18nText( - 'homeView.patchesConsentDialogText3', + 'settingsView.autoUpdatePatchesLabel', child: const Text( '', style: TextStyle(