mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-05-25 08:02:13 +00:00
Fix: Issue with focus changing when taking a picture
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
Some checks are pending
Flutter analyze & test / flutter_analyze_and_test (push) Waiting to run
This commit is contained in:
parent
2d6a2e436f
commit
f42a49cadf
6 changed files with 110 additions and 104 deletions
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -31,21 +31,24 @@ 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,
|
children: [
|
||||||
onTapDown: _mainCameraController.onTapDown,
|
MainCameraPreview(
|
||||||
child: Stack(
|
mainCameraController: _mainCameraController,
|
||||||
children: [
|
),
|
||||||
MainCameraPreview(
|
Positioned.fill(
|
||||||
mainCameraController: _mainCameraController,
|
child: GestureDetector(
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
onDoubleTap: _mainCameraController.onDoubleTap,
|
||||||
|
onTapDown: _mainCameraController.onTapDown,
|
||||||
),
|
),
|
||||||
CameraPreviewControllerView(
|
),
|
||||||
mainController: _mainCameraController,
|
CameraPreviewControllerView(
|
||||||
hideControllers: true,
|
mainController: _mainCameraController,
|
||||||
isVisible: true,
|
hideControllers: true,
|
||||||
),
|
isVisible: true,
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,21 +33,24 @@ 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,
|
children: [
|
||||||
onTapDown: _mainCameraController.onTapDown,
|
MainCameraPreview(
|
||||||
child: Stack(
|
mainCameraController: _mainCameraController,
|
||||||
children: [
|
),
|
||||||
MainCameraPreview(
|
Positioned.fill(
|
||||||
mainCameraController: _mainCameraController,
|
child: GestureDetector(
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
onDoubleTap: _mainCameraController.onDoubleTap,
|
||||||
|
onTapDown: _mainCameraController.onTapDown,
|
||||||
),
|
),
|
||||||
CameraPreviewControllerView(
|
),
|
||||||
mainController: _mainCameraController,
|
CameraPreviewControllerView(
|
||||||
sendToGroup: widget.sendToGroup,
|
mainController: _mainCameraController,
|
||||||
isVisible: true,
|
sendToGroup: widget.sendToGroup,
|
||||||
),
|
isVisible: true,
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -237,53 +237,57 @@ 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,
|
children: <Widget>[
|
||||||
onTapDown: _offsetRatio == 0 ? _mainCameraController.onTapDown : null,
|
MainCameraPreview(mainCameraController: _mainCameraController),
|
||||||
child: Stack(
|
Positioned.fill(
|
||||||
children: <Widget>[
|
child: Opacity(
|
||||||
MainCameraPreview(mainCameraController: _mainCameraController),
|
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(
|
Positioned.fill(
|
||||||
child: Opacity(
|
child: GestureDetector(
|
||||||
opacity: _offsetRatio,
|
behavior: HitTestBehavior.translucent,
|
||||||
child: Container(
|
onDoubleTap: _mainCameraController.onDoubleTap,
|
||||||
color: context.color.surface,
|
onTapDown: _mainCameraController.onTapDown,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
NotificationListener<ScrollNotification>(
|
Positioned(
|
||||||
onNotification: _onPageView,
|
left: 0,
|
||||||
child: Positioned.fill(
|
top: 0,
|
||||||
child: PageView(
|
right: 0,
|
||||||
controller: _homeViewPageController,
|
bottom: (_offsetRatio > 0.25) ? MediaQuery.sizeOf(context).height * 2 : 0,
|
||||||
onPageChanged: (index) {
|
child: Opacity(
|
||||||
setState(() {
|
opacity: 1 - (_offsetRatio * 4) % 1,
|
||||||
_activePageIdx = index;
|
child: CameraPreviewControllerView(
|
||||||
});
|
mainController: _mainCameraController,
|
||||||
},
|
isVisible: ((1 - (_offsetRatio * 4) % 1) == 1) && _activePageIdx == 1,
|
||||||
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,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
bottomNavigationBar: AnimatedSize(
|
bottomNavigationBar: AnimatedSize(
|
||||||
duration: const Duration(milliseconds: 250),
|
duration: const Duration(milliseconds: 250),
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue