Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: bump android dependency & clean up scanner widgets #1235

Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/flutter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
- uses: subosito/[email protected]
with:
cache: true
flutter-version: '3.22'
flutter-version: '3.24'
juliansteenbakker marked this conversation as resolved.
Show resolved Hide resolved
channel: 'stable'
- name: Version
run: flutter doctor -v
Expand Down
50 changes: 33 additions & 17 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,50 @@
## NEXT
- Fixed an issue which caused the scanWindow to always be present if provided, even when scanWindow is updated to null
juliansteenbakker marked this conversation as resolved.
Show resolved Hide resolved
- Integrated basic barcode overlay and scanner overlay into the package.
- Made updateScanWindow private, because logic within the MobileScanner widget is needed in order to pass a correct scanWindow.
The scanWindow can be updated by directly changing the scanWindow in the MobileScanner widget.

**BREAKING CHANGES:**

* The `updateScanWindow` method is now private. Instead, update the scan window in the `MobileScanner` widget directly.
juliansteenbakker marked this conversation as resolved.
Show resolved Hide resolved
* The deprecated `EncryptionType.none` constant has been removed. Use `EncryptionType.unknown` instead.

Bugs fixed:
juliansteenbakker marked this conversation as resolved.
Show resolved Hide resolved
* [Apple] Fixed an issue which caused the scanWindow to always be present, even when reset to no value.
* [Apple] Fixed an issue that caused the barcode size to report the wrong height.

Improvements:
* Added a basic barcode overlay widget, for use with the camera preview.
* Added a basic scan window overlay widget, for use with the camera preview.
* Update the bundled MLKit model for Android to version `17.3.0`.
* Added documentation in places where it was missing.
* Added `color` and `style` properties to the `BarcodePainter` widget.

## 7.0.0-beta.3
Fix build issues on macOS

* Fixed a build issue on macOS.

## 7.0.0-beta.2

Bugs fixed:
* [Apple] Fixed an issue with the zoom slider being non-functional.
* [Apple] Fixed an issue where the flash would briefly show when the camera is turned on.
* [Apple] Fixed an issue that prevented the scan window from working.
* [Apple] Fixed an issue that caused the barcode overlay to use the wrong dimensions.

Improvements:
* [iOS] Adds support for Swift Package Manager.
* [Apple] Fixes zoom slider
* Fixed torch at start not working
* Fixed scanWindow not being correct
* Fixed barcode overlay not being correct

Known issues:
* BoxFit.cover & BoxFit.fitHeight produces wrong width in barcodeOverlay
* BoxFit.cover & BoxFit.fitHeight produce the wrong width in the barcode overlay.

## 7.0.0-beta.1

This version replaces MLKit on iOS with Apple's Vision API and merges the iOS and MacOS sources.
The requirement for the minimum iOS version has been relaxed back down to iOS 12.0.
Improvements:
* [iOS] Migrate to the Vision API.
* [iOS] Updated the minimum iOS version back down to 12.0.
* [Apple] Merged the iOS and MacOS sources.

There are still some problems with this build.
* Zoom slider not working
* scanWindow not working
* Flash shows briefly when starting scanner.
* Other issues, not fully tested yet.
Known issues:
* [Apple] The zoom slider does not work correctly.
* [Apple] The scan window does not work correctly.
* [Apple] The camera flash briefly shows when the camera is started.

## 6.0.2

Expand Down
4 changes: 3 additions & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ include: package:lint/analysis_options_package.yaml
linter:
rules:
- combinators_ordering
- comment_references
- require_trailing_commas
- unnecessary_library_directive
- prefer_single_quotes
- prefer_single_quotes
- public_member_api_docs
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ dependencies {
implementation 'com.google.android.gms:play-services-mlkit-barcode-scanning:18.3.1'
} else {
// Bundled model in app
implementation 'com.google.mlkit:barcode-scanning:17.2.0'
implementation 'com.google.mlkit:barcode-scanning:17.3.0'
}

// org.jetbrains.kotlin:kotlin-bom artifact purpose is to align kotlin stdlib and related code versions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,11 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
})

DispatchQueue.main.async {
// If the image is nil, use zero as the size.
guard let image = cgImage else {
// Image not known, default image size to 1
self?.sink?([
"name": "barcode",
"data": barcodes.map({ $0.toMap(width: 1, height: 1) }),
"data": barcodes.map({ $0.toMap(imageWidth: 0, imageHeight: 0) }),
juliansteenbakker marked this conversation as resolved.
Show resolved Hide resolved
])
return
}
Expand All @@ -194,10 +194,9 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
"height": Double(image.height),
]


self?.sink?([
"name": "barcode",
"data": barcodes.map({ $0.toMap(width: image.width, height: image.height) }),
"data": barcodes.map({ $0.toMap(imageWidth: image.width, imageHeight: image.height) }),
"image": imageData,
])
}
Expand Down Expand Up @@ -473,7 +472,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
device.torchMode = .on
device.unlockForConfiguration()
} catch(_) {

// Do nothing.
}
}

Expand Down Expand Up @@ -526,7 +525,6 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,

/// Set the zoom factor of the camera
func setScaleInternal(_ scale: CGFloat) throws {

if (device == nil) {
throw MobileScannerError.zoomWhenStopped
}
Expand All @@ -545,10 +543,8 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
actualScale = min(maxZoomFactor, actualScale)

// Limit to 1.0 scale

device.videoZoomFactor = actualScale


device.unlockForConfiguration()
#endif
} catch {
Expand Down Expand Up @@ -620,7 +616,9 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
try device.lockForConfiguration()
device.torchMode = newTorchMode
device.unlockForConfiguration()
} catch(_) {}
} catch(_) {
// Do nothing.
}

result(nil)
}
Expand Down Expand Up @@ -690,7 +688,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,

result([
"name": "barcode",
"data": barcodes.map({ $0.toMap(width: 1, height: 1) }),
"data": barcodes.map({ $0.toMap(imageWidth: Int(ciImage.extent.width), imageHeight: Int(ciImage.extent.height)) }),
juliansteenbakker marked this conversation as resolved.
Show resolved Hide resolved
])
})

Expand Down Expand Up @@ -803,15 +801,18 @@ extension VNBarcodeObservation {
return sqrt(pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2))
}

public func toMap(width: Int, height: Int) -> [String: Any?] {
let topLeftX = topLeft.x * CGFloat(width)
let topRightX = topRight.x * CGFloat(width)
let bottomRightX = bottomRight.x * CGFloat(width)
let bottomLeftX = bottomLeft.x * CGFloat(width)
let topLeftY = (1 - topLeft.y) * CGFloat(height)
let topRightY = (1 - topRight.y) * CGFloat(height)
let bottomRightY = (1 - bottomRight.y) * CGFloat(height)
let bottomLeftY = (1 - bottomLeft.y) * CGFloat(height)
/// Map this `VNBarcodeObservation` to a dictionary.
///
/// The `imageWidth` and `imageHeight` indicate the width and height of the input image that contains this observation.
public func toMap(imageWidth: Int, imageHeight: Int) -> [String: Any?] {
juliansteenbakker marked this conversation as resolved.
Show resolved Hide resolved
let topLeftX = topLeft.x * CGFloat(imageWidth)
let topRightX = topRight.x * CGFloat(imageWidth)
let bottomRightX = bottomRight.x * CGFloat(imageWidth)
let bottomLeftX = bottomLeft.x * CGFloat(imageWidth)
let topLeftY = (1 - topLeft.y) * CGFloat(imageHeight)
let topRightY = (1 - topRight.y) * CGFloat(imageHeight)
let bottomRightY = (1 - bottomRight.y) * CGFloat(imageHeight)
let bottomLeftY = (1 - bottomLeft.y) * CGFloat(imageHeight)
let data = [
"corners": [
["x": bottomLeftX, "y": bottomLeftY],
juliansteenbakker marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -823,8 +824,8 @@ extension VNBarcodeObservation {
"rawValue": payloadStringValue ?? "",
"displayValue": payloadStringValue ?? "",
"size": [
"width": distanceBetween(topLeft, topRight) * CGFloat(width),
"height": distanceBetween(topLeft, bottomLeft) * CGFloat(width),
"width": distanceBetween(topLeft, topRight) * CGFloat(imageWidth),
"height": distanceBetween(topLeft, bottomLeft) * CGFloat(imageHeight),
juliansteenbakker marked this conversation as resolved.
Show resolved Hide resolved
],
] as [String : Any]
return data
Expand Down
6 changes: 0 additions & 6 deletions example/lib/barcode_scanner_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ class _BarcodeScannerWithControllerState
torchEnabled: true,
);

StreamSubscription<Object?>? _subscription;
juliansteenbakker marked this conversation as resolved.
Show resolved Hide resolved

@override
void initState() {
super.initState();
Expand All @@ -44,8 +42,6 @@ class _BarcodeScannerWithControllerState
case AppLifecycleState.resumed:
unawaited(controller.start());
case AppLifecycleState.inactive:
unawaited(_subscription?.cancel());
_subscription = null;
unawaited(controller.stop());
}
}
Expand Down Expand Up @@ -96,8 +92,6 @@ class _BarcodeScannerWithControllerState
@override
Future<void> dispose() async {
WidgetsBinding.instance.removeObserver(this);
unawaited(_subscription?.cancel());
_subscription = null;
super.dispose();
await controller.dispose();
}
Expand Down
2 changes: 1 addition & 1 deletion example/lib/barcode_scanner_window.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class _BarcodeScannerWithScanWindowState
},
),
BarcodeOverlay(controller: controller, boxFit: boxFit),
ScannerOverlay(
ScanWindowOverlay(
scanWindow: scanWindow,
controller: controller,
),
Expand Down
72 changes: 5 additions & 67 deletions example/lib/mobile_scanner_overlay.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,14 @@ class _BarcodeScannerWithOverlayState extends State<BarcodeScannerWithOverlay> {
builder: (context, value, child) {
if (!value.isInitialized ||
!value.isRunning ||
value.error != null) {
value.error != null ||
scanWindow.isEmpty) {
return const SizedBox();
}

return CustomPaint(
painter: ScannerOverlay(scanWindow: scanWindow),
return ScanWindowOverlay(
controller: controller,
scanWindow: scanWindow,
);
},
),
Expand Down Expand Up @@ -90,67 +92,3 @@ class _BarcodeScannerWithOverlayState extends State<BarcodeScannerWithOverlay> {
await controller.dispose();
}
}

class ScannerOverlay extends CustomPainter {
juliansteenbakker marked this conversation as resolved.
Show resolved Hide resolved
const ScannerOverlay({
required this.scanWindow,
this.borderRadius = 12.0,
});

final Rect scanWindow;
final double borderRadius;

@override
void paint(Canvas canvas, Size size) {
// TODO: use `Offset.zero & size` instead of Rect.largest
// we need to pass the size to the custom paint widget
final backgroundPath = Path()..addRect(Rect.largest);

final cutoutPath = Path()
..addRRect(
RRect.fromRectAndCorners(
scanWindow,
topLeft: Radius.circular(borderRadius),
topRight: Radius.circular(borderRadius),
bottomLeft: Radius.circular(borderRadius),
bottomRight: Radius.circular(borderRadius),
),
);

final backgroundPaint = Paint()
..color = Colors.black.withOpacity(0.5)
..style = PaintingStyle.fill
..blendMode = BlendMode.dstOut;

final backgroundWithCutout = Path.combine(
PathOperation.difference,
backgroundPath,
cutoutPath,
);

final borderPaint = Paint()
..color = Colors.white
..style = PaintingStyle.stroke
..strokeWidth = 4.0;

final borderRect = RRect.fromRectAndCorners(
scanWindow,
topLeft: Radius.circular(borderRadius),
topRight: Radius.circular(borderRadius),
bottomLeft: Radius.circular(borderRadius),
bottomRight: Radius.circular(borderRadius),
);

// First, draw the background,
// with a cutout area that is a bit larger than the scan window.
// Finally, draw the scan window itself.
canvas.drawPath(backgroundWithCutout, backgroundPaint);
canvas.drawRRect(borderRect, borderPaint);
}

@override
bool shouldRepaint(ScannerOverlay oldDelegate) {
return scanWindow != oldDelegate.scanWindow ||
borderRadius != oldDelegate.borderRadius;
}
}
4 changes: 2 additions & 2 deletions lib/mobile_scanner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ export 'src/objects/url_bookmark.dart';
export 'src/objects/wifi.dart';
export 'src/overlay/barcode_overlay.dart';
export 'src/overlay/barcode_painter.dart';
export 'src/overlay/scanner_overlay.dart';
export 'src/overlay/scanner_painter.dart';
export 'src/overlay/scan_window_overlay.dart';
export 'src/overlay/scan_window_painter.dart';
5 changes: 0 additions & 5 deletions lib/src/enums/encryption_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ enum EncryptionType {

const EncryptionType(this.rawValue);

@Deprecated(
'EncryptionType.none is deprecated. Use EncryptionType.unknown instead.',
)
static const EncryptionType none = EncryptionType.unknown;
juliansteenbakker marked this conversation as resolved.
Show resolved Hide resolved

factory EncryptionType.fromRawValue(int value) {
switch (value) {
case 0:
Expand Down
1 change: 1 addition & 0 deletions lib/src/method_channel/mobile_scanner_method_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class MethodChannelMobileScanner extends MobileScannerPlatform {

Stream<Map<Object?, Object?>>? _eventsStream;

/// Get the event stream of barcode events that come from the [eventChannel].
Stream<Map<Object?, Object?>> get eventsStream {
_eventsStream ??=
eventChannel.receiveBroadcastStream().cast<Map<Object?, Object?>>();
Expand Down
3 changes: 3 additions & 0 deletions lib/src/mobile_scanner_controller.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/// @docImport 'package:mobile_scanner/src/mobile_scanner.dart';
juliansteenbakker marked this conversation as resolved.
Show resolved Hide resolved
library;

import 'dart:async';

import 'package:flutter/widgets.dart';
Expand Down
6 changes: 6 additions & 0 deletions lib/src/mobile_scanner_exception.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/// @docImport 'package:flutter/services.dart';
/// @docImport 'package:mobile_scanner/src/mobile_scanner_controller.dart';
library;

import 'package:mobile_scanner/src/enums/mobile_scanner_error_code.dart';

/// This class represents an exception thrown by the [MobileScannerController].
class MobileScannerException implements Exception {
/// Construct a new [MobileScannerException] instance.
const MobileScannerException({
required this.errorCode,
this.errorDetails,
Expand All @@ -24,6 +29,7 @@ class MobileScannerException implements Exception {

/// The raw error details for a [MobileScannerException].
class MobileScannerErrorDetails {
/// Construct a new [MobileScannerErrorDetails] instance.
const MobileScannerErrorDetails({
this.code,
this.details,
Expand Down
1 change: 1 addition & 0 deletions lib/src/mobile_scanner_view_attributes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:mobile_scanner/src/enums/torch_state.dart';

/// This class defines the attributes for the mobile scanner view.
class MobileScannerViewAttributes {
/// Construct a new [MobileScannerViewAttributes] instance.
const MobileScannerViewAttributes({
required this.currentTorchMode,
this.numberOfCameras,
Expand Down
Loading
Loading