33// found in the LICENSE file.
44
55import 'dart:async' ;
6+ import 'dart:collection' ;
67import 'dart:math' ;
78
89import 'package:camera_platform_interface/camera_platform_interface.dart' ;
@@ -160,10 +161,10 @@ class CameraValue {
160161 bool ? exposurePointSupported,
161162 bool ? focusPointSupported,
162163 DeviceOrientation ? deviceOrientation,
163- DeviceOrientation ? lockedCaptureOrientation,
164- DeviceOrientation ? recordingOrientation,
164+ Optional < DeviceOrientation > ? lockedCaptureOrientation,
165+ Optional < DeviceOrientation > ? recordingOrientation,
165166 bool ? isPreviewPaused,
166- DeviceOrientation ? previewPauseOrientation,
167+ Optional < DeviceOrientation > ? previewPauseOrientation,
167168 }) {
168169 return CameraValue (
169170 isInitialized: isInitialized ?? this .isInitialized,
@@ -180,12 +181,16 @@ class CameraValue {
180181 exposurePointSupported ?? this .exposurePointSupported,
181182 focusPointSupported: focusPointSupported ?? this .focusPointSupported,
182183 deviceOrientation: deviceOrientation ?? this .deviceOrientation,
183- lockedCaptureOrientation:
184- lockedCaptureOrientation ?? this .lockedCaptureOrientation,
185- recordingOrientation: recordingOrientation ?? this .recordingOrientation,
184+ lockedCaptureOrientation: lockedCaptureOrientation == null
185+ ? this .lockedCaptureOrientation
186+ : lockedCaptureOrientation.orNull,
187+ recordingOrientation: recordingOrientation == null
188+ ? this .recordingOrientation
189+ : recordingOrientation.orNull,
186190 isPreviewPaused: isPreviewPaused ?? this .isPreviewPaused,
187- previewPauseOrientation:
188- previewPauseOrientation ?? this .previewPauseOrientation,
191+ previewPauseOrientation: previewPauseOrientation == null
192+ ? this .previewPauseOrientation
193+ : previewPauseOrientation.orNull,
189194 );
190195 }
191196
@@ -353,8 +358,8 @@ class CameraController extends ValueNotifier<CameraValue> {
353358 await CameraPlatform .instance.pausePreview (_cameraId);
354359 value = value.copyWith (
355360 isPreviewPaused: true ,
356- previewPauseOrientation:
357- value.lockedCaptureOrientation ?? value.deviceOrientation);
361+ previewPauseOrientation: Optional < DeviceOrientation >. of (
362+ value.lockedCaptureOrientation ?? value.deviceOrientation)) ;
358363 } on PlatformException catch (e) {
359364 throw CameraException (e.code, e.message);
360365 }
@@ -367,7 +372,9 @@ class CameraController extends ValueNotifier<CameraValue> {
367372 }
368373 try {
369374 await CameraPlatform .instance.resumePreview (_cameraId);
370- value = value.copyWith (isPreviewPaused: false );
375+ value = value.copyWith (
376+ isPreviewPaused: false ,
377+ previewPauseOrientation: const Optional <DeviceOrientation >.absent ());
371378 } on PlatformException catch (e) {
372379 throw CameraException (e.code, e.message);
373380 }
@@ -498,9 +505,9 @@ class CameraController extends ValueNotifier<CameraValue> {
498505 value = value.copyWith (
499506 isRecordingVideo: true ,
500507 isRecordingPaused: false ,
501- isStreamingImages : onAvailable != null ,
502- recordingOrientation :
503- value.lockedCaptureOrientation ?? value.deviceOrientation );
508+ recordingOrientation : Optional < DeviceOrientation >. of (
509+ value.lockedCaptureOrientation ?? value.deviceOrientation),
510+ isStreamingImages : onAvailable != null );
504511 } on PlatformException catch (e) {
505512 throw CameraException (e.code, e.message);
506513 }
@@ -525,7 +532,10 @@ class CameraController extends ValueNotifier<CameraValue> {
525532 try {
526533 final XFile file =
527534 await CameraPlatform .instance.stopVideoRecording (_cameraId);
528- value = value.copyWith (isRecordingVideo: false );
535+ value = value.copyWith (
536+ isRecordingVideo: false ,
537+ recordingOrientation: const Optional <DeviceOrientation >.absent (),
538+ );
529539 return file;
530540 } on PlatformException catch (e) {
531541 throw CameraException (e.code, e.message);
@@ -743,7 +753,8 @@ class CameraController extends ValueNotifier<CameraValue> {
743753 await CameraPlatform .instance.lockCaptureOrientation (
744754 _cameraId, orientation ?? value.deviceOrientation);
745755 value = value.copyWith (
746- lockedCaptureOrientation: orientation ?? value.deviceOrientation);
756+ lockedCaptureOrientation: Optional <DeviceOrientation >.of (
757+ orientation ?? value.deviceOrientation));
747758 } on PlatformException catch (e) {
748759 throw CameraException (e.code, e.message);
749760 }
@@ -763,7 +774,8 @@ class CameraController extends ValueNotifier<CameraValue> {
763774 Future <void > unlockCaptureOrientation () async {
764775 try {
765776 await CameraPlatform .instance.unlockCaptureOrientation (_cameraId);
766- value = value.copyWith ();
777+ value = value.copyWith (
778+ lockedCaptureOrientation: const Optional <DeviceOrientation >.absent ());
767779 } on PlatformException catch (e) {
768780 throw CameraException (e.code, e.message);
769781 }
@@ -834,3 +846,112 @@ class CameraController extends ValueNotifier<CameraValue> {
834846 }
835847 }
836848}
849+
850+ /// A value that might be absent.
851+ ///
852+ /// Used to represent [DeviceOrientation] s that are optional but also able
853+ /// to be cleared.
854+ @immutable
855+ class Optional <T > extends IterableBase <T > {
856+ /// Constructs an empty Optional.
857+ const Optional .absent () : _value = null ;
858+
859+ /// Constructs an Optional of the given [value] .
860+ ///
861+ /// Throws [ArgumentError] if [value] is null.
862+ Optional .of (T value) : _value = value {
863+ // TODO(cbracken): Delete and make this ctor const once mixed-mode
864+ // execution is no longer around.
865+ ArgumentError .checkNotNull (value);
866+ }
867+
868+ /// Constructs an Optional of the given [value] .
869+ ///
870+ /// If [value] is null, returns [absent()] .
871+ const Optional .fromNullable (T ? value) : _value = value;
872+
873+ final T ? _value;
874+
875+ /// True when this optional contains a value.
876+ bool get isPresent => _value != null ;
877+
878+ /// True when this optional contains no value.
879+ bool get isNotPresent => _value == null ;
880+
881+ /// Gets the Optional value.
882+ ///
883+ /// Throws [StateError] if [value] is null.
884+ T get value {
885+ if (_value == null ) {
886+ throw StateError ('value called on absent Optional.' );
887+ }
888+ return _value! ;
889+ }
890+
891+ /// Executes a function if the Optional value is present.
892+ void ifPresent (void Function (T value) ifPresent) {
893+ if (isPresent) {
894+ ifPresent (_value as T );
895+ }
896+ }
897+
898+ /// Execution a function if the Optional value is absent.
899+ void ifAbsent (void Function () ifAbsent) {
900+ if (! isPresent) {
901+ ifAbsent ();
902+ }
903+ }
904+
905+ /// Gets the Optional value with a default.
906+ ///
907+ /// The default is returned if the Optional is [absent()] .
908+ ///
909+ /// Throws [ArgumentError] if [defaultValue] is null.
910+ T or (T defaultValue) {
911+ return _value ?? defaultValue;
912+ }
913+
914+ /// Gets the Optional value, or `null` if there is none.
915+ T ? get orNull => _value;
916+
917+ /// Transforms the Optional value.
918+ ///
919+ /// If the Optional is [absent()] , returns [absent()] without applying the transformer.
920+ ///
921+ /// The transformer must not return `null` . If it does, an [ArgumentError] is thrown.
922+ Optional <S > transform <S >(S Function (T value) transformer) {
923+ return _value == null
924+ ? Optional <S >.absent ()
925+ : Optional <S >.of (transformer (_value as T ));
926+ }
927+
928+ /// Transforms the Optional value.
929+ ///
930+ /// If the Optional is [absent()] , returns [absent()] without applying the transformer.
931+ ///
932+ /// Returns [absent()] if the transformer returns `null` .
933+ Optional <S > transformNullable <S >(S ? Function (T value) transformer) {
934+ return _value == null
935+ ? Optional <S >.absent ()
936+ : Optional <S >.fromNullable (transformer (_value as T ));
937+ }
938+
939+ @override
940+ Iterator <T > get iterator =>
941+ isPresent ? < T > [_value as T ].iterator : Iterable <T >.empty ().iterator;
942+
943+ /// Delegates to the underlying [value] hashCode.
944+ @override
945+ int get hashCode => _value.hashCode;
946+
947+ /// Delegates to the underlying [value] operator==.
948+ @override
949+ bool operator == (Object o) => o is Optional <T > && o._value == _value;
950+
951+ @override
952+ String toString () {
953+ return _value == null
954+ ? 'Optional { absent }'
955+ : 'Optional { value: $_value }' ;
956+ }
957+ }
0 commit comments