[file_selector] Throw for unsupported type groups (#6120)
diff --git a/packages/file_selector/file_selector_macos/CHANGELOG.md b/packages/file_selector/file_selector_macos/CHANGELOG.md
index 8a4f217..0adf1ab 100644
--- a/packages/file_selector/file_selector_macos/CHANGELOG.md
+++ b/packages/file_selector/file_selector_macos/CHANGELOG.md
@@ -1,5 +1,8 @@
-## NEXT
+## 0.9.0
+* **BREAKING CHANGE**: Methods that take `XTypeGroup`s now throw an
+ `ArgumentError` if any group is not a wildcard (all filter types null or
+ empty), but doesn't include any of the filter types supported by macOS.
* Ignores deprecation warnings for upcoming styleFrom button API changes.
## 0.8.2+2
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 e50c296..74ce283 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
@@ -105,10 +105,19 @@
};
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.macUTIs?.isEmpty ?? true) &&
(typeGroup.mimeTypes?.isEmpty ?? true)) {
- return null;
+ 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", "macUTIs", or '
+ '"mimeTypes" must be non-empty for macOS if anything is '
+ 'non-empty.');
}
allowedTypes[extensionKey]!.addAll(typeGroup.extensions ?? <String>[]);
allowedTypes[mimeTypeKey]!.addAll(typeGroup.mimeTypes ?? <String>[]);
diff --git a/packages/file_selector/file_selector_macos/pubspec.yaml b/packages/file_selector/file_selector_macos/pubspec.yaml
index 8c6d1f7..fc9ca4d 100644
--- a/packages/file_selector/file_selector_macos/pubspec.yaml
+++ b/packages/file_selector/file_selector_macos/pubspec.yaml
@@ -2,7 +2,7 @@
description: macOS implementation of the file_selector plugin.
repository: https://github.com/flutter/plugins/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.8.2+2
+version: 0.9.0
environment:
sdk: ">=2.12.0 <3.0.0"
@@ -18,7 +18,7 @@
dependencies:
cross_file: ^0.3.1
- file_selector_platform_interface: ^2.0.4
+ file_selector_platform_interface: ^2.1.0
flutter:
sdk: flutter
flutter_test:
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 1c1b9c1..40ab585 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
@@ -62,6 +62,7 @@
],
);
});
+
test('passes initialDirectory correctly', () async {
await plugin.openFile(initialDirectory: '/example/directory');
@@ -77,6 +78,7 @@
],
);
});
+
test('passes confirmButtonText correctly', () async {
await plugin.openFile(confirmButtonText: 'Open File');
@@ -92,7 +94,28 @@
],
);
});
+
+ test('throws for a type group that does not support macOS', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'images',
+ webWildCards: <String>['images/*'],
+ );
+
+ await expectLater(
+ plugin.openFile(acceptedTypeGroups: <XTypeGroup>[group]),
+ throwsArgumentError);
+ });
+
+ test('allows a wildcard group', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'text',
+ );
+
+ await expectLater(
+ plugin.openFile(acceptedTypeGroups: <XTypeGroup>[group]), completes);
+ });
});
+
group('openFiles', () {
test('passes the accepted type groups correctly', () async {
final XTypeGroup group = XTypeGroup(
@@ -127,6 +150,7 @@
],
);
});
+
test('passes initialDirectory correctly', () async {
await plugin.openFiles(initialDirectory: '/example/directory');
@@ -142,6 +166,7 @@
],
);
});
+
test('passes confirmButtonText correctly', () async {
await plugin.openFiles(confirmButtonText: 'Open File');
@@ -157,6 +182,26 @@
],
);
});
+
+ test('throws for a type group that does not support macOS', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'images',
+ webWildCards: <String>['images/*'],
+ );
+
+ await expectLater(
+ plugin.openFiles(acceptedTypeGroups: <XTypeGroup>[group]),
+ throwsArgumentError);
+ });
+
+ test('allows a wildcard group', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'text',
+ );
+
+ await expectLater(
+ plugin.openFiles(acceptedTypeGroups: <XTypeGroup>[group]), completes);
+ });
});
group('getSavePath', () {
@@ -194,6 +239,7 @@
],
);
});
+
test('passes initialDirectory correctly', () async {
await plugin.getSavePath(initialDirectory: '/example/directory');
@@ -209,6 +255,7 @@
],
);
});
+
test('passes confirmButtonText correctly', () async {
await plugin.getSavePath(confirmButtonText: 'Open File');
@@ -224,33 +271,56 @@
],
);
});
- group('getDirectoryPath', () {
- test('passes initialDirectory correctly', () async {
- await plugin.getDirectoryPath(initialDirectory: '/example/directory');
- expect(
- log,
- <Matcher>[
- isMethodCall('getDirectoryPath', arguments: <String, dynamic>{
- 'initialDirectory': '/example/directory',
- 'confirmButtonText': null,
- }),
- ],
- );
- });
- test('passes confirmButtonText correctly', () async {
- await plugin.getDirectoryPath(confirmButtonText: 'Open File');
+ test('throws for a type group that does not support macOS', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'images',
+ webWildCards: <String>['images/*'],
+ );
- expect(
- log,
- <Matcher>[
- isMethodCall('getDirectoryPath', arguments: <String, dynamic>{
- 'initialDirectory': null,
- 'confirmButtonText': 'Open File',
- }),
- ],
- );
- });
+ await expectLater(
+ plugin.getSavePath(acceptedTypeGroups: <XTypeGroup>[group]),
+ throwsArgumentError);
+ });
+
+ test('allows a wildcard group', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'text',
+ );
+
+ await expectLater(
+ plugin.getSavePath(acceptedTypeGroups: <XTypeGroup>[group]),
+ completes);
+ });
+ });
+
+ group('getDirectoryPath', () {
+ test('passes initialDirectory correctly', () async {
+ await plugin.getDirectoryPath(initialDirectory: '/example/directory');
+
+ expect(
+ log,
+ <Matcher>[
+ isMethodCall('getDirectoryPath', arguments: <String, dynamic>{
+ 'initialDirectory': '/example/directory',
+ 'confirmButtonText': null,
+ }),
+ ],
+ );
+ });
+
+ test('passes confirmButtonText correctly', () async {
+ await plugin.getDirectoryPath(confirmButtonText: 'Open File');
+
+ expect(
+ log,
+ <Matcher>[
+ isMethodCall('getDirectoryPath', arguments: <String, dynamic>{
+ 'initialDirectory': null,
+ 'confirmButtonText': 'Open File',
+ }),
+ ],
+ );
});
});
diff --git a/packages/file_selector/file_selector_web/CHANGELOG.md b/packages/file_selector/file_selector_web/CHANGELOG.md
index 3963601..8a8a53a 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.0
+
+* **BREAKING CHANGE**: Methods that take `XTypeGroup`s now throw an
+ `ArgumentError` if any group is not a wildcard (all filter types null or
+ empty), but doesn't include any of the filter types supported by web.
+
## 0.8.1+5
* Minor fixes for new analysis options.
diff --git a/packages/file_selector/file_selector_web/lib/src/utils.dart b/packages/file_selector/file_selector_web/lib/src/utils.dart
index fe8d1f4..7a7aa7a 100644
--- a/packages/file_selector/file_selector_web/lib/src/utils.dart
+++ b/packages/file_selector/file_selector_web/lib/src/utils.dart
@@ -11,7 +11,11 @@
}
final List<String> allTypes = <String>[];
for (final XTypeGroup group in acceptedTypes) {
- _assertTypeGroupIsValid(group);
+ // If any group allows everything, no filtering should be done.
+ if (group.allowsAny) {
+ return '';
+ }
+ _validateTypeGroup(group);
if (group.extensions != null) {
allTypes.addAll(group.extensions!.map(_normalizeExtension));
}
@@ -25,13 +29,17 @@
return allTypes.join(',');
}
-/// Make sure that at least one of its fields is populated.
-void _assertTypeGroupIsValid(XTypeGroup group) {
- assert(
- !((group.extensions == null || group.extensions!.isEmpty) &&
- (group.mimeTypes == null || group.mimeTypes!.isEmpty) &&
- (group.webWildCards == null || group.webWildCards!.isEmpty)),
- 'At least one of extensions / mimeTypes / webWildCards is required for web.');
+/// Make sure that at least one of the supported fields is populated.
+void _validateTypeGroup(XTypeGroup group) {
+ if ((group.extensions?.isEmpty ?? true) &&
+ (group.mimeTypes?.isEmpty ?? true) &&
+ (group.webWildCards?.isEmpty ?? true)) {
+ throw ArgumentError('Provided type group $group does not allow '
+ 'all files, but does not set any of the web-supported filter '
+ 'categories. At least one of "extensions", "mimeTypes", or '
+ '"webWildCards" must be non-empty for web if anything is '
+ 'non-empty.');
+ }
}
/// Append a dot at the beggining if it is not there png -> .png
diff --git a/packages/file_selector/file_selector_web/pubspec.yaml b/packages/file_selector/file_selector_web/pubspec.yaml
index c685cca..a764cae 100644
--- a/packages/file_selector/file_selector_web/pubspec.yaml
+++ b/packages/file_selector/file_selector_web/pubspec.yaml
@@ -2,7 +2,7 @@
description: Web platform implementation of file_selector
repository: https://github.com/flutter/plugins/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.8.1+5
+version: 0.9.0
environment:
sdk: ">=2.12.0 <3.0.0"
@@ -17,7 +17,7 @@
fileName: file_selector_web.dart
dependencies:
- file_selector_platform_interface: ^2.0.0
+ file_selector_platform_interface: ^2.1.0
flutter:
sdk: flutter
flutter_web_plugins:
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 9bddfd2..3281c4c 100644
--- a/packages/file_selector/file_selector_web/test/utils_test.dart
+++ b/packages/file_selector/file_selector_web/test/utils_test.dart
@@ -53,6 +53,13 @@
final String accepts = acceptedTypesToString(acceptedTypes);
expect(accepts, 'image/*,audio/*,video/*');
});
+
+ test('throws for a type group that does not support web', () {
+ final List<XTypeGroup> acceptedTypes = <XTypeGroup>[
+ XTypeGroup(label: 'text', macUTIs: <String>['public.text']),
+ ];
+ expect(() => acceptedTypesToString(acceptedTypes), throwsArgumentError);
+ });
});
});
}
diff --git a/packages/file_selector/file_selector_windows/CHANGELOG.md b/packages/file_selector/file_selector_windows/CHANGELOG.md
index f5354b3..3f15de7 100644
--- a/packages/file_selector/file_selector_windows/CHANGELOG.md
+++ b/packages/file_selector/file_selector_windows/CHANGELOG.md
@@ -1,5 +1,8 @@
-## NEXT
+## 0.9.0
+* **BREAKING CHANGE**: Methods that take `XTypeGroup`s now throw an
+ `ArgumentError` if any group is not a wildcard (all filter types null or
+ empty), but doesn't include any of the filter types supported by Windows.
* Ignores deprecation warnings for upcoming styleFrom button API changes.
## 0.8.2+2
diff --git a/packages/file_selector/file_selector_windows/lib/file_selector_windows.dart b/packages/file_selector/file_selector_windows/lib/file_selector_windows.dart
index b91a223..6b1bc89 100644
--- a/packages/file_selector/file_selector_windows/lib/file_selector_windows.dart
+++ b/packages/file_selector/file_selector_windows/lib/file_selector_windows.dart
@@ -26,6 +26,7 @@
String? initialDirectory,
String? confirmButtonText,
}) async {
+ _validateTypeGroups(acceptedTypeGroups);
final List<String>? path = await _channel.invokeListMethod<String>(
'openFile',
<String, dynamic>{
@@ -46,6 +47,7 @@
String? initialDirectory,
String? confirmButtonText,
}) async {
+ _validateTypeGroups(acceptedTypeGroups);
final List<String>? pathList = await _channel.invokeListMethod<String>(
'openFile',
<String, dynamic>{
@@ -67,6 +69,7 @@
String? suggestedName,
String? confirmButtonText,
}) async {
+ _validateTypeGroups(acceptedTypeGroups);
return _channel.invokeMethod<String>(
'getSavePath',
<String, dynamic>{
@@ -93,4 +96,20 @@
},
);
}
+
+ /// Throws an [ArgumentError] if any of the provided type groups are not valid
+ /// for Windows.
+ void _validateTypeGroups(List<XTypeGroup>? groups) {
+ if (groups == null) {
+ return;
+ }
+ for (final XTypeGroup group in groups) {
+ if (!group.allowsAny && (group.extensions?.isEmpty ?? true)) {
+ throw ArgumentError('Provided type group $group does not allow '
+ 'all files, but does not set any of the Windows-supported filter '
+ 'categories. "extensions" must be non-empty for Windows if '
+ 'anything is non-empty.');
+ }
+ }
+ }
}
diff --git a/packages/file_selector/file_selector_windows/pubspec.yaml b/packages/file_selector/file_selector_windows/pubspec.yaml
index 7c933b2..13487fe 100644
--- a/packages/file_selector/file_selector_windows/pubspec.yaml
+++ b/packages/file_selector/file_selector_windows/pubspec.yaml
@@ -2,7 +2,7 @@
description: Windows implementation of the file_selector plugin.
repository: https://github.com/flutter/plugins/tree/main/packages/file_selector/file_selector_windows
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22
-version: 0.8.2+2
+version: 0.9.0
environment:
sdk: ">=2.12.0 <3.0.0"
@@ -18,7 +18,7 @@
dependencies:
cross_file: ^0.3.1
- file_selector_platform_interface: ^2.0.4
+ file_selector_platform_interface: ^2.1.0
flutter:
sdk: flutter
flutter_test:
diff --git a/packages/file_selector/file_selector_windows/test/file_selector_windows_test.dart b/packages/file_selector/file_selector_windows/test/file_selector_windows_test.dart
index 72604dd..48e13c2 100644
--- a/packages/file_selector/file_selector_windows/test/file_selector_windows_test.dart
+++ b/packages/file_selector/file_selector_windows/test/file_selector_windows_test.dart
@@ -10,7 +10,7 @@
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
- group('$FileSelectorWindows()', () {
+ group('FileSelectorWindows()', () {
final FileSelectorWindows plugin = FileSelectorWindows();
final List<MethodCall> log = <MethodCall>[];
@@ -63,6 +63,7 @@
],
);
});
+
test('passes initialDirectory correctly', () async {
await plugin.openFile(initialDirectory: '/example/directory');
@@ -78,6 +79,7 @@
],
);
});
+
test('passes confirmButtonText correctly', () async {
await plugin.openFile(confirmButtonText: 'Open File');
@@ -93,7 +95,29 @@
],
);
});
+
+ test('throws for a type group that does not support Windows', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'text',
+ mimeTypes: <String>['text/plain'],
+ );
+
+ await expectLater(
+ plugin.openFile(acceptedTypeGroups: <XTypeGroup>[group]),
+ throwsArgumentError);
+ });
+
+ test('allows a wildcard group', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'text',
+ );
+
+ await expectLater(
+ plugin.openFile(acceptedTypeGroups: <XTypeGroup>[group]),
+ completes);
+ });
});
+
group('#openFiles', () {
test('passes the accepted type groups correctly', () async {
final XTypeGroup group = XTypeGroup(
@@ -128,6 +152,7 @@
],
);
});
+
test('passes initialDirectory correctly', () async {
await plugin.openFiles(initialDirectory: '/example/directory');
@@ -143,6 +168,7 @@
],
);
});
+
test('passes confirmButtonText correctly', () async {
await plugin.openFiles(confirmButtonText: 'Open File');
@@ -158,6 +184,27 @@
],
);
});
+
+ test('throws for a type group that does not support Windows', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'text',
+ mimeTypes: <String>['text/plain'],
+ );
+
+ await expectLater(
+ plugin.openFiles(acceptedTypeGroups: <XTypeGroup>[group]),
+ throwsArgumentError);
+ });
+
+ test('allows a wildcard group', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'text',
+ );
+
+ await expectLater(
+ plugin.openFiles(acceptedTypeGroups: <XTypeGroup>[group]),
+ completes);
+ });
});
group('#getSavePath', () {
@@ -194,6 +241,7 @@
],
);
});
+
test('passes initialDirectory correctly', () async {
await plugin.getSavePath(initialDirectory: '/example/directory');
@@ -209,6 +257,7 @@
],
);
});
+
test('passes confirmButtonText correctly', () async {
await plugin.getSavePath(confirmButtonText: 'Open File');
@@ -224,33 +273,56 @@
],
);
});
- group('#getDirectoryPath', () {
- test('passes initialDirectory correctly', () async {
- await plugin.getDirectoryPath(initialDirectory: '/example/directory');
- expect(
- log,
- <Matcher>[
- isMethodCall('getDirectoryPath', arguments: <String, dynamic>{
- 'initialDirectory': '/example/directory',
- 'confirmButtonText': null,
- }),
- ],
- );
- });
- test('passes confirmButtonText correctly', () async {
- await plugin.getDirectoryPath(confirmButtonText: 'Open File');
+ test('throws for a type group that does not support Windows', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'text',
+ mimeTypes: <String>['text/plain'],
+ );
- expect(
- log,
- <Matcher>[
- isMethodCall('getDirectoryPath', arguments: <String, dynamic>{
- 'initialDirectory': null,
- 'confirmButtonText': 'Open File',
- }),
- ],
- );
- });
+ await expectLater(
+ plugin.getSavePath(acceptedTypeGroups: <XTypeGroup>[group]),
+ throwsArgumentError);
+ });
+
+ test('allows a wildcard group', () async {
+ final XTypeGroup group = XTypeGroup(
+ label: 'text',
+ );
+
+ await expectLater(
+ plugin.getSavePath(acceptedTypeGroups: <XTypeGroup>[group]),
+ completes);
+ });
+ });
+
+ group('#getDirectoryPath', () {
+ test('passes initialDirectory correctly', () async {
+ await plugin.getDirectoryPath(initialDirectory: '/example/directory');
+
+ expect(
+ log,
+ <Matcher>[
+ isMethodCall('getDirectoryPath', arguments: <String, dynamic>{
+ 'initialDirectory': '/example/directory',
+ 'confirmButtonText': null,
+ }),
+ ],
+ );
+ });
+
+ test('passes confirmButtonText correctly', () async {
+ await plugin.getDirectoryPath(confirmButtonText: 'Open File');
+
+ expect(
+ log,
+ <Matcher>[
+ isMethodCall('getDirectoryPath', arguments: <String, dynamic>{
+ 'initialDirectory': null,
+ 'confirmButtonText': 'Open File',
+ }),
+ ],
+ );
});
});
});