import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'enums/multi_byte_encoding.dart'; import 'enums/printer_alignment.dart'; import 'enums/serial_flow_control.dart'; import 'enums/serial_parity.dart'; import 'enums/serial_stop_bits.dart'; import 'models/printer_exception.dart'; import 'printer_platform_interface.dart'; /// An implementation of [PrinterPlatform] that uses method channels. class MethodChannelPrinter extends PrinterPlatform { /// The method channel used to interact with the native platform. @visibleForTesting final methodChannel = const MethodChannel('printer'); @override Future getPlatformVersion() async { final version = await methodChannel.invokeMethod( 'getPlatformVersion', ); return version; } @override Future openComPort({ required String portName, required int baudRate, int dataBits = 8, SerialParity parity = SerialParity.none, SerialStopBits stopBits = SerialStopBits.one, SerialFlowControl flowControl = SerialFlowControl.none, bool autoReplyMode = true, }) async { try { final result = await methodChannel.invokeMethod('openComPort', { 'portName': portName, 'baudRate': baudRate, 'dataBits': dataBits, 'parity': parity.value, 'stopBits': stopBits.value, 'flowControl': flowControl.value, 'autoReplyMode': autoReplyMode ? 1 : 0, }); return result!; } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to open COM port', details: e.details, ); } } @override Future openUsbPort({ required String portName, bool autoReplyMode = true, }) async { try { final result = await methodChannel.invokeMethod('openUsbPort', { 'portName': portName, 'autoReplyMode': autoReplyMode ? 1 : 0, }); return result!; } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to open USB port', details: e.details, ); } } @override Future closePort(int handle) async { try { final result = await methodChannel.invokeMethod( 'closePort', {'handle': handle}, ); return result ?? false; } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to close port', details: e.details, ); } } @override Future isPortOpened(int handle) async { try { final result = await methodChannel.invokeMethod( 'isPortOpened', {'handle': handle}, ); return result ?? false; } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to check port status', details: e.details, ); } } @override Future> enumComPorts() async { try { final result = await methodChannel.invokeMethod('enumComPorts'); return (result ?? []).map((e) => e.toString()).toList(); } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to enumerate COM ports', details: e.details, ); } } @override Future> enumUsbPorts() async { try { final result = await methodChannel.invokeMethod('enumUsbPorts'); return (result ?? []).map((e) => e.toString()).toList(); } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to enumerate USB ports', details: e.details, ); } } /// Sets the printer to multi-byte encoding mode. @override Future setMultiByteMode(int handle) async { try { final result = await methodChannel.invokeMethod( 'setMultiByteMode', {'handle': handle}, ); return result ?? false; } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to set multi-byte mode', details: e.details, ); } } /// Sets the multi-byte character encoding. @override Future setMultiByteEncoding(int handle, MultiByteEncoding encoding) async { try { final result = await methodChannel.invokeMethod( 'setMultiByteEncoding', {'handle': handle, 'encoding': encoding.value}, ); return result ?? false; } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to set multi-byte encoding', details: e.details, ); } } /// Prints text using UTF-8 encoding. @override Future printText(int handle, String text) async { try { final result = await methodChannel.invokeMethod( 'printText', {'handle': handle, 'text': text}, ); return result ?? false; } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to print text', details: e.details, ); } } /// Sets text alignment. @override Future setAlignment(int handle, PrinterAlignment alignment) async { try { final result = await methodChannel.invokeMethod( 'setAlignment', {'handle': handle, 'alignment': alignment.value}, ); return result ?? false; } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to set alignment', details: e.details, ); } } /// Sets text scale (width and height magnification). @override Future setTextScale(int handle, {required int widthScale, required int heightScale}) async { try { final result = await methodChannel.invokeMethod( 'setTextScale', { 'handle': handle, 'widthScale': widthScale, 'heightScale': heightScale, }, ); return result ?? false; } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to set text scale', details: e.details, ); } } /// Sets text bold on or off. @override Future setTextBold(int handle, bool bold) async { try { final result = await methodChannel.invokeMethod( 'setTextBold', {'handle': handle, 'bold': bold ? 1 : 0}, ); return result ?? false; } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to set text bold', details: e.details, ); } } /// Sets text underline level. @override Future setTextUnderline(int handle, int underline) async { try { final result = await methodChannel.invokeMethod( 'setTextUnderline', {'handle': handle, 'underline': underline}, ); return result ?? false; } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to set text underline', details: e.details, ); } } /// Feeds paper by specified number of lines. @override Future feedLine(int handle, int numLines) async { try { final result = await methodChannel.invokeMethod( 'feedLine', {'handle': handle, 'numLines': numLines}, ); return result ?? false; } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to feed line', details: e.details, ); } } /// Feeds paper by specified number of dots. @override Future feedDot(int handle, int numDots) async { try { final result = await methodChannel.invokeMethod( 'feedDot', {'handle': handle, 'numDots': numDots}, ); return result ?? false; } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to feed dot', details: e.details, ); } } /// Performs a half cut of the paper. @override Future halfCutPaper(int handle) async { try { final result = await methodChannel.invokeMethod( 'halfCutPaper', {'handle': handle}, ); return result ?? false; } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to half cut paper', details: e.details, ); } } /// Performs a full cut of the paper. @override Future fullCutPaper(int handle) async { try { final result = await methodChannel.invokeMethod( 'fullCutPaper', {'handle': handle}, ); return result ?? false; } on PlatformException catch (e) { throw PrinterException( code: e.code, message: e.message ?? 'Failed to full cut paper', details: e.details, ); } } }