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

@@ -1,6 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
class Cheque { class Cheque {
final String? type; final String? type;
final String? InstrType; final String? InstrType;
@@ -17,19 +18,19 @@ class Cheque {
final String? StopExpiryDate; final String? StopExpiryDate;
Cheque({ Cheque({
this.type, this.type,
this.InstrType, this.InstrType,
this.Date, this.Date,
this.branchCode, this.branchCode,
this.fromCheque, this.fromCheque,
this.toCheque, this.toCheque,
this.Chequescount, this.Chequescount,
this.ChequeNumber, this.ChequeNumber,
this.transactionCode, this.transactionCode,
this.amount, this.amount,
this.status, this.status,
this.stopIssueDate, this.stopIssueDate,
this.StopExpiryDate, this.StopExpiryDate,
}); });
factory Cheque.fromJson(Map<String, dynamic> json) { factory Cheque.fromJson(Map<String, dynamic> json) {
@@ -47,7 +48,7 @@ this.StopExpiryDate,
status: json['status'] ?? '', status: json['status'] ?? '',
stopIssueDate: json['stopIssueDate'] ?? '', stopIssueDate: json['stopIssueDate'] ?? '',
StopExpiryDate: json['StopExpiryDate'] ?? '', StopExpiryDate: json['StopExpiryDate'] ?? '',
); );
} }
static List<Cheque> listFromJson(List<dynamic> jsonList) { static List<Cheque> listFromJson(List<dynamic> jsonList) {
@@ -61,17 +62,17 @@ class ChequeService {
final Dio _dio; final Dio _dio;
ChequeService(this._dio); ChequeService(this._dio);
Future<List<Cheque>> ChequeEnquiry( Future<List<Cheque>> ChequeEnquiry({
{required String accountNumber, required String accountNumber,
required String instrType, required String instrType,
}) async { }) async {
try { try {
final response = await _dio.get( final response = await _dio.get(
"/api/cheque/enquiry", "/api/cheque/enquiry",
queryParameters: { queryParameters: {
'accountNumber': accountNumber, 'accountNumber': accountNumber,
'instrumentType': instrType, 'instrumentType': instrType,
}, },
options: Options( options: Options(
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
@@ -80,13 +81,15 @@ class ChequeService {
); );
if (response.statusCode == 200) { if (response.statusCode == 200) {
if (response.data is Map<String, dynamic> && response.data.containsKey('records')) { if (response.data is Map<String, dynamic> &&
response.data.containsKey('records')) {
final records = response.data['records']; final records = response.data['records'];
if (records is List) { if (records is List) {
return Cheque.listFromJson(records); return Cheque.listFromJson(records);
} }
} }
throw Exception("Unexpected API response format: 'records' list not found or malformed"); throw Exception(
"Unexpected API response format: 'records' list not found or malformed");
} else { } else {
throw Exception("Failed to fetch"); throw Exception("Failed to fetch");
} }
@@ -101,21 +104,19 @@ class ChequeService {
required String stopFromChequeNo, required String stopFromChequeNo,
required String instrType, required String instrType,
String? stopToChequeNo, String? stopToChequeNo,
String? stopIssueDate, String? stopIssueDate,
String? stopExpiryDate, String? stopExpiryDate,
String? stopAmount, String? stopAmount,
String? stopComment, String? stopComment,
String? chequeIssueDate, String? chequeIssueDate,
required String tpin, required String tpin,
}) async { }) async {
final response = await _dio.post( final response = await _dio.post(
'/api/cheque/stop', '/api/cheque/stop',
options: Options(
options: Options( validateStatus: (int? status) => true,
validateStatus: (int? status) => true, receiveDataWhenStatusError: true,
receiveDataWhenStatusError: true, ),
),
data: { data: {
'accountNumber': accountno, 'accountNumber': accountno,
'stopFromChequeNo': stopFromChequeNo, 'stopFromChequeNo': stopFromChequeNo,
@@ -126,12 +127,12 @@ class ChequeService {
'stopAmount': stopAmount, 'stopAmount': stopAmount,
'stopComment': stopComment, 'stopComment': stopComment,
'chqIssueDate': chequeIssueDate, 'chqIssueDate': chequeIssueDate,
'tpin':tpin, 'tpin': tpin,
}, },
); );
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception(jsonEncode(response.data)); throw Exception(jsonEncode(response.data));
} }
return response.toString(); return response.toString();
} }
} }

View File

@@ -77,8 +77,8 @@ Dio _createDioClient() {
BaseOptions( BaseOptions(
baseUrl: baseUrl:
'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com', //test 'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com', //test
//'http://lb-kccb-mobile-banking-app-848675342.ap-south-1.elb.amazonaws.com', //prod //'http://lb-kccb-mobile-banking-app-848675342.ap-south-1.elb.amazonaws.com', //prod
//'https://kccbmbnk.net', //prod small //'https://kccbmbnk.net', //prod small
connectTimeout: const Duration(seconds: 60), connectTimeout: const Duration(seconds: 60),
receiveTimeout: const Duration(seconds: 60), receiveTimeout: const Duration(seconds: 60),
headers: { headers: {

View File

@@ -147,7 +147,8 @@ class _ManageBeneficiariesScreen extends State<ManageBeneficiariesScreen> {
child: TextField( child: TextField(
controller: _searchController, controller: _searchController,
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search by name or account number", hintText:
AppLocalizations.of(context).searchByNameOrAccountHint,
prefixIcon: const Icon(Icons.search), prefixIcon: const Icon(Icons.search),
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),

View File

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

View File

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

View File

@@ -120,7 +120,7 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('Stop Cheque'), title: Text(AppLocalizations.of(context).stopChequeTitle),
centerTitle: false, centerTitle: false,
), ),
body: Stack( body: Stack(
@@ -137,9 +137,9 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
const Text( Text(
"Account Number", AppLocalizations.of(context).accountNumber,
style: TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 18), fontWeight: FontWeight.bold, fontSize: 18),
), ),
const SizedBox(width: 16), const SizedBox(width: 16),
@@ -164,7 +164,7 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
), ),
) )
else else
const Text('No accounts found'), Text(AppLocalizations.of(context).noAccountsFound),
], ],
), ),
), ),
@@ -182,8 +182,7 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => builder: (context) => StopSingleChequeScreen(
StopSingleChequeScreen(
selectedAccount: _selectedAccount!, selectedAccount: _selectedAccount!,
date: _ciCheque!.Date!, date: _ciCheque!.Date!,
instrType: _ciCheque!.InstrType!, instrType: _ciCheque!.InstrType!,
@@ -194,9 +193,9 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
); );
} else { } else {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar( SnackBar(
content: Text( content: Text(AppLocalizations.of(context)
'No cheque book found to stop cheques from.'), .noChequebookToStop),
), ),
); );
} }
@@ -205,7 +204,8 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Center( child: Center(
child: Text( child: Text(
'Stop Single Cheque', AppLocalizations.of(context)
.stopSingleChequeTitle,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
@@ -223,8 +223,7 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
const SizedBox(width: 10), const SizedBox(width: 10),
Expanded( Expanded(
child: Card( child: Card(
color: color: Theme.of(context).colorScheme.primaryContainer,
Theme.of(context).colorScheme.primaryContainer,
elevation: 4, elevation: 4,
child: InkWell( child: InkWell(
onTap: () { onTap: () {
@@ -244,9 +243,9 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
); );
} else { } else {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar( SnackBar(
content: Text( content: Text(AppLocalizations.of(context)
'Please select an account first.'), .pleaseSelectAccountFirst),
), ),
); );
} }
@@ -255,7 +254,8 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Center( child: Center(
child: Text( child: Text(
'Stop Multiple Cheques', AppLocalizations.of(context)
.stopMultipleChequesButton,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
@@ -277,8 +277,9 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
child: _isLoading child: _isLoading
? const Center(child: CircularProgressIndicator()) ? const Center(child: CircularProgressIndicator())
: _ciCheque == null : _ciCheque == null
? const Center( ? Center(
child: Text('No Cheque Issued status found.')) child: Text(AppLocalizations.of(context)
.noChequeIssuedStatus))
: _buildCiTile(context, _ciCheque!), : _buildCiTile(context, _ciCheque!),
), ),
], ],
@@ -313,7 +314,7 @@ class _StopChequeScreenState extends State<StopChequeScreen> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Chequebook Details', Text(AppLocalizations.of(context).chequebookDetailsTitle,
style: Theme.of(context).textTheme.titleLarge), style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 8), const SizedBox(height: 8),
_buildInfoRow('Account Number:', _selectedAccount!.accountNo!), _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/data/models/user.dart';
import 'package:kmobile/di/injection.dart'; import 'package:kmobile/di/injection.dart';
import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart'; import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart';
import 'package:kmobile/l10n/app_localizations.dart';
class StopMultipleChequesScreen extends StatefulWidget { class StopMultipleChequesScreen extends StatefulWidget {
final User selectedAccount; final User selectedAccount;
@@ -13,9 +14,8 @@ class StopMultipleChequesScreen extends StatefulWidget {
final String fromCheque; final String fromCheque;
final String toCheque; final String toCheque;
const StopMultipleChequesScreen( const StopMultipleChequesScreen(
{super.key, {super.key,
required this.selectedAccount, required this.selectedAccount,
required this.date, required this.date,
required this.instrType, required this.instrType,
@@ -82,7 +82,7 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('Stop Multiple Cheques'), title: Text(AppLocalizations.of(context).stopMultipleChequesTitle),
), ),
body: Padding( body: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
@@ -100,20 +100,22 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
height: 40, height: 40,
), ),
title: Text(widget.selectedAccount.accountNo!), title: Text(widget.selectedAccount.accountNo!),
subtitle: const Text("Account Number"), subtitle:
Text(AppLocalizations.of(context).accountNumberTitle),
), ),
), ),
const SizedBox(height: 24), const SizedBox(height: 24),
TextFormField( TextFormField(
controller: _stopFromChequeNoController, controller: _stopFromChequeNoController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'From Cheque Number *', labelText: AppLocalizations.of(context).fromChequeNumberHint,
border: OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Please enter a cheque number'; return AppLocalizations.of(context)
.pleaseEnterChequeNumberError;
} }
final chequeNumber = int.tryParse(value); final chequeNumber = int.tryParse(value);
final fromCheque = int.tryParse(widget.fromCheque); final fromCheque = int.tryParse(widget.fromCheque);
@@ -121,10 +123,12 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
if (chequeNumber == null || if (chequeNumber == null ||
fromCheque == null || fromCheque == null ||
toCheque == null) { toCheque == null) {
return 'Invalid cheque number format'; return AppLocalizations.of(context)
.invalidChequeNumberFormatError;
} }
if (chequeNumber < fromCheque || chequeNumber > toCheque) { 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; return null;
}, },
@@ -132,14 +136,15 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
controller: _stopToChequeNoController, controller: _stopToChequeNoController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'To Cheque Number *', labelText: AppLocalizations.of(context).toChequeNumberHint,
border: OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Please enter a cheque number'; return AppLocalizations.of(context)
.pleaseEnterChequeNumberError;
} }
final chequeNumber = int.tryParse(value); final chequeNumber = int.tryParse(value);
final fromCheque = int.tryParse(widget.fromCheque); final fromCheque = int.tryParse(widget.fromCheque);
@@ -147,10 +152,12 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
if (chequeNumber == null || if (chequeNumber == null ||
fromCheque == null || fromCheque == null ||
toCheque == null) { toCheque == null) {
return 'Invalid cheque number format'; return AppLocalizations.of(context)
.invalidChequeNumberFormatError;
} }
if (chequeNumber < fromCheque || chequeNumber > toCheque) { 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; return null;
}, },
@@ -159,53 +166,54 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
TextFormField( TextFormField(
initialValue: widget.instrType, initialValue: widget.instrType,
readOnly: true, readOnly: true,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Instrument Type *', labelText: AppLocalizations.of(context).instrumentTypeLabel,
border: OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
controller: _stopIssueDateController, controller: _stopIssueDateController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Stop Issue Date', labelText: AppLocalizations.of(context).stopIssueDateHint,
border: OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
keyboardType: TextInputType.datetime, keyboardType: TextInputType.datetime,
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
controller: _stopExpiryDateController, controller: _stopExpiryDateController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Stop Expiry Date', labelText: AppLocalizations.of(context).stopExpiryDateHint,
border: OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
keyboardType: TextInputType.datetime, keyboardType: TextInputType.datetime,
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
controller: _stopAmountController, controller: _stopAmountController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Stop Amount', labelText: AppLocalizations.of(context).stopAmountHint,
border: OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
controller: _stopCommentController, controller: _stopCommentController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Stop Comment', labelText: AppLocalizations.of(context).stopCommentHint,
border: OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
initialValue: _formatDate(widget.date), initialValue: _formatDate(widget.date),
readOnly: true, readOnly: true,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Chequebook Issue Date', labelText:
border: OutlineInputBorder(), AppLocalizations.of(context).chequebookIssueDateHint,
border: const OutlineInputBorder(),
), ),
), ),
const SizedBox(height: 32), const SizedBox(height: 32),
@@ -224,11 +232,9 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
stopFromChequeNo: stopFromChequeNo:
_stopFromChequeNoController.text, _stopFromChequeNoController.text,
instrType: widget.instrType, instrType: widget.instrType,
stopToChequeNo: stopToChequeNo: _stopToChequeNoController.text,
_stopToChequeNoController.text,
stopIssueDate: _stopIssueDateController.text, stopIssueDate: _stopIssueDateController.text,
stopExpiryDate: stopExpiryDate: _stopExpiryDateController.text,
_stopExpiryDateController.text,
stopAmount: _stopAmountController.text, stopAmount: _stopAmountController.text,
stopComment: _stopCommentController.text, stopComment: _stopCommentController.text,
chequeIssueDate: widget.date, chequeIssueDate: widget.date,
@@ -236,7 +242,7 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
); );
if (!mounted) return; if (!mounted) return;
final decodedResponse = jsonDecode(response); final decodedResponse = jsonDecode(response);
final status = decodedResponse['status']; final status = decodedResponse['status'];
final message = decodedResponse['message']; final message = decodedResponse['message'];
if (status == 'SUCCESS') { if (status == 'SUCCESS') {
_showResponseDialog('Success', message); _showResponseDialog('Success', message);
@@ -248,9 +254,11 @@ class _StopMultipleChequesScreenState extends State<StopMultipleChequesScreen> {
print(e.toString()); print(e.toString());
try { try {
final errorBodyString = e.toString().split('Exception: ')[1]; final errorBodyString =
e.toString().split('Exception: ')[1];
final errorBody = jsonDecode(errorBodyString); final errorBody = jsonDecode(errorBodyString);
if (errorBody.containsKey('error') && errorBody['error'] == 'INCORRECT_TPIN') { if (errorBody.containsKey('error') &&
errorBody['error'] == 'INCORRECT_TPIN') {
_showResponseDialog('Invalid TPIN', _showResponseDialog('Invalid TPIN',
'The TPIN you entered is incorrect. Please try again.'); 'The TPIN you entered is incorrect. Please try again.');
} else { } 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:flutter/material.dart';
import 'package:kmobile/api/services/cheque_service.dart'; import 'package:kmobile/api/services/cheque_service.dart';
import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart'; import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart';
import 'package:kmobile/l10n/app_localizations.dart';
class StopSingleChequeScreen extends StatefulWidget { class StopSingleChequeScreen extends StatefulWidget {
final User selectedAccount; final User selectedAccount;
@@ -63,7 +64,7 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
), ),
actions: <Widget>[ actions: <Widget>[
TextButton( TextButton(
child: const Text('Close'), child: Text(AppLocalizations.of(context).closeButton),
onPressed: () { onPressed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
@@ -78,7 +79,7 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('Stop Single Cheque'), title: Text(AppLocalizations.of(context).stopSingleChequeTitle),
), ),
body: Padding( body: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
@@ -96,20 +97,22 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
height: 40, height: 40,
), ),
title: Text(widget.selectedAccount.accountNo!), title: Text(widget.selectedAccount.accountNo!),
subtitle: const Text("Account Number"), subtitle:
Text(AppLocalizations.of(context).accountNumberLabel),
), ),
), ),
const SizedBox(height: 24), const SizedBox(height: 24),
TextFormField( TextFormField(
controller: _stopFromChequeNoController, controller: _stopFromChequeNoController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Cheque Number *', labelText: AppLocalizations.of(context).chequeNumberLabel,
border: OutlineInputBorder(), border: OutlineInputBorder(),
), ),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Please enter a cheque number'; return AppLocalizations.of(context)
.pleaseEnterChequeNumberError;
} }
final chequeNumber = int.tryParse(value); final chequeNumber = int.tryParse(value);
final fromCheque = int.tryParse(widget.fromCheque); final fromCheque = int.tryParse(widget.fromCheque);
@@ -117,10 +120,12 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
if (chequeNumber == null || if (chequeNumber == null ||
fromCheque == null || fromCheque == null ||
toCheque == null) { toCheque == null) {
return 'Invalid cheque number format'; return AppLocalizations.of(context)
.invalidChequeNumberFormatError;
} }
if (chequeNumber < fromCheque || chequeNumber > toCheque) { 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; return null;
}, },
@@ -129,53 +134,54 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
TextFormField( TextFormField(
initialValue: widget.instrType, initialValue: widget.instrType,
readOnly: true, readOnly: true,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Instrument Type *', labelText: AppLocalizations.of(context).instrumentTypeLabel,
border: OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
controller: _stopIssueDateController, controller: _stopIssueDateController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Stop Issue Date', labelText: AppLocalizations.of(context).stopIssueDateLabel,
border: OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
keyboardType: TextInputType.datetime, keyboardType: TextInputType.datetime,
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
controller: _stopExpiryDateController, controller: _stopExpiryDateController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Stop Expiry Date', labelText: AppLocalizations.of(context).stopExpiryDateLabel,
border: OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
keyboardType: TextInputType.datetime, keyboardType: TextInputType.datetime,
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
controller: _stopAmountController, controller: _stopAmountController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Stop Amount', labelText: AppLocalizations.of(context).stopAmountHint,
border: OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
controller: _stopCommentController, controller: _stopCommentController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Stop Comment', labelText: AppLocalizations.of(context).stopCommentHint,
border: OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
initialValue: _formatDate(widget.date), initialValue: _formatDate(widget.date),
readOnly: true, readOnly: true,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Chequebook Issue Date', labelText:
border: OutlineInputBorder(), AppLocalizations.of(context).chequebookIssueDateHint,
border: const OutlineInputBorder(),
), ),
), ),
const SizedBox(height: 32), const SizedBox(height: 32),
@@ -197,8 +203,7 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
stopToChequeNo: stopToChequeNo:
_stopFromChequeNoController.text, _stopFromChequeNoController.text,
stopIssueDate: _stopIssueDateController.text, stopIssueDate: _stopIssueDateController.text,
stopExpiryDate: stopExpiryDate: _stopExpiryDateController.text,
_stopExpiryDateController.text,
stopAmount: _stopAmountController.text, stopAmount: _stopAmountController.text,
stopComment: _stopCommentController.text, stopComment: _stopCommentController.text,
chequeIssueDate: widget.date, chequeIssueDate: widget.date,
@@ -206,7 +211,7 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
); );
if (!mounted) return; if (!mounted) return;
final decodedResponse = jsonDecode(response); final decodedResponse = jsonDecode(response);
final status = decodedResponse['status']; final status = decodedResponse['status'];
final message = decodedResponse['message']; final message = decodedResponse['message'];
if (status == 'SUCCESS') { if (status == 'SUCCESS') {
_showResponseDialog('Success', message); _showResponseDialog('Success', message);
@@ -218,9 +223,11 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
print(e.toString()); print(e.toString());
try { try {
final errorBodyString = e.toString().split('Exception: ')[1]; final errorBodyString =
e.toString().split('Exception: ')[1];
final errorBody = jsonDecode(errorBodyString); final errorBody = jsonDecode(errorBodyString);
if (errorBody.containsKey('error') && errorBody['error'] == 'INCORRECT_TPIN') { if (errorBody.containsKey('error') &&
errorBody['error'] == 'INCORRECT_TPIN') {
_showResponseDialog('Invalid TPIN', _showResponseDialog('Invalid TPIN',
'The TPIN you entered is incorrect. Please try again.'); 'The TPIN you entered is incorrect. Please try again.');
} else { } else {
@@ -238,7 +245,7 @@ class _StopSingleChequeScreenState extends State<StopSingleChequeScreen> {
); );
} }
}, },
child: const Text('Stop Cheque'), child: Text(AppLocalizations.of(context).stopChequeButton),
), ),
], ],
), ),

View File

@@ -652,9 +652,8 @@ class _DashboardScreenState extends State<DashboardScreen>
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => ChequeManagementScreen( builder: (context) => ChequeManagementScreen(
users: users, users: users,
selectedIndex: selectedAccountIndex selectedIndex: selectedAccountIndex),
),
), ),
); );
}, },

View File

@@ -129,7 +129,7 @@ class _EnquiryScreen extends State<EnquiryScreen> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
"Complaint Form", AppLocalizations.of(context).complaintFormTitle,
style: TextStyle( style: TextStyle(
fontSize: 15, fontSize: 15,
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,

View File

@@ -496,7 +496,7 @@ class _FundTransferAmountScreenState extends State<FundTransferAmountScreen> {
Text(AppLocalizations.of(context).fetchingDailyLimit), Text(AppLocalizations.of(context).fetchingDailyLimit),
if (!_isLoadingLimit && _limit != null) if (!_isLoadingLimit && _limit != null)
Text( Text(
'Remaining Daily Limit: ${_formatCurrency.format(_limit!.dailyLimit - _limit!.usedLimit)}', '${AppLocalizations.of(context).remainingDailyLimit} ${_formatCurrency.format(_limit!.dailyLimit - _limit!.usedLimit)}',
style: Theme.of(context).textTheme.bodySmall, style: Theme.of(context).textTheme.bodySmall,
), ),
const Spacer(), const Spacer(),

View File

@@ -198,7 +198,8 @@ class _FundTransferBeneficiaryScreenState
child: TextField( child: TextField(
controller: _searchController, controller: _searchController,
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search by name or account number", hintText:
AppLocalizations.of(context).searchByNameOrAccountHint,
prefixIcon: const Icon(Icons.search), prefixIcon: const Icon(Icons.search),
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),

View File

@@ -42,7 +42,7 @@ class FundTransferScreen extends StatelessWidget {
Expanded( Expanded(
child: FundTransferManagementTile( child: FundTransferManagementTile(
icon: Symbols.person, icon: Symbols.person,
label: "Self Pay", label: AppLocalizations.of(context).selfPay,
subtitle: subtitle:
AppLocalizations.of(context).ftselfpaysubtitle, AppLocalizations.of(context).ftselfpaysubtitle,
onTap: () { onTap: () {

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/fund_transfer/screens/fund_transfer_self_amount_screen.dart'; import 'package:kmobile/features/fund_transfer/screens/fund_transfer_self_amount_screen.dart';
import 'package:kmobile/l10n/app_localizations.dart';
import 'package:kmobile/widgets/bank_logos.dart'; import 'package:kmobile/widgets/bank_logos.dart';
class FundTransferSelfAccountsScreen extends StatelessWidget { class FundTransferSelfAccountsScreen extends StatelessWidget {
@@ -43,7 +44,7 @@ class FundTransferSelfAccountsScreen extends StatelessWidget {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text("Select Account"), title: Text(AppLocalizations.of(context).selectAccount),
), ),
body: Stack( body: Stack(
children: [ children: [

View File

@@ -7,6 +7,7 @@ import 'package:kmobile/data/models/user.dart';
import 'package:kmobile/di/injection.dart'; import 'package:kmobile/di/injection.dart';
import 'package:kmobile/features/fund_transfer/screens/payment_animation.dart'; import 'package:kmobile/features/fund_transfer/screens/payment_animation.dart';
import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart'; import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart';
import 'package:kmobile/l10n/app_localizations.dart';
import 'package:kmobile/widgets/bank_logos.dart'; import 'package:kmobile/widgets/bank_logos.dart';
class FundTransferSelfAmountScreen extends StatefulWidget { class FundTransferSelfAmountScreen extends StatefulWidget {
@@ -134,7 +135,7 @@ class _FundTransferSelfAmountScreenState
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text("Fund Transfer"), title: Text(AppLocalizations.of(context).fundTransferTitle),
), ),
body: SafeArea( body: SafeArea(
child: Stack( child: Stack(
@@ -148,7 +149,7 @@ class _FundTransferSelfAmountScreenState
children: [ children: [
// Debit Account (User) // Debit Account (User)
Text( Text(
"Debit From", AppLocalizations.of(context).debitFromLabel,
style: Theme.of(context).textTheme.titleSmall, style: Theme.of(context).textTheme.titleSmall,
), ),
Card( Card(
@@ -168,7 +169,7 @@ class _FundTransferSelfAmountScreenState
// Credit Account (Self) // Credit Account (Self)
Text( Text(
"Credited To", AppLocalizations.of(context).creditedTo,
style: Theme.of(context).textTheme.titleSmall, style: Theme.of(context).textTheme.titleSmall,
), ),
Card( Card(
@@ -186,9 +187,10 @@ class _FundTransferSelfAmountScreenState
// Remarks // Remarks
TextFormField( TextFormField(
controller: _remarksController, controller: _remarksController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: "Remarks (Optional)", labelText:
border: OutlineInputBorder(), AppLocalizations.of(context).remarksOptionalHint,
border: const OutlineInputBorder(),
), ),
), ),
const SizedBox(height: 24), const SizedBox(height: 24),
@@ -197,18 +199,18 @@ class _FundTransferSelfAmountScreenState
TextFormField( TextFormField(
controller: _amountController, controller: _amountController,
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: "Amount", labelText: AppLocalizations.of(context).amountLabel,
border: OutlineInputBorder(), border: const OutlineInputBorder(),
prefixIcon: Icon(Icons.currency_rupee), prefixIcon: const Icon(Icons.currency_rupee),
), ),
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return "Amount is required"; return AppLocalizations.of(context).amountRequired;
} }
if (double.tryParse(value) == null || if (double.tryParse(value) == null ||
double.parse(value) <= 0) { double.parse(value) <= 0) {
return "Please enter a valid amount"; return AppLocalizations.of(context).validAmountError;
} }
return null; return null;
}, },
@@ -216,10 +218,12 @@ class _FundTransferSelfAmountScreenState
const SizedBox(height: 8), const SizedBox(height: 8),
// Daily Limit Display // Daily Limit Display
if (_isLoadingLimit) const Text('Fetching daily limit...'), if (_isLoadingLimit)
Text(AppLocalizations.of(context)
.fetchingDailyLimitLoader),
if (!_isLoadingLimit && _limit != null) if (!_isLoadingLimit && _limit != null)
Text( Text(
'Remaining Daily Limit: ${_formatCurrency.format(_limit!.dailyLimit - _limit!.usedLimit)}', '${AppLocalizations.of(context).remainingDailyLimit} ${_formatCurrency.format(_limit!.dailyLimit - _limit!.usedLimit)}',
style: Theme.of(context).textTheme.bodySmall, style: Theme.of(context).textTheme.bodySmall,
), ),
const Spacer(), const Spacer(),
@@ -232,7 +236,7 @@ class _FundTransferSelfAmountScreenState
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16), padding: const EdgeInsets.symmetric(vertical: 16),
), ),
child: const Text("Proceed"), child: Text(AppLocalizations.of(context).proceedButton),
), ),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),

View File

@@ -83,8 +83,8 @@ class _DailyLimitScreenState extends State<DailyLimitScreen> {
if (value > 200000) { if (value > 200000) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: const Text( content:
"Limit To be Set must be less than 200000"), Text(localizations.limitToBeSetMustBeLessThan200000),
behavior: SnackBarBehavior.floating, behavior: SnackBarBehavior.floating,
backgroundColor: theme.colorScheme.error, backgroundColor: theme.colorScheme.error,
), ),
@@ -184,7 +184,7 @@ class _DailyLimitScreenState extends State<DailyLimitScreen> {
if (_currentLimit != null) ...[ if (_currentLimit != null) ...[
const SizedBox(height: 24), const SizedBox(height: 24),
Text( Text(
"Remaining Limit Today", // This should be localized localizations.remainingLimitToday, // This should be localized
style: theme.textTheme.titleMedium, style: theme.textTheme.titleMedium,
), ),
const SizedBox(height: 4), const SizedBox(height: 4),

View File

@@ -76,7 +76,8 @@ class _ATMLocatorScreenState extends State<ATMLocatorScreen> {
onChanged: onChanged:
_filterAtms, // Updated: Call _filterAtms on text change _filterAtms, // Updated: Call _filterAtms on text change
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Name/Address", // Hint text for the search bar hintText: AppLocalizations.of(context)
.nameAddress, // Hint text for the search bar
prefixIcon: const Icon(Icons.search), // Search icon prefixIcon: const Icon(Icons.search), // Search icon
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
@@ -90,9 +91,9 @@ class _ATMLocatorScreenState extends State<ATMLocatorScreen> {
child: _isLoading child: _isLoading
? _buildShimmerList() // Display shimmer while loading ? _buildShimmerList() // Display shimmer while loading
: _filteredAtms.isEmpty : _filteredAtms.isEmpty
? const Center( ? Center(
child: Text( child: Text(AppLocalizations.of(context)
"No matching ATMs found")) // Message if no ATMs found .noMatchingAtmsFound)) // Message if no ATMs found
: ListView.builder( : ListView.builder(
itemCount: _filteredAtms itemCount: _filteredAtms
.length, // Number of items in the filtered list .length, // Number of items in the filtered list

View File

@@ -69,7 +69,7 @@ class _BranchLocatorScreenState extends State<BranchLocatorScreen> {
controller: _searchController, controller: _searchController,
onChanged: _filterBranches, // Updated onChanged: _filterBranches, // Updated
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Branch Name", hintText: AppLocalizations.of(context).searchbranch,
prefixIcon: const Icon(Icons.search), prefixIcon: const Icon(Icons.search),
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
@@ -83,9 +83,9 @@ class _BranchLocatorScreenState extends State<BranchLocatorScreen> {
child: _isLoading child: _isLoading
? _buildShimmerList() // Changed to shimmer ? _buildShimmerList() // Changed to shimmer
: _filteredBranches.isEmpty : _filteredBranches.isEmpty
? const Center( ? Center(
child: Text( child: Text(AppLocalizations.of(context)
"No matching branches found")) // Updated tex .noMatchingBranchesFound)) // Updated tex
: ListView.builder( : ListView.builder(
itemCount: _filteredBranches.length, itemCount: _filteredBranches.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {

View File

@@ -416,5 +416,144 @@
"kycdetails": "KYC Details", "kycdetails": "KYC Details",
"viewall": "View All", "viewall": "View All",
"branchlocator": "Branch Locator", "branchlocator": "Branch Locator",
"atmlocator": "ATM Locator" "atmlocator": "ATM Locator",
"limitSetError": "Limit to be set must be less than {maxAmount}",
"genericError": "Error: {errorMessage}",
"limitUpdatedSuccess": "Limit Updated",
"remainingLimitToday": "Remaining Limit Today",
"branchNameHint": "Branch Name",
"noMatchingBranches": "No matching branches found",
"selfPay": "Self Pay",
"savingsAccountType": "Savings",
"amountExceedsDailyLimit": "Amount exceeds remaining daily limit of ",
"incorrectTpinError": "Please Enter the correct TPIN",
"insufficientFundsError": "Your account does not have sufficient balance",
"somethingWentWrongError": "Something Went Wrong",
"currencyINR": "INR",
"remainingDailyLimit": "Remaining Daily Limit:",
"searchByNameOrAccount": "Search by name or account number",
"beneficiaryCooldownMessage": "Beneficiary will be enabled after the cooldown period.",
"notApplicable": "N/A",
"savingsAccountLabel": "Savings Account",
"loanAccountLabel": "Loan Account",
"termDepositLabel": "Term Deposit",
"recurringDepositLabel": "Recurring Deposit",
"currentAccountLabel": "Current Account",
"unknownAccountLabel": "Unknown Account",
"selectAccountTitle": "Select Account",
"noOtherAccounts": "No other accounts found",
"kccbBankName": "Kangra Central Co-operative Bank",
"fundTransferTitle": "Fund Transfer",
"debitFromLabel": "Debit From",
"creditToLabel": "Credited To",
"remarksOptionalHint": "Remarks (Optional)",
"amountLabel": "Amount",
"amountRequiredError": "Amount is required",
"validAmountError": "Please enter a valid amount",
"fetchingDailyLimitLoader": "Fetching daily limit...",
"proceedButton": "Proceed",
"enterKey": "Enter",
"backKey": "back",
"doneKey": "done",
"transactionDate": "On {date}",
"paymentResultPng": "/payment_result.png",
"rubikFont": "Rubik",
"transactionDateLabel": "Date: {date}",
"utrLabel": "UTR: {utr}",
"searchByNameOrAccountHint": "Search by name or account number",
"savingsAccountDropdown": "Savings",
"beneficiaryExistsError": "Beneficiary already exists",
"somethingWentWrongShort": "Something went Wrong",
"currentAccountDropdown": "Current",
"failedToDeleteBeneficiaryError": "Failed to delete beneficiary: {error}",
"notAvailable": "N/A",
"bankNameLabel": "Bank Name",
"accountNumberLabel": "Account Number",
"accountTypeLabel": "Account Type",
"ifscCodeLabel": "IFSC Code",
"branchNameLabel": "Branch Name",
"enquiryEmailSubject": "Enquiry",
"couldNotOpenEmailApp": "Could not open email app for {email}",
"couldNotOpenDialer": "Could not open dialer for {phone}",
"couldNotLaunchUrl": "Could not launch {url}",
"complaintFormUrl": "https://kccbhp.bank.in/complaint-form/",
"complaintFormTitle": "Complaint Form",
"chairmanEmail": "chairman@kccb.in",
"chairmanPhone": "01892-222677",
"mdEmail": "md@kccb.in",
"mdPhone": "01892-224969",
"gmwEmail": "gmw@kccb.in",
"gmwPhone": "01892-223280",
"gmnEmail": "gmn@kccb.in",
"gmnPhone": "01892-224607",
"atmNameAddressHint": "Name/Address",
"noMatchingAtms": "No matching ATMs found",
"faq1Question": "How do I log in to the mobile banking app?",
"faq1Answer": "You can log in using your customer number and password. Biometric login (fingerprint) and MPIN is also available for supported evices.",
"faq2Question": "Is my banking information secure on this app?",
"faq2Answer": "Yes. We use industry-standard encryption and multi-factor authentication to ensure your data is safe.",
"faq3Question": "How can I check my account balance?",
"faq3Answer": "Once logged in, your account balance will be displayed on the home screen. You can also view detailed balances under the “Accounts” section.",
"faq4Question": "Can I transfer money to other bank accounts?",
"faq4Answer": "Yes. You can use NEFT, RTGS or IMPS to transfer funds to any bank account in India.",
"faq5Question": "How do I view my transaction history?",
"faq5Answer": "Click on the “Account Statement” icon under the Home Screen to view recent and past transactions.",
"chequeEnquiryTitle": "Cheque Enquiry",
"chequeEnquirySubtitle": "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",
"stopChequeSubtitle": "Initiate stop for one or more cheques from your issued checkbook. This essential service helps prevent unauthorized transactions and protects against fraud.",
"chequeEnquiryFailedError": "Failed to fetch cheque status: {error}",
"accountNumberTitle": "Account Number",
"noAccountsFound": "No accounts found",
"searchByChequeDetailsHint": "Search by Cheque Details",
"noChequeStatusFound": "No cheque status found.",
"chequebookIssuedLabel": "Chequebook Issued (CI)",
"branchCodeLabel": "Branch Code:",
"fromChequeLabel": "From Cheque:",
"toChequeLabel": "To Cheque:",
"dateLabel": "Date:",
"chequesCountLabel": "Cheques Count:",
"presentedChequeLabel": "Presented Cheque (PR)",
"chequeNumberLabel": "Cheque Number:",
"transactionCodeLabel": "Transaction Code:",
"amountLabelWithColon": "Amount:",
"statusLabel": "Status:",
"stopChequeLabel": "Stop Cheque (ST)",
"stopIssueDateLabel": "Stop Issue Date:",
"stopExpiryDateLabel": "Stop Expiry Date:",
"emptyString": "",
"cashCreditAccountLabel": "Cash Credit Account",
"stopChequeTitle": "Stop Cheque",
"noChequebookToStop": "No cheque book found to stop cheques from.",
"stopSingleChequeButton": "Stop Single Cheque",
"pleaseSelectAccountFirst": "Please select an account first.",
"stopMultipleChequesButton": "Stop Multiple Cheques",
"noChequeIssuedStatus": "No Cheque Issued status found.",
"chequebookDetailsTitle": "Chequebook Details",
"customerNameLabel": "Customer Name:",
"cifNumberLabel": "CIF Number:",
"startingChequeNumberLabel": "Starting Cheque Number:",
"endingChequeNumberLabel": "Ending Cheque Number:",
"issueDateLabel": "Issue Date:",
"numberOfChequesLabel": "Number of Cheques:",
"instrumentTypeLabel": "Instrument Type:",
"closeButton": "Close",
"stopSingleChequeTitle": "Stop Single Cheque",
"chequeNumberHint": "Cheque Number *",
"pleaseEnterChequeNumberError": "Please enter a cheque number",
"invalidChequeNumberFormatError": "Invalid cheque number format",
"chequeNumberRangeError": "Cheque number must be between {from} and {to}",
"instrumentTypeHint": "Instrument Type *",
"stopIssueDateHint": "Stop Issue Date",
"stopExpiryDateHint": "Stop Expiry Date",
"stopAmountHint": "Stop Amount",
"stopCommentHint": "Stop Comment",
"chequebookIssueDateHint": "Chequebook Issue Date",
"successStatus": "Success",
"errorStatus": "Error",
"incorrectTpinErrorMessage": "The TPIN you entered is incorrect. Please try again.",
"internalServerError": "Internal Server Error",
"stopChequeButton": "Stop Cheque",
"stopMultipleChequesTitle": "Stop Multiple Cheques",
"fromChequeNumberHint": "From Cheque Number *",
"toChequeNumberHint": "To Cheque Number *"
} }

View File

@@ -417,5 +417,144 @@
"kycdetails": "केवाईसी विवरण", "kycdetails": "केवाईसी विवरण",
"viewall": "सभी देखें", "viewall": "सभी देखें",
"branchlocator": "शाखा लोकेटर", "branchlocator": "शाखा लोकेटर",
"atmlocator": "एटीएम लोकेटर" "atmlocator": "एटीएम लोकेटर",
"limitSetError": "निर्धारित की जाने वाली सीमा {maxAmount} से कम होनी चाहिए।",
"genericError": "त्रुटि: {errorMessage}",
"limitUpdatedSuccess": "सीमा अपडेट हो गई",
"remainingLimitToday": "आज की शेष सीमा",
"branchNameHint": "शाखा का नाम",
"noMatchingBranches": "कोई मेल खाने वाली शाखा नहीं मिली",
"selfPay": "स्वयं भुगतान",
"savingsAccountType": "बचत खाता",
"amountExceedsDailyLimit": "राशि की शेष दैनिक सीमा से अधिक है",
"incorrectTpinError": "कृपया सही टीपिन दर्ज करें",
"insufficientFundsError": "आपके खाते में पर्याप्त शेष राशि नहीं है",
"somethingWentWrongError": "कुछ गलत हो गया",
"currencyINR": "INR",
"remainingDailyLimit": "शेष दैनिक सीमा:",
"searchByNameOrAccount": "नाम या खाता संख्या से खोजें",
"beneficiaryCooldownMessage": "कूलडाउन अवधि के बाद लाभार्थी सक्षम हो जाएगा।",
"notApplicable": "लागू नहीं",
"savingsAccountLabel": "बचत खाता",
"loanAccountLabel": "ऋण खाता",
"termDepositLabel": "सावधि जमा",
"recurringDepositLabel": "आवर्ती जमा",
"currentAccountLabel": "चालू खाता",
"unknownAccountLabel": "अज्ञात खाता",
"selectAccountTitle": "खाता चुनें",
"noOtherAccounts": "कोई अन्य खाता नहीं मिला",
"kccbBankName": "कांगड़ा केंद्रीय सहकारी बैंक",
"fundTransferTitle": "धन हस्तांतरण",
"debitFromLabel": "से डेबिट करें",
"creditToLabel": "को क्रेडिट करें",
"remarksOptionalHint": "टिप्पणी (वैकल्पिक)",
"amountLabel": "राशि",
"amountRequiredError": "राशि आवश्यक है",
"validAmountError": "कृपया एक वैध राशि दर्ज करें",
"fetchingDailyLimitLoader": "दैनिक सीमा लाई जा रही है...",
"proceedButton": "आगे बढ़ें",
"enterKey": "दर्ज करें",
"backKey": "वापस",
"doneKey": "पूर्ण",
"transactionDate": "{date} को",
"paymentResultPng": "/payment_result.png",
"rubikFont": "Rubik",
"transactionDateLabel": "दिनांक: {date}",
"utrLabel": "UTR: {utr}",
"searchByNameOrAccountHint": "नाम या खाता संख्या से खोजें",
"savingsAccountDropdown": "बचत",
"beneficiaryExistsError": "लाभार्थी पहले से मौजूद है",
"somethingWentWrongShort": "कुछ गलत हो गया",
"currentAccountDropdown": "चालू",
"failedToDeleteBeneficiaryError": "लाभार्थी को हटाने में विफल: {error}",
"notAvailable": "उपलब्ध नहीं है",
"bankNameLabel": "बैंक का नाम",
"accountNumberLabel": "खाता संख्या",
"accountTypeLabel": "खाते का प्रकार",
"ifscCodeLabel": "IFSC कोड",
"branchNameLabel": "शाखा का नाम",
"enquiryEmailSubject": "पूछताछ",
"couldNotOpenEmailApp": "{email} के लिए ईमेल ऐप नहीं खोला जा सका",
"couldNotOpenDialer": "{phone} के लिए डायलर नहीं खोला जा सका",
"couldNotLaunchUrl": "{url} लॉन्च नहीं किया जा सका",
"complaintFormUrl": "https://kccbhp.bank.in/complaint-form/",
"complaintFormTitle": "शिकायत प्रपत्र",
"chairmanEmail": "chairman@kccb.in",
"chairmanPhone": "01892-222677",
"mdEmail": "md@kccb.in",
"mdPhone": "01892-224969",
"gmwEmail": "gmw@kccb.in",
"gmwPhone": "01892-223280",
"gmnEmail": "gmn@kccb.in",
"gmnPhone": "01892-224607",
"atmNameAddressHint": "नाम/पता",
"noMatchingAtms": "कोई मेल खाने वाला एटीएम नहीं मिला",
"faq1Question": "मैं मोबाइल बैंकिंग ऐप में कैसे लॉग इन करूं?",
"faq1Answer": "आप अपने ग्राहक नंबर और पासवर्ड का उपयोग करके लॉग इन कर सकते हैं। समर्थित उपकरणों के लिए बायोमेट्रिक लॉगिन (फिंगरप्रिंट) और एमपिन भी उ।",
"faq2Question": "क्या इस ऐप पर मेरी बैंकिंग जानकारी सुरक्षित है?",
"faq2Answer": "हां। हम आपके डेटा को सुरक्षित रखने के लिए उद्योग-मानक एन्क्रिप्शन और बहु-कारक प्रमाणीकरण का उपयोग करते हैं।",
"faq3Question": "मैं अपने खाते की शेष राशि कैसे देख सकता हूं?",
"faq3Answer": "लॉग इन करने के बाद, आपके खाते की शेष राशि होम स्क्रीन पर प्रदर्शित होगी। आप “खाते” अनुभाग के तहत विस्तृत शेष राशि भी देख सकते हैं।",
"faq4Question": "क्या मैं अन्य बैंक खातों में पैसे ट्रांसफर कर सकता हूं?",
"faq4Answer": "हां। आप भारत में किसी भी बैंक खाते में धनराशि स्थानांतरित करने के लिए एनईएफटी, आरटीजीएस या आईएमपीएस का उपयोग कर सकते हैं।",
"faq5Question": "मैं अपना लेनदेन इतिहास कैसे देखूं?",
"faq5Answer": "हाल के और पिछले लेनदेन देखने के लिए होम स्क्रीन के नीचे “खाता विवरण” आइकन पर क्लिक करें।",
"chequeEnquiryTitle": "चेक पूछताछ",
"chequeEnquirySubtitle": "आप अपनी जारी की गई चेक बुक, प्रस्तुत किए गए चेकों और रोके गए चेकों के विवरण देख सकते हैं, जिसमें प्रासंगिक तिथियां, चेक नं्य आवश्यक जानकारी शामिल है",
"stopChequeSubtitle": "अपनी जारी की गई चेकबुक से एक या अधिक चेकों के लिए स्टॉप आरंभ करें। यह आवश्यक सेवा अनधिकृत लेनदेन को रोकने और धोखाधड़ी से बचानद करती है।",
"chequeEnquiryFailedError": "चेक स्थिति लाने में विफल: {error}",
"accountNumberTitle": "खाता संख्या",
"noAccountsFound": "कोई खाता नहीं मिला",
"searchByChequeDetailsHint": "चेक विवरण द्वारा खोजें",
"noChequeStatusFound": "कोई चेक स्थिति नहीं मिली।",
"chequebookIssuedLabel": "चेकबुक जारी (CI)",
"branchCodeLabel": "शाखा कोड:",
"fromChequeLabel": "चेक से:",
"toChequeLabel": "चेक तक:",
"dateLabel": "दिनांक:",
"chequesCountLabel": "चेकों की संख्या:",
"presentedChequeLabel": "प्रस्तुत चेक (PR)",
"chequeNumberLabel": "चेक नंबर:",
"transactionCodeLabel": "लेनदेन कोड:",
"amountLabelWithColon": "राशि:",
"statusLabel": "स्थिति:",
"stopChequeLabel": "चेक रोकें (ST)",
"stopIssueDateLabel": "रोक जारी करने की तारीख:",
"stopExpiryDateLabel": "रोक समाप्ति तिथि:",
"emptyString": "",
"cashCreditAccountLabel": "नकद क्रेडिट खाता",
"stopChequeTitle": "चेक रोकें",
"noChequebookToStop": "से चेक रोकने के लिए कोई चेक बुक नहीं मिली।",
"stopSingleChequeButton": "एकल चेक रोकें",
"pleaseSelectAccountFirst": "कृपया पहले एक खाता चुनें।",
"stopMultipleChequesButton": "एकाधिक चेक रोकें",
"noChequeIssuedStatus": "कोई चेक जारी स्थिति नहीं मिली।",
"chequebookDetailsTitle": "चेकबुक विवरण",
"customerNameLabel": "ग्राहक का नाम:",
"cifNumberLabel": "CIF नंबर:",
"startingChequeNumberLabel": "प्रारंभिक चेक नंबर:",
"endingChequeNumberLabel": "अंतिम चेक नंबर:",
"issueDateLabel": "जारी करने की तारीख:",
"numberOfChequesLabel": "चेकों की संख्या:",
"instrumentTypeLabel": "उपकरण का प्रकार:",
"closeButton": "बंद करें",
"stopSingleChequeTitle": "एकल चेक रोकें",
"chequeNumberHint": "चेक नंबर *",
"pleaseEnterChequeNumberError": "कृपया एक चेक नंबर दर्ज करें",
"invalidChequeNumberFormatError": "अमान्य चेक नंबर प्रारूप",
"chequeNumberRangeError": "चेक नंबर {from} और {to} के बीच होना चाहिए",
"instrumentTypeHint": "उपकरण का प्रकार *",
"stopIssueDateHint": "रोक जारी करने की तारीख",
"stopExpiryDateHint": "रोक समाप्ति तिथि",
"stopAmountHint": "राशि रोकें",
"stopCommentHint": "टिप्पणी रोकें",
"chequebookIssueDateHint": "चेकबुक जारी करने की तारीख",
"successStatus": "सफलता",
"errorStatus": "त्रुटि",
"incorrectTpinErrorMessage": "आपके द्वारा दर्ज किया गया टीपिन गलत है। कृपया पुन: प्रयास करें।",
"internalServerError": "आंतरिक सर्वर त्रुटि",
"stopChequeButton": "चेक रोकें",
"stopMultipleChequesTitle": "एकाधिक चेक रोकें",
"fromChequeNumberHint": "चेक नंबर से *",
"toChequeNumberHint": "चेक नंबर तक *"
} }