Navaron Bracke

refactor a sample to use a list view instead

1 -import 'package:flutter/material.dart';  
2 -import 'package:image_picker/image_picker.dart';  
3 -import 'package:mobile_scanner/mobile_scanner.dart';  
4 -import 'package:mobile_scanner_example/scanner_error_widget.dart';  
5 -  
6 -class BarcodeListScannerWithController extends StatefulWidget {  
7 - const BarcodeListScannerWithController({super.key});  
8 -  
9 - @override  
10 - State<BarcodeListScannerWithController> createState() =>  
11 - _BarcodeListScannerWithControllerState();  
12 -}  
13 -  
14 -class _BarcodeListScannerWithControllerState  
15 - extends State<BarcodeListScannerWithController>  
16 - with SingleTickerProviderStateMixin {  
17 - BarcodeCapture? barcodeCapture;  
18 -  
19 - final MobileScannerController controller = MobileScannerController(  
20 - torchEnabled: true,  
21 - // formats: [BarcodeFormat.qrCode]  
22 - // facing: CameraFacing.front,  
23 - // detectionSpeed: DetectionSpeed.normal  
24 - // detectionTimeoutMs: 1000,  
25 - // returnImage: false,  
26 - );  
27 -  
28 - bool isStarted = true;  
29 -  
30 - void _startOrStop() {  
31 - try {  
32 - if (isStarted) {  
33 - controller.stop();  
34 - } else {  
35 - controller.start();  
36 - }  
37 - setState(() {  
38 - isStarted = !isStarted;  
39 - });  
40 - } on Exception catch (e) {  
41 - ScaffoldMessenger.of(context).showSnackBar(  
42 - SnackBar(  
43 - content: Text('Something went wrong! $e'),  
44 - backgroundColor: Colors.red,  
45 - ),  
46 - );  
47 - }  
48 - }  
49 -  
50 - @override  
51 - Widget build(BuildContext context) {  
52 - return Scaffold(  
53 - appBar: AppBar(title: const Text('With ValueListenableBuilder')),  
54 - backgroundColor: Colors.black,  
55 - body: Builder(  
56 - builder: (context) {  
57 - return Stack(  
58 - children: [  
59 - MobileScanner(  
60 - controller: controller,  
61 - errorBuilder: (context, error, child) {  
62 - return ScannerErrorWidget(error: error);  
63 - },  
64 - fit: BoxFit.contain,  
65 - onDetect: (barcodeCapture) {  
66 - setState(() {  
67 - this.barcodeCapture = barcodeCapture;  
68 - });  
69 - },  
70 - onScannerStarted: (arguments) {  
71 - // Do something with arguments.  
72 - },  
73 - ),  
74 - Align(  
75 - alignment: Alignment.bottomCenter,  
76 - child: Container(  
77 - alignment: Alignment.bottomCenter,  
78 - height: 100,  
79 - color: Colors.black.withOpacity(0.4),  
80 - child: Row(  
81 - mainAxisAlignment: MainAxisAlignment.spaceEvenly,  
82 - children: [  
83 - IconButton(  
84 - color: Colors.white,  
85 - icon: ValueListenableBuilder<TorchState>(  
86 - valueListenable: controller.torchState,  
87 - builder: (context, state, child) {  
88 - switch (state) {  
89 - case TorchState.off:  
90 - return const Icon(  
91 - Icons.flash_off,  
92 - color: Colors.grey,  
93 - );  
94 - case TorchState.on:  
95 - return const Icon(  
96 - Icons.flash_on,  
97 - color: Colors.yellow,  
98 - );  
99 - }  
100 - },  
101 - ),  
102 - iconSize: 32.0,  
103 - onPressed: () => controller.toggleTorch(),  
104 - ),  
105 - IconButton(  
106 - color: Colors.white,  
107 - icon: isStarted  
108 - ? const Icon(Icons.stop)  
109 - : const Icon(Icons.play_arrow),  
110 - iconSize: 32.0,  
111 - onPressed: _startOrStop,  
112 - ),  
113 - Center(  
114 - child: SizedBox(  
115 - width: MediaQuery.of(context).size.width - 200,  
116 - height: 50,  
117 - child: FittedBox(  
118 - child: Text(  
119 - '${barcodeCapture?.barcodes.map((e) => e.rawValue) ?? 'Scan something!'}',  
120 - overflow: TextOverflow.fade,  
121 - style: Theme.of(context)  
122 - .textTheme  
123 - .headlineMedium!  
124 - .copyWith(color: Colors.white),  
125 - ),  
126 - ),  
127 - ),  
128 - ),  
129 - IconButton(  
130 - color: Colors.white,  
131 - icon: ValueListenableBuilder<CameraFacing>(  
132 - valueListenable: controller.cameraFacingState,  
133 - builder: (context, state, child) {  
134 - switch (state) {  
135 - case CameraFacing.front:  
136 - return const Icon(Icons.camera_front);  
137 - case CameraFacing.back:  
138 - return const Icon(Icons.camera_rear);  
139 - }  
140 - },  
141 - ),  
142 - iconSize: 32.0,  
143 - onPressed: () => controller.switchCamera(),  
144 - ),  
145 - IconButton(  
146 - color: Colors.white,  
147 - icon: const Icon(Icons.image),  
148 - iconSize: 32.0,  
149 - onPressed: () async {  
150 - final ImagePicker picker = ImagePicker();  
151 - // Pick an image  
152 - final XFile? image = await picker.pickImage(  
153 - source: ImageSource.gallery,  
154 - );  
155 - if (image != null) {  
156 - if (await controller.analyzeImage(image.path)) {  
157 - if (!context.mounted) return;  
158 - ScaffoldMessenger.of(context).showSnackBar(  
159 - const SnackBar(  
160 - content: Text('Barcode found!'),  
161 - backgroundColor: Colors.green,  
162 - ),  
163 - );  
164 - } else {  
165 - if (!context.mounted) return;  
166 - ScaffoldMessenger.of(context).showSnackBar(  
167 - const SnackBar(  
168 - content: Text('No barcode found!'),  
169 - backgroundColor: Colors.red,  
170 - ),  
171 - );  
172 - }  
173 - }  
174 - },  
175 - ),  
176 - ],  
177 - ),  
178 - ),  
179 - ),  
180 - ],  
181 - );  
182 - },  
183 - ),  
184 - );  
185 - }  
186 -  
187 - @override  
188 - void dispose() {  
189 - controller.dispose();  
190 - super.dispose();  
191 - }  
192 -}  
  1 +import 'dart:async';
  2 +
  3 +import 'package:flutter/material.dart';
  4 +import 'package:mobile_scanner/mobile_scanner.dart';
  5 +import 'package:mobile_scanner_example/scanner_button_widgets.dart';
  6 +import 'package:mobile_scanner_example/scanner_error_widget.dart';
  7 +
  8 +class BarcodeScannerListView extends StatefulWidget {
  9 + const BarcodeScannerListView({super.key});
  10 +
  11 + @override
  12 + State<BarcodeScannerListView> createState() => _BarcodeScannerListViewState();
  13 +}
  14 +
  15 +class _BarcodeScannerListViewState extends State<BarcodeScannerListView> {
  16 + final MobileScannerController controller = MobileScannerController(
  17 + torchEnabled: true,
  18 + // formats: [BarcodeFormat.qrCode]
  19 + // facing: CameraFacing.front,
  20 + // detectionSpeed: DetectionSpeed.normal
  21 + // detectionTimeoutMs: 1000,
  22 + // returnImage: false,
  23 + );
  24 +
  25 + @override
  26 + void initState() {
  27 + super.initState();
  28 +
  29 + controller.start();
  30 + }
  31 +
  32 + Widget _buildBarcodesListView() {
  33 + return StreamBuilder<BarcodeCapture>(
  34 + stream: controller.barcodes,
  35 + builder: (context, snapshot) {
  36 + final barcodes = snapshot.data?.barcodes;
  37 +
  38 + if (barcodes == null || barcodes.isEmpty) {
  39 + return const Center(
  40 + child: Text(
  41 + 'Scan Something!',
  42 + style: TextStyle(color: Colors.white, fontSize: 20),
  43 + ),
  44 + );
  45 + }
  46 +
  47 + return ListView.builder(
  48 + itemCount: barcodes.length,
  49 + itemBuilder: (context, index) {
  50 + return Padding(
  51 + padding: const EdgeInsets.all(8.0),
  52 + child: Text(
  53 + barcodes[index].rawValue ?? 'No raw value',
  54 + overflow: TextOverflow.fade,
  55 + style: const TextStyle(color: Colors.white),
  56 + ),
  57 + );
  58 + },
  59 + );
  60 + },
  61 + );
  62 + }
  63 +
  64 + @override
  65 + Widget build(BuildContext context) {
  66 + return Scaffold(
  67 + appBar: AppBar(title: const Text('With ListView')),
  68 + backgroundColor: Colors.black,
  69 + body: Stack(
  70 + children: [
  71 + MobileScanner(
  72 + controller: controller,
  73 + errorBuilder: (context, error, child) {
  74 + return ScannerErrorWidget(error: error);
  75 + },
  76 + fit: BoxFit.contain,
  77 + ),
  78 + Align(
  79 + alignment: Alignment.bottomCenter,
  80 + child: Container(
  81 + alignment: Alignment.bottomCenter,
  82 + height: 100,
  83 + color: Colors.black.withOpacity(0.4),
  84 + child: Column(
  85 + children: [
  86 + Expanded(
  87 + child: _buildBarcodesListView(),
  88 + ),
  89 + Row(
  90 + mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  91 + children: [
  92 + ToggleFlashlightButton(controller: controller),
  93 + StartStopMobileScannerButton(controller: controller),
  94 + const Spacer(),
  95 + SwitchCameraButton(controller: controller),
  96 + AnalyzeImageFromGalleryButton(controller: controller),
  97 + ],
  98 + ),
  99 + ],
  100 + ),
  101 + ),
  102 + ),
  103 + ],
  104 + ),
  105 + );
  106 + }
  107 +
  108 + @override
  109 + Future<void> dispose() async {
  110 + await controller.dispose();
  111 + super.dispose();
  112 + }
  113 +}
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 -import 'package:mobile_scanner_example/barcode_list_scanner_controller.dart';  
3 import 'package:mobile_scanner_example/barcode_scanner_controller.dart'; 2 import 'package:mobile_scanner_example/barcode_scanner_controller.dart';
  3 +import 'package:mobile_scanner_example/barcode_scanner_listview.dart';
4 import 'package:mobile_scanner_example/barcode_scanner_pageview.dart'; 4 import 'package:mobile_scanner_example/barcode_scanner_pageview.dart';
5 import 'package:mobile_scanner_example/barcode_scanner_returning_image.dart'; 5 import 'package:mobile_scanner_example/barcode_scanner_returning_image.dart';
6 import 'package:mobile_scanner_example/barcode_scanner_window.dart'; 6 import 'package:mobile_scanner_example/barcode_scanner_window.dart';
@@ -33,12 +33,11 @@ class MyHome extends StatelessWidget { @@ -33,12 +33,11 @@ class MyHome extends StatelessWidget {
33 onPressed: () { 33 onPressed: () {
34 Navigator.of(context).push( 34 Navigator.of(context).push(
35 MaterialPageRoute( 35 MaterialPageRoute(
36 - builder: (context) =>  
37 - const BarcodeListScannerWithController(), 36 + builder: (context) => const BarcodeScannerListView(),
38 ), 37 ),
39 ); 38 );
40 }, 39 },
41 - child: const Text('MobileScanner with List Controller'), 40 + child: const Text('MobileScanner with ListView'),
42 ), 41 ),
43 ElevatedButton( 42 ElevatedButton(
44 onPressed: () { 43 onPressed: () {