diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f8dee5d..60650de 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -8,6 +8,8 @@ PODS: - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS + - printing (1.0.0): + - Flutter - sqflite_darwin (0.0.4): - Flutter - FlutterMacOS @@ -17,6 +19,7 @@ DEPENDENCIES: - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - mobile_scanner (from `.symlinks/plugins/mobile_scanner/darwin`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - printing (from `.symlinks/plugins/printing/ios`) - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) EXTERNAL SOURCES: @@ -28,15 +31,18 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/mobile_scanner/darwin" path_provider_foundation: :path: ".symlinks/plugins/path_provider_foundation/darwin" + printing: + :path: ".symlinks/plugins/printing/ios" sqflite_darwin: :path: ".symlinks/plugins/sqflite_darwin/darwin" SPEC CHECKSUMS: Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 - flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13 - mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93 - path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 - sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 + flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12 + mobile_scanner: 77265f3dc8d580810e91849d4a0811a90467ed5e + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + printing: 233e1b73bd1f4a05615548e9b5a324c98588640b + sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e diff --git a/lib/core/services/print_service.dart b/lib/core/services/print_service.dart new file mode 100644 index 0000000..8f6c796 --- /dev/null +++ b/lib/core/services/print_service.dart @@ -0,0 +1,368 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:pdf/pdf.dart'; +import 'package:pdf/widgets.dart' as pw; +import 'package:printing/printing.dart'; + +/// Service for generating and printing warehouse export forms +class PrintService { + /// Generate and print a warehouse export form + static Future printWarehouseExport({ + required BuildContext context, + required String warehouseName, + required int productId, + required String productCode, + required String productName, + String? stageName, + required double passedKg, + required int passedPcs, + required double issuedKg, + required int issuedPcs, + String? responsibleName, + String? barcodeData, + }) async { + final pdf = pw.Document(); + + // Format current date + final dt = DateFormat('dd/MM/yyyy HH:mm').format(DateTime.now()); + + // Add page to PDF + pdf.addPage( + pw.Page( + pageFormat: PdfPageFormat.a4, + margin: const pw.EdgeInsets.all(12), + build: (pw.Context pdfContext) { + return pw.Container( + padding: const pw.EdgeInsets.all(12), + child: pw.Column( + crossAxisAlignment: pw.CrossAxisAlignment.start, + children: [ + // Title + pw.Center( + child: pw.Column( + children: [ + pw.Text( + 'PHIẾU XUẤT KHO', + style: pw.TextStyle( + fontSize: 20, + fontWeight: pw.FontWeight.bold, + ), + ), + pw.SizedBox(height: 8), + pw.Text( + 'Công ty TNHH Cơ Khí Chính Xác Minh Thư', + style: const pw.TextStyle(fontSize: 16), + ), + pw.SizedBox(height: 4), + pw.Text( + warehouseName, + style: const pw.TextStyle(fontSize: 14), + ), + pw.SizedBox(height: 4), + pw.Text( + 'Ngày: $dt', + style: pw.TextStyle( + fontSize: 12, + color: PdfColors.grey700, + ), + ), + ], + ), + ), + + pw.SizedBox(height: 16), + + // Product information box + pw.Container( + decoration: pw.BoxDecoration( + border: pw.Border.all(color: PdfColors.black, width: 0.5), + borderRadius: pw.BorderRadius.circular(8), + ), + padding: const pw.EdgeInsets.all(8), + child: pw.Column( + children: [ + pw.Row( + children: [ + pw.Expanded( + child: pw.Column( + crossAxisAlignment: pw.CrossAxisAlignment.start, + children: [ + pw.Text( + 'ProductId', + style: pw.TextStyle( + fontSize: 10, + color: PdfColors.grey700, + ), + ), + pw.SizedBox(height: 2), + pw.Text( + '$productId', + style: pw.TextStyle( + fontSize: 12, + fontWeight: pw.FontWeight.bold, + ), + ), + ], + ), + ), + pw.Expanded( + child: pw.Column( + crossAxisAlignment: pw.CrossAxisAlignment.start, + children: [ + pw.Text( + 'Mã sản phẩm', + style: pw.TextStyle( + fontSize: 10, + color: PdfColors.grey700, + ), + ), + pw.SizedBox(height: 2), + pw.Text( + productCode, + style: pw.TextStyle( + fontSize: 12, + fontWeight: pw.FontWeight.bold, + ), + ), + ], + ), + ), + ], + ), + pw.SizedBox(height: 8), + pw.Row( + children: [ + pw.Expanded( + child: pw.Column( + crossAxisAlignment: pw.CrossAxisAlignment.start, + children: [ + pw.Text( + 'Tên sản phẩm', + style: pw.TextStyle( + fontSize: 10, + color: PdfColors.grey700, + ), + ), + pw.SizedBox(height: 2), + pw.Text( + productName, + style: pw.TextStyle( + fontSize: 12, + fontWeight: pw.FontWeight.bold, + ), + ), + ], + ), + ), + pw.Expanded( + child: pw.Column( + crossAxisAlignment: pw.CrossAxisAlignment.start, + children: [ + pw.Text( + 'Công đoạn', + style: pw.TextStyle( + fontSize: 10, + color: PdfColors.grey700, + ), + ), + pw.SizedBox(height: 2), + pw.Text( + stageName ?? '-', + style: pw.TextStyle( + fontSize: 12, + fontWeight: pw.FontWeight.bold, + ), + ), + ], + ), + ), + ], + ), + ], + ), + ), + + pw.SizedBox(height: 12), + + // Quantities box + pw.Container( + decoration: pw.BoxDecoration( + border: pw.Border.all(color: PdfColors.black, width: 0.5), + borderRadius: pw.BorderRadius.circular(8), + ), + padding: const pw.EdgeInsets.all(8), + child: pw.Column( + crossAxisAlignment: pw.CrossAxisAlignment.start, + children: [ + pw.Text( + 'Số lượng:', + style: pw.TextStyle( + fontSize: 10, + color: PdfColors.grey700, + ), + ), + pw.SizedBox(height: 6), + pw.Table( + border: pw.TableBorder.all( + color: PdfColors.black, + width: 0.5, + ), + children: [ + // Header + pw.TableRow( + decoration: const pw.BoxDecoration( + color: PdfColors.grey300, + ), + children: [ + pw.Padding( + padding: const pw.EdgeInsets.all(8), + child: pw.Text( + 'Loại', + style: pw.TextStyle( + fontWeight: pw.FontWeight.bold, + ), + ), + ), + pw.Padding( + padding: const pw.EdgeInsets.all(8), + child: pw.Text( + 'KG', + style: pw.TextStyle( + fontWeight: pw.FontWeight.bold, + ), + ), + ), + pw.Padding( + padding: const pw.EdgeInsets.all(8), + child: pw.Text( + 'PCS', + style: pw.TextStyle( + fontWeight: pw.FontWeight.bold, + ), + ), + ), + ], + ), + // Passed quantity row + pw.TableRow( + children: [ + pw.Padding( + padding: const pw.EdgeInsets.all(8), + child: pw.Text('Hàng đạt'), + ), + pw.Padding( + padding: const pw.EdgeInsets.all(8), + child: pw.Text(passedKg.toStringAsFixed(2)), + ), + pw.Padding( + padding: const pw.EdgeInsets.all(8), + child: pw.Text('$passedPcs'), + ), + ], + ), + // Issued quantity row + pw.TableRow( + children: [ + pw.Padding( + padding: const pw.EdgeInsets.all(8), + child: pw.Text('Hàng lỗi'), + ), + pw.Padding( + padding: const pw.EdgeInsets.all(8), + child: pw.Text(issuedKg.toStringAsFixed(2)), + ), + pw.Padding( + padding: const pw.EdgeInsets.all(8), + child: pw.Text('$issuedPcs'), + ), + ], + ), + ], + ), + ], + ), + ), + + pw.SizedBox(height: 12), + + // Responsible person box + pw.Container( + decoration: pw.BoxDecoration( + border: pw.Border.all(color: PdfColors.black, width: 0.5), + borderRadius: pw.BorderRadius.circular(8), + ), + padding: const pw.EdgeInsets.all(8), + child: pw.Row( + children: [ + pw.Text( + 'Nhân viên kho: ', + style: pw.TextStyle( + fontSize: 10, + color: PdfColors.grey700, + ), + ), + pw.Text( + responsibleName ?? '-', + style: pw.TextStyle( + fontSize: 12, + fontWeight: pw.FontWeight.bold, + ), + ), + ], + ), + ), + + pw.SizedBox(height: 12), + + // Barcode section + if (barcodeData != null && barcodeData.isNotEmpty) + pw.Center( + child: pw.BarcodeWidget( + barcode: pw.Barcode.code128(), + data: barcodeData, + width: 200, + height: 60, + ), + ), + + pw.Spacer(), + + // Footer signature section + pw.Row( + mainAxisAlignment: pw.MainAxisAlignment.center, + children: [ + pw.Container( + width: 150, + child: pw.Column( + children: [ + pw.Text( + 'Người nhận', + style: pw.TextStyle( + fontSize: 10, + color: PdfColors.grey700, + ), + ), + pw.SizedBox(height: 40), + pw.Container( + height: 1, + color: PdfColors.grey700, + ), + ], + ), + ), + ], + ), + ], + ), + ); + }, + ), + ); + + // Show print preview dialog + await Printing.layoutPdf( + onLayout: (PdfPageFormat format) async => pdf.save(), + name: 'warehouse_export_${productCode}_${DateTime.now().millisecondsSinceEpoch}.pdf', + ); + } +} diff --git a/lib/docs/import.html b/lib/docs/import.html new file mode 100644 index 0000000..a842d75 --- /dev/null +++ b/lib/docs/import.html @@ -0,0 +1,106 @@ + + + + + Phiếu xuất kho + + + + +
+
+ + +
+ +

PHIẾU XUẤT KHO

+

Công ty TNHH Cơ Khí Chính Xác Minh Thư

+

${wareHouseText}

+
Ngày: ${dt}
+
+
+
ProductId
${productId}
+
Mã sản phẩm
${productCode}
+
+
+
Tên sản phẩm
${productName}
+
Công đoạn
${stageName || '-'}
+
+
+
+
Số lượng:
+ + + + + + + + + + + + + + + + +
LoạiKGPCS
Hàng đạt${Number(qty.passedKg || 0)}${Number(qty.passedPcs || 0)}
Hàng lỗi${Number(qty.issuedKg || 0)}${Number(qty.issuedPcs || 0)}
+
+
+
+
Nhân viên kho
${responsibleName || '-'}
+
+
+
+ ${barcodeDataUrl ? `Barcode` : ''} +
+ +
+ + + + \ No newline at end of file diff --git a/lib/features/products/presentation/pages/product_detail_page.dart b/lib/features/products/presentation/pages/product_detail_page.dart index 5a9a63d..d0989e4 100644 --- a/lib/features/products/presentation/pages/product_detail_page.dart +++ b/lib/features/products/presentation/pages/product_detail_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../../core/di/providers.dart'; +import '../../../../core/services/print_service.dart'; import '../../../users/domain/entities/user_entity.dart'; import '../../data/models/create_product_warehouse_request.dart'; import '../../domain/entities/product_stage_entity.dart'; @@ -118,21 +119,7 @@ class _ProductDetailPageState extends ConsumerState { return Scaffold( appBar: AppBar( - title: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - operationTitle, - style: textTheme.titleMedium, - ), - Text( - productName, - style: textTheme.bodySmall?.copyWith( - color: theme.colorScheme.onSurfaceVariant, - ), - ), - ], - ), + title: Text('${operationTitle} ${productName}'), actions: [ IconButton( icon: const Icon(Icons.refresh), @@ -149,6 +136,11 @@ class _ProductDetailPageState extends ConsumerState { selectedIndex: selectedIndex, theme: theme, ), + bottomNavigationBar: _buildBottomActionBar( + selectedStage: selectedStage, + stages: stages, + theme: theme, + ), ); } @@ -277,7 +269,7 @@ class _ProductDetailPageState extends ConsumerState { if (displayStages.isNotEmpty) Container( width: double.infinity, - padding: const EdgeInsets.all(16), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), decoration: BoxDecoration( color: theme.colorScheme.surfaceContainerHighest, border: Border( @@ -289,39 +281,6 @@ class _ProductDetailPageState extends ConsumerState { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - Text( - widget.stageId != null - ? 'Công đoạn' - : 'Công đoạn (${displayStages.length})', - style: theme.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.bold, - ), - ), - if (widget.stageId != null) ...[ - const Spacer(), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), - decoration: BoxDecoration( - color: theme.colorScheme.primaryContainer, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - 'ID: ${widget.stageId}', - style: theme.textTheme.bodySmall?.copyWith( - color: theme.colorScheme.onPrimaryContainer, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ], - ), - const SizedBox(height: 12), Wrap( spacing: 8, runSpacing: 8, @@ -376,43 +335,24 @@ class _ProductDetailPageState extends ConsumerState { padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - spacing: 16, + spacing: 8, children: [ // Stage header - _buildStageHeader(stageToShow, theme), - - _buildSectionCard( - theme: theme, - title: 'Thông tin công đoạn', - icon: Icons.info_outlined, - children: [ - _buildInfoRow('Mã sản phẩm', '${stageToShow.productId}'), - if (stageToShow.productStageId != null) - _buildInfoRow('Mã công đoạn', '${stageToShow.productStageId}'), - if (stageToShow.actionTypeId != null) - _buildInfoRow('Mã loại thao tác', '${stageToShow.actionTypeId}'), - _buildInfoRow('Tên công đoạn', stageToShow.displayName), - ], - ), - - // Current Quantity information - _buildSectionCard( - theme: theme, - title: 'Số lượng hiện tại', - icon: Icons.info_outlined, - children: [ - _buildInfoRow('Số lượng đạt', '${stageToShow.passedQuantity}'), - _buildInfoRow( - 'Khối lượng đạt', - '${stageToShow.passedQuantityWeight.toStringAsFixed(2)} kg', - ), - _buildInfoRow('Số lượng lỗi', '${stageToShow.issuedQuantity}'), - _buildInfoRow( - 'Khối lượng lỗi', - '${stageToShow.issuedQuantityWeight.toStringAsFixed(2)} kg', - ), - ], - ), + // _buildStageHeader(stageToShow, theme), + // + // _buildSectionCard( + // theme: theme, + // title: 'Thông tin công đoạn', + // icon: Icons.info_outlined, + // children: [ + // _buildInfoRow('Mã sản phẩm', '${stageToShow.productId}'), + // if (stageToShow.productStageId != null) + // _buildInfoRow('Mã công đoạn', '${stageToShow.productStageId}'), + // if (stageToShow.actionTypeId != null) + // _buildInfoRow('Mã loại thao tác', '${stageToShow.actionTypeId}'), + // _buildInfoRow('Tên công đoạn', stageToShow.displayName), + // ], + // ), // Add New Quantities section _buildSectionCard( @@ -462,6 +402,7 @@ class _ProductDetailPageState extends ConsumerState { }, theme: theme, ), + const SizedBox(height: 8), // All Employees Dropdown _buildUserDropdown( label: 'Nhân viên', @@ -476,30 +417,21 @@ class _ProductDetailPageState extends ConsumerState { ), ]), - // Action buttons - Row( - spacing: 12, + // Current Quantity information + _buildSectionCard( + theme: theme, + title: 'Số lượng hiện tại', + icon: Icons.info_outlined, children: [ - - Expanded( - child: OutlinedButton.icon( - onPressed: () => _printQuantities(stageToShow), - icon: const Icon(Icons.print), - label: const Text('In'), - style: OutlinedButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 16), - ), - ), + _buildInfoRow('Số lượng đạt', '${stageToShow.passedQuantity}'), + _buildInfoRow( + 'Khối lượng đạt', + '${stageToShow.passedQuantityWeight.toStringAsFixed(2)} kg', ), - Expanded( - child: FilledButton.icon( - onPressed: () => _addNewQuantities(stageToShow), - icon: const Icon(Icons.save), - label: const Text('Lưu'), - style: FilledButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 16), - ), - ), + _buildInfoRow('Số lượng lỗi', '${stageToShow.issuedQuantity}'), + _buildInfoRow( + 'Khối lượng lỗi', + '${stageToShow.issuedQuantityWeight.toStringAsFixed(2)} kg', ), ], ), @@ -513,14 +445,55 @@ class _ProductDetailPageState extends ConsumerState { ); } - void _printQuantities(ProductStageEntity stage) { - // TODO: Implement print functionality - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Tính năng in đang phát triển'), - duration: Duration(seconds: 2), - ), - ); + Future _printQuantities(ProductStageEntity stage) async { + // Get the current quantity values (entered by user or use current values) + final passedQuantity = int.tryParse(_passedQuantityController.text) ?? 0; + final passedWeight = double.tryParse(_passedWeightController.text) ?? 0.0; + final issuedQuantity = int.tryParse(_issuedQuantityController.text) ?? 0; + final issuedWeight = double.tryParse(_issuedWeightController.text) ?? 0.0; + + // Use entered values if available, otherwise use current stock values + final finalPassedPcs = passedQuantity > 0 ? passedQuantity : stage.passedQuantity; + final finalPassedKg = passedWeight > 0.0 ? passedWeight : stage.passedQuantityWeight; + final finalIssuedPcs = issuedQuantity > 0 ? issuedQuantity : stage.issuedQuantity; + final finalIssuedKg = issuedWeight > 0.0 ? issuedWeight : stage.issuedQuantityWeight; + + // Get responsible user name + final responsibleName = _selectedWarehouseUser != null + ? '${_selectedWarehouseUser!.name} ${_selectedWarehouseUser!.firstName}' + : null; + + // Generate barcode data (using product code or product ID) + final barcodeData = stage.productCode.isNotEmpty + ? stage.productCode + : 'P${stage.productId}'; + + try { + await PrintService.printWarehouseExport( + context: context, + warehouseName: widget.warehouseName, + productId: stage.productId, + productCode: stage.productCode, + productName: stage.productName, + stageName: stage.displayName, + passedKg: finalPassedKg, + passedPcs: finalPassedPcs, + issuedKg: finalIssuedKg, + issuedPcs: finalIssuedPcs, + responsibleName: responsibleName, + barcodeData: barcodeData, + ); + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error printing: ${e.toString()}'), + backgroundColor: Colors.red, + duration: const Duration(seconds: 3), + ), + ); + } + } } Future _addNewQuantities(ProductStageEntity stage) async { @@ -708,28 +681,11 @@ class _ProductDetailPageState extends ConsumerState { }) { return Card( child: Padding( - padding: const EdgeInsets.all(16), + padding: const EdgeInsets.all(8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, - spacing: 12, + spacing: 4, children: [ - Row( - children: [ - Icon( - icon, - size: 20, - color: theme.colorScheme.primary, - ), - const SizedBox(width: 8), - Text( - title, - style: theme.textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.bold, - ), - ), - ], - ), - const SizedBox(height: 16), ...children, ], ), @@ -921,4 +877,69 @@ class _ProductDetailPageState extends ConsumerState { } } + Widget? _buildBottomActionBar({ + required ProductStageEntity? selectedStage, + required List stages, + required ThemeData theme, + }) { + // Determine which stage to show + // When stageId is provided, use the filtered stage + final displayStages = widget.stageId != null + ? stages.where((stage) => stage.productStageId == widget.stageId).toList() + : stages; + + final stageToShow = widget.stageId != null && displayStages.isNotEmpty + ? displayStages.first + : selectedStage; + + // Don't show action bar if there's no stage to work with + if (stageToShow == null) { + return null; + } + + return Container( + decoration: BoxDecoration( + color: theme.colorScheme.surface, + boxShadow: [ + BoxShadow( + color: theme.colorScheme.shadow.withValues(alpha: 0.1), + blurRadius: 8, + offset: const Offset(0, -2), + ), + ], + ), + child: SafeArea( + top: false, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + spacing: 12, + children: [ + Expanded( + child: OutlinedButton.icon( + onPressed: () => _printQuantities(stageToShow), + icon: const Icon(Icons.print), + label: const Text('In'), + style: OutlinedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 16), + ), + ), + ), + Expanded( + child: FilledButton.icon( + onPressed: () => _addNewQuantities(stageToShow), + icon: const Icon(Icons.save), + label: const Text('Lưu'), + style: FilledButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 16), + ), + ), + ), + ], + ), + ), + ), + ); + } + } diff --git a/pubspec.lock b/pubspec.lock index 6ca6436..1ee0371 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -49,6 +49,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.13.0" + barcode: + dependency: transitive + description: + name: barcode + sha256: "7b6729c37e3b7f34233e2318d866e8c48ddb46c1f7ad01ff7bb2a8de1da2b9f4" + url: "https://pub.dev" + source: hosted + version: "2.2.9" + barcode_widget: + dependency: "direct main" + description: + name: barcode_widget + sha256: "6f2c5b08659b1a5f4d88d183e6007133ea2f96e50e7b8bb628f03266c3931427" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + bidi: + dependency: transitive + description: + name: bidi + sha256: "77f475165e94b261745cf1032c751e2032b8ed92ccb2bf5716036db79320637d" + url: "https://pub.dev" + source: hosted + version: "2.0.13" boolean_selector: dependency: transitive description: @@ -664,6 +688,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" path_provider: dependency: "direct main" description: @@ -712,6 +744,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + pdf: + dependency: "direct main" + description: + name: pdf + sha256: "28eacad99bffcce2e05bba24e50153890ad0255294f4dd78a17075a2ba5c8416" + url: "https://pub.dev" + source: hosted + version: "3.11.3" + pdf_widget_wrapper: + dependency: transitive + description: + name: pdf_widget_wrapper + sha256: c930860d987213a3d58c7ec3b7ecf8085c3897f773e8dc23da9cae60a5d6d0f5 + url: "https://pub.dev" + source: hosted + version: "1.0.4" petitparser: dependency: transitive description: @@ -752,6 +800,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.3" + printing: + dependency: "direct main" + description: + name: printing + sha256: "482cd5a5196008f984bb43ed0e47cbfdca7373490b62f3b27b3299275bf22a93" + url: "https://pub.dev" + source: hosted + version: "5.14.2" pub_semver: dependency: transitive description: @@ -768,6 +824,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.0" + qr: + dependency: transitive + description: + name: qr + sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445" + url: "https://pub.dev" + source: hosted + version: "3.0.2" riverpod: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index cd6bb8c..3657555 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,6 +36,11 @@ dependencies: cached_network_image: ^3.3.1 cupertino_icons: ^1.0.6 + # Printing & PDF + printing: ^5.13.4 + pdf: ^3.11.3 + barcode_widget: ^2.0.4 + dev_dependencies: flutter_test: sdk: flutter