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