Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,16 @@ - (instancetype)initWithCameraSensor:(PigeonSensorPosition)sensor
_physicalButtonController = [[PhysicalButtonController alloc] init];

[_motionController startMotionDetection];


// Keep the capture connection locked to portrait so the preview texture
// never rotates with the device — mimics the native iOS Camera app.
__weak typeof(self) weakSelf = self;
_motionController.onOrientationChanged = ^(UIDeviceOrientation newOrientation) {
if (weakSelf.captureConnection.isVideoOrientationSupported) {
[weakSelf.captureConnection setVideoOrientation:AVCaptureVideoOrientationPortrait];
}
};

if (enablePhysicalButton) {
[_physicalButtonController startListening];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ - (void)startMotionDetection {
}
if (self->_deviceOrientation != newOrientation) {
self->_deviceOrientation = newOrientation;


// Notify camera controller to update capture connection orientation
if (self->_onOrientationChanged) {
self->_onOrientationChanged(newOrientation);
}

NSString *orientationString;
switch (newOrientation) {
case UIDeviceOrientationLandscapeLeft:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
@property(nonatomic) FlutterEventSink orientationEventSink;
@property(readonly, nonatomic) UIDeviceOrientation deviceOrientation;
@property(readonly, nonatomic) CMMotionManager *motionManager;
@property(nonatomic, copy, nullable) void (^onOrientationChanged)(UIDeviceOrientation newOrientation);

- (instancetype)init;
- (void)startMotionDetection;
Expand Down
45 changes: 14 additions & 31 deletions lib/src/widgets/camera_awesome_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,7 @@ class CameraAwesomeBuilder extends StatefulWidget {
Alignment previewAlignment = Alignment.center,
PictureInPictureConfigBuilder? pictureInPictureConfigBuilder,
}) : this._(
sensorConfig: sensorConfig ??
SensorConfig.single(sensor: Sensor.position(SensorPosition.back)),
sensorConfig: sensorConfig ?? SensorConfig.single(sensor: Sensor.position(SensorPosition.back)),
enablePhysicalButton: false,
progressIndicator: progressIndicator,
builder: builder,
Expand Down Expand Up @@ -315,8 +314,7 @@ class CameraAwesomeBuilder extends StatefulWidget {
required OnImageForAnalysis onImageForAnalysis,
AnalysisConfig? imageAnalysisConfig,
}) : this._(
sensorConfig: sensorConfig ??
SensorConfig.single(sensor: Sensor.position(SensorPosition.back)),
sensorConfig: sensorConfig ?? SensorConfig.single(sensor: Sensor.position(SensorPosition.back)),
enablePhysicalButton: false,
progressIndicator: progressIndicator,
builder: builder,
Expand All @@ -342,8 +340,7 @@ class CameraAwesomeBuilder extends StatefulWidget {
}
}

class _CameraWidgetBuilder extends State<CameraAwesomeBuilder>
with WidgetsBindingObserver {
class _CameraWidgetBuilder extends State<CameraAwesomeBuilder> with WidgetsBindingObserver {
late CameraContext _cameraContext;
final _cameraPreviewKey = GlobalKey<AwesomeCameraPreviewState>();
StreamSubscription<MediaCapture?>? _captureStateListener;
Expand Down Expand Up @@ -394,15 +391,11 @@ class _CameraWidgetBuilder extends State<CameraAwesomeBuilder>
widget.sensorConfig,
enablePhysicalButton: widget.enablePhysicalButton,
filter: widget.defaultFilter ?? AwesomeFilter.None,
initialCaptureMode: widget.saveConfig?.initialCaptureMode ??
(widget.showPreview
? CaptureMode.preview
: CaptureMode.analysis_only),
initialCaptureMode: widget.saveConfig?.initialCaptureMode ?? (widget.showPreview ? CaptureMode.preview : CaptureMode.analysis_only),
saveConfig: widget.saveConfig,
onImageForAnalysis: widget.onImageForAnalysis,
analysisConfig: widget.imageAnalysisConfig,
exifPreferences: widget.saveConfig?.exifPreferences ??
ExifPreferences(saveGPSLocation: false),
exifPreferences: widget.saveConfig?.exifPreferences ?? ExifPreferences(saveGPSLocation: false),
availableFilters: widget.availableFilters,
);

Expand All @@ -423,9 +416,7 @@ class _CameraWidgetBuilder extends State<CameraAwesomeBuilder>
child: StreamBuilder<CameraState>(
stream: _cameraContext.state$,
builder: (context, snapshot) {
if (!snapshot.hasData ||
snapshot.data!.captureMode == null ||
snapshot.requireData is PreparingCameraState) {
if (!snapshot.hasData || snapshot.data!.captureMode == null || snapshot.requireData is PreparingCameraState) {
return widget.progressIndicator ??
const Center(
child: CircularProgressIndicator.adaptive(),
Expand All @@ -446,54 +437,46 @@ class _CameraWidgetBuilder extends State<CameraAwesomeBuilder>
state: snapshot.requireData,
padding: widget.previewPadding,
alignment: widget.previewAlignment,
onPreviewTap: widget.onPreviewTapBuilder
?.call(snapshot.requireData) ??
onPreviewTap: widget.onPreviewTapBuilder?.call(snapshot.requireData) ??
OnPreviewTap(
onTap: (
position,
flutterPreviewSize,
pixelPreviewSize,
) {
snapshot.requireData.when(
onPhotoMode: (photoState) =>
photoState.focusOnPoint(
onPhotoMode: (photoState) => photoState.focusOnPoint(
flutterPosition: position,
pixelPreviewSize: pixelPreviewSize,
flutterPreviewSize: flutterPreviewSize,
),
onVideoMode: (videoState) =>
videoState.focusOnPoint(
onVideoMode: (videoState) => videoState.focusOnPoint(
flutterPosition: position,
pixelPreviewSize: pixelPreviewSize,
flutterPreviewSize: flutterPreviewSize,
),
onVideoRecordingMode: (videoRecState) =>
videoRecState.focusOnPoint(
onVideoRecordingMode: (videoRecState) => videoRecState.focusOnPoint(
flutterPosition: position,
pixelPreviewSize: pixelPreviewSize,
flutterPreviewSize: flutterPreviewSize,
),
onPreviewMode: (previewState) =>
previewState.focusOnPoint(
onPreviewMode: (previewState) => previewState.focusOnPoint(
flutterPosition: position,
pixelPreviewSize: pixelPreviewSize,
flutterPreviewSize: flutterPreviewSize,
),
);
},
),
onPreviewScale: widget.onPreviewScaleBuilder
?.call(snapshot.requireData) ??
onPreviewScale: widget.onPreviewScaleBuilder?.call(snapshot.requireData) ??
OnPreviewScale(
onScale: (scale) {
snapshot.requireData.sensorConfig
.setZoom(scale);
snapshot.requireData.sensorConfig.setZoom(scale);
},
),
interfaceBuilder: widget.builder,
previewDecoratorBuilder: widget.previewDecoratorBuilder,
pictureInPictureConfigBuilder:
widget.pictureInPictureConfigBuilder,
pictureInPictureConfigBuilder: widget.pictureInPictureConfigBuilder,
),
),
],
Expand Down
14 changes: 11 additions & 3 deletions lib/src/widgets/preview/awesome_camera_preview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ class AwesomeCameraPreviewState extends State<AwesomeCameraPreview> {
);
}

// Don't rotate the camera preview texture when the device rotates —
// keep it stable like the native iOS Camera app.
const quarterTurns = 0;
final effectivePreviewSize = _previewSize!;

return Container(
color: Colors.black,
child: LayoutBuilder(
Expand All @@ -163,7 +168,7 @@ class AwesomeCameraPreviewState extends State<AwesomeCameraPreview> {
child: AnimatedPreviewFit(
alignment: widget.alignment,
previewFit: widget.previewFit,
previewSize: _previewSize!,
previewSize: effectivePreviewSize,
previewPadding: widget.padding,
constraints: constraints,
sensor: widget.state.sensorConfig.sensors.first,
Expand Down Expand Up @@ -192,13 +197,16 @@ class AwesomeCameraPreviewState extends State<AwesomeCameraPreview> {
//FIX performances
stream: widget.state.filter$,
builder: (context, snapshot) {
final texture = quarterTurns != 0
? RotatedBox(quarterTurns: quarterTurns, child: _textures.first)
: _textures.first;
return snapshot.hasData &&
snapshot.data != AwesomeFilter.None
? ColorFiltered(
colorFilter: snapshot.data!.preview,
child: _textures.first,
child: texture,
)
: _textures.first;
: texture;
},
),
),
Expand Down
1 change: 1 addition & 0 deletions lib/src/widgets/preview/awesome_preview_fit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ class PreviewFitWidget extends StatelessWidget {
return Align(
alignment: alignment,
child: SizedBox(
width: previewSize.width * scale,
height: previewSize.height * scale,
child: Padding(
padding: previewPadding ?? EdgeInsets.zero,
Expand Down