From de10ce6c2333a468f156145dbdef25cfd8b66aa4 Mon Sep 17 00:00:00 2001 From: rajumuliyashiya <24muliyashiya@gmail.com> Date: Tue, 11 Apr 2023 13:27:27 +0530 Subject: [PATCH 01/13] Fix-[FileSelector][web] openFiles never returns when user presses "cancel" in system UI file picker #121328 --- .../file_selector_web/lib/src/dom_helper.dart | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart index 1c3442f8dab..c84828244b1 100644 --- a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart +++ b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart @@ -28,6 +28,7 @@ class DomHelper { final Completer> completer = Completer>(); final FileUploadInputElement inputElement = input ?? FileUploadInputElement(); + bool changeEventTriggered = false; _container.children.add( inputElement @@ -39,6 +40,7 @@ class DomHelper { final List files = inputElement.files!.map(_convertFileToXFile).toList(); inputElement.remove(); + changeEventTriggered = true; completer.complete(files); }); @@ -52,6 +54,19 @@ class DomHelper { completer.completeError(platformException); }); + void cancelledEventListener(Event e) { + window.removeEventListener('focus', cancelledEventListener); + Future.delayed(const Duration(milliseconds: 500)).then((_) { + if (!changeEventTriggered && multiple) { + inputElement.remove(); + changeEventTriggered = true; + completer.complete([]); + } + }); + } + + window.addEventListener('focus', cancelledEventListener); + inputElement.click(); return completer.future; From eb833efaeee31cafc45db0156e147d8f2cf74d4a Mon Sep 17 00:00:00 2001 From: rajumuliyashiya <24muliyashiya@gmail.com> Date: Tue, 11 Apr 2023 15:25:41 +0530 Subject: [PATCH 02/13] version bump 0.9.0+5 --- packages/file_selector/file_selector_web/CHANGELOG.md | 4 ++++ packages/file_selector/file_selector_web/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/file_selector/file_selector_web/CHANGELOG.md b/packages/file_selector/file_selector_web/CHANGELOG.md index 073f1c20ed8..b6cfde3d085 100644 --- a/packages/file_selector/file_selector_web/CHANGELOG.md +++ b/packages/file_selector/file_selector_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.2 + +* Adds and propagates `cancel` event on file selection. + ## 0.9.1 * Adds `getSaveLocation` and deprecates `getSavePath`. diff --git a/packages/file_selector/file_selector_web/pubspec.yaml b/packages/file_selector/file_selector_web/pubspec.yaml index 81ba11a9634..a34e9c75548 100644 --- a/packages/file_selector/file_selector_web/pubspec.yaml +++ b/packages/file_selector/file_selector_web/pubspec.yaml @@ -2,7 +2,7 @@ name: file_selector_web description: Web platform implementation of file_selector repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_web issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22 -version: 0.9.1 +version: 0.9.2 environment: sdk: ">=2.18.0 <4.0.0" From eeafb5ce070081f11a3c5023c2e315eb0001272d Mon Sep 17 00:00:00 2001 From: rajumuliyashiya <24muliyashiya@gmail.com> Date: Wed, 10 May 2023 20:36:44 +0530 Subject: [PATCH 03/13] changes as per requested --- .../file_selector_web/lib/src/dom_helper.dart | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart index c84828244b1..5eff3c65de4 100644 --- a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart +++ b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart @@ -28,7 +28,6 @@ class DomHelper { final Completer> completer = Completer>(); final FileUploadInputElement inputElement = input ?? FileUploadInputElement(); - bool changeEventTriggered = false; _container.children.add( inputElement @@ -40,7 +39,6 @@ class DomHelper { final List files = inputElement.files!.map(_convertFileToXFile).toList(); inputElement.remove(); - changeEventTriggered = true; completer.complete(files); }); @@ -54,18 +52,11 @@ class DomHelper { completer.completeError(platformException); }); - void cancelledEventListener(Event e) { - window.removeEventListener('focus', cancelledEventListener); - Future.delayed(const Duration(milliseconds: 500)).then((_) { - if (!changeEventTriggered && multiple) { - inputElement.remove(); - changeEventTriggered = true; - completer.complete([]); - } - }); - } - - window.addEventListener('focus', cancelledEventListener); + inputElement.addEventListener('cancel', (_){ + print('cancel click'); + inputElement.remove(); + completer.complete([]); + }); inputElement.click(); From 3f9ce2e82e98a6c50e8c9464f090c39604fb2785 Mon Sep 17 00:00:00 2001 From: rajumuliyashiya <24muliyashiya@gmail.com> Date: Thu, 11 May 2023 11:30:09 +0530 Subject: [PATCH 04/13] removed print statement --- packages/file_selector/file_selector_web/lib/src/dom_helper.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart index 5eff3c65de4..76e7e725524 100644 --- a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart +++ b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart @@ -53,7 +53,6 @@ class DomHelper { }); inputElement.addEventListener('cancel', (_){ - print('cancel click'); inputElement.remove(); completer.complete([]); }); From ce4bde46c61b2752057e24ab36b48ea4a04bafd7 Mon Sep 17 00:00:00 2001 From: rajumuliyashiya <24muliyashiya@gmail.com> Date: Fri, 12 May 2023 12:45:24 +0530 Subject: [PATCH 05/13] conflict resolved --- .../file_selector/file_selector_web/lib/src/dom_helper.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart index 76e7e725524..15cb480e5c6 100644 --- a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart +++ b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart @@ -52,7 +52,7 @@ class DomHelper { completer.completeError(platformException); }); - inputElement.addEventListener('cancel', (_){ + inputElement.addEventListener('cancel', (Event event) { inputElement.remove(); completer.complete([]); }); From c8101e6052a79a3491cc353d0df70a0546747b2a Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 11 Jul 2023 17:54:28 -0700 Subject: [PATCH 06/13] Add note about showPicker API. --- packages/file_selector/file_selector_web/lib/src/dom_helper.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart index 15cb480e5c6..e600778b7dc 100644 --- a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart +++ b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart @@ -57,6 +57,7 @@ class DomHelper { completer.complete([]); }); + // TODO(dit): Reimplement this with the showPicker() API, https://github.com/flutter/flutter/issues/130365 inputElement.click(); return completer.future; From 9ebad61b3700e59ae53eeba754b63eb2c7c328b8 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 11 Jul 2023 17:55:10 -0700 Subject: [PATCH 07/13] openFile now returns null when no files are selected, following the API. --- .../file_selector_web/lib/file_selector_web.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/file_selector/file_selector_web/lib/file_selector_web.dart b/packages/file_selector/file_selector_web/lib/file_selector_web.dart index 2380e274c46..53e0c6d5ab3 100644 --- a/packages/file_selector/file_selector_web/lib/file_selector_web.dart +++ b/packages/file_selector/file_selector_web/lib/file_selector_web.dart @@ -29,14 +29,14 @@ class FileSelectorWeb extends FileSelectorPlatform { } @override - Future openFile({ + Future openFile({ List? acceptedTypeGroups, String? initialDirectory, String? confirmButtonText, }) async { final List files = await _openFiles(acceptedTypeGroups: acceptedTypeGroups); - return files.first; + return files.isNotEmpty ? files.first : null; } @override From 7e83a4ca6d3368cff40febf1e6003b3c6ff2bce6 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 11 Jul 2023 17:57:08 -0700 Subject: [PATCH 08/13] Test simulating a cancel event. --- .../integration_test/dom_helper_test.dart | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart b/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart index ee1af8cb62f..d6cb47fe45b 100644 --- a/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart +++ b/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart @@ -21,9 +21,17 @@ void main() { return dataTransfer.files as FileList?; } - void setFilesAndTriggerChange(List files) { + void setFilesAndTriggerEvent(List files, Event event) { input.files = createFileList(files); - input.dispatchEvent(Event('change')); + input.dispatchEvent(event); + } + + void setFilesAndTriggerChange(List files) { + setFilesAndTriggerEvent(files, Event('change')); + } + + void setFilesAndTriggerCancel(List files) { + setFilesAndTriggerEvent(files, Event('cancel')); } setUp(() { @@ -57,6 +65,18 @@ void main() { expect(await files[1].lastModified(), isNotNull); }); + testWidgets('"cancel" returns an empty selection', (_) async { + final Future> futureFiles = domHelper.getFiles( + input: input, + ); + + setFilesAndTriggerCancel([mockFile1, mockFile2]); + + final List files = await futureFiles; + + expect(files.length, 0); + }); + testWidgets('works multiple times', (_) async { Future> futureFiles; List files; From 1a24e818e30e2c14db0c91bcf44c909f77a8f85f Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 11 Jul 2023 17:57:27 -0700 Subject: [PATCH 09/13] Test return null behavior. --- .../file_selector_web_test.dart | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart b/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart index 664c40871f4..f64c08de056 100644 --- a/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart +++ b/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart @@ -33,14 +33,30 @@ void main() { webWildCards: ['image/*'], ); - final XFile file = + final XFile? file = await plugin.openFile(acceptedTypeGroups: [typeGroup]); - expect(file.name, mockFile.name); + expect(file, isNotNull); + expect(file!.name, mockFile.name); expect(await file.length(), 4); expect(await file.readAsString(), '1001'); expect(await file.lastModified(), isNotNull); }); + + testWidgets('returns null when getFiles returns an empty list', + (WidgetTester _) async { + // Simulate returning an empty list of files from the DomHelper... + final MockDomHelper mockDomHelper = MockDomHelper( + files: [], + ); + + final FileSelectorWeb plugin = + FileSelectorWeb(domHelper: mockDomHelper); + + final XFile? file = await plugin.openFile(); + + expect(file, isNull); + }); }); group('openFiles', () { From 41db1abfce73297fe98965498d90f38282c311f1 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 11 Jul 2023 17:57:42 -0700 Subject: [PATCH 10/13] Update CHANGELOG --- packages/file_selector/file_selector_web/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/file_selector/file_selector_web/CHANGELOG.md b/packages/file_selector/file_selector_web/CHANGELOG.md index b6cfde3d085..5bcbc2c1697 100644 --- a/packages/file_selector/file_selector_web/CHANGELOG.md +++ b/packages/file_selector/file_selector_web/CHANGELOG.md @@ -1,6 +1,8 @@ ## 0.9.2 * Adds and propagates `cancel` event on file selection. +* Changes `openFile` to return `null` when no files are selected/selection is canceled, + as in other platforms. ## 0.9.1 From 1ad6926b26e9c93f1e343be05c6713fd7fa58ee2 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 11 Jul 2023 19:12:10 -0700 Subject: [PATCH 11/13] Add documentation to README --- packages/file_selector/file_selector_web/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/file_selector/file_selector_web/README.md b/packages/file_selector/file_selector_web/README.md index 1c152100c35..3906b2f5082 100644 --- a/packages/file_selector/file_selector_web/README.md +++ b/packages/file_selector/file_selector_web/README.md @@ -13,3 +13,15 @@ should add it to your `pubspec.yaml` as usual. [1]: https://pub.dev/packages/file_selector [2]: https://flutter.dev/docs/development/packages-and-plugins/developing-packages#endorsed-federated-plugin + +## Limitations on the Web platform + +### `cancel` event + +The `cancel` event used by the web plugin to detect when users close the file +selector without picking a file is relatively new, and will only work in +recent browsers. + +See: + +* https://caniuse.com/mdn-api_htmlinputelement_cancel_event From fde3f95285f273766dd5e83395ce8627765679ec Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Tue, 11 Jul 2023 20:31:32 -0700 Subject: [PATCH 12/13] Add TestOn chrome to not confuse tooling on this web-only package. --- packages/file_selector/file_selector_web/test/utils_test.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/file_selector/file_selector_web/test/utils_test.dart b/packages/file_selector/file_selector_web/test/utils_test.dart index e207f3d45df..497d3ae4884 100644 --- a/packages/file_selector/file_selector_web/test/utils_test.dart +++ b/packages/file_selector/file_selector_web/test/utils_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +@TestOn('chrome') // web-only package. + import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; import 'package:file_selector_web/src/utils.dart'; import 'package:flutter_test/flutter_test.dart'; From 5df194338ca4809d01bf7e352455516dcc920adc Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 12 Jul 2023 17:06:39 -0400 Subject: [PATCH 13/13] Add vm flag to pathified unit test run --- .ci/scripts/dart_unit_tests_pathified.sh | 2 +- .ci/targets/dart_unit_tests.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.ci/scripts/dart_unit_tests_pathified.sh b/.ci/scripts/dart_unit_tests_pathified.sh index 8a4bac50d3a..e5b5c1feeb5 100755 --- a/.ci/scripts/dart_unit_tests_pathified.sh +++ b/.ci/scripts/dart_unit_tests_pathified.sh @@ -12,7 +12,7 @@ set -e # re-checked. dart ./script/tool/bin/flutter_plugin_tools.dart dart-test --run-on-dirty-packages \ --log-timing --exclude=script/configs/dart_unit_tests_exceptions.yaml \ - $PACKAGE_SHARDING + "$@" $PACKAGE_SHARDING # Restore the tree to a clean state, to avoid accidental issues if # other script steps are added to the enclosing task. git checkout . diff --git a/.ci/targets/dart_unit_tests.yaml b/.ci/targets/dart_unit_tests.yaml index e64bba8fa1d..3d06b600fd5 100644 --- a/.ci/targets/dart_unit_tests.yaml +++ b/.ci/targets/dart_unit_tests.yaml @@ -9,3 +9,4 @@ tasks: # that depend on it. - name: Dart unit tests - pathified script: .ci/scripts/dart_unit_tests_pathified.sh + args: ["--platform=vm"]