fix: keep invoice list visible when keyboard opens

This commit is contained in:
joe 2026-02-26 13:24:32 +09:00
parent 976ac6be20
commit 54135fa466

View file

@ -46,14 +46,11 @@ class _InvoiceHistoryScreenState extends State<InvoiceHistoryScreen> {
} }
Future<void> _showInvoiceActions(Invoice invoice) async { Future<void> _showInvoiceActions(Invoice invoice) async {
if (!_requireUnlock()) return;
if (invoice.isLocked) { if (invoice.isLocked) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("ロック中の伝票は操作できません"))); ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("ロック中の伝票は操作できません")));
return; return;
} }
if (!_isUnlocked) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("操作するにはアンロックが必要です")));
return;
}
await showModalBottomSheet( await showModalBottomSheet(
context: context, context: context,
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(16))), shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(16))),
@ -93,24 +90,26 @@ class _InvoiceHistoryScreenState extends State<InvoiceHistoryScreen> {
ListTile( ListTile(
leading: const Icon(Icons.edit), leading: const Icon(Icons.edit),
title: const Text("編集"), title: const Text("編集"),
onTap: () async { onTap: _isUnlocked
Navigator.pop(context); ? () async {
await Navigator.push( await Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => InvoiceInputForm( builder: (context) => InvoiceDetailPage(
existingInvoice: invoice, invoice: invoice,
onInvoiceGenerated: (inv, path) {}, isUnlocked: _isUnlocked, //
), ),
), ),
); );
_loadData(); _loadData();
}, }
: null,
), ),
ListTile( ListTile(
leading: const Icon(Icons.delete, color: Colors.redAccent), leading: const Icon(Icons.delete, color: Colors.redAccent),
title: const Text("削除", style: TextStyle(color: Colors.redAccent)), title: const Text("削除", style: TextStyle(color: Colors.redAccent)),
onTap: () async { onTap: _isUnlocked
? () async {
Navigator.pop(context); Navigator.pop(context);
final confirm = await showDialog<bool>( final confirm = await showDialog<bool>(
context: context, context: context,
@ -127,7 +126,8 @@ class _InvoiceHistoryScreenState extends State<InvoiceHistoryScreen> {
await _invoiceRepo.deleteInvoice(invoice.id); await _invoiceRepo.deleteInvoice(invoice.id);
_loadData(); _loadData();
} }
}, }
: null,
), ),
], ],
), ),
@ -135,6 +135,12 @@ class _InvoiceHistoryScreenState extends State<InvoiceHistoryScreen> {
); );
} }
bool _requireUnlock() {
if (_isUnlocked) return true;
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("スライドでロック解除してください")));
return false;
}
Future<void> _loadVersion() async { Future<void> _loadVersion() async {
final packageInfo = await PackageInfo.fromPlatform(); final packageInfo = await PackageInfo.fromPlatform();
setState(() { setState(() {
@ -193,9 +199,10 @@ class _InvoiceHistoryScreenState extends State<InvoiceHistoryScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final amountFormatter = NumberFormat("#,###"); final amountFormatter = NumberFormat("#,###");
final dateFormatter = DateFormat('yyyy/MM/dd'); final dateFormatter = DateFormat('yyyy/MM/dd');
return Scaffold( return Scaffold(
drawer: Drawer( resizeToAvoidBottomInset: false,
drawer: _isUnlocked
? Drawer(
child: ListView( child: ListView(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
children: [ children: [
@ -214,7 +221,9 @@ class _InvoiceHistoryScreenState extends State<InvoiceHistoryScreen> {
ListTile( ListTile(
leading: const Icon(Icons.receipt_long), leading: const Icon(Icons.receipt_long),
title: const Text("伝票マスター"), title: const Text("伝票マスター"),
onTap: () => Navigator.pop(context), onTap: () {
Navigator.pop(context);
},
), ),
ListTile( ListTile(
leading: const Icon(Icons.people), leading: const Icon(Icons.people),
@ -251,7 +260,8 @@ class _InvoiceHistoryScreenState extends State<InvoiceHistoryScreen> {
), ),
], ],
), ),
), )
: null,
appBar: AppBar( appBar: AppBar(
// leading removed // leading removed
title: GestureDetector( title: GestureDetector(
@ -317,7 +327,8 @@ class _InvoiceHistoryScreenState extends State<InvoiceHistoryScreen> {
), ),
), ),
), ),
body: Column( body: SafeArea(
child: Column(
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
@ -342,7 +353,8 @@ class _InvoiceHistoryScreenState extends State<InvoiceHistoryScreen> {
), ),
) )
: ListView.builder( : ListView.builder(
padding: const EdgeInsets.only(bottom: 100), // FAB考慮 keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
padding: const EdgeInsets.only(bottom: 120), // : FAB+
itemCount: _filteredInvoices.length, itemCount: _filteredInvoices.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final invoice = _filteredInvoices[index]; final invoice = _filteredInvoices[index];
@ -383,23 +395,20 @@ class _InvoiceHistoryScreenState extends State<InvoiceHistoryScreen> {
), ),
subtitle: Text("${dateFormatter.format(invoice.date)} - ${invoice.invoiceNumber}"), subtitle: Text("${dateFormatter.format(invoice.date)} - ${invoice.invoiceNumber}"),
trailing: SizedBox( trailing: SizedBox(
height: 56, height: 60,
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
Text("${amountFormatter.format(invoice.totalAmount)}", Text("${amountFormatter.format(invoice.totalAmount)}",
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13)), style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13)),
const SizedBox(height: 2),
if (invoice.isSynced) if (invoice.isSynced)
const Icon(Icons.sync, size: 14, color: Colors.green) const Icon(Icons.sync, size: 14, color: Colors.green)
else else
const Icon(Icons.sync_disabled, size: 14, color: Colors.orange), const Icon(Icons.sync_disabled, size: 14, color: Colors.orange),
const SizedBox(height: 4),
IconButton( IconButton(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
constraints: const BoxConstraints.tightFor(width: 32, height: 28), constraints: const BoxConstraints.tightFor(width: 32, height: 26),
icon: const Icon(Icons.edit, size: 18), icon: const Icon(Icons.edit, size: 18),
tooltip: invoice.isLocked ? "ロック中" : (_isUnlocked ? "編集" : "アンロックして編集"), tooltip: invoice.isLocked ? "ロック中" : (_isUnlocked ? "編集" : "アンロックして編集"),
onPressed: (invoice.isLocked || !_isUnlocked) onPressed: (invoice.isLocked || !_isUnlocked)
@ -420,7 +429,8 @@ class _InvoiceHistoryScreenState extends State<InvoiceHistoryScreen> {
], ],
), ),
), ),
onTap: () async { onTap: _isUnlocked
? () async {
await Navigator.push( await Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
@ -431,16 +441,19 @@ class _InvoiceHistoryScreenState extends State<InvoiceHistoryScreen> {
), ),
); );
_loadData(); _loadData();
}, }
onLongPress: () => _showInvoiceActions(invoice), : () => _requireUnlock(),
onLongPress: _isUnlocked ? () => _showInvoiceActions(invoice) : () => _requireUnlock(),
); );
}, },
), ),
), ),
], ],
), ),
),
floatingActionButton: FloatingActionButton.extended( floatingActionButton: FloatingActionButton.extended(
onPressed: () async { onPressed: _isUnlocked
? () async {
await Navigator.push( await Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
@ -448,7 +461,8 @@ class _InvoiceHistoryScreenState extends State<InvoiceHistoryScreen> {
), ),
); );
_loadData(); _loadData();
}, }
: _requireUnlock,
label: const Text("新規伝票作成"), label: const Text("新規伝票作成"),
icon: const Icon(Icons.add), icon: const Icon(Icons.add),
backgroundColor: Colors.indigo, backgroundColor: Colors.indigo,