From b26760b2163081e0e49b0bcd4799abefb4118920 Mon Sep 17 00:00:00 2001 From: Francesco Marastoni <49027005+Francesco146@users.noreply.github.com> Date: Sat, 29 Jun 2024 12:34:34 +0000 Subject: [PATCH] fix: Handle selecting files and folders for patch options correctly (#1941) --- lib/services/manager_api.dart | 9 ++- .../patch_options_fields.dart | 67 +++++++++++++------ pubspec.yaml | 1 + 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/lib/services/manager_api.dart b/lib/services/manager_api.dart index bc136208..a950c3d1 100644 --- a/lib/services/manager_api.dart +++ b/lib/services/manager_api.dart @@ -38,6 +38,8 @@ class ManagerAPI { bool releaseBuild = false; bool suggestedAppVersionSelected = true; bool isDynamicThemeAvailable = false; + bool isScopedStorageAvailable = false; + int sdkVersion = 0; String storedPatchesFile = '/selected-patches.json'; String keystoreFile = '/sdcard/Android/data/app.revanced.manager.flutter/files/revanced-manager.keystore'; @@ -55,8 +57,13 @@ class ManagerAPI { Future initialize() async { _prefs = await SharedPreferences.getInstance(); isRooted = await _rootAPI.isRooted(); + if (sdkVersion == 0) { + sdkVersion = await getSdkVersion(); + } isDynamicThemeAvailable = - (await getSdkVersion()) >= 31; // ANDROID_12_SDK_VERSION = 31 + sdkVersion >= 31; // ANDROID_12_SDK_VERSION = 31 + isScopedStorageAvailable = + sdkVersion >= 30; // ANDROID_11_SDK_VERSION = 30 storedPatchesFile = (await getApplicationDocumentsDirectory()).path + storedPatchesFile; if (kReleaseMode) { diff --git a/lib/ui/widgets/patchesSelectorView/patch_options_fields.dart b/lib/ui/widgets/patchesSelectorView/patch_options_fields.dart index f400019d..1fdb9d7a 100644 --- a/lib/ui/widgets/patchesSelectorView/patch_options_fields.dart +++ b/lib/ui/widgets/patchesSelectorView/patch_options_fields.dart @@ -1,9 +1,11 @@ +import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_file_dialog/flutter_file_dialog.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:revanced_manager/app/app.locator.dart'; import 'package:revanced_manager/gen/strings.g.dart'; import 'package:revanced_manager/models/patch.dart'; -import 'package:revanced_manager/ui/views/patch_options/patch_options_viewmodel.dart'; +import 'package:revanced_manager/services/manager_api.dart'; import 'package:revanced_manager/ui/widgets/shared/custom_card.dart'; class BooleanPatchOption extends StatelessWidget { @@ -398,6 +400,7 @@ class TextFieldForPatchOption extends StatefulWidget { } class _TextFieldForPatchOptionState extends State { + final ManagerAPI _managerAPI = locator(); final TextEditingController controller = TextEditingController(); String? selectedKey; String? defaultValue; @@ -524,29 +527,49 @@ class _TextFieldForPatchOptionState extends State { ]; }, onSelected: (String selection) async { - switch (selection) { - case 'file': - final String? result = await FlutterFileDialog.pickFile(); - if (result != null) { - controller.text = result; - widget.onChanged(controller.text); + // manageExternalStorage permission is required for file/folder selection + // otherwise, the app will not complain, but the patches will error out + // the same way as if the user selected an empty file/folder. + // Android 11 and above requires the manageExternalStorage permission + final Map availableActions = { + t.patchOptionsView.selectFilePath: () async { + if (_managerAPI.isScopedStorageAvailable) { + final permission = + await Permission.manageExternalStorage.request(); + if (!permission.isGranted) { + return; + } } - break; - case 'folder': - final DirectoryLocation? result = - await FlutterFileDialog.pickDirectory(); - if (result != null) { - controller.text = result.toString(); - widget.onChanged(controller.text); + final FilePickerResult? result = + await FilePicker.platform.pickFiles(); + if (result == null) { + return; } - break; - case 'remove': + controller.text = result.files.single.path!; + widget.onChanged(controller.text); + }, + t.patchOptionsView.selectFolder: () async { + if (_managerAPI.isScopedStorageAvailable) { + final permission = + await Permission.manageExternalStorage.request(); + if (!permission.isGranted) { + return; + } + } + final String? result = + await FilePicker.platform.getDirectoryPath(); + if (result == null) { + return; + } + controller.text = result; + widget.onChanged(controller.text); + }, + t.remove: () { widget.removeValue!(); - break; - case 'null': - controller.text = ''; - widget.onChanged(null); - break; + }, + }; + if (availableActions.containsKey(selection)) { + await availableActions[selection]!(); } }, ), diff --git a/pubspec.yaml b/pubspec.yaml index 5e897654..1a568076 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,6 +23,7 @@ dependencies: dynamic_color: ^1.7.0 dynamic_themes: ^1.1.0 expandable: ^5.0.1 + file_picker: ^8.0.3 flutter: sdk: flutter flutter_background: