diff --git a/assets/fonts/NotoSans-Bold.ttf b/assets/fonts/NotoSans-Bold.ttf new file mode 100644 index 0000000..ec02e04 --- /dev/null +++ b/assets/fonts/NotoSans-Bold.ttf @@ -0,0 +1,2151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Page not found · GitHub · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+ + + +
+
+ +
+
+ 404 “This is not the web page you are looking for” + + + + + + + + + + + + +
+
+ +
+
+ +
+ + +
+
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + diff --git a/assets/fonts/NotoSans-Regular.ttf b/assets/fonts/NotoSans-Regular.ttf new file mode 100644 index 0000000..cbde792 --- /dev/null +++ b/assets/fonts/NotoSans-Regular.ttf @@ -0,0 +1,2151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Page not found · GitHub · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+ + + +
+
+ +
+
+ 404 “This is not the web page you are looking for” + + + + + + + + + + + + +
+
+ +
+
+ +
+ + +
+
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + diff --git a/lib/core/services/print_service.dart b/lib/core/services/print_service.dart index 8f6c796..e8570da 100644 --- a/lib/core/services/print_service.dart +++ b/lib/core/services/print_service.dart @@ -21,16 +21,25 @@ class PrintService { String? responsibleName, String? barcodeData, }) async { + // Load Vietnamese-compatible fonts using PdfGoogleFonts + // Noto Sans has excellent Vietnamese character support + final fontRegular = await PdfGoogleFonts.notoSansRegular(); + final fontBold = await PdfGoogleFonts.notoSansBold(); + final pdf = pw.Document(); // Format current date final dt = DateFormat('dd/MM/yyyy HH:mm').format(DateTime.now()); - // Add page to PDF + // Add page to PDF with theme for Vietnamese font support pdf.addPage( pw.Page( pageFormat: PdfPageFormat.a4, margin: const pw.EdgeInsets.all(12), + theme: pw.ThemeData.withFont( + base: fontRegular, + bold: fontBold, + ), build: (pw.Context pdfContext) { return pw.Container( padding: const pw.EdgeInsets.all(12), diff --git a/lib/features/products/presentation/pages/product_detail_page.dart b/lib/features/products/presentation/pages/product_detail_page.dart index e2ce5df..b4787c3 100644 --- a/lib/features/products/presentation/pages/product_detail_page.dart +++ b/lib/features/products/presentation/pages/product_detail_page.dart @@ -362,12 +362,7 @@ class _ProductDetailPageState extends ConsumerState { title: 'Thêm số lượng mới', icon: Icons.add_circle_outline, children: [ - _buildTextField( - label: 'Số lượng đạt', - controller: _passedQuantityController, - keyboardType: TextInputType.number, - theme: theme, - ), + _buildTextField( label: 'Khối lượng đạt (kg)', controller: _passedWeightController, @@ -375,8 +370,8 @@ class _ProductDetailPageState extends ConsumerState { theme: theme, ), _buildTextField( - label: 'Số lượng lỗi', - controller: _issuedQuantityController, + label: 'Số lượng đạt', + controller: _passedQuantityController, keyboardType: TextInputType.number, theme: theme, ), @@ -386,13 +381,20 @@ class _ProductDetailPageState extends ConsumerState { keyboardType: const TextInputType.numberWithOptions(decimal: true), theme: theme, ), + _buildTextField( + label: 'Số lượng lỗi', + controller: _issuedQuantityController, + keyboardType: TextInputType.number, + theme: theme, + ), + ], ), _buildSectionCard(theme: theme, title: "Nhân viên", icon: Icons.people, children: [ - // Warehouse User Dropdown + // Warehouse User Dropdown (Required) _buildUserDropdown( - label: 'Người dùng kho', + label: 'Người dùng kho *', value: _selectedWarehouseUser, users: ref.watch(usersListProvider) .where((user) => user.isWareHouseUser) @@ -405,9 +407,9 @@ class _ProductDetailPageState extends ConsumerState { theme: theme, ), const SizedBox(height: 8), - // All Employees Dropdown + // All Employees Dropdown (Required) _buildUserDropdown( - label: 'Nhân viên', + label: 'Nhân viên *', value: _selectedEmployee, users: ref.watch(usersListProvider), onChanged: (user) { @@ -448,6 +450,18 @@ class _ProductDetailPageState extends ConsumerState { } Future _printQuantities(ProductStageEntity stage) async { + // Validate that both users are selected + if (_selectedEmployee == null || _selectedWarehouseUser == null) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Vui lòng chọn cả Nhân viên và Người dùng kho trước khi in'), + backgroundColor: Colors.orange, + duration: Duration(seconds: 3), + ), + ); + return; + } + // 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; @@ -461,9 +475,7 @@ class _ProductDetailPageState extends ConsumerState { final finalIssuedKg = issuedWeight > 0.0 ? issuedWeight : stage.issuedQuantityWeight; // Get responsible user name - final responsibleName = _selectedWarehouseUser != null - ? '${_selectedWarehouseUser!.name} ${_selectedWarehouseUser!.firstName}' - : null; + final responsibleName = '${_selectedWarehouseUser!.name} ${_selectedWarehouseUser!.firstName}'; // Generate barcode data (using product code or product ID) final barcodeData = stage.productCode.isNotEmpty @@ -521,8 +533,9 @@ class _ProductDetailPageState extends ConsumerState { if (_selectedEmployee == null || _selectedWarehouseUser == null) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( - content: Text('Vui lòng chọn cả Nhân viên và Người dùng kho'), + content: Text('Vui lòng chọn cả Nhân viên và Người dùng kho trước khi lưu'), backgroundColor: Colors.orange, + duration: Duration(seconds: 3), ), ); return; diff --git a/pubspec.lock b/pubspec.lock index 692e771..bf07448 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -480,6 +480,14 @@ packages: url: "https://pub.dev" source: hosted version: "13.2.5" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: "517b20870220c48752eafa0ba1a797a092fb22df0d89535fd9991e86ee2cdd9c" + url: "https://pub.dev" + source: hosted + version: "6.3.2" graphs: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f2b1f5e..641f1ce 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,6 +41,7 @@ dependencies: printing: ^5.13.4 pdf: ^3.11.3 barcode_widget: ^2.0.4 + google_fonts: ^6.2.1 dev_dependencies: flutter_test: @@ -63,6 +64,7 @@ flutter: # Assets assets: - assets/app_icon.jpg + - assets/fonts/ # Flutter Launcher Icons Configuration flutter_launcher_icons: