From 2a508cb412f5554866e8e8a43b02bd38e88d5ce5 Mon Sep 17 00:00:00 2001 From: Raju Muliyashiya <65381000+raju8000@users.noreply.github.com> Date: Thu, 13 Jul 2023 05:22:48 +0530 Subject: [PATCH] [file_selector_web] Listens to file input cancel event. (#3683) While using package ``file_selector`` making for multiple file request in web platform we are not able to get any data if user clicks cancel button on file selection window. This PR fixes it by watching the ``focus event`` and if ``onChange`` is not fired then return empty array, Empty array will only return if multiple selection is enabled with ``openFiles()``. *List which issues are fixed by this PR. You must list at least one issue.* [Issue #121328](https://github.com/flutter/flutter/issues/121328) --- .ci/scripts/dart_unit_tests_pathified.sh | 2 +- .ci/targets/dart_unit_tests.yaml | 1 + .../file_selector_web/CHANGELOG.md | 6 +++++ .../file_selector/file_selector_web/README.md | 12 ++++++++++ .../integration_test/dom_helper_test.dart | 24 +++++++++++++++++-- .../file_selector_web_test.dart | 20 ++++++++++++++-- .../lib/file_selector_web.dart | 4 ++-- .../file_selector_web/lib/src/dom_helper.dart | 6 +++++ .../file_selector_web/pubspec.yaml | 2 +- .../file_selector_web/test/utils_test.dart | 2 ++ 10 files changed, 71 insertions(+), 8 deletions(-) diff --git a/.ci/scripts/dart_unit_tests_pathified.sh b/.ci/scripts/dart_unit_tests_pathified.sh index 8a4bac50d3aac..e5b5c1feeb572 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 e64bba8fa1d46..3d06b600fd559 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"] diff --git a/packages/file_selector/file_selector_web/CHANGELOG.md b/packages/file_selector/file_selector_web/CHANGELOG.md index 073f1c20ed825..5bcbc2c16973b 100644 --- a/packages/file_selector/file_selector_web/CHANGELOG.md +++ b/packages/file_selector/file_selector_web/CHANGELOG.md @@ -1,3 +1,9 @@ +## 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 * Adds `getSaveLocation` and deprecates `getSavePath`. diff --git a/packages/file_selector/file_selector_web/README.md b/packages/file_selector/file_selector_web/README.md index 1c152100c3502..3906b2f508251 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 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 ee1af8cb62fd8..d6cb47fe45b63 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; 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 664c40871f49c..f64c08de05649 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', () { 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 2380e274c46a1..53e0c6d5ab33b 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 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 1c3442f8dab51..e600778b7dc73 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,6 +52,12 @@ class DomHelper { completer.completeError(platformException); }); + inputElement.addEventListener('cancel', (Event event) { + inputElement.remove(); + completer.complete([]); + }); + + // TODO(dit): Reimplement this with the showPicker() API, https://github.com/flutter/flutter/issues/130365 inputElement.click(); return completer.future; diff --git a/packages/file_selector/file_selector_web/pubspec.yaml b/packages/file_selector/file_selector_web/pubspec.yaml index 81ba11a9634a9..a34e9c75548f7 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" 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 e207f3d45df58..497d3ae48849d 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';