mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2026-01-24 11:41:01 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01a681ad00 | ||
|
|
adfeb61eab | ||
|
|
8c3faac343 | ||
|
|
c81acce31c | ||
|
|
fe629ce77c | ||
|
|
5c27add2b2 | ||
|
|
ff90dae695 | ||
|
|
4f8aec6a05 | ||
|
|
ba8df57580 | ||
|
|
3bab1940c1 | ||
|
|
e300c92215 | ||
|
|
99764e25ed | ||
|
|
b5dcae11a4 | ||
|
|
f69f475ab9 | ||
|
|
061e929705 | ||
|
|
9e8193a6ac | ||
|
|
1601796c6c | ||
|
|
a0af0dde0a | ||
|
|
c5ba6a238a |
5
.github/workflows/crowdin.yml
vendored
5
.github/workflows/crowdin.yml
vendored
@@ -22,7 +22,8 @@ jobs:
|
|||||||
uses: crowdin/github-action@1.5.0
|
uses: crowdin/github-action@1.5.0
|
||||||
with:
|
with:
|
||||||
config: crowdin.yml
|
config: crowdin.yml
|
||||||
upload_translations: true
|
upload_sources: true
|
||||||
|
upload_translations: false
|
||||||
download_translations: true
|
download_translations: true
|
||||||
push_translations: true
|
push_translations: true
|
||||||
create_pull_request: false
|
create_pull_request: false
|
||||||
@@ -42,4 +43,4 @@ jobs:
|
|||||||
# git checkout flutter
|
# git checkout flutter
|
||||||
# git add *
|
# git add *
|
||||||
# git merge i18n_flutter
|
# git merge i18n_flutter
|
||||||
# git push
|
# git push
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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.0.0"
|
implementation "app.revanced:revanced-patcher:6.3.0"
|
||||||
|
|
||||||
// Signing & aligning
|
// Signing & aligning
|
||||||
implementation("org.bouncycastle:bcpkix-jdk15on:1.70")
|
implementation("org.bouncycastle:bcpkix-jdk15on:1.70")
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"okButton": "OK",
|
"okButton": "OK",
|
||||||
"cancelButton": "Cancel",
|
"cancelButton": "Cancel",
|
||||||
|
"updateButton": "Update",
|
||||||
"enabledLabel": "Enabled",
|
"enabledLabel": "Enabled",
|
||||||
"disabledLabel": "Disabled",
|
"disabledLabel": "Disabled",
|
||||||
"yesButton": "Yes",
|
"yesButton": "Yes",
|
||||||
@@ -21,7 +22,7 @@
|
|||||||
"noInstallations": "No patched applications installed",
|
"noInstallations": "No patched applications installed",
|
||||||
"installed": "Installed",
|
"installed": "Installed",
|
||||||
"updateDialogTitle": "Update Manager",
|
"updateDialogTitle": "Update Manager",
|
||||||
"updateDialogText": "Are you sure you want to download and update ReVanced Manager?",
|
"updateChangelogTitle": "Changelog",
|
||||||
"notificationTitle": "Update downloaded",
|
"notificationTitle": "Update downloaded",
|
||||||
"notificationText": "Tap to install the update",
|
"notificationText": "Tap to install the update",
|
||||||
"downloadingMessage": "Downloading update...",
|
"downloadingMessage": "Downloading update...",
|
||||||
@@ -121,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",
|
||||||
|
|||||||
@@ -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();
|
||||||
@@ -60,10 +61,11 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
String rawLocale = prefs.getString('language') ?? 'en_US';
|
// String rawLocale = prefs.getString('language') ?? 'en_US';
|
||||||
String replaceLocale = rawLocale.replaceAll('_', '-');
|
// String replaceLocale = rawLocale.replaceAll('_', '-');
|
||||||
List<String> localeList = replaceLocale.split('-');
|
// List<String> localeList = replaceLocale.split('-');
|
||||||
Locale locale = Locale(localeList[0], localeList[1]);
|
// Locale locale = Locale(localeList[0], localeList[1]);
|
||||||
|
Locale locale = const Locale('en', 'US');
|
||||||
|
|
||||||
return DynamicThemeBuilder(
|
return DynamicThemeBuilder(
|
||||||
title: 'ReVanced Manager',
|
title: 'ReVanced Manager',
|
||||||
@@ -71,6 +73,7 @@ class MyApp extends StatelessWidget {
|
|||||||
localizationsDelegates: [
|
localizationsDelegates: [
|
||||||
FlutterI18nDelegate(
|
FlutterI18nDelegate(
|
||||||
translationLoader: FileTranslationLoader(
|
translationLoader: FileTranslationLoader(
|
||||||
|
fallbackFile: 'en_US',
|
||||||
forcedLocale: locale,
|
forcedLocale: locale,
|
||||||
basePath: 'assets/i18n',
|
basePath: 'assets/i18n',
|
||||||
useCountryCode: true,
|
useCountryCode: true,
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -51,13 +51,13 @@ 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;
|
||||||
@@ -97,7 +97,7 @@ class GithubAPI {
|
|||||||
|
|
||||||
Future<File?> getLatestReleaseFile(String extension, String repoName) async {
|
Future<File?> getLatestReleaseFile(String extension, String repoName) async {
|
||||||
try {
|
try {
|
||||||
Map<String, dynamic>? release = await _getLatestRelease(repoName);
|
Map<String, dynamic>? release = await getLatestRelease(repoName);
|
||||||
if (release != null) {
|
if (release != null) {
|
||||||
Map<String, dynamic>? asset =
|
Map<String, dynamic>? asset =
|
||||||
(release['assets'] as List<dynamic>).firstWhereOrNull(
|
(release['assets'] as List<dynamic>).firstWhereOrNull(
|
||||||
@@ -133,7 +133,7 @@ class GithubAPI {
|
|||||||
|
|
||||||
Future<String> getLastestReleaseVersion(String repoName) async {
|
Future<String> getLastestReleaseVersion(String repoName) async {
|
||||||
try {
|
try {
|
||||||
Map<String, dynamic>? release = await _getLatestRelease(repoName);
|
Map<String, dynamic>? release = await getLatestRelease(repoName);
|
||||||
if (release != null) {
|
if (release != null) {
|
||||||
return release['tag_name'];
|
return release['tag_name'];
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,25 @@ class PatcherAPI {
|
|||||||
|
|
||||||
Future<List<ApplicationWithIcon>> getFilteredInstalledApps() async {
|
Future<List<ApplicationWithIcon>> getFilteredInstalledApps() async {
|
||||||
List<ApplicationWithIcon> filteredApps = [];
|
List<ApplicationWithIcon> filteredApps = [];
|
||||||
|
bool? allAppsIncluded =
|
||||||
|
_patches.any((patch) => patch.compatiblePackages.isEmpty);
|
||||||
|
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 {
|
||||||
@@ -76,11 +95,19 @@ class PatcherAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Patch>> getFilteredPatches(String packageName) async {
|
Future<List<Patch>> getFilteredPatches(String packageName) async {
|
||||||
return _patches
|
List<Patch> filteredPatches = [];
|
||||||
.where((patch) =>
|
_patches.forEach((patch) {
|
||||||
!patch.name.contains('settings') &&
|
if (patch.compatiblePackages.isEmpty) {
|
||||||
patch.compatiblePackages.any((pack) => pack.name == packageName))
|
filteredPatches.add(patch);
|
||||||
.toList();
|
} else {
|
||||||
|
if (!patch.name.contains('settings') &&
|
||||||
|
patch.compatiblePackages.any((pack) => pack.name == packageName)
|
||||||
|
) {
|
||||||
|
filteredPatches.add(patch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return filteredPatches;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Patch>> getAppliedPatches(List<String> appliedPatches) async {
|
Future<List<Patch>> getAppliedPatches(List<String> appliedPatches) async {
|
||||||
@@ -229,7 +256,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 +264,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 +292,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 {
|
||||||
|
|||||||
@@ -12,10 +12,11 @@ import 'package:revanced_manager/app/app.router.dart';
|
|||||||
import 'package:revanced_manager/models/patched_application.dart';
|
import 'package:revanced_manager/models/patched_application.dart';
|
||||||
import 'package:revanced_manager/services/manager_api.dart';
|
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/github_api.dart';
|
||||||
import 'package:revanced_manager/services/toast.dart';
|
import 'package:revanced_manager/services/toast.dart';
|
||||||
import 'package:revanced_manager/ui/views/navigation/navigation_viewmodel.dart';
|
import 'package:revanced_manager/ui/views/navigation/navigation_viewmodel.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/ui/widgets/shared/custom_material_button.dart';
|
import 'package:revanced_manager/ui/widgets/homeView/update_confirmation_dialog.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 'package:stacked_services/stacked_services.dart';
|
import 'package:stacked_services/stacked_services.dart';
|
||||||
@@ -26,6 +27,7 @@ class HomeViewModel extends BaseViewModel {
|
|||||||
final NavigationService _navigationService = locator<NavigationService>();
|
final NavigationService _navigationService = locator<NavigationService>();
|
||||||
final ManagerAPI _managerAPI = locator<ManagerAPI>();
|
final ManagerAPI _managerAPI = locator<ManagerAPI>();
|
||||||
final PatcherAPI _patcherAPI = locator<PatcherAPI>();
|
final PatcherAPI _patcherAPI = locator<PatcherAPI>();
|
||||||
|
final GithubAPI _githubAPI = locator<GithubAPI>();
|
||||||
final Toast _toast = locator<Toast>();
|
final Toast _toast = locator<Toast>();
|
||||||
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
|
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
|
||||||
DateTime? _lastUpdate;
|
DateTime? _lastUpdate;
|
||||||
@@ -147,36 +149,26 @@ class HomeViewModel extends BaseViewModel {
|
|||||||
_toast.showBottom('homeView.updatesDisabled');
|
_toast.showBottom('homeView.updatesDisabled');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> showUpdateConfirmationDialog(BuildContext parentContext) async {
|
Future<void> showUpdateConfirmationDialog(BuildContext parentContext) {
|
||||||
return showDialog(
|
return showModalBottomSheet(
|
||||||
context: parentContext,
|
context: parentContext,
|
||||||
builder: (context) => AlertDialog(
|
isScrollControlled: true,
|
||||||
title: I18nText('homeView.updateDialogTitle'),
|
shape: const RoundedRectangleBorder(
|
||||||
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
|
borderRadius: BorderRadius.vertical(top: Radius.circular(24.0)),
|
||||||
content: I18nText('homeView.updateDialogText'),
|
|
||||||
actions: <Widget>[
|
|
||||||
CustomMaterialButton(
|
|
||||||
isFilled: false,
|
|
||||||
label: I18nText('noButton'),
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
),
|
|
||||||
CustomMaterialButton(
|
|
||||||
label: I18nText('yesButton'),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
updateManager(parentContext);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
builder: (context) => const UpdateConfirmationDialog(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> getLatestPatcherReleaseTime() async {
|
Future<Map<String, dynamic>?> getLatestManagerRelease() {
|
||||||
|
return _githubAPI.getLatestRelease(_managerAPI.defaultManagerRepo);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String?> getLatestPatcherReleaseTime() {
|
||||||
return _managerAPI.getLatestPatcherReleaseTime();
|
return _managerAPI.getLatestPatcherReleaseTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> getLatestManagerReleaseTime() async {
|
Future<String?> getLatestManagerReleaseTime() {
|
||||||
return _managerAPI.getLatestManagerReleaseTime();
|
return _managerAPI.getLatestManagerReleaseTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ class PatchesSelectorViewModel extends BaseViewModel {
|
|||||||
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));
|
||||||
selectRecommendedPatches();
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,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)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ class SettingsView extends StatelessWidget {
|
|||||||
delegate: SliverChildListDelegate.fixed(
|
delegate: SliverChildListDelegate.fixed(
|
||||||
<Widget>[
|
<Widget>[
|
||||||
SUpdateThemeUI(),
|
SUpdateThemeUI(),
|
||||||
SUpdateLanguageUI(),
|
// SUpdateLanguageUI(),
|
||||||
_settingsDivider,
|
// _settingsDivider,
|
||||||
STeamSection(),
|
STeamSection(),
|
||||||
_settingsDivider,
|
_settingsDivider,
|
||||||
SAdvancedSection(),
|
SAdvancedSection(),
|
||||||
|
|||||||
127
lib/ui/widgets/homeView/update_confirmation_dialog.dart
Normal file
127
lib/ui/widgets/homeView/update_confirmation_dialog.dart
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_i18n/flutter_i18n.dart';
|
||||||
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
|
import 'package:revanced_manager/app/app.locator.dart';
|
||||||
|
import 'package:revanced_manager/ui/views/home/home_viewmodel.dart';
|
||||||
|
import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart';
|
||||||
|
|
||||||
|
class UpdateConfirmationDialog extends StatelessWidget {
|
||||||
|
const UpdateConfirmationDialog({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final HomeViewModel model = locator<HomeViewModel>();
|
||||||
|
|
||||||
|
return DraggableScrollableSheet(
|
||||||
|
expand: false,
|
||||||
|
initialChildSize: 0.5,
|
||||||
|
snap: true,
|
||||||
|
snapSizes: const [0.5],
|
||||||
|
builder: (context, scrollController) => SingleChildScrollView(
|
||||||
|
controller: scrollController,
|
||||||
|
child: SafeArea(
|
||||||
|
child: FutureBuilder<Map<String, dynamic>?>(
|
||||||
|
future: model.getLatestManagerRelease(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (!snapshot.hasData) {
|
||||||
|
return const SizedBox(
|
||||||
|
height: 300,
|
||||||
|
child: Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 40.0, left: 24.0, right: 24.0, bottom: 32.0),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
I18nText(
|
||||||
|
'homeView.updateDialogTitle',
|
||||||
|
child: const Text(
|
||||||
|
"",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4.0),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.new_releases_outlined,
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8.0),
|
||||||
|
Text(
|
||||||
|
snapshot.data!["tag_name"] ?? "Unknown",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.secondary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
CustomMaterialButton(
|
||||||
|
isExpanded: true,
|
||||||
|
label: I18nText('updateButton'),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
model.updateManager(context);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 24.0, bottom: 12.0),
|
||||||
|
child: I18nText(
|
||||||
|
'homeView.updateChangelogTitle',
|
||||||
|
child: Text(
|
||||||
|
"",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSecondaryContainer),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||||
|
borderRadius: BorderRadius.circular(12.0),
|
||||||
|
),
|
||||||
|
child: Markdown(
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
padding: const EdgeInsets.all(20.0),
|
||||||
|
data: snapshot.data!["body"] ?? "",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ homepage: https://github.com/revanced/revanced-manager
|
|||||||
|
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
|
|
||||||
version: 0.0.42+42
|
version: 0.0.48+48
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.17.5 <3.0.0"
|
sdk: ">=2.17.5 <3.0.0"
|
||||||
@@ -76,6 +76,7 @@ dependencies:
|
|||||||
sentry_dio: ^6.12.2
|
sentry_dio: ^6.12.2
|
||||||
flutter_dotenv: ^5.0.2
|
flutter_dotenv: ^5.0.2
|
||||||
pub_release: ^8.0.3
|
pub_release: ^8.0.3
|
||||||
|
flutter_markdown: ^0.6.13
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
json_serializable: ^6.3.1
|
json_serializable: ^6.3.1
|
||||||
|
|||||||
Reference in New Issue
Block a user