Fromatting and localizations

This commit is contained in:
2025-12-31 12:44:39 +05:30
parent 60270a5fa9
commit 54a7b8f1b0
21 changed files with 501 additions and 194 deletions

View File

@@ -2,6 +2,7 @@ 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';
import 'package:kmobile/l10n/app_localizations.dart';
class ChequeEnquiryScreen extends StatefulWidget {
final List<User> users;
@@ -119,7 +120,8 @@ class _ChequeEnquiryScreenState extends State<ChequeEnquiryScreen> {
} else {
filteredCheques = _allCheques.where((cheque) {
final lowerQuery = query.toLowerCase();
return (cheque.ChequeNumber?.toLowerCase().contains(lowerQuery) ?? false) ||
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);
@@ -142,7 +144,7 @@ class _ChequeEnquiryScreenState extends State<ChequeEnquiryScreen> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Cheque Enquiry'),
title: Text(AppLocalizations.of(context).chequeEnquiryTitle),
centerTitle: false,
),
body: Stack(
@@ -159,9 +161,9 @@ class _ChequeEnquiryScreenState extends State<ChequeEnquiryScreen> {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"Account Number",
style: TextStyle(
Text(
AppLocalizations.of(context).accountNumber,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 18),
),
const SizedBox(width: 16),
@@ -199,9 +201,10 @@ class _ChequeEnquiryScreenState extends State<ChequeEnquiryScreen> {
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: _searchController,
decoration: const InputDecoration(
labelText: 'Search by Cheque Details',
prefixIcon: Icon(Icons.search),
decoration: InputDecoration(
labelText: AppLocalizations.of(context)
.searchByChequeDetailsHint,
prefixIcon: const Icon(Icons.search),
border: InputBorder
.none, // Remove border to make it look like it's inside the card
),
@@ -213,7 +216,9 @@ class _ChequeEnquiryScreenState extends State<ChequeEnquiryScreen> {
child: _isLoading
? const Center(child: CircularProgressIndicator())
: _groupedCheques.isEmpty
? const Center(child: Text('No cheque status found.'))
? Center(
child: Text(AppLocalizations.of(context)
.noChequeStatusFound))
: ListView(
children: _groupedCheques.entries.map((entry) {
return Column(
@@ -281,7 +286,7 @@ class ChequeStatusTile extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Chequebook Issued (CI)',
Text(AppLocalizations.of(context).chequebookIssuedLabel,
style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 8),
_buildInfoRow('Branch Code:', cheque.branchCode),
@@ -303,7 +308,7 @@ class ChequeStatusTile extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Presented Cheque (PR)',
Text(AppLocalizations.of(context).presentedChequeLabel,
style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 8),
_buildInfoRow('Branch Code:', cheque.branchCode),
@@ -326,7 +331,7 @@ class ChequeStatusTile extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Stop Cheque (ST)',
Text(AppLocalizations.of(context).stopChequeLabel,
style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 8),
_buildInfoRow('Branch Code:', cheque.branchCode),

View File

@@ -41,9 +41,9 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
Expanded(
child: ChequeManagementCardTile(
icon: Symbols.payments,
label: "Cheque Enquiry",
label: AppLocalizations.of(context).chequeEnquiryTitle,
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",
AppLocalizations.of(context).chequeEnquirySubtitle,
onTap: () {
Navigator.push(
context,
@@ -61,8 +61,7 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
child: ChequeManagementCardTile(
icon: Symbols.block_sharp,
label: AppLocalizations.of(context).stopCheque,
subtitle:
"Initiate stop for one or more cheques from your issued checkbook. This essential service helps prevent unauthorized transactions and protects against fraud.",
subtitle: AppLocalizations.of(context).stopChequeSubtitle,
onTap: () {
Navigator.push(
context,
@@ -138,8 +137,9 @@ class ChequeManagementCardTile extends StatelessWidget {
Icon(
icon,
size: 48, // Make icon larger
color:
disable ? theme.disabledColor : theme.colorScheme.primary,
color: disable
? theme.disabledColor
: theme.colorScheme.primary,
),
const SizedBox(height: 12),
Text(

View File

@@ -120,7 +120,7 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Stop Cheque'),
title: Text(AppLocalizations.of(context).stopChequeTitle),
centerTitle: false,
),
body: Stack(
@@ -137,9 +137,9 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"Account Number",
style: TextStyle(
Text(
AppLocalizations.of(context).accountNumber,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 18),
),
const SizedBox(width: 16),
@@ -164,7 +164,7 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
),
)
else
const Text('No accounts found'),
Text(AppLocalizations.of(context).noAccountsFound),
],
),
),
@@ -182,8 +182,7 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
StopSingleChequeScreen(
builder: (context) => StopSingleChequeScreen(
selectedAccount: _selectedAccount!,
date: _ciCheque!.Date!,
instrType: _ciCheque!.InstrType!,
@@ -194,9 +193,9 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'No cheque book found to stop cheques from.'),
SnackBar(
content: Text(AppLocalizations.of(context)
.noChequebookToStop),
),
);
}
@@ -205,7 +204,8 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
padding: const EdgeInsets.all(16.0),
child: Center(
child: Text(
'Stop Single Cheque',
AppLocalizations.of(context)
.stopSingleChequeTitle,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
@@ -223,8 +223,7 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
const SizedBox(width: 10),
Expanded(
child: Card(
color:
Theme.of(context).colorScheme.primaryContainer,
color: Theme.of(context).colorScheme.primaryContainer,
elevation: 4,
child: InkWell(
onTap: () {
@@ -244,9 +243,9 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'Please select an account first.'),
SnackBar(
content: Text(AppLocalizations.of(context)
.pleaseSelectAccountFirst),
),
);
}
@@ -255,7 +254,8 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
padding: const EdgeInsets.all(16.0),
child: Center(
child: Text(
'Stop Multiple Cheques',
AppLocalizations.of(context)
.stopMultipleChequesButton,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
@@ -277,8 +277,9 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
child: _isLoading
? const Center(child: CircularProgressIndicator())
: _ciCheque == null
? const Center(
child: Text('No Cheque Issued status found.'))
? Center(
child: Text(AppLocalizations.of(context)
.noChequeIssuedStatus))
: _buildCiTile(context, _ciCheque!),
),
],
@@ -313,7 +314,7 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Chequebook Details',
Text(AppLocalizations.of(context).chequebookDetailsTitle,
style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 8),
_buildInfoRow('Account Number:', _selectedAccount!.accountNo!),

View File

@@ -5,6 +5,7 @@ import 'package:kmobile/api/services/cheque_service.dart';
import 'package:kmobile/data/models/user.dart';
import 'package:kmobile/di/injection.dart';
import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart';
import 'package:kmobile/l10n/app_localizations.dart';
class StopMultipleChequesScreen extends StatefulWidget {
final User selectedAccount;
@@ -13,9 +14,8 @@ class StopMultipleChequesScreen extends StatefulWidget {
final String fromCheque;
final String toCheque;
const StopMultipleChequesScreen(
{super.key,
{super.key,
required this.selectedAccount,
required this.date,
required this.instrType,
@@ -82,7 +82,7 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Stop Multiple Cheques'),
title: Text(AppLocalizations.of(context).stopMultipleChequesTitle),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
@@ -100,20 +100,22 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
height: 40,
),
title: Text(widget.selectedAccount.accountNo!),
subtitle: const Text("Account Number"),
subtitle:
Text(AppLocalizations.of(context).accountNumberTitle),
),
),
const SizedBox(height: 24),
TextFormField(
controller: _stopFromChequeNoController,
decoration: const InputDecoration(
labelText: 'From Cheque Number *',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context).fromChequeNumberHint,
border: const OutlineInputBorder(),
),
keyboardType: TextInputType.number,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter a cheque number';
return AppLocalizations.of(context)
.pleaseEnterChequeNumberError;
}
final chequeNumber = int.tryParse(value);
final fromCheque = int.tryParse(widget.fromCheque);
@@ -121,10 +123,12 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
if (chequeNumber == null ||
fromCheque == null ||
toCheque == null) {
return 'Invalid cheque number format';
return AppLocalizations.of(context)
.invalidChequeNumberFormatError;
}
if (chequeNumber < fromCheque || chequeNumber > toCheque) {
return 'Cheque number must be between ${widget.fromCheque} and ${widget.toCheque}';
return AppLocalizations.of(context).chequeNumberRangeError(
widget.fromCheque, widget.toCheque);
}
return null;
},
@@ -132,14 +136,15 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
const SizedBox(height: 16),
TextFormField(
controller: _stopToChequeNoController,
decoration: const InputDecoration(
labelText: 'To Cheque Number *',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context).toChequeNumberHint,
border: const OutlineInputBorder(),
),
keyboardType: TextInputType.number,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter a cheque number';
return AppLocalizations.of(context)
.pleaseEnterChequeNumberError;
}
final chequeNumber = int.tryParse(value);
final fromCheque = int.tryParse(widget.fromCheque);
@@ -147,10 +152,12 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
if (chequeNumber == null ||
fromCheque == null ||
toCheque == null) {
return 'Invalid cheque number format';
return AppLocalizations.of(context)
.invalidChequeNumberFormatError;
}
if (chequeNumber < fromCheque || chequeNumber > toCheque) {
return 'Cheque number must be between ${widget.fromCheque} and ${widget.toCheque}';
return AppLocalizations.of(context).chequeNumberRangeError(
widget.fromCheque, widget.toCheque);
}
return null;
},
@@ -159,53 +166,54 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
TextFormField(
initialValue: widget.instrType,
readOnly: true,
decoration: const InputDecoration(
labelText: 'Instrument Type *',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context).instrumentTypeLabel,
border: const OutlineInputBorder(),
),
),
const SizedBox(height: 16),
TextFormField(
controller: _stopIssueDateController,
decoration: const InputDecoration(
labelText: 'Stop Issue Date',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context).stopIssueDateHint,
border: const OutlineInputBorder(),
),
keyboardType: TextInputType.datetime,
),
const SizedBox(height: 16),
TextFormField(
controller: _stopExpiryDateController,
decoration: const InputDecoration(
labelText: 'Stop Expiry Date',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context).stopExpiryDateHint,
border: const OutlineInputBorder(),
),
keyboardType: TextInputType.datetime,
),
const SizedBox(height: 16),
TextFormField(
controller: _stopAmountController,
decoration: const InputDecoration(
labelText: 'Stop Amount',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context).stopAmountHint,
border: const OutlineInputBorder(),
),
keyboardType: TextInputType.number,
),
const SizedBox(height: 16),
TextFormField(
controller: _stopCommentController,
decoration: const InputDecoration(
labelText: 'Stop Comment',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context).stopCommentHint,
border: const OutlineInputBorder(),
),
),
const SizedBox(height: 16),
TextFormField(
initialValue: _formatDate(widget.date),
readOnly: true,
decoration: const InputDecoration(
labelText: 'Chequebook Issue Date',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText:
AppLocalizations.of(context).chequebookIssueDateHint,
border: const OutlineInputBorder(),
),
),
const SizedBox(height: 32),
@@ -217,18 +225,16 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
MaterialPageRoute(
builder: (context) => TransactionPinScreen(
onPinCompleted: (ctx, pin) async {
Navigator.pop(context);
Navigator.pop(context);
try {
final response = await _chequeService.stopCheque(
accountno: widget.selectedAccount.accountNo!,
stopFromChequeNo:
_stopFromChequeNoController.text,
instrType: widget.instrType,
stopToChequeNo:
_stopToChequeNoController.text,
stopToChequeNo: _stopToChequeNoController.text,
stopIssueDate: _stopIssueDateController.text,
stopExpiryDate:
_stopExpiryDateController.text,
stopExpiryDate: _stopExpiryDateController.text,
stopAmount: _stopAmountController.text,
stopComment: _stopCommentController.text,
chequeIssueDate: widget.date,
@@ -236,7 +242,7 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
);
if (!mounted) return;
final decodedResponse = jsonDecode(response);
final status = decodedResponse['status'];
final status = decodedResponse['status'];
final message = decodedResponse['message'];
if (status == 'SUCCESS') {
_showResponseDialog('Success', message);
@@ -248,9 +254,11 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
print(e.toString());
try {
final errorBodyString = e.toString().split('Exception: ')[1];
final errorBodyString =
e.toString().split('Exception: ')[1];
final errorBody = jsonDecode(errorBodyString);
if (errorBody.containsKey('error') && errorBody['error'] == 'INCORRECT_TPIN') {
if (errorBody.containsKey('error') &&
errorBody['error'] == 'INCORRECT_TPIN') {
_showResponseDialog('Invalid TPIN',
'The TPIN you entered is incorrect. Please try again.');
} else {
@@ -268,7 +276,7 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
);
}
},
child: const Text('Stop Cheque'),
child: Text(AppLocalizations.of(context).stopChequeButton),
),
],
),

View File

@@ -4,6 +4,7 @@ import 'package:kmobile/di/injection.dart';
import 'package:flutter/material.dart';
import 'package:kmobile/api/services/cheque_service.dart';
import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart';
import 'package:kmobile/l10n/app_localizations.dart';
class StopSingleChequeScreen extends StatefulWidget {
final User selectedAccount;
@@ -63,7 +64,7 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
),
actions: <Widget>[
TextButton(
child: const Text('Close'),
child: Text(AppLocalizations.of(context).closeButton),
onPressed: () {
Navigator.of(context).pop();
},
@@ -78,7 +79,7 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Stop Single Cheque'),
title: Text(AppLocalizations.of(context).stopSingleChequeTitle),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
@@ -96,20 +97,22 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
height: 40,
),
title: Text(widget.selectedAccount.accountNo!),
subtitle: const Text("Account Number"),
subtitle:
Text(AppLocalizations.of(context).accountNumberLabel),
),
),
const SizedBox(height: 24),
TextFormField(
controller: _stopFromChequeNoController,
decoration: const InputDecoration(
labelText: 'Cheque Number *',
decoration: InputDecoration(
labelText: AppLocalizations.of(context).chequeNumberLabel,
border: OutlineInputBorder(),
),
keyboardType: TextInputType.number,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter a cheque number';
return AppLocalizations.of(context)
.pleaseEnterChequeNumberError;
}
final chequeNumber = int.tryParse(value);
final fromCheque = int.tryParse(widget.fromCheque);
@@ -117,10 +120,12 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
if (chequeNumber == null ||
fromCheque == null ||
toCheque == null) {
return 'Invalid cheque number format';
return AppLocalizations.of(context)
.invalidChequeNumberFormatError;
}
if (chequeNumber < fromCheque || chequeNumber > toCheque) {
return 'Cheque number must be between ${widget.fromCheque} and ${widget.toCheque}';
return AppLocalizations.of(context).chequeNumberRangeError(
widget.fromCheque, widget.toCheque);
}
return null;
},
@@ -129,53 +134,54 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
TextFormField(
initialValue: widget.instrType,
readOnly: true,
decoration: const InputDecoration(
labelText: 'Instrument Type *',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context).instrumentTypeLabel,
border: const OutlineInputBorder(),
),
),
const SizedBox(height: 16),
TextFormField(
controller: _stopIssueDateController,
decoration: const InputDecoration(
labelText: 'Stop Issue Date',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context).stopIssueDateLabel,
border: const OutlineInputBorder(),
),
keyboardType: TextInputType.datetime,
),
const SizedBox(height: 16),
TextFormField(
controller: _stopExpiryDateController,
decoration: const InputDecoration(
labelText: 'Stop Expiry Date',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context).stopExpiryDateLabel,
border: const OutlineInputBorder(),
),
keyboardType: TextInputType.datetime,
),
const SizedBox(height: 16),
TextFormField(
controller: _stopAmountController,
decoration: const InputDecoration(
labelText: 'Stop Amount',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context).stopAmountHint,
border: const OutlineInputBorder(),
),
keyboardType: TextInputType.number,
),
const SizedBox(height: 16),
TextFormField(
controller: _stopCommentController,
decoration: const InputDecoration(
labelText: 'Stop Comment',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context).stopCommentHint,
border: const OutlineInputBorder(),
),
),
const SizedBox(height: 16),
TextFormField(
initialValue: _formatDate(widget.date),
readOnly: true,
decoration: const InputDecoration(
labelText: 'Chequebook Issue Date',
border: OutlineInputBorder(),
decoration: InputDecoration(
labelText:
AppLocalizations.of(context).chequebookIssueDateHint,
border: const OutlineInputBorder(),
),
),
const SizedBox(height: 32),
@@ -187,7 +193,7 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
MaterialPageRoute(
builder: (context) => TransactionPinScreen(
onPinCompleted: (ctx, pin) async {
Navigator.pop(context);
Navigator.pop(context);
try {
final response = await _chequeService.stopCheque(
accountno: widget.selectedAccount.accountNo!,
@@ -197,8 +203,7 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
stopToChequeNo:
_stopFromChequeNoController.text,
stopIssueDate: _stopIssueDateController.text,
stopExpiryDate:
_stopExpiryDateController.text,
stopExpiryDate: _stopExpiryDateController.text,
stopAmount: _stopAmountController.text,
stopComment: _stopCommentController.text,
chequeIssueDate: widget.date,
@@ -206,7 +211,7 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
);
if (!mounted) return;
final decodedResponse = jsonDecode(response);
final status = decodedResponse['status'];
final status = decodedResponse['status'];
final message = decodedResponse['message'];
if (status == 'SUCCESS') {
_showResponseDialog('Success', message);
@@ -218,9 +223,11 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
print(e.toString());
try {
final errorBodyString = e.toString().split('Exception: ')[1];
final errorBodyString =
e.toString().split('Exception: ')[1];
final errorBody = jsonDecode(errorBodyString);
if (errorBody.containsKey('error') && errorBody['error'] == 'INCORRECT_TPIN') {
if (errorBody.containsKey('error') &&
errorBody['error'] == 'INCORRECT_TPIN') {
_showResponseDialog('Invalid TPIN',
'The TPIN you entered is incorrect. Please try again.');
} else {
@@ -238,7 +245,7 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
);
}
},
child: const Text('Stop Cheque'),
child: Text(AppLocalizations.of(context).stopChequeButton),
),
],
),