// version: 1.0.1 (Stable Standalone Edition) import 'dart:io'; import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:pdf/widgets.dart' as pw; import 'package:path_provider/path_provider.dart'; import 'package:crypto/crypto.dart'; import 'package:intl/intl.dart'; void main() => runApp(const MaterialApp(home: InvoiceApp())); class InvoiceApp extends StatefulWidget { const InvoiceApp({super.key}); @override State createState() => _InvoiceAppState(); } class _InvoiceAppState extends State { final _clientController = TextEditingController(text: "現場太郎 様"); final _amountController = TextEditingController(text: "1500"); // 10%抜き単価 String _status = "内容を入力してPDFを発行してください"; Future _generateInvoice() async { final pdf = pw.Document(); final clientName = _clientController.text; final int unitPrice = int.tryParse(_amountController.text) ?? 0; // 【こだわり1】10%固定計算 final int tax = (unitPrice * 0.1).floor(); final int total = unitPrice + tax; final dateStr = DateFormat('yyyy/MM/dd HH:mm').format(DateTime.now()); // PDFの内容(超シンプル) pdf.addPage(pw.Page(build: (context) => pw.Column(children: [ pw.Text("Invoice / Receipt", style: pw.TextStyle(fontSize: 40)), pw.Divider(), pw.Text("Client: $clientName"), pw.Text("Date: $dateStr"), pw.SizedBox(height: 20), pw.Text("Subtotal: $unitPrice JPY"), pw.Text("Tax (10%): $tax JPY"), pw.Text("Total: $total JPY", style: pw.TextStyle(fontWeight: pw.FontWeight.bold)), ]))); // PDFをバイトデータに変換 final Uint8List bytes = await pdf.save(); // 【こだわり2】SHA-256ハッシュ計算 final hash = sha256.convert(bytes).toString().substring(0, 10); // 【こだわり3】ファイル名に情報を詰め込む final fileName = "${DateFormat('yyyyMMdd').format(DateTime.now())}_${clientName}_${total}円_hash_$hash.pdf"; // 保存(Androidの書類フォルダなど) final directory = await getExternalStorageDirectory(); final file = File("${directory!.path}/$fileName"); await file.writeAsBytes(bytes); setState(() { _status = "保存完了!\n場所: ${file.path}\nハッシュ: $hash"; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("現場のじぇみエモン請求書")), body: Padding( padding: const EdgeInsets.all(16.0), child: Column(children: [ TextField(controller: _clientController, decoration: const InputDecoration(labelText: "取引先名")), TextField(controller: _amountController, decoration: const InputDecoration(labelText: "単価(税抜)")), const SizedBox(height: 20), ElevatedButton(onPressed: _generateInvoice, child: const Text("PDF発行 & ハッシュ保存")), const SizedBox(height: 20), Text(_status, style: const TextStyle(color: Colors.blue)), ]), ), ); } }