diff --git a/lib/services/manager_api.dart b/lib/services/manager_api.dart index 0e02228ae8..2eb4b3bb73 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 f400019db1..19213a4538 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 e7c2f4a6fd..8a7d5b7f97 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: