Fix: Issue with focus changing when taking a picture
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run

This commit is contained in:
otsmr 2026-05-20 01:06:46 +02:00
parent 2d6a2e436f
commit f42a49cadf
6 changed files with 110 additions and 104 deletions

View file

@ -7,6 +7,7 @@
- Improved: The blue verification checkmark now displays the total number of verifications. - Improved: The blue verification checkmark now displays the total number of verifications.
- Fix: Issue with receiving messages when user closed app while decrypting - Fix: Issue with receiving messages when user closed app while decrypting
- Fix: Background message fetching reliability. - Fix: Background message fetching reliability.
- Fix: Issue with focus changing when taking a picture
## 0.2.16 ## 0.2.16

View file

@ -85,22 +85,31 @@ class MainCameraController {
FaceFilterType _currentFilterType = FaceFilterType.none; FaceFilterType _currentFilterType = FaceFilterType.none;
FaceFilterType get currentFilterType => _currentFilterType; FaceFilterType get currentFilterType => _currentFilterType;
Future<void>? _initializeFuture;
Future<void>? _pendingDisposal; Future<void>? _pendingDisposal;
Future<void> closeCamera() async { Future<void> closeCamera() async {
contactsVerified = {}; contactsVerified = {};
scannedNewProfiles = {}; scannedNewProfiles = {};
scannedUrl = null; scannedUrl = null;
try {
await cameraController?.stopImageStream();
// ignore: empty_catches
} catch (e) {}
final cameraControllerTemp = cameraController; final cameraControllerTemp = cameraController;
cameraController = null; cameraController = null;
final initFutureTemp = _initializeFuture;
_initializeFuture = null;
// prevents: CameraException(Disposed CameraController, buildPreview() was called on a disposed CameraController.) // prevents: CameraException(Disposed CameraController, buildPreview() was called on a disposed CameraController.)
_pendingDisposal = Future.delayed( _pendingDisposal = Future.delayed(
const Duration(milliseconds: 100), const Duration(milliseconds: 100),
() async { () async {
try {
if (initFutureTemp != null) {
await initFutureTemp;
}
// ignore: empty_catches
} catch (e) {}
try {
await cameraControllerTemp?.stopImageStream();
// ignore: empty_catches
} catch (e) {}
await cameraControllerTemp?.dispose(); await cameraControllerTemp?.dispose();
}, },
); );
@ -126,8 +135,7 @@ class MainCameraController {
if (init) { if (init) {
for (; cameraId < AppEnvironment.cameras.length; cameraId++) { for (; cameraId < AppEnvironment.cameras.length; cameraId++) {
if (AppEnvironment.cameras[cameraId].lensDirection == if (AppEnvironment.cameras[cameraId].lensDirection == CameraLensDirection.back) {
CameraLensDirection.back) {
break; break;
} }
} }
@ -140,12 +148,11 @@ class MainCameraController {
AppEnvironment.cameras[cameraId], AppEnvironment.cameras[cameraId],
ResolutionPreset.high, ResolutionPreset.high,
enableAudio: await Permission.microphone.isGranted, enableAudio: await Permission.microphone.isGranted,
imageFormatGroup: Platform.isAndroid imageFormatGroup: Platform.isAndroid ? ImageFormatGroup.nv21 : ImageFormatGroup.bgra8888,
? ImageFormatGroup.nv21
: ImageFormatGroup.bgra8888,
); );
try { try {
await cameraController?.initialize(); _initializeFuture = cameraController?.initialize();
await _initializeFuture;
await cameraController?.startImageStream(_processCameraImage); await cameraController?.startImageStream(_processCameraImage);
await cameraController?.setZoomLevel(selectedCameraDetails.scaleFactor); await cameraController?.setZoomLevel(selectedCameraDetails.scaleFactor);
if (userService.currentUser.videoStabilizationEnabled && !kDebugMode) { if (userService.currentUser.videoStabilizationEnabled && !kDebugMode) {
@ -185,14 +192,10 @@ class MainCameraController {
await cameraController?.setFlashMode( await cameraController?.setFlashMode(
selectedCameraDetails.isFlashOn ? FlashMode.always : FlashMode.off, selectedCameraDetails.isFlashOn ? FlashMode.always : FlashMode.off,
); );
selectedCameraDetails.maxAvailableZoom = selectedCameraDetails.maxAvailableZoom = await cameraController?.getMaxZoomLevel() ?? 1;
await cameraController?.getMaxZoomLevel() ?? 1; selectedCameraDetails.minAvailableZoom = await cameraController?.getMinZoomLevel() ?? 1;
selectedCameraDetails.minAvailableZoom =
await cameraController?.getMinZoomLevel() ?? 1;
selectedCameraDetails selectedCameraDetails
..isZoomAble = ..isZoomAble = selectedCameraDetails.maxAvailableZoom != selectedCameraDetails.minAvailableZoom
selectedCameraDetails.maxAvailableZoom !=
selectedCameraDetails.minAvailableZoom
..cameraLoaded = true ..cameraLoaded = true
..cameraId = cameraId; ..cameraId = cameraId;
@ -214,8 +217,7 @@ class MainCameraController {
} }
Future<void> onTapDown(TapDownDetails details) async { Future<void> onTapDown(TapDownDetails details) async {
final box = final box = cameraPreviewKey.currentContext?.findRenderObject() as RenderBox?;
cameraPreviewKey.currentContext?.findRenderObject() as RenderBox?;
if (box == null) return; if (box == null) return;
final localPosition = box.globalToLocal(details.globalPosition); final localPosition = box.globalToLocal(details.globalPosition);
@ -231,8 +233,7 @@ class MainCameraController {
await cameraController?.setFocusPoint(Offset(dx, dy)); await cameraController?.setFocusPoint(Offset(dx, dy));
await cameraController?.setFocusMode(FocusMode.auto); await cameraController?.setFocusMode(FocusMode.auto);
} catch (e) { } catch (e) {
if (e is CameraException && if (e is CameraException && (e.code == 'setFocusPointFailed' || e.code == 'setFocusModeFailed')) {
(e.code == 'setFocusPointFailed' || e.code == 'setFocusModeFailed')) {
Log.info('Focus point or mode not supported on this device'); Log.info('Focus point or mode not supported on this device');
} else { } else {
Log.warn(e); Log.warn(e);
@ -273,8 +274,7 @@ class MainCameraController {
if (inputImage == null) return; if (inputImage == null) return;
_processBarcode(inputImage); _processBarcode(inputImage);
// check if front camera is selected // check if front camera is selected
if (cameraController?.description.lensDirection == if (cameraController?.description.lensDirection == CameraLensDirection.front) {
CameraLensDirection.front) {
if (_currentFilterType != FaceFilterType.none) { if (_currentFilterType != FaceFilterType.none) {
_processFaces(inputImage); _processFaces(inputImage);
} }
@ -293,16 +293,14 @@ class MainCameraController {
if (Platform.isIOS) { if (Platform.isIOS) {
rotation = InputImageRotationValue.fromRawValue(sensorOrientation); rotation = InputImageRotationValue.fromRawValue(sensorOrientation);
} else if (Platform.isAndroid) { } else if (Platform.isAndroid) {
var rotationCompensation = var rotationCompensation = _orientations[cameraController!.value.deviceOrientation];
_orientations[cameraController!.value.deviceOrientation];
if (rotationCompensation == null) return null; if (rotationCompensation == null) return null;
if (camera.lensDirection == CameraLensDirection.front) { if (camera.lensDirection == CameraLensDirection.front) {
// front-facing // front-facing
rotationCompensation = (sensorOrientation + rotationCompensation) % 360; rotationCompensation = (sensorOrientation + rotationCompensation) % 360;
} else { } else {
// back-facing // back-facing
rotationCompensation = rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360;
(sensorOrientation - rotationCompensation + 360) % 360;
} }
rotation = InputImageRotationValue.fromRawValue(rotationCompensation); rotation = InputImageRotationValue.fromRawValue(rotationCompensation);
} }
@ -344,9 +342,7 @@ class MainCameraController {
if (_isBusy) return; if (_isBusy) return;
_isBusy = true; _isBusy = true;
final barcodes = await _barcodeScanner.processImage(inputImage); final barcodes = await _barcodeScanner.processImage(inputImage);
if (inputImage.metadata?.size != null && if (inputImage.metadata?.size != null && inputImage.metadata?.rotation != null && cameraController != null) {
inputImage.metadata?.rotation != null &&
cameraController != null) {
final painter = BarcodeDetectorPainter( final painter = BarcodeDetectorPainter(
barcodes, barcodes,
inputImage.metadata!.size, inputImage.metadata!.size,
@ -430,9 +426,7 @@ class MainCameraController {
if (_isBusyFaces) return; if (_isBusyFaces) return;
_isBusyFaces = true; _isBusyFaces = true;
final faces = await _faceDetector.processImage(inputImage); final faces = await _faceDetector.processImage(inputImage);
if (inputImage.metadata?.size != null && if (inputImage.metadata?.size != null && inputImage.metadata?.rotation != null && cameraController != null) {
inputImage.metadata?.rotation != null &&
cameraController != null) {
if (faces.isNotEmpty) { if (faces.isNotEmpty) {
CustomPainter? painter; CustomPainter? painter;
switch (_currentFilterType) { switch (_currentFilterType) {

View file

@ -31,14 +31,18 @@ class QrCodeScannerViewState extends State<QrCodeScannerView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
body: GestureDetector( body: Stack(
onDoubleTap: _mainCameraController.onDoubleTap,
onTapDown: _mainCameraController.onTapDown,
child: Stack(
children: [ children: [
MainCameraPreview( MainCameraPreview(
mainCameraController: _mainCameraController, mainCameraController: _mainCameraController,
), ),
Positioned.fill(
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onDoubleTap: _mainCameraController.onDoubleTap,
onTapDown: _mainCameraController.onTapDown,
),
),
CameraPreviewControllerView( CameraPreviewControllerView(
mainController: _mainCameraController, mainController: _mainCameraController,
hideControllers: true, hideControllers: true,
@ -46,7 +50,6 @@ class QrCodeScannerViewState extends State<QrCodeScannerView> {
), ),
], ],
), ),
),
); );
} }
} }

View file

@ -33,14 +33,18 @@ class CameraSendToViewState extends State<CameraSendToView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
body: GestureDetector( body: Stack(
onDoubleTap: _mainCameraController.onDoubleTap,
onTapDown: _mainCameraController.onTapDown,
child: Stack(
children: [ children: [
MainCameraPreview( MainCameraPreview(
mainCameraController: _mainCameraController, mainCameraController: _mainCameraController,
), ),
Positioned.fill(
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onDoubleTap: _mainCameraController.onDoubleTap,
onTapDown: _mainCameraController.onTapDown,
),
),
CameraPreviewControllerView( CameraPreviewControllerView(
mainController: _mainCameraController, mainController: _mainCameraController,
sendToGroup: widget.sendToGroup, sendToGroup: widget.sendToGroup,
@ -48,7 +52,6 @@ class CameraSendToViewState extends State<CameraSendToView> {
), ),
], ],
), ),
),
); );
} }
} }

View file

@ -237,10 +237,7 @@ class HomeViewState extends State<HomeView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
body: GestureDetector( body: Stack(
onDoubleTap: _offsetRatio == 0 ? _mainCameraController.onDoubleTap : null,
onTapDown: _offsetRatio == 0 ? _mainCameraController.onTapDown : null,
child: Stack(
children: <Widget>[ children: <Widget>[
MainCameraPreview(mainCameraController: _mainCameraController), MainCameraPreview(mainCameraController: _mainCameraController),
Positioned.fill( Positioned.fill(
@ -269,6 +266,14 @@ class HomeViewState extends State<HomeView> {
), ),
), ),
), ),
if (_offsetRatio == 0)
Positioned.fill(
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onDoubleTap: _mainCameraController.onDoubleTap,
onTapDown: _mainCameraController.onTapDown,
),
),
Positioned( Positioned(
left: 0, left: 0,
top: 0, top: 0,
@ -284,7 +289,6 @@ class HomeViewState extends State<HomeView> {
), ),
], ],
), ),
),
bottomNavigationBar: AnimatedSize( bottomNavigationBar: AnimatedSize(
duration: const Duration(milliseconds: 250), duration: const Duration(milliseconds: 250),
curve: Curves.easeInOut, curve: Curves.easeInOut,

View file

@ -44,7 +44,7 @@ class _PublicProfileViewState extends State<PublicProfileView> {
SizedBox(width: 15), SizedBox(width: 15),
], ],
), ),
body: Column( body: ListView(
children: [ children: [
Container(width: double.infinity), Container(width: double.infinity),
const SizedBox(height: 10), const SizedBox(height: 10),
@ -75,6 +75,7 @@ class _PublicProfileViewState extends State<PublicProfileView> {
Text( Text(
userService.currentUser.username, userService.currentUser.username,
style: const TextStyle(fontSize: 24), style: const TextStyle(fontSize: 24),
textAlign: TextAlign.center,
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
const Divider(), const Divider(),