print images
parent
fd4168b614
commit
a45bbc03c3
|
|
@ -34,7 +34,7 @@ if (keystorePropertiesFile.exists()) {
|
|||
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
compileSdkVersion 30
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
|
|
@ -46,8 +46,8 @@ android {
|
|||
|
||||
defaultConfig {
|
||||
applicationId "kz.com.aman.kassa"
|
||||
minSdkVersion 18
|
||||
targetSdkVersion 29
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
|
|
@ -0,0 +1,6 @@
|
|||
class SettingModel {
|
||||
const SettingModel({this.name, this.type, this.address});
|
||||
final String type;
|
||||
final String name;
|
||||
final String address;
|
||||
}
|
||||
|
|
@ -5,4 +5,8 @@ const String PaymentViewRoute = "PaymentView";
|
|||
const String HistoryViewRoute = "HistoryView";
|
||||
const String InfoKkmViewRoute = "InfoKkmViewRoute";
|
||||
const String QrViewRoute = "QrViewRoute";
|
||||
|
||||
|
||||
const String SettingsPrinterRoute = "SettingsPrinterRoute";
|
||||
const String SettingsPrinterBTRoute = "SettingsPrinterBTRoute";
|
||||
// Generate the views here
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import 'package:aman_kassa_flutter/views/history/history_view.dart';
|
|||
import 'package:aman_kassa_flutter/views/info_kkm/info_kkm_view.dart';
|
||||
import 'package:aman_kassa_flutter/views/payment/payment_view.dart';
|
||||
import 'package:aman_kassa_flutter/views/qr_view/qr_view.dart';
|
||||
import 'package:aman_kassa_flutter/views/settings/printer/PrinterSelect.dart';
|
||||
import 'package:aman_kassa_flutter/views/settings/setting_printer_view.dart';
|
||||
|
||||
import './route_names.dart';
|
||||
import 'package:aman_kassa_flutter/views/home/home_view.dart';
|
||||
|
|
@ -51,6 +53,16 @@ Route<dynamic> generateRoute(RouteSettings settings) {
|
|||
routeName: settings.name,
|
||||
viewToShow: ImageShowContainer(data),
|
||||
);
|
||||
case SettingsPrinterRoute:
|
||||
return _getPageRoute(
|
||||
routeName: settings.name,
|
||||
viewToShow: SettingPrinterView(),
|
||||
);
|
||||
case SettingsPrinterBTRoute:
|
||||
return _getPageRoute(
|
||||
routeName: settings.name,
|
||||
viewToShow: PrinterSelectView(),
|
||||
);
|
||||
default:
|
||||
return MaterialPageRoute(
|
||||
builder: (_) => Scaffold(
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@ class MainApplication extends StatelessWidget {
|
|||
primaryColor: primaryColor,
|
||||
accentColor: yellowColor,
|
||||
scaffoldBackgroundColor: Colors.white,
|
||||
textTheme: GoogleFonts.latoTextTheme(
|
||||
Theme.of(context).textTheme,
|
||||
)
|
||||
// textTheme: GoogleFonts.latoTextTheme(
|
||||
// Theme.of(context).textTheme,
|
||||
// )
|
||||
),
|
||||
debugShowCheckedModeBanner: false,
|
||||
builder: (context, child) => Navigator(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import 'package:aman_kassa_flutter/redux/state/setting_state.dart';
|
|||
import 'package:meta/meta.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'package:redux_thunk/redux_thunk.dart';
|
||||
|
||||
import 'package:flutter_bluetooth_basic/src/bluetooth_device.dart';
|
||||
import '../store.dart';
|
||||
|
||||
@immutable
|
||||
|
|
@ -23,4 +23,10 @@ ThunkAction<AppState> changeTradeTypeFromSetting(String tradeType) {
|
|||
return (Store<AppState> store) async {
|
||||
store.dispatch(SetSettingStateAction(SettingState(tradeType: tradeType )));
|
||||
};
|
||||
}
|
||||
|
||||
ThunkAction<AppState> selectPrinterFromSetting(BluetoothDevice device) {
|
||||
return (Store<AppState> store) async {
|
||||
store.dispatch(SetSettingStateAction(SettingState(printerBT: device )));
|
||||
};
|
||||
}
|
||||
|
|
@ -3,4 +3,5 @@ const String SettingModeCalc = 'calcMode';
|
|||
|
||||
|
||||
const String SettingTradeTypeGood = 'g';
|
||||
const String SettingTradeTypeService = 's';
|
||||
const String SettingTradeTypeService = 's';
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ settingReducer(SettingState prevState, SetSettingStateAction action) {
|
|||
final payload = action.settingState;
|
||||
return prevState.copyWith(
|
||||
mode: payload.mode,
|
||||
tradeType: payload.tradeType
|
||||
tradeType: payload.tradeType,
|
||||
printerBT: payload.printerBT
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,35 @@
|
|||
import 'package:aman_kassa_flutter/redux/constants/setting_const.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:flutter_bluetooth_basic/src/bluetooth_device.dart';
|
||||
|
||||
|
||||
@immutable
|
||||
class SettingState {
|
||||
final String mode;
|
||||
final String tradeType;
|
||||
final BluetoothDevice printerBT;
|
||||
|
||||
SettingState({this.mode, this.tradeType});
|
||||
SettingState({this.mode, this.tradeType, this.printerBT});
|
||||
|
||||
//read hive
|
||||
factory SettingState.initial(SettingState payload) {
|
||||
return SettingState(
|
||||
mode: payload?.mode ?? SettingModeKassa,
|
||||
tradeType: payload?.tradeType ?? SettingTradeTypeGood);
|
||||
tradeType: payload?.tradeType ?? SettingTradeTypeGood,
|
||||
printerBT: payload?.printerBT ?? null
|
||||
);
|
||||
}
|
||||
|
||||
//write hive
|
||||
SettingState copyWith({
|
||||
@required mode,
|
||||
@required tradeType,
|
||||
@required printerBT,
|
||||
}) {
|
||||
return SettingState(
|
||||
mode: mode ?? this.mode,
|
||||
tradeType: tradeType ?? this.tradeType,
|
||||
printerBT: printerBT ?? this.printerBT
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -31,11 +38,16 @@ class SettingState {
|
|||
? SettingState(
|
||||
tradeType: json['tradeType'],
|
||||
mode: json['mode'],
|
||||
printerBT: json['printerBT']!=null ? BluetoothDevice.fromJson(json['printerBT']) : null
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
dynamic toJson() {
|
||||
return {"tradeType": tradeType, "mode": mode};
|
||||
return {
|
||||
"tradeType": tradeType,
|
||||
"mode": mode,
|
||||
"printerBT": printerBT !=null ? printerBT.toJson() : null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,15 @@ import 'package:aman_kassa_flutter/core/models/dialog_models.dart';
|
|||
import 'package:aman_kassa_flutter/core/route_names.dart';
|
||||
import 'package:aman_kassa_flutter/core/services/dialog_service.dart';
|
||||
import 'package:aman_kassa_flutter/core/services/navigator_service.dart';
|
||||
import 'package:aman_kassa_flutter/redux/store.dart';
|
||||
import 'package:aman_kassa_flutter/shared/app_colors.dart';
|
||||
import 'package:aman_kassa_flutter/shared/ui_helpers.dart';
|
||||
import 'package:aman_kassa_flutter/views/settings/printer/PrinterTest.dart';
|
||||
import 'package:aman_kassa_flutter/widgets/fields/busy_button_icon.dart';
|
||||
import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart';
|
||||
import 'package:esc_pos_utils/esc_pos_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bluetooth_basic/flutter_bluetooth_basic.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
import 'package:esys_flutter_share/esys_flutter_share.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
|
@ -59,9 +64,18 @@ class _MyFloatingActionButtonState extends State<MyFloatingActionButton> {
|
|||
bool showFab = true;
|
||||
DialogService _dialog = locator<DialogService>();
|
||||
NavigatorService _navigatorService = locator<NavigatorService>();
|
||||
PrinterBluetoothManager printerManager = PrinterBluetoothManager();
|
||||
final DialogService _dialogService = locator<DialogService>();
|
||||
BluetoothDevice printerBtDevice = Redux.store.state.settingState.printerBT;
|
||||
|
||||
double sheetHeight = 260;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if ( printerBtDevice != null){
|
||||
sheetHeight = 340;
|
||||
}
|
||||
|
||||
return showFab
|
||||
? FloatingActionButton(
|
||||
child: Icon(Icons.share),
|
||||
|
|
@ -79,7 +93,7 @@ class _MyFloatingActionButtonState extends State<MyFloatingActionButton> {
|
|||
color: Colors.grey[300],
|
||||
spreadRadius: 5)
|
||||
]),
|
||||
height: 260,
|
||||
height: sheetHeight,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
verticalSpaceSmall,
|
||||
|
|
@ -102,9 +116,17 @@ class _MyFloatingActionButtonState extends State<MyFloatingActionButton> {
|
|||
BusyButtonIcon(
|
||||
title: 'Поделиться',
|
||||
onPressed: shareFile,
|
||||
mainColor: yellowColor,
|
||||
mainColor: redColor,
|
||||
icon: Icons.share,
|
||||
),
|
||||
verticalSpaceSmall,
|
||||
BusyButtonIcon(
|
||||
title: 'Печать',
|
||||
onPressed: printFile,
|
||||
mainColor: primaryColor,
|
||||
icon: Icons.print,
|
||||
),
|
||||
|
||||
],
|
||||
)));
|
||||
showFoatingActionButton(false);
|
||||
|
|
@ -125,6 +147,23 @@ class _MyFloatingActionButtonState extends State<MyFloatingActionButton> {
|
|||
}
|
||||
}
|
||||
|
||||
void printFile() async {
|
||||
Navigator.of(context).pop(false);
|
||||
|
||||
printerManager.selectPrinter(PrinterBluetooth(Redux.store.state.settingState.printerBT));
|
||||
// TODO Don't forget to choose printer's paper
|
||||
const PaperSize paper = PaperSize.mm58;
|
||||
final PosPrintResult res =
|
||||
await printerManager.printTicket(
|
||||
await printImageCheck(paper,widget.data.data ),
|
||||
chunkSizeBytes: 3096,
|
||||
queueSleepTimeMs: 50
|
||||
);
|
||||
if(res.value != 1) {
|
||||
_dialogService.showDialog(description: res.msg);
|
||||
}
|
||||
}
|
||||
|
||||
void qrGenerate() async {
|
||||
_navigatorService.push(QrViewRoute,
|
||||
arguments:
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ const List<Choice> choices = const <Choice>[
|
|||
//const Choice(title: 'Помощь', icon: Icons.help, command: 'help'),
|
||||
const Choice(
|
||||
title: 'Информация о ККМ', icon: Icons.info_outline, command: 'infokkm'),
|
||||
//const Choice(title: 'Язык', icon: Icons.language, command: 'language'),
|
||||
const Choice(title: 'Принтер', icon: Icons.print, command: 'print'),
|
||||
const Choice(title: 'Выйти', icon: Icons.exit_to_app, command: 'exit')
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ class _HomeViewState extends State<HomeView> {
|
|||
Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();
|
||||
} else if (choice.command == 'infokkm') {
|
||||
_navigatorService.push(InfoKkmViewRoute);
|
||||
} else if (choice.command == 'print') {
|
||||
_navigatorService.push(SettingsPrinterRoute);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class SettingItem extends StatefulWidget {
|
||||
|
||||
final String name;
|
||||
final String value;
|
||||
final String title;
|
||||
final Function onTap;
|
||||
|
||||
SettingItem({Key key, this.name, this.value, this.onTap, this.title }) : super(key: key);
|
||||
|
||||
@override
|
||||
_SettingItemState createState() => _SettingItemState();
|
||||
}
|
||||
|
||||
class _SettingItemState extends State<SettingItem> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
child: ListTile(
|
||||
title: Text(widget.title),
|
||||
subtitle: Text.rich(
|
||||
TextSpan(
|
||||
text: widget.name,
|
||||
style: TextStyle(fontWeight: FontWeight.w500),
|
||||
children: <TextSpan>[
|
||||
if(widget.value !=null)
|
||||
TextSpan(text: ' ${widget.value}', style: TextStyle(fontStyle: FontStyle.italic)),
|
||||
],
|
||||
)
|
||||
),
|
||||
trailing: Icon(Icons.chevron_right),
|
||||
onTap: widget.onTap,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,324 @@
|
|||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:aman_kassa_flutter/core/logger.dart';
|
||||
import 'package:aman_kassa_flutter/redux/actions/setting_actions.dart';
|
||||
import 'package:aman_kassa_flutter/redux/store.dart';
|
||||
|
||||
import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart';
|
||||
import 'package:esc_pos_utils/esc_pos_utils.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart' hide Image;
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
|
||||
import 'package:flutter_bluetooth_basic/flutter_bluetooth_basic.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
|
||||
import 'PrinterTest.dart';
|
||||
|
||||
|
||||
class PrinterSelectView extends StatefulWidget {
|
||||
PrinterSelectView({Key key, this.title}) : super(key: key);
|
||||
final String title;
|
||||
|
||||
@override
|
||||
_PrinterSelectViewState createState() => _PrinterSelectViewState();
|
||||
|
||||
}
|
||||
|
||||
class _PrinterSelectViewState extends State<PrinterSelectView> {
|
||||
PrinterBluetoothManager printerManager = PrinterBluetoothManager();
|
||||
List<PrinterBluetooth> _devices = [];
|
||||
Logger _logger = getLogger('PrinterSelectView');
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
printerManager.scanResults.listen((devices) async {
|
||||
// print('UI: Devices found ${devices.length}');
|
||||
setState(() {
|
||||
_devices = devices;
|
||||
});
|
||||
});
|
||||
_startScanDevices();
|
||||
}
|
||||
|
||||
void _startScanDevices() {
|
||||
setState(() {
|
||||
_devices = [];
|
||||
});
|
||||
printerManager.startScan(Duration(seconds: 4));
|
||||
}
|
||||
|
||||
void _stopScanDevices() {
|
||||
printerManager.stopScan();
|
||||
}
|
||||
|
||||
Future<Ticket> demoReceipt(PaperSize paper) async {
|
||||
final Ticket ticket = Ticket(paper, );
|
||||
|
||||
// Print image
|
||||
// final ByteData data = await rootBundle.load('assets/images/aman_kassa_check.png');
|
||||
// final Uint8List bytes = data.buffer.asUint8List();
|
||||
// final Im.Image image = Im.decodeImage(bytes);
|
||||
// Im.Image thumbnail = Im.copyResize(image, width: 270);
|
||||
// ticket.image(thumbnail, align: PosAlign.center);
|
||||
|
||||
//ticket.imageRaster(image, align: PosAlign.center);
|
||||
|
||||
ticket.text('AMAN-SATU',
|
||||
styles: PosStyles(
|
||||
align: PosAlign.center,
|
||||
height: PosTextSize.size2,
|
||||
width: PosTextSize.size2,
|
||||
),
|
||||
linesAfter: 1);
|
||||
|
||||
ticket.text('889 Watson Lane', styles: PosStyles(align: PosAlign.center));
|
||||
ticket.text('Русский язык', styles: PosStyles(align: PosAlign.center, codeTable: PosCodeTable.westEur), containsChinese: true);
|
||||
ticket.text('Русский язык', styles: PosStyles(align: PosAlign.center, fontType: PosFontType.fontA), containsChinese: true);
|
||||
ticket.text('Русский язык', styles: PosStyles(align: PosAlign.center, fontType: PosFontType.fontB), containsChinese: true);
|
||||
ticket.text('Русский язык', styles: PosStyles(align: PosAlign.center, height: PosTextSize.size1), containsChinese: true);
|
||||
ticket.text('Русский язык', styles: PosStyles(align: PosAlign.center, width: PosTextSize.size2), containsChinese: true);
|
||||
ticket.text('Русский язык', styles: PosStyles(align: PosAlign.center, width: PosTextSize.size3), containsChinese: true);
|
||||
ticket.text('Русский язык', styles: PosStyles(align: PosAlign.center, width: PosTextSize.size4), containsChinese: true);
|
||||
ticket.text('Tel: 830-221-1234', styles: PosStyles(align: PosAlign.center));
|
||||
ticket.text('Web: www.example.com',
|
||||
styles: PosStyles(align: PosAlign.center), linesAfter: 1);
|
||||
|
||||
ticket.hr();
|
||||
ticket.row([
|
||||
PosColumn(text: 'Qty', width: 1),
|
||||
PosColumn(text: 'Item', width: 7),
|
||||
PosColumn(
|
||||
text: 'Price', width: 2, styles: PosStyles(align: PosAlign.right)),
|
||||
PosColumn(
|
||||
text: 'Total', width: 2, styles: PosStyles(align: PosAlign.right)),
|
||||
]);
|
||||
|
||||
ticket.row([
|
||||
PosColumn(text: '2', width: 1),
|
||||
PosColumn(text: 'ONION RINGS', width: 7),
|
||||
PosColumn(
|
||||
text: '0.99', width: 2, styles: PosStyles(align: PosAlign.right)),
|
||||
PosColumn(
|
||||
text: '1.98', width: 2, styles: PosStyles(align: PosAlign.right)),
|
||||
]);
|
||||
ticket.row([
|
||||
PosColumn(text: '1', width: 1),
|
||||
PosColumn(text: 'PIZZA', width: 7),
|
||||
PosColumn(
|
||||
text: '3.45', width: 2, styles: PosStyles(align: PosAlign.right)),
|
||||
PosColumn(
|
||||
text: '3.45', width: 2, styles: PosStyles(align: PosAlign.right)),
|
||||
]);
|
||||
ticket.row([
|
||||
PosColumn(text: '1', width: 1),
|
||||
PosColumn(text: 'SPRING ROLLS', width: 7),
|
||||
PosColumn(
|
||||
text: '2.99', width: 2, styles: PosStyles(align: PosAlign.right)),
|
||||
PosColumn(
|
||||
text: '2.99', width: 2, styles: PosStyles(align: PosAlign.right)),
|
||||
]);
|
||||
ticket.row([
|
||||
PosColumn(text: '3', width: 1),
|
||||
PosColumn(text: 'CRUNCHY STICKS', width: 7),
|
||||
PosColumn(
|
||||
text: '0.85', width: 2, styles: PosStyles(align: PosAlign.right)),
|
||||
PosColumn(
|
||||
text: '2.55', width: 2, styles: PosStyles(align: PosAlign.right)),
|
||||
]);
|
||||
ticket.hr();
|
||||
|
||||
ticket.row([
|
||||
PosColumn(
|
||||
text: 'TOTAL',
|
||||
width: 6,
|
||||
styles: PosStyles(
|
||||
height: PosTextSize.size2,
|
||||
width: PosTextSize.size2,
|
||||
)),
|
||||
PosColumn(
|
||||
text: '\$10.97',
|
||||
width: 6,
|
||||
styles: PosStyles(
|
||||
align: PosAlign.right,
|
||||
height: PosTextSize.size2,
|
||||
width: PosTextSize.size2,
|
||||
)),
|
||||
]);
|
||||
|
||||
ticket.hr(ch: '=', linesAfter: 1);
|
||||
|
||||
ticket.row([
|
||||
PosColumn(
|
||||
text: 'Cash',
|
||||
width: 7,
|
||||
styles: PosStyles(align: PosAlign.right, width: PosTextSize.size2)),
|
||||
PosColumn(
|
||||
text: '\$15.00',
|
||||
width: 5,
|
||||
styles: PosStyles(align: PosAlign.right, width: PosTextSize.size2)),
|
||||
]);
|
||||
ticket.row([
|
||||
PosColumn(
|
||||
text: 'Change',
|
||||
width: 7,
|
||||
styles: PosStyles(align: PosAlign.right, width: PosTextSize.size2)),
|
||||
PosColumn(
|
||||
text: '\$4.03',
|
||||
width: 5,
|
||||
styles: PosStyles(align: PosAlign.right, width: PosTextSize.size2)),
|
||||
]);
|
||||
|
||||
ticket.feed(2);
|
||||
ticket.text('Thank you!',
|
||||
styles: PosStyles(align: PosAlign.center, bold: true));
|
||||
|
||||
final now = DateTime.now();
|
||||
final formatter = DateFormat('MM/dd/yyyy H:m');
|
||||
final String timestamp = formatter.format(now);
|
||||
ticket.text(timestamp,
|
||||
styles: PosStyles(align: PosAlign.center), linesAfter: 2);
|
||||
|
||||
// Print QR Code from image
|
||||
// try {
|
||||
// const String qrData = 'example.com';
|
||||
// const double qrSize = 200;
|
||||
// final uiImg = await QrPainter(
|
||||
// data: qrData,
|
||||
// version: QrVersions.auto,
|
||||
// gapless: false,
|
||||
// ).toImageData(qrSize);
|
||||
// final dir = await getTemporaryDirectory();
|
||||
// final pathName = '${dir.path}/qr_tmp.png';
|
||||
// final qrFile = File(pathName);
|
||||
// final imgFile = await qrFile.writeAsBytes(uiImg.buffer.asUint8List());
|
||||
// final img = decodeImage(imgFile.readAsBytesSync());
|
||||
|
||||
// ticket.image(img);
|
||||
// } catch (e) {
|
||||
// print(e);
|
||||
// }
|
||||
|
||||
// Print QR Code using native function
|
||||
// ticket.qrcode('example.com');
|
||||
|
||||
ticket.feed(2);
|
||||
ticket.cut();
|
||||
return ticket;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _selectPrinter(PrinterBluetooth printer, BuildContext context, ) async {
|
||||
printerManager.selectPrinter(printer);
|
||||
_logger.i(printer.name);
|
||||
_logger.i(printer.address);
|
||||
|
||||
BluetoothDevice device = new BluetoothDevice()
|
||||
..address = printer.address
|
||||
..name=printer.name
|
||||
..type=printer.type;
|
||||
|
||||
await Redux.store.dispatch(selectPrinterFromSetting(device));
|
||||
Navigator.of(context).pop(false);
|
||||
}
|
||||
|
||||
void _testPrint(PrinterBluetooth printer) async {
|
||||
printerManager.selectPrinter(printer);
|
||||
|
||||
// TODO Don't forget to choose printer's paper
|
||||
const PaperSize paper = PaperSize.mm58;
|
||||
|
||||
// TEST PRINT
|
||||
// final PosPrintResult res =
|
||||
// await printerManager.printTicket(await testTicket(paper), queueSleepTimeMs: 50);
|
||||
|
||||
final PosPrintResult res =
|
||||
await printerManager.printTicket(
|
||||
await testTicketImage(paper),
|
||||
chunkSizeBytes: 1024,
|
||||
queueSleepTimeMs: 50
|
||||
);
|
||||
|
||||
// DEMO RECEIPT
|
||||
// final PosPrintResult res =
|
||||
// await printerManager.printTicket(await demoReceipt(paper) , queueSleepTimeMs: 50);
|
||||
|
||||
}
|
||||
|
||||
final key = GlobalKey();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RepaintBoundary(
|
||||
key: key,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Выберите принтер'),
|
||||
),
|
||||
body: ListView.builder(
|
||||
itemCount: _devices.length,
|
||||
itemBuilder: (BuildContext _, int index) {
|
||||
return InkWell(
|
||||
onTap: () => _selectPrinter(_devices[index], context),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
height: 60,
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(Icons.print),
|
||||
SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(_devices[index].name ?? ''),
|
||||
Text(_devices[index].address),
|
||||
Text(
|
||||
'Click to print a test receipt',
|
||||
style: TextStyle(color: Colors.grey[700]),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Divider(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
floatingActionButton: StreamBuilder<bool>(
|
||||
stream: printerManager.isScanningStream,
|
||||
initialData: false,
|
||||
builder: (c, snapshot) {
|
||||
if (snapshot.data) {
|
||||
return FloatingActionButton(
|
||||
child: Icon(Icons.stop),
|
||||
onPressed: _stopScanDevices,
|
||||
backgroundColor: Colors.red,
|
||||
);
|
||||
} else {
|
||||
return FloatingActionButton(
|
||||
child: Icon(Icons.search),
|
||||
onPressed: _startScanDevices,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:esc_pos_utils/esc_pos_utils.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:image/image.dart' as Im;
|
||||
|
||||
Future<Ticket> testTicket(PaperSize paper) async {
|
||||
final Ticket ticket = Ticket(paper);
|
||||
|
||||
//Uint8List encTxt11 = await CharsetConverter.encode("cp866", "Russian: Привет Мир!");
|
||||
//ticket.textEncoded(encTxt11, styles: PosStyles(codeTable: PosCodeTable.pc866_2));
|
||||
//ticket.textEncoded(encTxt11);
|
||||
|
||||
// ticket.text('Special 1: àÀ', styles: PosStyles(codeTable: PosCodeTable.westEur)); //А
|
||||
// ticket.text('Special 1: á'.toUpperCase(), styles: PosStyles(codeTable: PosCodeTable.westEur));// Б
|
||||
// ticket.text('Special 1: â', styles: PosStyles(codeTable: PosCodeTable.westEur)); //В
|
||||
// ticket.text('Special 1: ã', styles: PosStyles(codeTable: PosCodeTable.westEur));// Г
|
||||
// ticket.text('Special 1: äÄ', styles: PosStyles(codeTable: PosCodeTable.westEur)); //Д
|
||||
// ticket.text('Special 1: å', styles: PosStyles(codeTable: PosCodeTable.westEur));// Е
|
||||
// ticket.text('Special 1: æÆ', styles: PosStyles(codeTable: PosCodeTable.westEur));// Ж
|
||||
// ticket.text('Special 1: ç', styles: PosStyles(codeTable: PosCodeTable.westEur));//З
|
||||
// ticket.text('Special 1: èÈ', styles: PosStyles(codeTable: PosCodeTable.westEur)); // И
|
||||
// ticket.text('Special 1: éÉ', styles: PosStyles(codeTable: PosCodeTable.westEur)); // Й
|
||||
// ticket.text('Special 1: ê', styles: PosStyles(codeTable: PosCodeTable.westEur));//К
|
||||
// ticket.text('Special 1: ëË', styles: PosStyles(codeTable: PosCodeTable.westEur)); // Л
|
||||
// ticket.text('Special 1: ìÌ', styles: PosStyles(codeTable: PosCodeTable.westEur));// M
|
||||
// ticket.text('Special 1: íÍ', styles: PosStyles(codeTable: PosCodeTable.westEur)); // Н
|
||||
// ticket.text('Special 1: î', styles: PosStyles(codeTable: PosCodeTable.westEur));// О
|
||||
// ticket.text('Special 1: ï', styles: PosStyles(codeTable: PosCodeTable.westEur)); // П
|
||||
// ticket.text('Special 1: ð', styles: PosStyles(codeTable: PosCodeTable.westEur));// Р
|
||||
// ticket.text('Special 1: ñ', styles: PosStyles(codeTable: PosCodeTable.westEur));// С
|
||||
// ticket.text('Special 1: ò', styles: PosStyles(codeTable: PosCodeTable.westEur)); // Т
|
||||
// ticket.text('Special 1: óÓ', styles: PosStyles(codeTable: PosCodeTable.westEur)); //У
|
||||
// ticket.text('Special 1: ô', styles: PosStyles(codeTable: PosCodeTable.westEur));// Ф
|
||||
// ticket.text('Special 1: õÕ', styles: PosStyles(codeTable: PosCodeTable.westEur));// Х
|
||||
// ticket.text('Special 1: ö', styles: PosStyles(codeTable: PosCodeTable.westEur)); //Ц
|
||||
// ticket.text('Special 1: ÷', styles: PosStyles(codeTable: PosCodeTable.westEur)); //Ч
|
||||
// ticket.text('Special 1: ø', styles: PosStyles(codeTable: PosCodeTable.westEur));//Ш
|
||||
// ticket.text('Special 1: ù', styles: PosStyles(codeTable: PosCodeTable.westEur)); //Щ
|
||||
// ticket.text('Special 1: ú', styles: PosStyles(codeTable: PosCodeTable.westEur));//Ъ
|
||||
// ticket.text('Special 1: û', styles: PosStyles(codeTable: PosCodeTable.westEur));//Ы
|
||||
// ticket.text('Special 1: üÜ', styles: PosStyles(codeTable: PosCodeTable.westEur)); //Ь
|
||||
// ticket.text('Special 1: ý', styles: PosStyles(codeTable: PosCodeTable.westEur)); //Э
|
||||
// ticket.text('Special 1: þ', styles: PosStyles(codeTable: PosCodeTable.westEur)); // ю
|
||||
// ticket.text('Special 1: ÿß', styles: PosStyles(codeTable: PosCodeTable.westEur)); //Я
|
||||
|
||||
// Uint8List encTxt11 = await CharsetConverter.encode("cp866", "Russian: Привет Мир!");
|
||||
// //ticket.textEncoded(encTxt11, styles: PosStyles(codeTable: PosCodeTable.pc866_2));
|
||||
// ticket.textEncoded(encTxt11);
|
||||
|
||||
ticket.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');
|
||||
//ticket.text('Special 1: àÀ èÈ éÉ ûÛ üÜ çÇ ôÔ', styles: PosStyles(codeTable: PosCodeTable.westEur));
|
||||
//ticket.text('Special 2: blåbærgrød', styles: PosStyles(codeTable: PosCodeTable.westEur));
|
||||
|
||||
ticket.text('Bold text', styles: PosStyles(bold: true));
|
||||
ticket.text('Reverse text', styles: PosStyles(reverse: true));
|
||||
ticket.text('Underlined text',
|
||||
styles: PosStyles(underline: true), linesAfter: 1);
|
||||
ticket.text('Align left', styles: PosStyles(align: PosAlign.left));
|
||||
ticket.text('Align center', styles: PosStyles(align: PosAlign.center));
|
||||
ticket.text('Align right',
|
||||
styles: PosStyles(align: PosAlign.right), linesAfter: 1);
|
||||
|
||||
ticket.row([
|
||||
PosColumn(
|
||||
text: 'col3',
|
||||
width: 3,
|
||||
styles: PosStyles(align: PosAlign.center, underline: true),
|
||||
),
|
||||
PosColumn(
|
||||
text: 'col6',
|
||||
width: 6,
|
||||
styles: PosStyles(align: PosAlign.center, underline: true),
|
||||
),
|
||||
PosColumn(
|
||||
text: 'col3',
|
||||
width: 3,
|
||||
styles: PosStyles(align: PosAlign.center, underline: true),
|
||||
),
|
||||
]);
|
||||
|
||||
ticket.text('Text size 200%',
|
||||
styles: PosStyles(
|
||||
height: PosTextSize.size2,
|
||||
width: PosTextSize.size2,
|
||||
));
|
||||
|
||||
// Print image
|
||||
//final ByteData data = await rootBundle.load('assets/images/logo.png');
|
||||
//final Uint8List bytes = data.buffer.asUint8List();
|
||||
// Print image using alternative commands
|
||||
// ticket.imageRaster(image);
|
||||
// ticket.imageRaster(image, imageFn: PosImageFn.graphics);
|
||||
|
||||
// Print barcode
|
||||
final List<int> barData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 4];
|
||||
ticket.barcode(Barcode.upcA(barData));
|
||||
|
||||
|
||||
|
||||
ticket.feed(2);
|
||||
|
||||
ticket.cut();
|
||||
return ticket;
|
||||
}
|
||||
|
||||
Future<Ticket> testTicketImage(PaperSize paper) async {
|
||||
final Ticket ticket = Ticket(paper);
|
||||
|
||||
// Print image
|
||||
final ByteData byteData = await rootBundle.load('assets/images/check.png');
|
||||
final Uint8List bytes = byteData.buffer.asUint8List();
|
||||
final Im.Image imagea = Im.decodeImage(bytes);
|
||||
// Using `ESC *`
|
||||
//ticket.image(imagea);
|
||||
// Using `GS v 0` (obsolete)
|
||||
//ticket.imageRaster(imagea);
|
||||
// Using `GS ( L`
|
||||
ticket.imageRaster(imagea, imageFn: PosImageFn.bitImageRaster);
|
||||
|
||||
|
||||
|
||||
ticket.feed(2);
|
||||
|
||||
ticket.cut();
|
||||
return ticket;
|
||||
}
|
||||
|
||||
Future<Ticket> printImageCheck(PaperSize paper, String base64Src) async {
|
||||
final Ticket ticket = Ticket(paper);
|
||||
final Uint8List bytes = base64Decode(base64Src);
|
||||
final Im.Image image = Im.decodeImage(bytes);
|
||||
ticket.imageRaster(image, imageFn: PosImageFn.bitImageRaster);
|
||||
ticket.feed(2);
|
||||
ticket.cut();
|
||||
return ticket;
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:aman_kassa_flutter/core/locator.dart';
|
||||
import 'package:aman_kassa_flutter/core/route_names.dart';
|
||||
import 'package:aman_kassa_flutter/core/services/dialog_service.dart';
|
||||
import 'package:aman_kassa_flutter/core/services/navigator_service.dart';
|
||||
import 'package:aman_kassa_flutter/redux/state/setting_state.dart';
|
||||
import 'package:aman_kassa_flutter/redux/store.dart';
|
||||
import 'package:aman_kassa_flutter/shared/app_colors.dart';
|
||||
import 'package:aman_kassa_flutter/widgets/fields/aman_icon_button_horizontal.dart';
|
||||
import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart';
|
||||
import 'package:esc_pos_utils/esc_pos_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:aman_kassa_flutter/views/settings/printer/PrinterTest.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
|
||||
import 'component/setting_item.dart';
|
||||
|
||||
class SettingPrinterView extends StatefulWidget {
|
||||
@override
|
||||
_SettingPrinterViewState createState() => _SettingPrinterViewState();
|
||||
}
|
||||
|
||||
class _SettingPrinterViewState extends State<SettingPrinterView> {
|
||||
NavigatorService _navigatorService = locator<NavigatorService>();
|
||||
final DialogService _dialogService = locator<DialogService>();
|
||||
PrinterBluetoothManager printerManager = PrinterBluetoothManager();
|
||||
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
||||
void _testPrint() async {
|
||||
printerManager.selectPrinter(PrinterBluetooth(Redux.store.state.settingState.printerBT));
|
||||
// TODO Don't forget to choose printer's paper
|
||||
const PaperSize paper = PaperSize.mm58;
|
||||
final PosPrintResult res =
|
||||
await printerManager.printTicket(
|
||||
await testTicketImage(paper),
|
||||
chunkSizeBytes: 3096,
|
||||
queueSleepTimeMs: 50
|
||||
);
|
||||
_dialogService.showDialog(description: res.msg);
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Настройка принтера'),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: StoreConnector<AppState, SettingState>(
|
||||
converter: (store) => store.state.settingState,
|
||||
builder: (context, vm) {
|
||||
return Column(
|
||||
children: [
|
||||
SettingItem(
|
||||
title: 'Принтер',
|
||||
name: vm.printerBT?.name,
|
||||
value: vm.printerBT != null
|
||||
? 'BT: ${vm.printerBT.address} '
|
||||
: 'не выбран',
|
||||
onTap: () {
|
||||
_navigatorService.push(SettingsPrinterBTRoute);
|
||||
}),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 24.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
AmanIconButtonHorizontal(
|
||||
icon: Icons.local_printshop_outlined,
|
||||
title: 'Напечатать тестовую страницу',
|
||||
activeColor: primaryColor,
|
||||
selected: vm.printerBT != null,
|
||||
onPressed: () {
|
||||
_testPrint();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
105
pubspec.lock
105
pubspec.lock
|
|
@ -1,6 +1,20 @@
|
|||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
archive:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.13"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.6.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -43,6 +57,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0-nullsafety.1"
|
||||
charset_converter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: charset_converter
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -71,6 +92,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
csslib:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: csslib
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.16.2"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -99,6 +127,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.5"
|
||||
esc_pos_bluetooth:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: esc_pos_bluetooth
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.8"
|
||||
esc_pos_utils:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: esc_pos_utils
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.6"
|
||||
esys_flutter_share:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -139,6 +181,13 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_bluetooth_basic:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_bluetooth_basic
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.5"
|
||||
flutter_redux:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -163,6 +212,13 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
gbk_codec:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: gbk_codec
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.2"
|
||||
get_it:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -177,6 +233,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
hex:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: hex
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.2"
|
||||
html:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: html
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.14.0+4"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -191,6 +261,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.4"
|
||||
image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.19"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -198,6 +275,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.16.1"
|
||||
json_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: json_annotation
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
logger:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -289,6 +373,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.9.2"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: petitparser
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -373,6 +464,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
rxdart:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: rxdart
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.23.1"
|
||||
shared_preferences:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -553,6 +651,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.2"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.5.1"
|
||||
sdks:
|
||||
dart: ">=2.10.2 <2.11.0"
|
||||
flutter: ">=1.22.2 <2.0.0"
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ dependencies:
|
|||
qr_flutter: ^3.2.0
|
||||
mask_text_input_formatter: ^1.2.1
|
||||
flutter_screenutil: ^2.3.1
|
||||
esc_pos_bluetooth: ^0.2.8
|
||||
flutter_bluetooth_basic: ^0.1.5
|
||||
esc_pos_utils: ^0.3.6 # no edit for esc_pos_bluetooth: ^0.2.8
|
||||
charset_converter: ^1.0.3
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
|
@ -40,8 +44,7 @@ flutter:
|
|||
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
assets:
|
||||
- assets/images/logo.png
|
||||
- assets/images/icon_large.png
|
||||
- assets/images/
|
||||
- assets/lang/en.json
|
||||
- assets/lang/ru.json
|
||||
- assets/google_fonts/
|
||||
|
|
|
|||
Loading…
Reference in New Issue