cashumit/lib/widgets/invoice_preview_dialog.dart

152 lines
4.7 KiB
Dart

import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:open_file/open_file.dart';
import 'package:cashumit/services/invoice_image_service.dart';
import 'package:cashumit/services/media_store_service.dart';
/// Dialog preview gambar invoice. Tidak menyimpan file otomatis;
/// user menekan "Simpan" untuk menulis ke folder Download.
class InvoicePreviewDialog extends StatefulWidget {
final Uint8List bytes;
final String invoiceNumber;
const InvoicePreviewDialog({
super.key,
required this.bytes,
required this.invoiceNumber,
});
@override
State<InvoicePreviewDialog> createState() => _InvoicePreviewDialogState();
}
class _InvoicePreviewDialogState extends State<InvoicePreviewDialog> {
bool _saving = false;
InvoiceSaveResult? _saved;
Future<void> _save() async {
if (_saving) return;
setState(() => _saving = true);
final saved = await InvoiceImageService.saveBytes(
bytes: widget.bytes,
invoiceNumber: widget.invoiceNumber,
alsoSaveToDownloads: true,
);
if (!mounted) return;
setState(() {
_saving = false;
_saved = saved;
});
if (saved.downloadsDisplayPath != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Invoice tersimpan di ${saved.downloadsDisplayPath}')),
);
} else if (saved.localPath != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Invoice tersimpan: ${saved.localPath}')),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Gagal menyimpan invoice')),
);
}
}
Future<void> _openSaved() async {
final saved = _saved;
if (saved == null) return;
if (saved.downloadsUri != null) {
await MediaStoreService.openFile(uri: saved.downloadsUri);
} else if (saved.localPath != null) {
await OpenFile.open(saved.localPath!);
}
}
@override
Widget build(BuildContext context) {
return Dialog(
insetPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24),
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 460, maxHeight: 700),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(16, 12, 8, 8),
child: Row(
children: [
Expanded(
child: Text(
'Invoice ${widget.invoiceNumber}',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
IconButton(
icon: const Icon(Icons.close),
onPressed: () => Navigator.of(context).pop(),
),
],
),
),
const Divider(height: 1),
Expanded(
child: InteractiveViewer(
minScale: 0.5,
maxScale: 4.0,
child: Center(
child: Image.memory(
widget.bytes,
fit: BoxFit.contain,
),
),
),
),
const Divider(height: 1),
Padding(
padding: const EdgeInsets.all(12),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (_saved != null)
TextButton.icon(
onPressed: _openSaved,
icon: const Icon(Icons.open_in_new, size: 18),
label: const Text('Buka File'),
),
const SizedBox(width: 8),
ElevatedButton.icon(
onPressed: _saving ? null : _save,
icon: _saving
? const SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.white,
),
)
: const Icon(Icons.save_alt, size: 18),
label: Text(_saving ? 'Menyimpan...' : 'Simpan'),
),
const SizedBox(width: 8),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Tutup'),
),
],
),
),
],
),
),
);
}
}