Skip to content

Commit a32b160

Browse files
authored
Merge pull request #169 from sytzedewitte/feature/enabled-action-buttons
feat: Allow custom selection of action buttons
2 parents 46f02b9 + 4c6691c commit a32b160

File tree

2 files changed

+96
-49
lines changed

2 files changed

+96
-49
lines changed

example/lib/main.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,20 @@ class _HomePageState extends State<HomePage> {
160160
},
161161
),
162162
),
163+
_buildDemoButton(
164+
title: "Enabled Icons Only",
165+
subtitle: "Only show camera switch and torch.",
166+
scanner: AiBarcodeScanner(
167+
galleryButtonType: GalleryButtonType.icon,
168+
enabledActionButtons: const {
169+
ScannerAction.cameraSwitch,
170+
ScannerAction.torch,
171+
},
172+
onDetect: (BarcodeCapture capture) {
173+
/// Do something with the barcode
174+
},
175+
),
176+
),
163177
_buildDemoButton(
164178
title: "None Gallery Button",
165179
subtitle: "Shows no gallery button.",

lib/src/ai_barcode_scanner.dart

Lines changed: 82 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import 'error_builder.dart';
1111
import 'gallery_button.dart';
1212
import 'overlay.dart';
1313

14+
/// The set of quick action controls that can be shown alongside the scanner.
15+
enum ScannerAction { cameraSwitch, torch, gallery }
16+
1417
/// The main barcode scanner widget.
1518
class AiBarcodeScanner extends StatefulWidget {
1619
/// Defines how the camera preview will be fitted into the layout.
@@ -115,6 +118,9 @@ class AiBarcodeScanner extends StatefulWidget {
115118
/// Custom icon for the flashlight when off
116119
final IconData flashOffIcon;
117120

121+
/// Controls which quick action icons (camera switch, torch, gallery) are displayed.
122+
final Set<ScannerAction> enabledActionButtons;
123+
118124
/// Whether to return the raw image data (Uint8List) along with the BarcodeCapture.
119125
/// This can be useful for post-scan image processing such as color analysis or saving the frame.
120126
/// Defaults to `false`.
@@ -161,6 +167,11 @@ class AiBarcodeScanner extends StatefulWidget {
161167
this.cameraSwitchIcon = CupertinoIcons.arrow_2_circlepath,
162168
this.flashOnIcon = CupertinoIcons.bolt_fill,
163169
this.flashOffIcon = CupertinoIcons.bolt,
170+
this.enabledActionButtons = const {
171+
ScannerAction.gallery,
172+
ScannerAction.cameraSwitch,
173+
ScannerAction.torch,
174+
},
164175
this.returnImage = false,
165176
this.onCustomImagePicker,
166177
this.child,
@@ -261,49 +272,27 @@ class _AiBarcodeScannerState extends State<AiBarcodeScanner> {
261272

262273
/// default action icons
263274
/// camera switch and torch for easier access
264-
final actionIcons = [
265-
IconButton.filled(
266-
style: IconButton.styleFrom(
267-
backgroundColor: CupertinoColors.systemGrey6,
268-
foregroundColor: CupertinoColors.darkBackgroundGray,
269-
),
270-
icon: Icon(widget.cameraSwitchIcon),
271-
onPressed: () async {
272-
await _controller.switchCamera();
273-
setState(() {});
274-
},
275-
),
276-
IconButton.filled(
277-
style: IconButton.styleFrom(
278-
backgroundColor: isTorchOn
279-
? CupertinoColors.activeOrange
280-
: CupertinoColors.systemGrey6,
281-
foregroundColor: CupertinoColors.darkBackgroundGray,
282-
),
283-
icon: Icon(isTorchOn ? widget.flashOnIcon : widget.flashOffIcon),
284-
onPressed: () async {
285-
await _controller.toggleTorch();
286-
setState(() {});
287-
},
288-
)
289-
];
275+
final actionButtons = _buildActionButtons(isTorchOn);
276+
final showGalleryAction =
277+
widget.enabledActionButtons.contains(ScannerAction.gallery);
290278

291279
return Scaffold(
292280
appBar: widget.appBarBuilder?.call(context, _controller) ??
293281
AppBar(
294282
backgroundColor: Colors.transparent,
295283
actions: [
296284
if (widget.galleryButtonType == GalleryButtonType.icon) ...[
297-
GalleryButton.icon(
298-
onImagePick: widget.onImagePick,
299-
onDetect: widget.onDetect,
300-
validator: widget.validator,
301-
controller: _controller,
302-
isSuccess: _isSuccess,
303-
text: widget.galleryButtonText,
304-
onCustomImagePicker: widget.onCustomImagePicker,
305-
),
306-
...actionIcons,
285+
if (showGalleryAction)
286+
GalleryButton.icon(
287+
onImagePick: widget.onImagePick,
288+
onDetect: widget.onDetect,
289+
validator: widget.validator,
290+
controller: _controller,
291+
isSuccess: _isSuccess,
292+
text: widget.galleryButtonText,
293+
onCustomImagePicker: widget.onCustomImagePicker,
294+
),
295+
...actionButtons,
307296
],
308297
...?widget.actions,
309298
],
@@ -363,7 +352,8 @@ class _AiBarcodeScannerState extends State<AiBarcodeScanner> {
363352
useAppLifecycleState: widget.useAppLifecycleState,
364353
),
365354
widget.child ??
366-
(widget.galleryButtonType == GalleryButtonType.filled
355+
(widget.galleryButtonType == GalleryButtonType.filled &&
356+
(showGalleryAction || actionButtons.isNotEmpty)
367357
? Align(
368358
alignment: widget.galleryButtonAlignment ??
369359
Alignment.lerp(
@@ -375,18 +365,20 @@ class _AiBarcodeScannerState extends State<AiBarcodeScanner> {
375365
mainAxisAlignment: MainAxisAlignment.center,
376366
mainAxisSize: MainAxisSize.min,
377367
children: [
378-
GalleryButton(
379-
onImagePick: widget.onImagePick,
380-
onDetect: widget.onDetect,
381-
validator: widget.validator,
382-
controller: _controller,
383-
isSuccess: _isSuccess,
384-
text: widget.galleryButtonText,
385-
icon: widget.galleryIcon,
386-
onCustomImagePicker: widget.onCustomImagePicker,
387-
),
388-
const SizedBox(width: 4),
389-
...actionIcons,
368+
if (showGalleryAction)
369+
GalleryButton(
370+
onImagePick: widget.onImagePick,
371+
onDetect: widget.onDetect,
372+
validator: widget.validator,
373+
controller: _controller,
374+
isSuccess: _isSuccess,
375+
text: widget.galleryButtonText,
376+
icon: widget.galleryIcon,
377+
onCustomImagePicker: widget.onCustomImagePicker,
378+
),
379+
if (showGalleryAction && actionButtons.isNotEmpty)
380+
const SizedBox(width: 4),
381+
...actionButtons,
390382
],
391383
),
392384
)
@@ -433,4 +425,45 @@ class _AiBarcodeScannerState extends State<AiBarcodeScanner> {
433425
}
434426
});
435427
}
428+
429+
List<Widget> _buildActionButtons(bool isTorchOn) {
430+
final actions = widget.enabledActionButtons;
431+
final icons = <Widget>[];
432+
433+
if (actions.contains(ScannerAction.cameraSwitch)) {
434+
icons.add(
435+
IconButton.filled(
436+
style: IconButton.styleFrom(
437+
backgroundColor: CupertinoColors.systemGrey6,
438+
foregroundColor: CupertinoColors.darkBackgroundGray,
439+
),
440+
icon: Icon(widget.cameraSwitchIcon),
441+
onPressed: () async {
442+
await _controller.switchCamera();
443+
setState(() {});
444+
},
445+
),
446+
);
447+
}
448+
449+
if (actions.contains(ScannerAction.torch)) {
450+
icons.add(
451+
IconButton.filled(
452+
style: IconButton.styleFrom(
453+
backgroundColor: isTorchOn
454+
? CupertinoColors.activeOrange
455+
: CupertinoColors.systemGrey6,
456+
foregroundColor: CupertinoColors.darkBackgroundGray,
457+
),
458+
icon: Icon(isTorchOn ? widget.flashOnIcon : widget.flashOffIcon),
459+
onPressed: () async {
460+
await _controller.toggleTorch();
461+
setState(() {});
462+
},
463+
),
464+
);
465+
}
466+
467+
return icons;
468+
}
436469
}

0 commit comments

Comments
 (0)