feat: auto select default patches

This commit is contained in:
Aunali321 2023-04-19 01:21:08 +05:30
parent f0b028279c
commit 4c9cb560e3
5 changed files with 66 additions and 56 deletions

View File

@ -11,6 +11,7 @@ import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/github_api.dart'; import 'package:revanced_manager/services/github_api.dart';
import 'package:revanced_manager/services/revanced_api.dart'; import 'package:revanced_manager/services/revanced_api.dart';
import 'package:revanced_manager/services/root_api.dart'; import 'package:revanced_manager/services/root_api.dart';
import 'package:revanced_manager/utils/check_for_supported_patch.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@lazySingleton @lazySingleton
@ -22,7 +23,8 @@ class ManagerAPI {
final String cliRepo = 'revanced-cli'; final String cliRepo = 'revanced-cli';
late SharedPreferences _prefs; late SharedPreferences _prefs;
String storedPatchesFile = '/selected-patches.json'; String storedPatchesFile = '/selected-patches.json';
String keystoreFile = '/sdcard/Android/data/app.revanced.manager.flutter/files/revanced-manager.keystore'; String keystoreFile =
'/sdcard/Android/data/app.revanced.manager.flutter/files/revanced-manager.keystore';
String defaultKeystorePassword = 's3cur3p@ssw0rd'; String defaultKeystorePassword = 's3cur3p@ssw0rd';
String defaultApiUrl = 'https://releases.revanced.app/'; String defaultApiUrl = 'https://releases.revanced.app/';
String defaultRepoUrl = 'https://api.github.com'; String defaultRepoUrl = 'https://api.github.com';
@ -39,8 +41,7 @@ class ManagerAPI {
Future<void> initialize() async { Future<void> initialize() async {
_prefs = await SharedPreferences.getInstance(); _prefs = await SharedPreferences.getInstance();
storedPatchesFile = storedPatchesFile =
(await getApplicationDocumentsDirectory()).path + (await getApplicationDocumentsDirectory()).path + storedPatchesFile;
storedPatchesFile;
} }
String getApiUrl() { String getApiUrl() {
@ -79,8 +80,7 @@ class ManagerAPI {
} }
String getIntegrationsRepo() { String getIntegrationsRepo() {
return _prefs.getString('integrationsRepo') ?? return _prefs.getString('integrationsRepo') ?? defaultIntegrationsRepo;
defaultIntegrationsRepo;
} }
Future<void> setIntegrationsRepo(String value) async { Future<void> setIntegrationsRepo(String value) async {
@ -148,9 +148,7 @@ class ManagerAPI {
List<PatchedApplication> getPatchedApps() { List<PatchedApplication> getPatchedApps() {
final List<String> apps = _prefs.getStringList('patchedApps') ?? []; final List<String> apps = _prefs.getStringList('patchedApps') ?? [];
return apps return apps.map((a) => PatchedApplication.fromJson(jsonDecode(a))).toList();
.map((a) => PatchedApplication.fromJson(jsonDecode(a)))
.toList();
} }
Future<void> setPatchedApps( Future<void> setPatchedApps(
@ -328,12 +326,10 @@ class ManagerAPI {
final List<PatchedApplication> unsavedApps = []; final List<PatchedApplication> unsavedApps = [];
final bool hasRootPermissions = await _rootAPI.hasRootPermissions(); final bool hasRootPermissions = await _rootAPI.hasRootPermissions();
if (hasRootPermissions) { if (hasRootPermissions) {
final List<String> installedApps = final List<String> installedApps = await _rootAPI.getInstalledApps();
await _rootAPI.getInstalledApps();
for (final String packageName in installedApps) { for (final String packageName in installedApps) {
if (!patchedApps.any((app) => app.packageName == packageName)) { if (!patchedApps.any((app) => app.packageName == packageName)) {
final ApplicationWithIcon? application = final ApplicationWithIcon? application = await DeviceApps.getApp(
await DeviceApps.getApp(
packageName, packageName,
true, true,
) as ApplicationWithIcon?; ) as ApplicationWithIcon?;
@ -359,10 +355,8 @@ class ManagerAPI {
for (final Application app in userApps) { for (final Application app in userApps) {
if (app.packageName.startsWith('app.revanced') && if (app.packageName.startsWith('app.revanced') &&
!app.packageName.startsWith('app.revanced.manager.') && !app.packageName.startsWith('app.revanced.manager.') &&
!patchedApps !patchedApps.any((uapp) => uapp.packageName == app.packageName)) {
.any((uapp) => uapp.packageName == app.packageName)) { final ApplicationWithIcon? application = await DeviceApps.getApp(
final ApplicationWithIcon? application =
await DeviceApps.getApp(
app.packageName, app.packageName,
true, true,
) as ApplicationWithIcon?; ) as ApplicationWithIcon?;
@ -419,11 +413,9 @@ class ManagerAPI {
Future<bool> isAppUninstalled(PatchedApplication app) async { Future<bool> isAppUninstalled(PatchedApplication app) async {
bool existsRoot = false; bool existsRoot = false;
final bool existsNonRoot = final bool existsNonRoot = await DeviceApps.isAppInstalled(app.packageName);
await DeviceApps.isAppInstalled(app.packageName);
if (app.isRooted) { if (app.isRooted) {
final bool hasRootPermissions = final bool hasRootPermissions = await _rootAPI.hasRootPermissions();
await _rootAPI.hasRootPermissions();
if (hasRootPermissions) { if (hasRootPermissions) {
existsRoot = await _rootAPI.isAppInstalled(app.packageName); existsRoot = await _rootAPI.isAppInstalled(app.packageName);
} }
@ -478,8 +470,7 @@ class ManagerAPI {
List<String> patches, List<String> patches,
) async { ) async {
final File selectedPatchesFile = File(storedPatchesFile); final File selectedPatchesFile = File(storedPatchesFile);
final Map<String, dynamic> patchesMap = final Map<String, dynamic> patchesMap = await readSelectedPatchesFile();
await readSelectedPatchesFile();
if (patches.isEmpty) { if (patches.isEmpty) {
patchesMap.remove(app); patchesMap.remove(app);
} else { } else {
@ -488,10 +479,33 @@ class ManagerAPI {
selectedPatchesFile.writeAsString(jsonEncode(patchesMap)); selectedPatchesFile.writeAsString(jsonEncode(patchesMap));
} }
// get default patches for app
Future<List<String>> getDefaultPatches() async {
final List<Patch> patches = await getPatches();
final List<String> defaultPatches = [];
if (areExperimentalPatchesEnabled() == false) {
defaultPatches.addAll(
patches
.where(
(element) =>
element.excluded == false && isPatchSupported(element),
)
.map((p) => p.name),
);
} else {
defaultPatches.addAll(
patches
.where((element) => isPatchSupported(element))
.map((p) => p.name),
);
}
return defaultPatches;
}
Future<List<String>> getSelectedPatches(String app) async { Future<List<String>> getSelectedPatches(String app) async {
final Map<String, dynamic> patchesMap = final Map<String, dynamic> patchesMap = await readSelectedPatchesFile();
await readSelectedPatchesFile(); final List<String> defaultPatches = await getDefaultPatches();
return List.from(patchesMap.putIfAbsent(app, () => List.empty())); return List.from(patchesMap.putIfAbsent(app, () => defaultPatches));
} }
Future<Map<String, dynamic>> readSelectedPatchesFile() async { Future<Map<String, dynamic>> readSelectedPatchesFile() async {

View File

@ -69,8 +69,7 @@ class PatcherAPI {
onlyAppsWithLaunchIntent: true, onlyAppsWithLaunchIntent: true,
); );
for (final pkg in allPackages) { for (final pkg in allPackages) {
if (!filteredApps if (!filteredApps.any((app) => app.packageName == pkg.packageName)) {
.any((app) => app.packageName == pkg.packageName)) {
final appInfo = await DeviceApps.getApp( final appInfo = await DeviceApps.getApp(
pkg.packageName, pkg.packageName,
true, true,
@ -84,8 +83,7 @@ class PatcherAPI {
for (final Patch patch in _patches) { for (final Patch patch in _patches) {
for (final Package package in patch.compatiblePackages) { for (final Package package in patch.compatiblePackages) {
try { try {
if (!filteredApps if (!filteredApps.any((app) => app.packageName == package.name)) {
.any((app) => app.packageName == package.name)) {
final ApplicationWithIcon? app = await DeviceApps.getApp( final ApplicationWithIcon? app = await DeviceApps.getApp(
package.name, package.name,
true, true,
@ -151,8 +149,7 @@ class PatcherAPI {
String originalFilePath, String originalFilePath,
) async { ) async {
try { try {
final bool hasRootPermissions = final bool hasRootPermissions = await _rootAPI.hasRootPermissions();
await _rootAPI.hasRootPermissions();
if (hasRootPermissions) { if (hasRootPermissions) {
originalFilePath = await _rootAPI.getOriginalFilePath( originalFilePath = await _rootAPI.getOriginalFilePath(
packageName, packageName,
@ -173,15 +170,13 @@ class PatcherAPI {
String originalFilePath, String originalFilePath,
List<Patch> selectedPatches, List<Patch> selectedPatches,
) async { ) async {
final bool includeSettings = final bool includeSettings = await needsSettingsPatch(selectedPatches);
await needsSettingsPatch(selectedPatches);
if (includeSettings) { if (includeSettings) {
try { try {
final Patch? settingsPatch = _patches.firstWhereOrNull( final Patch? settingsPatch = _patches.firstWhereOrNull(
(patch) => (patch) =>
patch.name.contains('settings') && patch.name.contains('settings') &&
patch.compatiblePackages patch.compatiblePackages.any((pack) => pack.name == packageName),
.any((pack) => pack.name == packageName),
); );
if (settingsPatch != null) { if (settingsPatch != null) {
selectedPatches.add(settingsPatch); selectedPatches.add(settingsPatch);
@ -193,8 +188,7 @@ class PatcherAPI {
} }
} }
final File? patchBundleFile = await _managerAPI.downloadPatches(); final File? patchBundleFile = await _managerAPI.downloadPatches();
final File? integrationsFile = final File? integrationsFile = await _managerAPI.downloadIntegrations();
await _managerAPI.downloadIntegrations();
if (patchBundleFile != null) { if (patchBundleFile != null) {
_dataDir.createSync(); _dataDir.createSync();
_tmpDir.createSync(); _tmpDir.createSync();
@ -217,8 +211,7 @@ class PatcherAPI {
'patchedFilePath': patchedFile.path, 'patchedFilePath': patchedFile.path,
'outFilePath': _outFile!.path, 'outFilePath': _outFile!.path,
'integrationsPath': integrationsFile!.path, 'integrationsPath': integrationsFile!.path,
'selectedPatches': 'selectedPatches': selectedPatches.map((p) => p.name).toList(),
selectedPatches.map((p) => p.name).toList(),
'cacheDirPath': cacheDir.path, 'cacheDirPath': cacheDir.path,
'keyStoreFilePath': _keyStoreFile.path, 'keyStoreFilePath': _keyStoreFile.path,
'keystorePassword': _managerAPI.getKeystorePassword(), 'keystorePassword': _managerAPI.getKeystorePassword(),
@ -236,8 +229,7 @@ class PatcherAPI {
if (_outFile != null) { if (_outFile != null) {
try { try {
if (patchedApp.isRooted) { if (patchedApp.isRooted) {
final bool hasRootPermissions = final bool hasRootPermissions = await _rootAPI.hasRootPermissions();
await _rootAPI.hasRootPermissions();
if (hasRootPermissions) { if (hasRootPermissions) {
return _rootAPI.installApp( return _rootAPI.installApp(
patchedApp.packageName, patchedApp.packageName,
@ -321,8 +313,7 @@ class PatcherAPI {
String getRecommendedVersion(String packageName) { String getRecommendedVersion(String packageName) {
final Map<String, int> versions = {}; final Map<String, int> versions = {};
for (final Patch patch in _patches) { for (final Patch patch in _patches) {
final Package? package = final Package? package = patch.compatiblePackages.firstWhereOrNull(
patch.compatiblePackages.firstWhereOrNull(
(pack) => pack.name == packageName, (pack) => pack.name == packageName,
); );
if (package != null) { if (package != null) {
@ -341,8 +332,7 @@ class PatcherAPI {
versions versions
..clear() ..clear()
..addEntries(entries); ..addEntries(entries);
versions versions.removeWhere((key, value) => value != versions.values.last);
.removeWhere((key, value) => value != versions.values.last);
return (versions.keys.toList()..sort()).last; return (versions.keys.toList()..sort()).last;
} }
return ''; return '';

View File

@ -4,6 +4,7 @@ import 'package:revanced_manager/ui/views/patches_selector/patches_selector_view
import 'package:revanced_manager/ui/widgets/patchesSelectorView/patch_item.dart'; import 'package:revanced_manager/ui/widgets/patchesSelectorView/patch_item.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_popup_menu.dart'; import 'package:revanced_manager/ui/widgets/shared/custom_popup_menu.dart';
import 'package:revanced_manager/ui/widgets/shared/search_bar.dart'; import 'package:revanced_manager/ui/widgets/shared/search_bar.dart';
import 'package:revanced_manager/utils/check_for_supported_patch.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
class PatchesSelectorView extends StatefulWidget { class PatchesSelectorView extends StatefulWidget {
@ -168,7 +169,7 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
packageVersion: model.getAppVersion(), packageVersion: model.getAppVersion(),
supportedPackageVersions: supportedPackageVersions:
model.getSupportedVersions(patch), model.getSupportedVersions(patch),
isUnsupported: !model.isPatchSupported(patch), isUnsupported: !isPatchSupported(patch),
isSelected: model.isSelected(patch), isSelected: model.isSelected(patch),
onChanged: (value) => onChanged: (value) =>
model.selectPatch(patch, value), model.selectPatch(patch, value),

View File

@ -7,6 +7,7 @@ import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/patcher_api.dart'; import 'package:revanced_manager/services/patcher_api.dart';
import 'package:revanced_manager/services/toast.dart'; import 'package:revanced_manager/services/toast.dart';
import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart';
import 'package:revanced_manager/utils/check_for_supported_patch.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
class PatchesSelectorViewModel extends BaseViewModel { class PatchesSelectorViewModel extends BaseViewModel {
@ -118,16 +119,6 @@ class PatchesSelectorViewModel extends BaseViewModel {
} }
} }
bool isPatchSupported(Patch patch) {
final PatchedApplication app = locator<PatcherViewModel>().selectedApp!;
return patch.compatiblePackages.isEmpty ||
patch.compatiblePackages.any(
(pack) =>
pack.name == app.packageName &&
(pack.versions.isEmpty || pack.versions.contains(app.version)),
);
}
void onMenuSelection(value) { void onMenuSelection(value) {
switch (value) { switch (value) {
case 0: case 0:

View File

@ -0,0 +1,14 @@
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/ui/views/patcher/patcher_viewmodel.dart';
bool isPatchSupported(Patch patch) {
final PatchedApplication app = locator<PatcherViewModel>().selectedApp!;
return patch.compatiblePackages.isEmpty ||
patch.compatiblePackages.any(
(pack) =>
pack.name == app.packageName &&
(pack.versions.isEmpty || pack.versions.contains(app.version)),
);
}