mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-06-25 05:04:07 +00:00
fix camera initalization issue
This commit is contained in:
parent
c4fc14a909
commit
f14a94d639
8 changed files with 148 additions and 57 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'package:camera/camera.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:mutex/mutex.dart';
|
import 'package:mutex/mutex.dart';
|
||||||
|
|
@ -68,6 +69,14 @@ Future<bool> twonlyMinimumInitialization() async {
|
||||||
void main() async {
|
void main() async {
|
||||||
final binding = SentryWidgetsFlutterBinding.ensureInitialized();
|
final binding = SentryWidgetsFlutterBinding.ensureInitialized();
|
||||||
await AppEnvironment.init();
|
await AppEnvironment.init();
|
||||||
|
|
||||||
|
// Preload available cameras in the background to speed up camera tab startup
|
||||||
|
unawaited(
|
||||||
|
availableCameras().then((cameras) {
|
||||||
|
AppEnvironment.cameras = cameras;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
final stopwatch = Stopwatch()..start();
|
final stopwatch = Stopwatch()..start();
|
||||||
|
|
||||||
unawaited(StartupGuard.markAppStartup());
|
unawaited(StartupGuard.markAppStartup());
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,7 @@ class _CameraPreviewControllerViewState
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return PermissionHandlerView(
|
return PermissionHandlerView(
|
||||||
|
triggerPermissionRequest: widget.isVisible,
|
||||||
onSuccess: () {
|
onSuccess: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
AppState.hasCameraPermissions = true;
|
AppState.hasCameraPermissions = true;
|
||||||
|
|
|
||||||
|
|
@ -134,8 +134,14 @@ class MainCameraController {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> selectCamera(int sCameraId, bool init) async {
|
Future<void> selectCamera(int sCameraId, bool init) async {
|
||||||
|
if (initCameraStarted) return;
|
||||||
initCameraStarted = true;
|
initCameraStarted = true;
|
||||||
final sessionId = ++_cameraSessionId;
|
final sessionId = ++_cameraSessionId;
|
||||||
|
|
||||||
|
// Start checking microphone permission concurrently
|
||||||
|
final micPermissionFuture = Permission.microphone.isGranted;
|
||||||
|
|
||||||
|
try {
|
||||||
await _pendingDisposal;
|
await _pendingDisposal;
|
||||||
if (sessionId != _cameraSessionId) return;
|
if (sessionId != _cameraSessionId) return;
|
||||||
|
|
||||||
|
|
@ -143,12 +149,18 @@ class MainCameraController {
|
||||||
AppEnvironment.cameras = await availableCameras();
|
AppEnvironment.cameras = await availableCameras();
|
||||||
if (sessionId != _cameraSessionId) return;
|
if (sessionId != _cameraSessionId) return;
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Log.error('Error querying available cameras: $e');
|
||||||
|
initCameraStarted = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var cameraId = sCameraId;
|
var cameraId = sCameraId;
|
||||||
if (cameraId >= AppEnvironment.cameras.length) {
|
if (cameraId >= AppEnvironment.cameras.length) {
|
||||||
Log.warn(
|
Log.warn(
|
||||||
'Trying to select a non existing camera $cameraId >= ${AppEnvironment.cameras.length}',
|
'Trying to select a non existing camera $cameraId >= ${AppEnvironment.cameras.length}',
|
||||||
);
|
);
|
||||||
|
initCameraStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,12 +171,21 @@ class MainCameraController {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (cameraId >= AppEnvironment.cameras.length) {
|
||||||
|
cameraId = sCameraId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedCameraDetails.isZoomAble = false;
|
selectedCameraDetails.isZoomAble = false;
|
||||||
|
|
||||||
if (cameraController == null) {
|
if (cameraController == null || !cameraController!.value.isInitialized) {
|
||||||
final hasMic = await Permission.microphone.isGranted;
|
final controllerToDispose = cameraController;
|
||||||
|
cameraController = null;
|
||||||
|
if (controllerToDispose != null) {
|
||||||
|
unawaited(controllerToDispose.dispose());
|
||||||
|
}
|
||||||
|
|
||||||
|
final hasMic = await micPermissionFuture;
|
||||||
if (sessionId != _cameraSessionId) return;
|
if (sessionId != _cameraSessionId) return;
|
||||||
|
|
||||||
cameraController = CameraController(
|
cameraController = CameraController(
|
||||||
|
|
@ -178,56 +199,55 @@ class MainCameraController {
|
||||||
try {
|
try {
|
||||||
_initializeFuture = cameraController?.initialize();
|
_initializeFuture = cameraController?.initialize();
|
||||||
await _initializeFuture;
|
await _initializeFuture;
|
||||||
if (cameraController == null) return;
|
await cameraController!.startImageStream(_processCameraImage);
|
||||||
await cameraController?.startImageStream(_processCameraImage);
|
await cameraController!.setZoomLevel(selectedCameraDetails.scaleFactor);
|
||||||
if (cameraController == null) return;
|
|
||||||
await cameraController?.setZoomLevel(selectedCameraDetails.scaleFactor);
|
|
||||||
if (cameraController == null) return;
|
|
||||||
if (userService.currentUser.videoStabilizationEnabled && !kDebugMode) {
|
if (userService.currentUser.videoStabilizationEnabled && !kDebugMode) {
|
||||||
await cameraController?.setVideoStabilizationMode(
|
await cameraController!.setVideoStabilizationMode(
|
||||||
VideoStabilizationMode.level1,
|
VideoStabilizationMode.level1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
Log.error('Error initializing camera: $e');
|
||||||
|
final controllerToDispose = cameraController;
|
||||||
cameraController = null;
|
cameraController = null;
|
||||||
|
if (controllerToDispose != null) {
|
||||||
|
unawaited(controllerToDispose.dispose());
|
||||||
|
}
|
||||||
|
initCameraStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
if (!isVideoRecording) {
|
if (!isVideoRecording) {
|
||||||
await cameraController?.stopImageStream();
|
await cameraController!.stopImageStream();
|
||||||
}
|
}
|
||||||
if (cameraController == null) return;
|
|
||||||
selectedCameraDetails.scaleFactor = 1;
|
selectedCameraDetails.scaleFactor = 1;
|
||||||
|
|
||||||
await cameraController?.setZoomLevel(1);
|
await cameraController!.setZoomLevel(1);
|
||||||
if (cameraController == null) return;
|
await cameraController!.setDescription(
|
||||||
await cameraController?.setDescription(
|
|
||||||
AppEnvironment.cameras[cameraId],
|
AppEnvironment.cameras[cameraId],
|
||||||
);
|
);
|
||||||
if (cameraController == null) return;
|
|
||||||
if (!isVideoRecording) {
|
if (!isVideoRecording) {
|
||||||
await cameraController?.startImageStream(_processCameraImage);
|
await cameraController!.startImageStream(_processCameraImage);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.info(e);
|
Log.error('Error switching camera description: $e');
|
||||||
|
initCameraStarted = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (cameraController == null) return;
|
await cameraController!.lockCaptureOrientation(
|
||||||
await cameraController?.lockCaptureOrientation(
|
|
||||||
DeviceOrientation.portraitUp,
|
DeviceOrientation.portraitUp,
|
||||||
);
|
);
|
||||||
if (cameraController == null) return;
|
await cameraController!.setFlashMode(
|
||||||
await cameraController?.setFlashMode(
|
|
||||||
selectedCameraDetails.isFlashOn ? FlashMode.always : FlashMode.off,
|
selectedCameraDetails.isFlashOn ? FlashMode.always : FlashMode.off,
|
||||||
);
|
);
|
||||||
if (cameraController == null) return;
|
selectedCameraDetails.maxAvailableZoom = await cameraController!
|
||||||
selectedCameraDetails.maxAvailableZoom =
|
.getMaxZoomLevel();
|
||||||
await cameraController?.getMaxZoomLevel() ?? 1;
|
selectedCameraDetails.minAvailableZoom = await cameraController!
|
||||||
selectedCameraDetails.minAvailableZoom =
|
.getMinZoomLevel();
|
||||||
await cameraController?.getMinZoomLevel() ?? 1;
|
|
||||||
selectedCameraDetails
|
selectedCameraDetails
|
||||||
..isZoomAble =
|
..isZoomAble =
|
||||||
selectedCameraDetails.maxAvailableZoom !=
|
selectedCameraDetails.maxAvailableZoom !=
|
||||||
|
|
@ -240,10 +260,16 @@ class MainCameraController {
|
||||||
isSelectingFaceFilters = false;
|
isSelectingFaceFilters = false;
|
||||||
setFilter(FaceFilterType.none);
|
setFilter(FaceFilterType.none);
|
||||||
zoomButtonKey = GlobalKey();
|
zoomButtonKey = GlobalKey();
|
||||||
|
initCameraStarted = false;
|
||||||
setState?.call();
|
setState?.call();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error(e);
|
Log.error('Error post-initializing camera: $e');
|
||||||
|
final controllerToDispose = cameraController;
|
||||||
cameraController = null;
|
cameraController = null;
|
||||||
|
if (controllerToDispose != null) {
|
||||||
|
unawaited(controllerToDispose.dispose());
|
||||||
|
}
|
||||||
|
initCameraStarted = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -310,7 +336,6 @@ class MainCameraController {
|
||||||
}
|
}
|
||||||
final inputImage = _inputImageFromCameraImage(image);
|
final inputImage = _inputImageFromCameraImage(image);
|
||||||
if (inputImage == null) return;
|
if (inputImage == null) return;
|
||||||
_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) {
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,18 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:twonly/src/services/user.service.dart';
|
||||||
import 'package:twonly/src/utils/log.dart';
|
import 'package:twonly/src/utils/log.dart';
|
||||||
|
|
||||||
class PermissionHandlerView extends StatefulWidget {
|
class PermissionHandlerView extends StatefulWidget {
|
||||||
const PermissionHandlerView({required this.onSuccess, super.key});
|
const PermissionHandlerView({
|
||||||
|
required this.onSuccess,
|
||||||
|
this.triggerPermissionRequest = true,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
final Function onSuccess;
|
final Function onSuccess;
|
||||||
|
final bool triggerPermissionRequest;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
PermissionHandlerViewState createState() => PermissionHandlerViewState();
|
PermissionHandlerViewState createState() => PermissionHandlerViewState();
|
||||||
|
|
@ -17,10 +23,6 @@ Future<bool> checkPermissions() async {
|
||||||
if (!await Permission.camera.isGranted) {
|
if (!await Permission.camera.isGranted) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!await Permission.microphone.isGranted) {
|
|
||||||
// microphone is only needed when
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,6 +38,32 @@ class PermissionHandlerViewState extends State<PermissionHandlerView>
|
||||||
_timer = Timer.periodic(const Duration(milliseconds: 500), (timer) async {
|
_timer = Timer.periodic(const Duration(milliseconds: 500), (timer) async {
|
||||||
await _checkAndTriggerSuccess();
|
await _checkAndTriggerSuccess();
|
||||||
});
|
});
|
||||||
|
if (widget.triggerPermissionRequest) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
|
await _requestPermissions();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(PermissionHandlerView oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
if (widget.triggerPermissionRequest && !oldWidget.triggerPermissionRequest) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
|
await _requestPermissions();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _requestPermissions() async {
|
||||||
|
try {
|
||||||
|
await permissionServices();
|
||||||
|
if (await checkPermissions()) {
|
||||||
|
_handleSuccess();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Log.error(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -54,21 +82,32 @@ class PermissionHandlerViewState extends State<PermissionHandlerView>
|
||||||
|
|
||||||
Future<void> _checkAndTriggerSuccess() async {
|
Future<void> _checkAndTriggerSuccess() async {
|
||||||
if (_isSuccessTriggered) return;
|
if (_isSuccessTriggered) return;
|
||||||
|
final route = ModalRoute.of(context);
|
||||||
|
if (route != null && !route.isCurrent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if (await checkPermissions()) {
|
if (await checkPermissions()) {
|
||||||
_isSuccessTriggered = true;
|
_handleSuccess();
|
||||||
_timer?.cancel();
|
|
||||||
// ignore: avoid_dynamic_calls
|
|
||||||
widget.onSuccess();
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error(e);
|
Log.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _handleSuccess() {
|
||||||
|
if (_isSuccessTriggered) return;
|
||||||
|
_isSuccessTriggered = true;
|
||||||
|
_timer?.cancel();
|
||||||
|
unawaited(UserService.update((u) => u.requestedAudioPermission = true));
|
||||||
|
// ignore: avoid_dynamic_calls
|
||||||
|
widget.onSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
Future<Map<Permission, PermissionStatus>> permissionServices() async {
|
Future<Map<Permission, PermissionStatus>> permissionServices() async {
|
||||||
final statuses = await [
|
final statuses = await [
|
||||||
Permission.camera,
|
Permission.camera,
|
||||||
|
Permission.microphone,
|
||||||
Permission.notification,
|
Permission.notification,
|
||||||
].request();
|
].request();
|
||||||
|
|
||||||
|
|
@ -100,8 +139,7 @@ class PermissionHandlerViewState extends State<PermissionHandlerView>
|
||||||
try {
|
try {
|
||||||
await permissionServices();
|
await permissionServices();
|
||||||
if (await checkPermissions()) {
|
if (await checkPermissions()) {
|
||||||
// ignore: avoid_dynamic_calls
|
_handleSuccess();
|
||||||
widget.onSuccess();
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error(e);
|
Log.error(e);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview.dart';
|
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview_controller_view.dart';
|
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview_controller_view.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/camera_preview_components/main_camera_controller.dart';
|
import 'package:twonly/src/visual/views/camera/camera_preview_components/main_camera_controller.dart';
|
||||||
|
|
@ -19,8 +20,12 @@ class QrCodeScannerViewState extends State<QrCodeScannerView> {
|
||||||
_mainCameraController.setState = () {
|
_mainCameraController.setState = () {
|
||||||
if (mounted) setState(() {});
|
if (mounted) setState(() {});
|
||||||
};
|
};
|
||||||
|
Permission.camera.isGranted.then((hasPermission) {
|
||||||
|
if (hasPermission && mounted) {
|
||||||
unawaited(_mainCameraController.selectCamera(0, true));
|
unawaited(_mainCameraController.selectCamera(0, true));
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
|
@ -44,11 +49,13 @@ class QrCodeScannerViewState extends State<QrCodeScannerView> {
|
||||||
onTapDown: _mainCameraController.onTapDown,
|
onTapDown: _mainCameraController.onTapDown,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
CameraPreviewControllerView(
|
Positioned.fill(
|
||||||
|
child: CameraPreviewControllerView(
|
||||||
mainController: _mainCameraController,
|
mainController: _mainCameraController,
|
||||||
hideControllers: true,
|
hideControllers: true,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview.dart';
|
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview_controller_view.dart';
|
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview_controller_view.dart';
|
||||||
|
|
@ -21,8 +22,12 @@ class CameraSendToViewState extends State<CameraSendToView> {
|
||||||
_mainCameraController.setState = () {
|
_mainCameraController.setState = () {
|
||||||
if (mounted) setState(() {});
|
if (mounted) setState(() {});
|
||||||
};
|
};
|
||||||
|
Permission.camera.isGranted.then((hasPermission) {
|
||||||
|
if (hasPermission && mounted) {
|
||||||
unawaited(_mainCameraController.selectCamera(0, true));
|
unawaited(_mainCameraController.selectCamera(0, true));
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
|
@ -46,11 +51,13 @@ class CameraSendToViewState extends State<CameraSendToView> {
|
||||||
onTapDown: _mainCameraController.onTapDown,
|
onTapDown: _mainCameraController.onTapDown,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
CameraPreviewControllerView(
|
Positioned.fill(
|
||||||
|
child: CameraPreviewControllerView(
|
||||||
mainController: _mainCameraController,
|
mainController: _mainCameraController,
|
||||||
sendToGroup: widget.sendToGroup,
|
sendToGroup: widget.sendToGroup,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
import 'package:flutter_sharing_intent/model/sharing_file.dart';
|
import 'package:flutter_sharing_intent/model/sharing_file.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/constants/routes.keys.dart';
|
import 'package:twonly/src/constants/routes.keys.dart';
|
||||||
import 'package:twonly/src/providers/routing.provider.dart';
|
import 'package:twonly/src/providers/routing.provider.dart';
|
||||||
|
|
@ -102,8 +104,8 @@ class HomeViewState extends State<HomeView> with WidgetsBindingObserver {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (initialPage == 1) {
|
if (initialPage == 1) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
Permission.camera.isGranted.then((hasPermission) {
|
||||||
if (_isViewActive()) {
|
if (hasPermission && mounted) {
|
||||||
unawaited(_mainCameraController.selectCamera(0, true));
|
unawaited(_mainCameraController.selectCamera(0, true));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -219,7 +221,8 @@ class HomeViewState extends State<HomeView> with WidgetsBindingObserver {
|
||||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
super.didChangeAppLifecycleState(state);
|
super.didChangeAppLifecycleState(state);
|
||||||
if (state == AppLifecycleState.resumed) {
|
if (state == AppLifecycleState.resumed) {
|
||||||
if (_offsetRatio < 1 &&
|
if (AppState.hasCameraPermissions &&
|
||||||
|
_offsetRatio < 1 &&
|
||||||
!_mainCameraController.isSharePreviewIsShown &&
|
!_mainCameraController.isSharePreviewIsShown &&
|
||||||
_isViewActive() &&
|
_isViewActive() &&
|
||||||
_mainCameraController.cameraController == null &&
|
_mainCameraController.cameraController == null &&
|
||||||
|
|
@ -284,7 +287,8 @@ class HomeViewState extends State<HomeView> with WidgetsBindingObserver {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_mainCameraController.cameraController == null &&
|
if (AppState.hasCameraPermissions &&
|
||||||
|
_mainCameraController.cameraController == null &&
|
||||||
!_mainCameraController.initCameraStarted &&
|
!_mainCameraController.initCameraStarted &&
|
||||||
_offsetRatio < 1 &&
|
_offsetRatio < 1 &&
|
||||||
_isViewActive()) {
|
_isViewActive()) {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ description: "twonly, a privacy-friendly way to connect with friends through sec
|
||||||
|
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
|
|
||||||
version: 0.3.2+146
|
version: 0.3.3+147
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.11.0
|
sdk: ^3.11.0
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue