Skip to content

[image_picker_for_web] migrates to package:web #5799

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
8acdb0c
migrate to package:web
balvinderz Jan 4, 2024
b1d9a6f
dart format
balvinderz Jan 4, 2024
8591d98
dummy commit
balvinderz Jan 4, 2024
7143cfe
dummy commit
balvinderz Jan 4, 2024
db43995
fix tests
balvinderz Jan 4, 2024
9431bf6
fix test
balvinderz Jan 4, 2024
7adb97c
fix analyze and test
balvinderz Jan 4, 2024
b81568d
fix error
balvinderz Jan 4, 2024
390ee24
revert package
balvinderz Jan 4, 2024
7050c0e
fix analyze
balvinderz Jan 4, 2024
ccf7796
fix analyze
balvinderz Jan 4, 2024
0a160b5
fix analyze
balvinderz Jan 4, 2024
24ca0cd
format
balvinderz Jan 4, 2024
0a24255
analyze
balvinderz Jan 4, 2024
ac4149c
analyze
balvinderz Jan 4, 2024
0e29289
format
balvinderz Jan 4, 2024
5f53b82
empty commit
balvinderz Jan 4, 2024
02c4760
empty commit
balvinderz Jan 4, 2024
f0e1ca9
add ignore on declaration
balvinderz Jan 4, 2024
20bfe0e
fix analyze
balvinderz Jan 4, 2024
4d5c308
Merge branch 'main' into migrate_image_picker_to_package_web
balvinderz Jan 4, 2024
6e77037
added todo
balvinderz Jan 4, 2024
0ed9b6a
Merge remote-tracking branch 'origin/migrate_image_picker_to_package_…
balvinderz Jan 4, 2024
e58b1d2
Update image_picker_for_web_test.dart
balvinderz Jan 4, 2024
938c23b
dummy commit
balvinderz Jan 4, 2024
c70116d
dummy commit
balvinderz Jan 4, 2024
a270d01
apply patch
balvinderz Jan 4, 2024
b51fa8e
try without jsarray
balvinderz Jan 4, 2024
9c242ab
Merge branch 'main' into migrate_image_picker_to_package_web
balvinderz Jan 4, 2024
e6534b1
sync
balvinderz Jan 5, 2024
63c87f2
Merge branch 'migrate_image_picker_to_package_web' of ssh://github.co…
balvinderz Jan 5, 2024
c1eee82
Update image_resizer.dart
balvinderz Jan 5, 2024
9e475df
Update image_picker_for_web.dart
balvinderz Jan 5, 2024
4bac9b8
Merge branch 'main' into migrate_image_picker_to_package_web
balvinderz Jan 6, 2024
15fc178
Merge branch 'main' into migrate_image_picker_to_package_web
balvinderz Jan 9, 2024
83cf757
Merge branch 'main' into migrate_image_picker_to_package_web
balvinderz Jan 10, 2024
b68646a
Merge branch 'main' into migrate_image_picker_to_package_web
ditman Feb 28, 2024
3eb21b7
Update web and environment to latest stable.
ditman Feb 28, 2024
5898986
Address PR comments.
ditman Feb 29, 2024
299c800
Bump web to 0.5.1 and use element constructors.
ditman Mar 6, 2024
6c951b4
Merge branch 'main' into migrate_image_picker_to_package_web
ditman Mar 6, 2024
a6016b0
Add web 0.6.0 note and link to PR.
ditman Mar 6, 2024
516f98c
dart format .
ditman Mar 6, 2024
e569aa7
Doc tweaks. PR comments.
ditman Mar 6, 2024
ebe0e6a
Link to dart-lang issue
ditman Mar 6, 2024
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
6 changes: 5 additions & 1 deletion packages/image_picker/image_picker_for_web/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## 3.0.2
## 3.0.3

* Migrates package and tests to `platform:web`.
* Updates minimum supported SDK version to Flutter 3.16.0/Dart 3.2.0.

## 3.0.2
* Updates minimum supported SDK version to Flutter 3.10/Dart 3.0.
* Removes input element after completion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,27 @@
// found in the LICENSE file.

import 'dart:convert';
import 'dart:html' as html;
import 'dart:js_interop';
import 'dart:typed_data';

import 'package:flutter_test/flutter_test.dart';
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';
import 'package:web/web.dart' as web;

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

final web.File textFile =
web.File(<JSUint8Array>[bytes.toJS].toJS, 'hello.txt', options);
final web.File secondTextFile =
web.File(<JSUint8Array>[otherBytes.toJS].toJS, 'secondFile.txt');

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
Expand All @@ -36,12 +38,13 @@ void main() {
testWidgets('getImageFromSource can select a file', (
WidgetTester _,
) async {
final html.FileUploadInputElement mockInput = html.FileUploadInputElement();

final web.HTMLInputElement mockInput = (web.document.createElement('input')
as web.HTMLInputElement)
..type = 'file';
final ImagePickerPluginTestOverrides overrides =
ImagePickerPluginTestOverrides()
..createInputElement = ((_, __) => mockInput)
..getMultipleFilesFromInput = ((_) => <html.File>[textFile]);
..getMultipleFilesFromInput = ((_) => <web.File>[textFile]);

final ImagePickerPlugin plugin = ImagePickerPlugin(overrides: overrides);

Expand All @@ -50,11 +53,16 @@ void main() {
source: ImageSource.camera,
);

expect(html.querySelector('flt-image-picker-inputs')?.children.isEmpty,
expect(
web.document
.querySelector('flt-image-picker-inputs')
?.children
.length ==
0,
isFalse);

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

// Now the file should be available
expect(image, completes);
Expand All @@ -69,30 +77,37 @@ void main() {
expect(
file.lastModified(),
completion(
DateTime.fromMillisecondsSinceEpoch(textFile.lastModified!),
DateTime.fromMillisecondsSinceEpoch(textFile.lastModified),
));
expect(html.querySelector('flt-image-picker-inputs')?.children.isEmpty,
expect(
web.document
.querySelector('flt-image-picker-inputs')
?.children
.length ==
0,
isTrue);
});

testWidgets('getMultiImageWithOptions can select multiple files', (
WidgetTester _,
) async {
final html.FileUploadInputElement mockInput = html.FileUploadInputElement();
final web.HTMLInputElement mockInput = (web.document.createElement('input')
as web.HTMLInputElement)
..type = 'file';

final ImagePickerPluginTestOverrides overrides =
ImagePickerPluginTestOverrides()
..createInputElement = ((_, __) => mockInput)
..getMultipleFilesFromInput =
((_) => <html.File>[textFile, secondTextFile]);
((_) => <web.File>[textFile, secondTextFile]);

final ImagePickerPlugin plugin = ImagePickerPlugin(overrides: overrides);

// Init the pick file dialog...
final Future<List<XFile>> files = plugin.getMultiImageWithOptions();

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

// Now the file should be available
expect(files, completes);
Expand All @@ -108,13 +123,15 @@ void main() {
});

testWidgets('getMedia can select multiple files', (WidgetTester _) async {
final html.FileUploadInputElement mockInput = html.FileUploadInputElement();
final web.HTMLInputElement mockInput = (web.document.createElement('input')
as web.HTMLInputElement)
..type = 'file';

final ImagePickerPluginTestOverrides overrides =
ImagePickerPluginTestOverrides()
..createInputElement = ((_, __) => mockInput)
..getMultipleFilesFromInput =
((_) => <html.File>[textFile, secondTextFile]);
((_) => <web.File>[textFile, secondTextFile]);

final ImagePickerPlugin plugin = ImagePickerPlugin(overrides: overrides);

Expand All @@ -123,7 +140,7 @@ void main() {
plugin.getMedia(options: const MediaOptions(allowMultiple: true));

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

// Now the file should be available
expect(files, completes);
Expand All @@ -139,20 +156,21 @@ void main() {
});

group('cancel event', () {
late html.FileUploadInputElement mockInput;
late web.HTMLInputElement mockInput;
late ImagePickerPluginTestOverrides overrides;
late ImagePickerPlugin plugin;

setUp(() {
mockInput = html.FileUploadInputElement();
mockInput = (web.document.createElement('input') as web.HTMLInputElement)
..type = 'file';
overrides = ImagePickerPluginTestOverrides()
..createInputElement = ((_, __) => mockInput)
..getMultipleFilesFromInput = ((_) => <html.File>[textFile]);
..getMultipleFilesFromInput = ((_) => <web.File>[textFile]);
plugin = ImagePickerPlugin(overrides: overrides);
});

void mockCancel() {
mockInput.dispatchEvent(html.Event('cancel'));
mockInput.dispatchEvent(web.Event('cancel'));
}

testWidgets('getFiles - returns empty list', (WidgetTester _) async {
Expand Down Expand Up @@ -226,61 +244,62 @@ void main() {

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

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

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

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

testWidgets('accept: any, capture: null, multi: true',
(WidgetTester tester) async {
final html.Element input =
final web.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'));
expect(input.getAttribute('accept'), 'any');
expect(input.hasAttribute('capture'), false);
expect(input.hasAttribute('multiple'), true);
});

testWidgets('accept: any, capture: something, multi: true',
(WidgetTester tester) async {
final html.Element input =
final web.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'));
expect(input.getAttribute('accept'), 'any');
expect(input.getAttribute('capture'), 'something');
expect(input.hasAttribute('multiple'), true);
});
});

group('Deprecated methods', () {
late html.FileUploadInputElement mockInput;
late web.HTMLInputElement mockInput;
late ImagePickerPluginTestOverrides overrides;
late ImagePickerPlugin plugin;

setUp(() {
mockInput = html.FileUploadInputElement();
mockInput = (web.document.createElement('input') as web.HTMLInputElement)
..type = 'file';
overrides = ImagePickerPluginTestOverrides()
..createInputElement = ((_, __) => mockInput)
..getMultipleFilesFromInput = ((_) => <html.File>[textFile]);
..getMultipleFilesFromInput = ((_) => <web.File>[textFile]);
plugin = ImagePickerPlugin(overrides: overrides);
});

void mockCancel() {
mockInput.dispatchEvent(html.Event('cancel'));
mockInput.dispatchEvent(web.Event('cancel'));
}

void mockChange() {
mockInput.dispatchEvent(html.Event('change'));
mockInput.dispatchEvent(web.Event('change'));
}

group('getImage', () {
Expand All @@ -306,7 +325,7 @@ void main() {
expect(
file.lastModified(),
completion(
DateTime.fromMillisecondsSinceEpoch(textFile.lastModified!),
DateTime.fromMillisecondsSinceEpoch(textFile.lastModified),
));
});

Expand All @@ -326,7 +345,7 @@ void main() {
testWidgets('can select multiple files', (WidgetTester _) async {
// Override the returned files...
overrides.getMultipleFilesFromInput =
(_) => <html.File>[textFile, secondTextFile];
(_) => <web.File>[textFile, secondTextFile];

// ignore: deprecated_member_use
final Future<List<XFile>> files = plugin.getMultiImage();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
// found in the LICENSE file.

import 'dart:async';
import 'dart:html' as html;
import 'dart:js_interop';
import 'dart:typed_data';
import 'dart:ui';

import 'package:flutter_test/flutter_test.dart';
import 'package:image_picker_for_web/src/image_resizer.dart';
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
import 'package:integration_test/integration_test.dart';
import 'package:web/helpers.dart';
import 'package:web/web.dart' as web;

//This is a sample 10x10 png image
const String pngFileBase64Contents =
Expand All @@ -24,14 +26,13 @@ void main() {
late XFile pngFile;
setUp(() {
imageResizer = ImageResizer();
final html.File pngHtmlFile =
_base64ToFile(pngFileBase64Contents, 'pngImage.png');
pngFile = XFile(html.Url.createObjectUrl(pngHtmlFile),
name: pngHtmlFile.name, mimeType: pngHtmlFile.type);
final web.Blob pngHtmlFile = _base64ToBlob(pngFileBase64Contents);
pngFile = XFile(web.URL.createObjectURL(pngHtmlFile.toJSBox),
name: 'pngImage.png', mimeType: 'image/png');
});

testWidgets('image is loaded correctly ', (WidgetTester tester) async {
final html.ImageElement imageElement =
final web.HTMLImageElement imageElement =
await imageResizer.loadImage(pngFile.path);
expect(imageElement.width, 10);
expect(imageElement.height, 10);
Expand All @@ -40,9 +41,9 @@ void main() {
testWidgets(
"canvas is loaded with image's width and height when max width and max height are null",
(WidgetTester widgetTester) async {
final html.ImageElement imageElement =
final web.HTMLImageElement imageElement =
await imageResizer.loadImage(pngFile.path);
final html.CanvasElement canvas =
final web.HTMLCanvasElement canvas =
imageResizer.resizeImageElement(imageElement, null, null);
expect(canvas.width, imageElement.width);
expect(canvas.height, imageElement.height);
Expand All @@ -51,19 +52,19 @@ void main() {
testWidgets(
'canvas size is scaled when max width and max height are not null',
(WidgetTester widgetTester) async {
final html.ImageElement imageElement =
final web.HTMLImageElement imageElement =
await imageResizer.loadImage(pngFile.path);
final html.CanvasElement canvas =
final web.HTMLCanvasElement canvas =
imageResizer.resizeImageElement(imageElement, 8, 8);
expect(canvas.width, 8);
expect(canvas.height, 8);
});

testWidgets('resized image is returned after converting canvas to file',
(WidgetTester widgetTester) async {
final html.ImageElement imageElement =
final web.HTMLImageElement imageElement =
await imageResizer.loadImage(pngFile.path);
final html.CanvasElement canvas =
final web.HTMLCanvasElement canvas =
imageResizer.resizeImageElement(imageElement, null, null);
final XFile resizedImage =
await imageResizer.writeCanvasToFile(pngFile, canvas, null);
Expand Down Expand Up @@ -112,19 +113,21 @@ void main() {

Future<Size> _getImageSize(XFile file) async {
final Completer<Size> completer = Completer<Size>();
final html.ImageElement image = html.ImageElement(src: file.path);
image.onLoad.listen((html.Event event) {
completer.complete(Size(image.width!.toDouble(), image.height!.toDouble()));
final web.HTMLImageElement image =
web.document.createElement('img') as web.HTMLImageElement;
image.src = file.path;
image.onLoad.listen((web.Event event) {
completer.complete(Size(image.width.toDouble(), image.height.toDouble()));
});
image.onError.listen((html.Event event) {
image.onError.listen((web.Event event) {
completer.complete(Size.zero);
});
return completer.future;
}

html.File _base64ToFile(String data, String fileName) {
web.Blob _base64ToBlob(String data) {
final List<String> arr = data.split(',');
final String bstr = html.window.atob(arr[1]);
final String bstr = web.window.atob(arr[1]);
int n = bstr.length;
final Uint8List u8arr = Uint8List(n);

Expand All @@ -133,5 +136,5 @@ html.File _base64ToFile(String data, String fileName) {
n--;
}

return html.File(<Uint8List>[u8arr], fileName);
return Blob(<JSUint8Array>[u8arr.toJS].toJS);
}
Loading