chore: merge dev branch to main branch (#1096)

This commit is contained in:
Ushie 2023-08-08 03:51:05 +03:00 committed by GitHub
commit 055c52178f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 297 additions and 102 deletions

View File

@ -71,12 +71,11 @@ linter:
- flutter_style_todos - flutter_style_todos
- hash_and_equals - hash_and_equals
- implementation_imports - implementation_imports
- iterable_contains_unrelated_type - collection_methods_unrelated_type
- leading_newlines_in_multiline_strings - leading_newlines_in_multiline_strings
- library_names - library_names
- library_prefixes - library_prefixes
- library_private_types_in_public_api - library_private_types_in_public_api
- list_remove_unrelated_type
- missing_whitespace_between_adjacent_strings - missing_whitespace_between_adjacent_strings
- no_adjacent_strings_in_list - no_adjacent_strings_in_list
- no_duplicate_case_values - no_duplicate_case_values

View File

@ -10,6 +10,7 @@
"yesButton": "Yes", "yesButton": "Yes",
"noButton": "No", "noButton": "No",
"warning": "Warning", "warning": "Warning",
"new": "New",
"navigationView": { "navigationView": {
"dashboardTab": "Dashboard", "dashboardTab": "Dashboard",
"patcherTab": "Patcher", "patcherTab": "Patcher",
@ -33,10 +34,10 @@
"updatePatchesDialogTitle": "Update ReVanced Patches", "updatePatchesDialogTitle": "Update ReVanced Patches",
"updateChangelogTitle": "Changelog", "updateChangelogTitle": "Changelog",
"patchesConsentDialogText": "ReVanced Patches need to be downloaded to patch apps.", "patchesConsentDialogText": "ReVanced Patches needs to be downloaded.",
"patchesConsentDialogText2": "This will reveal your IP address to {url}.", "patchesConsentDialogText2": "This will connect you to {url}.",
"patchesConsentDialogText3": "Auto update", "patchesConsentDialogText3": "Auto update?",
"patchesConsentDialogText3Sub": "You can still change this in the settings later", "patchesConsentDialogText3Sub": "You can change this in settings at a later time.",
"notificationTitle": "Update downloaded", "notificationTitle": "Update downloaded",
"notificationText": "Tap to install the update", "notificationText": "Tap to install the update",
@ -112,6 +113,7 @@
"patchesSelectorView": { "patchesSelectorView": {
"viewTitle": "Select patches", "viewTitle": "Select patches",
"searchBarHint": "Search patches", "searchBarHint": "Search patches",
"universalPatches": "Universal patches",
"doneButton": "Done", "doneButton": "Done",
@ -129,7 +131,10 @@
}, },
"patchItem": { "patchItem": {
"unsupportedDialogText": "Selecting this patch may result in patching errors.\n\nApp version: {packageVersion}\nSupported versions:\n{supportedVersions}", "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": { "installerView": {
"widgetTitle": "Installer", "widgetTitle": "Installer",

View File

@ -5,9 +5,8 @@ After patching an app, you may want to manage it. This page will guide you throu
## 🪜 Steps to manage patched apps ## 🪜 Steps to manage patched apps
1. Tap on the **Dashboard** tab in the bottom navigation bar 1. Tap on the **Dashboard** tab in the bottom navigation bar
2. Select the **Installed** chip 2. Tap on the **Info** button for the app you want to manage
3. Tap on the **Info** button for the app you want to manage 3. Choose one of the options from the menu
4. Choose one of the options from the menu
## ⏭️ What's next ## ⏭️ What's next

View File

@ -58,7 +58,7 @@ class MyApp extends StatelessWidget {
}, },
), ),
GlobalMaterialLocalizations.delegate, GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate GlobalWidgetsLocalizations.delegate,
], ],
); );
} }

View File

@ -28,7 +28,7 @@ class ManagerAPI {
String keystoreFile = String keystoreFile =
'/sdcard/Android/data/app.revanced.manager.flutter/files/revanced-manager.keystore'; '/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://api.revanced.app/';
String defaultRepoUrl = 'https://api.github.com'; String defaultRepoUrl = 'https://api.github.com';
String defaultPatcherRepo = 'revanced/revanced-patcher'; String defaultPatcherRepo = 'revanced/revanced-patcher';
String defaultPatchesRepo = 'revanced/revanced-patches'; String defaultPatchesRepo = 'revanced/revanced-patches';
@ -36,10 +36,15 @@ class ManagerAPI {
String defaultCliRepo = 'revanced/revanced-cli'; String defaultCliRepo = 'revanced/revanced-cli';
String defaultManagerRepo = 'revanced/revanced-manager'; String defaultManagerRepo = 'revanced/revanced-manager';
String? patchesVersion = ''; String? patchesVersion = '';
String? integrationsVersion = '';
bool isDefaultPatchesRepo() { bool isDefaultPatchesRepo() {
return getPatchesRepo() == 'revanced/revanced-patches'; return getPatchesRepo() == 'revanced/revanced-patches';
} }
bool isDefaultIntegrationsRepo() {
return getIntegrationsRepo() == 'revanced/revanced-integrations';
}
Future<void> initialize() async { Future<void> initialize() async {
_prefs = await SharedPreferences.getInstance(); _prefs = await SharedPreferences.getInstance();
isRooted = await _rootAPI.isRooted(); isRooted = await _rootAPI.isRooted();
@ -98,6 +103,21 @@ class ManagerAPI {
await _prefs.setBool('patchesAutoUpdate', value); await _prefs.setBool('patchesAutoUpdate', value);
} }
List<Patch> getSavedPatches(String packageName) {
final List<String> patchesJson = _prefs.getStringList('savedPatches-$packageName') ?? [];
final List<Patch> patches = patchesJson.map((String patchJson) {
return Patch.fromJson(jsonDecode(patchJson));
}).toList();
return patches;
}
Future<void> savePatches(List<Patch> patches, String packageName) async {
final List<String> patchesJson = patches.map((Patch patch) {
return jsonEncode(patch.toJson());
}).toList();
await _prefs.setStringList('savedPatches-$packageName', patchesJson);
}
String getIntegrationsRepo() { String getIntegrationsRepo() {
return _prefs.getString('integrationsRepo') ?? defaultIntegrationsRepo; return _prefs.getString('integrationsRepo') ?? defaultIntegrationsRepo;
} }
@ -252,14 +272,12 @@ class ManagerAPI {
Future<File?> downloadIntegrations() async { Future<File?> downloadIntegrations() async {
try { try {
final String repoName = getIntegrationsRepo(); final String repoName = getIntegrationsRepo();
if (repoName == defaultIntegrationsRepo) { final String currentVersion = await getCurrentIntegrationsVersion();
return await _revancedAPI.getLatestReleaseFile( return await _githubAPI.getPatchesReleaseFile(
'.apk', '.apk',
defaultIntegrationsRepo, repoName,
currentVersion,
); );
} else {
return await _githubAPI.getLatestReleaseFile('.apk', repoName);
}
} on Exception catch (e) { } on Exception catch (e) {
if (kDebugMode) { if (kDebugMode) {
print(e); print(e);
@ -308,6 +326,22 @@ class ManagerAPI {
); );
} }
Future<String?> getLatestIntegrationsVersion() async {
if (isDefaultIntegrationsRepo()) {
return await _revancedAPI.getLatestReleaseVersion(
'.apk',
defaultIntegrationsRepo,
);
} else {
final release = await _githubAPI.getLatestRelease(getIntegrationsRepo());
if (release != null) {
return release['tag_name'];
} else {
return null;
}
}
}
Future<String?> getLatestPatchesVersion() async { Future<String?> getLatestPatchesVersion() async {
if (isDefaultPatchesRepo()) { if (isDefaultPatchesRepo()) {
return await _revancedAPI.getLatestReleaseVersion( return await _revancedAPI.getLatestReleaseVersion(
@ -315,7 +349,8 @@ class ManagerAPI {
defaultPatchesRepo, defaultPatchesRepo,
); );
} else { } else {
final release = await _githubAPI.getLatestPatchesRelease(getPatchesRepo()); final release =
await _githubAPI.getLatestPatchesRelease(getPatchesRepo());
if (release != null) { if (release != null) {
return release['tag_name']; return release['tag_name'];
} else { } else {
@ -342,6 +377,19 @@ class ManagerAPI {
await _prefs.setString('patchesVersion', version); await _prefs.setString('patchesVersion', version);
} }
Future<String> getCurrentIntegrationsVersion() async {
integrationsVersion = _prefs.getString('integrationsVersion') ?? '0.0.0';
if (integrationsVersion == '0.0.0' || isPatchesAutoUpdate()) {
integrationsVersion = await getLatestIntegrationsVersion() ?? '0.0.0';
await setCurrentIntegrationsVersion(integrationsVersion!);
}
return integrationsVersion!;
}
Future<void> setCurrentIntegrationsVersion(String version) async {
await _prefs.setString('integrationsVersion', version);
}
Future<List<PatchedApplication>> getAppsToRemove( Future<List<PatchedApplication>> getAppsToRemove(
List<PatchedApplication> patchedApps, List<PatchedApplication> patchedApps,
) async { ) async {

View File

@ -103,7 +103,6 @@ class PatcherAPI {
} }
List<Patch> getFilteredPatches(String packageName) { List<Patch> getFilteredPatches(String packageName) {
if (!filteredPatches.keys.contains(packageName)) {
final List<Patch> patches = _patches final List<Patch> patches = _patches
.where( .where(
(patch) => (patch) =>
@ -113,6 +112,11 @@ class PatcherAPI {
.any((pack) => pack.name == packageName), .any((pack) => pack.name == packageName),
) )
.toList(); .toList();
if (!_managerAPI.areUniversalPatchesEnabled()) {
filteredPatches[packageName] = patches
.where((patch) => patch.compatiblePackages.isNotEmpty)
.toList();
} else {
filteredPatches[packageName] = patches; filteredPatches[packageName] = patches;
} }
return filteredPatches[packageName]; return filteredPatches[packageName];

View File

@ -57,7 +57,7 @@ class ContributorsView extends StatelessWidget {
title: 'contributorsView.managerContributors', title: 'contributorsView.managerContributors',
contributors: model.managerContributors, contributors: model.managerContributors,
), ),
SizedBox(height: MediaQuery.of(context).viewPadding.bottom) SizedBox(height: MediaQuery.of(context).viewPadding.bottom),
], ],
), ),
), ),

View File

@ -174,7 +174,7 @@ class HomeViewModel extends BaseViewModel {
context: context, context: context,
barrierDismissible: false, barrierDismissible: false,
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
title: const Text('ReVanced Patches'), title: const Text('Download ReVanced Patches?'),
content: ValueListenableBuilder( content: ValueListenableBuilder(
valueListenable: autoUpdate, valueListenable: autoUpdate,
builder: (context, value, child) { builder: (context, value, child) {
@ -197,7 +197,9 @@ class HomeViewModel extends BaseViewModel {
padding: const EdgeInsets.symmetric(vertical: 10), padding: const EdgeInsets.symmetric(vertical: 10),
child: I18nText( child: I18nText(
'homeView.patchesConsentDialogText2', 'homeView.patchesConsentDialogText2',
translationParams: {'url': _managerAPI.defaultApiUrl.split('/')[2]}, translationParams: {
'url': _managerAPI.defaultApiUrl.split('/')[2],
},
child: Text( child: Text(
'', '',
style: TextStyle( style: TextStyle(
@ -211,8 +213,12 @@ class HomeViewModel extends BaseViewModel {
CheckboxListTile( CheckboxListTile(
value: value, value: value,
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
title: I18nText('homeView.patchesConsentDialogText3',), title: I18nText(
subtitle: I18nText('homeView.patchesConsentDialogText3Sub',), 'homeView.patchesConsentDialogText3',
),
subtitle: I18nText(
'homeView.patchesConsentDialogText3Sub',
),
onChanged: (selected) { onChanged: (selected) {
autoUpdate.value = selected!; autoUpdate.value = selected!;
}, },
@ -237,7 +243,7 @@ class HomeViewModel extends BaseViewModel {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
label: I18nText('okButton'), label: I18nText('okButton'),
) ),
], ],
), ),
); );
@ -247,9 +253,12 @@ class HomeViewModel extends BaseViewModel {
_toast.showBottom('homeView.downloadingMessage'); _toast.showBottom('homeView.downloadingMessage');
final String patchesVersion = final String patchesVersion =
await _managerAPI.getLatestPatchesVersion() ?? '0.0.0'; await _managerAPI.getLatestPatchesVersion() ?? '0.0.0';
if (patchesVersion != '0.0.0') { final String integrationsVersion =
await _managerAPI.getLatestIntegrationsVersion() ?? '0.0.0';
if (patchesVersion != '0.0.0' && integrationsVersion != '0.0.0') {
_toast.showBottom('homeView.downloadedMessage'); _toast.showBottom('homeView.downloadedMessage');
await _managerAPI.setCurrentPatchesVersion(patchesVersion); await _managerAPI.setCurrentPatchesVersion(patchesVersion);
await _managerAPI.setCurrentIntegrationsVersion(integrationsVersion);
forceRefresh(context); forceRefresh(context);
} else { } else {
_toast.showBottom('homeView.errorDownloadMessage'); _toast.showBottom('homeView.errorDownloadMessage');

View File

@ -85,7 +85,7 @@ class InstallerViewModel extends BaseViewModel {
}); });
} }
void update(double value, String header, String log) { Future<void> update(double value, String header, String log) async {
if (value >= 0.0) { if (value >= 0.0) {
progress = value; progress = value;
} }
@ -97,6 +97,10 @@ class InstallerViewModel extends BaseViewModel {
} else if (value == 1.0) { } else if (value == 1.0) {
isPatching = false; isPatching = false;
hasErrors = false; hasErrors = false;
await _managerAPI.savePatches(
_patcherAPI.getFilteredPatches(_app.packageName),
_app.packageName,
);
} else if (value == -100.0) { } else if (value == -100.0) {
isPatching = false; isPatching = false;
hasErrors = true; hasErrors = true;
@ -203,7 +207,7 @@ class InstallerViewModel extends BaseViewModel {
CustomMaterialButton( CustomMaterialButton(
label: I18nText('okButton'), label: I18nText('okButton'),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
) ),
], ],
), ),
); );

View File

@ -11,6 +11,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/ui/widgets/shared/custom_material_button.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/about_info.dart';
import 'package:revanced_manager/utils/check_for_supported_patch.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart'; import 'package:stacked_services/stacked_services.dart';
@ -77,7 +78,7 @@ class PatcherViewModel extends BaseViewModel {
Navigator.of(context).pop(); Navigator.of(context).pop();
showArmv7WarningDialog(context); showArmv7WarningDialog(context);
}, },
) ),
], ],
), ),
); );
@ -110,7 +111,7 @@ class PatcherViewModel extends BaseViewModel {
Navigator.of(context).pop(); Navigator.of(context).pop();
navigateToInstaller(); navigateToInstaller();
}, },
) ),
], ],
), ),
); );
@ -156,6 +157,14 @@ class PatcherViewModel extends BaseViewModel {
this this
.selectedPatches .selectedPatches
.addAll(patches.where((patch) => selectedPatches.contains(patch.name))); .addAll(patches.where((patch) => selectedPatches.contains(patch.name)));
if (!_managerAPI.areExperimentalPatchesEnabled()) {
this.selectedPatches.removeWhere((patch) => !isPatchSupported(patch));
}
if (!_managerAPI.areUniversalPatchesEnabled()) {
this
.selectedPatches
.removeWhere((patch) => patch.compatiblePackages.isEmpty);
}
notifyListeners(); notifyListeners();
} }
} }

View File

@ -1,5 +1,7 @@
import 'package:flutter/material.dart' hide SearchBar; import 'package:flutter/material.dart' hide SearchBar;
import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart'; import 'package:revanced_manager/ui/views/patches_selector/patches_selector_viewmodel.dart';
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';
@ -16,6 +18,7 @@ class PatchesSelectorView extends StatefulWidget {
class _PatchesSelectorViewState extends State<PatchesSelectorView> { class _PatchesSelectorViewState extends State<PatchesSelectorView> {
String _query = ''; String _query = '';
final _managerAPI = locator<ManagerAPI>();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -30,7 +33,7 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
label: Row( label: Row(
children: <Widget>[ children: <Widget>[
I18nText('patchesSelectorView.doneButton'), I18nText('patchesSelectorView.doneButton'),
Text(' (${model.selectedPatches.length})') Text(' (${model.selectedPatches.length})'),
], ],
), ),
icon: const Icon(Icons.check), icon: const Icon(Icons.check),
@ -165,23 +168,65 @@ class _PatchesSelectorViewState extends State<PatchesSelectorView> {
), ),
], ],
), ),
...model ...model.getQueriedPatches(_query).map(
.getQueriedPatches(_query) (patch) {
.map( if (patch.compatiblePackages.isNotEmpty) {
(patch) => PatchItem( return PatchItem(
name: patch.name, name: patch.name,
simpleName: patch.getSimpleName(), simpleName: patch.getSimpleName(),
description: patch.description, description: patch.description,
packageVersion: model.getAppVersion(), packageVersion: model.getAppInfo().version,
supportedPackageVersions: supportedPackageVersions:
model.getSupportedVersions(patch), model.getSupportedVersions(patch),
isUnsupported: !isPatchSupported(patch), isUnsupported: !isPatchSupported(patch),
isNew: model.isPatchNew(
patch,
model.getAppInfo().packageName,
),
isSelected: model.isSelected(patch), isSelected: model.isSelected(patch),
onChanged: (value) => onChanged: (value) =>
model.selectPatch(patch, value), model.selectPatch(patch, value),
);
} else {
return Container();
}
},
), ),
) if (_managerAPI.areUniversalPatchesEnabled())
.toList(), Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0,
),
child: I18nText(
'patchesSelectorView.universalPatches',
),
),
...model.getQueriedPatches(_query).map((patch) {
if (patch.compatiblePackages.isEmpty) {
return PatchItem(
name: patch.name,
simpleName: patch.getSimpleName(),
description: patch.description,
packageVersion:
model.getAppInfo().version,
supportedPackageVersions:
model.getSupportedVersions(patch),
isUnsupported: !isPatchSupported(patch),
isNew: false,
isSelected: model.isSelected(patch),
onChanged: (value) =>
model.selectPatch(patch, value),
);
} else {
return Container();
}
}),
],
),
const SizedBox(height: 70.0),
], ],
), ),
), ),

View File

@ -15,6 +15,7 @@ class PatchesSelectorViewModel extends BaseViewModel {
final List<Patch> patches = []; final List<Patch> patches = [];
final List<Patch> selectedPatches = final List<Patch> selectedPatches =
locator<PatcherViewModel>().selectedPatches; locator<PatcherViewModel>().selectedPatches;
PatchedApplication? selectedApp = locator<PatcherViewModel>().selectedApp;
String? patchesVersion = ''; String? patchesVersion = '';
bool isDefaultPatchesRepo() { bool isDefaultPatchesRepo() {
return _managerAPI.getPatchesRepo() == 'revanced/revanced-patches'; return _managerAPI.getPatchesRepo() == 'revanced/revanced-patches';
@ -24,10 +25,17 @@ class PatchesSelectorViewModel extends BaseViewModel {
getPatchesVersion().whenComplete(() => notifyListeners()); getPatchesVersion().whenComplete(() => notifyListeners());
patches.addAll( patches.addAll(
_patcherAPI.getFilteredPatches( _patcherAPI.getFilteredPatches(
locator<PatcherViewModel>().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(); notifyListeners();
} }
@ -81,7 +89,7 @@ class PatchesSelectorViewModel extends BaseViewModel {
} }
List<Patch> getQueriedPatches(String query) { List<Patch> getQueriedPatches(String query) {
return patches final List<Patch> patch = patches
.where( .where(
(patch) => (patch) =>
query.isEmpty || query.isEmpty ||
@ -90,10 +98,27 @@ class PatchesSelectorViewModel extends BaseViewModel {
patch.getSimpleName().toLowerCase().contains(query.toLowerCase()), patch.getSimpleName().toLowerCase().contains(query.toLowerCase()),
) )
.toList(); .toList();
if (_managerAPI.areUniversalPatchesEnabled()) {
return patch;
} else {
return patch
.where((patch) => patch.compatiblePackages.isNotEmpty)
.toList();
}
} }
String getAppVersion() { PatchedApplication getAppInfo() {
return locator<PatcherViewModel>().selectedApp!.version; return locator<PatcherViewModel>().selectedApp!;
}
bool isPatchNew(Patch patch, String packageName) {
final List<Patch> savedPatches = _managerAPI.getSavedPatches(packageName);
if (savedPatches.isEmpty) {
return false;
} else {
return !savedPatches
.any((p) => p.name == patch.name.toLowerCase().replaceAll(' ', '-'));
}
} }
List<String> getSupportedVersions(Patch patch) { List<String> getSupportedVersions(Patch patch) {

View File

@ -30,7 +30,7 @@ class SManageApiUrl extends BaseViewModel {
icon: const Icon(Icons.manage_history_outlined), icon: const Icon(Icons.manage_history_outlined),
onPressed: () => showApiUrlResetDialog(context), onPressed: () => showApiUrlResetDialog(context),
color: Theme.of(context).colorScheme.secondary, color: Theme.of(context).colorScheme.secondary,
) ),
], ],
), ),
backgroundColor: Theme.of(context).colorScheme.secondaryContainer, backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
@ -69,7 +69,7 @@ class SManageApiUrl extends BaseViewModel {
_managerAPI.setApiUrl(apiUrl); _managerAPI.setApiUrl(apiUrl);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
) ),
], ],
), ),
); );
@ -97,7 +97,7 @@ class SManageApiUrl extends BaseViewModel {
..pop() ..pop()
..pop(); ..pop();
}, },
) ),
], ],
), ),
); );

View File

@ -30,7 +30,7 @@ class SManageKeystorePassword extends BaseViewModel {
onPressed: () => _keystorePasswordController.text = onPressed: () => _keystorePasswordController.text =
_managerAPI.defaultKeystorePassword, _managerAPI.defaultKeystorePassword,
color: Theme.of(context).colorScheme.secondary, color: Theme.of(context).colorScheme.secondary,
) ),
], ],
), ),
backgroundColor: Theme.of(context).colorScheme.secondaryContainer, backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
@ -62,7 +62,7 @@ class SManageKeystorePassword extends BaseViewModel {
_managerAPI.setKeystorePassword(passwd); _managerAPI.setKeystorePassword(passwd);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
) ),
], ],
), ),
); );

View File

@ -40,7 +40,7 @@ class SManageSources extends BaseViewModel {
icon: const Icon(Icons.manage_history_outlined), icon: const Icon(Icons.manage_history_outlined),
onPressed: () => showResetConfirmationDialog(context), onPressed: () => showResetConfirmationDialog(context),
color: Theme.of(context).colorScheme.secondary, color: Theme.of(context).colorScheme.secondary,
) ),
], ],
), ),
backgroundColor: Theme.of(context).colorScheme.secondaryContainer, backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
@ -102,7 +102,7 @@ class SManageSources extends BaseViewModel {
onChanged: (value) => notifyListeners(), onChanged: (value) => notifyListeners(),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
I18nText('settingsView.sourcesUpdateNote') I18nText('settingsView.sourcesUpdateNote'),
], ],
), ),
), ),
@ -132,7 +132,7 @@ class SManageSources extends BaseViewModel {
_toast.showBottom('settingsView.restartAppForChanges'); _toast.showBottom('settingsView.restartAppForChanges');
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
) ),
], ],
), ),
); );
@ -163,7 +163,7 @@ class SManageSources extends BaseViewModel {
..pop() ..pop()
..pop(); ..pop();
}, },
) ),
], ],
), ),
); );

View File

@ -74,7 +74,7 @@ class AppInfoViewModel extends BaseViewModel {
CustomMaterialButton( CustomMaterialButton(
label: I18nText('okButton'), label: I18nText('okButton'),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
) ),
], ],
), ),
); );
@ -103,7 +103,7 @@ class AppInfoViewModel extends BaseViewModel {
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
) ),
], ],
), ),
); );
@ -140,7 +140,7 @@ class AppInfoViewModel extends BaseViewModel {
CustomMaterialButton( CustomMaterialButton(
label: I18nText('okButton'), label: I18nText('okButton'),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
) ),
], ],
), ),
); );

View File

@ -66,7 +66,7 @@ class _InstalledAppItemState extends State<InstalledAppItem> {
context, context,
'installed', 'installed',
translationParams: { translationParams: {
'version': 'v${widget.installedVersion}' 'version': 'v${widget.installedVersion}',
}, },
), ),
), ),

View File

@ -64,7 +64,7 @@ class InstalledAppsCard extends StatelessWidget {
Theme.of(context).colorScheme.secondary, Theme.of(context).colorScheme.secondary,
), ),
), ),
) ),
], ],
), ),
), ),

View File

@ -95,7 +95,7 @@ class UpdateConfirmationDialog extends StatelessWidget {
? model.updatePatches(context) ? model.updatePatches(context)
: model.updateManager(context); : model.updateManager(context);
}, },
) ),
], ],
), ),
), ),

View File

@ -3,7 +3,6 @@ import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/services/manager_api.dart';
import 'package:revanced_manager/services/toast.dart'; import 'package:revanced_manager/services/toast.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_experimental_patches.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_card.dart'; import 'package:revanced_manager/ui/widgets/shared/custom_card.dart';
import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart';
@ -17,6 +16,7 @@ class PatchItem extends StatefulWidget {
required this.packageVersion, required this.packageVersion,
required this.supportedPackageVersions, required this.supportedPackageVersions,
required this.isUnsupported, required this.isUnsupported,
required this.isNew,
required this.isSelected, required this.isSelected,
required this.onChanged, required this.onChanged,
this.child, this.child,
@ -27,6 +27,7 @@ class PatchItem extends StatefulWidget {
final String packageVersion; final String packageVersion;
final List<String> supportedPackageVersions; final List<String> supportedPackageVersions;
final bool isUnsupported; final bool isUnsupported;
final bool isNew;
bool isSelected; bool isSelected;
final Function(bool) onChanged; final Function(bool) onChanged;
final Widget? child; final Widget? child;
@ -126,25 +127,19 @@ class _PatchItemState extends State<PatchItem> {
} else { } else {
widget.isSelected = newValue!; widget.isSelected = newValue!;
} }
if (widget.isUnsupported &&
widget.isSelected &&
!selectedUnsupportedPatches
.contains(widget.name)) {
selectedUnsupportedPatches.add(widget.name);
}
}); });
widget.onChanged(widget.isSelected); widget.onChanged(widget.isSelected);
}, },
), ),
) ),
], ],
), ),
Row(
children: [
if (widget.isUnsupported && if (widget.isUnsupported &&
widget._managerAPI.areExperimentalPatchesEnabled()) widget._managerAPI.areExperimentalPatchesEnabled())
Row(
children: <Widget>[
Padding( Padding(
padding: const EdgeInsets.only(top: 8), padding: const EdgeInsets.only(top: 8, right: 8),
child: TextButton.icon( child: TextButton.icon(
label: I18nText('warning'), label: I18nText('warning'),
icon: const Icon(Icons.warning, size: 20.0), icon: const Icon(Icons.warning, size: 20.0),
@ -167,10 +162,33 @@ class _PatchItemState extends State<PatchItem> {
), ),
), ),
), ),
], 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,
),
),
),
) )
else ],
Container(), ),
widget.child ?? const SizedBox(), widget.child ?? const SizedBox(),
], ],
), ),
@ -197,7 +215,26 @@ class _PatchItemState extends State<PatchItem> {
CustomMaterialButton( CustomMaterialButton(
label: I18nText('okButton'), label: I18nText('okButton'),
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
) ),
],
),
);
}
Future<void> _showNewPatchDialog() {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: I18nText('patchItem.newPatch'),
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
content: I18nText(
'patchItem.newPatchDialogText',
),
actions: <Widget>[
CustomMaterialButton(
label: I18nText('okButton'),
onPressed: () => Navigator.of(context).pop(),
),
], ],
), ),
); );

View File

@ -50,7 +50,7 @@ class CustomSwitch extends StatelessWidget {
color: Colors.black12.withOpacity(0.1), color: Colors.black12.withOpacity(0.1),
spreadRadius: 0.5, spreadRadius: 0.5,
blurRadius: 1, blurRadius: 1,
) ),
], ],
), ),
), ),

View File

@ -93,9 +93,9 @@ class SAdvancedSection extends StatelessWidget {
label: I18nText('yesButton'), label: I18nText('yesButton'),
onPressed: () => { onPressed: () => {
Navigator.of(context).pop(), Navigator.of(context).pop(),
_settingsViewModel.deleteKeystore() _settingsViewModel.deleteKeystore(),
}, },
) ),
], ],
), ),
); );

View File

@ -1,7 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart'; import 'package:flutter_i18n/widgets/I18nText.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/patches_selector/patches_selector_viewmodel.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart'; import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
import 'package:revanced_manager/utils/check_for_supported_patch.dart';
class SExperimentalPatches extends StatefulWidget { class SExperimentalPatches extends StatefulWidget {
const SExperimentalPatches({super.key}); const SExperimentalPatches({super.key});
@ -11,7 +13,8 @@ class SExperimentalPatches extends StatefulWidget {
} }
final _settingsViewModel = SettingsViewModel(); final _settingsViewModel = SettingsViewModel();
final List<String> selectedUnsupportedPatches = []; final _patchesSelectorViewModel = PatchesSelectorViewModel();
final _patcherViewModel = PatcherViewModel();
class _SExperimentalPatchesState extends State<SExperimentalPatches> { class _SExperimentalPatchesState extends State<SExperimentalPatches> {
@override @override
@ -35,12 +38,10 @@ class _SExperimentalPatchesState extends State<SExperimentalPatches> {
_settingsViewModel.useExperimentalPatches(value); _settingsViewModel.useExperimentalPatches(value);
}); });
if (!value) { if (!value) {
for (final patch in selectedUnsupportedPatches) { _patcherViewModel.selectedPatches
PatchesSelectorViewModel() .removeWhere((patch) => !isPatchSupported(patch));
.selectedPatches _patchesSelectorViewModel.selectedPatches
.removeWhere((element) => patch == element.name); .removeWhere((patch) => !isPatchSupported(patch));
}
selectedUnsupportedPatches.clear();
} }
}, },
); );

View File

@ -1,5 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart'; import 'package:flutter_i18n/widgets/I18nText.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/settings_viewmodel.dart'; import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
class SExperimentalUniversalPatches extends StatefulWidget { class SExperimentalUniversalPatches extends StatefulWidget {
@ -11,6 +13,8 @@ class SExperimentalUniversalPatches extends StatefulWidget {
} }
final _settingsViewModel = SettingsViewModel(); final _settingsViewModel = SettingsViewModel();
final _patchesSelectorViewModel = PatchesSelectorViewModel();
final _patcherViewModel = PatcherViewModel();
class _SExperimentalUniversalPatchesState class _SExperimentalUniversalPatchesState
extends State<SExperimentalUniversalPatches> { extends State<SExperimentalUniversalPatches> {
@ -34,6 +38,12 @@ class _SExperimentalUniversalPatchesState
setState(() { setState(() {
_settingsViewModel.showUniversalPatches(value); _settingsViewModel.showUniversalPatches(value);
}); });
if (!value) {
_patcherViewModel.selectedPatches
.removeWhere((patch) => patch.compatiblePackages.isEmpty);
_patchesSelectorViewModel.selectedPatches
.removeWhere((patch) => patch.compatiblePackages.isEmpty);
}
}, },
); );
} }

View File

@ -119,9 +119,9 @@ class SExportSection extends StatelessWidget {
label: I18nText('yesButton'), label: I18nText('yesButton'),
onPressed: () => { onPressed: () => {
Navigator.of(context).pop(), Navigator.of(context).pop(),
_settingsViewModel.resetSelectedPatches() _settingsViewModel.resetSelectedPatches(),
}, },
) ),
], ],
), ),
); );

View File

@ -11,7 +11,7 @@ class AboutInfo {
'flavor': kReleaseMode ? 'release' : 'debug', 'flavor': kReleaseMode ? 'release' : 'debug',
'model': info.model, 'model': info.model,
'androidVersion': info.version.release, 'androidVersion': info.version.release,
'supportedArch': info.supportedAbis 'supportedArch': info.supportedAbis,
}; };
} }
} }