Skip to content

[file_selector] Convert Linux to Pigeon #7770

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/file_selector/file_selector_linux/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## NEXT
## 0.9.3

* Updates method channel implementation to use Pigeon.
* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3.

## 0.9.2+1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,17 @@

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.dev/file_selector_linux');

const String _typeGroupLabelKey = 'label';
const String _typeGroupExtensionsKey = 'extensions';
const String _typeGroupMimeTypesKey = 'mimeTypes';

const String _openFileMethod = 'openFile';
const String _getSavePathMethod = 'getSavePath';
const String _getDirectoryPathMethod = 'getDirectoryPath';

const String _acceptedTypeGroupsKey = 'acceptedTypeGroups';
const String _confirmButtonTextKey = 'confirmButtonText';
const String _initialDirectoryKey = 'initialDirectory';
const String _multipleKey = 'multiple';
const String _suggestedNameKey = 'suggestedName';
import 'src/messages.g.dart';

/// An implementation of [FileSelectorPlatform] for Linux.
class FileSelectorLinux extends FileSelectorPlatform {
/// The MethodChannel that is being used by this implementation of the plugin.
@visibleForTesting
MethodChannel get channel => _channel;
/// Creates a new plugin implementation instance.
FileSelectorLinux({
@visibleForTesting FileSelectorApi? api,
}) : _hostApi = api ?? FileSelectorApi();

final FileSelectorApi _hostApi;

/// Registers the Linux implementation.
static void registerWith() {
Expand All @@ -40,19 +27,16 @@ class FileSelectorLinux extends FileSelectorPlatform {
String? initialDirectory,
String? confirmButtonText,
}) async {
final List<Map<String, Object>> serializedTypeGroups =
_serializeTypeGroups(acceptedTypeGroups);
final List<String>? path = await _channel.invokeListMethod<String>(
_openFileMethod,
<String, dynamic>{
if (serializedTypeGroups.isNotEmpty)
_acceptedTypeGroupsKey: serializedTypeGroups,
'initialDirectory': initialDirectory,
_confirmButtonTextKey: confirmButtonText,
_multipleKey: false,
},
);
return path == null ? null : XFile(path.first);
final List<String> paths = await _hostApi.showFileChooser(
PlatformFileChooserActionType.open,
PlatformFileChooserOptions(
allowedFileTypes:
_platformTypeGroupsFromXTypeGroups(acceptedTypeGroups),
currentFolderPath: initialDirectory,
acceptButtonLabel: confirmButtonText,
selectMultiple: false,
));
return paths.isEmpty ? null : XFile(paths.first);
}

@override
Expand All @@ -61,19 +45,16 @@ class FileSelectorLinux extends FileSelectorPlatform {
String? initialDirectory,
String? confirmButtonText,
}) async {
final List<Map<String, Object>> serializedTypeGroups =
_serializeTypeGroups(acceptedTypeGroups);
final List<String>? pathList = await _channel.invokeListMethod<String>(
_openFileMethod,
<String, dynamic>{
if (serializedTypeGroups.isNotEmpty)
_acceptedTypeGroupsKey: serializedTypeGroups,
_initialDirectoryKey: initialDirectory,
_confirmButtonTextKey: confirmButtonText,
_multipleKey: true,
},
);
return pathList?.map((String path) => XFile(path)).toList() ?? <XFile>[];
final List<String> paths = await _hostApi.showFileChooser(
PlatformFileChooserActionType.open,
PlatformFileChooserOptions(
allowedFileTypes:
_platformTypeGroupsFromXTypeGroups(acceptedTypeGroups),
currentFolderPath: initialDirectory,
acceptButtonLabel: confirmButtonText,
selectMultiple: true,
));
return paths.map((String path) => XFile(path)).toList();
}

@override
Expand All @@ -98,78 +79,76 @@ class FileSelectorLinux extends FileSelectorPlatform {
List<XTypeGroup>? acceptedTypeGroups,
SaveDialogOptions options = const SaveDialogOptions(),
}) async {
final List<Map<String, Object>> serializedTypeGroups =
_serializeTypeGroups(acceptedTypeGroups);
// TODO(stuartmorgan): Add the selected type group here and return it. See
// https://github.com/flutter/flutter/issues/107093
final String? path = await _channel.invokeMethod<String>(
_getSavePathMethod,
<String, dynamic>{
if (serializedTypeGroups.isNotEmpty)
_acceptedTypeGroupsKey: serializedTypeGroups,
_initialDirectoryKey: options.initialDirectory,
_suggestedNameKey: options.suggestedName,
_confirmButtonTextKey: options.confirmButtonText,
},
);
return path == null ? null : FileSaveLocation(path);
final List<String> paths = await _hostApi.showFileChooser(
PlatformFileChooserActionType.save,
PlatformFileChooserOptions(
allowedFileTypes:
_platformTypeGroupsFromXTypeGroups(acceptedTypeGroups),
currentFolderPath: options.initialDirectory,
currentName: options.suggestedName,
acceptButtonLabel: options.confirmButtonText,
));
return paths.isEmpty ? null : FileSaveLocation(paths.first);
}

@override
Future<String?> getDirectoryPath({
String? initialDirectory,
String? confirmButtonText,
}) async {
final List<String>? path = await _channel
.invokeListMethod<String>(_getDirectoryPathMethod, <String, dynamic>{
_initialDirectoryKey: initialDirectory,
_confirmButtonTextKey: confirmButtonText,
});
return path?.first;
final List<String> paths = await _hostApi.showFileChooser(
PlatformFileChooserActionType.chooseDirectory,
PlatformFileChooserOptions(
currentFolderPath: initialDirectory,
acceptButtonLabel: confirmButtonText,
selectMultiple: false,
));
return paths.isEmpty ? null : paths.first;
}

@override
Future<List<String>> getDirectoryPaths({
String? initialDirectory,
String? confirmButtonText,
}) async {
final List<String>? pathList = await _channel
.invokeListMethod<String>(_getDirectoryPathMethod, <String, dynamic>{
_initialDirectoryKey: initialDirectory,
_confirmButtonTextKey: confirmButtonText,
_multipleKey: true,
});
return pathList ?? <String>[];
return _hostApi.showFileChooser(
PlatformFileChooserActionType.chooseDirectory,
PlatformFileChooserOptions(
currentFolderPath: initialDirectory,
acceptButtonLabel: confirmButtonText,
selectMultiple: true,
));
}
}

List<Map<String, Object>> _serializeTypeGroups(List<XTypeGroup>? groups) {
return (groups ?? <XTypeGroup>[]).map(_serializeTypeGroup).toList();
List<PlatformTypeGroup>? _platformTypeGroupsFromXTypeGroups(
List<XTypeGroup>? groups) {
return groups?.map(_platformTypeGroupFromXTypeGroup).toList();
}

Map<String, Object> _serializeTypeGroup(XTypeGroup group) {
final Map<String, Object> serialization = <String, Object>{
_typeGroupLabelKey: group.label ?? '',
};
PlatformTypeGroup _platformTypeGroupFromXTypeGroup(XTypeGroup group) {
final String label = group.label ?? '';
if (group.allowsAny) {
serialization[_typeGroupExtensionsKey] = <String>['*'];
} else {
if ((group.extensions?.isEmpty ?? true) &&
(group.mimeTypes?.isEmpty ?? true)) {
throw ArgumentError('Provided type group $group does not allow '
'all files, but does not set any of the Linux-supported filter '
'categories. "extensions" or "mimeTypes" must be non-empty for Linux '
'if anything is non-empty.');
}
if (group.extensions?.isNotEmpty ?? false) {
serialization[_typeGroupExtensionsKey] = group.extensions
return PlatformTypeGroup(
label: label,
extensions: <String>['*'],
);
}
if ((group.extensions?.isEmpty ?? true) &&
(group.mimeTypes?.isEmpty ?? true)) {
throw ArgumentError('Provided type group $group does not allow '
'all files, but does not set any of the Linux-supported filter '
'categories. "extensions" or "mimeTypes" must be non-empty for Linux '
'if anything is non-empty.');
}
return PlatformTypeGroup(
label: label,
// Covert to GtkFileFilter's *.<extension> format.
extensions: group.extensions
?.map((String extension) => '*.$extension')
.toList() ??
<String>[];
}
if (group.mimeTypes?.isNotEmpty ?? false) {
serialization[_typeGroupMimeTypesKey] = group.mimeTypes ?? <String>[];
}
}
return serialization;
<String>[],
mimeTypes: group.mimeTypes ?? <String>[]);
}
Loading