Initial commit: Task Printout pdf
This commit is contained in:
@@ -13,6 +13,11 @@ import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter_quill/flutter_quill.dart' as quill;
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/services.dart' show rootBundle;
|
||||
import 'package:pdf/widgets.dart' as pw;
|
||||
import 'package:pdf/pdf.dart' as pdf;
|
||||
import 'package:printing/printing.dart';
|
||||
import '../../providers/supabase_provider.dart';
|
||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
import '../../providers/profile_provider.dart';
|
||||
@@ -334,17 +339,32 @@ class _TaskDetailScreenState extends ConsumerState<TaskDetailScreen>
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 8,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
Row(
|
||||
children: [
|
||||
_buildStatusChip(context, task, canUpdateStatus),
|
||||
_MetaBadge(label: 'Office', value: officeName),
|
||||
_MetaBadge(
|
||||
label: 'Task #',
|
||||
value: task.taskNumber ?? task.id,
|
||||
isMono: true,
|
||||
Expanded(
|
||||
child: Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 8,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
_buildStatusChip(context, task, canUpdateStatus),
|
||||
_MetaBadge(label: 'Office', value: officeName),
|
||||
_MetaBadge(
|
||||
label: 'Task #',
|
||||
value: task.taskNumber ?? task.id,
|
||||
isMono: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: 'Preview/print task',
|
||||
onPressed: () async {
|
||||
try {
|
||||
await _showPdfPreview(task, ticket, officeName);
|
||||
} catch (_) {}
|
||||
},
|
||||
icon: const Icon(Icons.print),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -2734,6 +2754,186 @@ class _TaskDetailScreenState extends ConsumerState<TaskDetailScreen>
|
||||
assignment.taskId == taskId && assignment.userId == profile.id,
|
||||
);
|
||||
}
|
||||
|
||||
Future<Uint8List> _buildTaskPdfBytes(
|
||||
Task task,
|
||||
Ticket? ticket,
|
||||
String officeName,
|
||||
pdf.PdfPageFormat format,
|
||||
) async {
|
||||
final logoData = await rootBundle.load('crmc_logo.png');
|
||||
final logoImage = pw.MemoryImage(logoData.buffer.asUint8List());
|
||||
final doc = pw.Document();
|
||||
final created = AppTime.formatDate(task.createdAt);
|
||||
|
||||
doc.addPage(
|
||||
pw.Page(
|
||||
pageFormat: format,
|
||||
margin: pw.EdgeInsets.all(28),
|
||||
build: (pw.Context ctx) {
|
||||
return pw.Column(
|
||||
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||
children: [
|
||||
pw.Row(
|
||||
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||
children: [
|
||||
pw.Container(
|
||||
width: 64,
|
||||
height: 64,
|
||||
child: pw.Image(logoImage),
|
||||
),
|
||||
pw.SizedBox(width: 12),
|
||||
pw.Expanded(
|
||||
child: pw.Column(
|
||||
crossAxisAlignment: pw.CrossAxisAlignment.center,
|
||||
children: [
|
||||
pw.Text(
|
||||
'Republic of the Philippines',
|
||||
textAlign: pw.TextAlign.center,
|
||||
),
|
||||
pw.Text(
|
||||
'Department of Health',
|
||||
textAlign: pw.TextAlign.center,
|
||||
),
|
||||
pw.Text(
|
||||
'Regional and Medical Center',
|
||||
textAlign: pw.TextAlign.center,
|
||||
),
|
||||
pw.SizedBox(height: 6),
|
||||
pw.Text(
|
||||
'Cotabato Regional and Medical Center',
|
||||
textAlign: pw.TextAlign.center,
|
||||
style: pw.TextStyle(fontWeight: pw.FontWeight.bold),
|
||||
),
|
||||
pw.Text(
|
||||
'Integrated Hospital Operations and Management Program',
|
||||
textAlign: pw.TextAlign.center,
|
||||
),
|
||||
pw.Text('(IHOMP)', textAlign: pw.TextAlign.center),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
pw.SizedBox(height: 12),
|
||||
pw.Center(
|
||||
child: pw.Text(
|
||||
'IT Job / Maintenance Request Form',
|
||||
style: pw.TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: pw.FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
pw.SizedBox(height: 12),
|
||||
pw.Row(
|
||||
children: [
|
||||
pw.Text('Task Number: ${task.taskNumber ?? task.id}'),
|
||||
pw.Spacer(),
|
||||
pw.Text('Filed At: $created'),
|
||||
],
|
||||
),
|
||||
pw.SizedBox(height: 8),
|
||||
pw.Row(
|
||||
children: [
|
||||
pw.Text('Service: ${task.title}'),
|
||||
pw.SizedBox(width: 12),
|
||||
pw.Text('Office: $officeName'),
|
||||
],
|
||||
),
|
||||
pw.SizedBox(height: 8),
|
||||
pw.Row(
|
||||
children: [
|
||||
pw.Text('Type: ${task.requestType ?? ''}'),
|
||||
pw.SizedBox(width: 12),
|
||||
pw.Text('Category: ${task.requestCategory ?? ''}'),
|
||||
],
|
||||
),
|
||||
pw.SizedBox(height: 12),
|
||||
pw.Text('Description:'),
|
||||
pw.SizedBox(height: 6),
|
||||
pw.Container(
|
||||
height: 80,
|
||||
decoration: pw.BoxDecoration(
|
||||
border: pw.Border(
|
||||
bottom: pw.BorderSide(
|
||||
width: 0.5,
|
||||
color: pdf.PdfColors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
pw.SizedBox(height: 12),
|
||||
pw.Row(
|
||||
children: [
|
||||
pw.Text('Requested By: ${task.requestedBy ?? ''}'),
|
||||
pw.Spacer(),
|
||||
pw.Text('Noted by Supervisor/Senior'),
|
||||
],
|
||||
),
|
||||
pw.SizedBox(height: 12),
|
||||
pw.Text('Action Taken:'),
|
||||
pw.SizedBox(height: 6),
|
||||
pw.Container(
|
||||
height: 80,
|
||||
decoration: pw.BoxDecoration(
|
||||
border: pw.Border(
|
||||
bottom: pw.BorderSide(
|
||||
width: 0.5,
|
||||
color: pdf.PdfColors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
pw.SizedBox(height: 12),
|
||||
pw.Row(
|
||||
children: [
|
||||
pw.Text('Performed By:'),
|
||||
pw.Spacer(),
|
||||
pw.Text('Received By: ___________________________'),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
return doc.save();
|
||||
}
|
||||
|
||||
Future<void> _showPdfPreview(
|
||||
Task task,
|
||||
Ticket? ticket,
|
||||
String officeName,
|
||||
) async {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
contentPadding: const EdgeInsets.all(8),
|
||||
content: SizedBox(
|
||||
width: 700,
|
||||
height: 900,
|
||||
child: PdfPreview(
|
||||
build: (format) => _buildTaskPdfBytes(
|
||||
task,
|
||||
ticket,
|
||||
officeName,
|
||||
format as pdf.PdfPageFormat,
|
||||
),
|
||||
allowPrinting: true,
|
||||
allowSharing: true,
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(),
|
||||
child: const Text('Close'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _MetaBadge extends StatelessWidget {
|
||||
|
||||
Reference in New Issue
Block a user