Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

[image_picker_for_web] Migrate image_picker to package:cross_file #4083

Merged
merged 26 commits into from
Jul 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4b3c599
Migrate image picker platform interface to cross_file
BeMacized Jun 21, 2021
f4fbd0c
[image_picker_for_web] Migration to cross_file
BeMacized Jun 23, 2021
2de19b4
Merge branch 'master' into issue/70886
BeMacized Jun 30, 2021
86f604b
Merge branch 'issue/70886' into issue/70886-impl-web
BeMacized Jun 30, 2021
68e2ef8
Re-added old methods and marked them as deprecated.
BeMacized Jun 30, 2021
d345b37
Merge branch 'issue/70886' into issue/70886-impl-web
BeMacized Jun 30, 2021
a0ab00e
Update to match platform interface changes
BeMacized Jun 30, 2021
a987170
Format & annotate deprecated classes.
BeMacized Jun 30, 2021
6ab2bb0
Merge branch 'issue/70886' into issue/70886-impl-web
BeMacized Jun 30, 2021
3fa10b9
Updated pubspec and changelog.
BeMacized Jun 30, 2021
c1ff8b2
Merge branch 'issue/70886' into issue/70886-impl-web
BeMacized Jun 30, 2021
addfe99
Updated platform interface dependency version
BeMacized Jun 30, 2021
aefff73
Updated changelog and pubspec version
BeMacized Jun 30, 2021
2c4cd91
Fix analysis issues for deprecations
BeMacized Jul 2, 2021
69969b2
Merge branch 'issue/70886' into issue/70886-impl-web
BeMacized Jul 2, 2021
29e0c40
Remove Deprecation tags so we don't break consumers of this package o…
ditman Jul 8, 2021
c74cebb
Merge branch 'master' into issue/70886
ditman Jul 8, 2021
0a082c8
Merge branch 'issue/70886' into issue/70886-impl-web
BeMacized Jul 8, 2021
4615db1
Temporary platform interface reference dependency
BeMacized Jul 8, 2021
faa1a99
Implement PR feedback
BeMacized Jul 8, 2021
afa61ab
Merge branch 'issue/70886' into issue/70886-impl-web
BeMacized Jul 8, 2021
e297f3f
Merge branch 'master' into issue/70886-impl-web
ditman Jul 9, 2021
60c2ffd
Depend on the published version of the platform interface
ditman Jul 9, 2021
5e7abfd
Remove Deprecated methods, so consumers don't break immediately.
ditman Jul 9, 2021
de50d56
Port tests from --platform=chrome to integration_test
ditman Jul 9, 2021
b01daeb
dart format
ditman Jul 9, 2021
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
2 changes: 1 addition & 1 deletion .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ task:
env:
# Currently missing; see https://github.com/flutter/flutter/issues/81982
# and https://github.com/flutter/flutter/issues/82211
PLUGINS_TO_EXCLUDE_INTEGRATION_TESTS: "file_selector,image_picker_for_web,shared_preferences_web"
PLUGINS_TO_EXCLUDE_INTEGRATION_TESTS: "file_selector,shared_preferences_web"
matrix:
CHANNEL: "master"
CHANNEL: "stable"
Expand Down
5 changes: 5 additions & 0 deletions packages/image_picker/image_picker_for_web/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 2.1.0

* Implemented `getImage`, `getVideo` and `getFile` methods that return `XFile` instances.
* Move tests to `example` directory, so they run as integration_tests with `flutter drive`.

# 2.0.0

* Migrate to null safety.
Expand Down
9 changes: 9 additions & 0 deletions packages/image_picker/image_picker_for_web/example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Testing

This package uses `package:integration_test` to run its tests in a web browser.

See [Plugin Tests > Web Tests](https://github.com/flutter/flutter/wiki/Plugin-Tests#web-tests)
in the Flutter wiki for instructions to setup and run the tests in this package.

Check [flutter.dev > Integration testing](https://flutter.dev/docs/testing/integration-tests)
for more info.
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,30 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

@TestOn('chrome') // Uses dart:html

import 'dart:convert';
import 'dart:html' as html;
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';

final String expectedStringContents = "Hello, world!";
final Uint8List bytes = utf8.encode(expectedStringContents) as Uint8List;
final html.File textFile = html.File([bytes], "hello.txt");

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

// Under test...
late ImagePickerPlugin plugin;

setUp(() {
plugin = ImagePickerPlugin();
});

test('Can select a file', () async {
testWidgets('Can select a file (Deprecated)', (WidgetTester tester) async {
final mockInput = html.FileUploadInputElement();

final overrides = ImagePickerPluginTestOverrides()
Expand All @@ -45,9 +46,30 @@ void main() {
expect((await file).readAsBytes(), completion(isNotEmpty));
});

testWidgets('Can select a file', (WidgetTester tester) async {
final mockInput = html.FileUploadInputElement();

final overrides = ImagePickerPluginTestOverrides()
..createInputElement = ((_, __) => mockInput)
..getFileFromInput = ((_) => textFile);

final plugin = ImagePickerPlugin(overrides: overrides);

// Init the pick file dialog...
final file = plugin.getFile();

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

// Now the file should be available
expect(file, completes);
// And readable
expect((await file).readAsBytes(), completion(isNotEmpty));
});

// There's no good way of detecting when the user has "aborted" the selection.

test('computeCaptureAttribute', () {
testWidgets('computeCaptureAttribute', (WidgetTester tester) async {
expect(
plugin.computeCaptureAttribute(ImageSource.gallery, CameraDevice.front),
isNull,
Expand All @@ -67,14 +89,14 @@ void main() {
});

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

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

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

expect(input.attributes, containsPair('accept', 'any'));
Expand Down
25 changes: 25 additions & 0 deletions packages/image_picker/image_picker_for_web/example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/material.dart';

void main() {
runApp(MyApp());
}

/// App for testing
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.ltr,
child: Text('Testing... Look at the console output for results!'),
);
}
}
21 changes: 21 additions & 0 deletions packages/image_picker/image_picker_for_web/example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: connectivity_for_web_integration_tests
publish_to: none

environment:
sdk: ">=2.12.0 <3.0.0"
flutter: ">=2.2.0"

dependencies:
image_picker_for_web:
path: ../
flutter:
sdk: flutter

dev_dependencies:
js: ^0.6.3
flutter_test:
sdk: flutter
flutter_driver:
sdk: flutter
integration_test:
sdk: flutter
22 changes: 22 additions & 0 deletions packages/image_picker/image_picker_for_web/example/run_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/bash
# Copyright 2013 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

if pgrep -lf chromedriver > /dev/null; then
echo "chromedriver is running."

if [ $# -eq 0 ]; then
echo "No target specified, running all tests..."
find integration_test/ -iname *_test.dart | xargs -n1 -i -t flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target='{}'
else
echo "Running test target: $1..."
set -x
flutter drive -d web-server --web-port=7357 --browser-name=chrome --driver=test_driver/integration_test.dart --target=$1
fi

else
echo "chromedriver is not running."
echo "Please, check the README.md for instructions on how to use run_test.sh"
fi

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:integration_test/integration_test_driver.dart';

Future<void> main() => integrationDriver();
13 changes: 13 additions & 0 deletions packages/image_picker/image_picker_for_web/example/web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<!-- Copyright 2013 The Flutter Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<html>
<head>
<meta charset="UTF-8">
<title>example</title>
</head>
<body>
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,68 @@ class ImagePickerPlugin extends ImagePickerPlatform {
return _getSelectedFile(input);
}

/// Returns an [XFile] with the image that was picked.
///
/// The `source` argument controls where the image comes from. This can
/// be either [ImageSource.camera] or [ImageSource.gallery].
///
/// Note that the `maxWidth`, `maxHeight` and `imageQuality` arguments are not supported on the web. If any of these arguments is supplied, it'll be silently ignored by the web version of the plugin.
///
/// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera].
/// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device.
/// Defaults to [CameraDevice.rear].
///
/// If no images were picked, the return value is null.
@override
Future<XFile> getImage({
required ImageSource source,
double? maxWidth,
double? maxHeight,
int? imageQuality,
CameraDevice preferredCameraDevice = CameraDevice.rear,
}) {
String? capture = computeCaptureAttribute(source, preferredCameraDevice);
return getFile(accept: _kAcceptImageMimeType, capture: capture);
}

/// Returns an [XFile] containing the video that was picked.
///
/// The [source] argument controls where the video comes from. This can
/// be either [ImageSource.camera] or [ImageSource.gallery].
///
/// Note that the `maxDuration` argument is not supported on the web. If the argument is supplied, it'll be silently ignored by the web version of the plugin.
///
/// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera].
/// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device.
/// Defaults to [CameraDevice.rear].
///
/// If no images were picked, the return value is null.
@override
Future<XFile> getVideo({
required ImageSource source,
CameraDevice preferredCameraDevice = CameraDevice.rear,
Duration? maxDuration,
}) {
String? capture = computeCaptureAttribute(source, preferredCameraDevice);
return getFile(accept: _kAcceptVideoMimeType, capture: capture);
}

/// Injects a file input with the specified accept+capture attributes, and
/// returns the PickedFile 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,
}) {
html.FileUploadInputElement input =
createInputElement(accept, capture) as html.FileUploadInputElement;
_injectAndActivate(input);
return _getSelectedXFile(input);
}

// DOM methods

/// Converts plugin configuration into a proper value for the `capture` attribute.
Expand Down Expand Up @@ -150,6 +212,26 @@ class ImagePickerPlugin extends ImagePickerPlatform {
return _completer.future;
}

Future<XFile> _getSelectedXFile(html.FileUploadInputElement input) {
final Completer<XFile> _completer = Completer<XFile>();
// Observe the input until we can return something
input.onChange.first.then((event) {
final objectUrl = _handleOnChangeEvent(event);
if (!_completer.isCompleted && objectUrl != null) {
_completer.complete(XFile(objectUrl));
}
Comment on lines +219 to +222
Copy link
Member

@ditman ditman Jul 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's extract the name on disk of the file from this event so we can initialize the XFile with it! (to fix flutter/flutter#58764)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

});
input.onError.first.then((event) {
if (!_completer.isCompleted) {
_completer.completeError(event);
}
});
// Note that we don't bother detaching from these streams, since the
// "input" gets re-created in the DOM every time the user needs to
// pick a file.
return _completer.future;
}

/// Initializes a DOM container where we can host input elements.
html.Element _ensureInitialized(String id) {
var target = html.querySelector('#${id}');
Expand Down
4 changes: 2 additions & 2 deletions packages/image_picker/image_picker_for_web/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: image_picker_for_web
description: Web platform implementation of image_picker
repository: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker_for_web
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
version: 2.0.0
version: 2.1.0

environment:
sdk: ">=2.12.0 <3.0.0"
Expand All @@ -20,7 +20,7 @@ dependencies:
sdk: flutter
flutter_web_plugins:
sdk: flutter
image_picker_platform_interface: ^2.0.0
image_picker_platform_interface: ^2.2.0
meta: ^1.3.0

dev_dependencies:
Expand Down
5 changes: 5 additions & 0 deletions packages/image_picker/image_picker_for_web/test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## test

This package uses integration tests for testing.

See `example/README.md` for more info.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter_test/flutter_test.dart';

void main() {
test('Tell the user where to find the real tests', () {
print('---');
print('This package uses integration_test for its tests.');
print('See `example/README.md` for more info.');
print('---');
});
}