Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
fda6409
Squash
Rexios80 Jun 28, 2024
83e183c
Fixing issues
Rexios80 Jun 28, 2024
fc97336
Fixing CI issues
Rexios80 Jun 28, 2024
04fcf95
Refactoring mocked functions to JSFunction
Rexios80 Jun 28, 2024
6f16798
Fixing tests
Rexios80 Jun 28, 2024
d28199a
Fixing tests
Rexios80 Jun 28, 2024
18ad29d
...
Rexios80 Jun 28, 2024
70790a0
...
Rexios80 Jun 28, 2024
4caa695
Revert "..."
Rexios80 Jun 28, 2024
252737a
...
Rexios80 Jun 28, 2024
bf29b16
...
Rexios80 Jun 29, 2024
0bc840f
Fix another test
Rexios80 Jun 29, 2024
3c95d15
Update flutter version constraints and set platform view height/width
Rexios80 Jun 29, 2024
04610ce
Update Flutter version constraint again
Rexios80 Jun 29, 2024
93dc388
Merge branch 'main' into feature/camera-web-migration-2
Rexios80 Jul 12, 2024
ed30f43
Merge branch 'main' into feature/camera-web-migration-2
Rexios80 Jul 13, 2024
bbdc895
Remove camera from `exclude_all_packages_app_wasm.yaml`
Rexios80 Jul 13, 2024
1c634ff
Merge remote-tracking branch 'origin/feature/camera-web-migration-2' …
Rexios80 Jul 13, 2024
0c28bdd
Merge branch 'main' into feature/camera-web-migration-2
Rexios80 Jul 15, 2024
fd5fe5f
Merge branch 'main' into feature/camera-web-migration-2
ditman Jul 17, 2024
b883134
Merge remote-tracking branch 'upstream/main' into feature/camera-web-…
Rexios80 Jul 18, 2024
4056e6e
Migrations for `package:web` version `1.0.0`
Rexios80 Jul 18, 2024
33d5f1a
Merge remote-tracking branch 'upstream/main' into feature/camera-web-…
Rexios80 Jul 22, 2024
e843357
Merge branch 'main' into feature/camera-web-migration-2
Rexios80 Jul 26, 2024
f930d4c
Merge remote-tracking branch 'upstream/main' into feature/camera-web-…
Rexios80 Jul 26, 2024
4340ed2
Merge branch 'main' into feature/camera-web-migration-2
ditman Aug 1, 2024
6cc3221
Make camera support web 0.5.1 too.
ditman Aug 2, 2024
9eef302
Make analyzer happy
ditman Aug 2, 2024
69eaf1a
Make yaml file empty, not null.
ditman Aug 2, 2024
ce85b20
Merge branch 'main' into feature/camera-web-migration-2
Rexios80 Aug 2, 2024
a270c4b
Replace XFile mock by fake XFile.
ditman Aug 5, 2024
1cf16c9
Remove unneeded ignore and note.
ditman Aug 5, 2024
abbdb12
Add toMediaStreamConstraints method in camera_options.dart
ditman Aug 5, 2024
a8ba0cd
Merge remote-tracking branch 'upstream/main' into feature/camera-web-…
Rexios80 Aug 5, 2024
7329278
Formatting
Rexios80 Aug 5, 2024
0c60ea4
Add trailing commas
Rexios80 Aug 5, 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
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// found in the LICENSE file.

// ignore: implementation_imports
import 'dart:js_interop';

import 'package:camera_web/src/types/types.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
Expand All @@ -20,10 +22,10 @@ void main() {
);

expect(
cameraOptions.toJson(),
cameraOptions.toMediaStreamConstraints().dartify(),
equals(<String, Object>{
'audio': cameraOptions.audio.toJson(),
'video': cameraOptions.video.toJson(),
'audio': cameraOptions.audio.toMediaStreamConstraints().dartify()!,
'video': cameraOptions.video.toMediaStreamConstraints().dartify()!,
}),
);
});
Expand Down Expand Up @@ -61,8 +63,8 @@ void main() {
group('AudioConstraints', () {
testWidgets('serializes correctly', (WidgetTester tester) async {
expect(
const AudioConstraints(enabled: true).toJson(),
equals(true),
const AudioConstraints(enabled: true).toMediaStreamConstraints(),
true.toJS,
);
});

Expand All @@ -84,7 +86,7 @@ void main() {
);

expect(
videoConstraints.toJson(),
videoConstraints.toMediaStreamConstraints().dartify(),
equals(<String, Object>{
'facingMode': videoConstraints.facingMode!.toJson(),
'width': videoConstraints.width!.toJson(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,10 @@ void main() {

await cameraService.getMediaStreamForOptions(options);

expect(capturedConstraints?.video.dartify(), options.video.toJson());
expect(capturedConstraints?.audio.dartify(), options.audio.toJson());
expect(capturedConstraints?.video.dartify(),
equals(options.video.toMediaStreamConstraints().dartify()));
expect(capturedConstraints?.audio.dartify(),
equals(options.audio.toMediaStreamConstraints().dartify()));
});

group('throws CameraWebException', () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1117,10 +1117,10 @@ void main() {
group('takePicture', () {
testWidgets('captures a picture', (WidgetTester tester) async {
final MockCamera camera = MockCamera();
final MockXFile capturedPicture = MockXFile();
final XFile capturedPicture = XFile('/bogus/test');

when(camera.takePicture)
.thenAnswer((Invocation _) => Future<XFile>.value(capturedPicture));
.thenAnswer((Invocation _) async => capturedPicture);

// Save the camera in the camera plugin.
(CameraPlatform.instance as CameraPlugin).cameras[cameraId] = camera;
Expand Down Expand Up @@ -1333,10 +1333,10 @@ void main() {
group('stopVideoRecording', () {
testWidgets('stops a video recording', (WidgetTester tester) async {
final MockCamera camera = MockCamera();
final MockXFile capturedVideo = MockXFile();
final XFile capturedVideo = XFile('/bogus/test');

when(camera.stopVideoRecording)
.thenAnswer((Invocation _) => Future<XFile>.value(capturedVideo));
.thenAnswer((Invocation _) async => capturedVideo);

// Save the camera in the camera plugin.
(CameraPlatform.instance as CameraPlugin).cameras[cameraId] = camera;
Expand All @@ -1354,11 +1354,12 @@ void main() {
final MockCamera camera = MockCamera();
final StreamController<ErrorEvent> videoRecordingErrorController =
StreamController<ErrorEvent>();
final XFile capturedVideo = XFile('/bogus/test');

when(camera.startVideoRecording).thenAnswer((Invocation _) async {});

when(camera.stopVideoRecording)
.thenAnswer((Invocation _) => Future<XFile>.value(MockXFile()));
.thenAnswer((Invocation _) async => capturedVideo);

when(() => camera.onVideoRecordingError)
.thenAnswer((Invocation _) => videoRecordingErrorController.stream);
Expand Down Expand Up @@ -3088,7 +3089,7 @@ void main() {
testWidgets('onVideoRecordedEvent emits a VideoRecordedEvent',
(WidgetTester tester) async {
final MockCamera camera = MockCamera();
final MockXFile capturedVideo = MockXFile();
final XFile capturedVideo = XFile('/bogus/test');
final Stream<VideoRecordedEvent> stream =
Stream<VideoRecordedEvent>.value(
VideoRecordedEvent(cameraId, capturedVideo, Duration.zero));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import 'package:camera_web/src/camera.dart';
import 'package:camera_web/src/camera_service.dart';
import 'package:camera_web/src/shims/dart_js_util.dart';
import 'package:camera_web/src/types/types.dart';
import 'package:cross_file/cross_file.dart';
import 'package:mocktail/mocktail.dart';
// TODO(srujzs): This is exported in `package:web` 0.6.0. Remove this when it is available.
import 'package:web/src/helpers/events/streams.dart';
Expand Down Expand Up @@ -102,8 +101,6 @@ class MockVideoElement {
web.MediaError? error;
}

class MockXFile extends Mock implements XFile {}

class MockJsUtil extends Mock implements JsUtil {}

@JSExport()
Expand Down
11 changes: 4 additions & 7 deletions packages/camera/camera_web/lib/src/camera.dart
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,6 @@ class Camera {

/// A builder to merge a list of blobs into a single blob.
@visibleForTesting
// TODO(stuartmorgan): Remove this 'ignore' once we don't analyze using 2.10
// any more. It's a false positive that is fixed in later versions.
// ignore: prefer_function_declarations_over_variables
web.Blob Function(List<web.Blob> blobs, String type) blobBuilder =
(List<web.Blob> blobs, String type) =>
web.Blob(blobs.toJS, web.BlobPropertyBag(type: type));
Expand Down Expand Up @@ -367,8 +364,8 @@ class Camera {
false;

if (canEnableTorchMode) {
defaultVideoTrack
.applyConstraints(web.MediaTrackConstraints(torch: enabled.toJS));
defaultVideoTrack.applyWebTweakConstraints(
WebTweakMediaTrackConstraints(torch: enabled.toJS));
} else {
throw CameraWebException(
textureId,
Expand Down Expand Up @@ -416,8 +413,8 @@ class Camera {
);
}

zoomLevelCapability.videoTrack
.applyConstraints(MediaTrackConstraints(zoom: zoom.toJS));
zoomLevelCapability.videoTrack.applyWebTweakConstraints(
WebTweakMediaTrackConstraints(zoom: zoom.toJS));
}

/// Returns a lens direction of this camera.
Expand Down
11 changes: 4 additions & 7 deletions packages/camera/camera_web/lib/src/camera_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ class CameraService {
try {
return await mediaDevices
.getUserMedia(
web.MediaStreamConstraints(
video: options.video.toJson().jsify()!,
audio: options.audio.toJson().jsify()!,
),
options.toMediaStreamConstraints(),
)
.toDart;
} on web.DOMException catch (e) {
Expand Down Expand Up @@ -137,13 +134,13 @@ class CameraService {

/// The zoom level capability is represented by MediaSettingsRange.
/// See: https://developer.mozilla.org/en-US/docs/Web/API/MediaSettingsRange
final web.MediaSettingsRange? zoomLevelCapability =
final WebTweakMediaSettingsRange? zoomLevelCapability =
defaultVideoTrack.getCapabilities().zoomNullable;

if (zoomLevelCapability != null) {
return ZoomLevelCapability(
minimum: zoomLevelCapability.min.toDouble(),
maximum: zoomLevelCapability.max.toDouble(),
minimum: zoomLevelCapability.min,
maximum: zoomLevelCapability.max,
videoTrack: defaultVideoTrack,
);
} else {
Expand Down
3 changes: 2 additions & 1 deletion packages/camera/camera_web/lib/src/camera_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import 'package:web/web.dart' as web;

import 'camera.dart';
import 'camera_service.dart';
import 'pkg_web_tweaks.dart';
import 'types/types.dart';

// The default error message, when the error is an empty string.
Expand Down Expand Up @@ -416,7 +417,7 @@ class CameraPlugin extends CameraPlatform {
// See: https://w3c.github.io/screen-orientation/#interaction-with-fullscreen-api
// Recent versions of Dart changed requestFullscreen to return a Future instead of void.
// This wrapper allows use of both the old and new APIs.
dynamic fullScreen() => documentElement.requestFullscreen();
dynamic fullScreen() => documentElement.requestFullScreenTweak();
await fullScreen();
await screenOrientation.lock(orientationType).toDart;
} else {
Expand Down
43 changes: 41 additions & 2 deletions packages/camera/camera_web/lib/src/pkg_web_tweaks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import 'dart:js_interop';

import 'package:web/web.dart';

/// Adds missing fields to [Element].
extension FullScreenSupportMethods on Element {
@JS('requestFullscreen')
external JSPromise<JSAny?> requestFullScreenTweak([JSAny options]);
}

/// Adds missing fields to [MediaTrackSupportedConstraints].
extension NonStandardFieldsOnMediaTrackSupportedConstraints
on MediaTrackSupportedConstraints {
Expand All @@ -19,10 +25,9 @@ extension NonStandardFieldsOnMediaTrackSupportedConstraints
}

/// Adds missing fields to [MediaTrackCapabilities].

extension NonStandardFieldsOnMediaTrackCapabilities on MediaTrackCapabilities {
@JS('zoom')
external MediaSettingsRange? get zoomNullable;
external WebTweakMediaSettingsRange? get zoomNullable;

@JS('torch')
external JSArray<JSBoolean>? get torchNullable;
Expand All @@ -33,3 +38,37 @@ extension NonStandardFieldsOnMediaTrackSettings on MediaTrackSettings {
@JS('facingMode')
external String? get facingModeNullable;
}

/// Brought over from package:web 1.0.0
extension type WebTweakMediaSettingsRange._(JSObject _) implements JSObject {
@JS('MediaSettingsRange')
external factory WebTweakMediaSettingsRange({
num max,
num min,
num step,
});

external double get max;
external set max(num value);
external double get min;
external set min(num value);
external double get step;
external set step(num value);
}

/// Adds an applyConstraints method that accepts the WebTweakMediaTrackConstraints.
extension WebTweakMethodVersions on MediaStreamTrack {
@JS('applyConstraints')
external JSPromise<JSAny?> applyWebTweakConstraints(
[WebTweakMediaTrackConstraints constraints]);
}

/// Allows creating the MediaTrackConstraints that are needed.
/// Brought over from package:web 1.0.0
extension type WebTweakMediaTrackConstraints._(JSObject _) implements JSObject {
@JS('MediaTrackConstraints')
external factory WebTweakMediaTrackConstraints({
JSAny zoom,
ConstrainBoolean torch,
});
}
54 changes: 28 additions & 26 deletions packages/camera/camera_web/lib/src/types/camera_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:js_interop';

import 'package:flutter/foundation.dart';
import 'package:web/web.dart' as web;

/// Options used to create a camera with the given
/// [audio] and [video] media constraints.
Expand All @@ -28,12 +31,12 @@ class CameraOptions {
/// The video constraints for the camera.
final VideoConstraints video;

/// Converts the current instance to a Map.
Map<String, dynamic> toJson() {
return <String, Object>{
'audio': audio.toJson(),
'video': video.toJson(),
};
/// Converts `this` to something that can be used by the browser.
web.MediaStreamConstraints toMediaStreamConstraints() {
return web.MediaStreamConstraints(
audio: audio.toMediaStreamConstraints(),
video: video.toMediaStreamConstraints(),
);
}

@override
Expand Down Expand Up @@ -63,8 +66,8 @@ class AudioConstraints {
/// Whether the audio track should be enabled.
final bool enabled;

/// Converts the current instance to a Map.
Object toJson() => enabled;
/// Convert `this` to something that can be used on the browser.
JSAny toMediaStreamConstraints() => enabled.toJS;

@override
bool operator ==(Object other) {
Expand Down Expand Up @@ -104,24 +107,19 @@ class VideoConstraints {
/// The device id of the video track.
final String? deviceId;

/// Converts the current instance to a Map.
Object toJson() {
final Map<String, dynamic> json = <String, dynamic>{};

if (width != null) {
json['width'] = width!.toJson();
}
if (height != null) {
json['height'] = height!.toJson();
}
if (facingMode != null) {
json['facingMode'] = facingMode!.toJson();
}
if (deviceId != null) {
json['deviceId'] = <String, Object>{'exact': deviceId!};
}

return json;
// TODO(dit): package:web has a class for this. Use it instead of jsify and toJson.
/// Convert `this` to something that can be used on the browser.
JSAny toMediaStreamConstraints() {
return <String, Object> {
if (width != null)
'width': width!.toJson(),
if (height != null)
'height': height!.toJson(),
if (facingMode != null)
'facingMode': facingMode!.toJson(),
if (deviceId != null)
'deviceId': <String, Object>{'exact': deviceId!},
}.jsify()!;
}

@override
Expand Down Expand Up @@ -162,6 +160,7 @@ enum CameraType {
String toString() => _type;
}

// TODO(dit): package:web has a class for this. Use it instead of toJson.
/// Indicates the direction in which the desired camera should be pointing.
@immutable
class FacingModeConstraint {
Expand Down Expand Up @@ -191,6 +190,7 @@ class FacingModeConstraint {
/// the desired facing [type] to be considered acceptable.
final CameraType? exact;

// TODO(dit): package:web has a class for this. Use it instead of toJson.
/// Converts the current instance to a Map.
Object toJson() {
return <String, Object>{
Expand All @@ -214,6 +214,7 @@ class FacingModeConstraint {
int get hashCode => Object.hash(ideal, exact);
}

// TODO(dit): package:web has a class for this. Use it instead of toJson.
/// The size of the requested video track used in
/// [VideoConstraints.width] and [VideoConstraints.height].
///
Expand All @@ -240,6 +241,7 @@ class VideoSizeConstraint {
/// The maximum video size.
final int? maximum;

// TODO(dit): package:web has a class for this. Use it instead of toJson.
/// Converts the current instance to a Map.
Object toJson() {
final Map<String, dynamic> json = <String, dynamic>{};
Expand Down
2 changes: 1 addition & 1 deletion packages/camera/camera_web/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ dependencies:
flutter_web_plugins:
sdk: flutter
stream_transform: ^2.0.0
web: ^1.0.0
web: ">=0.5.1 <2.0.0"

dev_dependencies:
flutter_test:
Expand Down
4 changes: 1 addition & 3 deletions script/configs/exclude_all_packages_app_wasm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,4 @@
# This is only used for wasm compilation. Once all packages in the repo have
# been migrated, remove this file and use `exclude_all_packages_app.yaml` only.

# Dependencies are not migrated yet
# https://github.com/flutter/flutter/issues/148624
- google_maps_flutter
[] # Needed so the contents of this file are an empty array, not `null`!