blob: 3489938a73a177172ff26e582f672e3b6e095e78 [file] [log] [blame]
// 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 'src/messages.g.dart';
/// An implementation of [FileSelectorPlatform] for macOS.
class FileSelectorMacOS extends FileSelectorPlatform {
final FileSelectorApi _hostApi = FileSelectorApi();
/// 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?> paths =
await _hostApi.displayOpenPanel(OpenPanelOptions(
allowsMultipleSelection: false,
canChooseDirectories: false,
canChooseFiles: true,
baseOptions: SavePanelOptions(
allowedFileTypes: _allowedTypesFromTypeGroups(acceptedTypeGroups),
directoryPath: initialDirectory,
prompt: confirmButtonText,
)));
return paths.isEmpty ? null : XFile(paths.first!);
}
@override
Future<List<XFile>> openFiles({
List<XTypeGroup>? acceptedTypeGroups,
String? initialDirectory,
String? confirmButtonText,
}) async {
final List<String?> paths =
await _hostApi.displayOpenPanel(OpenPanelOptions(
allowsMultipleSelection: true,
canChooseDirectories: false,
canChooseFiles: true,
baseOptions: SavePanelOptions(
allowedFileTypes: _allowedTypesFromTypeGroups(acceptedTypeGroups),
directoryPath: initialDirectory,
prompt: confirmButtonText,
)));
return paths.map((String? path) => XFile(path!)).toList();
}
@override
Future<String?> getSavePath({
List<XTypeGroup>? acceptedTypeGroups,
String? initialDirectory,
String? suggestedName,
String? confirmButtonText,
}) async {
final FileSaveLocation? location = await getSaveLocation(
acceptedTypeGroups: acceptedTypeGroups,
options: SaveDialogOptions(
initialDirectory: initialDirectory,
suggestedName: suggestedName,
confirmButtonText: confirmButtonText,
));
return location?.path;
}
@override
Future<FileSaveLocation?> getSaveLocation({
List<XTypeGroup>? acceptedTypeGroups,
SaveDialogOptions options = const SaveDialogOptions(),
}) async {
final String? path = await _hostApi.displaySavePanel(SavePanelOptions(
allowedFileTypes: _allowedTypesFromTypeGroups(acceptedTypeGroups),
directoryPath: options.initialDirectory,
nameFieldStringValue: options.suggestedName,
prompt: options.confirmButtonText,
));
return path == null ? null : FileSaveLocation(path);
}
@override
Future<String?> getDirectoryPath({
String? initialDirectory,
String? confirmButtonText,
}) async {
final List<String?> paths =
await _hostApi.displayOpenPanel(OpenPanelOptions(
allowsMultipleSelection: false,
canChooseDirectories: true,
canChooseFiles: false,
baseOptions: SavePanelOptions(
directoryPath: initialDirectory,
prompt: confirmButtonText,
)));
return paths.isEmpty ? null : paths.first;
}
@override
Future<List<String>> getDirectoryPaths({
String? initialDirectory,
String? confirmButtonText,
}) async {
final List<String?> paths =
await _hostApi.displayOpenPanel(OpenPanelOptions(
allowsMultipleSelection: true,
canChooseDirectories: true,
canChooseFiles: false,
baseOptions: SavePanelOptions(
directoryPath: initialDirectory,
prompt: confirmButtonText,
)));
return paths.isEmpty ? <String>[] : List<String>.from(paths);
}
// Converts the type group list into a flat list of all allowed types, since
// macOS doesn't support filter groups.
AllowedTypes? _allowedTypesFromTypeGroups(List<XTypeGroup>? typeGroups) {
if (typeGroups == null || typeGroups.isEmpty) {
return null;
}
final AllowedTypes allowedTypes = AllowedTypes(
extensions: <String>[],
mimeTypes: <String>[],
utis: <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.uniformTypeIdentifiers?.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", '
'"uniformTypeIdentifiers", or "mimeTypes" must be non-empty for '
'macOS if anything is non-empty.');
}
allowedTypes.extensions.addAll(typeGroup.extensions ?? <String>[]);
allowedTypes.mimeTypes.addAll(typeGroup.mimeTypes ?? <String>[]);
allowedTypes.utis.addAll(typeGroup.uniformTypeIdentifiers ?? <String>[]);
}
return allowedTypes;
}
}