Skip to content

Commit

Permalink
fix: Black camera screen (#1732)
Browse files Browse the repository at this point in the history
* This should fix the black screen with the camera scanner

* Mark two methods as private

* A few more comments

* const constructor for CameraHelper

* Update packages/smooth_app/lib/pages/scan/lifecycle_manager.dart

Co-authored-by: monsieurtanuki <fabrice_fontaine@hotmail.com>

* Update packages/smooth_app/lib/pages/scan/lifecycle_manager.dart

Co-authored-by: monsieurtanuki <fabrice_fontaine@hotmail.com>

Co-authored-by: monsieurtanuki <fabrice_fontaine@hotmail.com>
  • Loading branch information
g123k and monsieurtanuki authored May 4, 2022
1 parent 21253c1 commit b55b6aa
Show file tree
Hide file tree
Showing 6 changed files with 268 additions and 87 deletions.
51 changes: 51 additions & 0 deletions packages/smooth_app/lib/helpers/camera_helper.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import 'package:camera/camera.dart';

class CameraHelper {
const CameraHelper._();

static List<CameraDescription>? _cameras;

/// Mandatory method to call before [findBestCamera]
static Future<void> init() async {
_cameras = await availableCameras();
}

/// Find the most relevant camera to use if none of these criteria are met,
/// the default value of [_cameraIndex] will be used to select the first
/// camera in the global cameras list.
/// if non matching is found we fall back to the first in the list
/// initValue of [_cameraIndex]/
static CameraDescription? findBestCamera({
CameraLensDirection cameraLensDirection = CameraLensDirection.back,
}) {
if (_cameras == null) {
throw Exception('Please call [init] before!');
} else if (_cameras!.isEmpty) {
return null;
}

int cameraIndex = -1;

if (_cameras!.any(
(CameraDescription element) =>
element.lensDirection == cameraLensDirection &&
element.sensorOrientation == 90,
)) {
cameraIndex = _cameras!.indexOf(
_cameras!.firstWhere((CameraDescription element) =>
element.lensDirection == cameraLensDirection &&
element.sensorOrientation == 90),
);
} else if (_cameras!.any((CameraDescription element) =>
element.lensDirection == cameraLensDirection)) {
cameraIndex = _cameras!.indexOf(
_cameras!.firstWhere(
(CameraDescription element) =>
element.lensDirection == cameraLensDirection,
),
);
}

return _cameras![cameraIndex];
}
}
7 changes: 2 additions & 5 deletions packages/smooth_app/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'dart:async';
import 'dart:io' show Platform;

import 'package:camera/camera.dart';
import 'package:device_preview/device_preview.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
Expand All @@ -22,12 +21,11 @@ import 'package:smooth_app/database/dao_string.dart';
import 'package:smooth_app/database/local_database.dart';
import 'package:smooth_app/database/product_query.dart';
import 'package:smooth_app/helpers/analytics_helper.dart';
import 'package:smooth_app/helpers/camera_helper.dart';
import 'package:smooth_app/pages/onboarding/onboarding_flow_navigator.dart';
import 'package:smooth_app/themes/smooth_theme.dart';
import 'package:smooth_app/themes/theme_provider.dart';

List<CameraDescription> cameras = <CameraDescription>[];

late bool _screenshots;

Future<void> main({final bool screenshots = false}) async {
Expand Down Expand Up @@ -103,8 +101,7 @@ Future<bool> _init1() async {
_themeProvider = ThemeProvider(_userPreferences);
ProductQuery.setQueryType(_userPreferences);

cameras = await availableCameras();

await CameraHelper.init();
await ProductQuery.setUuid(_localDatabase);
_init1done = true;
return true;
Expand Down
63 changes: 42 additions & 21 deletions packages/smooth_app/lib/pages/scan/lifecycle_manager.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:smooth_app/widgets/screen_visibility.dart';
import 'package:visibility_detector/visibility_detector.dart';

/// This Widgets tracks if the child is currently visible on screen and if the
/// app gets minimized/resumed by the system
/// This Widgets tracks both the app lifecycle and the screen visibility
/// [onStart] will be called only when the Widget is displayed for the first time
/// (= during the [initState] phase)
/// [onResume] will be called once the app is reopened (eg: the app is minimized
/// and brought back to front) or this part of the Widget tree is visible again
/// [onPause] will be called once the app is minimized or if this part of the
/// tree is invisible
class LifeCycleManager extends StatefulWidget {
const LifeCycleManager({
required this.onResume,
required this.onPause,
required this.child,
this.onStart,
Key? key,
}) : super(key: key);

final Function() onResume;
final Function() onPause;
final Function()? onStart;
final Widget child;

@override
Expand All @@ -22,29 +30,16 @@ class LifeCycleManager extends StatefulWidget {

class LifeCycleManagerState extends State<LifeCycleManager>
with WidgetsBindingObserver {
double visibleFraction = 100.0;
AppLifecycleState appLifecycleState = AppLifecycleState.resumed;

void checkLifeCycle() {
if (appLifecycleState == AppLifecycleState.inactive ||
visibleFraction == 0.0) {
widget.onPause.call();
} else if (appLifecycleState == AppLifecycleState.resumed &&
visibleFraction > 0.0) {
widget.onResume.call();
}
}

@override
void initState() {
super.initState();
WidgetsBinding.instance!.addObserver(this);
}

@override
void dispose() {
WidgetsBinding.instance!.removeObserver(this);
super.dispose();
if (widget.onStart != null) {
WidgetsBinding.instance!.addPostFrameCallback((_) => widget.onStart!());
}
}

// Lifecycle changes are not handled by either of the used plugin. This means
Expand All @@ -55,18 +50,44 @@ class LifeCycleManagerState extends State<LifeCycleManager>
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
appLifecycleState = state;
checkLifeCycle();
_onLifeCycleChanged();
}

void _onLifeCycleChanged() {
switch (appLifecycleState) {
case AppLifecycleState.resumed:
widget.onResume();
break;
case AppLifecycleState.inactive:
case AppLifecycleState.paused:
case AppLifecycleState.detached:
widget.onPause();
break;
}
}

void _onVisibilityChanged(bool visible) {
if (visible) {
widget.onResume();
} else {
widget.onPause();
}
}

@override
Widget build(BuildContext context) {
return VisibilityDetector(
key: const ValueKey<String>('VisibilityDetector'),
onVisibilityChanged: (VisibilityInfo info) {
visibleFraction = info.visibleFraction;
checkLifeCycle();
_onVisibilityChanged(info.visible);
},
child: widget.child,
);
}

@override
void dispose() {
WidgetsBinding.instance!.removeObserver(this);
super.dispose();
}
}
Loading

0 comments on commit b55b6aa

Please sign in to comment.