Skip to content

Commit cfbcc94

Browse files
authored
[camera_web] Migrate to package:web (flutter#7012)
Fixes flutter#139748 Notes: - Some fields are no longer nullable in `package:web`. We need to decide if we want to make them nullable again.
1 parent 1520ffb commit cfbcc94

24 files changed

+1507
-1243
lines changed

packages/camera/camera/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.11.0+2
2+
3+
* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3.
4+
15
## 0.11.0+1
26

37
* Updates minimum supported SDK version to Flutter 3.16/Dart 3.2.

packages/camera/camera/example/pubspec.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,9 @@ dev_dependencies:
2828
integration_test:
2929
sdk: flutter
3030

31+
dependency_overrides:
32+
camera_web:
33+
path: ../../camera_web
34+
3135
flutter:
3236
uses-material-design: true

packages/camera/camera/example/web/index.html

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
Use of this source code is governed by a BSD-style license that can be
44
found in the LICENSE file. -->
55
<html>
6-
76
<head>
7+
<base href="$FLUTTER_BASE_HREF">
8+
89
<meta charset="UTF-8">
910
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
1011
<meta name="description" content="An example of the camera on the web.">
@@ -16,14 +17,12 @@
1617
<link rel="apple-touch-icon" href="icons/Icon-192.png">
1718

1819
<!-- Favicon -->
19-
<link rel="shortcut icon" type="image/png" href="favicon.png" />
20+
<link rel="icon" type="image/png" href="favicon.png"/>
2021

2122
<title>Camera Web Example</title>
2223
<link rel="manifest" href="manifest.json">
2324
</head>
24-
2525
<body>
2626
<script src="flutter_bootstrap.js" async></script>
2727
</body>
28-
2928
</html>

packages/camera/camera/pubspec.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ description: A Flutter plugin for controlling the camera. Supports previewing
44
Dart.
55
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera
66
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
7-
version: 0.11.0+1
7+
version: 0.11.0+2
88

99
environment:
10-
sdk: ^3.2.3
11-
flutter: ">=3.16.6"
10+
sdk: ^3.3.0
11+
flutter: ">=3.19.0"
1212

1313
flutter:
1414
plugin:

packages/camera/camera_web/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 0.3.5
2+
3+
* Migrates to package:web to support WASM
4+
* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3.
5+
16
## 0.3.4
27

38
* Removes `maxVideoDuration`/`maxDuration`, as the feature was never exposed at

packages/camera/camera_web/example/integration_test/camera_bitrate_test.dart

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:html';
5+
import 'dart:js_interop';
66
import 'dart:math';
77
import 'dart:ui';
88

@@ -13,6 +13,7 @@ import 'package:camera_web/src/types/types.dart';
1313
import 'package:flutter_test/flutter_test.dart';
1414
import 'package:integration_test/integration_test.dart';
1515
import 'package:mocktail/mocktail.dart';
16+
import 'package:web/web.dart';
1617

1718
import 'helpers/helpers.dart';
1819

@@ -22,7 +23,7 @@ void main() {
2223
const Size videoSize = Size(320, 240);
2324

2425
/// Draw some seconds of random video frames on canvas in realtime.
25-
Future<void> simulateCamera(CanvasElement canvasElement) async {
26+
Future<void> simulateCamera(HTMLCanvasElement canvasElement) async {
2627
const int fps = 15;
2728
const int seconds = 3;
2829
const int frameDuration = 1000 ~/ fps;
@@ -34,8 +35,10 @@ void main() {
3435
final int h = videoSize.height ~/ 20;
3536
for (int y = 0; y < videoSize.height; y += h) {
3637
for (int x = 0; x < videoSize.width; x += w) {
37-
canvasElement.context2D.setFillColorRgb(
38-
random.nextInt(255), random.nextInt(255), random.nextInt(255));
38+
final int r = random.nextInt(255);
39+
final int g = random.nextInt(255);
40+
final int b = random.nextInt(255);
41+
canvasElement.context2D.fillStyle = 'rgba($r, $g, $b, 1)'.toJS;
3942
canvasElement.context2D.fillRect(x, y, w, h);
4043
}
4144
}
@@ -53,19 +56,25 @@ void main() {
5356
bool isVideoTypeSupported(String type) => type == supportedVideoType;
5457

5558
Future<int> recordVideo(int videoBitrate) async {
56-
final Window window = MockWindow();
57-
final Navigator navigator = MockNavigator();
58-
final MediaDevices mediaDevices = MockMediaDevices();
59+
final MockWindow mockWindow = MockWindow();
60+
final MockNavigator mockNavigator = MockNavigator();
61+
final MockMediaDevices mockMediaDevices = MockMediaDevices();
5962

60-
when(() => window.navigator).thenReturn(navigator);
61-
when(() => navigator.mediaDevices).thenReturn(mediaDevices);
63+
final Window window = createJSInteropWrapper(mockWindow) as Window;
64+
final Navigator navigator =
65+
createJSInteropWrapper(mockNavigator) as Navigator;
66+
final MediaDevices mediaDevices =
67+
createJSInteropWrapper(mockMediaDevices) as MediaDevices;
6268

63-
final CanvasElement canvasElement = CanvasElement(
64-
width: videoSize.width.toInt(),
65-
height: videoSize.height.toInt(),
66-
)..context2D.clearRect(0, 0, videoSize.width, videoSize.height);
69+
mockWindow.navigator = navigator;
70+
mockNavigator.mediaDevices = mediaDevices;
6771

68-
final VideoElement videoElement = VideoElement();
72+
final HTMLCanvasElement canvasElement = HTMLCanvasElement()
73+
..width = videoSize.width.toInt()
74+
..height = videoSize.height.toInt()
75+
..context2D.clearRect(0, 0, videoSize.width, videoSize.height);
76+
77+
final HTMLVideoElement videoElement = HTMLVideoElement();
6978

7079
final MockCameraService cameraService = MockCameraService();
7180

packages/camera/camera_web/example/integration_test/camera_error_code_test.dart

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:html';
6-
75
// ignore: implementation_imports
6+
import 'dart:js_interop';
7+
88
import 'package:camera_web/src/types/types.dart';
99
import 'package:flutter_test/flutter_test.dart';
1010
import 'package:integration_test/integration_test.dart';
11+
import 'package:web/web.dart';
1112

1213
import 'helpers/helpers.dart';
1314

@@ -132,7 +133,8 @@ void main() {
132133
testWidgets('with aborted error code', (WidgetTester tester) async {
133134
expect(
134135
CameraErrorCode.fromMediaError(
135-
FakeMediaError(MediaError.MEDIA_ERR_ABORTED),
136+
createJSInteropWrapper(
137+
FakeMediaError(MediaError.MEDIA_ERR_ABORTED)) as MediaError,
136138
).toString(),
137139
equals('mediaErrorAborted'),
138140
);
@@ -141,7 +143,8 @@ void main() {
141143
testWidgets('with network error code', (WidgetTester tester) async {
142144
expect(
143145
CameraErrorCode.fromMediaError(
144-
FakeMediaError(MediaError.MEDIA_ERR_NETWORK),
146+
createJSInteropWrapper(
147+
FakeMediaError(MediaError.MEDIA_ERR_NETWORK)) as MediaError,
145148
).toString(),
146149
equals('mediaErrorNetwork'),
147150
);
@@ -150,7 +153,8 @@ void main() {
150153
testWidgets('with decode error code', (WidgetTester tester) async {
151154
expect(
152155
CameraErrorCode.fromMediaError(
153-
FakeMediaError(MediaError.MEDIA_ERR_DECODE),
156+
createJSInteropWrapper(
157+
FakeMediaError(MediaError.MEDIA_ERR_DECODE)) as MediaError,
154158
).toString(),
155159
equals('mediaErrorDecode'),
156160
);
@@ -160,7 +164,9 @@ void main() {
160164
(WidgetTester tester) async {
161165
expect(
162166
CameraErrorCode.fromMediaError(
163-
FakeMediaError(MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED),
167+
createJSInteropWrapper(
168+
FakeMediaError(MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED))
169+
as MediaError,
164170
).toString(),
165171
equals('mediaErrorSourceNotSupported'),
166172
);
@@ -169,7 +175,7 @@ void main() {
169175
testWidgets('with unknown error code', (WidgetTester tester) async {
170176
expect(
171177
CameraErrorCode.fromMediaError(
172-
FakeMediaError(5),
178+
createJSInteropWrapper(FakeMediaError(5)) as MediaError,
173179
).toString(),
174180
equals('mediaErrorUnknown'),
175181
);

packages/camera/camera_web/example/integration_test/camera_options_test.dart

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// found in the LICENSE file.
44

55
// ignore: implementation_imports
6+
import 'dart:js_interop';
7+
68
import 'package:camera_web/src/types/types.dart';
79
import 'package:flutter_test/flutter_test.dart';
810
import 'package:integration_test/integration_test.dart';
@@ -20,10 +22,10 @@ void main() {
2022
);
2123

2224
expect(
23-
cameraOptions.toJson(),
25+
cameraOptions.toMediaStreamConstraints().dartify(),
2426
equals(<String, Object>{
25-
'audio': cameraOptions.audio.toJson(),
26-
'video': cameraOptions.video.toJson(),
27+
'audio': cameraOptions.audio.toMediaStreamConstraints().dartify()!,
28+
'video': cameraOptions.video.toMediaStreamConstraints().dartify()!,
2729
}),
2830
);
2931
});
@@ -61,8 +63,8 @@ void main() {
6163
group('AudioConstraints', () {
6264
testWidgets('serializes correctly', (WidgetTester tester) async {
6365
expect(
64-
const AudioConstraints(enabled: true).toJson(),
65-
equals(true),
66+
const AudioConstraints(enabled: true).toMediaStreamConstraints(),
67+
true.toJS,
6668
);
6769
});
6870

@@ -84,7 +86,7 @@ void main() {
8486
);
8587

8688
expect(
87-
videoConstraints.toJson(),
89+
videoConstraints.toMediaStreamConstraints().dartify(),
8890
equals(<String, Object>{
8991
'facingMode': videoConstraints.facingMode!.toJson(),
9092
'width': videoConstraints.width!.toJson(),

0 commit comments

Comments
 (0)