Files
kent_logistics_app/lib/screens/invoice_detail_screen.dart

179 lines
4.6 KiB
Dart
Raw Normal View History

2025-12-11 18:36:11 +05:30
import 'dart:io';
import 'package:dio/dio.dart';
2025-12-03 11:57:05 +05:30
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
2025-12-11 18:36:11 +05:30
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
2025-12-11 18:36:11 +05:30
import 'package:share_plus/share_plus.dart';
import '../config/api_config.dart';
2025-12-03 11:57:05 +05:30
import '../services/dio_client.dart';
import '../services/invoice_service.dart';
2025-12-11 18:36:11 +05:30
import '../widgets/invoice_detail_view.dart';
2025-12-03 11:57:05 +05:30
class InvoiceDetailScreen extends StatefulWidget {
final int invoiceId;
const InvoiceDetailScreen({super.key, required this.invoiceId});
@override
State<InvoiceDetailScreen> createState() => _InvoiceDetailScreenState();
}
class _InvoiceDetailScreenState extends State<InvoiceDetailScreen> {
bool loading = true;
Map invoice = {};
@override
void initState() {
super.initState();
load();
}
Future<void> load() async {
final service = InvoiceService(DioClient.getInstance(context));
2025-12-11 18:36:11 +05:30
try {
final res = await service.getInvoiceDetails(widget.invoiceId);
if (res['success'] == true) {
invoice = res['invoice'] ?? {};
} else {
invoice = {};
}
} catch (e) {
// handle error gracefully
2025-12-11 18:36:11 +05:30
invoice = {};
} finally {
if (mounted) setState(() => loading = false);
2025-12-03 11:57:05 +05:30
}
}
String? get pdfUrl {
final path = invoice['pdf_path'];
if (path == null || path.toString().isEmpty) return null;
return ApiConfig.fileBaseUrl + path;
}
static const MethodChannel _mediaScanner =
MethodChannel('media_scanner');
Future<void> _scanFile(String path) async {
try {
await _mediaScanner.invokeMethod('scanFile', {'path': path});
} catch (e) {
debugPrint("❌ MediaScanner error: $e");
}
}
2025-12-03 11:57:05 +05:30
Future<File?> _downloadPdf(String url) async {
try {
debugPrint("📥 PDF URL: $url");
final fileName = url.split('/').last;
// ✅ SAME FOLDER AS CHAT FILES
final baseDir = Directory('/storage/emulated/0/Download/KentChat');
if (!await baseDir.exists()) {
await baseDir.create(recursive: true);
debugPrint("📁 Created directory: ${baseDir.path}");
}
2025-12-03 11:57:05 +05:30
final filePath = "${baseDir.path}/$fileName";
debugPrint("📄 Saving PDF to: $filePath");
await Dio().download(
url,
filePath,
onReceiveProgress: (received, total) {
if (total > 0) {
debugPrint(
"⬇ Downloading: ${(received / total * 100).toStringAsFixed(1)}%",
);
}
},
2025-12-11 18:36:11 +05:30
);
2025-12-03 11:57:05 +05:30
// 🔔 VERY IMPORTANT: Notify Android system (same as chat)
await _scanFile(filePath);
2025-12-03 11:57:05 +05:30
debugPrint("✅ PDF Downloaded & Scanned Successfully");
2025-12-03 11:57:05 +05:30
return File(filePath);
} catch (e) {
debugPrint("❌ PDF download error: $e");
return null;
}
2025-12-11 18:36:11 +05:30
}
2025-12-03 11:57:05 +05:30
2025-12-11 18:36:11 +05:30
@override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
// ⭐ COMPACT RESPONSIVE SCALE
2025-12-11 18:36:11 +05:30
final scale = (width / 430).clamp(0.88, 1.08);
2025-12-03 11:57:05 +05:30
2025-12-11 18:36:11 +05:30
return Scaffold(
appBar: AppBar(
title: const Text("Invoice Details"),
actions: pdfUrl == null
? []
: [
// DOWNLOAD
2025-12-11 18:36:11 +05:30
IconButton(
icon: const Icon(Icons.download_rounded),
onPressed: () async {
final file = await _downloadPdf(pdfUrl!);
if (file != null && mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Invoice downloaded")),
);
}
},
2025-12-11 18:36:11 +05:30
),
// SHARE
2025-12-11 18:36:11 +05:30
IconButton(
icon: const Icon(Icons.share_rounded),
onPressed: () async {
final file = await _downloadPdf(pdfUrl!);
if (file != null) {
await Share.shareXFiles(
[XFile(file.path)],
text: "Invoice ${invoice['invoice_number']}",
);
}
},
2025-12-11 18:36:11 +05:30
),
],
),
2025-12-03 11:57:05 +05:30
2025-12-11 18:36:11 +05:30
body: loading
? const Center(child: CircularProgressIndicator())
: invoice.isEmpty
? Center(
child: Text(
"No Invoice Data Found",
style: TextStyle(
fontSize: 18 * scale,
fontWeight: FontWeight.w600,
color: Colors.black87,
),
2025-12-03 11:57:05 +05:30
),
2025-12-11 18:36:11 +05:30
)
: Padding(
padding: EdgeInsets.all(12 * scale),
// NOTE: InvoiceDetailView should handle its own responsiveness.
// If you want it to follow the same `scale`, I can update that widget to accept `scale`.
2025-12-11 18:36:11 +05:30
child: InvoiceDetailView(invoice: invoice),
2025-12-03 11:57:05 +05:30
),
);
}
}