Match tablet camera to preview ratio

Signed-off-by: kenny lopez <klopez4212@gmail.com>
This commit is contained in:
kenny lopez
2026-08-02 10:21:58 +01:00
parent 94b052faef
commit e0d7e628ba
2 changed files with 47 additions and 3 deletions
@@ -9,6 +9,8 @@ const _attachmentMenuItemSpacing = Grid.xxs;
const _attachmentMenuIconSize = 24.0;
const _attachmentMenuIconSlotWidth = 28.0;
const _attachmentExpandedHeight = 372.0;
const _tabletAttachmentCameraMaxHeight = 640.0;
const _tabletShortestSideBreakpoint = 600.0;
@immutable
class _AttachmentMenuLayout {
@@ -97,6 +99,7 @@ class _AttachmentSurfacePanel extends HookWidget {
final renderedExpandedSurface = useState<_AttachmentSurface?>(
isExpanded ? surface : null,
);
final cameraPreviewAspectRatio = useState<double?>(null);
final latestSurface = useRef(surface);
latestSurface.value = surface;
@@ -123,6 +126,13 @@ class _AttachmentSurfacePanel extends HookWidget {
return null;
}, [isExpanded, morphController, surface]);
useEffect(() {
if (surface != _AttachmentSurface.camera) {
cameraPreviewAspectRatio.value = null;
}
return null;
}, [surface]);
final visibleExpandedSurface =
renderedExpandedSurface.value ?? (isExpanded ? surface : null);
final cameraInitializationReady =
@@ -141,6 +151,11 @@ class _AttachmentSurfacePanel extends HookWidget {
initializeCamera: cameraInitializationReady,
onClose: onBack,
onCapture: onCapture,
onPreviewAspectRatio: (aspectRatio) {
if (cameraPreviewAspectRatio.value != aspectRatio) {
cameraPreviewAspectRatio.value = aspectRatio;
}
},
),
),
),
@@ -170,7 +185,18 @@ class _AttachmentSurfacePanel extends HookWidget {
return LayoutBuilder(
builder: (context, constraints) {
final expandedWidth = constraints.maxWidth;
const expandedHeight = _attachmentExpandedHeight;
final isTablet =
MediaQuery.sizeOf(context).shortestSide >=
_tabletShortestSideBreakpoint;
final expandedHeight =
visibleExpandedSurface == _AttachmentSurface.camera &&
isTablet &&
cameraPreviewAspectRatio.value != null
? math.min(
expandedWidth / cameraPreviewAspectRatio.value!,
_tabletAttachmentCameraMaxHeight,
)
: _attachmentExpandedHeight;
final width =
_attachmentMenuWidth +
((expandedWidth - _attachmentMenuWidth) * sizeProgress);
@@ -4,11 +4,13 @@ class _InlineCameraPreview extends HookConsumerWidget {
final bool initializeCamera;
final Future<void> Function(XFile image) onCapture;
final VoidCallback onClose;
final ValueChanged<double> onPreviewAspectRatio;
const _InlineCameraPreview({
required this.initializeCamera,
required this.onCapture,
required this.onClose,
required this.onPreviewAspectRatio,
});
@override
@@ -124,6 +126,18 @@ class _InlineCameraPreview extends HookConsumerWidget {
}
final activeController = controller.value;
final previewSize = activeController?.value.previewSize;
final previewAspectRatio = previewSize == null
? null
: MediaQuery.orientationOf(context) == Orientation.landscape
? activeController!.value.aspectRatio
: 1 / activeController!.value.aspectRatio;
useEffect(() {
if (previewAspectRatio != null) {
onPreviewAspectRatio(previewAspectRatio);
}
return null;
}, [onPreviewAspectRatio, previewAspectRatio]);
final usesAndroidCameraLayout =
defaultTargetPlatform == TargetPlatform.android;
return ColoredBox(
@@ -176,13 +190,17 @@ class _CameraFeed extends StatelessWidget {
Widget build(BuildContext context) {
final previewSize = controller.value.previewSize;
if (previewSize == null) return const ColoredBox(color: Colors.black);
final previewAspectRatio =
MediaQuery.orientationOf(context) == Orientation.landscape
? controller.value.aspectRatio
: 1 / controller.value.aspectRatio;
return ClipRect(
child: FittedBox(
fit: BoxFit.cover,
child: SizedBox(
width: previewSize.height,
height: previewSize.width,
width: previewAspectRatio,
height: 1,
child: camera.CameraPreview(controller),
),
),