From f905a529887f7e6025cad7392823780bf589a6ce Mon Sep 17 00:00:00 2001 From: aAbed <39409020+TheAabedKhan@users.noreply.github.com> Date: Fri, 4 Aug 2023 02:08:56 +0545 Subject: [PATCH] feat: allow control over patches update (#1063) Co-authored-by: oSumAtrIX --- assets/i18n/en_US.json | 9 ++ lib/main.dart | 2 - lib/services/github_api.dart | 81 ++++++++++--- lib/services/manager_api.dart | 96 ++++++++++----- lib/services/revanced_api.dart | 14 --- .../app_selector/app_selector_viewmodel.dart | 4 +- lib/ui/views/home/home_view.dart | 6 +- lib/ui/views/home/home_viewmodel.dart | 110 +++++++++++++++++- .../patches_selector_viewmodel.dart | 15 +-- .../settings_manage_sources.dart | 4 + lib/ui/views/settings/settings_viewmodel.dart | 9 ++ .../widgets/homeView/latest_commit_card.dart | 20 ++-- .../homeView/update_confirmation_dialog.dart | 15 ++- .../settings_advanced_section.dart | 2 + .../settings_auto_update_patches.dart | 38 ++++++ 15 files changed, 322 insertions(+), 103 deletions(-) create mode 100644 lib/ui/widgets/settingsView/settings_auto_update_patches.dart diff --git a/assets/i18n/en_US.json b/assets/i18n/en_US.json index 9f976a5a..c6df1db0 100644 --- a/assets/i18n/en_US.json +++ b/assets/i18n/en_US.json @@ -1,6 +1,7 @@ { "okButton": "OK", "cancelButton": "Cancel", + "quitButton": "Quit", "updateButton": "Update", "enabledLabel": "Enabled", "disabledLabel": "Disabled", @@ -31,8 +32,14 @@ "installUpdate": "Continue to install the update?", "updateDialogTitle": "Update Manager", + "updatePatchesDialogTitle": "Update ReVanced Patches", "updateChangelogTitle": "Changelog", + "patchesConsentDialogText": "ReVanced Patches need to be downloaded to patch apps.", + "patchesConsentDialogText2": "This will reveal your IP address to {url}.", + "patchesConsentDialogText3": "Auto update", + "patchesConsentDialogText3Sub": "You can still change this in the settings later", + "notificationTitle": "Update downloaded", "notificationText": "Tap to install the update", @@ -171,6 +178,7 @@ "sourcesResetDialogTitle": "Reset", "sourcesResetDialogText": "Are you sure you want to reset custom sources to their default values?", "apiURLResetDialogText": "Are you sure you want to reset API URL to its default value?", + "sourcesUpdateNote": "Note: ReVanced Patches will be updated to the latest version automatically.\n\nThis will reveal your IP address to the server.", "apiURLLabel": "API URL", "apiURLHint": "Configure your custom API URL", @@ -186,6 +194,7 @@ "logsLabel": "Logs", "logsHint": "Share Manager's logs", + "autoUpdatePatchesHint": "Automatically update ReVanced Patches to the latest version", "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", diff --git a/lib/main.dart b/lib/main.dart index d34f9d66..f386c75d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,7 +6,6 @@ import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/services/github_api.dart'; import 'package:revanced_manager/services/manager_api.dart'; -import 'package:revanced_manager/services/patcher_api.dart'; import 'package:revanced_manager/services/revanced_api.dart'; import 'package:revanced_manager/ui/theme/dynamic_theme_builder.dart'; import 'package:revanced_manager/ui/views/navigation/navigation_view.dart'; @@ -24,7 +23,6 @@ Future main() async { await locator().initialize(apiUrl); final String repoUrl = locator().getRepoUrl(); locator().initialize(repoUrl); - await locator().initialize(); tz.initializeTimeZones(); prefs = await SharedPreferences.getInstance(); diff --git a/lib/services/github_api.dart b/lib/services/github_api.dart index 62020328..c846d272 100644 --- a/lib/services/github_api.dart +++ b/lib/services/github_api.dart @@ -72,6 +72,39 @@ class GithubAPI { } } + Future?> getPatchesRelease( + String repoName, + String version, + ) async { + try { + final response = await _dio.get( + '/repos/$repoName/releases/tags/$version', + ); + return response.data; + } on Exception catch (e) { + if (kDebugMode) { + print(e); + } + return null; + } + } + + Future?> getLatestPatchesRelease( + String repoName, + ) async { + try { + final response = await _dio.get( + '/repos/$repoName/releases/latest', + ); + return response.data; + } on Exception catch (e) { + if (kDebugMode) { + print(e); + } + return null; + } + } + Future?> getLatestManagerRelease( String repoName, ) async { @@ -164,10 +197,37 @@ class GithubAPI { return null; } - Future> getPatches(String repoName) async { + Future getPatchesReleaseFile( + String extension, + String repoName, + String version, + ) async { + try { + final Map? release = + await getPatchesRelease(repoName, version); + if (release != null) { + final Map? asset = + (release['assets'] as List).firstWhereOrNull( + (asset) => (asset['name'] as String).endsWith(extension), + ); + if (asset != null) { + return await DefaultCacheManager().getSingleFile( + asset['browser_download_url'], + ); + } + } + } on Exception catch (e) { + if (kDebugMode) { + print(e); + } + } + return null; + } + + Future> getPatches(String repoName, String version) async { List patches = []; try { - final File? f = await getLatestReleaseFile('.json', repoName); + final File? f = await getPatchesReleaseFile('.json', repoName, version); if (f != null) { final List list = jsonDecode(f.readAsStringSync()); patches = list.map((patch) => Patch.fromJson(patch)).toList(); @@ -180,21 +240,4 @@ class GithubAPI { return patches; } - - Future getLastestReleaseVersion(String repoName) async { - try { - final Map? release = await getLatestRelease(repoName); - if (release != null) { - return release['tag_name']; - } else { - return 'Unknown'; - } - } on Exception catch (e) { - if (kDebugMode) { - print(e); - } - - return 'Unknown'; - } - } } diff --git a/lib/services/manager_api.dart b/lib/services/manager_api.dart index 5b71c6b7..0155cf44 100644 --- a/lib/services/manager_api.dart +++ b/lib/services/manager_api.dart @@ -13,6 +13,7 @@ import 'package:revanced_manager/services/revanced_api.dart'; import 'package:revanced_manager/services/root_api.dart'; import 'package:revanced_manager/utils/check_for_supported_patch.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:timeago/timeago.dart'; @lazySingleton class ManagerAPI { @@ -81,6 +82,22 @@ class ManagerAPI { await _prefs.setString('patchesRepo', value); } + bool getPatchesConsent() { + return _prefs.getBool('patchesConsent') ?? false; + } + + Future setPatchesConsent(bool consent) async { + await _prefs.setBool('patchesConsent', consent); + } + + bool isPatchesAutoUpdate() { + return _prefs.getBool('patchesAutoUpdate') ?? false; + } + + Future setPatchesAutoUpdate(bool value) async { + await _prefs.setBool('patchesAutoUpdate', value); + } + String getIntegrationsRepo() { return _prefs.getString('integrationsRepo') ?? defaultIntegrationsRepo; } @@ -205,11 +222,8 @@ class ManagerAPI { Future> getPatches() async { try { final String repoName = getPatchesRepo(); - if (repoName == defaultPatchesRepo) { - return await _revancedAPI.getPatches(); - } else { - return await _githubAPI.getPatches(repoName); - } + final String currentVersion = await getCurrentPatchesVersion(); + return await _githubAPI.getPatches(repoName, currentVersion); } on Exception catch (e) { if (kDebugMode) { print(e); @@ -221,14 +235,12 @@ class ManagerAPI { Future downloadPatches() async { try { final String repoName = getPatchesRepo(); - if (repoName == defaultPatchesRepo) { - return await _revancedAPI.getLatestReleaseFile( - '.jar', - defaultPatchesRepo, - ); - } else { - return await _githubAPI.getLatestReleaseFile('.jar', repoName); - } + final String currentVersion = await getCurrentPatchesVersion(); + return await _githubAPI.getPatchesReleaseFile( + '.jar', + repoName, + currentVersion, + ); } on Exception catch (e) { if (kDebugMode) { print(e); @@ -263,11 +275,23 @@ class ManagerAPI { ); } - Future getLatestPatcherReleaseTime() async { - return await _revancedAPI.getLatestReleaseTime( - '.gz', - defaultPatcherRepo, - ); + Future getLatestPatchesReleaseTime() async { + if (isDefaultPatchesRepo()) { + return await _revancedAPI.getLatestReleaseTime( + '.json', + defaultPatchesRepo, + ); + } else { + final release = + await _githubAPI.getLatestPatchesRelease(getPatchesRepo()); + if (release != null) { + final DateTime timestamp = + DateTime.parse(release['created_at'] as String); + return format(timestamp, locale: 'en_short'); + } else { + return null; + } + } } Future getLatestManagerReleaseTime() async { @@ -285,10 +309,19 @@ class ManagerAPI { } Future getLatestPatchesVersion() async { - return await _revancedAPI.getLatestReleaseVersion( - '.json', - defaultPatchesRepo, - ); + if (isDefaultPatchesRepo()) { + return await _revancedAPI.getLatestReleaseVersion( + '.json', + defaultPatchesRepo, + ); + } else { + final release = await _githubAPI.getLatestPatchesRelease(getPatchesRepo()); + if (release != null) { + return release['tag_name']; + } else { + return null; + } + } } Future getCurrentManagerVersion() async { @@ -296,16 +329,17 @@ class ManagerAPI { return packageInfo.version; } - Future getCurrentPatchesVersion() async { - if (isDefaultPatchesRepo()) { - patchesVersion = await getLatestPatchesVersion(); - // print('Patches version: $patchesVersion'); - } else { - // fetch from github - patchesVersion = - await _githubAPI.getLastestReleaseVersion(getPatchesRepo()); + Future getCurrentPatchesVersion() async { + patchesVersion = _prefs.getString('patchesVersion') ?? '0.0.0'; + if (patchesVersion == '0.0.0' || isPatchesAutoUpdate()) { + patchesVersion = await getLatestPatchesVersion() ?? '0.0.0'; + await setCurrentPatchesVersion(patchesVersion!); } - return patchesVersion ?? '0.0.0'; + return patchesVersion!; + } + + Future setCurrentPatchesVersion(String version) async { + await _prefs.setString('patchesVersion', version); } Future> getAppsToRemove( diff --git a/lib/services/revanced_api.dart b/lib/services/revanced_api.dart index bc3562ba..dde23cee 100644 --- a/lib/services/revanced_api.dart +++ b/lib/services/revanced_api.dart @@ -7,7 +7,6 @@ import 'package:dio_cache_interceptor/dio_cache_interceptor.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:injectable/injectable.dart'; -import 'package:revanced_manager/models/patch.dart'; import 'package:timeago/timeago.dart'; @lazySingleton @@ -64,19 +63,6 @@ class RevancedAPI { return contributors; } - Future> getPatches() async { - try { - final response = await _dio.get('/patches'); - final List patches = response.data; - return patches.map((patch) => Patch.fromJson(patch)).toList(); - } on Exception catch (e) { - if (kDebugMode) { - print(e); - } - return List.empty(); - } - } - Future?> _getLatestRelease( String extension, String repoName, diff --git a/lib/ui/views/app_selector/app_selector_viewmodel.dart b/lib/ui/views/app_selector/app_selector_viewmodel.dart index e0784abd..9075b2a3 100644 --- a/lib/ui/views/app_selector/app_selector_viewmodel.dart +++ b/lib/ui/views/app_selector/app_selector_viewmodel.dart @@ -10,7 +10,6 @@ import 'package:revanced_manager/models/patch.dart'; import 'package:revanced_manager/models/patched_application.dart'; import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/services/patcher_api.dart'; -import 'package:revanced_manager/services/revanced_api.dart'; import 'package:revanced_manager/services/toast.dart'; import 'package:revanced_manager/ui/views/patcher/patcher_viewmodel.dart'; import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; @@ -19,7 +18,6 @@ import 'package:stacked/stacked.dart'; class AppSelectorViewModel extends BaseViewModel { final PatcherAPI _patcherAPI = locator(); final ManagerAPI _managerAPI = locator(); - final RevancedAPI _revancedAPI = locator(); final Toast _toast = locator(); final List apps = []; List allApps = []; @@ -32,7 +30,7 @@ class AppSelectorViewModel extends BaseViewModel { List patches = []; Future initialize() async { - patches = await _revancedAPI.getPatches(); + patches = await _managerAPI.getPatches(); isRooted = _managerAPI.isRooted; apps.addAll( diff --git a/lib/ui/views/home/home_view.dart b/lib/ui/views/home/home_view.dart index 07ff7dad..52abfb0c 100644 --- a/lib/ui/views/home/home_view.dart +++ b/lib/ui/views/home/home_view.dart @@ -50,11 +50,7 @@ class HomeView extends StatelessWidget { ), ), const SizedBox(height: 10), - LatestCommitCard( - onPressedManager: () => - model.showUpdateConfirmationDialog(context), - onPressedPatches: () => model.forceRefresh(context), - ), + LatestCommitCard(model: model, parentContext: context), const SizedBox(height: 23), I18nText( 'homeView.patchedSubtitle', diff --git a/lib/ui/views/home/home_viewmodel.dart b/lib/ui/views/home/home_viewmodel.dart index f67125ab..3abe3c3b 100644 --- a/lib/ui/views/home/home_viewmodel.dart +++ b/lib/ui/views/home/home_viewmodel.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:cross_connectivity/cross_connectivity.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:injectable/injectable.dart'; @@ -42,6 +43,10 @@ class HomeViewModel extends BaseViewModel { Future initialize(BuildContext context) async { _latestManagerVersion = await _managerAPI.getLatestManagerVersion(); + if(!_managerAPI.getPatchesConsent()){ + await showPatchesConsent(context); + } + await _patcherAPI.initialize(); await flutterLocalNotificationsPlugin.initialize( const InitializationSettings( android: AndroidInitializationSettings('ic_notification'), @@ -129,13 +134,13 @@ class HomeViewModel extends BaseViewModel { Future hasPatchesUpdates() async { final String? latestVersion = await _managerAPI.getLatestPatchesVersion(); - final String? currentVersion = await _managerAPI.getCurrentPatchesVersion(); + final String currentVersion = await _managerAPI.getCurrentPatchesVersion(); if (latestVersion != null) { try { final int latestVersionInt = int.parse(latestVersion.replaceAll(RegExp('[^0-9]'), '')); final int currentVersionInt = - int.parse(currentVersion!.replaceAll(RegExp('[^0-9]'), '')); + int.parse(currentVersion.replaceAll(RegExp('[^0-9]'), '')); return latestVersionInt > currentVersionInt; } on Exception catch (e) { if (kDebugMode) { @@ -163,6 +168,94 @@ class HomeViewModel extends BaseViewModel { } } + Future showPatchesConsent(BuildContext context) async{ + final ValueNotifier autoUpdate = ValueNotifier(true); + await showDialog( + context: context, + barrierDismissible: false, + builder: (context) => AlertDialog( + title: const Text('ReVanced Patches'), + content: ValueListenableBuilder( + valueListenable: autoUpdate, + builder: (context, value, child) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + I18nText( + 'homeView.patchesConsentDialogText', + child: Text( + '', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Theme.of(context).colorScheme.secondary, + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: I18nText( + 'homeView.patchesConsentDialogText2', + translationParams: {'url': _managerAPI.defaultApiUrl.split('/')[2]}, + child: Text( + '', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Theme.of(context).colorScheme.error, + ), + ), + ), + ), + CheckboxListTile( + value: value, + contentPadding: EdgeInsets.zero, + title: I18nText('homeView.patchesConsentDialogText3',), + subtitle: I18nText('homeView.patchesConsentDialogText3Sub',), + onChanged: (selected) { + autoUpdate.value = selected!; + }, + ), + ], + ); + }, + ), + actions: [ + CustomMaterialButton( + isFilled: false, + onPressed: () async { + await _managerAPI.setPatchesConsent(false); + SystemNavigator.pop(); + }, + label: I18nText('quitButton'), + ), + CustomMaterialButton( + onPressed: () async { + await _managerAPI.setPatchesConsent(true); + await _managerAPI.setPatchesAutoUpdate(autoUpdate.value); + Navigator.of(context).pop(); + }, + label: I18nText('okButton'), + ) + ], + ), + ); + } + + Future updatePatches(BuildContext context) async { + _toast.showBottom('homeView.downloadingMessage'); + final String patchesVersion = + await _managerAPI.getLatestPatchesVersion() ?? '0.0.0'; + if (patchesVersion != '0.0.0') { + _toast.showBottom('homeView.downloadedMessage'); + await _managerAPI.setCurrentPatchesVersion(patchesVersion); + forceRefresh(context); + } else { + _toast.showBottom('homeView.errorDownloadMessage'); + } + } + Future updateManager(BuildContext context) async { final ValueNotifier downloaded = ValueNotifier(false); try { @@ -336,6 +429,7 @@ class HomeViewModel extends BaseViewModel { Future showUpdateConfirmationDialog( BuildContext parentContext, + bool isPatches, ) { return showModalBottomSheet( context: parentContext, @@ -343,7 +437,9 @@ class HomeViewModel extends BaseViewModel { shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(24.0)), ), - builder: (context) => const UpdateConfirmationDialog(), + builder: (context) => UpdateConfirmationDialog( + isPatches: isPatches, + ), ); } @@ -351,8 +447,12 @@ class HomeViewModel extends BaseViewModel { return _githubAPI.getLatestManagerRelease(_managerAPI.defaultManagerRepo); } - Future getLatestPatcherReleaseTime() { - return _managerAPI.getLatestPatcherReleaseTime(); + Future?> getLatestPatchesRelease() { + return _githubAPI.getLatestPatchesRelease(_managerAPI.defaultPatchesRepo); + } + + Future getLatestPatchesReleaseTime() { + return _managerAPI.getLatestPatchesReleaseTime(); } Future getLatestManagerReleaseTime() { diff --git a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart index 61cd9b81..ca776ccf 100644 --- a/lib/ui/views/patches_selector/patches_selector_viewmodel.dart +++ b/lib/ui/views/patches_selector/patches_selector_viewmodel.dart @@ -2,7 +2,6 @@ import 'package:collection/collection.dart'; import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/models/patch.dart'; import 'package:revanced_manager/models/patched_application.dart'; -import 'package:revanced_manager/services/github_api.dart'; import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/services/patcher_api.dart'; import 'package:revanced_manager/services/toast.dart'; @@ -13,7 +12,6 @@ import 'package:stacked/stacked.dart'; class PatchesSelectorViewModel extends BaseViewModel { final PatcherAPI _patcherAPI = locator(); final ManagerAPI _managerAPI = locator(); - final GithubAPI _githubAPI = locator(); final List patches = []; final List selectedPatches = locator().selectedPatches; @@ -78,17 +76,8 @@ class PatchesSelectorViewModel extends BaseViewModel { locator().notifyListeners(); } - Future getPatchesVersion() async { - if (isDefaultPatchesRepo()) { - patchesVersion = await _managerAPI.getLatestPatchesVersion(); - // print('Patches version: $patchesVersion'); - return patchesVersion ?? '0.0.0'; - } else { - // fetch from github - patchesVersion = await _githubAPI - .getLastestReleaseVersion(_managerAPI.getPatchesRepo()); - } - return null; + Future getPatchesVersion() async { + patchesVersion = await _managerAPI.getCurrentPatchesVersion(); } List getQueriedPatches(String query) { diff --git a/lib/ui/views/settings/settingsFragment/settings_manage_sources.dart b/lib/ui/views/settings/settingsFragment/settings_manage_sources.dart index cefde1b5..66572e01 100644 --- a/lib/ui/views/settings/settingsFragment/settings_manage_sources.dart +++ b/lib/ui/views/settings/settingsFragment/settings_manage_sources.dart @@ -101,6 +101,8 @@ class SManageSources extends BaseViewModel { hint: integrationsRepo.split('/')[1], onChanged: (value) => notifyListeners(), ), + const SizedBox(height: 20), + I18nText('settingsView.sourcesUpdateNote') ], ), ), @@ -126,6 +128,7 @@ class SManageSources extends BaseViewModel { _managerAPI.setIntegrationsRepo( '${_orgIntSourceController.text.trim()}/${_intSourceController.text.trim()}', ); + _managerAPI.setCurrentPatchesVersion('0.0.0'); _toast.showBottom('settingsView.restartAppForChanges'); Navigator.of(context).pop(); }, @@ -154,6 +157,7 @@ class SManageSources extends BaseViewModel { _managerAPI.setRepoUrl(''); _managerAPI.setPatchesRepo(''); _managerAPI.setIntegrationsRepo(''); + _managerAPI.setCurrentPatchesVersion('0.0.0'); _toast.showBottom('settingsView.restartAppForChanges'); Navigator.of(context) ..pop() diff --git a/lib/ui/views/settings/settings_viewmodel.dart b/lib/ui/views/settings/settings_viewmodel.dart index 447e965f..483834b8 100644 --- a/lib/ui/views/settings/settings_viewmodel.dart +++ b/lib/ui/views/settings/settings_viewmodel.dart @@ -28,6 +28,15 @@ class SettingsViewModel extends BaseViewModel { _navigationService.navigateTo(Routes.contributorsView); } + bool isPatchesAutoUpdate() { + return _managerAPI.isPatchesAutoUpdate(); + } + + void setPatchesAutoUpdate(bool value) { + _managerAPI.setPatchesAutoUpdate(value); + notifyListeners(); + } + bool areUniversalPatchesEnabled() { return _managerAPI.areUniversalPatchesEnabled(); } diff --git a/lib/ui/widgets/homeView/latest_commit_card.dart b/lib/ui/widgets/homeView/latest_commit_card.dart index e56b241f..0f9870f7 100644 --- a/lib/ui/widgets/homeView/latest_commit_card.dart +++ b/lib/ui/widgets/homeView/latest_commit_card.dart @@ -8,11 +8,11 @@ import 'package:revanced_manager/ui/widgets/shared/custom_material_button.dart'; class LatestCommitCard extends StatefulWidget { const LatestCommitCard({ Key? key, - required this.onPressedManager, - required this.onPressedPatches, + required this.model, + required this.parentContext, }) : super(key: key); - final Function() onPressedManager; - final Function() onPressedPatches; + final HomeViewModel model; + final BuildContext parentContext; @override State createState() => _LatestCommitCardState(); @@ -63,7 +63,10 @@ class _LatestCommitCardState extends State { child: CustomMaterialButton( label: I18nText('updateButton'), onPressed: snapshot.hasData && snapshot.data! - ? widget.onPressedManager + ? () => widget.model.showUpdateConfirmationDialog( + widget.parentContext, + false, + ) : () => {}, ), ), @@ -91,7 +94,7 @@ class _LatestCommitCardState extends State { Row( children: [ FutureBuilder( - future: model.getLatestPatcherReleaseTime(), + future: model.getLatestPatchesReleaseTime(), builder: (context, snapshot) => Text( snapshot.hasData && snapshot.data!.isNotEmpty ? FlutterI18n.translate( @@ -117,7 +120,10 @@ class _LatestCommitCardState extends State { child: CustomMaterialButton( label: I18nText('updateButton'), onPressed: snapshot.hasData && snapshot.data! - ? widget.onPressedPatches + ? () => widget.model.showUpdateConfirmationDialog( + widget.parentContext, + true, + ) : () => {}, ), ), diff --git a/lib/ui/widgets/homeView/update_confirmation_dialog.dart b/lib/ui/widgets/homeView/update_confirmation_dialog.dart index 16a1f1be..4d3b877e 100644 --- a/lib/ui/widgets/homeView/update_confirmation_dialog.dart +++ b/lib/ui/widgets/homeView/update_confirmation_dialog.dart @@ -6,8 +6,9 @@ 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); + const UpdateConfirmationDialog({super.key, required this.isPatches}); + final bool isPatches; @override Widget build(BuildContext context) { final HomeViewModel model = locator(); @@ -20,7 +21,9 @@ class UpdateConfirmationDialog extends StatelessWidget { controller: scrollController, child: SafeArea( child: FutureBuilder?>( - future: model.getLatestManagerRelease(), + future: !isPatches + ? model.getLatestManagerRelease() + : model.getLatestPatchesRelease(), builder: (_, snapshot) { if (!snapshot.hasData) { return const SizedBox( @@ -48,7 +51,9 @@ class UpdateConfirmationDialog extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ I18nText( - 'homeView.updateDialogTitle', + isPatches + ? 'homeView.updatePatchesDialogTitle' + : 'homeView.updateDialogTitle', child: const Text( '', style: TextStyle( @@ -86,7 +91,9 @@ class UpdateConfirmationDialog extends StatelessWidget { label: I18nText('updateButton'), onPressed: () { Navigator.of(context).pop(); - model.updateManager(context); + isPatches + ? model.updatePatches(context) + : model.updateManager(context); }, ) ], diff --git a/lib/ui/widgets/settingsView/settings_advanced_section.dart b/lib/ui/widgets/settingsView/settings_advanced_section.dart index 89763567..2cf1c3d7 100644 --- a/lib/ui/widgets/settingsView/settings_advanced_section.dart +++ b/lib/ui/widgets/settingsView/settings_advanced_section.dart @@ -5,6 +5,7 @@ import 'package:flutter_i18n/widgets/I18nText.dart'; import 'package:revanced_manager/ui/views/settings/settingsFragment/settings_manage_api_url.dart'; import 'package:revanced_manager/ui/views/settings/settingsFragment/settings_manage_sources.dart'; import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart'; +import 'package:revanced_manager/ui/widgets/settingsView/settings_auto_update_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'; @@ -23,6 +24,7 @@ class SAdvancedSection extends StatelessWidget { SManageApiUrlUI(), SManageSourcesUI(), // SManageKeystorePasswordUI(), + SAutoUpdatePatches(), SExperimentalUniversalPatches(), SExperimentalPatches(), ListTile( diff --git a/lib/ui/widgets/settingsView/settings_auto_update_patches.dart b/lib/ui/widgets/settingsView/settings_auto_update_patches.dart new file mode 100644 index 00000000..438882c8 --- /dev/null +++ b/lib/ui/widgets/settingsView/settings_auto_update_patches.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_i18n/widgets/I18nText.dart'; +import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart'; + +class SAutoUpdatePatches extends StatefulWidget { + const SAutoUpdatePatches({super.key}); + + @override + State createState() => _SAutoUpdatePatchesState(); +} + +final _settingsViewModel = SettingsViewModel(); + +class _SAutoUpdatePatchesState extends State { + @override + Widget build(BuildContext context) { + return SwitchListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 20.0), + title: I18nText( + 'homeView.patchesConsentDialogText3', + child: const Text( + '', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w500, + ), + ), + ), + subtitle: I18nText('settingsView.autoUpdatePatchesHint'), + value: _settingsViewModel.isPatchesAutoUpdate(), + onChanged: (value) { + setState(() { + _settingsViewModel.setPatchesAutoUpdate(value); + }); + }, + ); + } +}