From 6925d10d66f4797fd6b7d001663c0a1aec1954ce Mon Sep 17 00:00:00 2001 From: Bartosz Selwesiuk Date: Fri, 23 Jul 2021 14:28:59 +0200 Subject: [PATCH 01/19] feat: add web to the example app --- .../camera/camera/example/web/favicon.png | Bin 0 -> 917 bytes .../camera/example/web/icons/Icon-192.png | Bin 0 -> 5292 bytes .../camera/example/web/icons/Icon-512.png | Bin 0 -> 8252 bytes packages/camera/camera/example/web/index.html | 36 ++++++++++++++++++ .../camera/camera/example/web/manifest.json | 23 +++++++++++ 5 files changed, 59 insertions(+) create mode 100644 packages/camera/camera/example/web/favicon.png create mode 100644 packages/camera/camera/example/web/icons/Icon-192.png create mode 100644 packages/camera/camera/example/web/icons/Icon-512.png create mode 100644 packages/camera/camera/example/web/index.html create mode 100644 packages/camera/camera/example/web/manifest.json diff --git a/packages/camera/camera/example/web/favicon.png b/packages/camera/camera/example/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/packages/camera/camera/example/web/icons/Icon-192.png b/packages/camera/camera/example/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/packages/camera/camera/example/web/icons/Icon-512.png b/packages/camera/camera/example/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/packages/camera/camera/example/web/index.html b/packages/camera/camera/example/web/index.html new file mode 100644 index 000000000000..3d2aa37242d9 --- /dev/null +++ b/packages/camera/camera/example/web/index.html @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + Camera Web Example + + + + + + + + + + \ No newline at end of file diff --git a/packages/camera/camera/example/web/manifest.json b/packages/camera/camera/example/web/manifest.json new file mode 100644 index 000000000000..5fe0e048afe6 --- /dev/null +++ b/packages/camera/camera/example/web/manifest.json @@ -0,0 +1,23 @@ +{ + "name": "camera example", + "short_name": "camera", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "An example of the camera on the web.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} From f318101182f8fd397c1bb1e5ab00342abfcb7fed Mon Sep 17 00:00:00 2001 From: Bartosz Selwesiuk Date: Fri, 13 Aug 2021 15:28:01 +0200 Subject: [PATCH 02/19] docs: update camera README --- packages/camera/camera/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/camera/camera/README.md b/packages/camera/camera/README.md index fb6144face9b..0c2d90bc0d2e 100644 --- a/packages/camera/camera/README.md +++ b/packages/camera/camera/README.md @@ -2,7 +2,7 @@ [![pub package](https://img.shields.io/pub/v/camera.svg)](https://pub.dev/packages/camera) -A Flutter plugin for iOS and Android allowing access to the device cameras. +A Flutter plugin for iOS, Android and Web allowing access to the device cameras. *Note*: This plugin is still under development, and some APIs might not be available yet. We are working on a refactor which can be followed here: [issue](https://github.com/flutter/flutter/issues/31225) @@ -45,6 +45,11 @@ minSdkVersion 21 It's important to note that the `MediaRecorder` class is not working properly on emulators, as stated in the documentation: https://developer.android.com/reference/android/media/MediaRecorder. Specifically, when recording a video with sound enabled and trying to play it back, the duration won't be correct and you will only see the first frame. +### Web integration + +For web integration details, see the +[`camera_web` package](https://pub.dev/packages/camera_web). + ### Handling Lifecycle states As of version [0.5.0](https://github.com/flutter/plugins/blob/master/packages/camera/CHANGELOG.md#050) of the camera plugin, lifecycle changes are no longer handled by the plugin. This means developers are now responsible to control camera resources when the lifecycle state is updated. Failure to do so might lead to unexpected behavior (for example as described in issue [#39109](https://github.com/flutter/flutter/issues/39109)). Handling lifecycle changes can be done by overriding the `didChangeAppLifecycleState` method like so: From 52b8608f61f230ba89ef0e4acbfee0e0f6cce47b Mon Sep 17 00:00:00 2001 From: Bartosz Selwesiuk Date: Fri, 13 Aug 2021 15:28:30 +0200 Subject: [PATCH 03/19] docs: update camera platform interface comments --- .../lib/src/platform_interface/camera_platform.dart | 13 ++++++++----- .../lib/src/types/resolution_preset.dart | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index 9e84e8fdf47c..ad55454d5ce3 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -64,6 +64,7 @@ abstract class CameraPlatform extends PlatformInterface { /// [imageFormatGroup] is used to specify the image formatting used. /// On Android this defaults to ImageFormat.YUV_420_888 and applies only to the imageStream. /// On iOS this defaults to kCVPixelFormatType_32BGRA. + /// On Web this parameter is currently not supported. Future initializeCamera( int cameraId, { ImageFormatGroup imageFormatGroup = ImageFormatGroup.unknown, @@ -71,12 +72,13 @@ abstract class CameraPlatform extends PlatformInterface { throw UnimplementedError('initializeCamera() is not implemented.'); } - /// The camera has been initialized + /// The camera has been initialized. Stream onCameraInitialized(int cameraId) { throw UnimplementedError('onCameraInitialized() is not implemented.'); } - /// The camera's resolution has changed + /// The camera's resolution has changed. + /// On Web this returns an empty stream. Stream onCameraResolutionChanged(int cameraId) { throw UnimplementedError('onResolutionChanged() is not implemented.'); } @@ -91,7 +93,7 @@ abstract class CameraPlatform extends PlatformInterface { throw UnimplementedError('onCameraError() is not implemented.'); } - /// The camera finished recording a video + /// The camera finished recording a video. Stream onVideoRecordedEvent(int cameraId) { throw UnimplementedError('onCameraTimeLimitReached() is not implemented.'); } @@ -154,6 +156,7 @@ abstract class CameraPlatform extends PlatformInterface { } /// Sets the flash mode for the selected camera. + /// On Web [FlashMode.auto] corresponds to [FlashMode.always]. Future setFlashMode(int cameraId, FlashMode mode) { throw UnimplementedError('setFlashMode() is not implemented.'); } @@ -228,8 +231,8 @@ abstract class CameraPlatform extends PlatformInterface { /// Set the zoom level for the selected camera. /// - /// The supplied [zoom] value should be between 1.0 and the maximum supported - /// zoom level returned by the `getMaxZoomLevel`. Throws a `CameraException` + /// The supplied [zoom] value should be between the minimum and the maximum supported + /// zoom level returned by `getMinZoomLevel` and `getMaxZoomLevel`. Throws a `CameraException` /// when an illegal zoom level is supplied. Future setZoomLevel(int cameraId, double zoom) { throw UnimplementedError('setZoomLevel() is not implemented.'); diff --git a/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart b/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart index 1724f6c97517..05df3ab41433 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart @@ -6,10 +6,10 @@ /// /// If a preset is not available on the camera being used a preset of lower quality will be selected automatically. enum ResolutionPreset { - /// 352x288 on iOS, 240p (320x240) on Android + /// 352x288 on iOS, 240p (320x240) on Android and Web low, - /// 480p (640x480 on iOS, 720x480 on Android) + /// 480p (640x480 on iOS, 720x480 on Android and Web) medium, /// 720p (1280x720) From 85dab2510b6d60f6e277faf87e985938aa9146dd Mon Sep 17 00:00:00 2001 From: Bartosz Selwesiuk Date: Fri, 13 Aug 2021 15:33:30 +0200 Subject: [PATCH 04/19] feat: update example to support web --- packages/camera/camera/example/lib/main.dart | 147 +++++++++++-------- 1 file changed, 88 insertions(+), 59 deletions(-) diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 2314aecbece3..0d39763f5c3a 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -8,6 +8,7 @@ import 'dart:async'; import 'dart:io'; import 'package:camera/camera.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; @@ -231,7 +232,14 @@ class _CameraExampleHomeState extends State ? Container() : SizedBox( child: (localVideoController == null) - ? Image.file(File(imageFile!.path)) + ? ( + // The captured image on the web contains a network-accessible URL + // pointing to a location within the browser. It may be displayed + // either with Image.network or Image.memory after loading the image + // bytes to memory. + kIsWeb + ? Image.network(imageFile!.path) + : Image.file(File(imageFile!.path))) : Container( child: Center( child: AspectRatio( @@ -267,17 +275,24 @@ class _CameraExampleHomeState extends State color: Colors.blue, onPressed: controller != null ? onFlashModeButtonPressed : null, ), - IconButton( - icon: Icon(Icons.exposure), - color: Colors.blue, - onPressed: - controller != null ? onExposureModeButtonPressed : null, - ), - IconButton( - icon: Icon(Icons.filter_center_focus), - color: Colors.blue, - onPressed: controller != null ? onFocusModeButtonPressed : null, - ), + // The exposure and focus mode are currently not supported on the web. + ...(!kIsWeb + ? [ + IconButton( + icon: Icon(Icons.exposure), + color: Colors.blue, + onPressed: controller != null + ? onExposureModeButtonPressed + : null, + ), + IconButton( + icon: Icon(Icons.filter_center_focus), + color: Colors.blue, + onPressed: + controller != null ? onFocusModeButtonPressed : null, + ) + ] + : []), IconButton( icon: Icon(enableAudio ? Icons.volume_up : Icons.volume_mute), color: Colors.blue, @@ -499,38 +514,43 @@ class _CameraExampleHomeState extends State ? onTakePictureButtonPressed : null, ), - IconButton( - icon: const Icon(Icons.videocam), - color: Colors.blue, - onPressed: cameraController != null && - cameraController.value.isInitialized && - !cameraController.value.isRecordingVideo - ? onVideoRecordButtonPressed - : null, - ), - IconButton( - icon: cameraController != null && - cameraController.value.isRecordingPaused - ? Icon(Icons.play_arrow) - : Icon(Icons.pause), - color: Colors.blue, - onPressed: cameraController != null && - cameraController.value.isInitialized && - cameraController.value.isRecordingVideo - ? (cameraController.value.isRecordingPaused) - ? onResumeButtonPressed - : onPauseButtonPressed - : null, - ), - IconButton( - icon: const Icon(Icons.stop), - color: Colors.red, - onPressed: cameraController != null && - cameraController.value.isInitialized && - cameraController.value.isRecordingVideo - ? onStopButtonPressed - : null, - ) + // Video recording is currently not supported on the web. + ...(!kIsWeb + ? [ + IconButton( + icon: const Icon(Icons.videocam), + color: Colors.blue, + onPressed: cameraController != null && + cameraController.value.isInitialized && + !cameraController.value.isRecordingVideo + ? onVideoRecordButtonPressed + : null, + ), + IconButton( + icon: cameraController != null && + cameraController.value.isRecordingPaused + ? Icon(Icons.play_arrow) + : Icon(Icons.pause), + color: Colors.blue, + onPressed: cameraController != null && + cameraController.value.isInitialized && + cameraController.value.isRecordingVideo + ? (cameraController.value.isRecordingPaused) + ? onResumeButtonPressed + : onPauseButtonPressed + : null, + ), + IconButton( + icon: const Icon(Icons.stop), + color: Colors.red, + onPressed: cameraController != null && + cameraController.value.isInitialized && + cameraController.value.isRecordingVideo + ? onStopButtonPressed + : null, + ) + ] + : []), ], ); } @@ -621,12 +641,17 @@ class _CameraExampleHomeState extends State try { await cameraController.initialize(); await Future.wait([ - cameraController - .getMinExposureOffset() - .then((value) => _minAvailableExposureOffset = value), - cameraController - .getMaxExposureOffset() - .then((value) => _maxAvailableExposureOffset = value), + // The exposure mode is currently not supported on the web. + ...(!kIsWeb + ? [ + cameraController + .getMinExposureOffset() + .then((value) => _minAvailableExposureOffset = value), + cameraController + .getMaxExposureOffset() + .then((value) => _maxAvailableExposureOffset = value) + ] + : []), cameraController .getMaxZoomLevel() .then((value) => _maxAvailableZoom = value), @@ -696,16 +721,20 @@ class _CameraExampleHomeState extends State } void onCaptureOrientationLockButtonPressed() async { - if (controller != null) { - final CameraController cameraController = controller!; - if (cameraController.value.isCaptureOrientationLocked) { - await cameraController.unlockCaptureOrientation(); - showInSnackBar('Capture orientation unlocked'); - } else { - await cameraController.lockCaptureOrientation(); - showInSnackBar( - 'Capture orientation locked to ${cameraController.value.lockedCaptureOrientation.toString().split('.').last}'); + try { + if (controller != null) { + final CameraController cameraController = controller!; + if (cameraController.value.isCaptureOrientationLocked) { + await cameraController.unlockCaptureOrientation(); + showInSnackBar('Capture orientation unlocked'); + } else { + await cameraController.lockCaptureOrientation(); + showInSnackBar( + 'Capture orientation locked to ${cameraController.value.lockedCaptureOrientation.toString().split('.').last}'); + } } + } on CameraException catch (e) { + _showCameraException(e); } } From 2c58b59323926b47da583ea38e97a1874bd373ae Mon Sep 17 00:00:00 2001 From: Bartosz Selwesiuk Date: Fri, 13 Aug 2021 15:43:56 +0200 Subject: [PATCH 05/19] build: update camera pubspec --- packages/camera/camera/pubspec.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 57161656fc03..2a928bbbc5da 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -1,6 +1,6 @@ name: camera description: A Flutter plugin for getting information about and controlling the - camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video, + camera on Android, iOS and Web. Supports previewing the camera feed, capturing images, capturing video, and streaming image buffers to dart. repository: https://github.com/flutter/plugins/tree/master/packages/camera/camera issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 @@ -18,9 +18,12 @@ flutter: pluginClass: CameraPlugin ios: pluginClass: CameraPlugin + web: + default_package: camera_web dependencies: camera_platform_interface: ^2.0.0 + camera_web: ^0.0.1 flutter: sdk: flutter pedantic: ^1.10.0 From f203e81982e7e1b710de17dad6b74b125db81d8b Mon Sep 17 00:00:00 2001 From: Bartosz Selwesiuk Date: Fri, 13 Aug 2021 15:53:04 +0200 Subject: [PATCH 06/19] docs: add copyright to camera example index.html --- packages/camera/camera/example/web/index.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/camera/camera/example/web/index.html b/packages/camera/camera/example/web/index.html index 3d2aa37242d9..2a3117d29362 100644 --- a/packages/camera/camera/example/web/index.html +++ b/packages/camera/camera/example/web/index.html @@ -1,4 +1,7 @@ + From 410e8536a6d75d812ea3a967cbd6b8a34055400c Mon Sep 17 00:00:00 2001 From: Bartosz Selwesiuk Date: Sat, 14 Aug 2021 01:04:33 +0200 Subject: [PATCH 07/19] [camera_web] Add support for pausing and resuming the camera preview (#4239) * chore: update camera_platform_interface to 2.1.0 * feat: add pause to Camera * test: add Camera pause test * feat: add pausePreview and resumePreview implementation * test: add pausePreview and resumePreview tests --- .../example/integration_test/camera_test.dart | 18 ++ .../integration_test/camera_web_test.dart | 165 ++++++++++++++++++ .../camera/camera_web/lib/src/camera.dart | 5 + .../camera/camera_web/lib/src/camera_web.dart | 21 +++ packages/camera/camera_web/pubspec.yaml | 2 +- 5 files changed, 210 insertions(+), 1 deletion(-) diff --git a/packages/camera/camera_web/example/integration_test/camera_test.dart b/packages/camera/camera_web/example/integration_test/camera_test.dart index 5c3d842502ba..1d1659352f26 100644 --- a/packages/camera/camera_web/example/integration_test/camera_test.dart +++ b/packages/camera/camera_web/example/integration_test/camera_test.dart @@ -214,6 +214,24 @@ void main() { }); }); + group('pause', () { + testWidgets('pauses the camera stream', (tester) async { + final camera = Camera( + textureId: textureId, + cameraService: cameraService, + ); + + await camera.initialize(); + await camera.play(); + + expect(camera.videoElement.paused, isFalse); + + camera.pause(); + + expect(camera.videoElement.paused, isTrue); + }); + }); + group('stop', () { testWidgets('resets the camera stream', (tester) async { final camera = Camera( diff --git a/packages/camera/camera_web/example/integration_test/camera_web_test.dart b/packages/camera/camera_web/example/integration_test/camera_web_test.dart index 6b03b6d77035..d48df122277f 100644 --- a/packages/camera/camera_web/example/integration_test/camera_web_test.dart +++ b/packages/camera/camera_web/example/integration_test/camera_web_test.dart @@ -1459,6 +1459,135 @@ void main() { }); }); + group('pausePreview', () { + testWidgets('calls pause on the camera', (tester) async { + final camera = MockCamera(); + + // Save the camera in the camera plugin. + (CameraPlatform.instance as CameraPlugin).cameras[cameraId] = camera; + + await CameraPlatform.instance.pausePreview(cameraId); + + verify(camera.pause).called(1); + }); + + group('throws PlatformException', () { + testWidgets( + 'with notFound error ' + 'if the camera does not exist', (tester) async { + expect( + () async => await CameraPlatform.instance.pausePreview(cameraId), + throwsA( + isA().having( + (e) => e.code, + 'code', + CameraErrorCode.notFound.toString(), + ), + ), + ); + }); + + testWidgets('when pause throws DomException', (tester) async { + final camera = MockCamera(); + final exception = FakeDomException(DomException.NOT_SUPPORTED); + + when(camera.pause).thenThrow(exception); + + // Save the camera in the camera plugin. + (CameraPlatform.instance as CameraPlugin).cameras[cameraId] = camera; + + expect( + () async => await CameraPlatform.instance.pausePreview(cameraId), + throwsA( + isA().having( + (e) => e.code, + 'code', + exception.name, + ), + ), + ); + }); + }); + }); + + group('resumePreview', () { + testWidgets('calls play on the camera', (tester) async { + final camera = MockCamera(); + + when(camera.play).thenAnswer((_) async => {}); + + // Save the camera in the camera plugin. + (CameraPlatform.instance as CameraPlugin).cameras[cameraId] = camera; + + await CameraPlatform.instance.resumePreview(cameraId); + + verify(camera.play).called(1); + }); + + group('throws PlatformException', () { + testWidgets( + 'with notFound error ' + 'if the camera does not exist', (tester) async { + expect( + () async => await CameraPlatform.instance.resumePreview(cameraId), + throwsA( + isA().having( + (e) => e.code, + 'code', + CameraErrorCode.notFound.toString(), + ), + ), + ); + }); + + testWidgets('when play throws DomException', (tester) async { + final camera = MockCamera(); + final exception = FakeDomException(DomException.NOT_SUPPORTED); + + when(camera.play).thenThrow(exception); + + // Save the camera in the camera plugin. + (CameraPlatform.instance as CameraPlugin).cameras[cameraId] = camera; + + expect( + () async => await CameraPlatform.instance.resumePreview(cameraId), + throwsA( + isA().having( + (e) => e.code, + 'code', + exception.name, + ), + ), + ); + }); + + testWidgets('when play throws CameraWebException', (tester) async { + final camera = MockCamera(); + final exception = CameraWebException( + cameraId, + CameraErrorCode.unknown, + 'description', + ); + + when(camera.play).thenThrow(exception); + + // Save the camera in the camera plugin. + (CameraPlatform.instance as CameraPlugin).cameras[cameraId] = camera; + + expect( + () async => await CameraPlatform.instance.resumePreview(cameraId), + throwsA( + isA().having( + (e) => e.code, + 'code', + exception.code.toString(), + ), + ), + ); + }); + }); + }); + testWidgets( 'buildPreview returns an HtmlElementView ' 'with an appropriate view type', (tester) async { @@ -1993,6 +2122,42 @@ void main() { await streamQueue.cancel(); }); + + testWidgets( + 'emits a CameraErrorEvent ' + 'on resumePreview error', (tester) async { + final exception = CameraWebException( + cameraId, + CameraErrorCode.unknown, + 'description', + ); + + when(camera.play).thenThrow(exception); + + final Stream eventStream = + CameraPlatform.instance.onCameraError(cameraId); + + final streamQueue = StreamQueue(eventStream); + + expect( + () async => await CameraPlatform.instance.resumePreview(cameraId), + throwsA( + isA(), + ), + ); + + expect( + await streamQueue.next, + equals( + CameraErrorEvent( + cameraId, + 'Error code: ${exception.code}, error message: ${exception.description}', + ), + ), + ); + + await streamQueue.cancel(); + }); }); testWidgets('onVideoRecordedEvent throws UnimplementedError', diff --git a/packages/camera/camera_web/lib/src/camera.dart b/packages/camera/camera_web/lib/src/camera.dart index 237f9858855e..c1343ceccf49 100644 --- a/packages/camera/camera_web/lib/src/camera.dart +++ b/packages/camera/camera_web/lib/src/camera.dart @@ -119,6 +119,11 @@ class Camera { await videoElement.play(); } + /// Pauses the camera stream on the current frame. + void pause() async { + videoElement.pause(); + } + /// Stops the camera stream and resets the camera source. void stop() { final tracks = videoElement.srcObject?.getTracks(); diff --git a/packages/camera/camera_web/lib/src/camera_web.dart b/packages/camera/camera_web/lib/src/camera_web.dart index 134e0726ba4b..8b131f5d4f6e 100644 --- a/packages/camera/camera_web/lib/src/camera_web.dart +++ b/packages/camera/camera_web/lib/src/camera_web.dart @@ -517,6 +517,27 @@ class CameraPlugin extends CameraPlatform { } } + @override + Future pausePreview(int cameraId) async { + try { + getCamera(cameraId).pause(); + } on html.DomException catch (e) { + throw PlatformException(code: e.name, message: e.message); + } + } + + @override + Future resumePreview(int cameraId) async { + try { + await getCamera(cameraId).play(); + } on html.DomException catch (e) { + throw PlatformException(code: e.name, message: e.message); + } on CameraWebException catch (e) { + _addCameraErrorEvent(e); + throw PlatformException(code: e.code.toString(), message: e.description); + } + } + @override Widget buildPreview(int cameraId) { return HtmlElementView( diff --git a/packages/camera/camera_web/pubspec.yaml b/packages/camera/camera_web/pubspec.yaml index a2aa43c22d65..c4d78999f273 100644 --- a/packages/camera/camera_web/pubspec.yaml +++ b/packages/camera/camera_web/pubspec.yaml @@ -21,7 +21,7 @@ flutter: fileName: camera_web.dart dependencies: - camera_platform_interface: ^2.0.1 + camera_platform_interface: ^2.1.0 flutter: sdk: flutter flutter_web_plugins: From 17b7b2de97c0777f70e5c4e3dc7982364bd0e2ed Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Wed, 25 Aug 2021 16:18:16 -0700 Subject: [PATCH 08/19] Unendorse camera_web for now, but use it in the example app. --- packages/camera/camera/example/pubspec.yaml | 5 +++++ packages/camera/camera/pubspec.yaml | 3 --- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/camera/camera/example/pubspec.yaml b/packages/camera/camera/example/pubspec.yaml index eb8995e2f354..dd497154ef02 100644 --- a/packages/camera/camera/example/pubspec.yaml +++ b/packages/camera/camera/example/pubspec.yaml @@ -14,6 +14,11 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ + camera_web: + git: + url: https://github.com/flutter/plugins.git + ref: master + path: packages/camera/camera_web path_provider: ^2.0.0 flutter: sdk: flutter diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 2a928bbbc5da..2033b9fa7d98 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -18,12 +18,9 @@ flutter: pluginClass: CameraPlugin ios: pluginClass: CameraPlugin - web: - default_package: camera_web dependencies: camera_platform_interface: ^2.0.0 - camera_web: ^0.0.1 flutter: sdk: flutter pedantic: ^1.10.0 From 277407a9fcdc87289af89d1fbafea6abe93c37cb Mon Sep 17 00:00:00 2001 From: Bartosz Selwesiuk Date: Tue, 24 Aug 2021 18:24:21 +0200 Subject: [PATCH 09/19] feat: move previous camera controller dispose to finally in case of an uncaught exception --- packages/camera/camera/example/lib/main.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 0d39763f5c3a..6a34321929ca 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -661,13 +661,13 @@ class _CameraExampleHomeState extends State ]); } on CameraException catch (e) { _showCameraException(e); - } + } finally { + if (mounted) { + setState(() {}); + } - if (mounted) { - setState(() {}); + await previousCameraController?.dispose(); } - - await previousCameraController?.dispose(); } void onTakePictureButtonPressed() { From 7c1be26a2f0c5e3820dec89d12f2286c3d6bde9b Mon Sep 17 00:00:00 2001 From: Bartosz Selwesiuk Date: Fri, 27 Aug 2021 13:18:37 +0200 Subject: [PATCH 10/19] feat: do not rotate camera preview on the web --- packages/camera/camera/lib/src/camera_preview.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/camera/camera/lib/src/camera_preview.dart b/packages/camera/camera/lib/src/camera_preview.dart index 1df9f8e2e393..ad2116bd46d2 100644 --- a/packages/camera/camera/lib/src/camera_preview.dart +++ b/packages/camera/camera/lib/src/camera_preview.dart @@ -43,7 +43,7 @@ class CameraPreview extends StatelessWidget { } Widget _wrapInRotatedBox({required Widget child}) { - if (defaultTargetPlatform != TargetPlatform.android) { + if (kIsWeb || defaultTargetPlatform != TargetPlatform.android) { return child; } From 69fa8d2c386ea3b36a904acef7a0d61de14a4c29 Mon Sep 17 00:00:00 2001 From: Bartosz Selwesiuk Date: Fri, 27 Aug 2021 13:48:48 +0200 Subject: [PATCH 11/19] feat: use max camera resolution on the web --- packages/camera/camera/example/lib/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 8ff9796306fa..67c942cd657d 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -627,7 +627,7 @@ class _CameraExampleHomeState extends State final CameraController cameraController = CameraController( cameraDescription, - ResolutionPreset.medium, + kIsWeb ? ResolutionPreset.max : ResolutionPreset.medium, enableAudio: enableAudio, imageFormatGroup: ImageFormatGroup.jpeg, ); From ad5057472e07df63604489ec344c6a47d2de02a5 Mon Sep 17 00:00:00 2001 From: Bartosz Selwesiuk Date: Fri, 27 Aug 2021 14:06:42 +0200 Subject: [PATCH 12/19] docs: update resolution preset comments --- .../lib/src/types/resolution_preset.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart b/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart index 05df3ab41433..fcb6b83bbf14 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/resolution_preset.dart @@ -18,7 +18,7 @@ enum ResolutionPreset { /// 1080p (1920x1080) veryHigh, - /// 2160p (3840x2160) + /// 2160p (3840x2160 on Android and iOS, 4096x2160 on Web) ultraHigh, /// The highest resolution available. From 025410684a5bf7e7b97f44742fba19dd6c0125a9 Mon Sep 17 00:00:00 2001 From: Bartosz Selwesiuk Date: Mon, 30 Aug 2021 10:55:19 +0200 Subject: [PATCH 13/19] revert: #4236 --- packages/camera/camera/example/lib/main.dart | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 671f3aeedc9c..a271b4047de3 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -668,12 +668,10 @@ class _CameraExampleHomeState extends State ]); } on CameraException catch (e) { _showCameraException(e); - } finally { - if (mounted) { - setState(() {}); - } + } - await previousCameraController?.dispose(); + if (mounted) { + setState(() {}); } } From 52fca8539a6487c2bf94866418bae10ec7a4684a Mon Sep 17 00:00:00 2001 From: Bartosz Selwesiuk Date: Tue, 14 Sep 2021 15:54:12 +0200 Subject: [PATCH 14/19] feat: use network VideoPlayerController for the camera recordings --- packages/camera/camera/example/lib/main.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 10f1718e44c8..46b9b1b5f7e9 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -945,8 +945,10 @@ class _CameraExampleHomeState extends State return; } - final VideoPlayerController vController = - VideoPlayerController.file(File(videoFile!.path)); + final VideoPlayerController vController = kIsWeb + ? VideoPlayerController.network(videoFile!.path) + : VideoPlayerController.file(File(videoFile!.path)); + videoPlayerListener = () { if (videoController != null && videoController!.value.size != null) { // Refreshing the state to update video player with the correct ratio. From 6a051d991f6d5453550a5af28d1bb7b027408079 Mon Sep 17 00:00:00 2001 From: Bartosz Selwesiuk Date: Tue, 14 Sep 2021 15:58:31 +0200 Subject: [PATCH 15/19] docs: update readme --- packages/camera/camera_web/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/camera/camera_web/README.md b/packages/camera/camera_web/README.md index c6e1e0f13cab..032a345fad99 100644 --- a/packages/camera/camera_web/README.md +++ b/packages/camera/camera_web/README.md @@ -9,7 +9,7 @@ The web implementation of [`camera`][camera]. ### Depend on the package This package is not an [endorsed implementation](https://flutter.dev/docs/development/packages-and-plugins/developing-packages#endorsed-federated-plugin) -of the google_maps_flutter plugin yet, so you'll need to [add it explicitly](https://pub.dev/packages/camera_web/install). +of the camera plugin yet, so you'll need to [add it explicitly](https://pub.dev/packages/camera_web/install). ## Example From 6a146af8ae5f6109cb01695870ef0ebf92204e84 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 17 Sep 2021 18:29:59 -0700 Subject: [PATCH 16/19] Reenable video operations --- packages/camera/camera/example/lib/main.dart | 69 +++++++++----------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/packages/camera/camera/example/lib/main.dart b/packages/camera/camera/example/lib/main.dart index 46b9b1b5f7e9..a3a5d1d46391 100644 --- a/packages/camera/camera/example/lib/main.dart +++ b/packages/camera/camera/example/lib/main.dart @@ -521,43 +521,38 @@ class _CameraExampleHomeState extends State ? onTakePictureButtonPressed : null, ), - // Video recording is currently not supported on the web. - ...(!kIsWeb - ? [ - IconButton( - icon: const Icon(Icons.videocam), - color: Colors.blue, - onPressed: cameraController != null && - cameraController.value.isInitialized && - !cameraController.value.isRecordingVideo - ? onVideoRecordButtonPressed - : null, - ), - IconButton( - icon: cameraController != null && - cameraController.value.isRecordingPaused - ? Icon(Icons.play_arrow) - : Icon(Icons.pause), - color: Colors.blue, - onPressed: cameraController != null && - cameraController.value.isInitialized && - cameraController.value.isRecordingVideo - ? (cameraController.value.isRecordingPaused) - ? onResumeButtonPressed - : onPauseButtonPressed - : null, - ), - IconButton( - icon: const Icon(Icons.stop), - color: Colors.red, - onPressed: cameraController != null && - cameraController.value.isInitialized && - cameraController.value.isRecordingVideo - ? onStopButtonPressed - : null, - ), - ] - : []), + IconButton( + icon: const Icon(Icons.videocam), + color: Colors.blue, + onPressed: cameraController != null && + cameraController.value.isInitialized && + !cameraController.value.isRecordingVideo + ? onVideoRecordButtonPressed + : null, + ), + IconButton( + icon: cameraController != null && + cameraController.value.isRecordingPaused + ? Icon(Icons.play_arrow) + : Icon(Icons.pause), + color: Colors.blue, + onPressed: cameraController != null && + cameraController.value.isInitialized && + cameraController.value.isRecordingVideo + ? (cameraController.value.isRecordingPaused) + ? onResumeButtonPressed + : onPauseButtonPressed + : null, + ), + IconButton( + icon: const Icon(Icons.stop), + color: Colors.red, + onPressed: cameraController != null && + cameraController.value.isInitialized && + cameraController.value.isRecordingVideo + ? onStopButtonPressed + : null, + ), IconButton( icon: const Icon(Icons.pause_presentation), color: From d8878c4a57611581d52e80a0040b830217e0f0df Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 17 Sep 2021 18:31:06 -0700 Subject: [PATCH 17/19] Use endorsed version of camera_web --- packages/camera/camera/example/pubspec.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/camera/camera/example/pubspec.yaml b/packages/camera/camera/example/pubspec.yaml index 74732e75307e..1899835aca50 100644 --- a/packages/camera/camera/example/pubspec.yaml +++ b/packages/camera/camera/example/pubspec.yaml @@ -14,11 +14,6 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - camera_web: - git: - url: https://github.com/flutter/plugins.git - ref: master - path: packages/camera/camera_web path_provider: ^2.0.0 flutter: sdk: flutter From 3f8a625aac40c58bdf48bd0b10bbe1aee71ad381 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 17 Sep 2021 18:31:42 -0700 Subject: [PATCH 18/19] Endorse camera_web package. --- packages/camera/camera/CHANGELOG.md | 4 ++++ packages/camera/camera/pubspec.yaml | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 0e5385db44e0..62b5f1f9bd4c 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.4 + +* Add web support by endorsing `package:camera_web`. + ## 0.9.3+1 * Remove iOS 9 availability check around ultra high capture sessions. diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 99bec25daa3f..b8894d58ac3a 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -4,7 +4,7 @@ description: A Flutter plugin for getting information about and controlling the and streaming image buffers to dart. repository: https://github.com/flutter/plugins/tree/master/packages/camera/camera issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.3+1 +version: 0.9.4 environment: sdk: ">=2.14.0 <3.0.0" @@ -18,9 +18,12 @@ flutter: pluginClass: CameraPlugin ios: pluginClass: CameraPlugin + web: + default_package: camera_web dependencies: camera_platform_interface: ^2.1.0 + camera_web: ^0.2.1 flutter: sdk: flutter pedantic: ^1.10.0 From 798443e08b449a68d2584e7ea56d36499a99f279 Mon Sep 17 00:00:00 2001 From: David Iglesias Teixeira Date: Fri, 17 Sep 2021 18:52:25 -0700 Subject: [PATCH 19/19] Skip android-only tests on web. --- packages/camera/camera/test/camera_preview_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/camera/camera/test/camera_preview_test.dart b/packages/camera/camera/test/camera_preview_test.dart index 14afddaea070..32718f4d5169 100644 --- a/packages/camera/camera/test/camera_preview_test.dart +++ b/packages/camera/camera/test/camera_preview_test.dart @@ -221,7 +221,7 @@ void main() { debugDefaultTargetPlatformOverride = null; }); - }); + }, skip: kIsWeb); testWidgets('when not on Android there should not be a rotated box', (WidgetTester tester) async {