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.
- Fix: Issue with receiving messages when user closed app while decrypting
- Fix: Background message fetching reliability.
- Fix: Issue with focus changing when taking a picture
## 0.2.16

View file

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

View file

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

View file

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

View file

@ -237,53 +237,57 @@ class HomeViewState extends State<HomeView> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onDoubleTap: _offsetRatio == 0 ? _mainCameraController.onDoubleTap : null,
onTapDown: _offsetRatio == 0 ? _mainCameraController.onTapDown : null,
child: Stack(
children: <Widget>[
MainCameraPreview(mainCameraController: _mainCameraController),
body: Stack(
children: <Widget>[
MainCameraPreview(mainCameraController: _mainCameraController),
Positioned.fill(
child: Opacity(
opacity: _offsetRatio,
child: Container(
color: context.color.surface,
),
),
),
NotificationListener<ScrollNotification>(
onNotification: _onPageView,
child: Positioned.fill(
child: PageView(
controller: _homeViewPageController,
onPageChanged: (index) {
setState(() {
_activePageIdx = index;
});
},
children: [
const ChatListView(),
Container(),
const MemoriesView(),
],
),
),
),
if (_offsetRatio == 0)
Positioned.fill(
child: Opacity(
opacity: _offsetRatio,
child: Container(
color: context.color.surface,
),
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onDoubleTap: _mainCameraController.onDoubleTap,
onTapDown: _mainCameraController.onTapDown,
),
),
NotificationListener<ScrollNotification>(
onNotification: _onPageView,
child: Positioned.fill(
child: PageView(
controller: _homeViewPageController,
onPageChanged: (index) {
setState(() {
_activePageIdx = index;
});
},
children: [
const ChatListView(),
Container(),
const MemoriesView(),
],
),
Positioned(
left: 0,
top: 0,
right: 0,
bottom: (_offsetRatio > 0.25) ? MediaQuery.sizeOf(context).height * 2 : 0,
child: Opacity(
opacity: 1 - (_offsetRatio * 4) % 1,
child: CameraPreviewControllerView(
mainController: _mainCameraController,
isVisible: ((1 - (_offsetRatio * 4) % 1) == 1) && _activePageIdx == 1,
),
),
Positioned(
left: 0,
top: 0,
right: 0,
bottom: (_offsetRatio > 0.25) ? MediaQuery.sizeOf(context).height * 2 : 0,
child: Opacity(
opacity: 1 - (_offsetRatio * 4) % 1,
child: CameraPreviewControllerView(
mainController: _mainCameraController,
isVisible: ((1 - (_offsetRatio * 4) % 1) == 1) && _activePageIdx == 1,
),
),
),
],
),
),
],
),
bottomNavigationBar: AnimatedSize(
duration: const Duration(milliseconds: 250),

View file

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