From f1c2f4146cc9c8a8f14cf84cee02abc2b0d2c9f4 Mon Sep 17 00:00:00 2001 From: Francesco Marastoni <49027005+Francesco146@users.noreply.github.com> Date: Sun, 18 Aug 2024 08:11:10 +0000 Subject: [PATCH] fix: Handle selecting files and folders for patch options correctly (#2144) --- lib/services/manager_api.dart | 9 +++- .../patch_options_fields.dart | 45 ++++++++++++++----- pubspec.yaml | 1 + 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/lib/services/manager_api.dart b/lib/services/manager_api.dart index 0e02228a..2eb4b3bb 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,11 @@ class ManagerAPI { Future initialize() async { _prefs = await SharedPreferences.getInstance(); isRooted = await _rootAPI.isRooted(); - isDynamicThemeAvailable = - (await getSdkVersion()) >= 31; // ANDROID_12_SDK_VERSION = 31 + if (sdkVersion == 0) { + sdkVersion = await getSdkVersion(); + } + isDynamicThemeAvailable = 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..19213a45 100644 --- a/lib/ui/widgets/patchesSelectorView/patch_options_fields.dart +++ b/lib/ui/widgets/patchesSelectorView/patch_options_fields.dart @@ -1,8 +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/services/manager_api.dart'; import 'package:revanced_manager/ui/views/patch_options/patch_options_viewmodel.dart'; import 'package:revanced_manager/ui/widgets/shared/custom_card.dart'; @@ -398,6 +401,7 @@ class TextFieldForPatchOption extends StatefulWidget { } class _TextFieldForPatchOptionState extends State { + final ManagerAPI _managerAPI = locator(); final TextEditingController controller = TextEditingController(); String? selectedKey; String? defaultValue; @@ -524,21 +528,42 @@ class _TextFieldForPatchOptionState extends State { ]; }, onSelected: (String selection) async { + Future gotExternalStoragePermission() async { + // manageExternalStorage permission is required for folder selection + // otherwise, the app will not complain, but the patches will error out + // the same way as if the user selected an empty folder. + // Android 11 and above requires the manageExternalStorage permission + if (_managerAPI.isScopedStorageAvailable) { + final permission = + await Permission.manageExternalStorage.request(); + return permission.isGranted; + } + return true; + } + switch (selection) { case 'file': - final String? result = await FlutterFileDialog.pickFile(); - if (result != null) { - controller.text = result; - widget.onChanged(controller.text); + // here scope storage is not required because file_picker + // will copy the file to the app's cache + final FilePickerResult? result = + await FilePicker.platform.pickFiles(); + if (result == null) { + return; } + controller.text = result.files.single.path!; + widget.onChanged(controller.text); break; case 'folder': - final DirectoryLocation? result = - await FlutterFileDialog.pickDirectory(); - if (result != null) { - controller.text = result.toString(); - widget.onChanged(controller.text); + if (!await gotExternalStoragePermission()) { + return; } + final String? result = + await FilePicker.platform.getDirectoryPath(); + if (result == null) { + return; + } + controller.text = result; + widget.onChanged(controller.text); break; case 'remove': widget.removeValue!(); diff --git a/pubspec.yaml b/pubspec.yaml index e7c2f4a6..8a7d5b7f 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.5 flutter: sdk: flutter flutter_background: