Your changes

This commit is contained in:
divya abdar
2025-12-11 18:36:11 +05:30
parent 3bf27cc29d
commit 9faf983b95
36 changed files with 4677 additions and 1046 deletions

View File

@@ -1,6 +1,12 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:share_plus/share_plus.dart';
import '../services/dio_client.dart';
import '../services/invoice_service.dart';
import '../widgets/invoice_detail_view.dart';
class InvoiceDetailScreen extends StatefulWidget {
final int invoiceId;
@@ -20,149 +26,127 @@ class _InvoiceDetailScreenState extends State<InvoiceDetailScreen> {
load();
}
// -------------------------------------------------------
// ⭐ LOAD INVOICE FROM API
// -------------------------------------------------------
Future<void> load() async {
final service = InvoiceService(DioClient.getInstance(context));
final res = await service.getInvoiceDetails(widget.invoiceId);
try {
final res = await service.getInvoiceDetails(widget.invoiceId);
if (res['success'] == true) {
invoice = res['invoice'] ?? {};
if (res['success'] == true) {
invoice = res['invoice'] ?? {};
} else {
invoice = {};
}
} catch (e) {
invoice = {};
} finally {
if (mounted) setState(() => loading = false);
}
loading = false;
setState(() {});
}
/// ---------- REUSABLE ROW ----------
Widget row(String label, dynamic value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: const TextStyle(fontSize: 14, color: Colors.grey)),
Expanded(
child: Text(
value?.toString().isNotEmpty == true ? value.toString() : "N/A",
textAlign: TextAlign.end,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
),
// -------------------------------------------------------
// ⭐ GENERATE + SAVE PDF TO DOWNLOADS FOLDER
// (No Permission Needed)
// -------------------------------------------------------
Future<File> generatePDF() async {
final pdf = pw.Document();
pdf.addPage(
pw.Page(
build: (context) => pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
pw.Text(
"INVOICE DETAILS",
style: pw.TextStyle(fontSize: 26, fontWeight: pw.FontWeight.bold),
),
),
],
pw.SizedBox(height: 20),
pw.Text("Invoice ID: ${invoice['id'] ?? '-'}"),
pw.Text("Amount: ₹${invoice['amount'] ?? '-'}"),
pw.Text("Status: ${invoice['status'] ?? '-'}"),
pw.Text("Date: ${invoice['date'] ?? '-'}"),
pw.Text("Customer: ${invoice['customer_name'] ?? '-'}"),
],
),
),
);
// ⭐ SAFEST WAY (Android 1014)
final downloadsDir = await getDownloadsDirectory();
final filePath = "${downloadsDir!.path}/invoice_${invoice['id']}.pdf";
final file = File(filePath);
await file.writeAsBytes(await pdf.save());
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("PDF saved to Downloads:\n$filePath")),
);
}
return file;
}
// -------------------------------------------------------
// ⭐ SHARE THE SAVED PDF FILE
// -------------------------------------------------------
Future<void> sharePDF() async {
final file = await generatePDF();
await Share.shareXFiles(
[XFile(file.path)],
text: "Invoice Details",
);
}
@override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
final scale = (width / 430).clamp(0.88, 1.08);
return Scaffold(
appBar: AppBar(title: const Text("Invoice Details")),
appBar: AppBar(
title: Text(
"Invoice Details",
style: TextStyle(
fontSize: 18 * scale,
fontWeight: FontWeight.w600,
),
),
// ⭐ PDF + SHARE BUTTONS
actions: [
IconButton(
icon: const Icon(Icons.picture_as_pdf),
onPressed: generatePDF,
),
IconButton(
icon: const Icon(Icons.share),
onPressed: sharePDF,
),
],
),
body: loading
? const Center(child: CircularProgressIndicator())
/// ================ INVOICE DATA ================
: Padding(
padding: const EdgeInsets.all(16),
child: ListView(
children: [
/// -------- Invoice Summary --------
const Text(
"Invoice Summary",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
row("Invoice No", invoice['invoice_number']),
row("Invoice Date", invoice['invoice_date']),
row("Due Date", invoice['due_date']),
row("Status", invoice['status']),
const Divider(height: 30),
/// -------- Customer Details --------
const Text(
"Customer Details",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
row("Name", invoice['customer_name']),
row("Company", invoice['company_name']),
row("Email", invoice['customer_email']),
row("Mobile", invoice['customer_mobile']),
row("Address", invoice['customer_address']),
row("Pincode", invoice['pincode']),
const Divider(height: 30),
/// -------- Amounts & Taxes --------
const Text(
"Amounts",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
row("Final Amount", invoice['final_amount']),
row("Tax Type", invoice['tax_type']),
row("GST %", invoice['gst_percent']),
row("GST Amount", invoice['gst_amount']),
row("Final with GST", invoice['final_amount_with_gst']),
const Divider(height: 30),
/// -------- Payment Details --------
const Text(
"Payment Details",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
row("Payment Method", invoice['payment_method']),
row("Reference No", invoice['reference_no']),
row("Notes", invoice['notes']),
const Divider(height: 30),
/// -------- PDF --------
if (invoice['pdf_path'] != null)
ElevatedButton.icon(
icon: const Icon(Icons.picture_as_pdf),
label: const Text("Download PDF"),
onPressed: () {},
style:
ElevatedButton.styleFrom(backgroundColor: Colors.red),
),
const SizedBox(height: 20),
/// -------- Invoice Items --------
if (invoice['items'] != null)
const Text(
"Invoice Items",
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
...List.generate(invoice['items']?.length ?? 0, (i) {
final item = invoice['items'][i];
return Card(
child: ListTile(
title: Text(item['description'] ?? "Item"),
subtitle: Text("Qty: ${item['qty'] ?? 0}"),
trailing: Text(
"${item['ttl_amount'] ?? 0}",
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.indigo),
),
),
);
}),
],
: invoice.isEmpty
? Center(
child: Text(
"No Invoice Data Found",
style: TextStyle(
fontSize: 18 * scale,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
),
)
: Padding(
padding: EdgeInsets.all(12 * scale),
child: InvoiceDetailView(invoice: invoice),
),
);
}