• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

inventree / inventree-app / 12269597812

11 Dec 2024 04:18AM UTC coverage: 8.597% (-0.008%) from 8.605%
12269597812

push

github

web-flow
Merge pull request #571 from inventree/barcode-scan-fix

Barcode scan fix

0 of 14 new or added lines in 1 file covered. (0.0%)

1 existing line in 1 file now uncovered.

725 of 8433 relevant lines covered (8.6%)

0.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/lib/barcode/camera_controller.dart
1
import "dart:math";
2
import "dart:typed_data";
3

4
import "package:flutter/material.dart";
5
import "package:flutter_tabler_icons/flutter_tabler_icons.dart";
6
import "package:inventree/app_colors.dart";
7
import "package:inventree/preferences.dart";
8
import "package:wakelock_plus/wakelock_plus.dart";
9
import "package:flutter_zxing/flutter_zxing.dart";
10

11
import "package:inventree/l10.dart";
12

13
import "package:inventree/barcode/handler.dart";
14
import "package:inventree/barcode/controller.dart";
15

16
/*
17
 * Barcode controller which uses the device's camera to scan barcodes.
18
 * Under the hood it uses the qr_code_scanner package.
19
 */
20
class CameraBarcodeController extends InvenTreeBarcodeController {
21
  const CameraBarcodeController(BarcodeHandler handler, {Key? key})
×
22
      : super(handler, key: key);
×
23

24
  @override
×
25
  State<StatefulWidget> createState() => _CameraBarcodeControllerState();
×
26
}
27

28
class _CameraBarcodeControllerState extends InvenTreeBarcodeControllerState {
29
  _CameraBarcodeControllerState() : super();
×
30

31
  bool flash_status = false;
32

33
  int scan_delay = 500;
34
  bool single_scanning = false;
35
  bool scanning_paused = false;
36

37
  String scanned_code = "";
38

39
  @override
×
40
  void initState() {
41
    super.initState();
×
42
    _loadSettings();
×
43
    WakelockPlus.enable();
×
44
  }
45

46
  @override
×
47
  void dispose() {
48
    super.dispose();
×
49
    WakelockPlus.disable();
×
50
  }
51

52
  /*
53
   * Load the barcode scanning settings
54
   */
55
  Future<void> _loadSettings() async {
×
56
    bool _single = await InvenTreeSettingsManager()
×
57
        .getBool(INV_BARCODE_SCAN_SINGLE, false);
×
58

59
    int _delay = await InvenTreeSettingsManager()
×
60
        .getValue(INV_BARCODE_SCAN_DELAY, 500) as int;
×
61

62
    if (mounted) {
×
63
      setState(() {
×
64
        scan_delay = _delay;
×
65
        single_scanning = _single;
×
66
        scanning_paused = false;
×
67
      });
68
    }
69
  }
70

71
  @override
×
72
  Future<void> pauseScan() async {
73
    if (mounted) {
×
74
      setState(() {
×
75
        scanning_paused = true;
×
76
      });
77
    }
78
  }
79

80
  @override
×
81
  Future<void> resumeScan() async {
82
    if (mounted) {
×
83
      setState(() {
×
84
        scanning_paused = false;
×
85
      });
86
    }
87
  }
88

89
  /*
90
   * Callback function when a barcode is scanned
91
   */
92
  void _onScanSuccess(Code? code) {
×
93

94
    if (scanning_paused) {
×
95
      return;
96
    }
97

NEW
98
    Uint8List raw_data = code?.rawBytes ?? Uint8List(0);
×
99

100
    // Reconstruct barcode from raw data
101
    String barcode;
102

NEW
103
    if (raw_data.isNotEmpty) {
×
104
      barcode = "";
105

NEW
106
      final buffer = StringBuffer();
×
107

NEW
108
      for (int i = 0; i < raw_data.length; i++) {
×
NEW
109
        buffer.writeCharCode(raw_data[i]);
×
110
      }
111

NEW
112
      barcode = buffer.toString();
×
113

114
    } else {
NEW
115
      barcode = code?.text ?? "";
×
116
    }
117

118
    if (mounted) {
×
119
      setState(() {
×
NEW
120
        scanned_code = barcode;
×
NEW
121
        scanning_paused = barcode.isNotEmpty;
×
122
      });
123
    }
124

NEW
125
    if (barcode.isNotEmpty) {
×
126

NEW
127
      handleBarcodeData(barcode).then((_) {
×
UNCOV
128
        if (!single_scanning && mounted) {
×
129
          // Resume next scan
130
          setState(() {
×
131
            scanning_paused = false;
×
132
          });
133
        }
134
      });
135
    }
136

137
  }
138

139
  /*
140
   * Build the barcode scanner overlay
141
   */
142
  FixedScannerOverlay BarcodeOverlay(BuildContext context) {
×
143

144
    // Note: Copied from reader_widget.dart:ReaderWidget.build
145
    final Size size = MediaQuery.of(context).size;
×
146
    final double cropSize = min(size.width, size.height) * 0.5;
×
147

148
    return FixedScannerOverlay(
×
149
      borderColor: scanning_paused ? COLOR_WARNING : COLOR_ACTION,
×
150
      overlayColor: Colors.black45,
151
      borderRadius: 1,
152
      borderLength: 15,
153
      borderWidth: 8,
154
      cutOutSize: cropSize,
155
    );
156
  }
157

158
  /*
159
   * Build the barcode reader widget
160
   */
161
  Widget BarcodeReader(BuildContext context) {
×
162

163
    return ReaderWidget(
×
164
      onScan: _onScanSuccess,
×
165
      isMultiScan: false,
166
      tryHarder: true,
167
      tryInverted: true,
168
      tryRotate: true,
169
      showGallery: false,
170
      scanDelay: Duration(milliseconds: scan_delay),
×
171
      resolution: ResolutionPreset.high,
172
      lensDirection: CameraLensDirection.back,
173
      flashOnIcon: const Icon(Icons.flash_on),
174
      flashOffIcon: const Icon(Icons.flash_off),
175
      toggleCameraIcon: const Icon(TablerIcons.camera_rotate),
176
      actionButtonsBackgroundBorderRadius:
177
      BorderRadius.circular(40),
×
178
      scannerOverlay: BarcodeOverlay(context),
×
179
      actionButtonsBackgroundColor: Colors.black.withOpacity(0.7),
×
180
    );
181
  }
182

183
  Widget topCenterOverlay() {
×
184
    return SafeArea(
×
185
      child: Align(
×
186
        alignment: Alignment.topCenter,
187
        child: Padding(
×
188
          padding: EdgeInsets.all(10),
×
189
          child: Text(
×
190
            widget.handler.getOverlayText(context),
×
191
            style: TextStyle(
×
192
              color: Colors.white,
193
              fontSize: 16,
194
              fontWeight: FontWeight.bold
195
            )
196
          )
197
        )
198
      )
199
    );
200
  }
201

202
  Widget bottomCenterOverlay() {
×
203

204
    String info_text = scanning_paused ? L10().barcodeScanPaused : L10().barcodeScanPause;
×
205

NEW
206
    String text = scanned_code.isNotEmpty ? scanned_code : info_text;
×
207

NEW
208
    if (text.length > 50) {
×
NEW
209
      text = text.substring(0, 50) + "...";
×
210
    }
211

212
    return SafeArea(
×
213
      child: Align(
×
214
        alignment: Alignment.bottomCenter,
215
        child: Padding(
×
216
          padding: EdgeInsets.all(10),
×
217
          child: Text(
×
218
              text,
219
              textAlign: TextAlign.center,
220
              style: TextStyle(
×
221
                color: Colors.white,
222
                fontSize: 16,
223
                fontWeight: FontWeight.bold
224
              )
225
          ),
226
        )
227
      )
228
    );
229
  }
230

231

232
  /*
233
   *  Display an overlay at the bottom right of the screen
234
   */
235
  Widget bottomRightOverlay() {
×
236
    return SafeArea(
×
237
        child: Align(
×
238
            alignment: Alignment.bottomRight,
239
            child: Padding(
×
240
                padding: EdgeInsets.all(10),
×
241
                child: ClipRRect(
×
242
                    borderRadius: BorderRadius.circular(40),
×
243
                    child: ColoredBox(
×
244
                        color: Colors.black45,
245
                        child: Row(
×
246
                            mainAxisSize: MainAxisSize.min,
247
                            children: scanning_paused ? [] : [
×
248
                              CircularProgressIndicator(
×
249
                                  value: null
250
                              )
251
                              // actionIcon,
252
                            ]
253
                        )
254
                    )
255
                )
256
            )
257
        )
258
    );
259
  }
260

261
  @override
×
262
  Widget build(BuildContext context) {
263

264
    return Scaffold(
×
265
      appBar: AppBar(
×
266
        backgroundColor: COLOR_APP_BAR,
×
267
        title: Text(L10().scanBarcode),
×
268
      ),
269
      body: GestureDetector(
×
270
        onTap: () async {
×
271
          setState(() {
×
272
            scanning_paused = !scanning_paused;
×
273
          });
274
        },
275
        child: Stack(
×
276
          children: <Widget>[
×
277
            Column(
×
278
              children: [
×
279
                Expanded(
×
280
                    child: BarcodeReader(context)
×
281
                ),
282
              ],
283
            ),
284
            topCenterOverlay(),
×
285
            bottomCenterOverlay(),
×
286
            bottomRightOverlay(),
×
287
          ],
288
        ),
289
      ),
290
    );
291
  }
292

293
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc