Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

[camera] Add back Optional type for nullable CameraController orientations #6911

Merged
merged 15 commits into from
Jan 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/camera/camera/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.10.3

* Adds back use of Optional type.

## 0.10.2+1

* Updates code for stricter lint checks.
Expand Down
155 changes: 138 additions & 17 deletions packages/camera/camera/lib/src/camera_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

import 'dart:async';
import 'dart:collection';
import 'dart:math';

import 'package:camera_platform_interface/camera_platform_interface.dart';
Expand Down Expand Up @@ -160,10 +161,10 @@ class CameraValue {
bool? exposurePointSupported,
bool? focusPointSupported,
DeviceOrientation? deviceOrientation,
DeviceOrientation? lockedCaptureOrientation,
DeviceOrientation? recordingOrientation,
Optional<DeviceOrientation>? lockedCaptureOrientation,
Optional<DeviceOrientation>? recordingOrientation,
bool? isPreviewPaused,
DeviceOrientation? previewPauseOrientation,
Optional<DeviceOrientation>? previewPauseOrientation,
}) {
return CameraValue(
isInitialized: isInitialized ?? this.isInitialized,
Expand All @@ -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,
);
}

Expand Down Expand Up @@ -353,8 +358,8 @@ class CameraController extends ValueNotifier<CameraValue> {
await CameraPlatform.instance.pausePreview(_cameraId);
value = value.copyWith(
isPreviewPaused: true,
previewPauseOrientation:
value.lockedCaptureOrientation ?? value.deviceOrientation);
previewPauseOrientation: Optional<DeviceOrientation>.of(
value.lockedCaptureOrientation ?? value.deviceOrientation));
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
Expand All @@ -367,7 +372,9 @@ class CameraController extends ValueNotifier<CameraValue> {
}
try {
await CameraPlatform.instance.resumePreview(_cameraId);
value = value.copyWith(isPreviewPaused: false);
value = value.copyWith(
isPreviewPaused: false,
previewPauseOrientation: const Optional<DeviceOrientation>.absent());
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
Expand Down Expand Up @@ -498,9 +505,9 @@ class CameraController extends ValueNotifier<CameraValue> {
value = value.copyWith(
isRecordingVideo: true,
isRecordingPaused: false,
isStreamingImages: onAvailable != null,
recordingOrientation:
value.lockedCaptureOrientation ?? value.deviceOrientation);
recordingOrientation: Optional<DeviceOrientation>.of(
value.lockedCaptureOrientation ?? value.deviceOrientation),
isStreamingImages: onAvailable != null);
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
Expand All @@ -525,7 +532,10 @@ class CameraController extends ValueNotifier<CameraValue> {
try {
final XFile file =
await CameraPlatform.instance.stopVideoRecording(_cameraId);
value = value.copyWith(isRecordingVideo: false);
value = value.copyWith(
isRecordingVideo: false,
recordingOrientation: const Optional<DeviceOrientation>.absent(),
);
return file;
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
Expand Down Expand Up @@ -743,7 +753,8 @@ class CameraController extends ValueNotifier<CameraValue> {
await CameraPlatform.instance.lockCaptureOrientation(
_cameraId, orientation ?? value.deviceOrientation);
value = value.copyWith(
lockedCaptureOrientation: orientation ?? value.deviceOrientation);
lockedCaptureOrientation: Optional<DeviceOrientation>.of(
orientation ?? value.deviceOrientation));
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
Expand All @@ -763,7 +774,8 @@ class CameraController extends ValueNotifier<CameraValue> {
Future<void> unlockCaptureOrientation() async {
try {
await CameraPlatform.instance.unlockCaptureOrientation(_cameraId);
value = value.copyWith();
value = value.copyWith(
lockedCaptureOrientation: const Optional<DeviceOrientation>.absent());
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
Expand Down Expand Up @@ -834,3 +846,112 @@ class CameraController extends ValueNotifier<CameraValue> {
}
}
}

/// A value that might be absent.
///
/// Used to represent [DeviceOrientation]s that are optional but also able
/// to be cleared.
@immutable
class Optional<T> extends IterableBase<T> {
/// 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<S> transform<S>(S Function(T value) transformer) {
return _value == null
? Optional<S>.absent()
: Optional<S>.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<S> transformNullable<S>(S? Function(T value) transformer) {
return _value == null
? Optional<S>.absent()
: Optional<S>.fromNullable(transformer(_value as T));
}

@override
Iterator<T> get iterator =>
isPresent ? <T>[_value as T].iterator : Iterable<T>.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<T> && o._value == _value;

@override
String toString() {
return _value == null
? 'Optional { absent }'
: 'Optional { value: $_value }';
}
}
2 changes: 1 addition & 1 deletion packages/camera/camera/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.2+1
version: 0.10.3

environment:
sdk: ">=2.14.0 <3.0.0"
Expand Down
17 changes: 12 additions & 5 deletions packages/camera/camera/test/camera_preview_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,11 @@ void main() {
isInitialized: true,
isRecordingVideo: true,
deviceOrientation: DeviceOrientation.portraitUp,
lockedCaptureOrientation: DeviceOrientation.landscapeRight,
recordingOrientation: DeviceOrientation.landscapeLeft,
lockedCaptureOrientation:
const Optional<DeviceOrientation>.fromNullable(
DeviceOrientation.landscapeRight),
recordingOrientation: const Optional<DeviceOrientation>.fromNullable(
DeviceOrientation.landscapeLeft),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm a bit confused about this part - is Optional the old "nullable" before null safety in dart?

previewSize: const Size(480, 640),
);

Expand Down Expand Up @@ -164,8 +167,11 @@ void main() {
controller.value = controller.value.copyWith(
isInitialized: true,
deviceOrientation: DeviceOrientation.portraitUp,
lockedCaptureOrientation: DeviceOrientation.landscapeRight,
recordingOrientation: DeviceOrientation.landscapeLeft,
lockedCaptureOrientation:
const Optional<DeviceOrientation>.fromNullable(
DeviceOrientation.landscapeRight),
recordingOrientation: const Optional<DeviceOrientation>.fromNullable(
DeviceOrientation.landscapeLeft),
previewSize: const Size(480, 640),
);

Expand Down Expand Up @@ -195,7 +201,8 @@ void main() {
controller.value = controller.value.copyWith(
isInitialized: true,
deviceOrientation: DeviceOrientation.portraitUp,
recordingOrientation: DeviceOrientation.landscapeLeft,
recordingOrientation: const Optional<DeviceOrientation>.fromNullable(
DeviceOrientation.landscapeLeft),
previewSize: const Size(480, 640),
);

Expand Down
3 changes: 2 additions & 1 deletion packages/camera/camera/test/camera_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1166,7 +1166,8 @@ void main() {
cameraController.value = cameraController.value.copyWith(
isPreviewPaused: false,
deviceOrientation: DeviceOrientation.portraitUp,
lockedCaptureOrientation: DeviceOrientation.landscapeRight);
lockedCaptureOrientation:
Optional<DeviceOrientation>.of(DeviceOrientation.landscapeRight));

await cameraController.pausePreview();

Expand Down
3 changes: 2 additions & 1 deletion packages/camera/camera_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## NEXT
## 0.10.3

* Adds back use of Optional type.
* Updates minimum Flutter version to 3.0.

## 0.10.2+3
Expand Down
Loading