diff --git a/gemi_invoice/README.md b/gemi_invoice/README.md index fb65c06..28d631c 100644 --- a/gemi_invoice/README.md +++ b/gemi_invoice/README.md @@ -4,6 +4,9 @@ A new Flutter project. ## Getting Started +!! 日本語が主体のアプリです。アプリの基本言語は日本語です。コメントも日本語と英語併記です。!! +!! 可読性は重視しません。AIの開発効率を最大に上げて下さい。!! + This project is a starting point for a Flutter application. A few resources to get you started if this is your first Flutter project: @@ -14,3 +17,28 @@ A few resources to get you started if this is your first Flutter project: For help getting started with Flutter development, view the [online documentation](https://docs.flutter.dev/), which offers tutorials, samples, guidance on mobile development, and a full API reference. + +## 販売アシスト1号の機能 + +販売アシスト1号は、営業マンの販売業務を支援するためのアプリケーションです。主な機能は以下の通りです。 + +- ファイル名の規則 "{date}({請求等}){顧客名}_{件名}_{金額カンマ付}円_{sha256}" 20251202(請求)佐々木製作所_あの件_20,000円_25ab85cc9988 +- 伝票(件名)の管理 +- 管理ではファイルの様にオブジェクトとして管理します。 +- 顧客マスター管理 +- 商品マスター管理 +- 見積納品請求領収証の作成 +- 見積納品請求領収証の一覧表示 +- 見積納品請求領収証のPDF出力 +- PDFの管理 +- GPSと顧客マスターを連携し座標の履歴を記録する機能 +- フォーム入力時にGPS情報で自動的に顧客マスターから候補を選出する機能 +- 入力時にQRコードやOCRをGoogleレンズを使ってアシストします +- レシート印刷するポータブルプリンタを使って領収証印刷する機能 +- 印刷時にQRコードを印刷する機能 +- Googleドライブにバックアップする機能 +- 未来の機能(今は実装しない可能にしておく):odooとの同期・連携 伝票単位で同期 +アプリの基本言語は日本語です。コメントも日本語と英語併記です。可読性は重視しません。AIの開発効率を最大に上げるものです。 +表示言語は日本語です。環境により英語を表示する機能は未来に実装予定です。 +見積・納品・請求・領収証はフォームがほぼ同じですが、項目が時間と共に変化するので件名が同じでも明細は異なる場合があります。 +伝票はsqliteで管理します。 diff --git a/gemi_invoice/lib/main.dart b/gemi_invoice/lib/main.dart index 8bbb9c4..cca10cc 100644 --- a/gemi_invoice/lib/main.dart +++ b/gemi_invoice/lib/main.dart @@ -1,6 +1,7 @@ // lib/main.dart // version: 1.4.3c (Bug Fix: PDF layout error) - Refactored for modularity import 'package:flutter/material.dart'; +import 'screens/pdf_list_screen.dart'; // PDF一覧画面 // --- 独自モジュールのインポート --- import 'models/invoice_models.dart'; // Invoice, InvoiceItem モデル @@ -60,6 +61,20 @@ class _InvoiceFlowScreenState extends State { appBar: AppBar( title: const Text("販売アシスト1号 V1.4.3c"), backgroundColor: Colors.blueGrey, + actions: [ + IconButton( + icon: const Icon(Icons.picture_as_pdf), + tooltip: 'PDF一覧', + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => const PdfListScreen(), + ), + ); + }, + ), + ], ), // 入力フォームを表示 body: InvoiceInputForm( diff --git a/gemi_invoice/lib/screens/pdf_list_screen.dart b/gemi_invoice/lib/screens/pdf_list_screen.dart new file mode 100644 index 0000000..045aa2e --- /dev/null +++ b/gemi_invoice/lib/screens/pdf_list_screen.dart @@ -0,0 +1,99 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:open_filex/open_filex.dart'; + +class PdfListScreen extends StatefulWidget { + const PdfListScreen({super.key}); + + @override + State createState() => _PdfListScreenState(); +} + +class _PdfListScreenState extends State { + List _pdfFiles = []; + bool _loading = true; + + @override + void initState() { + super.initState(); + _fetchPdfFiles(); + } + + Future _fetchPdfFiles() async { + // Request storage permission + final status = await Permission.storage.request(); + if (!status.isGranted) { + setState(() { + _loading = false; + }); + return; + } + + // Prefer to look in the Downloads folder if available + Directory? downloadsDir; + if (Platform.isAndroid) { + downloadsDir = await getExternalStorageDirectory(); + // The Downloads folder may be a subdirectory; adjust as needed + if (downloadsDir != null) { + downloadsDir = Directory('${downloadsDir.path}/Download'); + } + } else if (Platform.isIOS) { + downloadsDir = await getApplicationDocumentsDirectory(); + } else { + downloadsDir = await getApplicationDocumentsDirectory(); + } + + if (downloadsDir == null || !await downloadsDir.exists()) { + setState(() { + _loading = false; + }); + return; + } + + final files = downloadsDir + .listSync() + .where((f) => f.path.toLowerCase().endsWith('.pdf')) + .toList(); + + setState(() { + _pdfFiles = files; + _loading = false; + }); + } + + void _openFile(FileSystemEntity file) async { + final result = await OpenFilex.open(file.path); + if (result.type != ResultType.success) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Could not open ${file.path}')), + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('PDF ファイル一覧'), + ), + body: _loading + ? const Center(child: CircularProgressIndicator()) + : _pdfFiles.isEmpty + ? const Center(child: Text('PDF ファイルが見つかりません。')) + : ListView.builder( + itemCount: _pdfFiles.length, + itemBuilder: (context, index) { + final file = _pdfFiles[index]; + final fileName = file.path.split(Platform.pathSeparator).last; + return ListTile( + leading: const Icon(Icons.picture_as_pdf), + title: Text(fileName), + onTap: () => _openFile(file), + ); + }, + ), + ); + } +} diff --git a/gemi_invoice/pubspec.lock b/gemi_invoice/pubspec.lock index 556910c..7e15fe1 100644 --- a/gemi_invoice/pubspec.lock +++ b/gemi_invoice/pubspec.lock @@ -172,10 +172,10 @@ packages: dependency: transitive description: name: hooks - sha256: "5d309c86e7ce34cd8e37aa71cb30cb652d3829b900ab145e4d9da564b31d59f7" + sha256: "7a08a0d684cb3b8fb604b78455d5d352f502b68079f7b80b831c62220ab0a4f6" url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.1" image: dependency: transitive description: @@ -276,10 +276,10 @@ packages: dependency: transitive description: name: objective_c - sha256: "983c7fa1501f6dcc0cb7af4e42072e9993cb28d73604d25ebf4dab08165d997e" + sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" url: "https://pub.dev" source: hosted - version: "9.2.5" + version: "9.3.0" open_filex: dependency: "direct main" description: @@ -481,10 +481,10 @@ packages: dependency: transitive description: name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" url: "https://pub.dev" source: hosted - version: "1.10.1" + version: "1.10.2" stack_trace: dependency: transitive description: