stop cheque screen added

This commit is contained in:
2025-12-26 15:47:47 +05:30
parent 07d5ea8fbe
commit 3fa40f133a
4 changed files with 472 additions and 136 deletions

View File

@@ -9,7 +9,7 @@ class Cheque {
final String? Chequescount; final String? Chequescount;
final String? ChequeNumber; final String? ChequeNumber;
final String? transactionCode; final String? transactionCode;
final String? amount; final int? amount;
final String? status; final String? status;
final String? stopIssueDate; final String? stopIssueDate;
final String? StopExpiryDate; final String? StopExpiryDate;
@@ -41,7 +41,7 @@ this.StopExpiryDate,
Chequescount: json['Chequescount'] ?? '', Chequescount: json['Chequescount'] ?? '',
ChequeNumber: json['ChequeNumber'] ?? '', ChequeNumber: json['ChequeNumber'] ?? '',
transactionCode: json['transactionCode'] ?? '', transactionCode: json['transactionCode'] ?? '',
amount: json['amount'] ?? '', amount: json['amount'],
status: json['status'] ?? '', status: json['status'] ?? '',
stopIssueDate: json['stopIssueDate'] ?? '', stopIssueDate: json['stopIssueDate'] ?? '',
StopExpiryDate: json['StopExpiryDate'] ?? '', StopExpiryDate: json['StopExpiryDate'] ?? '',

View File

@@ -3,31 +3,32 @@ import 'package:kmobile/api/services/cheque_service.dart';
import 'package:kmobile/data/models/user.dart'; import 'package:kmobile/data/models/user.dart';
import 'package:kmobile/di/injection.dart'; import 'package:kmobile/di/injection.dart';
class ChequeStatusScreen extends StatefulWidget { class ChequeEnquiryScreen extends StatefulWidget {
final List<User> users; final List<User> users;
final int selectedIndex; final int selectedIndex;
const ChequeStatusScreen({ const ChequeEnquiryScreen({
super.key, super.key,
required this.users, required this.users,
required this.selectedIndex, required this.selectedIndex,
}); });
@override @override
State<ChequeStatusScreen> createState() => _ChequeStatusScreenState(); State<ChequeEnquiryScreen> createState() => _ChequeEnquiryScreenState();
} }
class _ChequeStatusScreenState extends State<ChequeStatusScreen> { class _ChequeEnquiryScreenState extends State<ChequeEnquiryScreen> {
User? _selectedAccount; User? _selectedAccount;
final TextEditingController _searchController = TextEditingController(); final TextEditingController _searchController = TextEditingController();
var service = getIt<ChequeService>(); var service = getIt<ChequeService>();
bool _isLoading = true; bool _isLoading = true;
List<Cheque> _allCheques = []; List<Cheque> _allCheques = [];
Map<String, List<Cheque>> _groupedCheques = {}; Map<String, List<Cheque>> _groupedCheques = {};
List<User> _filteredUsers = [];
@override @override
void initState() { void initState() {
super.initState(); super.initState();
final List<User> _filteredUsers = widget.users _filteredUsers = widget.users
.where((user) => ['SA', 'SB', 'CA', 'CC'].contains(user.accountType)) .where((user) => ['SA', 'SB', 'CA', 'CC'].contains(user.accountType))
.toList(); .toList();
@@ -119,7 +120,6 @@ class _ChequeStatusScreenState extends State<ChequeStatusScreen> {
filteredCheques = _allCheques.where((cheque) { filteredCheques = _allCheques.where((cheque) {
final lowerQuery = query.toLowerCase(); final lowerQuery = query.toLowerCase();
return (cheque.ChequeNumber?.toLowerCase().contains(lowerQuery) ?? false) || return (cheque.ChequeNumber?.toLowerCase().contains(lowerQuery) ?? false) ||
(cheque.amount?.toLowerCase().contains(lowerQuery) ?? false) ||
(cheque.status?.toLowerCase().contains(lowerQuery) ?? false) || (cheque.status?.toLowerCase().contains(lowerQuery) ?? false) ||
(cheque.fromCheque?.toLowerCase().contains(lowerQuery) ?? false) || (cheque.fromCheque?.toLowerCase().contains(lowerQuery) ?? false) ||
(cheque.toCheque?.toLowerCase().contains(lowerQuery) ?? false); (cheque.toCheque?.toLowerCase().contains(lowerQuery) ?? false);
@@ -142,80 +142,108 @@ class _ChequeStatusScreenState extends State<ChequeStatusScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('Track Cheque Status'), title: const Text('Cheque Enquiry'),
centerTitle: false, centerTitle: false,
), ),
body: Padding( body: Stack(
padding: const EdgeInsets.all(16.0), children: [
child: Column( Padding(
children: [ padding: const EdgeInsets.all(16.0),
Card( child: Column(
elevation: 4, children: [
margin: const EdgeInsets.symmetric(vertical: 8.0), Card(
child: Padding( elevation: 4,
padding: const EdgeInsets.all(16.0), margin: const EdgeInsets.symmetric(vertical: 8.0),
child: Column( child: Padding(
crossAxisAlignment: CrossAxisAlignment.start, padding: const EdgeInsets.all(16.0),
children: [ child: Row(
const Text( mainAxisAlignment: MainAxisAlignment.spaceBetween,
"Account Number", children: [
style: const Text(
TextStyle(fontWeight: FontWeight.bold, fontSize: 18), "Account Number",
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 18),
),
const SizedBox(width: 16),
if (_selectedAccount != null)
Expanded(
child: DropdownButton<User>(
value: _selectedAccount,
onChanged: (User? newUser) {
if (newUser != null) {
setState(() {
_selectedAccount = newUser;
_loadCheques();
});
}
},
items: _filteredUsers.map((user) {
return DropdownMenuItem<User>(
value: user,
child: Text(user.accountNo.toString()),
);
}).toList(),
),
)
else
const Text('No accounts found'),
],
), ),
if (_selectedAccount != null) ),
DropdownButtonFormField<User>( ),
value: _selectedAccount, const SizedBox(height: 20),
onChanged: (User? newUser) { Card(
if (newUser != null) { elevation: 4,
setState(() { margin: const EdgeInsets.symmetric(vertical: 8.0),
_selectedAccount = newUser; child: Padding(
_loadCheques(); padding: const EdgeInsets.all(8.0),
}); child: TextField(
} controller: _searchController,
}, decoration: const InputDecoration(
items: widget.users labelText: 'Search...',
.where((user) => prefixIcon: Icon(Icons.search),
['SA', 'SB', 'CA', 'CC'].contains(user.accountType)) border: InputBorder
.map((user) { .none, // Remove border to make it look like it's inside the card
return DropdownMenuItem<User>( ),
value: user, ),
child: Text(user.accountNo.toString()), ),
); ),
}).toList(), const SizedBox(height: 20),
) Expanded(
else child: _isLoading
const Text('No accounts found'), ? const Center(child: CircularProgressIndicator())
], : _groupedCheques.isEmpty
? const Center(child: Text('No cheque status found.'))
: ListView(
children: _groupedCheques.entries.map((entry) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...entry.value.map((cheque) =>
ChequeStatusTile(cheque: cheque)),
],
);
}).toList(),
),
),
],
),
),
IgnorePointer(
child: Center(
child: Opacity(
opacity: 0.07, // Reduced opacity
child: ClipOval(
child: Image.asset(
'assets/images/logo.png',
width: 200, // Adjust size as needed
height: 200, // Adjust size as needed
),
), ),
), ),
), ),
const SizedBox(height: 20), ),
TextField( ],
controller: _searchController,
decoration: const InputDecoration(
labelText: 'Search...',
prefixIcon: Icon(Icons.search),
),
),
const SizedBox(height: 20),
Expanded(
child: _isLoading
? const Center(child: CircularProgressIndicator())
: _groupedCheques.isEmpty
? const Center(child: Text('No cheque status found.'))
: ListView(
children: _groupedCheques.entries.map((entry) {
return ExpansionTile(
title: Text(entry.key, style: TextStyle(fontWeight: FontWeight.bold)),
children: entry.value
.map((cheque) => ChequeStatusTile(cheque: cheque))
.toList(),
);
}).toList(),
),
),
],
),
), ),
); );
} }
@@ -245,18 +273,22 @@ class ChequeStatusTile extends StatelessWidget {
Widget _buildCiTile(BuildContext context) { Widget _buildCiTile(BuildContext context) {
return Card( return Card(
margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16), margin: const EdgeInsets.symmetric(
vertical: 8.0,
),
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Chequebook Issued (CI)',
style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 8),
_buildInfoRow('Branch Code:', cheque.branchCode), _buildInfoRow('Branch Code:', cheque.branchCode),
_buildInfoRow('From Cheque:', cheque.fromCheque), _buildInfoRow('From Cheque:', cheque.fromCheque),
_buildInfoRow('To Cheque:', cheque.toCheque), _buildInfoRow('To Cheque:', cheque.toCheque),
_buildInfoRow('Date:', cheque.Date), _buildInfoRow('Date:', cheque.Date),
_buildInfoRow('Cheques Count:', cheque.Chequescount), _buildInfoRow('Cheques Count:', cheque.Chequescount),
_buildInfoRow('Instrument Type:', cheque.InstrType),
], ],
), ),
), ),
@@ -265,19 +297,21 @@ class ChequeStatusTile extends StatelessWidget {
Widget _buildPrTile(BuildContext context) { Widget _buildPrTile(BuildContext context) {
return Card( return Card(
margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16), margin: const EdgeInsets.symmetric(vertical: 8.0),
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Presented Cheque (PR)',
style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 8),
_buildInfoRow('Branch Code:', cheque.branchCode), _buildInfoRow('Branch Code:', cheque.branchCode),
_buildInfoRow('Cheque Number:', cheque.ChequeNumber), _buildInfoRow('Cheque Number:', cheque.ChequeNumber),
_buildInfoRow('Date:', cheque.Date), _buildInfoRow('Date:', cheque.Date),
_buildInfoRow('Transaction Code:', cheque.transactionCode), _buildInfoRow('Transaction Code:', cheque.transactionCode),
_buildInfoRow('Amount:', cheque.amount), _buildInfoRow('Amount:', '${cheque.amount.toString()}'),
_buildInfoRow('Status:', cheque.status, statusColor: _getStatusColor(cheque.status ?? '')), _buildInfoRow('Status:', cheque.status),
_buildInfoRow('Instrument Type:', cheque.InstrType),
], ],
), ),
), ),
@@ -286,48 +320,37 @@ class ChequeStatusTile extends StatelessWidget {
Widget _buildStTile(BuildContext context) { Widget _buildStTile(BuildContext context) {
return Card( return Card(
margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16), margin: const EdgeInsets.symmetric(vertical: 8.0),
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Stop Cheque (ST)',
style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 8),
_buildInfoRow('Branch Code:', cheque.branchCode), _buildInfoRow('Branch Code:', cheque.branchCode),
_buildInfoRow('From Cheque:', cheque.fromCheque), _buildInfoRow('From Cheque:', cheque.fromCheque),
_buildInfoRow('To Cheque:', cheque.toCheque), _buildInfoRow('To Cheque:', cheque.toCheque),
_buildInfoRow('Stop Issue Date:', cheque.stopIssueDate), _buildInfoRow('Stop Issue Date:', cheque.stopIssueDate),
_buildInfoRow('Stop Expiry Date:', cheque.StopExpiryDate), _buildInfoRow('Stop Expiry Date:', cheque.StopExpiryDate),
_buildInfoRow('Cheques Count:', cheque.Chequescount), _buildInfoRow('Cheques Count:', cheque.Chequescount),
_buildInfoRow('Instrument Type:', cheque.InstrType),
], ],
), ),
), ),
); );
} }
Widget _buildInfoRow(String label, String? value, {Color? statusColor}) { Widget _buildInfoRow(String label, String? value) {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0), padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text(label, style: const TextStyle(fontWeight: FontWeight.bold)), Text(label, style: const TextStyle(fontWeight: FontWeight.bold)),
Text(value ?? '', style: TextStyle(color: statusColor)), Text(value ?? ''),
], ],
), ),
); );
} }
Color _getStatusColor(String status) {
switch (status.toLowerCase()) {
case 'cashed':
return Colors.green;
case 'pending':
return Colors.orange;
case 'bounced':
return Colors.red;
default:
return Colors.grey;
}
}
} }

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kmobile/data/models/user.dart'; import 'package:kmobile/data/models/user.dart';
import 'package:kmobile/features/cheque/screens/cheque_status_screen.dart'; import 'package:kmobile/features/cheque/screens/cheque_enquiry_screen.dart';
import 'package:kmobile/features/cheque/screens/stop_cheque_screen.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart'; import 'package:material_symbols_icons/material_symbols_icons.dart';
import '../../../l10n/app_localizations.dart'; import '../../../l10n/app_localizations.dart';
@@ -10,7 +11,8 @@ class ChequeManagementScreen extends StatefulWidget {
const ChequeManagementScreen({ const ChequeManagementScreen({
super.key, super.key,
required this.users, required this.users,
required this.selectedIndex,}); required this.selectedIndex,
});
@override @override
State<ChequeManagementScreen> createState() => _ChequeManagementScreen(); State<ChequeManagementScreen> createState() => _ChequeManagementScreen();
@@ -36,45 +38,41 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
Expanded(
child: ChequeManagementCardTile(
icon: Symbols.add,
label: AppLocalizations.of(context).requestChequeBook,
subtitle: "Apply for a new cheque book",
onTap: () {},
),
),
Expanded(
child: ChequeManagementCardTile(
icon: Symbols.data_alert,
label: "Cheque History",
subtitle: "View the status of your issued cheques",
onTap: () {},
),
),
Expanded(
child: ChequeManagementCardTile(
icon: Symbols.front_hand,
label: AppLocalizations.of(context).stopCheque,
subtitle: "Stop payment for a cheque",
onTap: () {},
),
),
Expanded( Expanded(
child: ChequeManagementCardTile( child: ChequeManagementCardTile(
icon: Symbols.payments, icon: Symbols.payments,
label: "Track Cheque Status", label: "Cheque Enquiry",
subtitle: "Check the current status of your cheque", subtitle:
"You can view the status of your issued cheque book, presented cheques and details of stopped cheques including relevant dates, cheque numbers and other essential information",
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => ChequeStatusScreen( builder: (context) => ChequeEnquiryScreen(
users: users, users: users,
selectedIndex: selectedAccountIndex, selectedIndex: selectedAccountIndex,
), ),
), ),
); );
},
),
),
Expanded(
child: ChequeManagementCardTile(
icon: Symbols.block_sharp,
label: AppLocalizations.of(context).stopCheque,
subtitle:
"Initiate a stop payment request for a cheque that has already been presented for payment. This action helps prevent unauthorized transactions or rectifies errors on cheques that are in the process of being cleared",
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => StopChequeScreen(
users: users,
selectedIndex: selectedAccountIndex,
),
),
);
}, },
), ),
), ),

View File

@@ -0,0 +1,315 @@
import 'package:flutter/material.dart';
import 'package:kmobile/api/services/cheque_service.dart';
import 'package:kmobile/data/models/user.dart';
import 'package:kmobile/di/injection.dart';
class StopChequeScreen extends StatefulWidget {
final List<User> users;
final int selectedIndex;
const StopChequeScreen({
super.key,
required this.users,
required this.selectedIndex,
});
@override
State<StopChequeScreen> createState() => _StopChequeScreenState();
}
class _StopChequeScreenState extends State<StopChequeScreen> {
User? _selectedAccount;
final TextEditingController _searchController = TextEditingController();
var service = getIt<ChequeService>();
bool _isLoading = true;
List<Cheque> _allCheques = [];
Map<String, List<Cheque>> _groupedCheques = {};
List<User> _filteredUsers = [];
@override
void initState() {
super.initState();
_filteredUsers = widget.users
.where((user) => ['SA', 'SB', 'CA', 'CC'].contains(user.accountType))
.toList();
if (widget.users.isNotEmpty && widget.selectedIndex < widget.users.length) {
if (_filteredUsers.isNotEmpty) {
if (_filteredUsers.contains(widget.users[widget.selectedIndex])) {
_selectedAccount = widget.users[widget.selectedIndex];
} else {
_selectedAccount = _filteredUsers.first;
}
} else {
_selectedAccount = widget.users[widget.selectedIndex];
}
} else {
if (_filteredUsers.isNotEmpty) {
_selectedAccount = _filteredUsers.first;
}
}
_loadCheques();
_searchController.addListener(() {
_filterCheques(_searchController.text);
});
}
Future<void> _loadCheques() async {
if (_selectedAccount == null) {
setState(() {
_isLoading = false;
_groupedCheques = {};
});
return;
}
setState(() {
_isLoading = true;
});
String instrType;
switch (_selectedAccount!.accountType) {
case 'SA':
case 'SB':
instrType = '10';
break;
case 'CA':
instrType = '11';
break;
case 'CC':
instrType = '13';
break;
default:
instrType = '10';
}
try {
final data = await service.ChequeEnquiry(
accountNumber: _selectedAccount!.accountNo!, instrType: instrType);
_allCheques = data.where((cheque) => cheque.type == 'PR').toList();
_groupedCheques.clear();
for (var cheque in _allCheques) {
if (cheque.type != null) {
if (!_groupedCheques.containsKey(cheque.type)) {
_groupedCheques[cheque.type!] = [];
}
_groupedCheques[cheque.type!]!.add(cheque);
}
}
setState(() {
_isLoading = false;
});
} catch (e) {
setState(() {
_isLoading = false;
_groupedCheques = {};
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Failed to fetch cheque status: ${e.toString()}'),
),
);
}
}
void _filterCheques(String query) {
_groupedCheques.clear();
List<Cheque> filteredCheques;
if (query.isEmpty) {
filteredCheques = _allCheques;
} else {
filteredCheques = _allCheques.where((cheque) {
final lowerQuery = query.toLowerCase();
return (cheque.ChequeNumber?.toLowerCase().contains(lowerQuery) ?? false) ||
(cheque.status?.toLowerCase().contains(lowerQuery) ?? false) ||
(cheque.fromCheque?.toLowerCase().contains(lowerQuery) ?? false) ||
(cheque.toCheque?.toLowerCase().contains(lowerQuery) ?? false);
}).toList();
}
for (var cheque in filteredCheques) {
if (cheque.type != null) {
if (!_groupedCheques.containsKey(cheque.type)) {
_groupedCheques[cheque.type!] = [];
}
_groupedCheques[cheque.type!]!.add(cheque);
}
}
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Stop Cheque'),
centerTitle: false,
),
body: Stack(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Card(
elevation: 4,
margin: const EdgeInsets.symmetric(vertical: 8.0),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"Account Number",
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 18),
),
const SizedBox(width: 16),
if (_selectedAccount != null)
Expanded(
child: DropdownButton<User>(
value: _selectedAccount,
onChanged: (User? newUser) {
if (newUser != null) {
setState(() {
_selectedAccount = newUser;
_loadCheques();
});
}
},
items: _filteredUsers.map((user) {
return DropdownMenuItem<User>(
value: user,
child: Text(user.accountNo.toString()),
);
}).toList(),
),
)
else
const Text('No accounts found'),
],
),
),
),
const SizedBox(height: 20),
Card(
elevation: 4,
margin: const EdgeInsets.symmetric(vertical: 8.0),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: _searchController,
decoration: const InputDecoration(
labelText: 'Search',
prefixIcon: Icon(Icons.search),
border: InputBorder
.none, // Remove border to make it look like it's inside the card
),
),
),
),
const SizedBox(height: 20),
Expanded(
child: _isLoading
? const Center(child: CircularProgressIndicator())
: _groupedCheques.isEmpty
? const Center(child: Text('No cheque status found.'))
: ListView(
children: _groupedCheques.entries.map((entry) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...entry.value.map((cheque) =>
ChequeStatusTile(cheque: cheque)),
],
);
}).toList(),
),
),
],
),
),
IgnorePointer(
child: Center(
child: Opacity(
opacity: 0.07, // Reduced opacity
child: ClipOval(
child: Image.asset(
'assets/images/logo.png',
width: 200, // Adjust size as needed
height: 200, // Adjust size as needed
),
),
),
),
),
],
),
);
}
}
class ChequeStatusTile extends StatelessWidget {
final Cheque cheque;
const ChequeStatusTile({
super.key,
required this.cheque,
});
@override
Widget build(BuildContext context) {
switch (cheque.type) {
case 'PR':
return _buildPrTile(context);
default:
return const SizedBox.shrink();
}
}
Widget _buildPrTile(BuildContext context) {
return Card(
margin: const EdgeInsets.symmetric(vertical: 8.0),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Presented Cheque(PR)',
style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 8),
_buildInfoRow('Branch Code:', cheque.branchCode),
_buildInfoRow('Cheque Number:', cheque.ChequeNumber),
_buildInfoRow('Date:', cheque.Date),
_buildInfoRow('Transaction Code:', cheque.transactionCode),
_buildInfoRow('Amount:', '${cheque.amount.toString()}'),
_buildInfoRow('Status:', cheque.status),
const SizedBox(height: 16),
Center(
child: ElevatedButton.icon(
onPressed: () {
// TODO: Implement stop cheque functionality
},
icon: const Icon(Icons.block_sharp),
label: const Text('Stop Cheque'),
),
),
],
),
),
);
}
Widget _buildInfoRow(String label, String? value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: const TextStyle(fontWeight: FontWeight.bold)),
Text(value ?? ''),
],
),
);
}
}