Skip to content

Commit b25f7e1

Browse files
feat: Disable selection of un-suggested app version by default (#1471)
Co-authored-by: oSumAtrIX <[email protected]>
1 parent e7d8285 commit b25f7e1

File tree

7 files changed

+178
-28
lines changed

7 files changed

+178
-28
lines changed

assets/i18n/en_US.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@
111111

112112
"downloadToast": "Download function is not available yet",
113113

114+
"requireSuggestedAppVersionDialogText": "The version of the app you have selected does not match the suggested version. Please select the app that matches the suggested version.\n\nSelected version: v{selected}\nSuggested version: v{suggested}\n\n.To proceed anyway, disable \"Require suggested app version\" in the settings.",
115+
114116
"featureNotAvailable": "Feature not implemented",
115117
"featureNotAvailableText": "This application is a split APK and cannot be selected. Unfortunately, this feature is only available for rooted users at the moment. However, you can still install the application by selecting its APK files from your device's storage instead"
116118
},
@@ -234,8 +236,12 @@
234236
"autoUpdatePatchesHint": "Automatically update patches to the latest version",
235237
"universalPatchesLabel": "Show universal patches",
236238
"universalPatchesHint": "Display all apps and universal patches (may slow down the app list)",
239+
237240
"versionCompatibilityCheckLabel": "Version compatibility check",
238241
"versionCompatibilityCheckHint": "Restricts patches to supported app versions",
242+
"requireSuggestedAppVersionLabel": "Require suggested app version",
243+
"requireSuggestedAppVersionHint": "Enforce selection of suggested app version",
244+
"requireSuggestedAppVersionDialogText": "Selecting an app that is not the suggested version may cause unexpected issues.\n\nDo you want to proceed anyways?",
239245

240246
"aboutLabel": "About",
241247
"snackbarMessage": "Copied to clipboard",

lib/services/manager_api.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class ManagerAPI {
3434
Patch? selectedPatch;
3535
BuildContext? ctx;
3636
bool isRooted = false;
37+
bool suggestedAppVersionSelected = true;
3738
bool isDynamicThemeAvailable = false;
3839
String storedPatchesFile = '/selected-patches.json';
3940
String keystoreFile =
@@ -259,6 +260,14 @@ class ManagerAPI {
259260
await _prefs.setBool('versionCompatibilityCheckEnabled', value);
260261
}
261262

263+
bool isRequireSuggestedAppVersionEnabled() {
264+
return _prefs.getBool('requireSuggestedAppVersionEnabled') ?? true;
265+
}
266+
267+
Future<void> enableRequireSuggestedAppVersionStatus(bool value) async {
268+
await _prefs.setBool('requireSuggestedAppVersionEnabled', value);
269+
}
270+
262271
Future<void> setKeystorePassword(String password) async {
263272
await _prefs.setString('keystorePassword', password);
264273
}

lib/ui/views/app_selector/app_selector_view.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ class _AppSelectorViewState extends State<AppSelectorView> {
2828
icon: const Icon(Icons.sd_storage),
2929
onPressed: () {
3030
model.selectAppFromStorage(context);
31-
Navigator.of(context).pop();
3231
},
3332
),
3433
body: CustomScrollView(

lib/ui/views/app_selector/app_selector_viewmodel.dart

Lines changed: 76 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,39 @@ class AppSelectorViewModel extends BaseViewModel {
7070
return true;
7171
}
7272

73-
Future<void> selectApp(ApplicationWithIcon application) async {
73+
Future<void> selectApp(
74+
BuildContext context,
75+
ApplicationWithIcon application, [
76+
bool isFromStorage = false,
77+
]) async {
78+
final String suggestedVersion =
79+
getSuggestedVersion(application.packageName);
80+
if (application.versionName != suggestedVersion && suggestedVersion.isNotEmpty) {
81+
_managerAPI.suggestedAppVersionSelected = false;
82+
if (_managerAPI.isRequireSuggestedAppVersionEnabled() &&
83+
context.mounted) {
84+
return showRequireSuggestedAppVersionDialog(
85+
context,
86+
application.versionName!,
87+
suggestedVersion,
88+
);
89+
}
90+
} else {
91+
_managerAPI.suggestedAppVersionSelected = true;
92+
}
7493
locator<PatcherViewModel>().selectedApp = PatchedApplication(
7594
name: application.appName,
7695
packageName: application.packageName,
7796
version: application.versionName!,
7897
apkFilePath: application.apkFilePath,
7998
icon: application.icon,
8099
patchDate: DateTime.now(),
100+
isFromStorage: isFromStorage,
81101
);
82102
await locator<PatcherViewModel>().loadLastSelectedPatches();
103+
if (context.mounted) {
104+
Navigator.pop(context);
105+
}
83106
}
84107

85108
Future<void> canSelectInstalled(
@@ -89,23 +112,60 @@ class AppSelectorViewModel extends BaseViewModel {
89112
final app =
90113
await DeviceApps.getApp(packageName, true) as ApplicationWithIcon?;
91114
if (app != null) {
92-
if (await checkSplitApk(packageName) && !isRooted) {
93-
if (context.mounted) {
94-
return showSelectFromStorageDialog(context);
95-
}
96-
} else if (!await checkSplitApk(packageName) || isRooted) {
97-
await selectApp(app);
115+
final bool isSplitApk = await checkSplitApk(packageName);
116+
if (isRooted || !isSplitApk) {
98117
if (context.mounted) {
99-
Navigator.pop(context);
118+
await selectApp(context, app);
100119
}
101-
final List<Option> requiredNullOptions = getNullRequiredOptions(locator<PatcherViewModel>().selectedPatches, packageName);
102-
if(requiredNullOptions.isNotEmpty){
120+
final List<Option> requiredNullOptions = getNullRequiredOptions(
121+
locator<PatcherViewModel>().selectedPatches,
122+
packageName,
123+
);
124+
if (requiredNullOptions.isNotEmpty) {
103125
locator<PatcherViewModel>().showRequiredOptionDialog();
104126
}
127+
} else {
128+
if (context.mounted) {
129+
return showSelectFromStorageDialog(context);
130+
}
105131
}
106132
}
107133
}
108134

135+
Future showRequireSuggestedAppVersionDialog(
136+
BuildContext context,
137+
String selectedVersion,
138+
String suggestedVersion,
139+
) async {
140+
return showDialog(
141+
context: context,
142+
builder: (context) => AlertDialog(
143+
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
144+
title: I18nText('warning'),
145+
content: I18nText(
146+
'appSelectorView.requireSuggestedAppVersionDialogText',
147+
translationParams: {
148+
'suggested': suggestedVersion,
149+
'selected': selectedVersion,
150+
},
151+
child: const Text(
152+
'',
153+
style: TextStyle(
154+
fontSize: 16,
155+
fontWeight: FontWeight.w500,
156+
),
157+
),
158+
),
159+
actions: [
160+
CustomMaterialButton(
161+
label: I18nText('okButton'),
162+
onPressed: () => Navigator.of(context).pop(),
163+
),
164+
],
165+
),
166+
);
167+
}
168+
109169
Future showSelectFromStorageDialog(BuildContext context) async {
110170
return showDialog(
111171
context: context,
@@ -145,12 +205,10 @@ class AppSelectorViewModel extends BaseViewModel {
145205
),
146206
const SizedBox(height: 30),
147207
CustomMaterialButton(
148-
onPressed: () => selectAppFromStorage(context).then(
149-
(_) {
150-
Navigator.pop(context);
151-
Navigator.pop(context);
152-
},
153-
),
208+
onPressed: () async {
209+
Navigator.pop(context);
210+
await selectAppFromStorage(context);
211+
},
154212
label: Row(
155213
mainAxisAlignment: MainAxisAlignment.center,
156214
children: [
@@ -203,17 +261,8 @@ class AppSelectorViewModel extends BaseViewModel {
203261
apkFile.path,
204262
true,
205263
) as ApplicationWithIcon?;
206-
if (application != null) {
207-
locator<PatcherViewModel>().selectedApp = PatchedApplication(
208-
name: application.appName,
209-
packageName: application.packageName,
210-
version: application.versionName!,
211-
apkFilePath: result,
212-
icon: application.icon,
213-
patchDate: DateTime.now(),
214-
isFromStorage: true,
215-
);
216-
locator<PatcherViewModel>().loadLastSelectedPatches();
264+
if (application != null && context.mounted) {
265+
await selectApp(context, application, true);
217266
}
218267
}
219268
} on Exception catch (e) {

lib/ui/views/settings/settings_viewmodel.dart

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,54 @@ class SettingsViewModel extends BaseViewModel {
140140
notifyListeners();
141141
}
142142

143+
bool isRequireSuggestedAppVersionEnabled() {
144+
return _managerAPI.isRequireSuggestedAppVersionEnabled();
145+
}
146+
147+
Future<void>? showRequireSuggestedAppVersionDialog(
148+
BuildContext context, bool value) {
149+
if (!value) {
150+
return showDialog(
151+
context: context,
152+
builder: (context) => AlertDialog(
153+
backgroundColor: Theme.of(context).colorScheme.secondaryContainer,
154+
title: I18nText('warning'),
155+
content: I18nText(
156+
'settingsView.requireSuggestedAppVersionDialogText',
157+
child: const Text(
158+
'',
159+
style: TextStyle(
160+
fontSize: 16,
161+
fontWeight: FontWeight.w500,
162+
),
163+
),
164+
),
165+
actions: [
166+
CustomMaterialButton(
167+
isFilled: false,
168+
label: I18nText('yesButton'),
169+
onPressed: () {
170+
_managerAPI.enableRequireSuggestedAppVersionStatus(false);
171+
Navigator.of(context).pop();
172+
},
173+
),
174+
CustomMaterialButton(
175+
label: I18nText('noButton'),
176+
onPressed: () {
177+
Navigator.of(context).pop();
178+
},
179+
),
180+
],
181+
),
182+
);
183+
} else {
184+
_managerAPI.enableRequireSuggestedAppVersionStatus(true);
185+
if (!_managerAPI.suggestedAppVersionSelected) {
186+
_patcherViewModel.selectedApp = null;
187+
}
188+
}
189+
}
190+
143191
void deleteKeystore() {
144192
_managerAPI.deleteKeystore();
145193
_toast.showBottom('settingsView.regeneratedKeystore');

lib/ui/widgets/settingsView/settings_advanced_section.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:revanced_manager/ui/views/settings/settingsFragment/settings_man
55
import 'package:revanced_manager/ui/views/settings/settingsFragment/settings_manage_sources.dart';
66
import 'package:revanced_manager/ui/widgets/settingsView/settings_auto_update_patches.dart';
77
import 'package:revanced_manager/ui/widgets/settingsView/settings_enable_patches_selection.dart';
8+
import 'package:revanced_manager/ui/widgets/settingsView/settings_require_suggested_app_version.dart';
89
import 'package:revanced_manager/ui/widgets/settingsView/settings_section.dart';
910
import 'package:revanced_manager/ui/widgets/settingsView/settings_universal_patches.dart';
1011
import 'package:revanced_manager/ui/widgets/settingsView/settings_version_compatibility_check.dart';
@@ -20,6 +21,7 @@ class SAdvancedSection extends StatelessWidget {
2021
children: const <Widget>[
2122
SAutoUpdatePatches(),
2223
SEnablePatchesSelection(),
24+
SRequireSuggestedAppVersion(),
2325
SVersionCompatibilityCheck(),
2426
SUniversalPatches(),
2527
SManageSourcesUI(),
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_i18n/widgets/I18nText.dart';
3+
import 'package:revanced_manager/ui/views/settings/settings_viewmodel.dart';
4+
5+
class SRequireSuggestedAppVersion extends StatefulWidget {
6+
const SRequireSuggestedAppVersion({super.key});
7+
8+
@override
9+
State<SRequireSuggestedAppVersion> createState() => _SRequireSuggestedAppVersionState();
10+
}
11+
12+
final _settingsViewModel = SettingsViewModel();
13+
14+
class _SRequireSuggestedAppVersionState extends State<SRequireSuggestedAppVersion> {
15+
@override
16+
Widget build(BuildContext context) {
17+
return SwitchListTile(
18+
contentPadding: const EdgeInsets.symmetric(horizontal: 20.0),
19+
title: I18nText(
20+
'settingsView.requireSuggestedAppVersionLabel',
21+
child: const Text(
22+
'',
23+
style: TextStyle(
24+
fontSize: 20,
25+
fontWeight: FontWeight.w500,
26+
),
27+
),
28+
),
29+
subtitle: I18nText('settingsView.requireSuggestedAppVersionHint'),
30+
value: _settingsViewModel.isRequireSuggestedAppVersionEnabled(),
31+
onChanged: (value) async {
32+
await _settingsViewModel.showRequireSuggestedAppVersionDialog(context, value);
33+
setState(() {});
34+
},
35+
);
36+
}
37+
}

0 commit comments

Comments
 (0)