| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; |
| import 'package:flutter/foundation.dart' show visibleForTesting; |
| import 'package:flutter/services.dart'; |
| |
| const MethodChannel _channel = |
| MethodChannel('plugins.flutter.io/file_selector_macos'); |
| |
| /// An implementation of [FileSelectorPlatform] for macOS. |
| class FileSelectorMacOS extends FileSelectorPlatform { |
| /// The MethodChannel that is being used by this implementation of the plugin. |
| @visibleForTesting |
| MethodChannel get channel => _channel; |
| |
| /// Registers the macOS implementation. |
| static void registerWith() { |
| FileSelectorPlatform.instance = FileSelectorMacOS(); |
| } |
| |
| @override |
| Future<XFile?> openFile({ |
| List<XTypeGroup>? acceptedTypeGroups, |
| String? initialDirectory, |
| String? confirmButtonText, |
| }) async { |
| final List<String>? path = await _channel.invokeListMethod<String>( |
| 'openFile', |
| <String, dynamic>{ |
| 'acceptedTypes': _allowedTypeListFromTypeGroups(acceptedTypeGroups), |
| 'initialDirectory': initialDirectory, |
| 'confirmButtonText': confirmButtonText, |
| 'multiple': false, |
| }, |
| ); |
| return path == null ? null : XFile(path.first); |
| } |
| |
| @override |
| Future<List<XFile>> openFiles({ |
| List<XTypeGroup>? acceptedTypeGroups, |
| String? initialDirectory, |
| String? confirmButtonText, |
| }) async { |
| final List<String>? pathList = await _channel.invokeListMethod<String>( |
| 'openFile', |
| <String, dynamic>{ |
| 'acceptedTypes': _allowedTypeListFromTypeGroups(acceptedTypeGroups), |
| 'initialDirectory': initialDirectory, |
| 'confirmButtonText': confirmButtonText, |
| 'multiple': true, |
| }, |
| ); |
| return pathList?.map((String path) => XFile(path)).toList() ?? <XFile>[]; |
| } |
| |
| @override |
| Future<String?> getSavePath({ |
| List<XTypeGroup>? acceptedTypeGroups, |
| String? initialDirectory, |
| String? suggestedName, |
| String? confirmButtonText, |
| }) async { |
| return _channel.invokeMethod<String>( |
| 'getSavePath', |
| <String, dynamic>{ |
| 'acceptedTypes': _allowedTypeListFromTypeGroups(acceptedTypeGroups), |
| 'initialDirectory': initialDirectory, |
| 'suggestedName': suggestedName, |
| 'confirmButtonText': confirmButtonText, |
| }, |
| ); |
| } |
| |
| @override |
| Future<String?> getDirectoryPath({ |
| String? initialDirectory, |
| String? confirmButtonText, |
| }) async { |
| return _channel.invokeMethod<String>( |
| 'getDirectoryPath', |
| <String, dynamic>{ |
| 'initialDirectory': initialDirectory, |
| 'confirmButtonText': confirmButtonText, |
| }, |
| ); |
| } |
| |
| // Converts the type group list into a flat list of all allowed types, since |
| // macOS doesn't support filter groups. |
| Map<String, List<String>>? _allowedTypeListFromTypeGroups( |
| List<XTypeGroup>? typeGroups) { |
| const String extensionKey = 'extensions'; |
| const String mimeTypeKey = 'mimeTypes'; |
| const String utiKey = 'UTIs'; |
| if (typeGroups == null || typeGroups.isEmpty) { |
| return null; |
| } |
| final Map<String, List<String>> allowedTypes = <String, List<String>>{ |
| extensionKey: <String>[], |
| mimeTypeKey: <String>[], |
| utiKey: <String>[], |
| }; |
| for (final XTypeGroup typeGroup in typeGroups) { |
| // If any group allows everything, no filtering should be done. |
| if (typeGroup.allowsAny) { |
| return null; |
| } |
| // Reject a filter that isn't an allow-any, but doesn't set any |
| // macOS-supported filter categories. |
| if ((typeGroup.extensions?.isEmpty ?? true) && |
| (typeGroup.macUTIs?.isEmpty ?? true) && |
| (typeGroup.mimeTypes?.isEmpty ?? true)) { |
| throw ArgumentError('Provided type group $typeGroup does not allow ' |
| 'all files, but does not set any of the macOS-supported filter ' |
| 'categories. At least one of "extensions", "macUTIs", or ' |
| '"mimeTypes" must be non-empty for macOS if anything is ' |
| 'non-empty.'); |
| } |
| allowedTypes[extensionKey]!.addAll(typeGroup.extensions ?? <String>[]); |
| allowedTypes[mimeTypeKey]!.addAll(typeGroup.mimeTypes ?? <String>[]); |
| allowedTypes[utiKey]!.addAll(typeGroup.macUTIs ?? <String>[]); |
| } |
| |
| return allowedTypes; |
| } |
| } |