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 createState() => _InvoiceDetailScreenState(); } class _InvoiceDetailScreenState extends State { bool loading = true; Map invoice = {}; @override void initState() { super.initState(); load(); } Future 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 _scanFile(String path) async { try { await _mediaScanner.invokeMethod('scanFile', {'path': path}); } catch (e) { debugPrint("❌ MediaScanner error: $e"); } } Future _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), ), ); } }