feat: Show a dialog when an update is available (#1654)

This commit is contained in:
aAbed 2024-01-25 23:05:34 +05:45 committed by aAbed
parent 7104d6d6dd
commit c7d975e612
No known key found for this signature in database
GPG Key ID: F26611AB3F996827
10 changed files with 302 additions and 190 deletions

View File

@ -16,6 +16,8 @@
"noShowAgain": "Don't show this again", "noShowAgain": "Don't show this again",
"add": "Add", "add": "Add",
"remove": "Remove", "remove": "Remove",
"showChangelogButton": "Show changelog",
"showUpdateButton": "Show update",
"navigationView": { "navigationView": {
"dashboardTab": "Dashboard", "dashboardTab": "Dashboard",
"patcherTab": "Patcher", "patcherTab": "Patcher",
@ -27,6 +29,7 @@
"updatesSubtitle": "Updates", "updatesSubtitle": "Updates",
"patchedSubtitle": "Patched apps", "patchedSubtitle": "Patched apps",
"changeLaterSubtitle": "You can change this in the settings at a later time.",
"noUpdates": "No updates available", "noUpdates": "No updates available",
@ -35,20 +38,25 @@
"noInstallations": "No patched apps installed", "noInstallations": "No patched apps installed",
"installUpdate": "Continue to install the update?", "installUpdate": "Continue to install the update?",
"updateDialogTitle": "Update Manager", "updateSheetTitle": "Update ReVanced Manager",
"updatePatchesDialogTitle": "Update ReVanced Patches", "updateDialogTitle": "New update available",
"updatePatchesSheetTitle": "Update ReVanced Patches",
"updateChangelogTitle": "Changelog", "updateChangelogTitle": "Changelog",
"patchesConsentDialogText": "ReVanced Patches needs to be downloaded.", "updateDialogText": "A new update is available for {file}.\n\nThe currently installed version is {version}.",
"patchesConsentDialogText2": "This will connect you to {url}.",
"patchesConsentDialogText3": "Auto update?", "downloadConsentDialogTitle": "Download necessary files?",
"patchesConsentDialogText3Sub": "You can change this in settings at a later time.", "downloadConsentDialogText": "ReVanced Manager needs to download necessary files to work properly.",
"downloadConsentDialogText2": "This will connect you to {url}.",
"checkUpdateDialogTitle": "Check for updates?",
"checkUpdateDialogText": "Do you want ReVanced Manager to check for updates automatically?",
"notificationTitle": "Update downloaded", "notificationTitle": "Update downloaded",
"notificationText": "Tap to install the update", "notificationText": "Tap to install the update",
"downloadingMessage": "Downloading update...", "downloadingMessage": "Downloading update...",
"downloadedMessage": "Update downloaded!", "downloadedMessage": "Update downloaded",
"installingMessage": "Installing update...", "installingMessage": "Installing update...",
@ -157,7 +165,7 @@
"unsupportedPatchVersion": "Patch is not supported for this app version.", "unsupportedPatchVersion": "Patch is not supported for this app version.",
"unsupportedRequiredOption": "This patch contains a required option that is not supported by this app", "unsupportedRequiredOption": "This patch contains a required option that is not supported by this app",
"patchesChangeWarningDialogText": "It is recommended to use the default patch selection and options. Changing them may result in unexpected issues.\n\nYou'll need to turn on \"Allow changing patch selection\" in settings before changing any patch selection.", "patchesChangeWarningDialogText": "It is recommended to use the default patch selection and options. Changing them may result in unexpected issues.\n\nYou'll need to turn on \"Allow changing patch selection\" in the settings before changing any patch selection.",
"patchesChangeWarningDialogButton": "Use default selection" "patchesChangeWarningDialogButton": "Use default selection"
}, },
"installerView": { "installerView": {
@ -235,6 +243,8 @@
"autoUpdatePatchesLabel": "Auto update patches", "autoUpdatePatchesLabel": "Auto update patches",
"autoUpdatePatchesHint": "Automatically update patches to the latest version", "autoUpdatePatchesHint": "Automatically update patches to the latest version",
"showUpdateDialogLabel": "Show update dialog",
"showUpdateDialogHint": "Show a dialog when a new update is available",
"universalPatchesLabel": "Show universal patches", "universalPatchesLabel": "Show universal patches",
"universalPatchesHint": "Display all apps and universal patches (may slow down the app list)", "universalPatchesHint": "Display all apps and universal patches (may slow down the app list)",

View File

@ -81,7 +81,7 @@ class GithubAPI {
int updates = 0; int updates = 0;
final String currentVersion = final String currentVersion =
await _managerAPI.getCurrentManagerVersion(); await _managerAPI.getCurrentManagerVersion();
while (response.data[updates]['tag_name'] != 'v$currentVersion') { while (response.data[updates]['tag_name'] != currentVersion) {
updates++; updates++;
} }
for (int i = 1; i < updates; i++) { for (int i = 1; i < updates; i++) {

View File

@ -128,12 +128,12 @@ class ManagerAPI {
await _prefs.setString('patchesRepo', value); await _prefs.setString('patchesRepo', value);
} }
bool getPatchesConsent() { bool getDownloadConsent() {
return _prefs.getBool('patchesConsent') ?? false; return _prefs.getBool('downloadConsent') ?? false;
} }
Future<void> setPatchesConsent(bool consent) async { void setDownloadConsent(bool consent) {
await _prefs.setBool('patchesConsent', consent); _prefs.setBool('downloadConsent', consent);
} }
bool isPatchesAutoUpdate() { bool isPatchesAutoUpdate() {
@ -156,6 +156,14 @@ class ManagerAPI {
_prefs.setBool('showPatchesChangeWarning', !value); _prefs.setBool('showPatchesChangeWarning', !value);
} }
bool showUpdateDialog() {
return _prefs.getBool('showUpdateDialog') ?? true;
}
void setShowUpdateDialog(bool value) {
_prefs.setBool('showUpdateDialog', value);
}
bool isChangingToggleModified() { bool isChangingToggleModified() {
return _prefs.getBool('isChangingToggleModified') ?? false; return _prefs.getBool('isChangingToggleModified') ?? false;
} }
@ -164,8 +172,8 @@ class ManagerAPI {
_prefs.setBool('isChangingToggleModified', value); _prefs.setBool('isChangingToggleModified', value);
} }
Future<void> setPatchesAutoUpdate(bool value) async { void setPatchesAutoUpdate(bool value) {
await _prefs.setBool('patchesAutoUpdate', value); _prefs.setBool('patchesAutoUpdate', value);
} }
List<Patch> getSavedPatches(String packageName) { List<Patch> getSavedPatches(String packageName) {
@ -508,7 +516,11 @@ class ManagerAPI {
Future<String> getCurrentManagerVersion() async { Future<String> getCurrentManagerVersion() async {
final PackageInfo packageInfo = await PackageInfo.fromPlatform(); final PackageInfo packageInfo = await PackageInfo.fromPlatform();
return packageInfo.version; String version = packageInfo.version;
if (!version.startsWith('v')) {
version = 'v$version';
}
return version;
} }
Future<String> getCurrentPatchesVersion() async { Future<String> getCurrentPatchesVersion() async {

View File

@ -8,6 +8,7 @@ import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:injectable/injectable.dart'; import 'package:injectable/injectable.dart';
import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/services/download_manager.dart'; import 'package:revanced_manager/services/download_manager.dart';
import 'package:revanced_manager/services/manager_api.dart';
import 'package:synchronized/synchronized.dart'; import 'package:synchronized/synchronized.dart';
import 'package:timeago/timeago.dart'; import 'package:timeago/timeago.dart';
@ -48,6 +49,9 @@ class RevancedAPI {
String extension, String extension,
String repoName, String repoName,
) { ) {
if (!locator<ManagerAPI>().getDownloadConsent()) {
return Future(() => null);
}
return getToolsLock.synchronized(() async { return getToolsLock.synchronized(() async {
try { try {
final response = await _dio.get('/tools'); final response = await _dio.get('/tools');

View File

@ -19,7 +19,7 @@ import 'package:revanced_manager/services/revanced_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/homeView/update_confirmation_dialog.dart'; import 'package:revanced_manager/ui/widgets/homeView/update_confirmation_sheet.dart';
import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_checkbox_list_tile.dart'; import 'package:revanced_manager/ui/widgets/shared/haptics/haptic_checkbox_list_tile.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';
@ -35,15 +35,28 @@ class HomeViewModel extends BaseViewModel {
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
bool showUpdatableApps = false; bool showUpdatableApps = false;
List<PatchedApplication> patchedInstalledApps = []; List<PatchedApplication> patchedInstalledApps = [];
String _currentManagerVersion = '';
String _currentPatchesVersion = '';
String? _latestManagerVersion = ''; String? _latestManagerVersion = '';
File? downloadedApk; File? downloadedApk;
Future<void> initialize(BuildContext context) async { Future<void> initialize(BuildContext context) async {
_managerAPI.rePatchedSavedApps().then((_) => _getPatchedApps()); _managerAPI.rePatchedSavedApps().then((_) => _getPatchedApps());
_currentManagerVersion = await _managerAPI.getCurrentManagerVersion();
if (!_managerAPI.getDownloadConsent()) {
await showDownloadConsent(context);
await forceRefresh(context);
return;
}
_latestManagerVersion = await _managerAPI.getLatestManagerVersion(); _latestManagerVersion = await _managerAPI.getLatestManagerVersion();
if (!_managerAPI.getPatchesConsent()) { _currentPatchesVersion = await _managerAPI.getCurrentPatchesVersion();
await showPatchesConsent(context); if (_managerAPI.showUpdateDialog() && await hasManagerUpdates()) {
showUpdateDialog(context, false);
}
if (!_managerAPI.isPatchesAutoUpdate() &&
_managerAPI.showUpdateDialog() &&
await hasPatchesUpdates()) {
showUpdateDialog(context, true);
} }
await _patcherAPI.initialize(); await _patcherAPI.initialize();
@ -114,17 +127,10 @@ class HomeViewModel extends BaseViewModel {
} }
Future<bool> hasManagerUpdates() async { Future<bool> hasManagerUpdates() async {
String currentVersion = await _managerAPI.getCurrentManagerVersion();
// add v to current version
if (!currentVersion.startsWith('v')) {
currentVersion = 'v$currentVersion';
}
_latestManagerVersion = _latestManagerVersion =
await _managerAPI.getLatestManagerVersion() ?? currentVersion; await _managerAPI.getLatestManagerVersion() ?? _currentManagerVersion;
if (_latestManagerVersion != currentVersion) { if (_latestManagerVersion != _currentManagerVersion) {
return true; return true;
} }
return false; return false;
@ -132,13 +138,12 @@ class HomeViewModel extends BaseViewModel {
Future<bool> hasPatchesUpdates() async { Future<bool> hasPatchesUpdates() async {
final String? latestVersion = await _managerAPI.getLatestPatchesVersion(); final String? latestVersion = await _managerAPI.getLatestPatchesVersion();
final String currentVersion = await _managerAPI.getCurrentPatchesVersion();
if (latestVersion != null) { if (latestVersion != null) {
try { try {
final int latestVersionInt = final int latestVersionInt =
int.parse(latestVersion.replaceAll(RegExp('[^0-9]'), '')); int.parse(latestVersion.replaceAll(RegExp('[^0-9]'), ''));
final int currentVersionInt = final int currentVersionInt =
int.parse(currentVersion.replaceAll(RegExp('[^0-9]'), '')); int.parse(_currentPatchesVersion.replaceAll(RegExp('[^0-9]'), ''));
return latestVersionInt > currentVersionInt; return latestVersionInt > currentVersionInt;
} on Exception catch (e) { } on Exception catch (e) {
if (kDebugMode) { if (kDebugMode) {
@ -166,22 +171,98 @@ class HomeViewModel extends BaseViewModel {
} }
} }
Future<void> showPatchesConsent(BuildContext context) async { Future<void> showDownloadConsent(BuildContext context) async {
final ValueNotifier<bool> autoUpdate = ValueNotifier(true); final ValueNotifier<bool> autoUpdate = ValueNotifier(true);
await showDialog( await showDialog(
context: context, context: context,
barrierDismissible: false, barrierDismissible: false,
builder: (context) => AlertDialog( builder: (context) => PopScope(
title: const Text('Download ReVanced Patches?'), canPop: false,
child: AlertDialog(
title: I18nText('homeView.downloadConsentDialogTitle'),
content: ValueListenableBuilder(
valueListenable: autoUpdate,
builder: (context, value, child) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
I18nText(
'homeView.downloadConsentDialogText',
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.downloadConsentDialogText2',
translationParams: {
'url': _managerAPI.defaultApiUrl.split('/')[2],
},
child: Text(
'',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.error,
),
),
),
),
],
);
},
),
actions: [
TextButton(
onPressed: () async {
_managerAPI.setDownloadConsent(false);
SystemNavigator.pop();
},
child: I18nText('quitButton'),
),
FilledButton(
onPressed: () async {
_managerAPI.setDownloadConsent(true);
_managerAPI.setPatchesAutoUpdate(autoUpdate.value);
Navigator.of(context).pop();
},
child: I18nText('okButton'),
),
],
),
),
);
}
void showUpdateDialog(BuildContext context, bool isPatches) {
final ValueNotifier<bool> noShow =
ValueNotifier(!_managerAPI.showUpdateDialog());
showDialog(
context: context,
builder: (innerContext) => AlertDialog(
title: I18nText('homeView.updateDialogTitle'),
content: ValueListenableBuilder( content: ValueListenableBuilder(
valueListenable: autoUpdate, valueListenable: noShow,
builder: (context, value, child) { builder: (context, value, child) {
return Column( return Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
I18nText( I18nText(
'homeView.patchesConsentDialogText', 'homeView.updateDialogText',
translationParams: {
'file': isPatches ? 'ReVanced Patches' : 'ReVanced Manager',
'version': isPatches
? _currentPatchesVersion
: _currentManagerVersion,
},
child: Text( child: Text(
'', '',
style: TextStyle( style: TextStyle(
@ -191,34 +272,18 @@ class HomeViewModel extends BaseViewModel {
), ),
), ),
), ),
Padding( const SizedBox(height: 10),
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,
),
),
),
),
HapticCheckboxListTile( HapticCheckboxListTile(
value: value, value: value,
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
title: I18nText( title: I18nText(
'homeView.patchesConsentDialogText3', 'noShowAgain',
), ),
subtitle: I18nText( subtitle: I18nText(
'homeView.patchesConsentDialogText3Sub', 'homeView.changeLaterSubtitle',
), ),
onChanged: (selected) { onChanged: (selected) {
autoUpdate.value = selected!; noShow.value = selected!;
}, },
), ),
], ],
@ -228,18 +293,18 @@ class HomeViewModel extends BaseViewModel {
actions: [ actions: [
TextButton( TextButton(
onPressed: () async { onPressed: () async {
await _managerAPI.setPatchesConsent(false); _managerAPI.setShowUpdateDialog(!noShow.value);
SystemNavigator.pop(); Navigator.pop(innerContext);
}, },
child: I18nText('quitButton'), child: I18nText('dismissButton'), // Decide later
), ),
FilledButton( FilledButton(
onPressed: () async { onPressed: () async {
await _managerAPI.setPatchesConsent(true); _managerAPI.setShowUpdateDialog(!noShow.value);
await _managerAPI.setPatchesAutoUpdate(autoUpdate.value); Navigator.pop(innerContext);
Navigator.of(context).pop(); await showUpdateConfirmationDialog(context, isPatches);
}, },
child: I18nText('okButton'), child: I18nText('showUpdateButton'),
), ),
], ],
), ),
@ -271,120 +336,91 @@ class HomeViewModel extends BaseViewModel {
builder: (context) => ValueListenableBuilder( builder: (context) => ValueListenableBuilder(
valueListenable: downloaded, valueListenable: downloaded,
builder: (context, value, child) { builder: (context, value, child) {
return SimpleDialog( return AlertDialog(
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
contentPadding: const EdgeInsets.all(16.0),
title: I18nText( title: I18nText(
!value !value
? 'homeView.downloadingMessage' ? 'homeView.downloadingMessage'
: 'homeView.downloadedMessage', : 'homeView.downloadedMessage',
child: Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.secondary,
),
),
), ),
children: [ content: Column(
Column( mainAxisSize: MainAxisSize.min,
children: [ children: [
Row( if (!value)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Icon( StreamBuilder<double>(
Icons.new_releases_outlined, initialData: 0.0,
color: Theme.of(context).colorScheme.secondary, stream: _revancedAPI.managerUpdateProgress.stream,
builder: (context, snapshot) {
return LinearProgressIndicator(
value: snapshot.data! * 0.01,
valueColor: AlwaysStoppedAnimation<Color>(
Theme.of(context).colorScheme.secondary,
),
);
},
), ),
const SizedBox(width: 8.0), const SizedBox(height: 16.0),
Text( Align(
'$_latestManagerVersion', alignment: Alignment.centerRight,
style: TextStyle( child: FilledButton(
fontSize: 18, onPressed: () {
fontWeight: FontWeight.w500, _revancedAPI.disposeManagerUpdateProgress();
color: Theme.of(context).colorScheme.secondary, Navigator.of(context).pop();
},
child: I18nText('cancelButton'),
), ),
), ),
], ],
), ),
const SizedBox(height: 16.0), if (value)
if (!value) Column(
Column( crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ I18nText(
StreamBuilder<double>( 'homeView.installUpdate',
initialData: 0.0, child: Text(
stream: _revancedAPI.managerUpdateProgress.stream, '',
builder: (context, snapshot) { style: TextStyle(
return LinearProgressIndicator( fontSize: 16,
value: snapshot.data! * 0.01, fontWeight: FontWeight.w500,
valueColor: AlwaysStoppedAnimation<Color>( color: Theme.of(context).colorScheme.secondary,
Theme.of(context).colorScheme.secondary,
),
);
},
),
const SizedBox(height: 16.0),
Align(
alignment: Alignment.centerRight,
child: FilledButton(
onPressed: () {
_revancedAPI.disposeManagerUpdateProgress();
Navigator.of(context).pop();
},
child: I18nText('cancelButton'),
), ),
), ),
], ),
), const SizedBox(height: 16.0),
if (value) Row(
Column( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ Align(
I18nText( alignment: Alignment.centerRight,
'homeView.installUpdate', child: TextButton(
child: Text( onPressed: () {
'', Navigator.of(context).pop();
style: TextStyle( },
fontSize: 20, child: I18nText('cancelButton'),
fontWeight: FontWeight.w500,
color: Theme.of(context).colorScheme.secondary,
), ),
), ),
), const SizedBox(width: 8.0),
const SizedBox(height: 16.0), Align(
Row( alignment: Alignment.centerRight,
mainAxisAlignment: MainAxisAlignment.end, child: FilledButton(
children: [ onPressed: () async {
Align( await _patcherAPI.installApk(
alignment: Alignment.centerRight, context,
child: TextButton( downloadedApk!.path,
onPressed: () { );
Navigator.of(context).pop(); },
}, child: I18nText('updateButton'),
child: I18nText('cancelButton'),
),
), ),
const SizedBox(width: 8.0), ),
Align( ],
alignment: Alignment.centerRight, ),
child: FilledButton( ],
onPressed: () async { ),
await _patcherAPI.installApk( ],
context, ),
downloadedApk!.path,
);
},
child: I18nText('updateButton'),
),
),
],
),
],
),
],
),
],
); );
}, },
), ),
@ -436,16 +472,18 @@ class HomeViewModel extends BaseViewModel {
Future<void> showUpdateConfirmationDialog( Future<void> showUpdateConfirmationDialog(
BuildContext parentContext, BuildContext parentContext,
bool isPatches, bool isPatches, [
) { bool changelog = false,
]) {
return showModalBottomSheet( return showModalBottomSheet(
context: parentContext, context: parentContext,
isScrollControlled: true, isScrollControlled: true,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(24.0)), borderRadius: BorderRadius.vertical(top: Radius.circular(24.0)),
), ),
builder: (context) => UpdateConfirmationDialog( builder: (context) => UpdateConfirmationSheet(
isPatches: isPatches, isPatches: isPatches,
changelog: changelog,
), ),
); );
} }

View File

@ -39,6 +39,15 @@ class SettingsViewModel extends BaseViewModel {
notifyListeners(); notifyListeners();
} }
bool showUpdateDialog() {
return _managerAPI.showUpdateDialog();
}
void setShowUpdateDialog(bool value) {
_managerAPI.setShowUpdateDialog(value);
notifyListeners();
}
bool isPatchesChangeEnabled() { bool isPatchesChangeEnabled() {
return _managerAPI.isPatchesChangeEnabled(); return _managerAPI.isPatchesChangeEnabled();
} }

View File

@ -55,17 +55,15 @@ class _LatestCommitCardState extends State<LatestCommitCard> {
FutureBuilder<bool>( FutureBuilder<bool>(
future: model.hasManagerUpdates(), future: model.hasManagerUpdates(),
initialData: false, initialData: false,
builder: (context, snapshot) => Opacity( builder: (context, snapshot) => FilledButton(
opacity: snapshot.hasData && snapshot.data! ? 1.0 : 0.25, onPressed: () => widget.model.showUpdateConfirmationDialog(
child: FilledButton( widget.parentContext,
onPressed: snapshot.hasData && snapshot.data! false,
? () => widget.model.showUpdateConfirmationDialog( !snapshot.data!,
widget.parentContext,
false,
)
: () => {},
child: I18nText('updateButton'),
), ),
child: (snapshot.hasData && !snapshot.data!)
? I18nText('showChangelogButton')
: I18nText('showUpdateButton'),
), ),
), ),
], ],
@ -83,7 +81,7 @@ class _LatestCommitCardState extends State<LatestCommitCard> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
const Text('Patches'), const Text('ReVanced Patches'),
const SizedBox(height: 4), const SizedBox(height: 4),
Row( Row(
children: <Widget>[ children: <Widget>[
@ -108,19 +106,17 @@ class _LatestCommitCardState extends State<LatestCommitCard> {
), ),
), ),
FutureBuilder<bool>( FutureBuilder<bool>(
future: locator<HomeViewModel>().hasPatchesUpdates(), future: model.hasPatchesUpdates(),
initialData: false, initialData: false,
builder: (context, snapshot) => Opacity( builder: (context, snapshot) => FilledButton(
opacity: snapshot.hasData && snapshot.data! ? 1.0 : 0.25, onPressed: () => widget.model.showUpdateConfirmationDialog(
child: FilledButton( widget.parentContext,
onPressed: snapshot.hasData && snapshot.data! true,
? () => widget.model.showUpdateConfirmationDialog( !snapshot.data!,
widget.parentContext,
true,
)
: () => {},
child: I18nText('updateButton'),
), ),
child: (snapshot.hasData && !snapshot.data!)
? I18nText('showChangelogButton')
: I18nText('showUpdateButton'),
), ),
), ),
], ],

View File

@ -4,10 +4,11 @@ import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/app/app.locator.dart';
import 'package:revanced_manager/ui/views/home/home_viewmodel.dart'; import 'package:revanced_manager/ui/views/home/home_viewmodel.dart';
class UpdateConfirmationDialog extends StatelessWidget { class UpdateConfirmationSheet extends StatelessWidget {
const UpdateConfirmationDialog({super.key, required this.isPatches}); const UpdateConfirmationSheet({super.key, required this.isPatches, this.changelog = false});
final bool isPatches; final bool isPatches;
final bool changelog;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final HomeViewModel model = locator<HomeViewModel>(); final HomeViewModel model = locator<HomeViewModel>();
@ -36,6 +37,7 @@ class UpdateConfirmationDialog extends StatelessWidget {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (!changelog)
Padding( Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
top: 40.0, top: 40.0,
@ -51,8 +53,8 @@ class UpdateConfirmationDialog extends StatelessWidget {
children: [ children: [
I18nText( I18nText(
isPatches isPatches
? 'homeView.updatePatchesDialogTitle' ? 'homeView.updatePatchesSheetTitle'
: 'homeView.updateDialogTitle', : 'homeView.updateSheetTitle',
child: const Text( child: const Text(
'', '',
style: TextStyle( style: TextStyle(

View File

@ -7,6 +7,7 @@ import 'package:revanced_manager/ui/widgets/settingsView/settings_auto_update_pa
import 'package:revanced_manager/ui/widgets/settingsView/settings_enable_patches_selection.dart'; import 'package:revanced_manager/ui/widgets/settingsView/settings_enable_patches_selection.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_require_suggested_app_version.dart'; import 'package:revanced_manager/ui/widgets/settingsView/settings_require_suggested_app_version.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart'; import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_show_update_dialog.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_universal_patches.dart'; import 'package:revanced_manager/ui/widgets/settingsView/settings_universal_patches.dart';
import 'package:revanced_manager/ui/widgets/settingsView/settings_version_compatibility_check.dart'; import 'package:revanced_manager/ui/widgets/settingsView/settings_version_compatibility_check.dart';
@ -19,6 +20,7 @@ class SAdvancedSection extends StatelessWidget {
title: 'settingsView.advancedSectionTitle', title: 'settingsView.advancedSectionTitle',
children: const <Widget>[ children: const <Widget>[
SAutoUpdatePatches(), SAutoUpdatePatches(),
SShowUpdateDialog(),
SEnablePatchesSelection(), SEnablePatchesSelection(),
SRequireSuggestedAppVersion(), SRequireSuggestedAppVersion(),
SVersionCompatibilityCheck(), SVersionCompatibilityCheck(),

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/shared/haptics/haptic_switch_list_tile.dart';
class SShowUpdateDialog extends StatefulWidget {
const SShowUpdateDialog({super.key});
@override
State<SShowUpdateDialog> createState() => _SShowUpdateDialogState();
}
final _settingsViewModel = SettingsViewModel();
class _SShowUpdateDialogState extends State<SShowUpdateDialog> {
@override
Widget build(BuildContext context) {
return HapticSwitchListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
title: I18nText(
'settingsView.showUpdateDialogLabel',
child: const Text(
'',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
),
subtitle: I18nText('settingsView.showUpdateDialogHint'),
value: _settingsViewModel.showUpdateDialog(),
onChanged: (value) {
setState(() {
_settingsViewModel.setShowUpdateDialog(value);
});
},
);
}
}