diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml
index 993298dc..009cef0d 100644
--- a/.github/workflows/pr-build.yml
+++ b/.github/workflows/pr-build.yml
@@ -59,7 +59,7 @@ jobs:
persist-credentials: false
- name: Setup JDK
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'zulu'
diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml
index d8f3d745..2db06f3f 100644
--- a/.github/workflows/release-build.yml
+++ b/.github/workflows/release-build.yml
@@ -13,7 +13,7 @@ jobs:
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Set up JDK
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "zulu"
@@ -47,4 +47,4 @@ jobs:
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false
- files: revanced-manager-${{ env.RELEASE_VERSION }}.apk
\ No newline at end of file
+ files: revanced-manager-${{ env.RELEASE_VERSION }}.apk
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d261a86a..52d99b39 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -12,7 +12,10 @@
-
+
-
+
-
+
-
+
-
+
@@ -69,7 +84,7 @@ If you encounter a bug while using the ReVanced Manager app, open an issue using
## 📝 How to contribute
-> [!NOTE]
+> [!TIP]
> We recommend that you discuss your changes with
> the maintainers of ReVanced Manager before contributing.
> This will help you determine whether your change is acceptable.
diff --git a/docs/4_building.md b/docs/4_building.md
index fec5b7e9..29168acc 100644
--- a/docs/4_building.md
+++ b/docs/4_building.md
@@ -2,29 +2,31 @@
This page will guide you through building ReVanced Manager from source.
-1. Setup the Flutter environment for your [platform](https://docs.flutter.dev/get-started/install)
+1\. Setup the Flutter environment for your [platform](https://docs.flutter.dev/get-started/install)
-2. Clone the repository
+2\. Clone the repository
```sh
git clone https://github.com/revanced/revanced-manager.git && cd revanced-manager
```
-3. Get dependencies
+3\. Get dependencies
```sh
flutter pub get
```
-4. Delete conflicting outputs
+4\. Delete conflicting outputs
+
+> [!TIP]
+> Must be run every time you sync your local repository with the remote repository.
```sh
dart run build_runner build --delete-conflicting-outputs
```
- > [!Note]
- > Must be run every time you sync your local repository with the remote repository.
-5. Build the APK
+
+5\. Build the APK
```sh
flutter build apk
diff --git a/lib/services/manager_api.dart b/lib/services/manager_api.dart
index 85306873..7a9e091d 100644
--- a/lib/services/manager_api.dart
+++ b/lib/services/manager_api.dart
@@ -582,8 +582,8 @@ class ManagerAPI {
return showDialog(
barrierDismissible: false,
context: context,
- builder: (context) => PopScope(
- canPop: false,
+ builder: (context) => WillPopScope(
+ onWillPop: () async => false,
child: AlertDialog(
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
title: I18nText('warning'),
diff --git a/lib/services/patcher_api.dart b/lib/services/patcher_api.dart
index 65f5ecc0..f79d02e5 100644
--- a/lib/services/patcher_api.dart
+++ b/lib/services/patcher_api.dart
@@ -237,7 +237,7 @@ void exportPatchedFile(String appName, String version) {
if (outFile != null) {
final String newName = _getFileName(appName, version);
FlutterFileDialog.saveFile(
- params: SaveFileDialogParams(
+ params: SaveFileDialogParams(
sourceFilePath: outFile!.path,
fileName: newName,
mimeTypesFilter: ['application/vnd.android.package-archive'],
@@ -269,8 +269,9 @@ void sharePatchedFile(String appName, String version) {
}
String _getFileName(String appName, String version) {
+ final String patchVersion = _managerAPI.patchesVersion!;
final String prefix = appName.toLowerCase().replaceAll(' ', '-');
- final String newName = '$prefix-revanced_v$version.apk';
+ final String newName = '$prefix-revanced_v$version-patches_$patchVersion.apk';
return newName;
}
diff --git a/lib/ui/views/installer/installer_view.dart b/lib/ui/views/installer/installer_view.dart
index 45d20519..d1626ed5 100644
--- a/lib/ui/views/installer/installer_view.dart
+++ b/lib/ui/views/installer/installer_view.dart
@@ -15,8 +15,7 @@ class InstallerView extends StatelessWidget {
return ViewModelBuilder.reactive(
onViewModelReady: (model) => model.initialize(context),
viewModelBuilder: () => InstallerViewModel(),
- builder: (context, model, child) => PopScope(
- onPopInvoked: (bool didPop) => model.onPopInvoked(context, didPop),
+ builder: (context, model, child) => WillPopScope(
child: SafeArea(
top: false,
bottom: model.isPatching,
@@ -84,7 +83,7 @@ class InstallerView extends StatelessWidget {
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
- onBackButtonPressed: () => model.onBackButtonInvoked(context),
+ onBackButtonPressed: () => model.onWillPop(context),
bottom: PreferredSize(
preferredSize: const Size(double.infinity, 1.0),
child: GradientProgressIndicator(progress: model.progress),
@@ -112,6 +111,7 @@ class InstallerView extends StatelessWidget {
),
),
),
+ onWillPop: () => model.onWillPop(context),
),
);
}
diff --git a/lib/ui/views/installer/installer_viewmodel.dart b/lib/ui/views/installer/installer_viewmodel.dart
index 53a03040..d16f1309 100644
--- a/lib/ui/views/installer/installer_viewmodel.dart
+++ b/lib/ui/views/installer/installer_viewmodel.dart
@@ -183,13 +183,15 @@ class InstallerViewModel extends BaseViewModel {
final lineCount = logLines.where((line) => line.endsWith(keyword)).length;
final index = logLines.indexWhere((line) => line.endsWith(keyword));
if (newString != null && lineCount > 0) {
- logLines.insert(index, newString.replaceAll('{lineCount}', lineCount.toString()));
+ logLines.insert(
+ index, newString.replaceAll('{lineCount}', lineCount.toString()));
}
logLines.removeWhere((lines) => lines.endsWith(keyword));
}
dynamic _getPatchOptionValue(String patchName, Option option) {
- final Option? savedOption = _managerAPI.getPatchOption(_app.packageName, patchName, option.key);
+ final Option? savedOption =
+ _managerAPI.getPatchOption(_app.packageName, patchName, option.key);
if (savedOption != null) {
return savedOption.value;
} else {
@@ -201,7 +203,24 @@ class InstallerViewModel extends BaseViewModel {
if (patches.isEmpty) {
return 'None';
}
- return patches.map((p) => p.name + (p.options.isEmpty ? '' : ' [${p.options.map((o) => '${o.title}: ${_getPatchOptionValue(p.name, o)}').join(", ")}]')).toList().join(', ');
+ return patches
+ .map((p) =>
+ p.name +
+ (p.options.isEmpty
+ ? ''
+ : ' [${p.options.map((o) => '${o.title}: ${_getPatchOptionValue(p.name, o)}').join(", ")}]'))
+ .toList()
+ .join(', ');
+ }
+
+ String _getSuggestedVersion(String packageName) {
+ String suggestedVersion = _patcherAPI.getSuggestedVersion(_app.packageName);
+ if (suggestedVersion.isEmpty) {
+ suggestedVersion = 'Any';
+ } else {
+ suggestedVersion = 'v$suggestedVersion';
+ }
+ return suggestedVersion;
}
Future copyLogs() async {
@@ -213,12 +232,21 @@ class InstallerViewModel extends BaseViewModel {
_trimLogs(logsTrimmed, '.dex', 'Compiled {lineCount} dex files');
// Get patches added / removed
- final defaultPatches = _patcherAPI.getFilteredPatches(_app.packageName).where((p) => !p.excluded).toList();
- final patchesAdded = _patches.where((p) => !defaultPatches.contains(p)).toList();
- final patchesRemoved = defaultPatches.where((p) => !_patches.contains(p)).toList();
+ final defaultPatches = _patcherAPI
+ .getFilteredPatches(_app.packageName)
+ .where((p) => !p.excluded)
+ .toList();
+ final patchesAdded =
+ _patches.where((p) => !defaultPatches.contains(p)).toList();
+ final patchesRemoved =
+ defaultPatches.where((p) => !_patches.contains(p)).toList();
// Options changed
- final patchesChanged = defaultPatches.where((p) => _patches.contains(p) && p.options.any((o) => _getPatchOptionValue(p.name, o) != o.value)).toList();
+ final patchesChanged = defaultPatches
+ .where((p) =>
+ _patches.contains(p) &&
+ p.options.any((o) => _getPatchOptionValue(p.name, o) != o.value))
+ .toList();
// Add Info
final formattedLogs = [
@@ -228,22 +256,22 @@ class InstallerViewModel extends BaseViewModel {
'Model: ${info['model']}',
'Android version: ${info['androidVersion']}',
'Supported architectures: ${info['supportedArch'].join(", ")}',
- 'Root permissions: ${isRooted ? 'Yes' : 'No'}',
-
+ 'Root permissions: ${isRooted ? 'Yes' : 'No'}', //
+
'\n- Patch Info',
- 'App: ${_app.packageName} v${_app.version}',
+ 'App: ${_app.packageName} v${_app.version} (Suggested: ${_getSuggestedVersion(_app.packageName)})',
'Patches version: ${_managerAPI.patchesVersion}',
'Patches added: ${_formatPatches(patchesAdded)}',
'Patches removed: ${_formatPatches(patchesRemoved)}',
- 'Options changed: ${_formatPatches(patchesChanged)}',
+ 'Options changed: ${_formatPatches(patchesChanged)}', //
'\n- Settings',
'Allow changing patch selection: ${_managerAPI.isPatchesChangeEnabled()}',
'Version compatibility check: ${_managerAPI.isVersionCompatibilityCheckEnabled()}',
'Show universal patches: ${_managerAPI.areUniversalPatchesEnabled()}',
'Patches source: ${_managerAPI.getPatchesRepo()}',
- 'Integration source: ${_managerAPI.getIntegrationsRepo()}',
-
+ 'Integration source: ${_managerAPI.getIntegrationsRepo()}', //
+
'\n- Logs',
logsTrimmed.join('\n'),
];
@@ -461,38 +489,25 @@ class InstallerViewModel extends BaseViewModel {
}
}
- bool canPop() {
- return !isPatching;
- }
-
- void onBackButtonInvoked(BuildContext context) {
- if (canPop()) {
- onPopInvoked(context, true);
- } else {
- onPopInvoked(context, false);
- }
- }
-
- Future onPopInvoked(BuildContext context, bool didPop) async {
- if (didPop) {
+ Future onWillPop(BuildContext context) async {
+ if (isPatching) {
if (!cancel) {
- cleanPatcher();
+ cancel = true;
+ _toast.showBottom('installerView.pressBackAgain');
+ } else if (!isCanceled) {
+ await stopPatcher();
} else {
- _patcherAPI.cleanPatcher();
- }
- screenshotCallback.dispose();
- Navigator.of(context).pop();
- } else {
- if (isPatching) {
- if (!cancel) {
- cancel = true;
- _toast.showBottom('installerView.pressBackAgain');
- } else if (!isCanceled) {
- await stopPatcher();
- } else {
- _toast.showBottom('installerView.noExit');
- }
+ _toast.showBottom('installerView.noExit');
}
+ return false;
}
+ if (!cancel) {
+ cleanPatcher();
+ } else {
+ _patcherAPI.cleanPatcher();
+ }
+ screenshotCallback.dispose();
+ Navigator.of(context).pop();
+ return true;
}
}
diff --git a/lib/ui/views/navigation/navigation_view.dart b/lib/ui/views/navigation/navigation_view.dart
index 56c24d17..13a4457e 100644
--- a/lib/ui/views/navigation/navigation_view.dart
+++ b/lib/ui/views/navigation/navigation_view.dart
@@ -13,11 +13,13 @@ class NavigationView extends StatelessWidget {
return ViewModelBuilder.reactive(
onViewModelReady: (model) => model.initialize(context),
viewModelBuilder: () => locator(),
- builder: (context, model, child) => PopScope(
- canPop: model.currentIndex == 0,
- onPopInvoked: (bool didPop) {
- if (!didPop) {
+ builder: (context, model, child) => WillPopScope(
+ onWillPop: () async {
+ if (model.currentIndex == 0) {
+ return true;
+ } else {
model.setIndex(0);
+ return false;
}
},
child: Scaffold(
diff --git a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart
index 173c1f53..399fe349 100644
--- a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart
+++ b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart
@@ -25,6 +25,9 @@ class PatchesSelectorViewModel extends BaseViewModel {
locator().selectedPatches;
PatchedApplication? selectedApp = locator().selectedApp;
String? patchesVersion = '';
+
+ Set savedPatchNames = {};
+
bool isDefaultPatchesRepo() {
return _managerAPI.getPatchesRepo() == 'revanced/revanced-patches';
}
@@ -48,13 +51,17 @@ class PatchesSelectorViewModel extends BaseViewModel {
});
currentSelection.clear();
currentSelection.addAll(selectedPatches);
+
+ savedPatchNames = _managerAPI.getSavedPatches(selectedApp!.packageName).map((p) => p.name).toSet();
+
notifyListeners();
}
bool isSelected(Patch patch) {
return selectedPatches.any(
- (element) => element.name == patch.name,
- );
+ (element) => element.name == patch.name,
+ ) ||
+ (isPatchNew(patch) && !patch.excluded);
}
void navigateToPatchOptions(List