Files
kent_logistics_app/lib/screens/invoice_detail_screen.dart
2025-12-23 11:44:56 +05:30

178 lines
4.6 KiB
Dart

import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:share_plus/share_plus.dart';
import '../config/api_config.dart';
import '../services/dio_client.dart';
import '../services/invoice_service.dart';
import '../widgets/invoice_detail_view.dart';
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));
try {
final res = await service.getInvoiceDetails(widget.invoiceId);
if (res['success'] == true) {
invoice = res['invoice'] ?? {};
} else {
invoice = {};
}
} catch (e) {
// handle error gracefully
invoice = {};
} finally {
if (mounted) setState(() => loading = false);
}
}
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");
}
}
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}");
}
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)}%",
);
}
},
);
// 🔔 VERY IMPORTANT: Notify Android system (same as chat)
await _scanFile(filePath);
debugPrint("✅ PDF Downloaded & Scanned Successfully");
return File(filePath);
} catch (e) {
debugPrint("❌ PDF download error: $e");
return null;
}
}
@override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
// ⭐ COMPACT RESPONSIVE SCALE
final scale = (width / 430).clamp(0.88, 1.08);
return Scaffold(
appBar: AppBar(
title: const Text("Invoice Details"),
actions: pdfUrl == null
? []
: [
// DOWNLOAD
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")),
);
}
},
),
// SHARE
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']}",
);
}
},
),
],
),
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,
),
),
)
: 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`.
child: InvoiceDetailView(invoice: invoice),
),
);
}
}