diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..f5f1328 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,21 @@ +include: package:effective_dart/analysis_options.yaml +analyzer: + exclude: + - "**/generated_plugin_registrant.dart" + - "**/build/**" + - "**/generated_*.dart" + - "**/*.g.dart" + - "**/*.freezed.dart" + - "**/*.gr.dart" + - "**/l10n*.dart" + - "**/*.gen.dart" + +linter: + rules: + public_member_api_docs: false + one_member_abstracts: false + prefer_const_constructors: true + # IDE works bad with relative import + # See: https://github.com/dart-lang/sdk/issues/32916 + prefer_relative_imports: false + always_use_package_imports: true diff --git a/example/blue/analysis_options.yaml b/example/blue/analysis_options.yaml new file mode 100644 index 0000000..f5f1328 --- /dev/null +++ b/example/blue/analysis_options.yaml @@ -0,0 +1,21 @@ +include: package:effective_dart/analysis_options.yaml +analyzer: + exclude: + - "**/generated_plugin_registrant.dart" + - "**/build/**" + - "**/generated_*.dart" + - "**/*.g.dart" + - "**/*.freezed.dart" + - "**/*.gr.dart" + - "**/l10n*.dart" + - "**/*.gen.dart" + +linter: + rules: + public_member_api_docs: false + one_member_abstracts: false + prefer_const_constructors: true + # IDE works bad with relative import + # See: https://github.com/dart-lang/sdk/issues/32916 + prefer_relative_imports: false + always_use_package_imports: true diff --git a/example/blue/lib/main.dart b/example/blue/lib/main.dart index 108d463..de7e1fc 100644 --- a/example/blue/lib/main.dart +++ b/example/blue/lib/main.dart @@ -1,15 +1,15 @@ -import 'dart:io'; -import 'dart:typed_data'; -import 'package:intl/intl.dart'; -import 'package:qr_flutter/qr_flutter.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:flutter/services.dart'; -import 'package:image/image.dart'; -import 'package:esc_pos_utils/esc_pos_utils.dart'; import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart'; +import 'package:esc_pos_utils/esc_pos_utils.dart'; import 'package:flutter/material.dart' hide Image; +import 'package:flutter/services.dart'; +import 'package:image/image.dart'; +import 'package:intl/intl.dart'; import 'package:oktoast/oktoast.dart'; +import 'dart:io'; +import 'package:qr_flutter/qr_flutter.dart'; +import 'package:path_provider/path_provider.dart'; + void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @@ -55,7 +55,7 @@ class _MyHomePageState extends State { setState(() { _devices = []; }); - printerManager.startScan(Duration(seconds: 4)); + printerManager.startScan(const Duration(seconds: 4)); } void _stopScanDevices() { @@ -64,8 +64,8 @@ class _MyHomePageState extends State { Future> demoReceipt( PaperSize paper, CapabilityProfile profile) async { - final Generator ticket = Generator(paper, profile); - List bytes = []; + final generator = Generator(paper, profile); + var bytes = []; // Print image // final ByteData data = await rootBundle.load('assets/rabbit_black.jpg'); @@ -73,117 +73,141 @@ class _MyHomePageState extends State { // final Image? image = decodeImage(imageBytes); // bytes += ticket.image(image); - bytes += ticket.text('GROCERYLY', - styles: PosStyles( + bytes += generator.text('GROCERYLY', + styles: const PosStyles( align: PosAlign.center, height: PosTextSize.size2, width: PosTextSize.size2, ), linesAfter: 1); - bytes += ticket.text('889 Watson Lane', - styles: PosStyles(align: PosAlign.center)); - bytes += ticket.text('New Braunfels, TX', - styles: PosStyles(align: PosAlign.center)); - bytes += ticket.text('Tel: 830-221-1234', - styles: PosStyles(align: PosAlign.center)); - bytes += ticket.text('Web: www.example.com', - styles: PosStyles(align: PosAlign.center), linesAfter: 1); - - bytes += ticket.hr(); - bytes += ticket.row([ + bytes += generator.text('889 Watson Lane', + styles: const PosStyles(align: PosAlign.center)); + bytes += generator.text('New Braunfels, TX', + styles: const PosStyles(align: PosAlign.center)); + bytes += generator.text('Tel: 830-221-1234', + styles: const PosStyles(align: PosAlign.center)); + bytes += generator.text('Web: www.example.com', + styles: const PosStyles(align: PosAlign.center), linesAfter: 1); + + bytes += generator.hr(); + bytes += generator.row([ PosColumn(text: 'Qty', width: 1), PosColumn(text: 'Item', width: 7), PosColumn( - text: 'Price', width: 2, styles: PosStyles(align: PosAlign.right)), + text: 'Price', + width: 2, + styles: const PosStyles(align: PosAlign.right)), PosColumn( - text: 'Total', width: 2, styles: PosStyles(align: PosAlign.right)), + text: 'Total', + width: 2, + styles: const PosStyles(align: PosAlign.right)), ]); - bytes += ticket.row([ + bytes += generator.row([ PosColumn(text: '2', width: 1), PosColumn(text: 'ONION RINGS', width: 7), PosColumn( - text: '0.99', width: 2, styles: PosStyles(align: PosAlign.right)), + text: '0.99', + width: 2, + styles: const PosStyles(align: PosAlign.right)), PosColumn( - text: '1.98', width: 2, styles: PosStyles(align: PosAlign.right)), + text: '1.98', + width: 2, + styles: const PosStyles(align: PosAlign.right)), ]); - bytes += ticket.row([ + bytes += generator.row([ PosColumn(text: '1', width: 1), PosColumn(text: 'PIZZA', width: 7), PosColumn( - text: '3.45', width: 2, styles: PosStyles(align: PosAlign.right)), + text: '3.45', + width: 2, + styles: const PosStyles(align: PosAlign.right)), PosColumn( - text: '3.45', width: 2, styles: PosStyles(align: PosAlign.right)), + text: '3.45', + width: 2, + styles: const PosStyles(align: PosAlign.right)), ]); - bytes += ticket.row([ + bytes += generator.row([ PosColumn(text: '1', width: 1), PosColumn(text: 'SPRING ROLLS', width: 7), PosColumn( - text: '2.99', width: 2, styles: PosStyles(align: PosAlign.right)), + text: '2.99', + width: 2, + styles: const PosStyles(align: PosAlign.right)), PosColumn( - text: '2.99', width: 2, styles: PosStyles(align: PosAlign.right)), + text: '2.99', + width: 2, + styles: const PosStyles(align: PosAlign.right)), ]); - bytes += ticket.row([ + bytes += generator.row([ PosColumn(text: '3', width: 1), PosColumn(text: 'CRUNCHY STICKS', width: 7), PosColumn( - text: '0.85', width: 2, styles: PosStyles(align: PosAlign.right)), + text: '0.85', + width: 2, + styles: const PosStyles(align: PosAlign.right)), PosColumn( - text: '2.55', width: 2, styles: PosStyles(align: PosAlign.right)), + text: '2.55', + width: 2, + styles: const PosStyles(align: PosAlign.right)), ]); - bytes += ticket.hr(); + bytes += generator.hr(); - bytes += ticket.row([ + bytes += generator.row([ PosColumn( text: 'TOTAL', width: 6, - styles: PosStyles( + styles: const PosStyles( height: PosTextSize.size2, width: PosTextSize.size2, )), PosColumn( text: '\$10.97', width: 6, - styles: PosStyles( + styles: const PosStyles( align: PosAlign.right, height: PosTextSize.size2, width: PosTextSize.size2, )), ]); - bytes += ticket.hr(ch: '=', linesAfter: 1); + bytes += generator.hr(ch: '=', linesAfter: 1); - bytes += ticket.row([ + bytes += generator.row([ PosColumn( text: 'Cash', width: 7, - styles: PosStyles(align: PosAlign.right, width: PosTextSize.size2)), + styles: + const PosStyles(align: PosAlign.right, width: PosTextSize.size2)), PosColumn( text: '\$15.00', width: 5, - styles: PosStyles(align: PosAlign.right, width: PosTextSize.size2)), + styles: + const PosStyles(align: PosAlign.right, width: PosTextSize.size2)), ]); - bytes += ticket.row([ + bytes += generator.row([ PosColumn( text: 'Change', width: 7, - styles: PosStyles(align: PosAlign.right, width: PosTextSize.size2)), + styles: + const PosStyles(align: PosAlign.right, width: PosTextSize.size2)), PosColumn( text: '\$4.03', width: 5, - styles: PosStyles(align: PosAlign.right, width: PosTextSize.size2)), + styles: + const PosStyles(align: PosAlign.right, width: PosTextSize.size2)), ]); - bytes += ticket.feed(2); - bytes += ticket.text('Thank you!', - styles: PosStyles(align: PosAlign.center, bold: true)); + bytes += generator.feed(2); + bytes += generator.text('Thank you!', + styles: const PosStyles(align: PosAlign.center, bold: true)); final now = DateTime.now(); final formatter = DateFormat('MM/dd/yyyy H:m'); - final String timestamp = formatter.format(now); - bytes += ticket.text(timestamp, - styles: PosStyles(align: PosAlign.center), linesAfter: 2); + final timestamp = formatter.format(now); + bytes += generator.text(timestamp, + styles: const PosStyles(align: PosAlign.center), linesAfter: 2); // Print QR Code from image // try { @@ -208,15 +232,15 @@ class _MyHomePageState extends State { // Print QR Code using native function // bytes += ticket.qrcode('example.com'); - ticket.feed(2); - ticket.cut(); + generator.feed(2); + generator.cut(); return bytes; } Future> testTicket( PaperSize paper, CapabilityProfile profile) async { - final Generator generator = Generator(paper, profile); - List bytes = []; + final generator = Generator(paper, profile); + var bytes = []; bytes += generator.text( 'Regular: aA bB cC dD eE fF gG hH iI jJ kK lL mM nN oO pP qQ rR sS tT uU vV wW xX yY zZ'); @@ -225,55 +249,57 @@ class _MyHomePageState extends State { // bytes += generator.text('Special 2: blåbærgrød', // styles: PosStyles(codeTable: PosCodeTable.westEur)); - bytes += generator.text('Bold text', styles: PosStyles(bold: true)); - bytes += generator.text('Reverse text', styles: PosStyles(reverse: true)); - bytes += generator.text('Underlined text', - styles: PosStyles(underline: true), linesAfter: 1); + bytes += generator.text('Bold text', styles: const PosStyles(bold: true)); bytes += - generator.text('Align left', styles: PosStyles(align: PosAlign.left)); + generator.text('Reverse text', styles: const PosStyles(reverse: true)); + bytes += generator.text('Underlined text', + styles: const PosStyles(underline: true), linesAfter: 1); + bytes += generator.text('Align left', + styles: const PosStyles(align: PosAlign.left)); bytes += generator.text('Align center', - styles: PosStyles(align: PosAlign.center)); + styles: const PosStyles(align: PosAlign.center)); bytes += generator.text('Align right', - styles: PosStyles(align: PosAlign.right), linesAfter: 1); + styles: const PosStyles(align: PosAlign.right), linesAfter: 1); bytes += generator.row([ PosColumn( text: 'col3', width: 3, - styles: PosStyles(align: PosAlign.center, underline: true), + styles: const PosStyles(align: PosAlign.center, underline: true), ), PosColumn( text: 'col6', width: 6, - styles: PosStyles(align: PosAlign.center, underline: true), + styles: const PosStyles(align: PosAlign.center, underline: true), ), PosColumn( text: 'col3', width: 3, - styles: PosStyles(align: PosAlign.center, underline: true), + styles: const PosStyles(align: PosAlign.center, underline: true), ), ]); bytes += generator.text('Text size 200%', - styles: PosStyles( + styles: const PosStyles( height: PosTextSize.size2, width: PosTextSize.size2, )); // Print image - final ByteData data = await rootBundle.load('assets/logo.png'); - final Uint8List buf = data.buffer.asUint8List(); - final Image image = decodeImage(buf)!; + final byteData = await rootBundle.load('assets/logo.png'); + final buf = byteData.buffer.asUint8List(); + final image = decodeImage(buf)!; bytes += generator.image(image); // Print image using alternative commands // bytes += generator.imageRaster(image); // bytes += generator.imageRaster(image, imageFn: PosImageFn.graphics); // Print barcode - final List barData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 4]; - bytes += generator.barcode(Barcode.upcA(barData)); + final barcodeData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 4]; + bytes += generator.barcode(Barcode.upcA(barcodeData)); - // Print mixed (chinese + latin) text. Only for printers supporting Kanji mode + // Print mixed (chinese + latin) text. + // Only for printers supporting Kanji mode // bytes += generator.text( // 'hello ! 中文字 # world @ éphémère &', // styles: PosStyles(codeTable: PosCodeTable.westEur), @@ -290,7 +316,7 @@ class _MyHomePageState extends State { printerManager.selectPrinter(printer); // TODO Don't forget to choose printer's paper - const PaperSize paper = PaperSize.mm80; + const paperSize = PaperSize.mm80; final profile = await CapabilityProfile.load(); // TEST PRINT @@ -298,10 +324,10 @@ class _MyHomePageState extends State { // await printerManager.printTicket(await testTicket(paper)); // DEMO RECEIPT - final PosPrintResult res = - await printerManager.printTicket((await demoReceipt(paper, profile))); + final posPrintResult = await printerManager + .printTicket((await demoReceipt(paperSize, profile))); - showToast(res.msg); + showToast(posPrintResult.msg); } @override @@ -312,19 +338,19 @@ class _MyHomePageState extends State { ), body: ListView.builder( itemCount: _devices.length, - itemBuilder: (BuildContext context, int index) { + itemBuilder: (context, index) { return InkWell( onTap: () => _testPrint(_devices[index]), child: Column( children: [ Container( height: 60, - padding: EdgeInsets.only(left: 10), + padding: const EdgeInsets.only(left: 10), alignment: Alignment.centerLeft, child: Row( children: [ - Icon(Icons.print), - SizedBox(width: 10), + const Icon(Icons.print), + const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -342,7 +368,7 @@ class _MyHomePageState extends State { ], ), ), - Divider(), + const Divider(), ], ), ); @@ -353,13 +379,13 @@ class _MyHomePageState extends State { builder: (c, snapshot) { if (snapshot.data!) { return FloatingActionButton( - child: Icon(Icons.stop), + child: const Icon(Icons.stop), onPressed: _stopScanDevices, backgroundColor: Colors.red, ); } else { return FloatingActionButton( - child: Icon(Icons.search), + child: const Icon(Icons.search), onPressed: _startScanDevices, ); } diff --git a/example/blue/pubspec.yaml b/example/blue/pubspec.yaml index f7e11c7..7744fb2 100644 --- a/example/blue/pubspec.yaml +++ b/example/blue/pubspec.yaml @@ -1,4 +1,4 @@ -name: blue +name: esc_pos_bluetooth_example description: A new Flutter project. version: 1.0.0+1 @@ -20,6 +20,7 @@ dependencies: intl: ^0.17.0 qr_flutter: ^4.0.0 path_provider: ^2.0.2 + effective_dart: ^1.3.0 dev_dependencies: flutter_test: diff --git a/lib/src/printer_bluetooth_manager.dart b/lib/src/printer_bluetooth_manager.dart index b4ebc07..b274a0e 100644 --- a/lib/src/printer_bluetooth_manager.dart +++ b/lib/src/printer_bluetooth_manager.dart @@ -8,18 +8,23 @@ import 'dart:async'; import 'dart:io'; -import 'package:esc_pos_utils/esc_pos_utils.dart'; -import 'package:rxdart/rxdart.dart'; + +import 'package:esc_pos_bluetooth/src/enums.dart'; import 'package:flutter_bluetooth_basic/flutter_bluetooth_basic.dart'; -import './enums.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'package:esc_pos_utils/esc_pos_utils.dart'; /// Bluetooth printer class PrinterBluetooth { PrinterBluetooth(this._device); + final BluetoothDevice _device; String? get name => _device.name; + String? get address => _device.address; + int? get type => _device.type; } @@ -33,10 +38,12 @@ class PrinterBluetoothManager { PrinterBluetooth? _selectedPrinter; final BehaviorSubject _isScanning = BehaviorSubject.seeded(false); + Stream get isScanningStream => _isScanning.stream; final BehaviorSubject> _scanResults = BehaviorSubject.seeded([]); + Stream> get scanResults => _scanResults.stream; Future _runDelayed(int seconds) { @@ -76,9 +83,9 @@ class PrinterBluetoothManager { int chunkSizeBytes = 20, int queueSleepTimeMs = 20, }) async { - final Completer completer = Completer(); + final completer = Completer(); - const int timeout = 5; + const timeout = 5; if (_selectedPrinter == null) { return Future.value(PosPrintResult.printerNotSelected); } else if (_isScanning.value!) { @@ -90,7 +97,7 @@ class PrinterBluetoothManager { _isPrinting = true; // We have to rescan before connecting, otherwise we can connect only once - await _bluetoothManager.startScan(timeout: Duration(seconds: 1)); + await _bluetoothManager.startScan(timeout: const Duration(seconds: 1)); await _bluetoothManager.stopScan(); // Connect @@ -103,7 +110,7 @@ class PrinterBluetoothManager { // To avoid double call if (!_isConnected) { final len = bytes.length; - List> chunks = []; + var chunks = >[]; for (var i = 0; i < len; i += chunkSizeBytes) { var end = (i + chunkSizeBytes < len) ? i + chunkSizeBytes : len; chunks.add(bytes.sublist(i, end)); diff --git a/pubspec.yaml b/pubspec.yaml index 84965c2..030b8d1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,6 +10,7 @@ dependencies: flutter: sdk: flutter rxdart: ^0.26.0 + effective_dart: ^1.3.0 esc_pos_utils: ^1.1.0 # esc_pos_utils: # path: ../esc_pos_utils diff --git a/test/esc_pos_bluetooth_test.dart b/test/esc_pos_bluetooth_test.dart index 349f625..2f6b825 100644 --- a/test/esc_pos_bluetooth_test.dart +++ b/test/esc_pos_bluetooth_test.dart @@ -1,7 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; -import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart'; - void main() { test('Tests not implemented', () { expect(1, 1);