Navaron Bracke

clean up the zoom slider example

  1 +import 'dart:async';
  2 +
1 import 'package:flutter/material.dart'; 3 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/mobile_scanner.dart';
4 5
  6 +import 'package:mobile_scanner_example/scanner_button_widgets.dart';
5 import 'package:mobile_scanner_example/scanner_error_widget.dart'; 7 import 'package:mobile_scanner_example/scanner_error_widget.dart';
6 8
7 class BarcodeScannerWithZoom extends StatefulWidget { 9 class BarcodeScannerWithZoom extends StatefulWidget {
@@ -15,13 +17,71 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom> @@ -15,13 +17,71 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom>
15 with SingleTickerProviderStateMixin { 17 with SingleTickerProviderStateMixin {
16 BarcodeCapture? barcode; 18 BarcodeCapture? barcode;
17 19
18 - MobileScannerController controller = MobileScannerController( 20 + final MobileScannerController controller = MobileScannerController(
19 torchEnabled: true, 21 torchEnabled: true,
20 ); 22 );
21 23
22 - bool isStarted = true;  
23 double _zoomFactor = 0.0; 24 double _zoomFactor = 0.0;
24 25
  26 + StreamSubscription<Object?>? _barcodesSubscription;
  27 +
  28 + @override
  29 + void initState() {
  30 + super.initState();
  31 + _barcodesSubscription = controller.barcodes.listen((event) {
  32 + setState(() {
  33 + barcode = event;
  34 + });
  35 + });
  36 +
  37 + controller.start();
  38 + }
  39 +
  40 + Widget _buildZoomScaleSlider() {
  41 + return ValueListenableBuilder(
  42 + valueListenable: controller,
  43 + builder: (context, state, child) {
  44 + if (!state.isInitialized || !state.isRunning) {
  45 + return const SizedBox.shrink();
  46 + }
  47 +
  48 + final TextStyle labelStyle = Theme.of(context)
  49 + .textTheme
  50 + .headlineMedium!
  51 + .copyWith(color: Colors.white);
  52 +
  53 + return Padding(
  54 + padding: const EdgeInsets.symmetric(horizontal: 8.0),
  55 + child: Row(
  56 + children: [
  57 + Text(
  58 + '0%',
  59 + overflow: TextOverflow.fade,
  60 + style: labelStyle,
  61 + ),
  62 + Expanded(
  63 + child: Slider(
  64 + value: _zoomFactor,
  65 + onChanged: (value) {
  66 + setState(() {
  67 + _zoomFactor = value;
  68 + controller.setZoomScale(value);
  69 + });
  70 + },
  71 + ),
  72 + ),
  73 + Text(
  74 + '100%',
  75 + overflow: TextOverflow.fade,
  76 + style: labelStyle,
  77 + ),
  78 + ],
  79 + ),
  80 + );
  81 + },
  82 + );
  83 + }
  84 +
25 @override 85 @override
26 Widget build(BuildContext context) { 86 Widget build(BuildContext context) {
27 return Scaffold( 87 return Scaffold(
@@ -37,11 +97,6 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom> @@ -37,11 +97,6 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom>
37 errorBuilder: (context, error, child) { 97 errorBuilder: (context, error, child) {
38 return ScannerErrorWidget(error: error); 98 return ScannerErrorWidget(error: error);
39 }, 99 },
40 - onDetect: (barcode) {  
41 - setState(() {  
42 - this.barcode = barcode;  
43 - });  
44 - },  
45 ), 100 ),
46 Align( 101 Align(
47 alignment: Alignment.bottomCenter, 102 alignment: Alignment.bottomCenter,
@@ -51,81 +106,12 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom> @@ -51,81 +106,12 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom>
51 color: Colors.black.withOpacity(0.4), 106 color: Colors.black.withOpacity(0.4),
52 child: Column( 107 child: Column(
53 children: [ 108 children: [
54 - Padding(  
55 - padding: const EdgeInsets.symmetric(horizontal: 8.0),  
56 - child: Row(  
57 - children: [  
58 - Text(  
59 - "0%",  
60 - overflow: TextOverflow.fade,  
61 - style: Theme.of(context)  
62 - .textTheme  
63 - .headlineMedium!  
64 - .copyWith(color: Colors.white),  
65 - ),  
66 - Expanded(  
67 - child: Slider(  
68 - max: 100,  
69 - divisions: 100,  
70 - value: _zoomFactor,  
71 - label: "${_zoomFactor.round()} %",  
72 - onChanged: (value) {  
73 - setState(() {  
74 - _zoomFactor = value;  
75 - controller.setZoomScale(value);  
76 - });  
77 - },  
78 - ),  
79 - ),  
80 - Text(  
81 - "100%",  
82 - overflow: TextOverflow.fade,  
83 - style: Theme.of(context)  
84 - .textTheme  
85 - .headlineMedium!  
86 - .copyWith(color: Colors.white),  
87 - ),  
88 - ],  
89 - ),  
90 - ), 109 + _buildZoomScaleSlider(),
91 Row( 110 Row(
92 mainAxisAlignment: MainAxisAlignment.spaceEvenly, 111 mainAxisAlignment: MainAxisAlignment.spaceEvenly,
93 children: [ 112 children: [
94 - IconButton(  
95 - color: Colors.white,  
96 - icon: ValueListenableBuilder<TorchState>(  
97 - valueListenable: controller.torchState,  
98 - builder: (context, state, child) {  
99 - switch (state) {  
100 - case TorchState.off:  
101 - return const Icon(  
102 - Icons.flash_off,  
103 - color: Colors.grey,  
104 - );  
105 - case TorchState.on:  
106 - return const Icon(  
107 - Icons.flash_on,  
108 - color: Colors.yellow,  
109 - );  
110 - }  
111 - },  
112 - ),  
113 - iconSize: 32.0,  
114 - onPressed: () => controller.toggleTorch(),  
115 - ),  
116 - IconButton(  
117 - color: Colors.white,  
118 - icon: isStarted  
119 - ? const Icon(Icons.stop)  
120 - : const Icon(Icons.play_arrow),  
121 - iconSize: 32.0,  
122 - onPressed: () => setState(() {  
123 - isStarted  
124 - ? controller.stop()  
125 - : controller.start();  
126 - isStarted = !isStarted;  
127 - }),  
128 - ), 113 + ToggleFlashlightButton(controller: controller),
  114 + StartStopMobileScannerButton(controller: controller),
129 Center( 115 Center(
130 child: SizedBox( 116 child: SizedBox(
131 width: MediaQuery.of(context).size.width - 200, 117 width: MediaQuery.of(context).size.width - 200,
@@ -143,53 +129,8 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom> @@ -143,53 +129,8 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom>
143 ), 129 ),
144 ), 130 ),
145 ), 131 ),
146 - IconButton(  
147 - color: Colors.white,  
148 - icon: ValueListenableBuilder<CameraFacing>(  
149 - valueListenable: controller.cameraFacingState,  
150 - builder: (context, state, child) {  
151 - switch (state) {  
152 - case CameraFacing.front:  
153 - return const Icon(Icons.camera_front);  
154 - case CameraFacing.back:  
155 - return const Icon(Icons.camera_rear);  
156 - }  
157 - },  
158 - ),  
159 - iconSize: 32.0,  
160 - onPressed: () => controller.switchCamera(),  
161 - ),  
162 - IconButton(  
163 - color: Colors.white,  
164 - icon: const Icon(Icons.image),  
165 - iconSize: 32.0,  
166 - onPressed: () async {  
167 - final ImagePicker picker = ImagePicker();  
168 - // Pick an image  
169 - final XFile? image = await picker.pickImage(  
170 - source: ImageSource.gallery,  
171 - );  
172 - if (image != null) {  
173 - if (await controller.analyzeImage(image.path)) {  
174 - if (!context.mounted) return;  
175 - ScaffoldMessenger.of(context).showSnackBar(  
176 - const SnackBar(  
177 - content: Text('Barcode found!'),  
178 - backgroundColor: Colors.green,  
179 - ),  
180 - );  
181 - } else {  
182 - if (!context.mounted) return;  
183 - ScaffoldMessenger.of(context).showSnackBar(  
184 - const SnackBar(  
185 - content: Text('No barcode found!'),  
186 - backgroundColor: Colors.red,  
187 - ),  
188 - );  
189 - }  
190 - }  
191 - },  
192 - ), 132 + SwitchCameraButton(controller: controller),
  133 + AnalyzeImageFromGalleryButton(controller: controller),
193 ], 134 ],
194 ), 135 ),
195 ], 136 ],
@@ -202,4 +143,11 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom> @@ -202,4 +143,11 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom>
202 ), 143 ),
203 ); 144 );
204 } 145 }
  146 +
  147 + @override
  148 + Future<void> dispose() async {
  149 + _barcodesSubscription?.cancel();
  150 + await controller.dispose();
  151 + super.dispose();
  152 + }
205 } 153 }