From 61adbf5c6d9318264d365ea2cd7827a624e486aa Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 3 Jan 2023 14:12:36 -0800 Subject: [PATCH 01/11] Add flag --- .../camera/lib/src/camera_controller.dart | 39 +++++++++++++++---- .../example/lib/camera_controller.dart | 34 +++++++++++++--- .../example/lib/camera_controller.dart | 33 ++++++++++++---- 3 files changed, 85 insertions(+), 21 deletions(-) diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index b05e61bef9f8..9241b9299653 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -146,6 +146,11 @@ class CameraValue { /// /// Explicitly specified fields get the specified value, all other fields get /// the same value of the current object. + /// + /// Nullable orientations ([lockedCaptureOrientation], [recordingOrientation], + /// and [previewPauseOrientation]) default to current object's value if + /// specified as null. To have specified orientations explicitly interpreted, + /// set [clearNullOrientationsFlag] to true. CameraValue copyWith({ bool? isInitialized, bool? isRecordingVideo, @@ -164,6 +169,7 @@ class CameraValue { DeviceOrientation? recordingOrientation, bool? isPreviewPaused, DeviceOrientation? previewPauseOrientation, + bool clearNullOrientationsFlag = false, }) { return CameraValue( isInitialized: isInitialized ?? this.isInitialized, @@ -180,12 +186,16 @@ class CameraValue { exposurePointSupported ?? this.exposurePointSupported, focusPointSupported: focusPointSupported ?? this.focusPointSupported, deviceOrientation: deviceOrientation ?? this.deviceOrientation, - lockedCaptureOrientation: - lockedCaptureOrientation ?? this.lockedCaptureOrientation, - recordingOrientation: recordingOrientation ?? this.recordingOrientation, + lockedCaptureOrientation: clearNullOrientationsFlag + ? lockedCaptureOrientation + : lockedCaptureOrientation ?? this.lockedCaptureOrientation, + recordingOrientation: clearNullOrientationsFlag + ? recordingOrientation + : recordingOrientation ?? this.recordingOrientation, isPreviewPaused: isPreviewPaused ?? this.isPreviewPaused, - previewPauseOrientation: - previewPauseOrientation ?? this.previewPauseOrientation, + previewPauseOrientation: clearNullOrientationsFlag + ? previewPauseOrientation + : previewPauseOrientation ?? this.previewPauseOrientation, ); } @@ -367,7 +377,11 @@ class CameraController extends ValueNotifier { } try { await CameraPlatform.instance.resumePreview(_cameraId); - value = value.copyWith(isPreviewPaused: false); + value = value.copyWith( + isPreviewPaused: false, + lockedCaptureOrientation: value.lockedCaptureOrientation, + recordingOrientation: value.recordingOrientation, + clearNullOrientationsFlag: true); } on PlatformException catch (e) { throw CameraException(e.code, e.message); } @@ -519,7 +533,12 @@ class CameraController extends ValueNotifier { try { final XFile file = await CameraPlatform.instance.stopVideoRecording(_cameraId); - value = value.copyWith(isRecordingVideo: false); + value = value.copyWith( + isRecordingVideo: false, + lockedCaptureOrientation: value.lockedCaptureOrientation, + previewPauseOrientation: value.previewPauseOrientation, + clearNullOrientationsFlag: true, + ); return file; } on PlatformException catch (e) { throw CameraException(e.code, e.message); @@ -757,7 +776,11 @@ class CameraController extends ValueNotifier { Future unlockCaptureOrientation() async { try { await CameraPlatform.instance.unlockCaptureOrientation(_cameraId); - value = value.copyWith(); + value = value.copyWith( + recordingOrientation: value.recordingOrientation, + previewPauseOrientation: value.previewPauseOrientation, + clearNullOrientationsFlag: true, + ); } on PlatformException catch (e) { throw CameraException(e.code, e.message); } diff --git a/packages/camera/camera_android/example/lib/camera_controller.dart b/packages/camera/camera_android/example/lib/camera_controller.dart index 79bf4e8b01e1..9b1b6adbe3f2 100644 --- a/packages/camera/camera_android/example/lib/camera_controller.dart +++ b/packages/camera/camera_android/example/lib/camera_controller.dart @@ -95,6 +95,11 @@ class CameraValue { /// /// Explicitly specified fields get the specified value, all other fields get /// the same value of the current object. + /// + /// Nullable orientations ([lockedCaptureOrientation], [recordingOrientation], + /// and [previewPauseOrientation]) default to current object's value if + /// specified as null. To have specified orientations explicitly interpreted, + /// set [clearNullOrientationsFlag] to true. CameraValue copyWith({ bool? isInitialized, bool? isRecordingVideo, @@ -112,6 +117,7 @@ class CameraValue { DeviceOrientation? recordingOrientation, bool? isPreviewPaused, DeviceOrientation? previewPauseOrientation, + bool clearNullOrientationsFlag = false, }) { return CameraValue( isInitialized: isInitialized ?? this.isInitialized, @@ -124,12 +130,16 @@ class CameraValue { exposureMode: exposureMode ?? this.exposureMode, focusMode: focusMode ?? this.focusMode, deviceOrientation: deviceOrientation ?? this.deviceOrientation, - lockedCaptureOrientation: - lockedCaptureOrientation ?? this.lockedCaptureOrientation, - recordingOrientation: recordingOrientation ?? this.recordingOrientation, + lockedCaptureOrientation: clearNullOrientationsFlag + ? lockedCaptureOrientation + : lockedCaptureOrientation ?? this.lockedCaptureOrientation, + recordingOrientation: clearNullOrientationsFlag + ? recordingOrientation + : recordingOrientation ?? this.recordingOrientation, isPreviewPaused: isPreviewPaused ?? this.isPreviewPaused, - previewPauseOrientation: - previewPauseOrientation ?? this.previewPauseOrientation, + previewPauseOrientation: clearNullOrientationsFlag + ? previewPauseOrientation + : previewPauseOrientation ?? this.previewPauseOrientation, ); } @@ -264,7 +274,11 @@ class CameraController extends ValueNotifier { /// Resumes the current camera preview Future resumePreview() async { await CameraPlatform.instance.resumePreview(_cameraId); - value = value.copyWith(isPreviewPaused: false); + value = value.copyWith( + isPreviewPaused: false, + lockedCaptureOrientation: value.lockedCaptureOrientation, + recordingOrientation: value.recordingOrientation, + clearNullOrientationsFlag: true); } /// Captures an image and returns the file where it was saved. @@ -324,6 +338,9 @@ class CameraController extends ValueNotifier { value = value.copyWith( isRecordingVideo: false, isRecordingPaused: false, + lockedCaptureOrientation: value.lockedCaptureOrientation, + previewPauseOrientation: value.previewPauseOrientation, + clearNullOrientationsFlag: true, ); return file; } @@ -398,6 +415,11 @@ class CameraController extends ValueNotifier { /// Unlocks the capture orientation. Future unlockCaptureOrientation() async { await CameraPlatform.instance.unlockCaptureOrientation(_cameraId); + value = value.copyWith( + recordingOrientation: value.recordingOrientation, + previewPauseOrientation: value.previewPauseOrientation, + clearNullOrientationsFlag: true, + ); } /// Sets the focus mode for taking pictures. diff --git a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart index 47c1f6f0415b..8cf170ac9412 100644 --- a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart +++ b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart @@ -112,6 +112,7 @@ class CameraValue { DeviceOrientation? recordingOrientation, bool? isPreviewPaused, DeviceOrientation? previewPauseOrientation, + bool clearNullOrientationsFlag = false, }) { return CameraValue( isInitialized: isInitialized ?? this.isInitialized, @@ -124,12 +125,16 @@ class CameraValue { exposureMode: exposureMode ?? this.exposureMode, focusMode: focusMode ?? this.focusMode, deviceOrientation: deviceOrientation ?? this.deviceOrientation, - lockedCaptureOrientation: - lockedCaptureOrientation ?? this.lockedCaptureOrientation, - recordingOrientation: recordingOrientation ?? this.recordingOrientation, + lockedCaptureOrientation: clearNullOrientationsFlag + ? lockedCaptureOrientation + : lockedCaptureOrientation ?? this.lockedCaptureOrientation, + recordingOrientation: clearNullOrientationsFlag + ? recordingOrientation + : recordingOrientation ?? this.recordingOrientation, isPreviewPaused: isPreviewPaused ?? this.isPreviewPaused, - previewPauseOrientation: - previewPauseOrientation ?? this.previewPauseOrientation, + previewPauseOrientation: clearNullOrientationsFlag + ? previewPauseOrientation + : previewPauseOrientation ?? this.previewPauseOrientation, ); } @@ -264,7 +269,11 @@ class CameraController extends ValueNotifier { /// Resumes the current camera preview Future resumePreview() async { await CameraPlatform.instance.resumePreview(_cameraId); - value = value.copyWith(isPreviewPaused: false); + value = value.copyWith( + isPreviewPaused: false, + lockedCaptureOrientation: value.lockedCaptureOrientation, + recordingOrientation: value.recordingOrientation, + clearNullOrientationsFlag: true); } /// Captures an image and returns the file where it was saved. @@ -321,7 +330,12 @@ class CameraController extends ValueNotifier { final XFile file = await CameraPlatform.instance.stopVideoRecording(_cameraId); - value = value.copyWith(isRecordingVideo: false); + value = value.copyWith( + isRecordingVideo: false, + lockedCaptureOrientation: value.lockedCaptureOrientation, + previewPauseOrientation: value.previewPauseOrientation, + clearNullOrientationsFlag: true, + ); return file; } @@ -395,6 +409,11 @@ class CameraController extends ValueNotifier { /// Unlocks the capture orientation. Future unlockCaptureOrientation() async { await CameraPlatform.instance.unlockCaptureOrientation(_cameraId); + value = value.copyWith( + recordingOrientation: value.recordingOrientation, + previewPauseOrientation: value.previewPauseOrientation, + clearNullOrientationsFlag: true, + ); } /// Sets the focus mode for taking pictures. From 1e69503adef06e78b1efc3337cc2c10ed258baf7 Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 3 Jan 2023 14:17:58 -0800 Subject: [PATCH 02/11] Add missing comment --- .../camera_avfoundation/example/lib/camera_controller.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart index 8cf170ac9412..61813f59e81c 100644 --- a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart +++ b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart @@ -95,6 +95,11 @@ class CameraValue { /// /// Explicitly specified fields get the specified value, all other fields get /// the same value of the current object. + /// + /// Nullable orientations ([lockedCaptureOrientation], [recordingOrientation], + /// and [previewPauseOrientation]) default to current object's value if + /// specified as null. To have specified orientations explicitly interpreted, + /// set [clearNullOrientationsFlag] to true. CameraValue copyWith({ bool? isInitialized, bool? isRecordingVideo, From ad781584c2f9c0abc961f7adc9c8a3d6a0805b36 Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 3 Jan 2023 15:38:09 -0800 Subject: [PATCH 03/11] Add tests --- packages/camera/camera/test/camera_test.dart | 86 ++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index 2138f2d055a5..a4ef7bc6fc66 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -359,6 +359,85 @@ void main() { ))); }); + test( + 'stopVideoRecording() throws $CameraException when not recording video', + () async { + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + + cameraController.value = + cameraController.value.copyWith(isRecordingVideo: false); + + expect( + cameraController.stopVideoRecording(), + throwsA(isA().having( + (CameraException error) => error.description, + 'No video is recording', + 'stopVideoRecording was called when no video is recording.', + ))); + }); + + test('stopVideoRecording() calls $CameraPlatform', () async { + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + + cameraController.value = + cameraController.value.copyWith(isRecordingVideo: true); + + when(CameraPlatform.instance + .stopVideoRecording(cameraController.cameraId)) + .thenAnswer((_) => Future.value(XFile('bar/foo.mpeg'))); + + await cameraController.stopVideoRecording(); + + expect(cameraController.value.recordingOrientation, equals(null)); + + verify(CameraPlatform.instance + .stopVideoRecording(cameraController.cameraId)) + .called(1); + }); + + test('stopVideoRecording() throws $CameraException on $PlatformException', + () async { + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + cameraController.value = + cameraController.value.copyWith(isRecordingVideo: true); + + when(CameraPlatform.instance + .stopVideoRecording(cameraController.cameraId)) + .thenThrow(CameraException( + 'foo', + 'bar', + )); + + expect( + cameraController.stopVideoRecording(), + throwsA(isA().having( + (CameraException error) => error.description, + 'foo', + 'bar', + ))); + }); + test('getMaxZoomLevel() throws $CameraException when uninitialized', () async { final CameraController cameraController = CameraController( @@ -1242,6 +1321,7 @@ void main() { verify(CameraPlatform.instance.resumePreview(cameraController.cameraId)) .called(1); expect(cameraController.value.isPreviewPaused, equals(false)); + expect(cameraController.value.previewPauseOrientation, equals(null)); }); test('resumePreview() does not call $CameraPlatform when not paused', @@ -1457,6 +1537,12 @@ class MockCameraPlatform extends Mock {Duration? maxVideoDuration}) => Future.value(mockVideoRecordingXFile); + @override + Future stopVideoRecording(int cameraId) async => super.noSuchMethod( + Invocation.method(#stopVideoRecording, [cameraId]), + returnValue: Future.value(mockVideoRecordingXFile), + ) as Future; + @override Future lockCaptureOrientation( int? cameraId, DeviceOrientation? orientation) async => From 29b4bb573b86ce50ccda40e17b663e7cf00dee02 Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 3 Jan 2023 15:54:01 -0800 Subject: [PATCH 04/11] Bump versions --- packages/camera/camera/CHANGELOG.md | 4 ++++ packages/camera/camera/pubspec.yaml | 2 +- packages/camera/camera_android/CHANGELOG.md | 4 ++++ packages/camera/camera_android/pubspec.yaml | 2 +- packages/camera/camera_avfoundation/CHANGELOG.md | 4 ++++ packages/camera/camera_avfoundation/pubspec.yaml | 2 +- 6 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 84c7559d391b..99c7f853326b 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.10.2 + +* Adds option to `CameraValue`s `copyWith` method to explicitly interpret optional orientation values. + ## 0.10.1 * Remove usage of deprecated quiver Optional type. diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 33d704ef651f..a4cff8c95335 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -4,7 +4,7 @@ description: A Flutter plugin for controlling the camera. Supports previewing Dart. repository: https://github.com/flutter/plugins/tree/main/packages/camera/camera issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.10.1 +version: 0.10.2 environment: sdk: ">=2.14.0 <3.0.0" diff --git a/packages/camera/camera_android/CHANGELOG.md b/packages/camera/camera_android/CHANGELOG.md index 1b07c3005a4c..249193c85cd4 100644 --- a/packages/camera/camera_android/CHANGELOG.md +++ b/packages/camera/camera_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.10.3 + +* Adds option to `CameraValue`s `copyWith` method to explicitly interpret optional orientation values. + ## 0.10.2 * Remove usage of deprecated quiver Optional type. diff --git a/packages/camera/camera_android/pubspec.yaml b/packages/camera/camera_android/pubspec.yaml index 6f25af7d61fb..4ecf768bfe12 100644 --- a/packages/camera/camera_android/pubspec.yaml +++ b/packages/camera/camera_android/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_android description: Android implementation of the camera plugin. repository: https://github.com/flutter/plugins/tree/main/packages/camera/camera_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.10.2 +version: 0.10.3 environment: sdk: ">=2.14.0 <3.0.0" diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index 9217f2633322..e89ee6ab12a3 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.11 + +* Adds option to `CameraValue`s `copyWith` method to explicitly interpret optional orientation values. + ## 0.9.10 * Remove usage of deprecated quiver Optional type. diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index aa1c1106a774..bcd8c8aa547b 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_avfoundation description: iOS implementation of the camera plugin. repository: https://github.com/flutter/plugins/tree/main/packages/camera/camera_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.10 +version: 0.9.11 environment: sdk: ">=2.14.0 <3.0.0" From 39b924083622f6424eb98202325fa531c79dffb1 Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 17 Jan 2023 09:31:34 -0800 Subject: [PATCH 05/11] Stage changelog changes --- packages/camera/camera/CHANGELOG.md | 4 +- .../camera/lib/src/camera_controller.dart | 39 ++------- packages/camera/camera/test/camera_test.dart | 86 ------------------- packages/camera/camera_android/CHANGELOG.md | 2 +- .../example/lib/camera_controller.dart | 34 ++------ .../camera/camera_avfoundation/CHANGELOG.md | 2 +- .../example/lib/camera_controller.dart | 38 ++------ 7 files changed, 25 insertions(+), 180 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 99c7f853326b..608fff976769 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,6 +1,6 @@ -## 0.10.2 +## 0.10.3 -* Adds option to `CameraValue`s `copyWith` method to explicitly interpret optional orientation values. +* Adds back use of Optional type. ## 0.10.1 diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index 9241b9299653..b05e61bef9f8 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -146,11 +146,6 @@ class CameraValue { /// /// Explicitly specified fields get the specified value, all other fields get /// the same value of the current object. - /// - /// Nullable orientations ([lockedCaptureOrientation], [recordingOrientation], - /// and [previewPauseOrientation]) default to current object's value if - /// specified as null. To have specified orientations explicitly interpreted, - /// set [clearNullOrientationsFlag] to true. CameraValue copyWith({ bool? isInitialized, bool? isRecordingVideo, @@ -169,7 +164,6 @@ class CameraValue { DeviceOrientation? recordingOrientation, bool? isPreviewPaused, DeviceOrientation? previewPauseOrientation, - bool clearNullOrientationsFlag = false, }) { return CameraValue( isInitialized: isInitialized ?? this.isInitialized, @@ -186,16 +180,12 @@ class CameraValue { exposurePointSupported ?? this.exposurePointSupported, focusPointSupported: focusPointSupported ?? this.focusPointSupported, deviceOrientation: deviceOrientation ?? this.deviceOrientation, - lockedCaptureOrientation: clearNullOrientationsFlag - ? lockedCaptureOrientation - : lockedCaptureOrientation ?? this.lockedCaptureOrientation, - recordingOrientation: clearNullOrientationsFlag - ? recordingOrientation - : recordingOrientation ?? this.recordingOrientation, + lockedCaptureOrientation: + lockedCaptureOrientation ?? this.lockedCaptureOrientation, + recordingOrientation: recordingOrientation ?? this.recordingOrientation, isPreviewPaused: isPreviewPaused ?? this.isPreviewPaused, - previewPauseOrientation: clearNullOrientationsFlag - ? previewPauseOrientation - : previewPauseOrientation ?? this.previewPauseOrientation, + previewPauseOrientation: + previewPauseOrientation ?? this.previewPauseOrientation, ); } @@ -377,11 +367,7 @@ class CameraController extends ValueNotifier { } try { await CameraPlatform.instance.resumePreview(_cameraId); - value = value.copyWith( - isPreviewPaused: false, - lockedCaptureOrientation: value.lockedCaptureOrientation, - recordingOrientation: value.recordingOrientation, - clearNullOrientationsFlag: true); + value = value.copyWith(isPreviewPaused: false); } on PlatformException catch (e) { throw CameraException(e.code, e.message); } @@ -533,12 +519,7 @@ class CameraController extends ValueNotifier { try { final XFile file = await CameraPlatform.instance.stopVideoRecording(_cameraId); - value = value.copyWith( - isRecordingVideo: false, - lockedCaptureOrientation: value.lockedCaptureOrientation, - previewPauseOrientation: value.previewPauseOrientation, - clearNullOrientationsFlag: true, - ); + value = value.copyWith(isRecordingVideo: false); return file; } on PlatformException catch (e) { throw CameraException(e.code, e.message); @@ -776,11 +757,7 @@ class CameraController extends ValueNotifier { Future unlockCaptureOrientation() async { try { await CameraPlatform.instance.unlockCaptureOrientation(_cameraId); - value = value.copyWith( - recordingOrientation: value.recordingOrientation, - previewPauseOrientation: value.previewPauseOrientation, - clearNullOrientationsFlag: true, - ); + value = value.copyWith(); } on PlatformException catch (e) { throw CameraException(e.code, e.message); } diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index a4ef7bc6fc66..2138f2d055a5 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -359,85 +359,6 @@ void main() { ))); }); - test( - 'stopVideoRecording() throws $CameraException when not recording video', - () async { - final CameraController cameraController = CameraController( - const CameraDescription( - name: 'cam', - lensDirection: CameraLensDirection.back, - sensorOrientation: 90), - ResolutionPreset.max); - - await cameraController.initialize(); - - cameraController.value = - cameraController.value.copyWith(isRecordingVideo: false); - - expect( - cameraController.stopVideoRecording(), - throwsA(isA().having( - (CameraException error) => error.description, - 'No video is recording', - 'stopVideoRecording was called when no video is recording.', - ))); - }); - - test('stopVideoRecording() calls $CameraPlatform', () async { - final CameraController cameraController = CameraController( - const CameraDescription( - name: 'cam', - lensDirection: CameraLensDirection.back, - sensorOrientation: 90), - ResolutionPreset.max); - - await cameraController.initialize(); - - cameraController.value = - cameraController.value.copyWith(isRecordingVideo: true); - - when(CameraPlatform.instance - .stopVideoRecording(cameraController.cameraId)) - .thenAnswer((_) => Future.value(XFile('bar/foo.mpeg'))); - - await cameraController.stopVideoRecording(); - - expect(cameraController.value.recordingOrientation, equals(null)); - - verify(CameraPlatform.instance - .stopVideoRecording(cameraController.cameraId)) - .called(1); - }); - - test('stopVideoRecording() throws $CameraException on $PlatformException', - () async { - final CameraController cameraController = CameraController( - const CameraDescription( - name: 'cam', - lensDirection: CameraLensDirection.back, - sensorOrientation: 90), - ResolutionPreset.max); - - await cameraController.initialize(); - cameraController.value = - cameraController.value.copyWith(isRecordingVideo: true); - - when(CameraPlatform.instance - .stopVideoRecording(cameraController.cameraId)) - .thenThrow(CameraException( - 'foo', - 'bar', - )); - - expect( - cameraController.stopVideoRecording(), - throwsA(isA().having( - (CameraException error) => error.description, - 'foo', - 'bar', - ))); - }); - test('getMaxZoomLevel() throws $CameraException when uninitialized', () async { final CameraController cameraController = CameraController( @@ -1321,7 +1242,6 @@ void main() { verify(CameraPlatform.instance.resumePreview(cameraController.cameraId)) .called(1); expect(cameraController.value.isPreviewPaused, equals(false)); - expect(cameraController.value.previewPauseOrientation, equals(null)); }); test('resumePreview() does not call $CameraPlatform when not paused', @@ -1537,12 +1457,6 @@ class MockCameraPlatform extends Mock {Duration? maxVideoDuration}) => Future.value(mockVideoRecordingXFile); - @override - Future stopVideoRecording(int cameraId) async => super.noSuchMethod( - Invocation.method(#stopVideoRecording, [cameraId]), - returnValue: Future.value(mockVideoRecordingXFile), - ) as Future; - @override Future lockCaptureOrientation( int? cameraId, DeviceOrientation? orientation) async => diff --git a/packages/camera/camera_android/CHANGELOG.md b/packages/camera/camera_android/CHANGELOG.md index 249193c85cd4..79eb7cd875a2 100644 --- a/packages/camera/camera_android/CHANGELOG.md +++ b/packages/camera/camera_android/CHANGELOG.md @@ -1,6 +1,6 @@ ## 0.10.3 -* Adds option to `CameraValue`s `copyWith` method to explicitly interpret optional orientation values. +* Adds back use of Optional type defined in the app-facing package. ## 0.10.2 diff --git a/packages/camera/camera_android/example/lib/camera_controller.dart b/packages/camera/camera_android/example/lib/camera_controller.dart index 9b1b6adbe3f2..79bf4e8b01e1 100644 --- a/packages/camera/camera_android/example/lib/camera_controller.dart +++ b/packages/camera/camera_android/example/lib/camera_controller.dart @@ -95,11 +95,6 @@ class CameraValue { /// /// Explicitly specified fields get the specified value, all other fields get /// the same value of the current object. - /// - /// Nullable orientations ([lockedCaptureOrientation], [recordingOrientation], - /// and [previewPauseOrientation]) default to current object's value if - /// specified as null. To have specified orientations explicitly interpreted, - /// set [clearNullOrientationsFlag] to true. CameraValue copyWith({ bool? isInitialized, bool? isRecordingVideo, @@ -117,7 +112,6 @@ class CameraValue { DeviceOrientation? recordingOrientation, bool? isPreviewPaused, DeviceOrientation? previewPauseOrientation, - bool clearNullOrientationsFlag = false, }) { return CameraValue( isInitialized: isInitialized ?? this.isInitialized, @@ -130,16 +124,12 @@ class CameraValue { exposureMode: exposureMode ?? this.exposureMode, focusMode: focusMode ?? this.focusMode, deviceOrientation: deviceOrientation ?? this.deviceOrientation, - lockedCaptureOrientation: clearNullOrientationsFlag - ? lockedCaptureOrientation - : lockedCaptureOrientation ?? this.lockedCaptureOrientation, - recordingOrientation: clearNullOrientationsFlag - ? recordingOrientation - : recordingOrientation ?? this.recordingOrientation, + lockedCaptureOrientation: + lockedCaptureOrientation ?? this.lockedCaptureOrientation, + recordingOrientation: recordingOrientation ?? this.recordingOrientation, isPreviewPaused: isPreviewPaused ?? this.isPreviewPaused, - previewPauseOrientation: clearNullOrientationsFlag - ? previewPauseOrientation - : previewPauseOrientation ?? this.previewPauseOrientation, + previewPauseOrientation: + previewPauseOrientation ?? this.previewPauseOrientation, ); } @@ -274,11 +264,7 @@ class CameraController extends ValueNotifier { /// Resumes the current camera preview Future resumePreview() async { await CameraPlatform.instance.resumePreview(_cameraId); - value = value.copyWith( - isPreviewPaused: false, - lockedCaptureOrientation: value.lockedCaptureOrientation, - recordingOrientation: value.recordingOrientation, - clearNullOrientationsFlag: true); + value = value.copyWith(isPreviewPaused: false); } /// Captures an image and returns the file where it was saved. @@ -338,9 +324,6 @@ class CameraController extends ValueNotifier { value = value.copyWith( isRecordingVideo: false, isRecordingPaused: false, - lockedCaptureOrientation: value.lockedCaptureOrientation, - previewPauseOrientation: value.previewPauseOrientation, - clearNullOrientationsFlag: true, ); return file; } @@ -415,11 +398,6 @@ class CameraController extends ValueNotifier { /// Unlocks the capture orientation. Future unlockCaptureOrientation() async { await CameraPlatform.instance.unlockCaptureOrientation(_cameraId); - value = value.copyWith( - recordingOrientation: value.recordingOrientation, - previewPauseOrientation: value.previewPauseOrientation, - clearNullOrientationsFlag: true, - ); } /// Sets the focus mode for taking pictures. diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index e89ee6ab12a3..cfcedb5c92d6 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,6 +1,6 @@ ## 0.9.11 -* Adds option to `CameraValue`s `copyWith` method to explicitly interpret optional orientation values. +* Adds back use of Optional type defined in the app-facing package. ## 0.9.10 diff --git a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart index 61813f59e81c..47c1f6f0415b 100644 --- a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart +++ b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart @@ -95,11 +95,6 @@ class CameraValue { /// /// Explicitly specified fields get the specified value, all other fields get /// the same value of the current object. - /// - /// Nullable orientations ([lockedCaptureOrientation], [recordingOrientation], - /// and [previewPauseOrientation]) default to current object's value if - /// specified as null. To have specified orientations explicitly interpreted, - /// set [clearNullOrientationsFlag] to true. CameraValue copyWith({ bool? isInitialized, bool? isRecordingVideo, @@ -117,7 +112,6 @@ class CameraValue { DeviceOrientation? recordingOrientation, bool? isPreviewPaused, DeviceOrientation? previewPauseOrientation, - bool clearNullOrientationsFlag = false, }) { return CameraValue( isInitialized: isInitialized ?? this.isInitialized, @@ -130,16 +124,12 @@ class CameraValue { exposureMode: exposureMode ?? this.exposureMode, focusMode: focusMode ?? this.focusMode, deviceOrientation: deviceOrientation ?? this.deviceOrientation, - lockedCaptureOrientation: clearNullOrientationsFlag - ? lockedCaptureOrientation - : lockedCaptureOrientation ?? this.lockedCaptureOrientation, - recordingOrientation: clearNullOrientationsFlag - ? recordingOrientation - : recordingOrientation ?? this.recordingOrientation, + lockedCaptureOrientation: + lockedCaptureOrientation ?? this.lockedCaptureOrientation, + recordingOrientation: recordingOrientation ?? this.recordingOrientation, isPreviewPaused: isPreviewPaused ?? this.isPreviewPaused, - previewPauseOrientation: clearNullOrientationsFlag - ? previewPauseOrientation - : previewPauseOrientation ?? this.previewPauseOrientation, + previewPauseOrientation: + previewPauseOrientation ?? this.previewPauseOrientation, ); } @@ -274,11 +264,7 @@ class CameraController extends ValueNotifier { /// Resumes the current camera preview Future resumePreview() async { await CameraPlatform.instance.resumePreview(_cameraId); - value = value.copyWith( - isPreviewPaused: false, - lockedCaptureOrientation: value.lockedCaptureOrientation, - recordingOrientation: value.recordingOrientation, - clearNullOrientationsFlag: true); + value = value.copyWith(isPreviewPaused: false); } /// Captures an image and returns the file where it was saved. @@ -335,12 +321,7 @@ class CameraController extends ValueNotifier { final XFile file = await CameraPlatform.instance.stopVideoRecording(_cameraId); - value = value.copyWith( - isRecordingVideo: false, - lockedCaptureOrientation: value.lockedCaptureOrientation, - previewPauseOrientation: value.previewPauseOrientation, - clearNullOrientationsFlag: true, - ); + value = value.copyWith(isRecordingVideo: false); return file; } @@ -414,11 +395,6 @@ class CameraController extends ValueNotifier { /// Unlocks the capture orientation. Future unlockCaptureOrientation() async { await CameraPlatform.instance.unlockCaptureOrientation(_cameraId); - value = value.copyWith( - recordingOrientation: value.recordingOrientation, - previewPauseOrientation: value.previewPauseOrientation, - clearNullOrientationsFlag: true, - ); } /// Sets the focus mode for taking pictures. From ca483a7a2a4306de6f42f09e72a59f2c39f756b8 Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 17 Jan 2023 09:31:46 -0800 Subject: [PATCH 06/11] Revert "Fix examples analyze" This reverts commit 4db1858a29136f3fb07a223d94d7e68b6b8d4b7d. --- .../camera/lib/src/camera_controller.dart | 23 +++++++++++------- .../example/lib/camera_controller.dart | 21 +++++++++++----- .../example/lib/camera_controller.dart | 24 +++++++++++++------ 3 files changed, 47 insertions(+), 21 deletions(-) diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index b05e61bef9f8..dab0c2cd940e 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -9,6 +9,7 @@ import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:quiver/core.dart'; import '../camera.dart'; @@ -180,12 +181,16 @@ class CameraValue { exposurePointSupported ?? this.exposurePointSupported, focusPointSupported: focusPointSupported ?? this.focusPointSupported, deviceOrientation: deviceOrientation ?? this.deviceOrientation, - lockedCaptureOrientation: - lockedCaptureOrientation ?? this.lockedCaptureOrientation, - recordingOrientation: recordingOrientation ?? this.recordingOrientation, + lockedCaptureOrientation: lockedCaptureOrientation == null + ? this.lockedCaptureOrientation + : lockedCaptureOrientation.orNull, + recordingOrientation: recordingOrientation == null + ? this.recordingOrientation + : recordingOrientation.orNull, isPreviewPaused: isPreviewPaused ?? this.isPreviewPaused, - previewPauseOrientation: - previewPauseOrientation ?? this.previewPauseOrientation, + previewPauseOrientation: previewPauseOrientation == null + ? this.previewPauseOrientation + : previewPauseOrientation.orNull, ); } @@ -367,7 +372,8 @@ class CameraController extends ValueNotifier { } try { await CameraPlatform.instance.resumePreview(_cameraId); - value = value.copyWith(isPreviewPaused: false); + value = + value.copyWith(isPreviewPaused: false, previewPauseOrientation: null); } on PlatformException catch (e) { throw CameraException(e.code, e.message); } @@ -519,7 +525,8 @@ class CameraController extends ValueNotifier { try { final XFile file = await CameraPlatform.instance.stopVideoRecording(_cameraId); - value = value.copyWith(isRecordingVideo: false); + value = + value.copyWith(isRecordingVideo: false, recordingOrientation: null); return file; } on PlatformException catch (e) { throw CameraException(e.code, e.message); @@ -757,7 +764,7 @@ class CameraController extends ValueNotifier { Future unlockCaptureOrientation() async { try { await CameraPlatform.instance.unlockCaptureOrientation(_cameraId); - value = value.copyWith(); + value = value.copyWith(lockedCaptureOrientation: null); } on PlatformException catch (e) { throw CameraException(e.code, e.message); } diff --git a/packages/camera/camera_android/example/lib/camera_controller.dart b/packages/camera/camera_android/example/lib/camera_controller.dart index 79bf4e8b01e1..0350249abff7 100644 --- a/packages/camera/camera_android/example/lib/camera_controller.dart +++ b/packages/camera/camera_android/example/lib/camera_controller.dart @@ -8,6 +8,7 @@ import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:quiver/core.dart'; /// The state of a [CameraController]. class CameraValue { @@ -107,6 +108,7 @@ class CameraValue { FocusMode? focusMode, bool? exposurePointSupported, bool? focusPointSupported, + bool? isPreviewPaused, DeviceOrientation? deviceOrientation, DeviceOrientation? lockedCaptureOrientation, DeviceOrientation? recordingOrientation, @@ -124,12 +126,16 @@ class CameraValue { exposureMode: exposureMode ?? this.exposureMode, focusMode: focusMode ?? this.focusMode, deviceOrientation: deviceOrientation ?? this.deviceOrientation, - lockedCaptureOrientation: - lockedCaptureOrientation ?? this.lockedCaptureOrientation, - recordingOrientation: recordingOrientation ?? this.recordingOrientation, + lockedCaptureOrientation: lockedCaptureOrientation == null + ? this.lockedCaptureOrientation + : lockedCaptureOrientation.orNull, + recordingOrientation: recordingOrientation == null + ? this.recordingOrientation + : recordingOrientation.orNull, isPreviewPaused: isPreviewPaused ?? this.isPreviewPaused, - previewPauseOrientation: - previewPauseOrientation ?? this.previewPauseOrientation, + previewPauseOrientation: previewPauseOrientation == null + ? this.previewPauseOrientation + : previewPauseOrientation.orNull, ); } @@ -264,7 +270,8 @@ class CameraController extends ValueNotifier { /// Resumes the current camera preview Future resumePreview() async { await CameraPlatform.instance.resumePreview(_cameraId); - value = value.copyWith(isPreviewPaused: false); + value = + value.copyWith(isPreviewPaused: false, previewPauseOrientation: null); } /// Captures an image and returns the file where it was saved. @@ -324,6 +331,7 @@ class CameraController extends ValueNotifier { value = value.copyWith( isRecordingVideo: false, isRecordingPaused: false, + recordingOrientation: null, ); return file; } @@ -398,6 +406,7 @@ class CameraController extends ValueNotifier { /// Unlocks the capture orientation. Future unlockCaptureOrientation() async { await CameraPlatform.instance.unlockCaptureOrientation(_cameraId); + value = value.copyWith(lockedCaptureOrientation: null); } /// Sets the focus mode for taking pictures. diff --git a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart index 47c1f6f0415b..78f2321df8c9 100644 --- a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart +++ b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart @@ -8,6 +8,7 @@ import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:quiver/core.dart'; /// The state of a [CameraController]. class CameraValue { @@ -124,12 +125,16 @@ class CameraValue { exposureMode: exposureMode ?? this.exposureMode, focusMode: focusMode ?? this.focusMode, deviceOrientation: deviceOrientation ?? this.deviceOrientation, - lockedCaptureOrientation: - lockedCaptureOrientation ?? this.lockedCaptureOrientation, - recordingOrientation: recordingOrientation ?? this.recordingOrientation, + lockedCaptureOrientation: lockedCaptureOrientation == null + ? this.lockedCaptureOrientation + : lockedCaptureOrientation.orNull, + recordingOrientation: recordingOrientation == null + ? this.recordingOrientation + : recordingOrientation.orNull, isPreviewPaused: isPreviewPaused ?? this.isPreviewPaused, - previewPauseOrientation: - previewPauseOrientation ?? this.previewPauseOrientation, + previewPauseOrientation: previewPauseOrientation == null + ? this.previewPauseOrientation + : previewPauseOrientation.orNull, ); } @@ -264,7 +269,8 @@ class CameraController extends ValueNotifier { /// Resumes the current camera preview Future resumePreview() async { await CameraPlatform.instance.resumePreview(_cameraId); - value = value.copyWith(isPreviewPaused: false); + value = + value.copyWith(isPreviewPaused: false, previewPauseOrientation: null); } /// Captures an image and returns the file where it was saved. @@ -321,7 +327,10 @@ class CameraController extends ValueNotifier { final XFile file = await CameraPlatform.instance.stopVideoRecording(_cameraId); - value = value.copyWith(isRecordingVideo: false); + value = value.copyWith( + isRecordingVideo: false, + recordingOrientation: null, + ); return file; } @@ -395,6 +404,7 @@ class CameraController extends ValueNotifier { /// Unlocks the capture orientation. Future unlockCaptureOrientation() async { await CameraPlatform.instance.unlockCaptureOrientation(_cameraId); + value = value.copyWith(lockedCaptureOrientation: null); } /// Sets the focus mode for taking pictures. From 03f992ccaa9642282145e44c993b14e96b2700a6 Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 17 Jan 2023 09:40:14 -0800 Subject: [PATCH 07/11] Revert "[camera] Remove deprecated Optional type (#6870)" This reverts commit 3d8b73bf08bf746bcbcdd219eb87ced572cc529b. --- packages/camera/camera/CHANGELOG.md | 2 +- .../camera/lib/src/camera_controller.dart | 31 +++++++++++-------- .../camera/test/camera_preview_test.dart | 18 ++++++++--- packages/camera/camera/test/camera_test.dart | 4 ++- .../example/lib/camera_controller.dart | 28 ++++++++++------- .../example/lib/camera_controller.dart | 28 ++++++++++------- 6 files changed, 67 insertions(+), 44 deletions(-) diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index 608fff976769..8d80b0e43fd2 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.10.3 +## 0.10.2 * Adds back use of Optional type. diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index dab0c2cd940e..ed1c951925d8 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -161,10 +161,10 @@ class CameraValue { bool? exposurePointSupported, bool? focusPointSupported, DeviceOrientation? deviceOrientation, - DeviceOrientation? lockedCaptureOrientation, - DeviceOrientation? recordingOrientation, + Optional? lockedCaptureOrientation, + Optional? recordingOrientation, bool? isPreviewPaused, - DeviceOrientation? previewPauseOrientation, + Optional? previewPauseOrientation, }) { return CameraValue( isInitialized: isInitialized ?? this.isInitialized, @@ -358,8 +358,8 @@ class CameraController extends ValueNotifier { await CameraPlatform.instance.pausePreview(_cameraId); value = value.copyWith( isPreviewPaused: true, - previewPauseOrientation: - value.lockedCaptureOrientation ?? value.deviceOrientation); + previewPauseOrientation: Optional.of( + value.lockedCaptureOrientation ?? value.deviceOrientation)); } on PlatformException catch (e) { throw CameraException(e.code, e.message); } @@ -372,8 +372,9 @@ class CameraController extends ValueNotifier { } try { await CameraPlatform.instance.resumePreview(_cameraId); - value = - value.copyWith(isPreviewPaused: false, previewPauseOrientation: null); + value = value.copyWith( + isPreviewPaused: false, + previewPauseOrientation: const Optional.absent()); } on PlatformException catch (e) { throw CameraException(e.code, e.message); } @@ -504,8 +505,8 @@ class CameraController extends ValueNotifier { value = value.copyWith( isRecordingVideo: true, isRecordingPaused: false, - recordingOrientation: - value.lockedCaptureOrientation ?? value.deviceOrientation); + recordingOrientation: Optional.of( + value.lockedCaptureOrientation ?? value.deviceOrientation)); } on PlatformException catch (e) { throw CameraException(e.code, e.message); } @@ -525,8 +526,10 @@ class CameraController extends ValueNotifier { try { final XFile file = await CameraPlatform.instance.stopVideoRecording(_cameraId); - value = - value.copyWith(isRecordingVideo: false, recordingOrientation: null); + value = value.copyWith( + isRecordingVideo: false, + recordingOrientation: const Optional.absent(), + ); return file; } on PlatformException catch (e) { throw CameraException(e.code, e.message); @@ -744,7 +747,8 @@ class CameraController extends ValueNotifier { await CameraPlatform.instance.lockCaptureOrientation( _cameraId, orientation ?? value.deviceOrientation); value = value.copyWith( - lockedCaptureOrientation: orientation ?? value.deviceOrientation); + lockedCaptureOrientation: Optional.of( + orientation ?? value.deviceOrientation)); } on PlatformException catch (e) { throw CameraException(e.code, e.message); } @@ -764,7 +768,8 @@ class CameraController extends ValueNotifier { Future unlockCaptureOrientation() async { try { await CameraPlatform.instance.unlockCaptureOrientation(_cameraId); - value = value.copyWith(lockedCaptureOrientation: null); + value = value.copyWith( + lockedCaptureOrientation: const Optional.absent()); } on PlatformException catch (e) { throw CameraException(e.code, e.message); } diff --git a/packages/camera/camera/test/camera_preview_test.dart b/packages/camera/camera/test/camera_preview_test.dart index 546f4e925759..bedb0ea8e01f 100644 --- a/packages/camera/camera/test/camera_preview_test.dart +++ b/packages/camera/camera/test/camera_preview_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:quiver/core.dart'; class FakeController extends ValueNotifier implements CameraController { @@ -132,8 +133,11 @@ void main() { isInitialized: true, isRecordingVideo: true, deviceOrientation: DeviceOrientation.portraitUp, - lockedCaptureOrientation: DeviceOrientation.landscapeRight, - recordingOrientation: DeviceOrientation.landscapeLeft, + lockedCaptureOrientation: + const Optional.fromNullable( + DeviceOrientation.landscapeRight), + recordingOrientation: const Optional.fromNullable( + DeviceOrientation.landscapeLeft), previewSize: const Size(480, 640), ); @@ -163,8 +167,11 @@ void main() { controller.value = controller.value.copyWith( isInitialized: true, deviceOrientation: DeviceOrientation.portraitUp, - lockedCaptureOrientation: DeviceOrientation.landscapeRight, - recordingOrientation: DeviceOrientation.landscapeLeft, + lockedCaptureOrientation: + const Optional.fromNullable( + DeviceOrientation.landscapeRight), + recordingOrientation: const Optional.fromNullable( + DeviceOrientation.landscapeLeft), previewSize: const Size(480, 640), ); @@ -194,7 +201,8 @@ void main() { controller.value = controller.value.copyWith( isInitialized: true, deviceOrientation: DeviceOrientation.portraitUp, - recordingOrientation: DeviceOrientation.landscapeLeft, + recordingOrientation: const Optional.fromNullable( + DeviceOrientation.landscapeLeft), previewSize: const Size(480, 640), ); diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index 2138f2d055a5..3c12648f13b9 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -13,6 +13,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +import 'package:quiver/core.dart'; List get mockAvailableCameras => [ const CameraDescription( @@ -1190,7 +1191,8 @@ void main() { cameraController.value = cameraController.value.copyWith( isPreviewPaused: false, deviceOrientation: DeviceOrientation.portraitUp, - lockedCaptureOrientation: DeviceOrientation.landscapeRight); + lockedCaptureOrientation: + Optional.of(DeviceOrientation.landscapeRight)); await cameraController.pausePreview(); diff --git a/packages/camera/camera_android/example/lib/camera_controller.dart b/packages/camera/camera_android/example/lib/camera_controller.dart index 0350249abff7..ce91bc769f0a 100644 --- a/packages/camera/camera_android/example/lib/camera_controller.dart +++ b/packages/camera/camera_android/example/lib/camera_controller.dart @@ -110,10 +110,10 @@ class CameraValue { bool? focusPointSupported, bool? isPreviewPaused, DeviceOrientation? deviceOrientation, - DeviceOrientation? lockedCaptureOrientation, - DeviceOrientation? recordingOrientation, + Optional? lockedCaptureOrientation, + Optional? recordingOrientation, bool? isPreviewPaused, - DeviceOrientation? previewPauseOrientation, + Optional? previewPauseOrientation, }) { return CameraValue( isInitialized: isInitialized ?? this.isInitialized, @@ -263,15 +263,16 @@ class CameraController extends ValueNotifier { await CameraPlatform.instance.pausePreview(_cameraId); value = value.copyWith( isPreviewPaused: true, - previewPauseOrientation: - value.lockedCaptureOrientation ?? value.deviceOrientation); + previewPauseOrientation: Optional.of( + value.lockedCaptureOrientation ?? value.deviceOrientation)); } /// Resumes the current camera preview Future resumePreview() async { await CameraPlatform.instance.resumePreview(_cameraId); - value = - value.copyWith(isPreviewPaused: false, previewPauseOrientation: null); + value = value.copyWith( + isPreviewPaused: false, + previewPauseOrientation: const Optional.absent()); } /// Captures an image and returns the file where it was saved. @@ -314,8 +315,8 @@ class CameraController extends ValueNotifier { isRecordingVideo: true, isRecordingPaused: false, isStreamingImages: streamCallback != null, - recordingOrientation: - value.lockedCaptureOrientation ?? value.deviceOrientation); + recordingOrientation: Optional.of( + value.lockedCaptureOrientation ?? value.deviceOrientation)); } /// Stops the video recording and returns the file where it was saved. @@ -331,7 +332,7 @@ class CameraController extends ValueNotifier { value = value.copyWith( isRecordingVideo: false, isRecordingPaused: false, - recordingOrientation: null, + recordingOrientation: const Optional.absent(), ); return file; } @@ -400,13 +401,16 @@ class CameraController extends ValueNotifier { Future lockCaptureOrientation() async { await CameraPlatform.instance .lockCaptureOrientation(_cameraId, value.deviceOrientation); - value = value.copyWith(lockedCaptureOrientation: value.deviceOrientation); + value = value.copyWith( + lockedCaptureOrientation: + Optional.of(value.deviceOrientation)); } /// Unlocks the capture orientation. Future unlockCaptureOrientation() async { await CameraPlatform.instance.unlockCaptureOrientation(_cameraId); - value = value.copyWith(lockedCaptureOrientation: null); + value = value.copyWith( + lockedCaptureOrientation: const Optional.absent()); } /// Sets the focus mode for taking pictures. diff --git a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart index 78f2321df8c9..2fcd868934fb 100644 --- a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart +++ b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart @@ -109,10 +109,10 @@ class CameraValue { bool? exposurePointSupported, bool? focusPointSupported, DeviceOrientation? deviceOrientation, - DeviceOrientation? lockedCaptureOrientation, - DeviceOrientation? recordingOrientation, + Optional? lockedCaptureOrientation, + Optional? recordingOrientation, bool? isPreviewPaused, - DeviceOrientation? previewPauseOrientation, + Optional? previewPauseOrientation, }) { return CameraValue( isInitialized: isInitialized ?? this.isInitialized, @@ -262,15 +262,16 @@ class CameraController extends ValueNotifier { await CameraPlatform.instance.pausePreview(_cameraId); value = value.copyWith( isPreviewPaused: true, - previewPauseOrientation: - value.lockedCaptureOrientation ?? value.deviceOrientation); + previewPauseOrientation: Optional.of( + value.lockedCaptureOrientation ?? value.deviceOrientation)); } /// Resumes the current camera preview Future resumePreview() async { await CameraPlatform.instance.resumePreview(_cameraId); - value = - value.copyWith(isPreviewPaused: false, previewPauseOrientation: null); + value = value.copyWith( + isPreviewPaused: false, + previewPauseOrientation: const Optional.absent()); } /// Captures an image and returns the file where it was saved. @@ -313,8 +314,8 @@ class CameraController extends ValueNotifier { isRecordingVideo: true, isRecordingPaused: false, isStreamingImages: streamCallback != null, - recordingOrientation: - value.lockedCaptureOrientation ?? value.deviceOrientation); + recordingOrientation: Optional.of( + value.lockedCaptureOrientation ?? value.deviceOrientation)); } /// Stops the video recording and returns the file where it was saved. @@ -329,7 +330,7 @@ class CameraController extends ValueNotifier { await CameraPlatform.instance.stopVideoRecording(_cameraId); value = value.copyWith( isRecordingVideo: false, - recordingOrientation: null, + recordingOrientation: const Optional.absent(), ); return file; } @@ -398,13 +399,16 @@ class CameraController extends ValueNotifier { Future lockCaptureOrientation() async { await CameraPlatform.instance .lockCaptureOrientation(_cameraId, value.deviceOrientation); - value = value.copyWith(lockedCaptureOrientation: value.deviceOrientation); + value = value.copyWith( + lockedCaptureOrientation: + Optional.of(value.deviceOrientation)); } /// Unlocks the capture orientation. Future unlockCaptureOrientation() async { await CameraPlatform.instance.unlockCaptureOrientation(_cameraId); - value = value.copyWith(lockedCaptureOrientation: null); + value = value.copyWith( + lockedCaptureOrientation: const Optional.absent()); } /// Sets the focus mode for taking pictures. From d10b1cc53feb6e2083348bb2c2812c9ab7dcef50 Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 17 Jan 2023 10:04:36 -0800 Subject: [PATCH 08/11] Add back optional --- .../camera/lib/src/camera_controller.dart | 111 ++++++++++++++++- .../camera/test/camera_preview_test.dart | 1 - packages/camera/camera/test/camera_test.dart | 1 - .../example/lib/camera_controller.dart | 112 +++++++++++++++++- .../example/lib/camera_controller.dart | 111 ++++++++++++++++- 5 files changed, 330 insertions(+), 6 deletions(-) diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index ed1c951925d8..f0e08da40419 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -3,13 +3,13 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:collection'; import 'dart:math'; import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:quiver/core.dart'; import '../camera.dart'; @@ -840,3 +840,112 @@ class CameraController extends ValueNotifier { } } } + +/// A value that might be absent. +/// +/// Used to represent [DeviceOrientation]s that are optional but also able +/// to be cleared. +@immutable +class Optional extends IterableBase { + /// Constructs an empty Optional. + const Optional.absent() : _value = null; + + /// Constructs an Optional of the given [value]. + /// + /// Throws [ArgumentError] if [value] is null. + Optional.of(T value) : _value = value { + // TODO(cbracken): Delete and make this ctor const once mixed-mode + // execution is no longer around. + ArgumentError.checkNotNull(value); + } + + /// Constructs an Optional of the given [value]. + /// + /// If [value] is null, returns [absent()]. + const Optional.fromNullable(T? value) : _value = value; + + final T? _value; + + /// True when this optional contains a value. + bool get isPresent => _value != null; + + /// True when this optional contains no value. + bool get isNotPresent => _value == null; + + /// Gets the Optional value. + /// + /// Throws [StateError] if [value] is null. + T get value { + if (_value == null) { + throw StateError('value called on absent Optional.'); + } + return _value!; + } + + /// Executes a function if the Optional value is present. + void ifPresent(void Function(T value) ifPresent) { + if (isPresent) { + ifPresent(_value as T); + } + } + + /// Execution a function if the Optional value is absent. + void ifAbsent(void Function() ifAbsent) { + if (!isPresent) { + ifAbsent(); + } + } + + /// Gets the Optional value with a default. + /// + /// The default is returned if the Optional is [absent()]. + /// + /// Throws [ArgumentError] if [defaultValue] is null. + T or(T defaultValue) { + return _value ?? defaultValue; + } + + /// Gets the Optional value, or `null` if there is none. + T? get orNull => _value; + + /// Transforms the Optional value. + /// + /// If the Optional is [absent()], returns [absent()] without applying the transformer. + /// + /// The transformer must not return `null`. If it does, an [ArgumentError] is thrown. + Optional transform(S Function(T value) transformer) { + return _value == null + ? Optional.absent() + : Optional.of(transformer(_value as T)); + } + + /// Transforms the Optional value. + /// + /// If the Optional is [absent()], returns [absent()] without applying the transformer. + /// + /// Returns [absent()] if the transformer returns `null`. + Optional transformNullable(S? Function(T value) transformer) { + return _value == null + ? Optional.absent() + : Optional.fromNullable(transformer(_value as T)); + } + + @override + Iterator get iterator => + isPresent ? [_value as T].iterator : Iterable.empty().iterator; + + /// Delegates to the underlying [value] hashCode. + @override + int get hashCode => _value.hashCode; + + /// Delegates to the underlying [value] operator==. + @override + bool operator ==(Object o) => o is Optional && o._value == _value; + + @override + String toString() { + return _value == null + ? 'Optional { absent }' + : 'Optional { value: $_value }'; + } +} diff --git a/packages/camera/camera/test/camera_preview_test.dart b/packages/camera/camera/test/camera_preview_test.dart index bedb0ea8e01f..65ae1f8e8584 100644 --- a/packages/camera/camera/test/camera_preview_test.dart +++ b/packages/camera/camera/test/camera_preview_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:quiver/core.dart'; class FakeController extends ValueNotifier implements CameraController { diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index 3c12648f13b9..929e239ed766 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -13,7 +13,6 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import 'package:quiver/core.dart'; List get mockAvailableCameras => [ const CameraDescription( diff --git a/packages/camera/camera_android/example/lib/camera_controller.dart b/packages/camera/camera_android/example/lib/camera_controller.dart index ce91bc769f0a..8139dcdb0220 100644 --- a/packages/camera/camera_android/example/lib/camera_controller.dart +++ b/packages/camera/camera_android/example/lib/camera_controller.dart @@ -3,12 +3,12 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:collection'; import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:quiver/core.dart'; /// The state of a [CameraController]. class CameraValue { @@ -108,7 +108,6 @@ class CameraValue { FocusMode? focusMode, bool? exposurePointSupported, bool? focusPointSupported, - bool? isPreviewPaused, DeviceOrientation? deviceOrientation, Optional? lockedCaptureOrientation, Optional? recordingOrientation, @@ -444,3 +443,112 @@ class CameraController extends ValueNotifier { } } } + +/// A value that might be absent. +/// +/// Used to represent [DeviceOrientation]s that are optional but also able +/// to be cleared. +@immutable +class Optional extends IterableBase { + /// Constructs an empty Optional. + const Optional.absent() : _value = null; + + /// Constructs an Optional of the given [value]. + /// + /// Throws [ArgumentError] if [value] is null. + Optional.of(T value) : _value = value { + // TODO(cbracken): Delete and make this ctor const once mixed-mode + // execution is no longer around. + ArgumentError.checkNotNull(value); + } + + /// Constructs an Optional of the given [value]. + /// + /// If [value] is null, returns [absent()]. + const Optional.fromNullable(T? value) : _value = value; + + final T? _value; + + /// True when this optional contains a value. + bool get isPresent => _value != null; + + /// True when this optional contains no value. + bool get isNotPresent => _value == null; + + /// Gets the Optional value. + /// + /// Throws [StateError] if [value] is null. + T get value { + if (_value == null) { + throw StateError('value called on absent Optional.'); + } + return _value!; + } + + /// Executes a function if the Optional value is present. + void ifPresent(void Function(T value) ifPresent) { + if (isPresent) { + ifPresent(_value as T); + } + } + + /// Execution a function if the Optional value is absent. + void ifAbsent(void Function() ifAbsent) { + if (!isPresent) { + ifAbsent(); + } + } + + /// Gets the Optional value with a default. + /// + /// The default is returned if the Optional is [absent()]. + /// + /// Throws [ArgumentError] if [defaultValue] is null. + T or(T defaultValue) { + return _value ?? defaultValue; + } + + /// Gets the Optional value, or `null` if there is none. + T? get orNull => _value; + + /// Transforms the Optional value. + /// + /// If the Optional is [absent()], returns [absent()] without applying the transformer. + /// + /// The transformer must not return `null`. If it does, an [ArgumentError] is thrown. + Optional transform(S Function(T value) transformer) { + return _value == null + ? Optional.absent() + : Optional.of(transformer(_value as T)); + } + + /// Transforms the Optional value. + /// + /// If the Optional is [absent()], returns [absent()] without applying the transformer. + /// + /// Returns [absent()] if the transformer returns `null`. + Optional transformNullable(S? Function(T value) transformer) { + return _value == null + ? Optional.absent() + : Optional.fromNullable(transformer(_value as T)); + } + + @override + Iterator get iterator => + isPresent ? [_value as T].iterator : Iterable.empty().iterator; + + /// Delegates to the underlying [value] hashCode. + @override + int get hashCode => _value.hashCode; + + /// Delegates to the underlying [value] operator==. + @override + bool operator ==(Object o) => o is Optional && o._value == _value; + + @override + String toString() { + return _value == null + ? 'Optional { absent }' + : 'Optional { value: $_value }'; + } +} diff --git a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart index 2fcd868934fb..524186816aab 100644 --- a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart +++ b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart @@ -3,12 +3,12 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:collection'; import 'package:camera_platform_interface/camera_platform_interface.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:quiver/core.dart'; /// The state of a [CameraController]. class CameraValue { @@ -442,3 +442,112 @@ class CameraController extends ValueNotifier { } } } + +/// A value that might be absent. +/// +/// Used to represent [DeviceOrientation]s that are optional but also able +/// to be cleared. +@immutable +class Optional extends IterableBase { + /// Constructs an empty Optional. + const Optional.absent() : _value = null; + + /// Constructs an Optional of the given [value]. + /// + /// Throws [ArgumentError] if [value] is null. + Optional.of(T value) : _value = value { + // TODO(cbracken): Delete and make this ctor const once mixed-mode + // execution is no longer around. + ArgumentError.checkNotNull(value); + } + + /// Constructs an Optional of the given [value]. + /// + /// If [value] is null, returns [absent()]. + const Optional.fromNullable(T? value) : _value = value; + + final T? _value; + + /// True when this optional contains a value. + bool get isPresent => _value != null; + + /// True when this optional contains no value. + bool get isNotPresent => _value == null; + + /// Gets the Optional value. + /// + /// Throws [StateError] if [value] is null. + T get value { + if (_value == null) { + throw StateError('value called on absent Optional.'); + } + return _value!; + } + + /// Executes a function if the Optional value is present. + void ifPresent(void Function(T value) ifPresent) { + if (isPresent) { + ifPresent(_value as T); + } + } + + /// Execution a function if the Optional value is absent. + void ifAbsent(void Function() ifAbsent) { + if (!isPresent) { + ifAbsent(); + } + } + + /// Gets the Optional value with a default. + /// + /// The default is returned if the Optional is [absent()]. + /// + /// Throws [ArgumentError] if [defaultValue] is null. + T or(T defaultValue) { + return _value ?? defaultValue; + } + + /// Gets the Optional value, or `null` if there is none. + T? get orNull => _value; + + /// Transforms the Optional value. + /// + /// If the Optional is [absent()], returns [absent()] without applying the transformer. + /// + /// The transformer must not return `null`. If it does, an [ArgumentError] is thrown. + Optional transform(S Function(T value) transformer) { + return _value == null + ? Optional.absent() + : Optional.of(transformer(_value as T)); + } + + /// Transforms the Optional value. + /// + /// If the Optional is [absent()], returns [absent()] without applying the transformer. + /// + /// Returns [absent()] if the transformer returns `null`. + Optional transformNullable(S? Function(T value) transformer) { + return _value == null + ? Optional.absent() + : Optional.fromNullable(transformer(_value as T)); + } + + @override + Iterator get iterator => + isPresent ? [_value as T].iterator : Iterable.empty().iterator; + + /// Delegates to the underlying [value] hashCode. + @override + int get hashCode => _value.hashCode; + + /// Delegates to the underlying [value] operator==. + @override + bool operator ==(Object o) => o is Optional && o._value == _value; + + @override + String toString() { + return _value == null + ? 'Optional { absent }' + : 'Optional { value: $_value }'; + } +} From 6412a1bcb841ef2b5a52c546bd43931fe1160c6b Mon Sep 17 00:00:00 2001 From: camsim99 Date: Tue, 17 Jan 2023 10:06:42 -0800 Subject: [PATCH 09/11] Edit changelog --- packages/camera/camera_android/CHANGELOG.md | 2 +- packages/camera/camera_avfoundation/CHANGELOG.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/camera/camera_android/CHANGELOG.md b/packages/camera/camera_android/CHANGELOG.md index a481412f0248..72fedb2afdb3 100644 --- a/packages/camera/camera_android/CHANGELOG.md +++ b/packages/camera/camera_android/CHANGELOG.md @@ -1,6 +1,6 @@ ## 0.10.3 -* Adds back use of Optional type defined in the app-facing package. +* Adds back use of Optional type. ## 0.10.2+1 diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index bc239b34b8ba..e68de75bc01e 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,6 +1,6 @@ ## 0.9.11 -* Adds back use of Optional type defined in the app-facing package. +* Adds back use of Optional type. ## 0.9.10+1 From 2d7495935ed995fe222a10d128e2ead29b986eaf Mon Sep 17 00:00:00 2001 From: camsim99 Date: Wed, 18 Jan 2023 14:02:12 -0800 Subject: [PATCH 10/11] Fix semicolon --- packages/camera/camera/lib/src/camera_controller.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index 991aa06ce593..9480498b75a3 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -506,7 +506,7 @@ class CameraController extends ValueNotifier { isRecordingVideo: true, isRecordingPaused: false, recordingOrientation: Optional.of( - value.lockedCaptureOrientation ?? value.deviceOrientation)); + value.lockedCaptureOrientation ?? value.deviceOrientation)), isStreamingImages: onAvailable != null, } on PlatformException catch (e) { throw CameraException(e.code, e.message); From c56da37dd505c65a87e08508b030f8bb4583e62d Mon Sep 17 00:00:00 2001 From: camsim99 Date: Wed, 18 Jan 2023 14:07:39 -0800 Subject: [PATCH 11/11] Add ) --- packages/camera/camera/lib/src/camera_controller.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index 9480498b75a3..7a396c1589f9 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -506,8 +506,8 @@ class CameraController extends ValueNotifier { isRecordingVideo: true, isRecordingPaused: false, recordingOrientation: Optional.of( - value.lockedCaptureOrientation ?? value.deviceOrientation)), - isStreamingImages: onAvailable != null, + value.lockedCaptureOrientation ?? value.deviceOrientation), + isStreamingImages: onAvailable != null); } on PlatformException catch (e) { throw CameraException(e.code, e.message); }