From 7e4787f0da6ba0bbc92d69bff2317d00a0ca53a8 Mon Sep 17 00:00:00 2001 From: otsmr Date: Sat, 22 Mar 2025 15:42:05 +0100 Subject: [PATCH] allow to zoom more than 2x --- lib/src/components/zoom_selector.dart | 74 +++++++++++------- .../camera_to_share/camera_preview_view.dart | 78 +++++++++---------- lib/src/views/settings/profile_view.dart | 38 ++++----- 3 files changed, 98 insertions(+), 92 deletions(-) diff --git a/lib/src/components/zoom_selector.dart b/lib/src/components/zoom_selector.dart index b8a20b1..efc5ff1 100644 --- a/lib/src/components/zoom_selector.dart +++ b/lib/src/components/zoom_selector.dart @@ -30,13 +30,15 @@ class _CameraZoomButtonsState extends State { @override Widget build(BuildContext context) { var zoomButtonStyle = TextButton.styleFrom( - padding: EdgeInsets.zero, - foregroundColor: Colors.white, - minimumSize: Size(40, 40), - alignment: Alignment.center, - tapTargetSize: MaterialTapTargetSize.shrinkWrap); + padding: EdgeInsets.zero, + foregroundColor: Colors.white, + minimumSize: Size(40, 40), + alignment: Alignment.center, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ); final zoomTextStyle = TextStyle(fontSize: 13); + final isMiddleFocused = widget.scaleFactor >= 1 && widget.scaleFactor < 2; return Center( child: ClipRRect( borderRadius: BorderRadius.circular(40.0), @@ -46,43 +48,54 @@ class _CameraZoomButtonsState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ TextButton( - style: zoomButtonStyle, + style: zoomButtonStyle.copyWith( + foregroundColor: WidgetStateProperty.all( + (widget.scaleFactor < 1) ? Colors.yellow : Colors.white, + ), + ), onPressed: () async { var level = await widget.controller.getMinZoomLevel(); widget.updateScaleFactor(level); }, child: FutureBuilder( - future: widget.controller.getMinZoomLevel(), - builder: (context, snap) { - if (snap.hasData) { - var minLevel = - beautifulZoomScale(snap.data!.toDouble()); - var currentLevel = - beautifulZoomScale(widget.scaleFactor); - return Text( - widget.scaleFactor < 1 - ? "${currentLevel}x" - : "${minLevel}x", - style: zoomTextStyle, - ); - } else { - return Text(""); - } - }), + future: widget.controller.getMinZoomLevel(), + builder: (context, snap) { + if (snap.hasData) { + var minLevel = beautifulZoomScale(snap.data!.toDouble()); + var currentLevel = beautifulZoomScale(widget.scaleFactor); + return Text( + widget.scaleFactor < 1 + ? "${currentLevel}x" + : "${minLevel}x", + style: zoomTextStyle, + ); + } else { + return Text(""); + } + }, + ), ), TextButton( - style: zoomButtonStyle, + style: zoomButtonStyle.copyWith( + foregroundColor: WidgetStateProperty.all( + isMiddleFocused ? Colors.yellow : Colors.white, + ), + ), onPressed: () { widget.updateScaleFactor(1.0); }, child: Text( - (widget.scaleFactor >= 1 && widget.scaleFactor < 2) + (isMiddleFocused) ? "${beautifulZoomScale(widget.scaleFactor)}x" : "1.0x", style: zoomTextStyle, )), TextButton( - style: zoomButtonStyle, + style: zoomButtonStyle.copyWith( + foregroundColor: WidgetStateProperty.all( + (widget.scaleFactor >= 2) ? Colors.yellow : Colors.white, + ), + ), onPressed: () async { var level = min(await widget.controller.getMaxZoomLevel(), 2) .toDouble(); @@ -92,8 +105,13 @@ class _CameraZoomButtonsState extends State { future: widget.controller.getMaxZoomLevel(), builder: (context, snap) { if (snap.hasData) { - var maxLevel = min((snap.data?.toInt())!, 2); - return Text("${maxLevel}x", style: zoomTextStyle); + var maxLevel = max( + min((snap.data?.toInt())!, 2), + widget.scaleFactor, + ); + return Text( + "${beautifulZoomScale(maxLevel.toDouble())}x", + style: zoomTextStyle); } else { return Text(""); } diff --git a/lib/src/views/camera_to_share/camera_preview_view.dart b/lib/src/views/camera_to_share/camera_preview_view.dart index 92e77f3..dbd0a83 100644 --- a/lib/src/views/camera_to_share/camera_preview_view.dart +++ b/lib/src/views/camera_to_share/camera_preview_view.dart @@ -54,6 +54,8 @@ class _CameraPreviewViewState extends State { bool showSelfieFlash = false; int cameraId = 0; bool isZoomAble = false; + double basePanY = 0; + double baseScaleFactor = 0; final GlobalKey navigatorKey = GlobalKey(); late CameraController controller; @@ -105,6 +107,7 @@ class _CameraPreviewViewState extends State { } Future updateScaleFactor(double newScale) async { + if (scaleFactor == newScale) return; var minFactor = await controller.getMinZoomLevel(); var maxFactor = await controller.getMaxZoomLevel(); if (newScale < minFactor) { @@ -128,6 +131,9 @@ class _CameraPreviewViewState extends State { super.dispose(); } + bool get isFront => + controller.description.lensDirection == CameraLensDirection.front; + @override Widget build(BuildContext context) { if (cameraId >= gCameras.length) { @@ -145,49 +151,45 @@ class _CameraPreviewViewState extends State { (controller.value.isInitialized) ? Positioned.fill( child: Screenshot( - controller: screenshotController, - child: AspectRatio( - aspectRatio: 9 / 16, - child: ClipRect( - child: FittedBox( - fit: BoxFit.cover, - child: SizedBox( - width: controller.value.previewSize!.height, - height: controller.value.previewSize!.width, - child: CameraPreview(controller), - ), + controller: screenshotController, + child: AspectRatio( + aspectRatio: 9 / 16, + child: ClipRect( + child: FittedBox( + fit: BoxFit.cover, + child: SizedBox( + width: controller.value.previewSize!.height, + height: controller.value.previewSize!.width, + child: CameraPreview(controller), ), ), - )), + ), + ), + ), ) : Container(), Positioned.fill( child: GestureDetector( onPanStart: (details) async { - // if (cameraState.sensorConfig.sensors.first.position == - // SensorPosition.front) { - // return; - // } - // setState(() { - // _basePanY = details.localPosition.dy; - // }); + if (isFront) { + return; + } + setState(() { + basePanY = details.localPosition.dy; + baseScaleFactor = scaleFactor; + }); }, onPanUpdate: (details) async { - // if (cameraState.sensorConfig.sensors.first.position == - // SensorPosition.front) { - // return; - // } - // var diff = _basePanY - details.localPosition.dy; - // if (diff > 200) diff = 200; - // if (diff < 0) diff = 0; - // var tmp = (diff / 200 * 50).toInt() / 50; - // if (tmp != _lastZoom) { - // cameraState.sensorConfig.setZoom(tmp); - // setState(() { - // (tmp); - // _lastZoom = tmp; - // }); - // } + if (isFront) { + return; + } + var diff = basePanY - details.localPosition.dy; + if (diff > 200) diff = 200; + if (diff < -200) diff = -200; + var tmp = (diff / 200 * (7 * 2)).toInt() / 2; + tmp = baseScaleFactor + tmp; + if (tmp < 1) tmp = 1; + updateScaleFactor(tmp); }, onDoubleTap: () async { selectCamera((cameraId + 1) % 2); @@ -246,10 +248,9 @@ class _CameraPreviewViewState extends State { children: [ if (controller.value.isInitialized && isZoomAble && - controller.description.lensDirection != - CameraLensDirection.front) + !isFront) SizedBox( - width: 150, + width: 120, child: CameraZoomButtons( key: widget.key, scaleFactor: scaleFactor, @@ -261,8 +262,7 @@ class _CameraPreviewViewState extends State { GestureDetector( onTap: () async { if (isFlashOn) { - if (controller.description.lensDirection == - CameraLensDirection.front) { + if (isFront) { setState(() { showSelfieFlash = true; }); diff --git a/lib/src/views/settings/profile_view.dart b/lib/src/views/settings/profile_view.dart index 25eab30..c735596 100644 --- a/lib/src/views/settings/profile_view.dart +++ b/lib/src/views/settings/profile_view.dart @@ -53,37 +53,26 @@ class _ProfileViewState extends State { body: ListView( physics: BouncingScrollPhysics(), children: [ - SizedBox( - height: 25, - ), + SizedBox(height: 25), AvatarMakerAvatar( backgroundColor: Colors.transparent, radius: 80, ), - SizedBox( - height: 10, - ), - Row( - children: [ - Spacer(flex: 2), - Expanded( - flex: 3, - child: SizedBox( - height: 35, - child: ElevatedButton.icon( - icon: Icon(Icons.edit), - label: Text(context.lang.settingsProfileCustomizeAvatar), - onPressed: () => Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ModifyAvatar(), - ), - ), + SizedBox(height: 10), + Center( + child: SizedBox( + height: 35, + child: ElevatedButton.icon( + icon: Icon(Icons.edit), + label: Text(context.lang.settingsProfileCustomizeAvatar), + onPressed: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ModifyAvatar(), ), ), ), - Spacer(flex: 2), - ], + ), ), SizedBox(height: 20), const Divider(), @@ -94,7 +83,6 @@ class _ProfileViewState extends State { onTap: () async { final displayName = await showDisplayNameChangeDialog(context, user!.displayName); - if (context.mounted && displayName != null && displayName != "") { updateUserDisplayname(displayName); }