Skip to content

Instantly share code, notes, and snippets.

@lukaspili
Created June 17, 2021 13:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lukaspili/3452095688971497cebd0ba6a54c511a to your computer and use it in GitHub Desktop.
Save lukaspili/3452095688971497cebd0ba6a54c511a to your computer and use it in GitHub Desktop.
import 'dart:io';
import 'package:esc_pos_printer/esc_pos_printer.dart';
import 'package:esc_pos_utils/esc_pos_utils.dart';
import 'package:flutter/services.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:image/image.dart' as image;
import 'package:mimosushi_forecast/data/data.dart';
import 'package:mimosushi_forecast/presentation/presentation.dart';
import 'package:ping_discover_network/ping_discover_network.dart';
import 'package:wifi_info_flutter/wifi_info_flutter.dart';
part 'printer_repository.freezed.dart';
@freezed
abstract class PrinterRepositoryData with _$PrinterRepositoryData {
const factory PrinterRepositoryData({
@nullable Printer printer,
@Default(const []) List<Printer> printers,
@Default(const Task.idle()) Task searchTask,
@Default(const Task.idle()) Task printTask,
}) = _PrinterRepositoryData;
}
class PrinterRepository extends StateNotifier<PrinterRepositoryData> {
static final pod = StateNotifierProvider((ref) => PrinterRepository(ref.read));
static final _port = 9100;
// static final _port = 1400;
PrinterRepository(this.read) : super(const PrinterRepositoryData());
final Reader read;
final WifiInfo wifiInfo = WifiInfo();
void search() async {
if (state.searchTask is Loading) return;
final permission = await wifiInfo.requestLocationServiceAuthorization(requestAlwaysLocationUsage: false);
if (permission != LocationAuthorizationStatus.authorizedWhenInUse && permission != LocationAuthorizationStatus.authorizedAlways) {
state = state.copyWith(
searchTask: const Task.failed(AppError.fetchFailed('You must accept location permission to search printers on Wifi')),
);
return;
}
state = state.copyWith(searchTask: const Task.loading());
final ip = await wifiInfo.getWifiIP();
if (ip.isBlank || ip == 'error') {
state = state.copyWith(
searchTask: const Task.failed(AppError.fetchFailed('Not connected to Wifi')),
);
return;
}
debugPrint('[search printers] local ip: ${ip}');
final printers = <Printer>[];
try {
final subnet = ip.substring(0, ip.lastIndexOf('.'));
final stream = NetworkAnalyzer.discover2(subnet, _port);
await stream.forEach((address) async {
if (address.exists) {
// addresses.add(address.ip);
String name;
try {
final internetAddress = await InternetAddress(address.ip).reverse();
name = internetAddress.host.isNotBlank ? internetAddress.host : null;
} catch (e) {}
printers.add(Printer(
name: name.isNotBlank ? name : '',
ip: address.ip,
));
}
});
} catch (e) {
state = state.copyWith(
searchTask: const Task.failed(AppError.fetchFailed('Failed to scan local network')),
);
}
debugPrint('[search printers] results: ${printers}');
state = state.copyWith(
printers: printers,
searchTask: const Task.successful(),
);
}
void select(Printer printer) {
state = state.copyWith(printer: printer);
// read(AutomaticPrintService.pod).printActiveForecast();
}
Future<bool> printForecast(Forecast forecast) async {
if (state.printer == null) {
state = state.copyWith(printTask: Task.failed(AppError('Aucune imprimante connectée')));
return false;
}
if (state.printTask is Loading) {
state = state.copyWith(printTask: Task.failed(AppError('Une impression est déjà en cours')));
return false;
}
final paper = PaperSize.mm80;
final profile = await CapabilityProfile.load();
final printer = NetworkPrinter(paper, profile);
try {
final PosPrintResult connection = await printer.connect(state.printer.ip, port: _port);
debugPrint('[print] connection to printer: ${connection.msg}');
if (connection != PosPrintResult.success) {
state = state.copyWith(printTask: Task.failed(AppError.operationFailed(connection.msg)));
return false;
}
state = state.copyWith(printTask: const Task.loading());
if (!Configuration.skipPrinting) {
final data = await rootBundle.load(Assets.printer.logoPrint.path);
final bytes = data.buffer.asUint8List();
printer.image(image.decodeImage(bytes));
printer.text(
'MIMO SUSHI FORECAST',
styles: PosStyles(
align: PosAlign.center,
height: PosTextSize.size2,
width: PosTextSize.size2,
),
linesAfter: 1,
);
printer.text(
Format.forecastPrintDate(forecast.date),
styles: const PosStyles(align: PosAlign.center),
);
printer.text(
Format.servingPeriod(forecast.servingPeriod),
styles: const PosStyles(align: PosAlign.center, bold: true),
linesAfter: 1,
);
printer.hr();
forecast.products.forEach((fProduct) {
printer.row([
PosColumn(
text: fProduct.product.name,
width: 10,
styles: const PosStyles(width: PosTextSize.size2),
),
PosColumn(
text: fProduct.quantity.toString(),
width: 2,
styles: const PosStyles(width: PosTextSize.size2, align: PosAlign.right),
),
]);
});
printer.hr();
printer.feed(1);
printer.cut();
}
debugPrint('[print] finished');
} catch (e, s) {
debugPrint('[print] error: ${e}');
debugPrint('[print] error: ${s}');
state = state.copyWith(printTask: Task.failed(AppError.operationFailed(e.toString())));
return false;
} finally {
try {
await printer.disconnect();
} catch (e, s) {
debugPrint('[print] disconnect error: ${e}');
debugPrint('[print] disconnect error: ${s}');
}
}
await read(AutomaticPrintService.pod).markForecastPrinted(forecast);
state = state.copyWith(printTask: const Task.successful());
return true;
}
void resetPrintTask() {
state = state.copyWith(printTask: const Task.idle());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment