Julian Steenbakker

bug: fix black screen on pageview and scanwindow not being reverted.

... ... @@ -19,23 +19,6 @@ import dev.steenbakker.mobile_scanner.objects.MobileScannerStartParameters
import io.flutter.view.TextureRegistry
import kotlin.math.roundToInt
typealias MobileScannerCallback = (barcodes: List<Map<String, Any?>>, image: ByteArray?, width: Int?, height: Int?) -> Unit
typealias AnalyzerCallback = (barcodes: List<Map<String, Any?>>?) -> Unit
typealias MobileScannerErrorCallback = (error: String) -> Unit
typealias TorchStateCallback = (state: Int) -> Unit
typealias MobileScannerStartedCallback = (parameters: MobileScannerStartParameters) -> Unit
class NoCamera : Exception()
class AlreadyStarted : Exception()
class AlreadyStopped : Exception()
class TorchError : Exception()
class CameraError : Exception()
class TorchWhenStopped : Exception()
class ZoomWhenStopped : Exception()
class ZoomNotInRange : Exception()
class MobileScanner(
private val activity: Activity,
private val textureRegistry: TextureRegistry,
... ... @@ -43,22 +26,21 @@ class MobileScanner(
private val mobileScannerErrorCallback: MobileScannerErrorCallback
) {
/// Internal variables
private var cameraProvider: ProcessCameraProvider? = null
private var camera: Camera? = null
private var preview: Preview? = null
private var textureEntry: TextureRegistry.SurfaceTextureEntry? = null
var scanWindow: List<Float>? = null
private var detectionSpeed: DetectionSpeed = DetectionSpeed.NO_DUPLICATES
private var detectionTimeout: Long = 250
private var scanner = BarcodeScanning.getClient()
private var lastScanned: List<String?>? = null
private var scannerTimeout = false
/// Configurable variables
var scanWindow: List<Float>? = null
private var detectionSpeed: DetectionSpeed = DetectionSpeed.NO_DUPLICATES
private var detectionTimeout: Long = 250
private var returnImage = false
private var scanner = BarcodeScanning.getClient()
/**
* callback for the camera. Every frame is passed through this function.
*/
... ... @@ -87,10 +69,10 @@ class MobileScanner(
val barcodeMap: MutableList<Map<String, Any?>> = mutableListOf()
for ( barcode in barcodes) {
if(scanWindow != null) {
val match = isbarCodeInScanWindow(scanWindow!!, barcode, imageProxy)
if(!match) {
for (barcode in barcodes) {
if (scanWindow != null) {
val match = isBarcodeInScanWindow(scanWindow!!, barcode, imageProxy)
if (!match) {
continue
} else {
barcodeMap.add(barcode.data)
... ... @@ -126,7 +108,11 @@ class MobileScanner(
// scales the scanWindow to the provided inputImage and checks if that scaled
// scanWindow contains the barcode
private fun isbarCodeInScanWindow(scanWindow: List<Float>, barcode: Barcode, inputImage: ImageProxy): Boolean {
private fun isBarcodeInScanWindow(
scanWindow: List<Float>,
barcode: Barcode,
inputImage: ImageProxy
): Boolean {
val barcodeBoundingBox = barcode.boundingBox ?: return false
val imageWidth = inputImage.height
... ...
package dev.steenbakker.mobile_scanner
import dev.steenbakker.mobile_scanner.objects.MobileScannerStartParameters
typealias MobileScannerCallback = (barcodes: List<Map<String, Any?>>, image: ByteArray?, width: Int?, height: Int?) -> Unit
typealias AnalyzerCallback = (barcodes: List<Map<String, Any?>>?) -> Unit
typealias MobileScannerErrorCallback = (error: String) -> Unit
typealias TorchStateCallback = (state: Int) -> Unit
typealias MobileScannerStartedCallback = (parameters: MobileScannerStartParameters) -> Unit
\ No newline at end of file
... ...
package dev.steenbakker.mobile_scanner
class NoCamera : Exception()
class AlreadyStarted : Exception()
class AlreadyStopped : Exception()
class TorchError : Exception()
class CameraError : Exception()
class TorchWhenStopped : Exception()
class ZoomWhenStopped : Exception()
class ZoomNotInRange : Exception()
\ No newline at end of file
... ...
... ... @@ -230,6 +230,6 @@ class MobileScannerHandler(
}
private fun updateScanWindow(call: MethodCall) {
mobileScanner!!.scanWindow = call.argument<List<Float>>("rect")
mobileScanner!!.scanWindow = call.argument<List<Float>?>("rect")
}
}
\ No newline at end of file
... ...
... ... @@ -56,6 +56,12 @@ class MobileScanner extends StatefulWidget {
/// [BoxFit]
final Rect? scanWindow;
/// Only set this to true if you are starting another instance of mobile_scanner
/// right after disposing the first one, like in a PageView.
///
/// Default: false
final bool startDelay;
/// Create a new [MobileScanner] using the provided [controller]
/// and [onBarcodeDetected] callback.
const MobileScanner({
... ... @@ -67,6 +73,7 @@ class MobileScanner extends StatefulWidget {
this.onScannerStarted,
this.placeholderBuilder,
this.scanWindow,
this.startDelay = false,
super.key,
});
... ... @@ -88,7 +95,7 @@ class _MobileScannerState extends State<MobileScanner>
MobileScannerException? _startException;
Widget __buildPlaceholderOrError(BuildContext context, Widget? child) {
Widget _buildPlaceholderOrError(BuildContext context, Widget? child) {
final error = _startException;
if (error != null) {
... ... @@ -104,18 +111,28 @@ class _MobileScannerState extends State<MobileScanner>
}
/// Start the given [scanner].
void _startScanner(MobileScannerController scanner) {
Future<void> _startScanner() async {
if (widget.startDelay) {
await Future.delayed(const Duration(seconds: 1, milliseconds: 500));
}
if (!_controller.autoStart) {
debugPrint(
'mobile_scanner: not starting automatically because autoStart is set to false in the controller.',
);
return;
}
scanner.start().then((arguments) {
_barcodesSubscription = _controller.barcodes.listen(
widget.onDetect,
);
_controller.start().then((arguments) {
// ignore: deprecated_member_use_from_same_package
widget.onStart?.call(arguments);
widget.onScannerStarted?.call(arguments);
}).catchError((error) {
debugPrint('mobile_scanner: $error');
if (mounted) {
setState(() {
_startException = error as MobileScannerException;
... ... @@ -129,14 +146,7 @@ class _MobileScannerState extends State<MobileScanner>
super.initState();
WidgetsBinding.instance.addObserver(this);
_controller = widget.controller ?? MobileScannerController();
_barcodesSubscription = _controller.barcodes.listen(
widget.onDetect,
);
if (!_controller.isStarting) {
_startScanner(_controller);
}
_startScanner();
}
@override
... ... @@ -149,7 +159,7 @@ class _MobileScannerState extends State<MobileScanner>
switch (state) {
case AppLifecycleState.resumed:
_resumeFromBackground = false;
_startScanner(_controller);
_startScanner();
break;
case AppLifecycleState.paused:
_resumeFromBackground = true;
... ... @@ -228,7 +238,7 @@ class _MobileScannerState extends State<MobileScanner>
valueListenable: _controller.startArguments,
builder: (context, value, child) {
if (value == null) {
return __buildPlaceholderOrError(context, child);
return _buildPlaceholderOrError(context, child);
}
if (widget.scanWindow != null && scanWindow == null) {
... ... @@ -238,6 +248,7 @@ class _MobileScannerState extends State<MobileScanner>
value.size,
Size(constraints.maxWidth, constraints.maxHeight),
);
_controller.updateScanWindow(scanWindow!);
}
... ... @@ -268,8 +279,10 @@ class _MobileScannerState extends State<MobileScanner>
@override
void dispose() {
_controller.updateScanWindow(null);
WidgetsBinding.instance.removeObserver(this);
_barcodesSubscription?.cancel();
_barcodesSubscription = null;
_controller.dispose();
super.dispose();
}
... ...
... ... @@ -20,20 +20,7 @@ class MobileScannerController {
@Deprecated('Instead, use the result of calling `start()` to determine if permissions were granted.')
this.onPermissionSet,
this.autoStart = true,
}) {
// In case a new instance is created before calling dispose()
if (controllerHashcode != null) {
stop();
}
controllerHashcode = hashCode;
events = _eventChannel
.receiveBroadcastStream()
.listen((data) => _handleEvent(data as Map));
}
/// The hashcode of the controller to check if the correct object is mounted.
/// Must be static to keep the same value on new instances
static int? controllerHashcode;
});
/// Select which camera should be used.
///
... ... @@ -84,7 +71,7 @@ class MobileScannerController {
Function(bool permissionGranted)? onPermissionSet;
/// Listen to events from the platform specific code
late StreamSubscription events;
StreamSubscription? events;
/// A notifier that provides several arguments about the MobileScanner
final ValueNotifier<MobileScannerArguments?> startArguments =
... ... @@ -164,6 +151,11 @@ class MobileScannerController {
isStarting = true;
events?.cancel();
events = _eventChannel
.receiveBroadcastStream()
.listen((data) => _handleEvent(data as Map));
// Check authorization status
if (!kIsWeb) {
final MobileScannerState state = MobileScannerState
... ... @@ -327,11 +319,8 @@ class MobileScannerController {
/// If you call this, you cannot use this controller object anymore.
void dispose() {
stop();
events.cancel();
events?.cancel();
_barcodesController.close();
if (hashCode == controllerHashcode) {
controllerHashcode = null;
}
}
/// Handles a returning event from the platform side
... ... @@ -394,9 +383,13 @@ class MobileScannerController {
}
}
/// updates the native scanwindow
Future<void> updateScanWindow(Rect window) async {
final data = [window.left, window.top, window.right, window.bottom];
/// updates the native ScanWindow
Future<void> updateScanWindow(Rect? window) async {
List? data;
if (window != null) {
data = [window.left, window.top, window.right, window.bottom];
}
await _methodChannel.invokeMethod('updateScanWindow', {'rect': data});
}
}
... ...