@@ -18,8 +18,7 @@ class AiBarcodeScanner extends StatefulWidget {
1818 /// You can use your own custom overlay builder
1919 /// to build your own overlay
2020 /// This will override the default custom overlay
21- final Widget ? Function (BuildContext , bool ? , MobileScannerController )?
22- customOverlayBuilder;
21+ final Widget ? Function (BuildContext , bool ? , MobileScannerController )? customOverlayBuilder;
2322
2423 /// Overlay border color (default: white)
2524 final Color ? borderColor;
@@ -65,8 +64,7 @@ class AiBarcodeScanner extends StatefulWidget {
6564 ///
6665 /// If this is null, defaults to a black [ColoredBox]
6766 /// with a centered white [Icons.error] icon.
68- final Widget Function (BuildContext , MobileScannerException , Widget ? )?
69- errorBuilder;
67+ final Widget Function (BuildContext , MobileScannerException , Widget ? )? errorBuilder;
7068
7169 /// The function that builds a placeholder widget when the scanner
7270 /// is not yet displaying its camera preview.
@@ -79,87 +77,19 @@ class AiBarcodeScanner extends StatefulWidget {
7977
8078 /// AppBar widget
8179 /// you can use this to add appBar to the scanner screen
82- ///
83- final PreferredSizeWidget ? Function (
84- BuildContext context, MobileScannerController controller)? appBarBuilder;
80+ final PreferredSizeWidget ? Function (BuildContext context, MobileScannerController controller)? appBarBuilder;
8581
8682 /// The builder for the bottom sheet.
8783 /// This is displayed below the camera preview.
88- final Widget ? Function (
89- BuildContext context, MobileScannerController controller)?
90- bottomSheetBuilder;
84+ final Widget ? Function (BuildContext context, MobileScannerController controller)? bottomSheetBuilder;
9185
9286 /// The builder for the overlay above the camera preview.
93- ///
94- /// The resulting widget can be combined with the [scanWindow] rectangle
95- /// to create a cutout for the camera preview.
96- ///
97- /// The [BoxConstraints] for this builder
98- /// are the same constraints that are used to compute the effective [scanWindow] .
99- ///
100- /// The overlay is only displayed when the camera preview is visible.
10187 final LayoutWidgetBuilder ? overlayBuilder;
10288
10389 /// The scan window rectangle for the barcode scanner.
104- ///
105- /// If this is not null, the barcode scanner will only scan barcodes
106- /// which intersect this rectangle.
107- ///
108- /// This rectangle is relative to the layout size
109- /// of the *camera preview widget* in the widget tree,
110- /// rather than the actual size of the camera preview output.
111- /// This is because the size of the camera preview widget
112- /// might not be the same as the size of the camera output.
113- ///
114- /// For example, the applied [fit] has an effect on the size of the camera preview widget,
115- /// while the camera preview size remains the same.
116- ///
117- /// The following example shows a scan window that is centered,
118- /// fills half the height and one third of the width of the layout:
119- ///
120- /// ```dart
121- /// LayoutBuider(
122- /// builder: (BuildContext context, BoxConstraints constraints) {
123- /// final Size layoutSize = constraints.biggest;
124- ///
125- /// final double scanWindowWidth = layoutSize.width / 3;
126- /// final double scanWindowHeight = layoutSize.height / 2;
127- ///
128- /// final Rect scanWindow = Rect.fromCenter(
129- /// center: layoutSize.center(Offset.zero),
130- /// width: scanWindowWidth,
131- /// height: scanWindowHeight,
132- /// );
133- /// }
134- /// );
135- /// ```
13690 final Rect ? scanWindow;
13791
13892 /// The threshold for updates to the [scanWindow] .
139- ///
140- /// If the [scanWindow] would be updated,
141- /// due to new layout constraints for the scanner,
142- /// and the width or height of the new scan window have not changed by this threshold,
143- /// then the scan window is not updated.
144- ///
145- /// It is recommended to set this threshold
146- /// if scan window updates cause performance issues.
147- ///
148- /// Defaults to no threshold for scan window updates.
149- ///
150- final void Function (BarcodeCapture )? onDetect;
151-
152- /// The threshold for updates to the [scanWindow] .
153- ///
154- /// If the [scanWindow] would be updated,
155- /// due to new layout constraints for the scanner,
156- /// and the width or height of the new scan window have not changed by this threshold,
157- /// then the scan window is not updated.
158- ///
159- /// It is recommended to set this threshold
160- /// if scan window updates cause performance issues.
161- ///
162- /// Defaults to no threshold for scan window updates.
16393 final double scanWindowUpdateThreshold;
16494
16595 /// Validator function to check if barcode is valid or not
@@ -191,15 +121,16 @@ class AiBarcodeScanner extends StatefulWidget {
191121 final bool extendBodyBehindAppBar;
192122
193123 /// Upload from gallery button alignment
194- /// default: bottom center, center, 0.75
195124 final AlignmentGeometry ? galleryButtonAlignment;
196125
197126 /// actions for the app bar (optional)
198127 /// Camera switch and torch toggle buttons are added by default
199128 /// You can add more actions to the app bar using this parameter
200129 final List <Widget >? actions;
201130
131+ /// Lock orientation to portrait (default: true)
202132 final bool setPortraitOrientation;
133+
203134 const AiBarcodeScanner ({
204135 super .key,
205136 this .fit = BoxFit .cover,
@@ -232,12 +163,12 @@ class AiBarcodeScanner extends StatefulWidget {
232163 this .sheetChild = const SizedBox .shrink (),
233164 this .hideSheetDragHandler = false ,
234165 this .hideSheetTitle = false ,
235- this .galleryButtonAlignment,
236- this .actions,
237166 this .hideGalleryButton = false ,
238167 this .hideGalleryIcon = true ,
239168 this .bottomSheetBuilder,
240169 this .extendBodyBehindAppBar = true ,
170+ this .galleryButtonAlignment,
171+ this .actions,
241172 this .setPortraitOrientation = true ,
242173 });
243174
@@ -246,37 +177,37 @@ class AiBarcodeScanner extends StatefulWidget {
246177}
247178
248179class _AiBarcodeScannerState extends State <AiBarcodeScanner > {
249- /// bool to check if barcode is valid or not
250180 final ValueNotifier <bool ?> _isSuccess = ValueNotifier <bool ?>(null );
251-
252- /// Scanner controller
253181 late MobileScannerController controller;
254-
255182 double _cutOutBottomOffset = 0 ;
256183
257184 @override
258185 void initState () {
186+ if (widget.setPortraitOrientation) {
187+ SystemChrome .setPreferredOrientations ([
188+ DeviceOrientation .portraitUp,
189+ DeviceOrientation .portraitDown,
190+ ]);
191+ }
259192 controller = widget.controller ?? MobileScannerController ();
260193 _cutOutBottomOffset = widget.cutOutBottomOffset;
261194 super .initState ();
262195 }
263196
264197 @override
265198 void dispose () {
266- // controller.dispose();
267- // widget.controller?.dispose();
199+ if (widget.controller == null ) {
200+ controller.dispose ();
201+ }
268202 widget.onDispose? .call ();
203+ if (widget.setPortraitOrientation) {
204+ SystemChrome .setPreferredOrientations (DeviceOrientation .values);
205+ }
269206 super .dispose ();
270207 }
271208
272209 @override
273210 Widget build (BuildContext context) {
274- if (widget.setPortraitOrientation) {
275- SystemChrome .setPreferredOrientations ([
276- DeviceOrientation .portraitUp,
277- DeviceOrientation .portraitDown,
278- ]);
279- }
280211 return Scaffold (
281212 appBar: widget.appBarBuilder? .call (context, controller) ??
282213 AppBar (
@@ -286,17 +217,16 @@ class _AiBarcodeScannerState extends State<AiBarcodeScanner> {
286217 actions: [
287218 IconButton (
288219 icon: const Icon (Icons .cameraswitch_rounded),
289- onPressed: controller.switchCamera,
220+ onPressed: () => controller.switchCamera () ,
290221 ),
291-
292222 IconButton (
293223 icon: controller.value.torchState == TorchState .on
294224 ? const Icon (Icons .flashlight_off_rounded)
295225 : const Icon (Icons .flashlight_on_rounded),
296- onPressed: (){
226+ onPressed: () {
297227 controller.toggleTorch ();
298228 setState (() {});
299- }
229+ },
300230 ),
301231 if (! widget.hideGalleryIcon)
302232 GalleryButton .icon (
@@ -323,8 +253,7 @@ class _AiBarcodeScannerState extends State<AiBarcodeScanner> {
323253 onDetect: onDetect,
324254 controller: controller,
325255 fit: widget.fit,
326- errorBuilder:
327- widget.errorBuilder ?? (_, error, ___) => const ErrorBuilder (),
256+ errorBuilder: widget.errorBuilder ?? (_, __, ___) => const ErrorBuilder (),
328257 placeholderBuilder: widget.placeholderBuilder,
329258 scanWindow: widget.scanWindow,
330259 key: widget.key,
@@ -334,30 +263,27 @@ class _AiBarcodeScannerState extends State<AiBarcodeScanner> {
334263 ValueListenableBuilder <bool ?>(
335264 valueListenable: _isSuccess,
336265 builder: (context, isSuccess, __) {
337- return widget.customOverlayBuilder
338- ? .call (context, isSuccess, controller) ??
266+ return widget.customOverlayBuilder? .call (context, isSuccess, controller) ??
339267 Container (
340268 decoration: ShapeDecoration (
341269 shape: OverlayShape (
342270 borderRadius: widget.borderRadius,
343- borderColor:
344- ((isSuccess ?? false ) && widget.showSuccess)
345- ? widget.successColor
346- : (! (isSuccess ?? true ) && widget.showError)
347- ? widget.errorColor
348- : widget.borderColor ?? Colors .white,
271+ borderColor: ((isSuccess ?? false ) && widget.showSuccess)
272+ ? widget.successColor
273+ : (! (isSuccess ?? true ) && widget.showError)
274+ ? widget.errorColor
275+ : widget.borderColor ?? Colors .white,
349276 borderLength: widget.borderLength,
350277 borderWidth: widget.borderWidth,
351278 cutOutSize: widget.cutOutSize,
352279 cutOutBottomOffset: _cutOutBottomOffset,
353280 cutOutWidth: widget.cutOutWidth,
354281 cutOutHeight: widget.cutOutHeight,
355- overlayColor:
356- ((isSuccess ?? false ) && widget.showSuccess)
357- ? widget.successColor.withOpacity (0.4 )
358- : (! (isSuccess ?? true ) && widget.showError)
359- ? widget.errorColor.withOpacity (0.4 )
360- : widget.overlayColor,
282+ overlayColor: ((isSuccess ?? false ) && widget.showSuccess)
283+ ? widget.successColor.withOpacity (0.4 )
284+ : (! (isSuccess ?? true ) && widget.showError)
285+ ? widget.errorColor.withOpacity (0.4 )
286+ : widget.overlayColor,
361287 ),
362288 ),
363289 );
@@ -366,11 +292,7 @@ class _AiBarcodeScannerState extends State<AiBarcodeScanner> {
366292 if (! widget.hideGalleryButton)
367293 Align (
368294 alignment: widget.galleryButtonAlignment ??
369- Alignment .lerp (
370- Alignment .bottomCenter,
371- Alignment .center,
372- 0.75 ,
373- )! ,
295+ Alignment .lerp (Alignment .bottomCenter, Alignment .center, 0.75 )! ,
374296 child: GalleryButton (
375297 onImagePick: widget.onImagePick,
376298 onDetect: widget.onDetect,
@@ -388,11 +310,12 @@ class _AiBarcodeScannerState extends State<AiBarcodeScanner> {
388310 widget.onDetect? .call (barcodes);
389311 if (widget.validator != null ) {
390312 final isValid = widget.validator !(barcodes);
313+ _isSuccess.value = isValid;
391314 if (! isValid) {
392315 HapticFeedback .heavyImpact ();
316+ } else {
317+ HapticFeedback .mediumImpact ();
393318 }
394- HapticFeedback .mediumImpact ();
395- _isSuccess.value = isValid;
396319 }
397320 }
398321}
0 commit comments