Julian Steenbakker

refactor: revert autoStart and onDetect. See changelog for more

## 5.1.0
This updates reverts a few breaking changes made in v5.0.0 in order to keep things simple.
* The `onDetect` method has been reinstated in the `MobileScanner` widget, but is nullable. You can
still listen to `MobileScannerController.barcodes` directly by passing null to this parameter.
* The `autoStart` attribute has been reinstated in the `MobileScannerController` and defaults to true. However, if you want
to control which camera is used on start, or you want to manage the lifecycle yourself, you should set
autoStart to false and manually call `MobileScannerController.start({CameraFacing? cameraDirection})`.
* The `controller` is no longer required in the `MobileScanner` widget. However if provided, the user should take care
of disposing it.
* [Android] Revert Gradle 8 back to Gradle 7, to be inline with most Flutter plugins and prevent build issues.
* [Android] Revert Kotlin back from 1.9 to 1.7 to be inline with most Flutter plugins. Special 1.9 functionality
has been refactored to be compatible with 1.7.
## 5.0.2
Bugs fixed:
... ...
... ... @@ -7,6 +7,10 @@
A universal scanner for Flutter based on MLKit. Uses CameraX on Android and AVFoundation on iOS.
## Breaking Changes V5.0.0
Version 5.0.0 brings some breaking changes. Please see the changelog for an overview.
## Features Supported
See the example app for detailed implementation information.
... ...
... ... @@ -13,7 +13,8 @@ class BarcodeScannerPageView extends StatefulWidget {
}
class _BarcodeScannerPageViewState extends State<BarcodeScannerPageView> {
final MobileScannerController controller = MobileScannerController();
final MobileScannerController controller =
MobileScannerController(autoStart: false);
final PageController pageController = PageController();
... ...
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:mobile_scanner_example/scanner_button_widgets.dart';
import 'package:mobile_scanner_example/scanner_error_widget.dart';
class BarcodeScannerSimple extends StatefulWidget {
const BarcodeScannerSimple({super.key});
@override
State<BarcodeScannerSimple> createState() => _BarcodeScannerSimpleState();
}
class _BarcodeScannerSimpleState extends State<BarcodeScannerSimple> {
Barcode? _barcode;
Widget _buildBarcode(Barcode? value) {
if (value == null) {
return const Text(
'Scan something!',
overflow: TextOverflow.fade,
style: TextStyle(color: Colors.white),
);
}
return Text(
value.displayValue ?? 'No display value.',
overflow: TextOverflow.fade,
style: const TextStyle(color: Colors.white),
);
}
void _handleBarcode(BarcodeCapture barcodes) {
if (mounted) {
setState(() {
_barcode = barcodes.barcodes.firstOrNull;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Simple scanner')),
backgroundColor: Colors.black,
body: Stack(
children: [
MobileScanner(
onDetect: _handleBarcode,
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
alignment: Alignment.bottomCenter,
height: 100,
color: Colors.black.withOpacity(0.4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(child: Center(child: _buildBarcode(_barcode))),
],
),
),
),
],
),
);
}
}
... ...
... ... @@ -3,6 +3,7 @@ import 'package:mobile_scanner_example/barcode_scanner_controller.dart';
import 'package:mobile_scanner_example/barcode_scanner_listview.dart';
import 'package:mobile_scanner_example/barcode_scanner_pageview.dart';
import 'package:mobile_scanner_example/barcode_scanner_returning_image.dart';
import 'package:mobile_scanner_example/barcode_scanner_simple.dart';
import 'package:mobile_scanner_example/barcode_scanner_window.dart';
import 'package:mobile_scanner_example/barcode_scanner_zoom.dart';
import 'package:mobile_scanner_example/mobile_scanner_overlay.dart';
... ... @@ -31,6 +32,16 @@ class MyHome extends StatelessWidget {
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const BarcodeScannerSimple(),
),
);
},
child: const Text('MobileScanner Simple'),
),
ElevatedButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const BarcodeScannerListView(),
),
);
... ...
... ... @@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:mobile_scanner/src/mobile_scanner_controller.dart';
import 'package:mobile_scanner/src/mobile_scanner_exception.dart';
import 'package:mobile_scanner/src/mobile_scanner_platform_interface.dart';
import 'package:mobile_scanner/src/objects/barcode_capture.dart';
import 'package:mobile_scanner/src/objects/mobile_scanner_state.dart';
import 'package:mobile_scanner/src/scan_window_calculation.dart';
... ... @@ -18,7 +19,8 @@ typedef MobileScannerErrorBuilder = Widget Function(
class MobileScanner extends StatefulWidget {
/// Create a new [MobileScanner] using the provided [controller].
const MobileScanner({
required this.controller,
this.controller,
this.onDetect,
this.fit = BoxFit.cover,
this.errorBuilder,
this.overlayBuilder,
... ... @@ -29,7 +31,11 @@ class MobileScanner extends StatefulWidget {
});
/// The controller for the camera preview.
final MobileScannerController controller;
final MobileScannerController? controller;
/// The function that signals when new codes were detected by the [controller].
/// If null, use the contrller.barcodes stream directly to capture barcodes.
final void Function(BarcodeCapture barcodes)? onDetect;
/// The error builder for the camera preview.
///
... ... @@ -113,6 +119,7 @@ class MobileScanner extends StatefulWidget {
}
class _MobileScannerState extends State<MobileScanner> {
late final controller = widget.controller ?? MobileScannerController();
/// The current scan window.
Rect? scanWindow;
... ... @@ -139,7 +146,7 @@ class _MobileScannerState extends State<MobileScanner> {
if (scanWindow == null) {
scanWindow = newScanWindow;
unawaited(widget.controller.updateScanWindow(scanWindow));
unawaited(controller.updateScanWindow(scanWindow));
return;
}
... ... @@ -154,7 +161,7 @@ class _MobileScannerState extends State<MobileScanner> {
if (widget.scanWindowUpdateThreshold == 0.0) {
scanWindow = newScanWindow;
unawaited(widget.controller.updateScanWindow(scanWindow));
unawaited(controller.updateScanWindow(scanWindow));
return;
}
... ... @@ -167,14 +174,14 @@ class _MobileScannerState extends State<MobileScanner> {
dy >= widget.scanWindowUpdateThreshold) {
scanWindow = newScanWindow;
unawaited(widget.controller.updateScanWindow(scanWindow));
unawaited(controller.updateScanWindow(scanWindow));
}
}
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<MobileScannerState>(
valueListenable: widget.controller,
valueListenable: controller,
builder: (BuildContext context, MobileScannerState value, Widget? child) {
if (!value.isInitialized) {
const Widget defaultPlaceholder = ColoredBox(color: Colors.black);
... ... @@ -234,10 +241,36 @@ class _MobileScannerState extends State<MobileScanner> {
);
}
StreamSubscription? barcodeSubscription;
@override
void initState() {
if (widget.onDetect != null) {
barcodeSubscription = controller.barcodes.listen(widget.onDetect);
}
if (controller.autoStart) {
controller.start();
}
super.initState();
}
@override
void dispose() {
super.dispose();
if (barcodeSubscription != null) {
barcodeSubscription!.cancel();
barcodeSubscription = null;
}
if (controller.autoStart) {
controller.stop();
}
// When this widget is unmounted, reset the scan window.
unawaited(widget.controller.updateScanWindow(null));
unawaited(controller.updateScanWindow(null));
// Dispose default controller if not provided by user
if (widget.controller == null) {
controller.dispose();
}
}
}
... ...
... ... @@ -17,6 +17,7 @@ import 'package:mobile_scanner/src/objects/start_options.dart';
class MobileScannerController extends ValueNotifier<MobileScannerState> {
/// Construct a new [MobileScannerController] instance.
MobileScannerController({
this.autoStart = true,
this.cameraResolution,
this.detectionSpeed = DetectionSpeed.normal,
int detectionTimeoutMs = 250,
... ... @@ -47,6 +48,9 @@ class MobileScannerController extends ValueNotifier<MobileScannerState> {
/// Currently only supported on Android.
final Size? cameraResolution;
/// Automatically start the scanner on initialization.
final bool autoStart;
/// The detection speed for the scanner.
///
/// Defaults to [DetectionSpeed.normal].
... ...
name: mobile_scanner
description: A universal barcode and QR code scanner for Flutter based on MLKit. Uses CameraX on Android, AVFoundation on iOS and Apple Vision & AVFoundation on macOS.
version: 5.0.2
version: 5.1.0
repository: https://github.com/juliansteenbakker/mobile_scanner
screenshots:
... ...