From 1714c3fa865e33dff5f1eddb6f338be0aa9bbb6e Mon Sep 17 00:00:00 2001 From: aAbed <39409020+TheAabedKhan@users.noreply.github.com> Date: Mon, 7 Aug 2023 21:13:09 +0545 Subject: [PATCH] feat(patches-selector): show `New` tag for new patches (#1099) --- assets/i18n/en_US.json | 6 +- lib/services/manager_api.dart | 15 +++++ .../views/installer/installer_viewmodel.dart | 6 +- .../patches_selector_view.dart | 10 ++- .../patches_selector_viewmodel.dart | 26 ++++++-- .../patchesSelectorView/patch_item.dart | 62 ++++++++++++++++--- 6 files changed, 108 insertions(+), 17 deletions(-) diff --git a/assets/i18n/en_US.json b/assets/i18n/en_US.json index a9ac05c3..de6e660a 100644 --- a/assets/i18n/en_US.json +++ b/assets/i18n/en_US.json @@ -10,6 +10,7 @@ "yesButton": "Yes", "noButton": "No", "warning": "Warning", + "new": "New", "navigationView": { "dashboardTab": "Dashboard", "patcherTab": "Patcher", @@ -130,7 +131,10 @@ }, "patchItem": { "unsupportedDialogText": "Selecting this patch may result in patching errors.\n\nApp version: {packageVersion}\nSupported versions:\n{supportedVersions}", - "unsupportedPatchVersion": "Patch is not supported for this app version. Enable the experimental toggle in settings to proceed." + "unsupportedPatchVersion": "Patch is not supported for this app version. Enable the experimental toggle in settings to proceed.", + + "newPatchDialogText": "This is a new patch that has been added since the last time you have patched this app.", + "newPatch": "New patch" }, "installerView": { "widgetTitle": "Installer", diff --git a/lib/services/manager_api.dart b/lib/services/manager_api.dart index 9aedc368..de11e598 100644 --- a/lib/services/manager_api.dart +++ b/lib/services/manager_api.dart @@ -98,6 +98,21 @@ class ManagerAPI { await _prefs.setBool('patchesAutoUpdate', value); } + List getSavedPatches(String packageName) { + final List patchesJson = _prefs.getStringList('savedPatches-$packageName') ?? []; + final List patches = patchesJson.map((String patchJson) { + return Patch.fromJson(jsonDecode(patchJson)); + }).toList(); + return patches; + } + + Future savePatches(List patches, String packageName) async { + final List patchesJson = patches.map((Patch patch) { + return jsonEncode(patch.toJson()); + }).toList(); + await _prefs.setStringList('savedPatches-$packageName', patchesJson); + } + String getIntegrationsRepo() { return _prefs.getString('integrationsRepo') ?? defaultIntegrationsRepo; } diff --git a/lib/ui/views/installer/installer_viewmodel.dart b/lib/ui/views/installer/installer_viewmodel.dart index 2200c40d..162de9e1 100644 --- a/lib/ui/views/installer/installer_viewmodel.dart +++ b/lib/ui/views/installer/installer_viewmodel.dart @@ -85,7 +85,7 @@ class InstallerViewModel extends BaseViewModel { }); } - void update(double value, String header, String log) { + Future update(double value, String header, String log) async { if (value >= 0.0) { progress = value; } @@ -97,6 +97,10 @@ class InstallerViewModel extends BaseViewModel { } else if (value == 1.0) { isPatching = false; hasErrors = false; + await _managerAPI.savePatches( + _patcherAPI.getFilteredPatches(_app.packageName), + _app.packageName, + ); } else if (value == -100.0) { isPatching = false; hasErrors = true; diff --git a/lib/ui/views/patches_selector/patches_selector_view.dart b/lib/ui/views/patches_selector/patches_selector_view.dart index acecf5e4..f5f4a7bd 100644 --- a/lib/ui/views/patches_selector/patches_selector_view.dart +++ b/lib/ui/views/patches_selector/patches_selector_view.dart @@ -175,10 +175,14 @@ class _PatchesSelectorViewState extends State { name: patch.name, simpleName: patch.getSimpleName(), description: patch.description, - packageVersion: model.getAppVersion(), + packageVersion: model.getAppInfo().version, supportedPackageVersions: model.getSupportedVersions(patch), isUnsupported: !isPatchSupported(patch), + isNew: model.isPatchNew( + patch, + model.getAppInfo().packageName, + ), isSelected: model.isSelected(patch), onChanged: (value) => model.selectPatch(patch, value), @@ -206,10 +210,12 @@ class _PatchesSelectorViewState extends State { name: patch.name, simpleName: patch.getSimpleName(), description: patch.description, - packageVersion: model.getAppVersion(), + packageVersion: + model.getAppInfo().version, supportedPackageVersions: model.getSupportedVersions(patch), isUnsupported: !isPatchSupported(patch), + isNew: false, isSelected: model.isSelected(patch), onChanged: (value) => model.selectPatch(patch, value), diff --git a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart index b480f51c..744b3e07 100644 --- a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart +++ b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart @@ -15,6 +15,7 @@ class PatchesSelectorViewModel extends BaseViewModel { final List patches = []; final List selectedPatches = locator().selectedPatches; + PatchedApplication? selectedApp = locator().selectedApp; String? patchesVersion = ''; bool isDefaultPatchesRepo() { return _managerAPI.getPatchesRepo() == 'revanced/revanced-patches'; @@ -24,10 +25,17 @@ class PatchesSelectorViewModel extends BaseViewModel { getPatchesVersion().whenComplete(() => notifyListeners()); patches.addAll( _patcherAPI.getFilteredPatches( - locator().selectedApp!.originalPackageName, + selectedApp!.originalPackageName, ), ); - patches.sort((a, b) => a.name.compareTo(b.name)); + patches.sort((a, b) { + if (isPatchNew(a, selectedApp!.packageName) == + isPatchNew(b, selectedApp!.packageName)) { + return a.name.compareTo(b.name); + } else { + return isPatchNew(b, selectedApp!.packageName) ? 1 : -1; + } + }); notifyListeners(); } @@ -99,8 +107,18 @@ class PatchesSelectorViewModel extends BaseViewModel { } } - String getAppVersion() { - return locator().selectedApp!.version; + PatchedApplication getAppInfo() { + return locator().selectedApp!; + } + + bool isPatchNew(Patch patch, String packageName) { + final List savedPatches = _managerAPI.getSavedPatches(packageName); + if (savedPatches.isEmpty) { + return false; + } else { + return !savedPatches + .any((p) => p.name == patch.name.toLowerCase().replaceAll(' ', '-')); + } } List getSupportedVersions(Patch patch) { diff --git a/lib/ui/widgets/patchesSelectorView/patch_item.dart b/lib/ui/widgets/patchesSelectorView/patch_item.dart index f814a28b..21bd4726 100644 --- a/lib/ui/widgets/patchesSelectorView/patch_item.dart +++ b/lib/ui/widgets/patchesSelectorView/patch_item.dart @@ -16,6 +16,7 @@ class PatchItem extends StatefulWidget { required this.packageVersion, required this.supportedPackageVersions, required this.isUnsupported, + required this.isNew, required this.isSelected, required this.onChanged, this.child, @@ -26,6 +27,7 @@ class PatchItem extends StatefulWidget { final String packageVersion; final List supportedPackageVersions; final bool isUnsupported; + final bool isNew; bool isSelected; final Function(bool) onChanged; final Widget? child; @@ -132,12 +134,12 @@ class _PatchItemState extends State { ), ], ), - if (widget.isUnsupported && - widget._managerAPI.areExperimentalPatchesEnabled()) - Row( - children: [ + Row( + children: [ + if (widget.isUnsupported && + widget._managerAPI.areExperimentalPatchesEnabled()) Padding( - padding: const EdgeInsets.only(top: 8), + padding: const EdgeInsets.only(top: 8, right: 8), child: TextButton.icon( label: I18nText('warning'), icon: const Icon(Icons.warning, size: 20.0), @@ -160,10 +162,33 @@ class _PatchItemState extends State { ), ), ), - ], - ) - else - Container(), + if (widget.isNew) + Padding( + padding: const EdgeInsets.only(top: 8), + child: TextButton.icon( + label: I18nText('new'), + icon: const Icon(Icons.star, size: 20.0), + onPressed: () => _showNewPatchDialog(), + style: ButtonStyle( + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide( + color: Theme.of(context).colorScheme.secondary, + ), + ), + ), + backgroundColor: MaterialStateProperty.all( + Colors.transparent, + ), + foregroundColor: MaterialStateProperty.all( + Theme.of(context).colorScheme.secondary, + ), + ), + ), + ) + ], + ), widget.child ?? const SizedBox(), ], ), @@ -195,4 +220,23 @@ class _PatchItemState extends State { ), ); } + + Future _showNewPatchDialog() { + return showDialog( + context: context, + builder: (context) => AlertDialog( + title: I18nText('patchItem.newPatch'), + backgroundColor: Theme.of(context).colorScheme.secondaryContainer, + content: I18nText( + 'patchItem.newPatchDialogText', + ), + actions: [ + CustomMaterialButton( + label: I18nText('okButton'), + onPressed: () => Navigator.of(context).pop(), + ), + ], + ), + ); + } }