Skip to content

Commit

Permalink
feat: Migration to the latest camera/mobile_scanner (openfoodfacts#6075)
Browse files Browse the repository at this point in the history
* Migration to the latest camera/mobile_scanner

* Bump minSdkVersion (Android)

* Minor change
  • Loading branch information
g123k authored Dec 28, 2024
1 parent baea968 commit a89f7a5
Show file tree
Hide file tree
Showing 8 changed files with 448 additions and 347 deletions.
142 changes: 142 additions & 0 deletions packages/scanner/ml_kit/lib/src/mobile_scanner_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:torch_light/torch_light.dart';

class CustomScannerController {
CustomScannerController({
required MobileScannerController controller,
}) : _controller = controller,
_torchState = TorchState(),
_availableCamerasState = AvailableCamerasState(),
_cameraFacingState = CameraFacingState() {
_detectTorch();
}

final MobileScannerController _controller;
final TorchState _torchState;
final AvailableCamerasState _availableCamerasState;
final CameraFacingState _cameraFacingState;

bool _isStarted = false;
bool _isStarting = false;
bool _isClosing = false;
bool _isClosed = false;

Future<void> start() async {
if (isStarted || _isStarting || isClosing) {
return;
}

_isStarting = true;
_isClosed = false;
try {
_controller.addListener(_onControllerChanged);
await _controller.start();
_isStarted = true;

if (isTorchOn) {
// Slight delay, because it doesn't always work if called immediately
Future<void>.delayed(const Duration(milliseconds: 250), () {
turnTorchOn();
});
}
_isStarting = false;
} catch (_) {}
}

void _onControllerChanged() {
_availableCamerasState.value = _controller.value.availableCameras ?? 0;
_cameraFacingState.value = _controller.facing;
}

MobileScannerController get controller => _controller;

bool get isStarted => _isStarted;

bool get isClosing => _isClosing;

bool get isClosed => _isClosed;

Future<void> stop() async {
if (isClosed || isClosing || _isStarting) {
return;
}

_isClosing = true;
_isStarting = false;
_isStarted = false;
try {
await _controller.stop();
_controller.removeListener(_onControllerChanged);
_isClosing = false;
_isClosed = true;
} catch (_) {}
}

bool get hasTorch => _torchState.value != null;

ValueNotifier<bool?> get hasTorchState => _torchState;

bool get isTorchOn => _torchState.value == true;

void turnTorchOff() {
if (isTorchOn) {
_controller.toggleTorch();
_torchState.value = false;
}
}

void turnTorchOn() {
if (!isTorchOn) {
_controller.toggleTorch();
_torchState.value = true;
}
}

void toggleTorch() {
if (isTorchOn) {
turnTorchOff();
} else {
turnTorchOn();
}
}

ValueNotifier<int> get availableCameras => _availableCamerasState;
ValueNotifier<CameraFacing> get cameraFacing => _cameraFacingState;

void toggleCamera() {
_controller.switchCamera();
if (_controller.facing == CameraFacing.front) {
_torchState.value = null;
_cameraFacingState.value = CameraFacing.front;
} else if (_controller.facing == CameraFacing.front) {
_torchState.value = false;
_cameraFacingState.value = CameraFacing.back;
}
}

Future<void> _detectTorch() async {
try {
final bool isTorchAvailable = await TorchLight.isTorchAvailable();
if (isTorchAvailable) {
_torchState.value = false;
} else {
_torchState.value = null;
}
} on Exception catch (_) {}
}

Future<void> dispose() => _controller.dispose();
}

class TorchState extends ValueNotifier<bool?> {
TorchState({bool? value}) : super(value);
}

class AvailableCamerasState extends ValueNotifier<int> {
AvailableCamerasState() : super(0);
}

class CameraFacingState extends ValueNotifier<CameraFacing> {
CameraFacingState() : super(CameraFacing.back);
}
Loading

0 comments on commit a89f7a5

Please sign in to comment.