mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-09-01 08:04:07 +00:00
fix black screen
This commit is contained in:
parent
79d668e004
commit
e8e3254278
4 changed files with 82 additions and 3 deletions
|
|
@ -168,6 +168,7 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
super.initState();
|
super.initState();
|
||||||
initVolumeControl();
|
initVolumeControl();
|
||||||
initAsync();
|
initAsync();
|
||||||
|
_checkAndInitCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -176,12 +177,26 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
if (oldWidget.isVisible != widget.isVisible) {
|
if (oldWidget.isVisible != widget.isVisible) {
|
||||||
if (widget.isVisible) {
|
if (widget.isVisible) {
|
||||||
initVolumeControl();
|
initVolumeControl();
|
||||||
|
_checkAndInitCamera();
|
||||||
} else {
|
} else {
|
||||||
_deInitVolumeControl();
|
_deInitVolumeControl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _checkAndInitCamera() {
|
||||||
|
if (widget.isVisible &&
|
||||||
|
mc.cameraController == null &&
|
||||||
|
!mc.initCameraStarted) {
|
||||||
|
unawaited(
|
||||||
|
mc.selectCamera(
|
||||||
|
mc.selectedCameraDetails.cameraId,
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_videoRecordingTimer?.cancel();
|
_videoRecordingTimer?.cancel();
|
||||||
|
|
@ -686,7 +701,23 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (mc.selectedCameraDetails.cameraId >= AppEnvironment.cameras.length ||
|
if (mc.selectedCameraDetails.cameraId >= AppEnvironment.cameras.length ||
|
||||||
mc.cameraController == null) {
|
mc.cameraController == null) {
|
||||||
return Container();
|
if (widget.isVisible && !mc.initCameraStarted) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_checkAndInitCamera();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Show a loader instead of an empty container to prevent a black screen
|
||||||
|
// while the camera is initializing or if initialization failed.
|
||||||
|
return Center(
|
||||||
|
child: SizedBox(
|
||||||
|
height: 60,
|
||||||
|
width: 60,
|
||||||
|
child: ThreeRotatingDots(
|
||||||
|
size: 40,
|
||||||
|
color: context.color.primary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return StreamBuilder(
|
return StreamBuilder(
|
||||||
stream: userService.onUserUpdated,
|
stream: userService.onUserUpdated,
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,7 @@ class MainCameraController {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error('Error querying available cameras: $e');
|
Log.error('Error querying available cameras: $e');
|
||||||
initCameraStarted = false;
|
initCameraStarted = false;
|
||||||
|
setState?.call();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,6 +165,7 @@ class MainCameraController {
|
||||||
'Trying to select a non existing camera $cameraId >= ${AppEnvironment.cameras.length}',
|
'Trying to select a non existing camera $cameraId >= ${AppEnvironment.cameras.length}',
|
||||||
);
|
);
|
||||||
initCameraStarted = false;
|
initCameraStarted = false;
|
||||||
|
setState?.call();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,7 +194,7 @@ class MainCameraController {
|
||||||
final hasMic = await micPermissionFuture;
|
final hasMic = await micPermissionFuture;
|
||||||
if (sessionId != _cameraSessionId) return;
|
if (sessionId != _cameraSessionId) return;
|
||||||
|
|
||||||
final controller = CameraController(
|
var controller = CameraController(
|
||||||
AppEnvironment.cameras[cameraId],
|
AppEnvironment.cameras[cameraId],
|
||||||
ResolutionPreset.high,
|
ResolutionPreset.high,
|
||||||
enableAudio: hasMic,
|
enableAudio: hasMic,
|
||||||
|
|
@ -204,7 +206,21 @@ class MainCameraController {
|
||||||
var assignedToGlobal = false;
|
var assignedToGlobal = false;
|
||||||
try {
|
try {
|
||||||
_initializeFuture = controller.initialize();
|
_initializeFuture = controller.initialize();
|
||||||
|
try {
|
||||||
await _initializeFuture;
|
await _initializeFuture;
|
||||||
|
} on CameraException catch (e) {
|
||||||
|
// If specific image format is unsupported on this hardware, fallback to default format
|
||||||
|
Log.warn('Initial camera format initialization failed ($e), trying fallback format...');
|
||||||
|
await controller.dispose();
|
||||||
|
controller = CameraController(
|
||||||
|
AppEnvironment.cameras[cameraId],
|
||||||
|
ResolutionPreset.high,
|
||||||
|
enableAudio: hasMic,
|
||||||
|
);
|
||||||
|
_initializeFuture = controller.initialize();
|
||||||
|
await _initializeFuture;
|
||||||
|
}
|
||||||
|
|
||||||
if (sessionId != _cameraSessionId) {
|
if (sessionId != _cameraSessionId) {
|
||||||
unawaited(controller.dispose());
|
unawaited(controller.dispose());
|
||||||
return;
|
return;
|
||||||
|
|
@ -256,6 +272,7 @@ class MainCameraController {
|
||||||
unawaited(controller.dispose());
|
unawaited(controller.dispose());
|
||||||
}
|
}
|
||||||
initCameraStarted = false;
|
initCameraStarted = false;
|
||||||
|
setState?.call();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
import 'package:twonly/src/services/key_verification.service.dart';
|
import 'package:twonly/src/services/key_verification.service.dart';
|
||||||
|
|
@ -8,6 +10,7 @@ import 'package:twonly/src/utils/misc.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';
|
||||||
|
import 'package:twonly/src/visual/views/camera/share_image_editor_components/action_button.dart';
|
||||||
|
|
||||||
class QrCodeScannerView extends StatefulWidget {
|
class QrCodeScannerView extends StatefulWidget {
|
||||||
const QrCodeScannerView({
|
const QrCodeScannerView({
|
||||||
|
|
@ -41,6 +44,7 @@ class QrCodeScannerViewState extends State<QrCodeScannerView> {
|
||||||
}
|
}
|
||||||
Permission.camera.isGranted.then((hasPermission) {
|
Permission.camera.isGranted.then((hasPermission) {
|
||||||
if (hasPermission && mounted) {
|
if (hasPermission && mounted) {
|
||||||
|
AppState.hasCameraPermissions = true;
|
||||||
unawaited(_mainCameraController.selectCamera(0, true));
|
unawaited(_mainCameraController.selectCamera(0, true));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -100,6 +104,17 @@ class QrCodeScannerViewState extends State<QrCodeScannerView> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// Always-visible back button so the user can exit regardless of
|
||||||
|
// camera state (e.g. during init or after init failure).
|
||||||
|
Positioned(
|
||||||
|
left: 5,
|
||||||
|
top: MediaQuery.paddingOf(context).top + 10,
|
||||||
|
child: ActionButton(
|
||||||
|
FontAwesomeIcons.xmark,
|
||||||
|
tooltipText: context.lang.close,
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
|
import 'package:twonly/src/utils/misc.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';
|
||||||
|
import 'package:twonly/src/visual/views/camera/share_image_editor_components/action_button.dart';
|
||||||
|
|
||||||
class CameraSendToView extends StatefulWidget {
|
class CameraSendToView extends StatefulWidget {
|
||||||
const CameraSendToView(this.sendToGroup, {super.key});
|
const CameraSendToView(this.sendToGroup, {super.key});
|
||||||
|
|
@ -24,6 +28,7 @@ class CameraSendToViewState extends State<CameraSendToView> {
|
||||||
};
|
};
|
||||||
Permission.camera.isGranted.then((hasPermission) {
|
Permission.camera.isGranted.then((hasPermission) {
|
||||||
if (hasPermission && mounted) {
|
if (hasPermission && mounted) {
|
||||||
|
AppState.hasCameraPermissions = true;
|
||||||
unawaited(_mainCameraController.selectCamera(0, true));
|
unawaited(_mainCameraController.selectCamera(0, true));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -58,6 +63,17 @@ class CameraSendToViewState extends State<CameraSendToView> {
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// Always-visible back button so the user can exit regardless of
|
||||||
|
// camera state (e.g. during init or after init failure).
|
||||||
|
Positioned(
|
||||||
|
left: 5,
|
||||||
|
top: MediaQuery.paddingOf(context).top + 10,
|
||||||
|
child: ActionButton(
|
||||||
|
FontAwesomeIcons.xmark,
|
||||||
|
tooltipText: context.lang.close,
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue