import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; import 'dart:ui'; import 'package:barcode_widget/barcode_widget.dart'; import 'package:dj_printer/src/status_enum.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_image_compress/flutter_image_compress.dart'; import 'package:widget_to_image/widget_to_image.dart'; class DjPrinter { static late final DjPrinter _instance = DjPrinter._(); DjPrinter._(); factory DjPrinter() => _instance; static const MethodChannel _channel = MethodChannel('dj_printer'); static const EventChannel _deviceChannel = EventChannel("com.discovery.devices"); StreamSubscription? _discoveryStream; StreamSubscription addDiscoveryListen( {required void Function(dynamic data) onReceive, void Function()? onStart, void Function()? onFinish}) { if (_discoveryStream == null) { return _deviceChannel.receiveBroadcastStream().listen((data) { if (data == "start" && onStart != null) { onStart(); } else if (data == "finish" && onFinish != null) { onFinish(); } else { onReceive(data); } }); } else { return _discoveryStream!; } } void cancelDiscovery() { _discoveryStream?.cancel(); _discoveryStream = null; print('结束搜索'); disposeDiscovery(); } static const EventChannel _connectChannel = EventChannel("com.connect"); StreamSubscription? _connectStream; StreamSubscription addConnectListen({required void Function() onConnect, required void Function() onDisconnect}) { if (_connectStream == null) { return _connectChannel.receiveBroadcastStream().listen((data) { if (data == 'connected') { onConnect(); } else if (data == 'disconnected') { onDisconnect(); } }); } else { return _connectStream!; } } void cancelConnect() { if (_connectStream != null) { _connectStream!.cancel(); _connectStream = null; } } void get startSearch { final res = _channel.invokeMethod('startSearch'); } bool _hasInit = false; bool get hasInit => _hasInit; Future connect(String address) async { final res = await _channel.invokeMethod('connect', {'address': address}); return res; } void disposeDiscovery() { print('disposeDiscovery'); final res = _channel.invokeMethod('disposeDiscovery'); } Future disposeConnect() async { final res = await _channel.invokeMethod('disposeConnect'); return res; } Future init() async { final res = await _channel.invokeMethod('init'); _hasInit = true; return res; } //0 normal //1 busy //2 paper empty //4 cover open //8 battery low Future getStatus() async { final res = await _channel.invokeMethod('getStatus'); switch (res) { case 0: return PRINT_STATUS.normal; case 1: return PRINT_STATUS.busy; case 2: return PRINT_STATUS.paperEmpty; case 4: return PRINT_STATUS.coverOpen; case 8: return PRINT_STATUS.batteryLow; default: return null; } } Future printNewAScode({required String code, required String barCode, required String channel, required String country, required String num, required String sum, required int offset, required bool hasPlan}) async { final res = await _channel.invokeMethod('newPrint', { 'code': code, 'barCode':barCode, 'channel': channel, 'country': country, 'num': num, 'sum': sum, 'offset': offset, 'hasPlan': hasPlan, }); return res; } Future printAScode({required String code, required String channel, required String country, required String countStr, required int offset, required bool hasPlan}) async { final res = await _channel.invokeMethod('print', { 'code': code, 'channel': channel, 'country': country, 'countStr': countStr, 'offset': offset, 'hasPlan': hasPlan, }); return res; } Future printAScodeByImg({required String code, required String channel, required String country, required String num, required String sum, required String countStr, required int offset, required bool hasPlan}) async { ByteData bDCode = await WidgetToImage.widgetToImage( Directionality( textDirection: TextDirection.ltr, child: Material( child:_getCode(code), ), ),pixelRatio: window.devicePixelRatio,size: const Size(25,240)); Uint8List uint8ListCode = await testComporessList(bDCode); ByteData bDChannel = await WidgetToImage.widgetToImage( Directionality( textDirection: TextDirection.ltr, child: Material( child:_getChannel(channel) ), ),pixelRatio: window.devicePixelRatio,size: const Size(40,140)); Uint8List uint8ListChannel = await testComporessList(bDChannel); ByteData bDNum = await WidgetToImage.widgetToImage( Directionality( textDirection: TextDirection.ltr, child: Material( child:_getNum(num) ), ),pixelRatio: window.devicePixelRatio,size: Size(20,(20*num.length).toDouble())); Uint8List uint8ListNum = await testComporessList(bDNum); ByteData bDSum = await WidgetToImage.widgetToImage( Directionality( textDirection: TextDirection.ltr, child: Material( child:_getNum(sum) ), ),pixelRatio: window.devicePixelRatio,size: Size(20,(20*sum.length).toDouble())); Uint8List uint8ListSum= await testComporessList(bDSum); Uint8List uint8ListCountry; if(hasPlan){ ByteData bDCountry = await WidgetToImage.widgetToImage( Directionality( textDirection: TextDirection.ltr, child: Material( child:_getCountry(country) ), ),pixelRatio: window.devicePixelRatio,size: Size(country.length>4?44: 22,70)); uint8ListCountry = await testComporessList(bDCountry); }else{ ByteData bDCountry = await WidgetToImage.widgetToImage( Directionality( textDirection: TextDirection.ltr, child: Material( child:_getNoplan() ), ),pixelRatio: window.devicePixelRatio,size: const Size(22,100)); uint8ListCountry = await testComporessList(bDCountry); } ByteData bDBarCode = await WidgetToImage.widgetToImage( Directionality( textDirection: TextDirection.ltr, child: Material( child:_getBarCode(code) ), ),pixelRatio: window.devicePixelRatio,size: const Size(60,120)); Uint8List uint8ListBarCode = await testComporessList(bDBarCode); final res = await _channel.invokeMethod('print', { 'code': code, 'channel': channel, 'country': country, 'countStr': countStr, 'offset': offset, 'hasPlan': hasPlan, 'byteCode': uint8ListCode, 'bytesChannel':uint8ListChannel, 'bytesCountry':uint8ListCountry, 'bytesBarCode':uint8ListBarCode, 'bytesSum':uint8ListSum, 'bytesNum':uint8ListNum, }); return res; } Future testComporessList(ByteData data) async { final buffer = data.buffer; var result = await FlutterImageCompress.compressWithList( buffer.asUint8List(), quality: 1, ); print(buffer.asUint8List().length); print(result.length); return result; } Widget _getCountry(String country){ return RotatedBox( quarterTurns: 1, child: Text( country, maxLines: 2, textAlign: TextAlign.center, style: const TextStyle( color: Colors.black, fontSize: 17, fontWeight: FontWeight.bold, ), ), ); } Widget _getNoplan(){ return RotatedBox( quarterTurns: 1, child: Text( '未 建 计 划', textAlign: TextAlign.center, style: const TextStyle( color: Colors.black, fontSize: 17, fontWeight: FontWeight.bold, ), ), ); } Widget _getNum(String num){ return RotatedBox( quarterTurns: 1, child: Text( num, textAlign: TextAlign.center, style: const TextStyle( color: Colors.black, fontSize: 17, fontWeight: FontWeight.bold, ), ), ); } Widget _getChannel(String channel){ return RotatedBox( quarterTurns: 1, child: Text( channel, maxLines: 2, style: const TextStyle( color: Colors.black, fontSize: 13, ), ), ); } Widget _getCode(String code){ return RotatedBox( quarterTurns: 1, child: Text( code, style: const TextStyle( color: Colors.black, fontSize: 20, fontWeight: FontWeight.bold), ), ); } Widget _getBarCode(String code){ return RotatedBox( quarterTurns: 1, child: BarcodeWidget( barcode: Barcode.code128(), data: code, style: TextStyle( fontSize: 10 ), ), ); } Widget _getCard(String code, String channel, String country, String countStr, int offset, bool hasPlan) { return RotatedBox( quarterTurns: 3, child: Text( code, style: const TextStyle( color: Colors.black, fontSize: 15, ), ), ); Container( //margin: EdgeInsets.all(5), width: 700 / 3.7, height: 950 / 3.7, // decoration: BoxDecoration( // color: Colors.white, // border: Border.all(color: Colors.black, width: 0.5)), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( width: 197 / 3.7, height: 950 / 3.7, // decoration: BoxDecoration( // color: Colors.white, // border: Border( // right: BorderSide( // color: Colors.black, // width: 0.5, // )), // ), alignment: Alignment.center, child: RotatedBox( quarterTurns: 3, child: Text( code, style: TextStyle( color: Colors.black, fontSize: 20, fontWeight: FontWeight.bold), ), ), ), Container( width: 215 / 3.7, height: 950 / 3.7, // decoration: BoxDecoration( // border: Border( // right: BorderSide( // color: Colors.black, // width: 0.5, // )), // ), alignment: Alignment.center, // child: Column( // children: [ // Container( // width: 215 / 3.7, // height: 950 / 3.7 / 3, // decoration: BoxDecoration( // border: Border( // bottom: BorderSide( // color: Colors.black, // width: 0.5, // )), // ), // alignment: Alignment.center, // child: RotatedBox( // quarterTurns: 3, // child: Text( // country, // style: TextStyle( // color: Colors.black, // fontSize: 17, // fontWeight: FontWeight.bold), // ), // ), // ), // Container( // width: 215 / 3.7, // height: 950 / 3.7 / 3 * 2 - 4, // padding: EdgeInsets.symmetric(vertical: 10), // alignment: Alignment.center, // child: RotatedBox( // quarterTurns: 3, // child: Text( // channel, // style: TextStyle( // color: Colors.black, // fontSize: 15, // ), // ), // ), // ) // ], // ) ), Container( width: 358 / 3.7 -30, height: 950 / 3.7, alignment: Alignment.center, child: Column( children: [ // Container( // width: 358 / 3.7 -20, // height: 950 / 3.7 / 3, // decoration: BoxDecoration( // border: Border( // bottom: BorderSide( // color: Colors.black, // width: 0.5, // )), // ), // alignment: Alignment.center, // child: RotatedBox( // quarterTurns: 3, // child: Text( // countStr, // style: TextStyle( // color: Colors.black, // fontSize: 17, // fontWeight: FontWeight.bold), // ), // ), // ), // Container( // width: 358 / 3.7 -30, // height: 950 / 3.7 / 3 * 2 - 1.5, // padding: EdgeInsets.only(left: 15,top: 15,bottom: 15,right: 10) , // child: RotatedBox( // quarterTurns: 3, // child: BarcodeWidget( // // barcode: Barcode.code128(), // data: code, // style: TextStyle( // fontSize: 10 // ), // ), // ), // ) ], )), ], ), ); } }