Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Some PR feedback.
* Removed redundant getFile method (getFiles already exists)
* Added tests to verify that 'multiple' attribute is set in file input
* Added tests to verify that extra metadata is set.
* Added some , to improve dart format output.
  • Loading branch information
ditman committed Jul 19, 2021
commit 3c83bef3164deb63d04407d3c9c123e055910ad6
2 changes: 1 addition & 1 deletion packages/image_picker/image_picker_for_web/AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,4 @@ Aleksandr Yurkovskiy <[email protected]>
Anton Borries <[email protected]>
Alex Li <[email protected]>
Rahul Raj <[email protected]>
Balvinder Singh Gambhir<[email protected]>
Balvinder Singh Gambhir <[email protected]>
3 changes: 2 additions & 1 deletion packages/image_picker/image_picker_for_web/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# 2.1.1

* Implemented `getMultiImage`.
* Added support for getting name,length,mimeType and lastModified from XFile.
* Initialized the following `XFile` attributes for picked files:
* `name`, `length`, `mimeType` and `lastModified`.

# 2.1.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@ import 'package:image_picker_for_web/image_picker_for_web.dart';
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
import 'package:integration_test/integration_test.dart';

final String expectedStringContents = "Hello, world!";
final String expectedStringContents = 'Hello, world!';
final String otherStringContents = 'Hello again, world!';
final Uint8List bytes = utf8.encode(expectedStringContents) as Uint8List;
final html.File textFile = html.File([bytes], "hello.txt");
final html.File secondTextFile = html.File([bytes], "secondFile.txt");
final Uint8List otherBytes = utf8.encode(otherStringContents) as Uint8List;
final Map<String, dynamic> options = {
'type': 'text/plain',
'lastModified': DateTime.utc(2017, 12, 13).millisecondsSinceEpoch,
};
final html.File textFile = html.File([bytes], 'hello.txt', options);
final html.File secondTextFile = html.File([otherBytes], 'secondFile.txt');

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
Expand Down Expand Up @@ -57,15 +63,25 @@ void main() {
final plugin = ImagePickerPlugin(overrides: overrides);

// Init the pick file dialog...
final file = plugin.getFile();
final image = plugin.getImage(source: ImageSource.camera);

// Mock the browser behavior of selecting a file...
mockInput.dispatchEvent(html.Event('change'));

// Now the file should be available
expect(file, completes);
expect(image, completes);

// And readable
expect((await file).readAsBytes(), completion(isNotEmpty));
final XFile file = await image;
expect(file.readAsBytes(), completion(isNotEmpty));
expect(file.name, textFile.name);
expect(file.length(), completion(textFile.size));
expect(file.mimeType, textFile.type);
expect(
file.lastModified(),
completion(
DateTime.fromMillisecondsSinceEpoch(textFile.lastModified!),
));
});

testWidgets('Can select multiple files', (WidgetTester tester) async {
Expand All @@ -85,10 +101,15 @@ void main() {

// Now the file should be available
expect(files, completes);

// And readable
expect((await files).first.readAsBytes(), completion(isNotEmpty));

expect((await files)?.first.readAsBytes(), completion(isNotEmpty));
expect((await files)?[1].readAsBytes(), completion(isNotEmpty));
// Peek into the second file...
final XFile secondFile = (await files).elementAt(1);
expect(secondFile.readAsBytes(), completion(isNotEmpty));
expect(secondFile.name, secondTextFile.name);
expect(secondFile.length(), completion(secondTextFile.size));
});

// There's no good way of detecting when the user has "aborted" the selection.
Expand Down Expand Up @@ -118,13 +139,35 @@ void main() {

expect(input.attributes, containsPair('accept', 'any'));
expect(input.attributes, isNot(contains('capture')));
expect(input.attributes, isNot(contains('multiple')));
});

testWidgets('accept: any, capture: something', (WidgetTester tester) async {
html.Element input = plugin.createInputElement('any', 'something');

expect(input.attributes, containsPair('accept', 'any'));
expect(input.attributes, containsPair('capture', 'something'));
expect(input.attributes, isNot(contains('multiple')));
});

testWidgets('accept: any, capture: null, multi: true',
(WidgetTester tester) async {
html.Element input =
plugin.createInputElement('any', null, multiple: true);

expect(input.attributes, containsPair('accept', 'any'));
expect(input.attributes, isNot(contains('capture')));
expect(input.attributes, contains('multiple'));
});

testWidgets('accept: any, capture: something, multi: true',
(WidgetTester tester) async {
html.Element input =
plugin.createInputElement('any', 'something', multiple: true);

expect(input.attributes, containsPair('accept', 'any'));
expect(input.attributes, containsPair('capture', 'something'));
expect(input.attributes, contains('multiple'));
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,13 @@ class ImagePickerPlugin extends ImagePickerPlatform {
double? maxHeight,
int? imageQuality,
CameraDevice preferredCameraDevice = CameraDevice.rear,
}) {
}) async {
String? capture = computeCaptureAttribute(source, preferredCameraDevice);
return getFile(accept: _kAcceptImageMimeType, capture: capture);
List<XFile> files = await getFiles(
accept: _kAcceptImageMimeType,
capture: capture,
);
return files.first;
}

/// Returns an [XFile] containing the video that was picked.
Expand All @@ -138,53 +142,50 @@ class ImagePickerPlugin extends ImagePickerPlatform {
required ImageSource source,
CameraDevice preferredCameraDevice = CameraDevice.rear,
Duration? maxDuration,
}) {
}) async {
String? capture = computeCaptureAttribute(source, preferredCameraDevice);
return getFile(accept: _kAcceptVideoMimeType, capture: capture);
List<XFile> files = await getFiles(
accept: _kAcceptVideoMimeType,
capture: capture,
);
return files.first;
}

/// Injects a file input, and returns a list of XFile that the user selected locally.
@override
Future<List<XFile>?> getMultiImage(
{double? maxWidth, double? maxHeight, int? imageQuality}) {
return getFiles(accept: _kAcceptImageMimeType);
Future<List<XFile>> getMultiImage({
double? maxWidth,
double? maxHeight,
int? imageQuality,
}) {
return getFiles(accept: _kAcceptImageMimeType, multiple: true);
}

/// Injects a file input with the specified accept+capture attributes, and
/// returns a list of XFile that the user selected locally.
///
/// `capture` is only supported in mobile browsers.
///
/// `multiple` can be passed to allow for multiple selection of files. Defaults
/// to false.
///
/// See https://caniuse.com/#feat=html-media-capture
@visibleForTesting
Future<List<XFile>> getFiles({
String? accept,
String? capture,
bool multiple = false,
}) {
html.FileUploadInputElement input =
createInputElement(accept, capture, multiple: true)
as html.FileUploadInputElement;
html.FileUploadInputElement input = createInputElement(
accept,
capture,
multiple: multiple,
) as html.FileUploadInputElement;
_injectAndActivate(input);

return _getSelectedXFiles(input);
}

/// Injects a file input with the specified accept+capture attributes, and
/// returns the XFile that the user selected locally.
///
/// `capture` is only supported in mobile browsers.
/// See https://caniuse.com/#feat=html-media-capture
@visibleForTesting
Future<XFile> getFile({
String? accept,
String? capture,
}) async {
html.FileUploadInputElement input =
createInputElement(accept, capture) as html.FileUploadInputElement;
_injectAndActivate(input);
final files = await _getSelectedXFiles(input);
return files.first;
}

// DOM methods

/// Converts plugin configuration into a proper value for the `capture` attribute.
Expand Down Expand Up @@ -218,10 +219,11 @@ class ImagePickerPlugin extends ImagePickerPlatform {
final Completer<PickedFile> _completer = Completer<PickedFile>();
// Observe the input until we can return something
input.onChange.first.then((event) {
final pickedFile = _handleOnChangeEvent(event);
if (!_completer.isCompleted && pickedFile != null) {
_completer
.complete(PickedFile(html.Url.createObjectUrl(pickedFile.first)));
final files = _handleOnChangeEvent(event);
if (!_completer.isCompleted && files != null) {
_completer.complete(PickedFile(
html.Url.createObjectUrl(files.first),
));
}
});
input.onError.first.then((event) {
Expand All @@ -235,6 +237,7 @@ class ImagePickerPlugin extends ImagePickerPlatform {
return _completer.future;
}

/// Monitors an <input type="file"> and returns the selected file(s).
Future<List<XFile>> _getSelectedXFiles(html.FileUploadInputElement input) {
final Completer<List<XFile>> _completer = Completer<List<XFile>>();
// Observe the input until we can return something
Expand All @@ -246,7 +249,10 @@ class ImagePickerPlugin extends ImagePickerPlatform {
html.Url.createObjectUrl(file),
name: file.name,
length: file.size,
lastModified: file.lastModifiedDate,
lastModified: DateTime.fromMillisecondsSinceEpoch(
file.lastModified ?? DateTime.now().millisecondsSinceEpoch,
),
mimeType: file.type,
))
.toList());
}
Expand Down Expand Up @@ -278,8 +284,11 @@ class ImagePickerPlugin extends ImagePickerPlatform {
/// Creates an input element that accepts certain file types, and
/// allows to `capture` from the device's cameras (where supported)
@visibleForTesting
html.Element createInputElement(String? accept, String? capture,
{bool multiple = false}) {
html.Element createInputElement(
String? accept,
String? capture, {
bool multiple = false,
}) {
if (_hasOverrides) {
return _overrides!.createInputElement(accept, capture);
}
Expand Down Expand Up @@ -314,9 +323,7 @@ typedef OverrideCreateInputFunction = html.Element Function(
/// A function that extracts list of files from the file `input` passed in.
@visibleForTesting
typedef OverrideExtractMultipleFilesFromInputFunction = List<html.File>
Function(
html.Element? input,
);
Function(html.Element? input);

/// Overrides for some of the functionality above.
@visibleForTesting
Expand Down