見た目修正保守

This commit is contained in:
joe 2026-02-28 04:36:30 +09:00
parent 0c338dc12b
commit b23c400aa8
5 changed files with 433 additions and 121 deletions

View file

@ -73,7 +73,7 @@ class MyApp extends StatelessWidget {
panEnabled: false,
scaleEnabled: true,
minScale: 0.8,
maxScale: 2.0,
maxScale: 4.0,
child: child ?? const SizedBox.shrink(),
),
),

View file

@ -416,6 +416,7 @@ class _CustomerMasterScreenState extends State<CustomerMasterScreen> {
department: departmentController.text.isEmpty ? null : departmentController.text,
address: addressController.text.isEmpty ? null : addressController.text,
tel: telController.text.isEmpty ? null : telController.text,
email: emailController.text.isEmpty ? null : emailController.text,
headChar1: head1.isEmpty ? _headKana(displayNameController.text) : head1,
headChar2: head2.isEmpty ? null : head2,
isLocked: customer?.isLocked ?? false,

View file

@ -13,6 +13,36 @@ import 'product_picker_modal.dart';
import '../models/company_model.dart';
import '../widgets/keyboard_inset_wrapper.dart';
class _DetailSnapshot {
final String formalName;
final String notes;
final List<InvoiceItem> items;
final double taxRate;
final bool includeTax;
final bool isDraft;
const _DetailSnapshot({
required this.formalName,
required this.notes,
required this.items,
required this.taxRate,
required this.includeTax,
required this.isDraft,
});
}
List<InvoiceItem> _cloneItemsDetail(List<InvoiceItem> source) {
return source
.map((e) => InvoiceItem(
id: e.id,
productId: e.productId,
description: e.description,
quantity: e.quantity,
unitPrice: e.unitPrice,
))
.toList(growable: true);
}
class InvoiceDetailPage extends StatefulWidget {
final Invoice invoice;
final bool editable;
@ -38,6 +68,9 @@ class _InvoiceDetailPageState extends State<InvoiceDetailPage> {
final _companyRepo = CompanyRepository();
CompanyInfo? _companyInfo;
bool _showFormalWarning = true;
final List<_DetailSnapshot> _undoStack = [];
final List<_DetailSnapshot> _redoStack = [];
bool _isApplyingSnapshot = false;
@override
void initState() {
@ -69,12 +102,14 @@ class _InvoiceDetailPageState extends State<InvoiceDetailPage> {
setState(() {
_items.add(InvoiceItem(description: "新項目", quantity: 1, unitPrice: 0));
});
_pushHistory();
}
void _removeItem(int index) {
setState(() {
_items.removeAt(index);
});
_pushHistory();
}
void _pickFromMaster() {
@ -126,6 +161,8 @@ class _InvoiceDetailPageState extends State<InvoiceDetailPage> {
}
setState(() => _isEditing = false);
_undoStack.clear();
_redoStack.clear();
final newPath = await generateInvoicePdf(updatedInvoice);
if (newPath != null) {
@ -153,6 +190,7 @@ class _InvoiceDetailPageState extends State<InvoiceDetailPage> {
Widget build(BuildContext context) {
final fmt = NumberFormat("#,###");
final isDraft = _currentInvoice.isDraft;
final docTypeName = _currentInvoice.documentTypeName;
final themeColor = Colors.white; //
final textColor = Colors.black87;
@ -163,26 +201,7 @@ class _InvoiceDetailPageState extends State<InvoiceDetailPage> {
resizeToAvoidBottomInset: false,
appBar: AppBar(
leading: const BackButton(), //
title: Row(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: Text(
isDraft ? "A3:伝票詳細" : "A3:伝票詳細",
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(width: 8),
if (isDraft)
Chip(
label: const Text("下書き", style: TextStyle(color: Colors.white)),
backgroundColor: Colors.orange,
padding: EdgeInsets.zero,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: VisualDensity.compact,
),
],
),
title: const Text("A3:伝票詳細"),
backgroundColor: Colors.indigo.shade700,
actions: [
if (locked)
@ -226,6 +245,7 @@ class _InvoiceDetailPageState extends State<InvoiceDetailPage> {
onPressed: (locked || !widget.isUnlocked)
? null
: () async {
_pushHistory(clearRedo: true);
await Navigator.push(
context,
MaterialPageRoute(
@ -243,6 +263,16 @@ class _InvoiceDetailPageState extends State<InvoiceDetailPage> {
},
),
] else ...[
IconButton(
icon: const Icon(Icons.undo),
onPressed: _undoStack.isNotEmpty ? _undo : null,
tooltip: "元に戻す",
),
IconButton(
icon: const Icon(Icons.redo),
onPressed: _redoStack.isNotEmpty ? _redo : null,
tooltip: "やり直す",
),
IconButton(icon: const Icon(Icons.save), onPressed: _saveChanges),
IconButton(icon: const Icon(Icons.cancel), onPressed: () => setState(() => _isEditing = false)),
]
@ -259,21 +289,33 @@ class _InvoiceDetailPageState extends State<InvoiceDetailPage> {
if (isDraft)
Container(
width: double.infinity,
padding: const EdgeInsets.all(8),
padding: const EdgeInsets.all(10),
margin: const EdgeInsets.only(bottom: 8),
decoration: BoxDecoration(
color: Colors.orange.shade50,
color: Colors.indigo.shade800,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.orange.shade200),
border: Border.all(color: Colors.indigo.shade900),
),
child: Row(
children: const [
Icon(Icons.edit_note, color: Colors.orange),
SizedBox(width: 8),
children: [
const Icon(Icons.edit_note, color: Colors.white70),
const SizedBox(width: 8),
Expanded(
child: Text(
"下書き: 未確定・PDFは正式発行で確定",
style: TextStyle(color: Colors.orange),
style: const TextStyle(color: Colors.white70),
),
),
const SizedBox(width: 8),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: Colors.orange.shade600,
borderRadius: BorderRadius.circular(16),
),
child: Text(
"下書${docTypeName}",
style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12),
),
),
],
@ -332,12 +374,14 @@ class _InvoiceDetailPageState extends State<InvoiceDetailPage> {
if (_isEditing) ...[
TextField(
controller: _formalNameController,
onChanged: (_) => _pushHistory(),
decoration: const InputDecoration(labelText: "取引先 正式名称", border: OutlineInputBorder()),
style: TextStyle(color: textColor),
),
const SizedBox(height: 12),
TextField(
controller: _notesController,
onChanged: (_) => _pushHistory(),
maxLines: 2,
decoration: const InputDecoration(labelText: "備考", border: OutlineInputBorder()),
style: TextStyle(color: textColor),
@ -350,17 +394,6 @@ class _InvoiceDetailPageState extends State<InvoiceDetailPage> {
"伝票番号: ${_currentInvoice.invoiceNumber}",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: textColor),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: _currentInvoice.isDraft ? Colors.orange : Colors.green.shade700,
borderRadius: BorderRadius.circular(20),
),
child: Text(
_currentInvoice.isDraft ? "下書き" : "確定済",
style: const TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold),
),
),
],
),
const SizedBox(height: 8),
@ -369,16 +402,27 @@ class _InvoiceDetailPageState extends State<InvoiceDetailPage> {
style: TextStyle(color: textColor.withAlpha((0.8 * 255).round())),
),
const SizedBox(height: 8),
Text("取引先:", style: TextStyle(fontWeight: FontWeight.bold, color: textColor)),
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("取引先", style: TextStyle(fontWeight: FontWeight.bold, color: textColor)),
const SizedBox(height: 4),
Text("${_currentInvoice.customerNameForDisplay} ${_currentInvoice.customer.title}",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: textColor)),
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: textColor)),
if (_currentInvoice.subject?.isNotEmpty ?? false) ...[
const SizedBox(height: 8),
const SizedBox(height: 6),
Text("件名: ${_currentInvoice.subject}",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.indigoAccent)),
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.indigo)),
],
if (_currentInvoice.customer.department != null && _currentInvoice.customer.department!.isNotEmpty)
Text(_currentInvoice.customer.department!, style: TextStyle(fontSize: 16, color: textColor)),
Text(_currentInvoice.customer.department!, style: TextStyle(fontSize: 14, color: textColor)),
if ((_currentInvoice.contactAddressSnapshot ?? _currentInvoice.customer.address) != null)
Text("住所: ${_currentInvoice.contactAddressSnapshot ?? _currentInvoice.customer.address}", style: TextStyle(color: textColor)),
if ((_currentInvoice.contactTelSnapshot ?? _currentInvoice.customer.tel) != null)
@ -386,13 +430,16 @@ class _InvoiceDetailPageState extends State<InvoiceDetailPage> {
if ((_currentInvoice.contactEmailSnapshot ?? _currentInvoice.customer.email) != null)
Text("メール: ${_currentInvoice.contactEmailSnapshot ?? _currentInvoice.customer.email}", style: TextStyle(color: textColor)),
if (_currentInvoice.notes?.isNotEmpty ?? false) ...[
const SizedBox(height: 8),
const SizedBox(height: 6),
Text(
"備考: ${_currentInvoice.notes}",
style: TextStyle(color: textColor.withAlpha((0.9 * 255).round())),
),
],
],
),
),
],
],
);
}
@ -427,19 +474,28 @@ class _InvoiceDetailPageState extends State<InvoiceDetailPage> {
_EditableCell(
initialValue: item.description,
textColor: textColor,
onChanged: (val) => item.description = val,
onChanged: (val) {
setState(() => item.description = val);
_pushHistory();
},
),
_EditableCell(
initialValue: item.quantity.toString(),
textColor: textColor,
keyboardType: TextInputType.number,
onChanged: (val) => setState(() => item.quantity = int.tryParse(val) ?? 0),
onChanged: (val) {
setState(() => item.quantity = int.tryParse(val) ?? 0);
_pushHistory();
},
),
_EditableCell(
initialValue: item.unitPrice.toString(),
textColor: textColor,
keyboardType: TextInputType.number,
onChanged: (val) => setState(() => item.unitPrice = int.tryParse(val) ?? 0),
onChanged: (val) {
setState(() => item.unitPrice = int.tryParse(val) ?? 0);
_pushHistory();
},
),
_TableCell(formatter.format(item.subtotal), textColor: textColor),
IconButton(icon: const Icon(Icons.delete, size: 20, color: Colors.red), onPressed: () => _removeItem(idx)),
@ -468,7 +524,7 @@ class _InvoiceDetailPageState extends State<InvoiceDetailPage> {
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.indigo.shade900,
color: Colors.indigo,
borderRadius: BorderRadius.circular(12),
),
child: Column(
@ -525,6 +581,61 @@ class _InvoiceDetailPageState extends State<InvoiceDetailPage> {
return _items.fold(0, (sum, item) => sum + (item.quantity * item.unitPrice));
}
void _pushHistory({bool clearRedo = false}) {
if (!_isEditing || _isApplyingSnapshot) return;
if (_undoStack.length >= 30) _undoStack.removeAt(0);
_undoStack.add(_DetailSnapshot(
formalName: _formalNameController.text,
notes: _notesController.text,
items: _cloneItemsDetail(_items),
taxRate: _taxRate,
includeTax: _includeTax,
isDraft: _currentInvoice.isDraft,
));
if (clearRedo) _redoStack.clear();
setState(() {});
}
void _undo() {
if (_undoStack.isEmpty) return;
final snapshot = _undoStack.removeLast();
_redoStack.add(_DetailSnapshot(
formalName: _formalNameController.text,
notes: _notesController.text,
items: _cloneItemsDetail(_items),
taxRate: _taxRate,
includeTax: _includeTax,
isDraft: _currentInvoice.isDraft,
));
_applySnapshot(snapshot);
}
void _redo() {
if (_redoStack.isEmpty) return;
final snapshot = _redoStack.removeLast();
_undoStack.add(_DetailSnapshot(
formalName: _formalNameController.text,
notes: _notesController.text,
items: _cloneItemsDetail(_items),
taxRate: _taxRate,
includeTax: _includeTax,
isDraft: _currentInvoice.isDraft,
));
_applySnapshot(snapshot);
}
void _applySnapshot(_DetailSnapshot snapshot) {
_isApplyingSnapshot = true;
setState(() {
_formalNameController.text = snapshot.formalName;
_notesController.text = snapshot.notes;
_items = _cloneItemsDetail(snapshot.items);
_taxRate = snapshot.taxRate;
_includeTax = snapshot.includeTax;
});
_isApplyingSnapshot = false;
}
Widget _buildExperimentalSection(bool isDraft) {
return Container(
padding: const EdgeInsets.all(12),

View file

@ -28,6 +28,18 @@ class InvoiceInputForm extends StatefulWidget {
State<InvoiceInputForm> createState() => _InvoiceInputFormState();
}
List<InvoiceItem> _cloneItems(List<InvoiceItem> source) {
return source
.map((e) => InvoiceItem(
id: e.id,
productId: e.productId,
description: e.description,
quantity: e.quantity,
unitPrice: e.unitPrice,
))
.toList(growable: true);
}
class _InvoiceInputFormState extends State<InvoiceInputForm> {
final _repository = InvoiceRepository();
final InvoiceRepository _invoiceRepo = InvoiceRepository();
@ -40,6 +52,11 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
bool _isDraft = true; //
final TextEditingController _subjectController = TextEditingController(); //
bool _isSaving = false; //
final List<_InvoiceSnapshot> _undoStack = [];
final List<_InvoiceSnapshot> _redoStack = [];
bool _isApplyingSnapshot = false;
bool get _canUndo => _undoStack.length > 1;
bool get _canRedo => _redoStack.isNotEmpty;
//
final List<Offset?> _signaturePath = [];
@ -47,16 +64,21 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
@override
void initState() {
super.initState();
_subjectController.addListener(_onSubjectChanged);
_loadInitialData();
}
@override
void dispose() {
_subjectController.removeListener(_onSubjectChanged);
_subjectController.dispose();
super.dispose();
}
Future<void> _loadInitialData() async {
_repository.cleanupOrphanedPdfs();
final customerRepo = CustomerRepository();
final customers = await customerRepo.getAllCustomers();
if (customers.isNotEmpty) {
setState(() => _selectedCustomer = customers.first);
}
await customerRepo.getAllCustomers();
setState(() {
//
@ -77,6 +99,12 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
_documentType = widget.initialDocumentType;
}
});
_pushHistory(clearRedo: true);
}
void _onSubjectChanged() {
if (_isApplyingSnapshot) return;
_pushHistory();
}
void _addItem() {
@ -93,6 +121,7 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
unitPrice: product.defaultUnitPrice,
));
});
_pushHistory();
});
}
@ -207,6 +236,84 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
);
}
void _pushHistory({bool clearRedo = false}) {
setState(() {
if (_undoStack.length >= 30) _undoStack.removeAt(0);
_undoStack.add(_InvoiceSnapshot(
customer: _selectedCustomer,
items: _cloneItems(_items),
taxRate: _taxRate,
includeTax: _includeTax,
documentType: _documentType,
date: _selectedDate,
isDraft: _isDraft,
subject: _subjectController.text,
));
if (clearRedo) _redoStack.clear();
});
}
void _undo() {
if (_undoStack.length <= 1) return; //
setState(() {
// redoへ積む
_redoStack.add(_InvoiceSnapshot(
customer: _selectedCustomer,
items: _cloneItems(_items),
taxRate: _taxRate,
includeTax: _includeTax,
documentType: _documentType,
date: _selectedDate,
isDraft: _isDraft,
subject: _subjectController.text,
));
//
_undoStack.removeLast();
final snapshot = _undoStack.last;
_isApplyingSnapshot = true;
_selectedCustomer = snapshot.customer;
_items
..clear()
..addAll(_cloneItems(snapshot.items));
_taxRate = snapshot.taxRate;
_includeTax = snapshot.includeTax;
_documentType = snapshot.documentType;
_selectedDate = snapshot.date;
_isDraft = snapshot.isDraft;
_subjectController.text = snapshot.subject;
_isApplyingSnapshot = false;
});
}
void _redo() {
if (_redoStack.isEmpty) return;
setState(() {
_undoStack.add(_InvoiceSnapshot(
customer: _selectedCustomer,
items: _cloneItems(_items),
taxRate: _taxRate,
includeTax: _includeTax,
documentType: _documentType,
date: _selectedDate,
isDraft: _isDraft,
subject: _subjectController.text,
));
final snapshot = _redoStack.removeLast();
_isApplyingSnapshot = true;
_selectedCustomer = snapshot.customer;
_items
..clear()
..addAll(_cloneItems(snapshot.items));
_taxRate = snapshot.taxRate;
_includeTax = snapshot.includeTax;
_documentType = snapshot.documentType;
_selectedDate = snapshot.date;
_isDraft = snapshot.isDraft;
_subjectController.text = snapshot.subject;
_isApplyingSnapshot = false;
});
}
@override
Widget build(BuildContext context) {
final fmt = NumberFormat("#,###");
@ -219,6 +326,18 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
appBar: AppBar(
leading: const BackButton(),
title: const Text("A1:伝票入力"),
actions: [
IconButton(
icon: const Icon(Icons.undo),
onPressed: _canUndo ? _undo : null,
tooltip: "元に戻す",
),
IconButton(
icon: const Icon(Icons.redo),
onPressed: _canRedo ? _redo : null,
tooltip: "やり直す",
),
],
),
body: Stack(
children: [
@ -281,6 +400,7 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
);
if (picked != null) {
setState(() => _selectedDate = picked);
_pushHistory();
}
},
child: Container(
@ -324,6 +444,7 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
);
if (picked != null) {
setState(() => _selectedCustomer = picked);
_pushHistory();
}
},
),
@ -357,6 +478,7 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
final item = _items.removeAt(oldIndex);
_items.insert(newIndex, item);
});
_pushHistory();
},
buildDefaultDragHandles: false,
itemBuilder: (context, idx) {
@ -376,21 +498,33 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
const SizedBox(width: 8),
IconButton(
icon: const Icon(Icons.remove_circle_outline, color: Colors.redAccent),
onPressed: () => setState(() => _items.removeAt(idx)),
onPressed: () {
setState(() => _items.removeAt(idx));
_pushHistory();
},
tooltip: "削除",
),
],
),
onTap: () {
//
//
final descCtrl = TextEditingController(text: item.description);
final qtyCtrl = TextEditingController(text: item.quantity.toString());
final priceCtrl = TextEditingController(text: item.unitPrice.toString());
showDialog(
context: context,
builder: (context) => AlertDialog(
builder: (context) {
final inset = MediaQuery.of(context).viewInsets.bottom;
return MediaQuery.removeViewInsets(
removeBottom: true,
context: context,
child: AlertDialog(
insetPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24),
title: const Text("明細の編集"),
content: Column(
content: SingleChildScrollView(
padding: EdgeInsets.only(bottom: inset + 12),
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(controller: descCtrl, decoration: const InputDecoration(labelText: "品名 / 項目")),
@ -398,6 +532,7 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
TextField(controller: priceCtrl, decoration: const InputDecoration(labelText: "単価"), keyboardType: TextInputType.number),
],
),
),
actions: [
TextButton.icon(
icon: const Icon(Icons.search, size: 18),
@ -420,6 +555,7 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
unitPrice: int.tryParse(priceCtrl.text) ?? item.unitPrice,
);
});
_pushHistory();
Navigator.pop(context);
},
child: const Text("更新"),
@ -428,6 +564,8 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
),
);
},
);
},
),
),
);
@ -446,7 +584,7 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.indigo.shade900,
color: Colors.indigo,
borderRadius: BorderRadius.circular(12),
),
child: Column(
@ -584,16 +722,23 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
children: [
Text("案件名 / 件名", style: TextStyle(fontWeight: FontWeight.bold, color: textColor)),
const SizedBox(height: 8),
TextField(
Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(12),
),
child: TextField(
controller: _subjectController,
style: TextStyle(color: textColor),
decoration: InputDecoration(
hintText: "例:事務所改修工事 / 〇〇月分リース料",
hintStyle: TextStyle(color: textColor.withAlpha((0.5 * 255).round())),
filled: true,
fillColor: _isDraft ? Colors.white12 : Colors.grey.shade100,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
border: InputBorder.none,
isDense: true,
contentPadding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4),
),
),
),
],
@ -601,6 +746,28 @@ class _InvoiceInputFormState extends State<InvoiceInputForm> {
}
}
class _InvoiceSnapshot {
final Customer? customer;
final List<InvoiceItem> items;
final double taxRate;
final bool includeTax;
final DocumentType documentType;
final DateTime date;
final bool isDraft;
final String subject;
_InvoiceSnapshot({
required this.customer,
required this.items,
required this.taxRate,
required this.includeTax,
required this.documentType,
required this.date,
required this.isDraft,
required this.subject,
});
}
class SignaturePainter extends CustomPainter {
final List<Offset?> points;
SignaturePainter(this.points);

View file

@ -232,6 +232,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: const Text('S1:設定'),
backgroundColor: Colors.indigo,
actions: [
IconButton(
icon: const Icon(Icons.info_outline),
@ -246,6 +247,38 @@ class _SettingsScreenState extends State<SettingsScreen> {
physics: const AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.only(bottom: listBottomPadding),
children: [
Container(
width: double.infinity,
padding: const EdgeInsets.all(14),
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: Colors.indigo.shade50,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.indigo.shade100),
),
child: Row(
children: [
const Icon(Icons.business, color: Colors.indigo, size: 28),
const SizedBox(width: 12),
const Expanded(
child: Text(
"自社情報を開く",
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.indigo),
),
),
ElevatedButton.icon(
onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const CompanyInfoScreen())),
icon: const Icon(Icons.chevron_right),
label: const Text("詳細"),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.indigo,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
),
),
],
),
),
_section(
title: '自社情報',
subtitle: '会社名・住所・登録番号など',