Skip to content

Commit d4d52ad

Browse files
Merge pull request #1235 from navaronbracke/bump_android_barcode_scanning
feat: bump android dependency & clean up scanner widgets
2 parents b7d6599 + d9c2d1e commit d4d52ad

30 files changed

+373
-226
lines changed

.github/workflows/flutter.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
- uses: subosito/flutter-action@v2.12.0
3737
with:
3838
cache: true
39-
flutter-version: '3.22'
39+
flutter-version: '3.24'
4040
channel: 'stable'
4141
- name: Version
4242
run: flutter doctor -v

CHANGELOG.md

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,51 @@
11
## NEXT
2-
- Fixed an issue which caused the scanWindow to always be present if provided, even when scanWindow is updated to null
3-
- Integrated basic barcode overlay and scanner overlay into the package.
4-
- Made updateScanWindow private, because logic within the MobileScanner widget is needed in order to pass a correct scanWindow.
5-
The scanWindow can be updated by directly changing the scanWindow in the MobileScanner widget.
2+
3+
**BREAKING CHANGES:**
4+
5+
* The `updateScanWindow` method is now private. Instead, update the scan window in the `MobileScanner` widget directly.
6+
* The deprecated `EncryptionType.none` constant has been removed. Use `EncryptionType.unknown` instead.
7+
8+
Bugs fixed:
9+
* [Apple] Fixed an issue which caused the scanWindow to always be present, even when reset to no value.
10+
* [Apple] Fixed an issue that caused the barcode size to report the wrong height.
11+
* [Apple] Fixed a bug that caused the corner points to not be returned in clockwise orientation.
12+
13+
Improvements:
14+
* Added a basic barcode overlay widget, for use with the camera preview.
15+
* Added a basic scan window overlay widget, for use with the camera preview.
16+
* Update the bundled MLKit model for Android to version `17.3.0`.
17+
* Added documentation in places where it was missing.
18+
* Added `color` and `style` properties to the `BarcodePainter` widget.
619

720
## 7.0.0-beta.3
8-
Fix build issues on macOS
21+
22+
* Fixed a build issue on macOS.
923

1024
## 7.0.0-beta.2
1125

26+
Bugs fixed:
27+
* [Apple] Fixed an issue with the zoom slider being non-functional.
28+
* [Apple] Fixed an issue where the flash would briefly show when the camera is turned on.
29+
* [Apple] Fixed an issue that prevented the scan window from working.
30+
* [Apple] Fixed an issue that caused the barcode overlay to use the wrong dimensions.
31+
1232
Improvements:
1333
* [iOS] Adds support for Swift Package Manager.
14-
* [Apple] Fixes zoom slider
15-
* Fixed torch at start not working
16-
* Fixed scanWindow not being correct
17-
* Fixed barcode overlay not being correct
1834

1935
Known issues:
20-
* BoxFit.cover & BoxFit.fitHeight produces wrong width in barcodeOverlay
36+
* BoxFit.cover & BoxFit.fitHeight produce the wrong width in the barcode overlay.
2137

2238
## 7.0.0-beta.1
2339

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

27-
There are still some problems with this build.
28-
* Zoom slider not working
29-
* scanWindow not working
30-
* Flash shows briefly when starting scanner.
31-
* Other issues, not fully tested yet.
45+
Known issues:
46+
* [Apple] The zoom slider does not work correctly.
47+
* [Apple] The scan window does not work correctly.
48+
* [Apple] The camera flash briefly shows when the camera is started.
3249

3350
## 6.0.2
3451

analysis_options.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ include: package:lint/analysis_options_package.yaml
33
linter:
44
rules:
55
- combinators_ordering
6+
- comment_references
67
- require_trailing_commas
78
- unnecessary_library_directive
8-
- prefer_single_quotes
9+
- prefer_single_quotes
10+
- public_member_api_docs

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ dependencies {
7070
implementation 'com.google.android.gms:play-services-mlkit-barcode-scanning:18.3.1'
7171
} else {
7272
// Bundled model in app
73-
implementation 'com.google.mlkit:barcode-scanning:17.2.0'
73+
implementation 'com.google.mlkit:barcode-scanning:17.3.0'
7474
}
7575

7676
// org.jetbrains.kotlin:kotlin-bom artifact purpose is to align kotlin stdlib and related code versions.

darwin/mobile_scanner/Sources/mobile_scanner/MobileScannerPlugin.swift

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,11 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
177177
})
178178

179179
DispatchQueue.main.async {
180+
// If the image is nil, use zero as the size.
180181
guard let image = cgImage else {
181-
// Image not known, default image size to 1
182182
self?.sink?([
183183
"name": "barcode",
184-
"data": barcodes.map({ $0.toMap(width: 1, height: 1) }),
184+
"data": barcodes.map({ $0.toMap(imageWidth: 0, imageHeight: 0) }),
185185
])
186186
return
187187
}
@@ -194,10 +194,9 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
194194
"height": Double(image.height),
195195
]
196196

197-
198197
self?.sink?([
199198
"name": "barcode",
200-
"data": barcodes.map({ $0.toMap(width: image.width, height: image.height) }),
199+
"data": barcodes.map({ $0.toMap(imageWidth: image.width, imageHeight: image.height) }),
201200
"image": imageData,
202201
])
203202
}
@@ -473,7 +472,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
473472
device.torchMode = .on
474473
device.unlockForConfiguration()
475474
} catch(_) {
476-
475+
// Do nothing.
477476
}
478477
}
479478

@@ -526,7 +525,6 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
526525

527526
/// Set the zoom factor of the camera
528527
func setScaleInternal(_ scale: CGFloat) throws {
529-
530528
if (device == nil) {
531529
throw MobileScannerError.zoomWhenStopped
532530
}
@@ -545,10 +543,8 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
545543
actualScale = min(maxZoomFactor, actualScale)
546544

547545
// Limit to 1.0 scale
548-
549546
device.videoZoomFactor = actualScale
550547

551-
552548
device.unlockForConfiguration()
553549
#endif
554550
} catch {
@@ -620,7 +616,9 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
620616
try device.lockForConfiguration()
621617
device.torchMode = newTorchMode
622618
device.unlockForConfiguration()
623-
} catch(_) {}
619+
} catch(_) {
620+
// Do nothing.
621+
}
624622

625623
result(nil)
626624
}
@@ -690,7 +688,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
690688

691689
result([
692690
"name": "barcode",
693-
"data": barcodes.map({ $0.toMap(width: 1, height: 1) }),
691+
"data": barcodes.map({ $0.toMap(imageWidth: Int(ciImage.extent.width), imageHeight: Int(ciImage.extent.height)) }),
694692
])
695693
})
696694

@@ -803,28 +801,32 @@ extension VNBarcodeObservation {
803801
return sqrt(pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2))
804802
}
805803

806-
public func toMap(width: Int, height: Int) -> [String: Any?] {
807-
let topLeftX = topLeft.x * CGFloat(width)
808-
let topRightX = topRight.x * CGFloat(width)
809-
let bottomRightX = bottomRight.x * CGFloat(width)
810-
let bottomLeftX = bottomLeft.x * CGFloat(width)
811-
let topLeftY = (1 - topLeft.y) * CGFloat(height)
812-
let topRightY = (1 - topRight.y) * CGFloat(height)
813-
let bottomRightY = (1 - bottomRight.y) * CGFloat(height)
814-
let bottomLeftY = (1 - bottomLeft.y) * CGFloat(height)
804+
/// Map this `VNBarcodeObservation` to a dictionary.
805+
///
806+
/// The `imageWidth` and `imageHeight` indicate the width and height of the input image that contains this observation.
807+
public func toMap(imageWidth: Int, imageHeight: Int) -> [String: Any?] {
808+
let topLeftX = topLeft.x * CGFloat(imageWidth)
809+
let topRightX = topRight.x * CGFloat(imageWidth)
810+
let bottomRightX = bottomRight.x * CGFloat(imageWidth)
811+
let bottomLeftX = bottomLeft.x * CGFloat(imageWidth)
812+
let topLeftY = (1 - topLeft.y) * CGFloat(imageHeight)
813+
let topRightY = (1 - topRight.y) * CGFloat(imageHeight)
814+
let bottomRightY = (1 - bottomRight.y) * CGFloat(imageHeight)
815+
let bottomLeftY = (1 - bottomLeft.y) * CGFloat(imageHeight)
815816
let data = [
817+
// Clockwise, starting from the top-left corner.
816818
"corners": [
817-
["x": bottomLeftX, "y": bottomLeftY],
818819
["x": topLeftX, "y": topLeftY],
819820
["x": topRightX, "y": topRightY],
820821
["x": bottomRightX, "y": bottomRightY],
822+
["x": bottomLeftX, "y": bottomLeftY],
821823
],
822824
"format": symbology.toInt ?? -1,
823825
"rawValue": payloadStringValue ?? "",
824826
"displayValue": payloadStringValue ?? "",
825827
"size": [
826-
"width": distanceBetween(topLeft, topRight) * CGFloat(width),
827-
"height": distanceBetween(topLeft, bottomLeft) * CGFloat(width),
828+
"width": distanceBetween(topLeft, topRight) * CGFloat(imageWidth),
829+
"height": distanceBetween(topLeft, bottomLeft) * CGFloat(imageHeight),
828830
],
829831
] as [String : Any]
830832
return data

example/lib/barcode_scanner_controller.dart

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ class _BarcodeScannerWithControllerState
2121
torchEnabled: true,
2222
);
2323

24-
StreamSubscription<Object?>? _subscription;
25-
2624
@override
2725
void initState() {
2826
super.initState();
@@ -44,8 +42,6 @@ class _BarcodeScannerWithControllerState
4442
case AppLifecycleState.resumed:
4543
unawaited(controller.start());
4644
case AppLifecycleState.inactive:
47-
unawaited(_subscription?.cancel());
48-
_subscription = null;
4945
unawaited(controller.stop());
5046
}
5147
}
@@ -96,8 +92,6 @@ class _BarcodeScannerWithControllerState
9692
@override
9793
Future<void> dispose() async {
9894
WidgetsBinding.instance.removeObserver(this);
99-
unawaited(_subscription?.cancel());
100-
_subscription = null;
10195
super.dispose();
10296
await controller.dispose();
10397
}

example/lib/barcode_scanner_window.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class _BarcodeScannerWithScanWindowState
4444
},
4545
),
4646
BarcodeOverlay(controller: controller, boxFit: boxFit),
47-
ScannerOverlay(
47+
ScanWindowOverlay(
4848
scanWindow: scanWindow,
4949
controller: controller,
5050
),

example/lib/mobile_scanner_overlay.dart

Lines changed: 5 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,14 @@ class _BarcodeScannerWithOverlayState extends State<BarcodeScannerWithOverlay> {
5757
builder: (context, value, child) {
5858
if (!value.isInitialized ||
5959
!value.isRunning ||
60-
value.error != null) {
60+
value.error != null ||
61+
scanWindow.isEmpty) {
6162
return const SizedBox();
6263
}
6364

64-
return CustomPaint(
65-
painter: ScannerOverlay(scanWindow: scanWindow),
65+
return ScanWindowOverlay(
66+
controller: controller,
67+
scanWindow: scanWindow,
6668
);
6769
},
6870
),
@@ -90,67 +92,3 @@ class _BarcodeScannerWithOverlayState extends State<BarcodeScannerWithOverlay> {
9092
await controller.dispose();
9193
}
9294
}
93-
94-
class ScannerOverlay extends CustomPainter {
95-
const ScannerOverlay({
96-
required this.scanWindow,
97-
this.borderRadius = 12.0,
98-
});
99-
100-
final Rect scanWindow;
101-
final double borderRadius;
102-
103-
@override
104-
void paint(Canvas canvas, Size size) {
105-
// TODO: use `Offset.zero & size` instead of Rect.largest
106-
// we need to pass the size to the custom paint widget
107-
final backgroundPath = Path()..addRect(Rect.largest);
108-
109-
final cutoutPath = Path()
110-
..addRRect(
111-
RRect.fromRectAndCorners(
112-
scanWindow,
113-
topLeft: Radius.circular(borderRadius),
114-
topRight: Radius.circular(borderRadius),
115-
bottomLeft: Radius.circular(borderRadius),
116-
bottomRight: Radius.circular(borderRadius),
117-
),
118-
);
119-
120-
final backgroundPaint = Paint()
121-
..color = Colors.black.withOpacity(0.5)
122-
..style = PaintingStyle.fill
123-
..blendMode = BlendMode.dstOut;
124-
125-
final backgroundWithCutout = Path.combine(
126-
PathOperation.difference,
127-
backgroundPath,
128-
cutoutPath,
129-
);
130-
131-
final borderPaint = Paint()
132-
..color = Colors.white
133-
..style = PaintingStyle.stroke
134-
..strokeWidth = 4.0;
135-
136-
final borderRect = RRect.fromRectAndCorners(
137-
scanWindow,
138-
topLeft: Radius.circular(borderRadius),
139-
topRight: Radius.circular(borderRadius),
140-
bottomLeft: Radius.circular(borderRadius),
141-
bottomRight: Radius.circular(borderRadius),
142-
);
143-
144-
// First, draw the background,
145-
// with a cutout area that is a bit larger than the scan window.
146-
// Finally, draw the scan window itself.
147-
canvas.drawPath(backgroundWithCutout, backgroundPaint);
148-
canvas.drawRRect(borderRect, borderPaint);
149-
}
150-
151-
@override
152-
bool shouldRepaint(ScannerOverlay oldDelegate) {
153-
return scanWindow != oldDelegate.scanWindow ||
154-
borderRadius != oldDelegate.borderRadius;
155-
}
156-
}

lib/mobile_scanner.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ export 'src/objects/url_bookmark.dart';
2929
export 'src/objects/wifi.dart';
3030
export 'src/overlay/barcode_overlay.dart';
3131
export 'src/overlay/barcode_painter.dart';
32-
export 'src/overlay/scanner_overlay.dart';
33-
export 'src/overlay/scanner_painter.dart';
32+
export 'src/overlay/scan_window_overlay.dart';
33+
export 'src/overlay/scan_window_painter.dart';

lib/src/enums/encryption_type.dart

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,6 @@ enum EncryptionType {
1414

1515
const EncryptionType(this.rawValue);
1616

17-
@Deprecated(
18-
'EncryptionType.none is deprecated. Use EncryptionType.unknown instead.',
19-
)
20-
static const EncryptionType none = EncryptionType.unknown;
21-
2217
factory EncryptionType.fromRawValue(int value) {
2318
switch (value) {
2419
case 0:

0 commit comments

Comments
 (0)