Compare commits

...

19 Commits

Author SHA1 Message Date
Ushie
82c2b2f128 build: bump version to v0.0.51 2022-12-15 21:24:06 +03:00
Ushie
5f81d65911 feat: sort by amount of patches, display patches count, setting to enable universal patches (#593)
* feat: sort by amount of patches

* feat: display patches count in application card

* feat: setting to enable universal patches
2022-12-15 23:35:45 +05:30
Ushie
19f990c564 build: bump version to v0.0.50 2022-12-14 14:17:38 +03:00
Ushie
62467007b2 Revert "feat: display app's patch count in appcard"
This reverts commit 8d4e4ba6c9.
2022-12-14 13:20:17 +03:00
Ushie
d7624e5e1f Revert "feat: filter apps by patch count"
This reverts commit d78868b462.
2022-12-14 13:19:59 +03:00
oSumAtrIX
4505f10e50 build: bump version number 2022-12-14 06:04:42 +01:00
oSumAtrIX
3ce3df5e19 build: bump patcher version 2022-12-14 06:04:10 +01:00
Ushie
8d4e4ba6c9 feat: display app's patch count in appcard 2022-12-14 02:12:57 +03:00
Ushie
d78868b462 feat: filter apps by patch count 2022-12-14 01:52:06 +03:00
Canny
01a681ad00 build: bump version to v0.0.48 2022-12-12 22:34:39 +03:00
Canny
adfeb61eab fix: print patch fail cause if message is null 2022-12-12 22:32:11 +03:00
Ushie
8c3faac343 build: bump version to v0.0.47 2022-12-12 17:09:32 +03:00
Ushie
c81acce31c feat: improve patch fail logging 2022-12-12 17:09:32 +03:00
Aunali321
fe629ce77c Merge branch 'flutter' of https://github.com/revanced/revanced-manager into flutter 2022-12-11 18:04:06 +05:30
Aunali321
5c27add2b2 bump:bump version to v0.0.46 2022-12-11 18:04:00 +05:30
aliernfrog
ff90dae695 feat: add support for shared patches (#577)
* fix: avoid npe if a patch has empty compatible package.

* feat: support for shared patches

* fix: incorrect bool check and cleanup

Co-authored-by: Aunali321 <aunvakil.aa@gmail.com>
2022-12-11 18:00:44 +05:30
Aunali321
4f8aec6a05 build: bump version to v0.0.45 2022-12-09 17:47:51 +05:30
Syed Ahmad
ba8df57580 Update broken link (#569) 2022-12-09 17:42:09 +05:30
Logykk
3bab1940c1 Support Gitea repositories (#570) 2022-12-09 17:40:43 +05:30
18 changed files with 180 additions and 40 deletions

View File

@@ -28,7 +28,7 @@ If you wish to translate ReVanced Manager, we're accepting translations on [Crow
## 🛠️ Building Manager from source ## 🛠️ Building Manager from source
1. Setup flutter environment for your [platform](https://docs.flutter.dev/get-started/install) 1. Setup flutter environment for your [platform](https://docs.flutter.dev/get-started/install)
2. Clone the repository locally 2. Clone the repository locally
3. Add your github token in gradle.properties like [this](https://github.com/revanced/revanced-documentation/wiki/Building-from-source) 3. Add your github token in gradle.properties like [this](https://github.com/revanced/revanced-documentation/blob/main/docs/revanced-development/2_building_from_source.md)
4. Open the project in terminal 4. Open the project in terminal
5. Run `flutter pub get` in terminal 5. Run `flutter pub get` in terminal
6. Then `flutter packages pub run build_runner build --delete-conflicting-outputs` (Must be done on each git pull) 6. Then `flutter packages pub run build_runner build --delete-conflicting-outputs` (Must be done on each git pull)

View File

@@ -71,7 +71,7 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// ReVanced // ReVanced
implementation "app.revanced:revanced-patcher:6.3.0" implementation "app.revanced:revanced-patcher:6.3.1"
// Signing & aligning // Signing & aligning
implementation("org.bouncycastle:bcpkix-jdk15on:1.70") implementation("org.bouncycastle:bcpkix-jdk15on:1.70")

View File

@@ -174,7 +174,7 @@ class MainActivity : FlutterActivity() {
javaClass.classLoader javaClass.classLoader
) )
).loadPatches().filter { patch -> ).loadPatches().filter { patch ->
patch.compatiblePackages!!.any { it.name == patcher.context.packageMetadata.packageName } && (patch.compatiblePackages?.any { it.name == patcher.context.packageMetadata.packageName } == true || patch.compatiblePackages.isNullOrEmpty()) &&
selectedPatches.any { it == patch.patchName } selectedPatches.any { it == patch.patchName }
} }
} else { } else {
@@ -196,7 +196,7 @@ class MainActivity : FlutterActivity() {
} }
return@forEach return@forEach
} }
val msg = "$patch failed.\nError:\n" + res.exceptionOrNull()!!.printStackTrace() val msg = "Failed to apply $patch: " + "${res.exceptionOrNull()!!.message ?: res.exceptionOrNull()!!.cause!!::class.simpleName}"
handler.post { handler.post {
installerChannel.invokeMethod( installerChannel.invokeMethod(
"update", "update",

View File

@@ -122,6 +122,7 @@
"englishOption": "English", "englishOption": "English",
"sourcesLabel": "Sources", "sourcesLabel": "Sources",
"sourcesLabelHint": "Configure your custom sources", "sourcesLabelHint": "Configure your custom sources",
"hostRepositoryLabel": "Repository API",
"orgPatchesLabel": "Patches organization", "orgPatchesLabel": "Patches organization",
"sourcesPatchesLabel": "Patches source", "sourcesPatchesLabel": "Patches source",
"orgIntegrationsLabel": "Integrations organization", "orgIntegrationsLabel": "Integrations organization",
@@ -136,6 +137,8 @@
"apiURLLabel": "API URL", "apiURLLabel": "API URL",
"apiURLHint": "Configure your custom API URL", "apiURLHint": "Configure your custom API URL",
"selectApiURL": "API URL", "selectApiURL": "API URL",
"experimentalUniversalPatchesLabel": "Experimental universal patches support",
"experimentalUniversalPatchesHint": "Display all applications to use with universal patches, loading list of apps may be slower",
"experimentalPatchesLabel": "Experimental patches support", "experimentalPatchesLabel": "Experimental patches support",
"experimentalPatchesHint": "Enable usage of unsupported patches in any app version", "experimentalPatchesHint": "Enable usage of unsupported patches in any app version",
"enabledExperimentalPatches": "Experimental patches support enabled", "enabledExperimentalPatches": "Experimental patches support enabled",

View File

@@ -25,7 +25,8 @@ Future main() async {
await locator<RevancedAPI>().initialize(apiUrl); await locator<RevancedAPI>().initialize(apiUrl);
await locator<CrowdinAPI>().initialize(); await locator<CrowdinAPI>().initialize();
bool isSentryEnabled = locator<ManagerAPI>().isSentryEnabled(); bool isSentryEnabled = locator<ManagerAPI>().isSentryEnabled();
locator<GithubAPI>().initialize(); String repoUrl = locator<ManagerAPI>().getRepoUrl();
locator<GithubAPI>().initialize(repoUrl);
await locator<PatcherAPI>().initialize(); await locator<PatcherAPI>().initialize();
tz.initializeTimeZones(); tz.initializeTimeZones();
prefs = await SharedPreferences.getInstance(); prefs = await SharedPreferences.getInstance();

View File

@@ -28,10 +28,10 @@ class GithubAPI {
'com.spotify.music': 'spotify', 'com.spotify.music': 'spotify',
}; };
void initialize() async { void initialize(String repoUrl) async {
try { try {
_dio = Dio(BaseOptions( _dio = Dio(BaseOptions(
baseUrl: 'https://api.github.com', baseUrl: repoUrl,
)); ));
_dio.interceptors.add(_dioCacheManager.interceptor); _dio.interceptors.add(_dioCacheManager.interceptor);
@@ -54,10 +54,10 @@ class GithubAPI {
Future<Map<String, dynamic>?> getLatestRelease(String repoName) async { Future<Map<String, dynamic>?> getLatestRelease(String repoName) async {
try { try {
var response = await _dio.get( var response = await _dio.get(
'/repos/$repoName/releases/latest', '/repos/$repoName/releases',
options: _cacheOptions, options: _cacheOptions,
); );
return response.data; return response.data[0];
} on Exception catch (e, s) { } on Exception catch (e, s) {
await Sentry.captureException(e, stackTrace: s); await Sentry.captureException(e, stackTrace: s);
return null; return null;

View File

@@ -23,6 +23,7 @@ class ManagerAPI {
late String storedPatchesFile = '/selected-patches.json'; late String storedPatchesFile = '/selected-patches.json';
late SharedPreferences _prefs; late SharedPreferences _prefs;
String defaultApiUrl = 'https://releases.revanced.app/'; String defaultApiUrl = 'https://releases.revanced.app/';
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';
String defaultIntegrationsRepo = 'revanced/revanced-integrations'; String defaultIntegrationsRepo = 'revanced/revanced-integrations';
@@ -48,6 +49,17 @@ class ManagerAPI {
await _prefs.setString('apiUrl', url); await _prefs.setString('apiUrl', url);
} }
String getRepoUrl() {
return _prefs.getString('repoUrl') ?? defaultRepoUrl;
}
Future<void> setRepoUrl(String url) async {
if (url.isEmpty || url == ' ') {
url = defaultRepoUrl;
}
await _prefs.setString('repoUrl', url);
}
String getPatchesRepo() { String getPatchesRepo() {
return _prefs.getString('patchesRepo') ?? defaultPatchesRepo; return _prefs.getString('patchesRepo') ?? defaultPatchesRepo;
} }
@@ -94,6 +106,14 @@ class ManagerAPI {
await _prefs.setBool('sentryEnabled', value); await _prefs.setBool('sentryEnabled', value);
} }
bool areUniversalPatchesEnabled() {
return _prefs.getBool('universalPatchesEnabled') ?? false;
}
Future<void> enableUniversalPatchesStatus(bool value) async {
await _prefs.setBool('universalPatchesEnabled', value);
}
bool areExperimentalPatchesEnabled() { bool areExperimentalPatchesEnabled() {
return _prefs.getBool('experimentalPatchesEnabled') ?? false; return _prefs.getBool('experimentalPatchesEnabled') ?? false;
} }

View File

@@ -24,6 +24,7 @@ class PatcherAPI {
late Directory _tmpDir; late Directory _tmpDir;
late File _keyStoreFile; late File _keyStoreFile;
List<Patch> _patches = []; List<Patch> _patches = [];
Map filteredPatches = <String, List<Patch>>{};
File? _outFile; File? _outFile;
Future<void> initialize() async { Future<void> initialize() async {
@@ -52,8 +53,27 @@ class PatcherAPI {
} }
} }
Future<List<ApplicationWithIcon>> getFilteredInstalledApps() async { Future<List<ApplicationWithIcon>> getFilteredInstalledApps(bool showUniversalPatches) async {
List<ApplicationWithIcon> filteredApps = []; List<ApplicationWithIcon> filteredApps = [];
bool? allAppsIncluded =
_patches.any((patch) => patch.compatiblePackages.isEmpty) && showUniversalPatches;
if (allAppsIncluded) {
var allPackages = await DeviceApps.getInstalledApplications(
includeAppIcons: true,
onlyAppsWithLaunchIntent: true,
);
allPackages.forEach((pkg) async {
if (!filteredApps.any((app) => app.packageName == pkg.packageName)) {
var appInfo = await DeviceApps.getApp(
pkg.packageName,
true,
) as ApplicationWithIcon?;
if (appInfo != null) {
filteredApps.add(appInfo);
}
}
});
}
for (Patch patch in _patches) { for (Patch patch in _patches) {
for (Package package in patch.compatiblePackages) { for (Package package in patch.compatiblePackages) {
try { try {
@@ -75,12 +95,18 @@ class PatcherAPI {
return filteredApps; return filteredApps;
} }
Future<List<Patch>> getFilteredPatches(String packageName) async { List<Patch> getFilteredPatches(String packageName) {
return _patches if (!filteredPatches.keys.contains(packageName)) {
.where((patch) => List<Patch> patches = _patches
!patch.name.contains('settings') && .where((patch) =>
patch.compatiblePackages.any((pack) => pack.name == packageName)) patch.compatiblePackages.isEmpty ||
.toList(); !patch.name.contains('settings') &&
patch.compatiblePackages
.any((pack) => pack.name == packageName))
.toList();
filteredPatches[packageName] = patches;
}
return filteredPatches[packageName];
} }
Future<List<Patch>> getAppliedPatches(List<String> appliedPatches) async { Future<List<Patch>> getAppliedPatches(List<String> appliedPatches) async {
@@ -229,7 +255,6 @@ class PatcherAPI {
return false; return false;
} }
void exportPatchedFile(String appName, String version) { void exportPatchedFile(String appName, String version) {
try { try {
if (_outFile != null) { if (_outFile != null) {
@@ -238,13 +263,12 @@ class PatcherAPI {
// This is temporary workaround to populate initial file name // This is temporary workaround to populate initial file name
// ref: https://github.com/Cleveroad/cr_file_saver/issues/7 // ref: https://github.com/Cleveroad/cr_file_saver/issues/7
int lastSeparator = _outFile!.path.lastIndexOf('/'); int lastSeparator = _outFile!.path.lastIndexOf('/');
String newSourcePath = _outFile!.path.substring(0, lastSeparator + 1) + newName; String newSourcePath =
_outFile!.path.substring(0, lastSeparator + 1) + newName;
_outFile!.copySync(newSourcePath); _outFile!.copySync(newSourcePath);
CRFileSaver.saveFileWithDialog(SaveFileDialogParams( CRFileSaver.saveFileWithDialog(SaveFileDialogParams(
sourceFilePath: newSourcePath, sourceFilePath: newSourcePath, destinationFileName: newName));
destinationFileName: newName
));
} }
} on Exception catch (e, s) { } on Exception catch (e, s) {
Sentry.captureException(e, stackTrace: s); Sentry.captureException(e, stackTrace: s);
@@ -267,10 +291,9 @@ class PatcherAPI {
} }
String _getFileName(String appName, String version) { String _getFileName(String appName, String version) {
String prefix = appName.toLowerCase().replaceAll(' ', '-'); String prefix = appName.toLowerCase().replaceAll(' ', '-');
String newName = '$prefix-revanced_v$version.apk'; String newName = '$prefix-revanced_v$version.apk';
return newName; return newName;
} }
Future<void> sharePatcherLog(String logs) async { Future<void> sharePatcherLog(String logs) async {

View File

@@ -92,6 +92,8 @@ class _AppSelectorViewState extends State<AppSelectorView> {
name: app.appName, name: app.appName,
pkgName: app.packageName, pkgName: app.packageName,
icon: app.icon, icon: app.icon,
patchesCount:
model.patchesCount(app.packageName),
onTap: () { onTap: () {
model.selectApp(app); model.selectApp(app);
Navigator.of(context).pop(); Navigator.of(context).pop();

View File

@@ -2,7 +2,6 @@ import 'dart:io';
import 'package:device_apps/device_apps.dart'; import 'package:device_apps/device_apps.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/models/patched_application.dart';
import 'package:revanced_manager/services/patcher_api.dart'; import 'package:revanced_manager/services/patcher_api.dart';
@@ -10,16 +9,24 @@ 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:sentry_flutter/sentry_flutter.dart'; import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import '../../../services/manager_api.dart';
class AppSelectorViewModel extends BaseViewModel { class AppSelectorViewModel extends BaseViewModel {
final PatcherAPI _patcherAPI = locator<PatcherAPI>(); final PatcherAPI _patcherAPI = locator<PatcherAPI>();
final ManagerAPI _managerAPI = locator<ManagerAPI>();
final Toast _toast = locator<Toast>(); final Toast _toast = locator<Toast>();
final List<ApplicationWithIcon> apps = []; final List<ApplicationWithIcon> apps = [];
bool noApps = false; bool noApps = false;
int patchesCount(String packageName) {
return _patcherAPI.getFilteredPatches(packageName).length;
}
Future<void> initialize() async { Future<void> initialize() async {
apps.addAll(await _patcherAPI.getFilteredInstalledApps()); apps.addAll(await _patcherAPI.getFilteredInstalledApps(_managerAPI.areUniversalPatchesEnabled()));
apps.sort((a, b) => a.appName.compareTo(b.appName)); apps.sort(((a, b) => _patcherAPI
.getFilteredPatches(b.packageName)
.length
.compareTo(_patcherAPI.getFilteredPatches(a.packageName).length)));
noApps = apps.isEmpty; noApps = apps.isEmpty;
notifyListeners(); notifyListeners();
} }

View File

@@ -113,7 +113,7 @@ class PatcherViewModel extends BaseViewModel {
List<String> selectedPatches = List<String> selectedPatches =
await _managerAPI.getSelectedPatches(selectedApp!.originalPackageName); await _managerAPI.getSelectedPatches(selectedApp!.originalPackageName);
List<Patch> patches = List<Patch> patches =
await _patcherAPI.getFilteredPatches(selectedApp!.originalPackageName); _patcherAPI.getFilteredPatches(selectedApp!.originalPackageName);
this this
.selectedPatches .selectedPatches
.addAll(patches.where((patch) => selectedPatches.contains(patch.name))); .addAll(patches.where((patch) => selectedPatches.contains(patch.name)));

View File

@@ -26,7 +26,7 @@ class PatchesSelectorViewModel extends BaseViewModel {
Future<void> initialize() async { Future<void> initialize() async {
getPatchesVersion(); getPatchesVersion();
patches.addAll(await _patcherAPI.getFilteredPatches( patches.addAll(_patcherAPI.getFilteredPatches(
locator<PatcherViewModel>().selectedApp!.originalPackageName, locator<PatcherViewModel>().selectedApp!.originalPackageName,
)); ));
patches.sort((a, b) => a.name.compareTo(b.name)); patches.sort((a, b) => a.name.compareTo(b.name));
@@ -147,7 +147,7 @@ class PatchesSelectorViewModel extends BaseViewModel {
bool isPatchSupported(Patch patch) { bool isPatchSupported(Patch patch) {
PatchedApplication app = locator<PatcherViewModel>().selectedApp!; PatchedApplication app = locator<PatcherViewModel>().selectedApp!;
return patch.compatiblePackages.any((pack) => return patch.compatiblePackages.isEmpty || patch.compatiblePackages.any((pack) =>
pack.name == app.packageName && pack.name == app.packageName &&
(pack.versions.isEmpty || pack.versions.contains(app.version))); (pack.versions.isEmpty || pack.versions.contains(app.version)));
} }

View File

@@ -12,14 +12,17 @@ import 'package:stacked/stacked.dart';
class SManageSources extends BaseViewModel { class SManageSources extends BaseViewModel {
final ManagerAPI _managerAPI = locator<ManagerAPI>(); final ManagerAPI _managerAPI = locator<ManagerAPI>();
final TextEditingController _hostSourceController = TextEditingController();
final TextEditingController _orgPatSourceController = TextEditingController(); final TextEditingController _orgPatSourceController = TextEditingController();
final TextEditingController _patSourceController = TextEditingController(); final TextEditingController _patSourceController = TextEditingController();
final TextEditingController _orgIntSourceController = TextEditingController(); final TextEditingController _orgIntSourceController = TextEditingController();
final TextEditingController _intSourceController = TextEditingController(); final TextEditingController _intSourceController = TextEditingController();
Future<void> showSourcesDialog(BuildContext context) async { Future<void> showSourcesDialog(BuildContext context) async {
String hostRepository = _managerAPI.getRepoUrl();
String patchesRepo = _managerAPI.getPatchesRepo(); String patchesRepo = _managerAPI.getPatchesRepo();
String integrationsRepo = _managerAPI.getIntegrationsRepo(); String integrationsRepo = _managerAPI.getIntegrationsRepo();
_hostSourceController.text = hostRepository;
_orgPatSourceController.text = patchesRepo.split('/')[0]; _orgPatSourceController.text = patchesRepo.split('/')[0];
_patSourceController.text = patchesRepo.split('/')[1]; _patSourceController.text = patchesRepo.split('/')[1];
_orgIntSourceController.text = integrationsRepo.split('/')[0]; _orgIntSourceController.text = integrationsRepo.split('/')[0];
@@ -42,6 +45,17 @@ class SManageSources extends BaseViewModel {
content: SingleChildScrollView( content: SingleChildScrollView(
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
CustomTextField(
leadingIcon: const Icon(
Icons.extension_outlined,
color: Colors.transparent,
),
inputController: _hostSourceController,
label: I18nText('settingsView.hostRepositoryLabel'),
hint: hostRepository,
onChanged: (value) => notifyListeners(),
),
const SizedBox(height: 20),
CustomTextField( CustomTextField(
leadingIcon: Icon( leadingIcon: Icon(
Icons.extension_outlined, Icons.extension_outlined,
@@ -103,6 +117,7 @@ class SManageSources extends BaseViewModel {
CustomMaterialButton( CustomMaterialButton(
label: I18nText('okButton'), label: I18nText('okButton'),
onPressed: () { onPressed: () {
_managerAPI.setRepoUrl(_hostSourceController.text);
_managerAPI.setPatchesRepo( _managerAPI.setPatchesRepo(
'${_orgPatSourceController.text}/${_patSourceController.text}', '${_orgPatSourceController.text}/${_patSourceController.text}',
); );
@@ -133,10 +148,12 @@ class SManageSources extends BaseViewModel {
CustomMaterialButton( CustomMaterialButton(
label: I18nText('yesButton'), label: I18nText('yesButton'),
onPressed: () { onPressed: () {
_managerAPI.setRepoUrl('');
_managerAPI.setPatchesRepo(''); _managerAPI.setPatchesRepo('');
_managerAPI.setIntegrationsRepo(''); _managerAPI.setIntegrationsRepo('');
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.of(context).pop(); Navigator.of(context).pop();
Navigator.of(context).pop();
}, },
) )
], ],

View File

@@ -38,6 +38,15 @@ class SettingsViewModel extends BaseViewModel {
notifyListeners(); notifyListeners();
} }
bool areUniversalPatchesEnabled() {
return _managerAPI.areUniversalPatchesEnabled();
}
void showUniversalPatches(bool value) {
_managerAPI.enableUniversalPatchesStatus(value);
notifyListeners();
}
bool areExperimentalPatchesEnabled() { bool areExperimentalPatchesEnabled() {
return _managerAPI.areExperimentalPatchesEnabled(); return _managerAPI.areExperimentalPatchesEnabled();
} }

View File

@@ -6,6 +6,7 @@ class InstalledAppItem extends StatefulWidget {
final String name; final String name;
final String pkgName; final String pkgName;
final Uint8List icon; final Uint8List icon;
final int patchesCount;
final Function()? onTap; final Function()? onTap;
const InstalledAppItem({ const InstalledAppItem({
@@ -13,6 +14,7 @@ class InstalledAppItem extends StatefulWidget {
required this.name, required this.name,
required this.pkgName, required this.pkgName,
required this.icon, required this.icon,
required this.patchesCount,
this.onTap, this.onTap,
}) : super(key: key); }) : super(key: key);
@@ -45,14 +47,29 @@ class _InstalledAppItemState extends State<InstalledAppItem> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Text( Row(
widget.name, crossAxisAlignment: CrossAxisAlignment.center,
maxLines: 2, children: <Widget>[
overflow: TextOverflow.visible, Text(
style: const TextStyle( widget.name,
fontSize: 16, maxLines: 2,
fontWeight: FontWeight.w500, overflow: TextOverflow.visible,
), style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
const SizedBox(width: 6),
Text(
widget.patchesCount == 1
? "${widget.patchesCount} patch"
: "${widget.patchesCount} patches",
style: TextStyle(
fontSize: 8,
color: Theme.of(context).colorScheme.secondary,
),
),
],
), ),
const SizedBox(height: 4), const SizedBox(height: 4),
Text(widget.pkgName), Text(widget.pkgName),

View File

@@ -6,6 +6,7 @@ import 'package:revanced_manager/ui/views/settings/settingsFragement/settings_ma
import 'package:revanced_manager/ui/views/settings/settingsFragement/settings_manage_sources.dart'; import 'package:revanced_manager/ui/views/settings/settingsFragement/settings_manage_sources.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/ui/widgets/settingsView/settings_experimental_patches.dart'; import 'package:revanced_manager/ui/widgets/settingsView/settings_experimental_patches.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_experimental_universal_patches.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart'; import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart';
final _settingsViewModel = SettingsViewModel(); final _settingsViewModel = SettingsViewModel();
@@ -20,6 +21,7 @@ class SAdvancedSection extends StatelessWidget {
children: <Widget>[ children: <Widget>[
SManageApiUrlUI(), SManageApiUrlUI(),
SManageSourcesUI(), SManageSourcesUI(),
SExperimentalUniversalPatches(),
SExperimentalPatches(), SExperimentalPatches(),
ListTile( ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0), contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),

View File

@@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:flutter_i18n/widgets/I18nText.dart';
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
import 'package:revanced_manager/ui/widgets/settingsView/custom_switch_tile.dart';
class SExperimentalUniversalPatches extends StatefulWidget {
const SExperimentalUniversalPatches({super.key});
@override
State<SExperimentalUniversalPatches> createState() => _SExperimentalUniversalPatchesState();
}
final _settingsViewModel = SettingsViewModel();
class _SExperimentalUniversalPatchesState extends State<SExperimentalUniversalPatches> {
@override
Widget build(BuildContext context) {
return CustomSwitchTile(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.experimentalUniversalPatchesLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
),
subtitle: I18nText('settingsView.experimentalUniversalPatchesHint'),
value: _settingsViewModel.areUniversalPatchesEnabled(),
onTap: (value) {
setState(() {
_settingsViewModel.showUniversalPatches(value);
});
},
);
}
}

View File

@@ -4,7 +4,7 @@ homepage: https://github.com/revanced/revanced-manager
publish_to: 'none' publish_to: 'none'
version: 0.0.44+44 version: 0.0.51+51
environment: environment:
sdk: ">=2.17.5 <3.0.0" sdk: ">=2.17.5 <3.0.0"