From b39655a7a3d7c52ff8cc32797e0720b0db96340a Mon Sep 17 00:00:00 2001 From: Daniel Ferreira Date: Sun, 16 Nov 2025 16:00:47 -0300 Subject: [PATCH 1/5] [file_selector] Implement canCreateDirectories for macOS and Linux --- .../file_selector_linux/CHANGELOG.md | 3 +- .../file_selector_linux/example/pubspec.yaml | 2 +- .../lib/file_selector_linux.dart | 33 ++++- .../lib/src/messages.g.dart | 10 +- .../linux/file_selector_plugin.cc | 7 + .../file_selector_linux/linux/messages.g.cc | 30 ++++- .../file_selector_linux/linux/messages.g.h | 18 ++- .../linux/test/file_selector_plugin_test.cc | 90 +++++++++++-- .../file_selector_linux/pigeons/messages.dart | 6 + .../file_selector_linux/pubspec.yaml | 4 +- .../test/file_selector_linux_test.dart | 85 ++++++++++++ .../file_selector_macos/CHANGELOG.md | 4 + .../example/lib/get_directory_page.dart | 7 +- .../lib/get_multiple_directories_page.dart | 7 +- .../macos/Runner.xcodeproj/project.pbxproj | 18 +++ .../macos/RunnerTests/RunnerTests.swift | 70 ++++++++++ .../file_selector_macos/example/pubspec.yaml | 2 +- .../lib/file_selector_macos.dart | 33 ++++- .../lib/src/messages.g.dart | 5 + .../FileSelectorPlugin.swift | 4 + .../file_selector_macos/messages.g.swift | 6 +- .../file_selector_macos/pigeons/messages.dart | 2 + .../file_selector_macos/pubspec.yaml | 4 +- .../test/file_selector_macos_test.dart | 122 ++++++++++++++++++ 24 files changed, 540 insertions(+), 32 deletions(-) diff --git a/packages/file_selector/file_selector_linux/CHANGELOG.md b/packages/file_selector/file_selector_linux/CHANGELOG.md index 1c0b1fc62c1..ee9872ba1f4 100644 --- a/packages/file_selector/file_selector_linux/CHANGELOG.md +++ b/packages/file_selector/file_selector_linux/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 0.9.4 +* Adds `getDirectoryPathWithOptions` and `getDirectoryPathsWithOptions` implementations. * Updates minimum supported SDK version to Flutter 3.32/Dart 3.8. ## 0.9.3+2 diff --git a/packages/file_selector/file_selector_linux/example/pubspec.yaml b/packages/file_selector/file_selector_linux/example/pubspec.yaml index bf4a8ca7eb4..73248a2704a 100644 --- a/packages/file_selector/file_selector_linux/example/pubspec.yaml +++ b/packages/file_selector/file_selector_linux/example/pubspec.yaml @@ -10,7 +10,7 @@ environment: dependencies: file_selector_linux: path: ../ - file_selector_platform_interface: ^2.6.0 + file_selector_platform_interface: ^2.7.0 flutter: sdk: flutter diff --git a/packages/file_selector/file_selector_linux/lib/file_selector_linux.dart b/packages/file_selector/file_selector_linux/lib/file_selector_linux.dart index ae816093fea..f80c9f60d3b 100644 --- a/packages/file_selector/file_selector_linux/lib/file_selector_linux.dart +++ b/packages/file_selector/file_selector_linux/lib/file_selector_linux.dart @@ -94,6 +94,7 @@ class FileSelectorLinux extends FileSelectorPlatform { currentFolderPath: options.initialDirectory, currentName: options.suggestedName, acceptButtonLabel: options.confirmButtonText, + createFolders: options.canCreateDirectories, ), ); return paths.isEmpty ? null : FileSaveLocation(paths.first); @@ -104,11 +105,22 @@ class FileSelectorLinux extends FileSelectorPlatform { String? initialDirectory, String? confirmButtonText, }) async { + return getDirectoryPathWithOptions( + FileDialogOptions( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + ), + ); + } + + @override + Future getDirectoryPathWithOptions(FileDialogOptions options) async { final List paths = await _hostApi.showFileChooser( PlatformFileChooserActionType.chooseDirectory, PlatformFileChooserOptions( - currentFolderPath: initialDirectory, - acceptButtonLabel: confirmButtonText, + currentFolderPath: options.initialDirectory, + acceptButtonLabel: options.confirmButtonText, + createFolders: options.canCreateDirectories, selectMultiple: false, ), ); @@ -120,11 +132,24 @@ class FileSelectorLinux extends FileSelectorPlatform { String? initialDirectory, String? confirmButtonText, }) async { + return getDirectoryPathsWithOptions( + FileDialogOptions( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + ), + ); + } + + @override + Future> getDirectoryPathsWithOptions( + FileDialogOptions options, + ) async { return _hostApi.showFileChooser( PlatformFileChooserActionType.chooseDirectory, PlatformFileChooserOptions( - currentFolderPath: initialDirectory, - acceptButtonLabel: confirmButtonText, + currentFolderPath: options.initialDirectory, + acceptButtonLabel: options.confirmButtonText, + createFolders: options.canCreateDirectories, selectMultiple: true, ), ); diff --git a/packages/file_selector/file_selector_linux/lib/src/messages.g.dart b/packages/file_selector/file_selector_linux/lib/src/messages.g.dart index 552d0cdd023..4e16f4308dd 100644 --- a/packages/file_selector/file_selector_linux/lib/src/messages.g.dart +++ b/packages/file_selector/file_selector_linux/lib/src/messages.g.dart @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v22.6.2), do not edit directly. +// Autogenerated from Pigeon (v22.7.4), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers @@ -59,6 +59,7 @@ class PlatformFileChooserOptions { this.currentName, this.acceptButtonLabel, this.selectMultiple, + this.createFolders, }); List? allowedFileTypes; @@ -74,6 +75,11 @@ class PlatformFileChooserOptions { /// Nullable because it does not apply to the "save" action. bool? selectMultiple; + /// Whether to allow new folders creation. + /// + /// Nullable because it does not apply to the "open" action. + bool? createFolders; + Object encode() { return [ allowedFileTypes, @@ -81,6 +87,7 @@ class PlatformFileChooserOptions { currentName, acceptButtonLabel, selectMultiple, + createFolders, ]; } @@ -93,6 +100,7 @@ class PlatformFileChooserOptions { currentName: result[2] as String?, acceptButtonLabel: result[3] as String?, selectMultiple: result[4] as bool?, + createFolders: result[5] as bool?, ); } } diff --git a/packages/file_selector/file_selector_linux/linux/file_selector_plugin.cc b/packages/file_selector/file_selector_linux/linux/file_selector_plugin.cc index e87f94d8bad..bd67979272b 100644 --- a/packages/file_selector/file_selector_linux/linux/file_selector_plugin.cc +++ b/packages/file_selector/file_selector_linux/linux/file_selector_plugin.cc @@ -94,6 +94,13 @@ static GtkFileChooserNative* create_dialog( } } + const gboolean* create_folders = + ffs_platform_file_chooser_options_get_create_folders(options); + if (create_folders != nullptr) { + gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dialog), + *create_folders); + } + return GTK_FILE_CHOOSER_NATIVE(g_object_ref(dialog)); } diff --git a/packages/file_selector/file_selector_linux/linux/messages.g.cc b/packages/file_selector/file_selector_linux/linux/messages.g.cc index 596ca836482..9c353408ca0 100644 --- a/packages/file_selector/file_selector_linux/linux/messages.g.cc +++ b/packages/file_selector/file_selector_linux/linux/messages.g.cc @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v22.6.2), do not edit directly. +// Autogenerated from Pigeon (v22.7.4), do not edit directly. // See also: https://pub.dev/packages/pigeon #include "messages.g.h" @@ -84,6 +84,7 @@ struct _FfsPlatformFileChooserOptions { gchar* current_name; gchar* accept_button_label; gboolean* select_multiple; + gboolean* create_folders; }; G_DEFINE_TYPE(FfsPlatformFileChooserOptions, ffs_platform_file_chooser_options, @@ -97,6 +98,7 @@ static void ffs_platform_file_chooser_options_dispose(GObject* object) { g_clear_pointer(&self->current_name, g_free); g_clear_pointer(&self->accept_button_label, g_free); g_clear_pointer(&self->select_multiple, g_free); + g_clear_pointer(&self->create_folders, g_free); G_OBJECT_CLASS(ffs_platform_file_chooser_options_parent_class) ->dispose(object); } @@ -112,7 +114,7 @@ static void ffs_platform_file_chooser_options_class_init( FfsPlatformFileChooserOptions* ffs_platform_file_chooser_options_new( FlValue* allowed_file_types, const gchar* current_folder_path, const gchar* current_name, const gchar* accept_button_label, - gboolean* select_multiple) { + gboolean* select_multiple, gboolean* create_folders) { FfsPlatformFileChooserOptions* self = FFS_PLATFORM_FILE_CHOOSER_OPTIONS( g_object_new(ffs_platform_file_chooser_options_get_type(), nullptr)); if (allowed_file_types != nullptr) { @@ -141,6 +143,12 @@ FfsPlatformFileChooserOptions* ffs_platform_file_chooser_options_new( } else { self->select_multiple = nullptr; } + if (create_folders != nullptr) { + self->create_folders = static_cast(malloc(sizeof(gboolean))); + *self->create_folders = *create_folders; + } else { + self->create_folders = nullptr; + } return self; } @@ -174,6 +182,12 @@ gboolean* ffs_platform_file_chooser_options_get_select_multiple( return self->select_multiple; } +gboolean* ffs_platform_file_chooser_options_get_create_folders( + FfsPlatformFileChooserOptions* self) { + g_return_val_if_fail(FFS_IS_PLATFORM_FILE_CHOOSER_OPTIONS(self), nullptr); + return self->create_folders; +} + static FlValue* ffs_platform_file_chooser_options_to_list( FfsPlatformFileChooserOptions* self) { FlValue* values = fl_value_new_list(); @@ -194,6 +208,9 @@ static FlValue* ffs_platform_file_chooser_options_to_list( fl_value_append_take(values, self->select_multiple != nullptr ? fl_value_new_bool(*self->select_multiple) : fl_value_new_null()); + fl_value_append_take(values, self->create_folders != nullptr + ? fl_value_new_bool(*self->create_folders) + : fl_value_new_null()); return values; } @@ -226,9 +243,16 @@ ffs_platform_file_chooser_options_new_from_list(FlValue* values) { select_multiple_value = fl_value_get_bool(value4); select_multiple = &select_multiple_value; } + FlValue* value5 = fl_value_get_list_value(values, 5); + gboolean* create_folders = nullptr; + gboolean create_folders_value; + if (fl_value_get_type(value5) != FL_VALUE_TYPE_NULL) { + create_folders_value = fl_value_get_bool(value5); + create_folders = &create_folders_value; + } return ffs_platform_file_chooser_options_new( allowed_file_types, current_folder_path, current_name, - accept_button_label, select_multiple); + accept_button_label, select_multiple, create_folders); } struct _FfsMessageCodec { diff --git a/packages/file_selector/file_selector_linux/linux/messages.g.h b/packages/file_selector/file_selector_linux/linux/messages.g.h index d7cd4d8724f..c8d3b869bd4 100644 --- a/packages/file_selector/file_selector_linux/linux/messages.g.h +++ b/packages/file_selector/file_selector_linux/linux/messages.g.h @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v22.6.2), do not edit directly. +// Autogenerated from Pigeon (v22.7.4), do not edit directly. // See also: https://pub.dev/packages/pigeon #ifndef PIGEON_MESSAGES_G_H_ @@ -97,6 +97,7 @@ G_DECLARE_FINAL_TYPE(FfsPlatformFileChooserOptions, * current_name: field in this object. * accept_button_label: field in this object. * select_multiple: field in this object. + * create_folders: field in this object. * * Creates a new #PlatformFileChooserOptions object. * @@ -105,7 +106,7 @@ G_DECLARE_FINAL_TYPE(FfsPlatformFileChooserOptions, FfsPlatformFileChooserOptions* ffs_platform_file_chooser_options_new( FlValue* allowed_file_types, const gchar* current_folder_path, const gchar* current_name, const gchar* accept_button_label, - gboolean* select_multiple); + gboolean* select_multiple, gboolean* create_folders); /** * ffs_platform_file_chooser_options_get_allowed_file_types @@ -164,6 +165,19 @@ const gchar* ffs_platform_file_chooser_options_get_accept_button_label( gboolean* ffs_platform_file_chooser_options_get_select_multiple( FfsPlatformFileChooserOptions* object); +/** + * ffs_platform_file_chooser_options_get_create_folders + * @object: a #FfsPlatformFileChooserOptions. + * + * Whether to allow new folders creation. + * + * Nullable because it does not apply to the "open" action. + * + * Returns: the field value. + */ +gboolean* ffs_platform_file_chooser_options_get_create_folders( + FfsPlatformFileChooserOptions* object); + G_DECLARE_FINAL_TYPE(FfsMessageCodec, ffs_message_codec, FFS, MESSAGE_CODEC, FlStandardMessageCodec) diff --git a/packages/file_selector/file_selector_linux/linux/test/file_selector_plugin_test.cc b/packages/file_selector/file_selector_linux/linux/test/file_selector_plugin_test.cc index 841cc8f7f54..863ba187cf5 100644 --- a/packages/file_selector/file_selector_linux/linux/test/file_selector_plugin_test.cc +++ b/packages/file_selector/file_selector_linux/linux/test/file_selector_plugin_test.cc @@ -28,7 +28,7 @@ static const int platform_type_group_object_id = 130; TEST(FileSelectorPlugin, TestOpenSimple) { g_autoptr(FfsPlatformFileChooserOptions) options = ffs_platform_file_chooser_options_new(nullptr, nullptr, nullptr, nullptr, - nullptr); + nullptr, nullptr); g_autoptr(GtkFileChooserNative) dialog = create_dialog_of_type( nullptr, FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_OPEN, @@ -45,7 +45,7 @@ TEST(FileSelectorPlugin, TestOpenMultiple) { gboolean select_multiple = true; g_autoptr(FfsPlatformFileChooserOptions) options = ffs_platform_file_chooser_options_new(nullptr, nullptr, nullptr, nullptr, - &select_multiple); + &select_multiple, nullptr); g_autoptr(GtkFileChooserNative) dialog = create_dialog_of_type( nullptr, FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_OPEN, @@ -105,7 +105,7 @@ TEST(FileSelectorPlugin, TestOpenWithFilter) { g_autoptr(FfsPlatformFileChooserOptions) options = ffs_platform_file_chooser_options_new(type_groups, nullptr, nullptr, - nullptr, nullptr); + nullptr, nullptr, nullptr); g_autoptr(GtkFileChooserNative) dialog = create_dialog_of_type( nullptr, FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_OPEN, @@ -149,7 +149,7 @@ TEST(FileSelectorPlugin, TestOpenWithFilter) { TEST(FileSelectorPlugin, TestSaveSimple) { g_autoptr(FfsPlatformFileChooserOptions) options = ffs_platform_file_chooser_options_new(nullptr, nullptr, nullptr, nullptr, - nullptr); + nullptr, nullptr); g_autoptr(GtkFileChooserNative) dialog = create_dialog_of_type( nullptr, FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_SAVE, @@ -165,7 +165,7 @@ TEST(FileSelectorPlugin, TestSaveSimple) { TEST(FileSelectorPlugin, TestSaveWithArguments) { g_autoptr(FfsPlatformFileChooserOptions) options = ffs_platform_file_chooser_options_new(nullptr, "/tmp", "foo.txt", nullptr, - nullptr); + nullptr, nullptr); g_autoptr(GtkFileChooserNative) dialog = create_dialog_of_type( nullptr, FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_SAVE, @@ -184,10 +184,48 @@ TEST(FileSelectorPlugin, TestSaveWithArguments) { // doesn't in a test context, so that's not currently validated. } +TEST(FileSelectorPlugin, TestSaveWithCreateFoldersEnabled) { + gboolean create_folders = true; + g_autoptr(FfsPlatformFileChooserOptions) options = + ffs_platform_file_chooser_options_new(nullptr, nullptr, nullptr, nullptr, + nullptr, &create_folders); + + g_autoptr(GtkFileChooserNative) dialog = create_dialog_of_type( + nullptr, FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_SAVE, + options); + + ASSERT_NE(dialog, nullptr); + EXPECT_EQ(gtk_file_chooser_get_action(GTK_FILE_CHOOSER(dialog)), + GTK_FILE_CHOOSER_ACTION_SAVE); + EXPECT_EQ(gtk_file_chooser_get_select_multiple(GTK_FILE_CHOOSER(dialog)), + false); + EXPECT_EQ(gtk_file_chooser_get_create_folders(GTK_FILE_CHOOSER(dialog)), + create_folders); +} + +TEST(FileSelectorPlugin, TestSaveWithCreateFoldersDisabled) { + gboolean create_folders = false; + g_autoptr(FfsPlatformFileChooserOptions) options = + ffs_platform_file_chooser_options_new(nullptr, nullptr, nullptr, nullptr, + nullptr, &create_folders); + + g_autoptr(GtkFileChooserNative) dialog = create_dialog_of_type( + nullptr, FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_SAVE, + options); + + ASSERT_NE(dialog, nullptr); + EXPECT_EQ(gtk_file_chooser_get_action(GTK_FILE_CHOOSER(dialog)), + GTK_FILE_CHOOSER_ACTION_SAVE); + EXPECT_EQ(gtk_file_chooser_get_select_multiple(GTK_FILE_CHOOSER(dialog)), + false); + EXPECT_EQ(gtk_file_chooser_get_create_folders(GTK_FILE_CHOOSER(dialog)), + create_folders); +} + TEST(FileSelectorPlugin, TestGetDirectory) { g_autoptr(FfsPlatformFileChooserOptions) options = ffs_platform_file_chooser_options_new(nullptr, nullptr, nullptr, nullptr, - nullptr); + nullptr, nullptr); g_autoptr(GtkFileChooserNative) dialog = create_dialog_of_type( nullptr, @@ -205,7 +243,7 @@ TEST(FileSelectorPlugin, TestGetMultipleDirectories) { gboolean select_multiple = true; g_autoptr(FfsPlatformFileChooserOptions) options = ffs_platform_file_chooser_options_new(nullptr, nullptr, nullptr, nullptr, - &select_multiple); + &select_multiple, nullptr); g_autoptr(GtkFileChooserNative) dialog = create_dialog_of_type( nullptr, @@ -219,6 +257,42 @@ TEST(FileSelectorPlugin, TestGetMultipleDirectories) { true); } +TEST(FileSelectorPlugin, TestGetDirectoryWithCreateFoldersEnabled) { + gboolean create_folders = true; + g_autoptr(FfsPlatformFileChooserOptions) options = + ffs_platform_file_chooser_options_new(nullptr, nullptr, nullptr, nullptr, + nullptr, &create_folders); + + g_autoptr(GtkFileChooserNative) dialog = create_dialog_of_type( + nullptr, + FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_CHOOSE_DIRECTORY, + options); + + ASSERT_NE(dialog, nullptr); + EXPECT_EQ(gtk_file_chooser_get_action(GTK_FILE_CHOOSER(dialog)), + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); + EXPECT_EQ(gtk_file_chooser_get_create_folders(GTK_FILE_CHOOSER(dialog)), + create_folders); +} + +TEST(FileSelectorPlugin, TestGetDirectoryWithCreateFoldersDisabled) { + gboolean create_folders = false; + g_autoptr(FfsPlatformFileChooserOptions) options = + ffs_platform_file_chooser_options_new(nullptr, nullptr, nullptr, nullptr, + nullptr, &create_folders); + + g_autoptr(GtkFileChooserNative) dialog = create_dialog_of_type( + nullptr, + FILE_SELECTOR_LINUX_PLATFORM_FILE_CHOOSER_ACTION_TYPE_CHOOSE_DIRECTORY, + options); + + ASSERT_NE(dialog, nullptr); + EXPECT_EQ(gtk_file_chooser_get_action(GTK_FILE_CHOOSER(dialog)), + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); + EXPECT_EQ(gtk_file_chooser_get_create_folders(GTK_FILE_CHOOSER(dialog)), + create_folders); +} + static gint mock_run_dialog_cancel(GtkNativeDialog* dialog) { return GTK_RESPONSE_CANCEL; } @@ -226,7 +300,7 @@ static gint mock_run_dialog_cancel(GtkNativeDialog* dialog) { TEST(FileSelectorPlugin, TestGetDirectoryCancel) { g_autoptr(FfsPlatformFileChooserOptions) options = ffs_platform_file_chooser_options_new(nullptr, nullptr, nullptr, nullptr, - nullptr); + nullptr, nullptr); g_autoptr(GtkFileChooserNative) dialog = create_dialog_of_type( nullptr, diff --git a/packages/file_selector/file_selector_linux/pigeons/messages.dart b/packages/file_selector/file_selector_linux/pigeons/messages.dart index 658450c2477..d54dff99118 100644 --- a/packages/file_selector/file_selector_linux/pigeons/messages.dart +++ b/packages/file_selector/file_selector_linux/pigeons/messages.dart @@ -39,6 +39,7 @@ class PlatformFileChooserOptions { required this.currentName, required this.acceptButtonLabel, this.selectMultiple, + this.createFolders, }); final List? allowedFileTypes; @@ -50,6 +51,11 @@ class PlatformFileChooserOptions { /// /// Nullable because it does not apply to the "save" action. final bool? selectMultiple; + + /// Whether to allow new folders creation. + /// + /// Nullable because it does not apply to the "open" action. + final bool? createFolders; } @HostApi() diff --git a/packages/file_selector/file_selector_linux/pubspec.yaml b/packages/file_selector/file_selector_linux/pubspec.yaml index bd085f3a6a8..86940e44203 100644 --- a/packages/file_selector/file_selector_linux/pubspec.yaml +++ b/packages/file_selector/file_selector_linux/pubspec.yaml @@ -2,7 +2,7 @@ name: file_selector_linux description: Liunx implementation of the file_selector plugin. repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_linux issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22 -version: 0.9.3+2 +version: 0.9.4 environment: sdk: ^3.8.0 @@ -18,7 +18,7 @@ flutter: dependencies: cross_file: ^0.3.1 - file_selector_platform_interface: ^2.6.0 + file_selector_platform_interface: ^2.7.0 flutter: sdk: flutter diff --git a/packages/file_selector/file_selector_linux/test/file_selector_linux_test.dart b/packages/file_selector/file_selector_linux/test/file_selector_linux_test.dart index d6ddf3abf37..4f6786b5cfb 100644 --- a/packages/file_selector/file_selector_linux/test/file_selector_linux_test.dart +++ b/packages/file_selector/file_selector_linux/test/file_selector_linux_test.dart @@ -385,6 +385,45 @@ void main() { }); }); + group('getDirectoryPathWithOptions', () { + test('passes the core flags correctly', () async { + const String path = '/foo/bar'; + api.result = [path]; + + expect( + await plugin.getDirectoryPathWithOptions(const FileDialogOptions()), + path, + ); + + expect(api.passedType, PlatformFileChooserActionType.chooseDirectory); + expect(api.passedOptions?.selectMultiple, false); + }); + + test('passes initialDirectory correctly', () async { + const String path = '/example/directory'; + await plugin.getDirectoryPathWithOptions( + const FileDialogOptions(initialDirectory: path), + ); + + expect(api.passedOptions?.currentFolderPath, path); + }); + + test('passes confirmButtonText correctly', () async { + const String button = 'Select Folder'; + await plugin.getDirectoryPathWithOptions( + const FileDialogOptions(confirmButtonText: button), + ); + expect(api.passedOptions?.acceptButtonLabel, button); + }); + + test('passes canCreateDirectories correctly', () async { + await plugin.getDirectoryPathWithOptions( + const FileDialogOptions(canCreateDirectories: true), + ); + expect(api.passedOptions?.createFolders, true); + }); + }); + group('getDirectoryPaths', () { test('passes the core flags correctly', () async { api.result = ['/foo/bar', 'baz']; @@ -415,6 +454,52 @@ void main() { expect(api.passedOptions?.selectMultiple, true); }); }); + + group('getDirectoryPathsWithOptions', () { + test('passes the core flags correctly', () async { + api.result = ['/foo/bar', 'baz']; + + expect( + await plugin.getDirectoryPathsWithOptions(const FileDialogOptions()), + api.result, + ); + + expect(api.passedType, PlatformFileChooserActionType.chooseDirectory); + expect(api.passedOptions?.selectMultiple, true); + }); + + test('passes initialDirectory correctly', () async { + const String path = '/example/directory'; + await plugin.getDirectoryPathsWithOptions( + const FileDialogOptions(initialDirectory: path), + ); + + expect(api.passedOptions?.currentFolderPath, path); + }); + + test('passes confirmButtonText correctly', () async { + const String button = 'Select one or mode folders'; + await plugin.getDirectoryPathsWithOptions( + const FileDialogOptions(confirmButtonText: button), + ); + + expect(api.passedOptions?.acceptButtonLabel, button); + }); + + test('passes canCreateDirectories flag correctly', () async { + await plugin.getDirectoryPathsWithOptions( + const FileDialogOptions(canCreateDirectories: true), + ); + + expect(api.passedOptions?.createFolders, true); + }); + + test('passes multiple flag correctly', () async { + await plugin.getDirectoryPathsWithOptions(const FileDialogOptions()); + + expect(api.passedOptions?.selectMultiple, true); + }); + }); } /// Fake implementation that stores arguments and provides a canned response. diff --git a/packages/file_selector/file_selector_macos/CHANGELOG.md b/packages/file_selector/file_selector_macos/CHANGELOG.md index a2598b73515..dfc98902953 100644 --- a/packages/file_selector/file_selector_macos/CHANGELOG.md +++ b/packages/file_selector/file_selector_macos/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.5 + +* Adds `getDirectoryPathWithOptions` and `getDirectoryPathsWithOptions` implementations. + ## 0.9.4+5 * Updates minimum supported version to macOS 10.15. diff --git a/packages/file_selector/file_selector_macos/example/lib/get_directory_page.dart b/packages/file_selector/file_selector_macos/example/lib/get_directory_page.dart index fbc8d2673d9..edbd299fda2 100644 --- a/packages/file_selector/file_selector_macos/example/lib/get_directory_page.dart +++ b/packages/file_selector/file_selector_macos/example/lib/get_directory_page.dart @@ -14,7 +14,12 @@ class GetDirectoryPage extends StatelessWidget { Future _getDirectoryPath(BuildContext context) async { const String confirmButtonText = 'Choose'; final String? directoryPath = await FileSelectorPlatform.instance - .getDirectoryPath(confirmButtonText: confirmButtonText); + .getDirectoryPathWithOptions( + const FileDialogOptions( + confirmButtonText: confirmButtonText, + canCreateDirectories: true, + ), + ); if (directoryPath == null) { // Operation was canceled by the user. return; diff --git a/packages/file_selector/file_selector_macos/example/lib/get_multiple_directories_page.dart b/packages/file_selector/file_selector_macos/example/lib/get_multiple_directories_page.dart index be1bdfd40a0..c0b32ace41d 100644 --- a/packages/file_selector/file_selector_macos/example/lib/get_multiple_directories_page.dart +++ b/packages/file_selector/file_selector_macos/example/lib/get_multiple_directories_page.dart @@ -14,7 +14,12 @@ class GetMultipleDirectoriesPage extends StatelessWidget { Future _getDirectoryPaths(BuildContext context) async { const String confirmButtonText = 'Choose'; final List directoriesPaths = await FileSelectorPlatform.instance - .getDirectoryPaths(confirmButtonText: confirmButtonText); + .getDirectoryPathsWithOptions( + const FileDialogOptions( + confirmButtonText: confirmButtonText, + canCreateDirectories: true, + ), + ); if (directoriesPaths.isEmpty) { // Operation was canceled by the user. return; diff --git a/packages/file_selector/file_selector_macos/example/macos/Runner.xcodeproj/project.pbxproj b/packages/file_selector/file_selector_macos/example/macos/Runner.xcodeproj/project.pbxproj index ce516fb3512..6797fa22411 100644 --- a/packages/file_selector/file_selector_macos/example/macos/Runner.xcodeproj/project.pbxproj +++ b/packages/file_selector/file_selector_macos/example/macos/Runner.xcodeproj/project.pbxproj @@ -232,6 +232,7 @@ 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, + D670A6A16AFB08D3E6D21B41 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -379,6 +380,23 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + D670A6A16AFB08D3E6D21B41 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/packages/file_selector/file_selector_macos/example/macos/RunnerTests/RunnerTests.swift b/packages/file_selector/file_selector_macos/example/macos/RunnerTests/RunnerTests.swift index 9ef419c9aaa..b68065387a0 100644 --- a/packages/file_selector/file_selector_macos/example/macos/RunnerTests/RunnerTests.swift +++ b/packages/file_selector/file_selector_macos/example/macos/RunnerTests/RunnerTests.swift @@ -330,6 +330,10 @@ class ExampleTests: XCTestCase { wait(for: [called]) XCTAssertNotNil(panelController.savePanel) + if let panel = panelController.savePanel { + // By default, "New Folder" button is visible for Save dialogs + XCTAssertTrue(panel.canCreateDirectories) + } } func testSaveWithArguments() throws { @@ -365,6 +369,35 @@ class ExampleTests: XCTestCase { } } + func testSaveNewFolderHidden() throws { + let panelController = TestPanelController() + let plugin = FileSelectorPlugin( + viewProvider: TestViewProvider(), + panelController: panelController) + + let returnPath = "/foo/bar" + panelController.saveURL = URL(fileURLWithPath: returnPath) + + let called = XCTestExpectation() + let options = SavePanelOptions(canCreateDirectories: false) + + plugin.displaySavePanel(options: options) { result in + switch result { + case .success(let path): + XCTAssertEqual(path, returnPath) + case .failure(let error): + XCTFail("\(error)") + } + called.fulfill() + } + + wait(for: [called]) + XCTAssertNotNil(panelController.savePanel) + if let panel = panelController.savePanel { + XCTAssertFalse(panel.canCreateDirectories) + } + } + func testSaveCancel() throws { let panelController = TestPanelController() let plugin = FileSelectorPlugin( @@ -421,6 +454,8 @@ class ExampleTests: XCTestCase { // The Dart API only allows a single directory to be returned, so users shouldn't be allowed // to select multiple. XCTAssertFalse(panel.allowsMultipleSelection) + // By default, "New Folder" button is hidden for Choose Directory dialogs. + XCTAssertFalse(panel.canCreateDirectories) } } @@ -482,6 +517,8 @@ class ExampleTests: XCTestCase { // For consistency across platforms, file selection is disabled. XCTAssertFalse(panel.canChooseFiles) XCTAssertTrue(panel.allowsMultipleSelection) + // By default, "New Folder" button is hidden for Choose Directory dialogs. + XCTAssertFalse(panel.canCreateDirectories) } } @@ -510,4 +547,37 @@ class ExampleTests: XCTestCase { wait(for: [called]) XCTAssertNotNil(panelController.openPanel) } + + func testGetDirectoryNewFolderVisible() throws { + let panelController = TestPanelController() + let plugin = FileSelectorPlugin( + viewProvider: TestViewProvider(), + panelController: panelController) + + let returnPath = "/foo/bar" + panelController.openURLs = [URL(fileURLWithPath: returnPath)] + + let called = XCTestExpectation() + let options = OpenPanelOptions( + allowsMultipleSelection: false, + canChooseDirectories: true, + canChooseFiles: false, + baseOptions: SavePanelOptions(canCreateDirectories: true)) + + plugin.displayOpenPanel(options: options) { result in + switch result { + case .success(let paths): + XCTAssertEqual(paths[0], returnPath) + case .failure(let error): + XCTFail("\(error)") + } + called.fulfill() + } + + wait(for: [called]) + XCTAssertNotNil(panelController.openPanel) + if let panel = panelController.openPanel { + XCTAssertTrue(panel.canCreateDirectories) + } + } } diff --git a/packages/file_selector/file_selector_macos/example/pubspec.yaml b/packages/file_selector/file_selector_macos/example/pubspec.yaml index 79250222c3c..5c54c86f4af 100644 --- a/packages/file_selector/file_selector_macos/example/pubspec.yaml +++ b/packages/file_selector/file_selector_macos/example/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: .. - file_selector_platform_interface: ^2.6.0 + file_selector_platform_interface: ^2.7.0 flutter: sdk: flutter diff --git a/packages/file_selector/file_selector_macos/lib/file_selector_macos.dart b/packages/file_selector/file_selector_macos/lib/file_selector_macos.dart index 9b18cc88ac3..dbcbd345fc2 100644 --- a/packages/file_selector/file_selector_macos/lib/file_selector_macos.dart +++ b/packages/file_selector/file_selector_macos/lib/file_selector_macos.dart @@ -91,6 +91,7 @@ class FileSelectorMacOS extends FileSelectorPlatform { directoryPath: options.initialDirectory, nameFieldStringValue: options.suggestedName, prompt: options.confirmButtonText, + canCreateDirectories: options.canCreateDirectories, ), ); return path == null ? null : FileSaveLocation(path); @@ -101,14 +102,25 @@ class FileSelectorMacOS extends FileSelectorPlatform { String? initialDirectory, String? confirmButtonText, }) async { + return getDirectoryPathWithOptions( + FileDialogOptions( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + ), + ); + } + + @override + Future getDirectoryPathWithOptions(FileDialogOptions options) async { final List paths = await _hostApi.displayOpenPanel( OpenPanelOptions( allowsMultipleSelection: false, canChooseDirectories: true, canChooseFiles: false, baseOptions: SavePanelOptions( - directoryPath: initialDirectory, - prompt: confirmButtonText, + directoryPath: options.initialDirectory, + prompt: options.confirmButtonText, + canCreateDirectories: options.canCreateDirectories, ), ), ); @@ -120,14 +132,27 @@ class FileSelectorMacOS extends FileSelectorPlatform { String? initialDirectory, String? confirmButtonText, }) async { + return getDirectoryPathsWithOptions( + FileDialogOptions( + initialDirectory: initialDirectory, + confirmButtonText: confirmButtonText, + ), + ); + } + + @override + Future> getDirectoryPathsWithOptions( + FileDialogOptions options, + ) async { final List paths = await _hostApi.displayOpenPanel( OpenPanelOptions( allowsMultipleSelection: true, canChooseDirectories: true, canChooseFiles: false, baseOptions: SavePanelOptions( - directoryPath: initialDirectory, - prompt: confirmButtonText, + directoryPath: options.initialDirectory, + prompt: options.confirmButtonText, + canCreateDirectories: options.canCreateDirectories, ), ), ); diff --git a/packages/file_selector/file_selector_macos/lib/src/messages.g.dart b/packages/file_selector/file_selector_macos/lib/src/messages.g.dart index d41b0cd24c0..21c2dd6336d 100644 --- a/packages/file_selector/file_selector_macos/lib/src/messages.g.dart +++ b/packages/file_selector/file_selector_macos/lib/src/messages.g.dart @@ -108,6 +108,7 @@ class SavePanelOptions { this.directoryPath, this.nameFieldStringValue, this.prompt, + this.canCreateDirectories, }); AllowedTypes? allowedFileTypes; @@ -118,12 +119,15 @@ class SavePanelOptions { String? prompt; + bool? canCreateDirectories; + List _toList() { return [ allowedFileTypes, directoryPath, nameFieldStringValue, prompt, + canCreateDirectories, ]; } @@ -138,6 +142,7 @@ class SavePanelOptions { directoryPath: result[1] as String?, nameFieldStringValue: result[2] as String?, prompt: result[3] as String?, + canCreateDirectories: result[4] as bool?, ); } diff --git a/packages/file_selector/file_selector_macos/macos/file_selector_macos/Sources/file_selector_macos/FileSelectorPlugin.swift b/packages/file_selector/file_selector_macos/macos/file_selector_macos/Sources/file_selector_macos/FileSelectorPlugin.swift index d35266df096..9fbee4489df 100644 --- a/packages/file_selector/file_selector_macos/macos/file_selector_macos/Sources/file_selector_macos/FileSelectorPlugin.swift +++ b/packages/file_selector/file_selector_macos/macos/file_selector_macos/Sources/file_selector_macos/FileSelectorPlugin.swift @@ -128,6 +128,10 @@ public class FileSelectorPlugin: NSObject, FlutterPlugin, FileSelectorApi { } } } + + if let canCreateDirectories = options.canCreateDirectories { + panel.canCreateDirectories = canCreateDirectories + } } /// Configures an NSOpenPanel based on channel method call arguments. diff --git a/packages/file_selector/file_selector_macos/macos/file_selector_macos/Sources/file_selector_macos/messages.g.swift b/packages/file_selector/file_selector_macos/macos/file_selector_macos/Sources/file_selector_macos/messages.g.swift index 068365ed0f9..51e1aa3a8be 100644 --- a/packages/file_selector/file_selector_macos/macos/file_selector_macos/Sources/file_selector_macos/messages.g.swift +++ b/packages/file_selector/file_selector_macos/macos/file_selector_macos/Sources/file_selector_macos/messages.g.swift @@ -175,6 +175,7 @@ struct SavePanelOptions: Hashable { var directoryPath: String? = nil var nameFieldStringValue: String? = nil var prompt: String? = nil + var canCreateDirectories: Bool? = nil // swift-format-ignore: AlwaysUseLowerCamelCase static func fromList(_ pigeonVar_list: [Any?]) -> SavePanelOptions? { @@ -182,12 +183,14 @@ struct SavePanelOptions: Hashable { let directoryPath: String? = nilOrValue(pigeonVar_list[1]) let nameFieldStringValue: String? = nilOrValue(pigeonVar_list[2]) let prompt: String? = nilOrValue(pigeonVar_list[3]) + let canCreateDirectories: Bool? = nilOrValue(pigeonVar_list[4]) return SavePanelOptions( allowedFileTypes: allowedFileTypes, directoryPath: directoryPath, nameFieldStringValue: nameFieldStringValue, - prompt: prompt + prompt: prompt, + canCreateDirectories: canCreateDirectories ) } func toList() -> [Any?] { @@ -196,6 +199,7 @@ struct SavePanelOptions: Hashable { directoryPath, nameFieldStringValue, prompt, + canCreateDirectories, ] } static func == (lhs: SavePanelOptions, rhs: SavePanelOptions) -> Bool { diff --git a/packages/file_selector/file_selector_macos/pigeons/messages.dart b/packages/file_selector/file_selector_macos/pigeons/messages.dart index 8da0ef9fd26..e65780f0c20 100644 --- a/packages/file_selector/file_selector_macos/pigeons/messages.dart +++ b/packages/file_selector/file_selector_macos/pigeons/messages.dart @@ -35,11 +35,13 @@ class SavePanelOptions { this.directoryPath, this.nameFieldStringValue, this.prompt, + this.canCreateDirectories, }); final AllowedTypes? allowedFileTypes; final String? directoryPath; final String? nameFieldStringValue; final String? prompt; + final bool? canCreateDirectories; } /// Options for open panels. diff --git a/packages/file_selector/file_selector_macos/pubspec.yaml b/packages/file_selector/file_selector_macos/pubspec.yaml index 02f0c7ed5e6..8c75441b54f 100644 --- a/packages/file_selector/file_selector_macos/pubspec.yaml +++ b/packages/file_selector/file_selector_macos/pubspec.yaml @@ -2,7 +2,7 @@ name: file_selector_macos description: macOS implementation of the file_selector plugin. repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_macos issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22 -version: 0.9.4+5 +version: 0.9.5 environment: sdk: ^3.9.0 @@ -18,7 +18,7 @@ flutter: dependencies: cross_file: ^0.3.1 - file_selector_platform_interface: ^2.6.0 + file_selector_platform_interface: ^2.7.0 flutter: sdk: flutter diff --git a/packages/file_selector/file_selector_macos/test/file_selector_macos_test.dart b/packages/file_selector/file_selector_macos/test/file_selector_macos_test.dart index edd4c2e2d7f..1a8d3bfcc11 100644 --- a/packages/file_selector/file_selector_macos/test/file_selector_macos_test.dart +++ b/packages/file_selector/file_selector_macos/test/file_selector_macos_test.dart @@ -485,6 +485,62 @@ void main() { }); }); + group('getDirectoryPathWithOptions', () { + test('works as expected with no arguments', () async { + api.result = ['foo']; + + final String? path = await plugin.getDirectoryPathWithOptions( + const FileDialogOptions(), + ); + + expect(path, 'foo'); + final OpenPanelOptions options = api.passedOpenPanelOptions!; + expect(options.allowsMultipleSelection, false); + expect(options.canChooseFiles, false); + expect(options.canChooseDirectories, true); + expect(options.baseOptions.allowedFileTypes, null); + expect(options.baseOptions.directoryPath, null); + expect(options.baseOptions.nameFieldStringValue, null); + expect(options.baseOptions.canCreateDirectories, null); + expect(options.baseOptions.prompt, null); + }); + + test('handles cancel', () async { + api.result = []; + + final String? path = await plugin.getDirectoryPath(); + + expect(path, null); + }); + + test('passes initialDirectory correctly', () async { + await plugin.getDirectoryPathWithOptions( + const FileDialogOptions(initialDirectory: '/example/directory'), + ); + + final OpenPanelOptions options = api.passedOpenPanelOptions!; + expect(options.baseOptions.directoryPath, '/example/directory'); + }); + + test('passes confirmButtonText correctly', () async { + await plugin.getDirectoryPathWithOptions( + const FileDialogOptions(confirmButtonText: 'Open File'), + ); + + final OpenPanelOptions options = api.passedOpenPanelOptions!; + expect(options.baseOptions.prompt, 'Open File'); + }); + + test('passes canCreateDirectories correctly', () async { + await plugin.getDirectoryPathWithOptions( + const FileDialogOptions(canCreateDirectories: false), + ); + + final OpenPanelOptions options = api.passedOpenPanelOptions!; + expect(options.baseOptions.canCreateDirectories, false); + }); + }); + group('getDirectoryPaths', () { test('works as expected with no arguments', () async { api.result = [ @@ -532,6 +588,72 @@ void main() { expect(options.baseOptions.directoryPath, '/example/directory'); }); }); + + group('getDirectoryPathsWithOptions', () { + test('works as expected with no arguments', () async { + api.result = [ + 'firstDirectory', + 'secondDirectory', + 'thirdDirectory', + ]; + + final List path = await plugin.getDirectoryPathsWithOptions( + const FileDialogOptions(), + ); + + expect(path, [ + 'firstDirectory', + 'secondDirectory', + 'thirdDirectory', + ]); + final OpenPanelOptions options = api.passedOpenPanelOptions!; + expect(options.allowsMultipleSelection, true); + expect(options.canChooseFiles, false); + expect(options.canChooseDirectories, true); + expect(options.baseOptions.allowedFileTypes, null); + expect(options.baseOptions.directoryPath, null); + expect(options.baseOptions.nameFieldStringValue, null); + expect(options.baseOptions.canCreateDirectories, null); + expect(options.baseOptions.prompt, null); + }); + + test('handles cancel', () async { + api.result = []; + + final List paths = await plugin.getDirectoryPathsWithOptions( + const FileDialogOptions(), + ); + + expect(paths, []); + }); + + test('passes confirmButtonText correctly', () async { + await plugin.getDirectoryPathsWithOptions( + const FileDialogOptions(confirmButtonText: 'Select directories'), + ); + + final OpenPanelOptions options = api.passedOpenPanelOptions!; + expect(options.baseOptions.prompt, 'Select directories'); + }); + + test('passes initialDirectory correctly', () async { + await plugin.getDirectoryPathsWithOptions( + const FileDialogOptions(initialDirectory: '/example/directory'), + ); + + final OpenPanelOptions options = api.passedOpenPanelOptions!; + expect(options.baseOptions.directoryPath, '/example/directory'); + }); + + test('passes canCreateDirectories correctly', () async { + await plugin.getDirectoryPathsWithOptions( + const FileDialogOptions(canCreateDirectories: false), + ); + + final OpenPanelOptions options = api.passedOpenPanelOptions!; + expect(options.baseOptions.canCreateDirectories, false); + }); + }); } /// Fake implementation that stores arguments and provides a canned response. From 88e63d1070edc3d67e1d2870feb71f6e492f8b7b Mon Sep 17 00:00:00 2001 From: Daniel Ferreira Date: Wed, 19 Nov 2025 01:04:36 -0300 Subject: [PATCH 2/5] update pigeon --- .../file_selector_linux/lib/src/messages.g.dart | 16 +++++++++++----- .../file_selector_linux/linux/messages.g.cc | 2 +- .../file_selector_linux/linux/messages.g.h | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/file_selector/file_selector_linux/lib/src/messages.g.dart b/packages/file_selector/file_selector_linux/lib/src/messages.g.dart index 69ce3d48065..68b649d1fa4 100644 --- a/packages/file_selector/file_selector_linux/lib/src/messages.g.dart +++ b/packages/file_selector/file_selector_linux/lib/src/messages.g.dart @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v26.1.0), do not edit directly. +// Autogenerated from Pigeon (v26.1.1), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers @@ -113,6 +113,11 @@ class PlatformFileChooserOptions { /// Nullable because it does not apply to the "save" action. bool? selectMultiple; + /// Whether to allow new folders creation. + /// + /// Nullable because it does not apply to the "open" action. + bool? createFolders; + List _toList() { return [ allowedFileTypes, @@ -131,8 +136,8 @@ class PlatformFileChooserOptions { static PlatformFileChooserOptions decode(Object result) { result as List; return PlatformFileChooserOptions( - allowedFileTypes: - (result[0] as List?)?.cast(), + allowedFileTypes: (result[0] as List?) + ?.cast(), currentFolderPath: result[1] as String?, currentName: result[2] as String?, acceptButtonLabel: result[3] as String?, @@ -206,8 +211,9 @@ class FileSelectorApi { BinaryMessenger? binaryMessenger, String messageChannelSuffix = '', }) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); diff --git a/packages/file_selector/file_selector_linux/linux/messages.g.cc b/packages/file_selector/file_selector_linux/linux/messages.g.cc index 3662a192de8..5788006d77d 100644 --- a/packages/file_selector/file_selector_linux/linux/messages.g.cc +++ b/packages/file_selector/file_selector_linux/linux/messages.g.cc @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v26.1.0), do not edit directly. +// Autogenerated from Pigeon (v26.1.1), do not edit directly. // See also: https://pub.dev/packages/pigeon #include "messages.g.h" diff --git a/packages/file_selector/file_selector_linux/linux/messages.g.h b/packages/file_selector/file_selector_linux/linux/messages.g.h index 792dffd415b..64bbc2ee7b7 100644 --- a/packages/file_selector/file_selector_linux/linux/messages.g.h +++ b/packages/file_selector/file_selector_linux/linux/messages.g.h @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v26.1.0), do not edit directly. +// Autogenerated from Pigeon (v26.1.1), do not edit directly. // See also: https://pub.dev/packages/pigeon #ifndef PIGEON_MESSAGES_G_H_ From 2fbd48c166a1d251bb9c4476d15721779f904cfa Mon Sep 17 00:00:00 2001 From: Daniel Ferreira Date: Wed, 19 Nov 2025 01:04:54 -0300 Subject: [PATCH 3/5] run format --- .../file_selector_android/example/lib/main.dart | 4 ++-- .../example/lib/get_multiple_directories_page.dart | 4 ++-- .../file_selector_linux/example/lib/home_page.dart | 4 ++-- .../file_selector_linux/example/lib/main.dart | 8 ++++---- .../example/lib/open_multiple_images_page.dart | 7 ++++--- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/file_selector/file_selector_android/example/lib/main.dart b/packages/file_selector/file_selector_android/example/lib/main.dart index b69b4c1e4e9..1a2362dc1e1 100644 --- a/packages/file_selector/file_selector_android/example/lib/main.dart +++ b/packages/file_selector/file_selector_android/example/lib/main.dart @@ -40,8 +40,8 @@ class MyApp extends StatelessWidget { home: const HomePage(), routes: { '/open/image': (BuildContext context) => const OpenImagePage(), - '/open/images': (BuildContext context) => - const OpenMultipleImagesPage(), + '/open/images': + (BuildContext context) => const OpenMultipleImagesPage(), '/open/text': (BuildContext context) => const OpenTextPage(), }, ); diff --git a/packages/file_selector/file_selector_linux/example/lib/get_multiple_directories_page.dart b/packages/file_selector/file_selector_linux/example/lib/get_multiple_directories_page.dart index fe7fd3d2416..0c5297313d2 100644 --- a/packages/file_selector/file_selector_linux/example/lib/get_multiple_directories_page.dart +++ b/packages/file_selector/file_selector_linux/example/lib/get_multiple_directories_page.dart @@ -22,8 +22,8 @@ class GetMultipleDirectoriesPage extends StatelessWidget { if (context.mounted) { await showDialog( context: context, - builder: (BuildContext context) => - TextDisplay(directoryPaths.join('\n')), + builder: + (BuildContext context) => TextDisplay(directoryPaths.join('\n')), ); } } diff --git a/packages/file_selector/file_selector_linux/example/lib/home_page.dart b/packages/file_selector/file_selector_linux/example/lib/home_page.dart index b49884852ba..a4e6f828876 100644 --- a/packages/file_selector/file_selector_linux/example/lib/home_page.dart +++ b/packages/file_selector/file_selector_linux/example/lib/home_page.dart @@ -54,8 +54,8 @@ class HomePage extends StatelessWidget { ElevatedButton( style: style, child: const Text('Open a get directories dialog'), - onPressed: () => - Navigator.pushNamed(context, '/multi-directories'), + onPressed: + () => Navigator.pushNamed(context, '/multi-directories'), ), ], ), diff --git a/packages/file_selector/file_selector_linux/example/lib/main.dart b/packages/file_selector/file_selector_linux/example/lib/main.dart index 28a34200274..f1d207839e6 100644 --- a/packages/file_selector/file_selector_linux/example/lib/main.dart +++ b/packages/file_selector/file_selector_linux/example/lib/main.dart @@ -32,13 +32,13 @@ class MyApp extends StatelessWidget { home: const HomePage(), routes: { '/open/image': (BuildContext context) => const OpenImagePage(), - '/open/images': (BuildContext context) => - const OpenMultipleImagesPage(), + '/open/images': + (BuildContext context) => const OpenMultipleImagesPage(), '/open/text': (BuildContext context) => const OpenTextPage(), '/save/text': (BuildContext context) => SaveTextPage(), '/directory': (BuildContext context) => const GetDirectoryPage(), - '/multi-directories': (BuildContext context) => - const GetMultipleDirectoriesPage(), + '/multi-directories': + (BuildContext context) => const GetMultipleDirectoriesPage(), }, ); } diff --git a/packages/file_selector/file_selector_linux/example/lib/open_multiple_images_page.dart b/packages/file_selector/file_selector_linux/example/lib/open_multiple_images_page.dart index 0b9fe352516..1b11e49391f 100644 --- a/packages/file_selector/file_selector_linux/example/lib/open_multiple_images_page.dart +++ b/packages/file_selector/file_selector_linux/example/lib/open_multiple_images_page.dart @@ -80,9 +80,10 @@ class MultipleImagesDisplay extends StatelessWidget { children: [ ...files.map( (XFile file) => Flexible( - child: kIsWeb - ? Image.network(file.path) - : Image.file(File(file.path)), + child: + kIsWeb + ? Image.network(file.path) + : Image.file(File(file.path)), ), ), ], From 313213e772fb0db09417f4a50df100f3c74aa94d Mon Sep 17 00:00:00 2001 From: Daniel Ferreira Date: Thu, 20 Nov 2025 21:03:17 -0300 Subject: [PATCH 4/5] force format --- .../file_selector_android/example/lib/main.dart | 4 ++-- .../example/lib/get_multiple_directories_page.dart | 4 ++-- .../file_selector_linux/example/lib/home_page.dart | 4 ++-- .../file_selector_linux/example/lib/main.dart | 8 ++++---- .../example/lib/open_multiple_images_page.dart | 7 +++---- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/file_selector/file_selector_android/example/lib/main.dart b/packages/file_selector/file_selector_android/example/lib/main.dart index 1a2362dc1e1..b69b4c1e4e9 100644 --- a/packages/file_selector/file_selector_android/example/lib/main.dart +++ b/packages/file_selector/file_selector_android/example/lib/main.dart @@ -40,8 +40,8 @@ class MyApp extends StatelessWidget { home: const HomePage(), routes: { '/open/image': (BuildContext context) => const OpenImagePage(), - '/open/images': - (BuildContext context) => const OpenMultipleImagesPage(), + '/open/images': (BuildContext context) => + const OpenMultipleImagesPage(), '/open/text': (BuildContext context) => const OpenTextPage(), }, ); diff --git a/packages/file_selector/file_selector_linux/example/lib/get_multiple_directories_page.dart b/packages/file_selector/file_selector_linux/example/lib/get_multiple_directories_page.dart index 0c5297313d2..fe7fd3d2416 100644 --- a/packages/file_selector/file_selector_linux/example/lib/get_multiple_directories_page.dart +++ b/packages/file_selector/file_selector_linux/example/lib/get_multiple_directories_page.dart @@ -22,8 +22,8 @@ class GetMultipleDirectoriesPage extends StatelessWidget { if (context.mounted) { await showDialog( context: context, - builder: - (BuildContext context) => TextDisplay(directoryPaths.join('\n')), + builder: (BuildContext context) => + TextDisplay(directoryPaths.join('\n')), ); } } diff --git a/packages/file_selector/file_selector_linux/example/lib/home_page.dart b/packages/file_selector/file_selector_linux/example/lib/home_page.dart index a4e6f828876..b49884852ba 100644 --- a/packages/file_selector/file_selector_linux/example/lib/home_page.dart +++ b/packages/file_selector/file_selector_linux/example/lib/home_page.dart @@ -54,8 +54,8 @@ class HomePage extends StatelessWidget { ElevatedButton( style: style, child: const Text('Open a get directories dialog'), - onPressed: - () => Navigator.pushNamed(context, '/multi-directories'), + onPressed: () => + Navigator.pushNamed(context, '/multi-directories'), ), ], ), diff --git a/packages/file_selector/file_selector_linux/example/lib/main.dart b/packages/file_selector/file_selector_linux/example/lib/main.dart index f1d207839e6..28a34200274 100644 --- a/packages/file_selector/file_selector_linux/example/lib/main.dart +++ b/packages/file_selector/file_selector_linux/example/lib/main.dart @@ -32,13 +32,13 @@ class MyApp extends StatelessWidget { home: const HomePage(), routes: { '/open/image': (BuildContext context) => const OpenImagePage(), - '/open/images': - (BuildContext context) => const OpenMultipleImagesPage(), + '/open/images': (BuildContext context) => + const OpenMultipleImagesPage(), '/open/text': (BuildContext context) => const OpenTextPage(), '/save/text': (BuildContext context) => SaveTextPage(), '/directory': (BuildContext context) => const GetDirectoryPage(), - '/multi-directories': - (BuildContext context) => const GetMultipleDirectoriesPage(), + '/multi-directories': (BuildContext context) => + const GetMultipleDirectoriesPage(), }, ); } diff --git a/packages/file_selector/file_selector_linux/example/lib/open_multiple_images_page.dart b/packages/file_selector/file_selector_linux/example/lib/open_multiple_images_page.dart index 1b11e49391f..0b9fe352516 100644 --- a/packages/file_selector/file_selector_linux/example/lib/open_multiple_images_page.dart +++ b/packages/file_selector/file_selector_linux/example/lib/open_multiple_images_page.dart @@ -80,10 +80,9 @@ class MultipleImagesDisplay extends StatelessWidget { children: [ ...files.map( (XFile file) => Flexible( - child: - kIsWeb - ? Image.network(file.path) - : Image.file(File(file.path)), + child: kIsWeb + ? Image.network(file.path) + : Image.file(File(file.path)), ), ), ], From 9cf6256902ce7c59d9bcb12442964ebeeda0c6d9 Mon Sep 17 00:00:00 2001 From: Daniel Ferreira Date: Thu, 20 Nov 2025 21:09:15 -0300 Subject: [PATCH 5/5] fix description --- .../file_selector/file_selector_linux/lib/src/messages.g.dart | 2 +- packages/file_selector/file_selector_linux/linux/messages.g.h | 2 +- .../file_selector/file_selector_linux/pigeons/messages.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/file_selector/file_selector_linux/lib/src/messages.g.dart b/packages/file_selector/file_selector_linux/lib/src/messages.g.dart index 68b649d1fa4..592db0366e3 100644 --- a/packages/file_selector/file_selector_linux/lib/src/messages.g.dart +++ b/packages/file_selector/file_selector_linux/lib/src/messages.g.dart @@ -113,7 +113,7 @@ class PlatformFileChooserOptions { /// Nullable because it does not apply to the "save" action. bool? selectMultiple; - /// Whether to allow new folders creation. + /// Whether to allow new folder creation. /// /// Nullable because it does not apply to the "open" action. bool? createFolders; diff --git a/packages/file_selector/file_selector_linux/linux/messages.g.h b/packages/file_selector/file_selector_linux/linux/messages.g.h index 64bbc2ee7b7..3d5c8c65806 100644 --- a/packages/file_selector/file_selector_linux/linux/messages.g.h +++ b/packages/file_selector/file_selector_linux/linux/messages.g.h @@ -169,7 +169,7 @@ gboolean* ffs_platform_file_chooser_options_get_select_multiple( * ffs_platform_file_chooser_options_get_create_folders * @object: a #FfsPlatformFileChooserOptions. * - * Whether to allow new folders creation. + * Whether to allow new folder creation. * * Nullable because it does not apply to the "open" action. * diff --git a/packages/file_selector/file_selector_linux/pigeons/messages.dart b/packages/file_selector/file_selector_linux/pigeons/messages.dart index d54dff99118..e700c6ae5bf 100644 --- a/packages/file_selector/file_selector_linux/pigeons/messages.dart +++ b/packages/file_selector/file_selector_linux/pigeons/messages.dart @@ -52,7 +52,7 @@ class PlatformFileChooserOptions { /// Nullable because it does not apply to the "save" action. final bool? selectMultiple; - /// Whether to allow new folders creation. + /// Whether to allow new folder creation. /// /// Nullable because it does not apply to the "open" action. final bool? createFolders;