changed imports of AppLocalization

Also added beneficiary validation while quick pay within bank
This commit is contained in:
2025-07-24 22:21:19 +05:30
parent 23d742ace9
commit 787fcdc2e2
42 changed files with 3965 additions and 1025 deletions

View File

@@ -1,4 +1,4 @@
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../../../l10n/app_localizations.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
@@ -109,8 +109,10 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
Text(
widget.debitAccount,
style: const TextStyle(
fontSize: 18, fontWeight: FontWeight.w500),
)
fontSize: 18,
fontWeight: FontWeight.w500,
),
),
],
),
const SizedBox(height: 20),
@@ -247,29 +249,30 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
Row(
children: [
Expanded(
child: TextFormField(
decoration: InputDecoration(
labelText: AppLocalizations.of(context).ifscCode,
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
child: TextFormField(
decoration: InputDecoration(
labelText: AppLocalizations.of(context).ifscCode,
border: OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
controller: ifscController,
textInputAction: TextInputAction.next,
validator: (value) {
if (value == null || value.isEmpty) {
return AppLocalizations.of(context).ifscRequired;
}
return null;
},
),
controller: ifscController,
textInputAction: TextInputAction.next,
validator: (value) {
if (value == null || value.isEmpty) {
return AppLocalizations.of(context).ifscRequired;
}
return null;
},
)),
),
const SizedBox(width: 10),
Expanded(
child: DropdownButtonFormField<String>(
@@ -287,15 +290,16 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
items: [
AppLocalizations.of(context).savings,
AppLocalizations.of(context).current
]
.map((e) => DropdownMenuItem(
value: e,
child: Text(e),
))
.toList(),
items:
[
AppLocalizations.of(context).savings,
AppLocalizations.of(context).current,
]
.map(
(e) =>
DropdownMenuItem(value: e, child: Text(e)),
)
.toList(),
onChanged: (value) => setState(() {
accountType = value!;
}),
@@ -366,50 +370,52 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
const SizedBox(height: 30),
Row(
children: [
Text(AppLocalizations.of(context).transactionMode,
style: TextStyle(fontWeight: FontWeight.w500)),
Text(
AppLocalizations.of(context).transactionMode,
style: TextStyle(fontWeight: FontWeight.w500),
),
const SizedBox(width: 12),
Expanded(child: buildTransactionModeSelector()),
],
),
const SizedBox(height: 45),
Align(
alignment: Alignment.center,
child: SwipeButton.expand(
thumb: const Icon(
Icons.arrow_forward,
color: Colors.white,
),
activeThumbColor: Colors.blue[900],
activeTrackColor: Colors.blue.shade100,
borderRadius: BorderRadius.circular(30),
height: 56,
child: Text(
AppLocalizations.of(context).swipeToPay,
style:
TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
onSwipe: () {
if (_formKey.currentState!.validate()) {
// Perform payment logic
final selectedMode =
transactionModes(context)[selectedTransactionIndex];
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'${AppLocalizations.of(context).payingVia} $selectedMode...')),
);
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) =>
// const TransactionPinScreen(
// transactionData: {},
// transactionCode: 'PAYMENT',
// )));
}
},
)),
alignment: Alignment.center,
child: SwipeButton.expand(
thumb: const Icon(Icons.arrow_forward, color: Colors.white),
activeThumbColor: Colors.blue[900],
activeTrackColor: Colors.blue.shade100,
borderRadius: BorderRadius.circular(30),
height: 56,
child: Text(
AppLocalizations.of(context).swipeToPay,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
onSwipe: () {
if (_formKey.currentState!.validate()) {
// Perform payment logic
final selectedMode = transactionModes(
context,
)[selectedTransactionIndex];
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'${AppLocalizations.of(context).payingVia} $selectedMode...',
),
),
);
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) =>
// const TransactionPinScreen(
// transactionData: {},
// transactionCode: 'PAYMENT',
// )));
}
},
),
),
],
),
),
@@ -442,9 +448,7 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
alignment: Alignment.center,
child: Text(
transactionModes(context)[index],
style: const TextStyle(
color: Colors.black,
),
style: const TextStyle(color: Colors.black),
),
),
),

View File

@@ -3,7 +3,7 @@ import 'package:flutter_svg/svg.dart';
import 'package:kmobile/features/quick_pay/screens/quick_pay_outside_bank_screen.dart';
import 'package:kmobile/features/quick_pay/screens/quick_pay_within_bank_screen.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../../../l10n/app_localizations.dart';
class QuickPayScreen extends StatefulWidget {
final String debitAccount;
@@ -25,8 +25,9 @@ class _QuickPayScreen extends State<QuickPayScreen> {
},
),
title: Text(
AppLocalizations.of(context).quickPay,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
AppLocalizations.of(context).quickPay.replaceAll('\n', ' '),
style:
const TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
),
centerTitle: false,
actions: [
@@ -52,30 +53,32 @@ class _QuickPayScreen extends State<QuickPayScreen> {
label: AppLocalizations.of(context).ownBank,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => QuickPayWithinBankScreen(
debitAccount: widget.debitAccount)));
context,
MaterialPageRoute(
builder: (context) => QuickPayWithinBankScreen(
debitAccount: widget.debitAccount,
),
),
);
},
),
const Divider(
height: 1,
),
const Divider(height: 1),
QuickPayManagementTile(
//disable: true,
disable: true,
icon: Symbols.output_circle,
label: AppLocalizations.of(context).outsideBank,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => QuickPayOutsideBankScreen(
debitAccount: widget.debitAccount)));
context,
MaterialPageRoute(
builder: (context) => QuickPayOutsideBankScreen(
debitAccount: widget.debitAccount,
),
),
);
},
),
const Divider(
height: 1,
),
const Divider(height: 1),
],
),
);

View File

@@ -1,9 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:flutter_swipe_button/flutter_swipe_button.dart';
import 'package:kmobile/api/services/beneficiary_service.dart';
import 'package:kmobile/data/models/transfer.dart';
import 'package:kmobile/di/injection.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../../../l10n/app_localizations.dart';
import '../../fund_transfer/screens/transaction_pin_screen.dart';
class QuickPayWithinBankScreen extends StatefulWidget {
@@ -23,6 +25,64 @@ class _QuickPayWithinBankScreen extends State<QuickPayWithinBankScreen> {
final TextEditingController amountController = TextEditingController();
String? _selectedAccountType;
String? _beneficiaryName;
bool _isValidating = false;
bool _isBeneficiaryValidated = false;
String? _validationError;
@override
void initState() {
super.initState();
accountNumberController.addListener(_resetBeneficiaryValidation);
confirmAccountNumberController.addListener(_resetBeneficiaryValidation);
}
void _resetBeneficiaryValidation() {
if (_isBeneficiaryValidated ||
_beneficiaryName != null ||
_validationError != null) {
setState(() {
_isBeneficiaryValidated = false;
_beneficiaryName = null;
_validationError = null;
});
}
}
@override
void dispose() {
accountNumberController.removeListener(_resetBeneficiaryValidation);
confirmAccountNumberController.removeListener(_resetBeneficiaryValidation);
accountNumberController.dispose();
confirmAccountNumberController.dispose();
amountController.dispose();
super.dispose();
}
Future<void> _validateBeneficiary() async {
var beneficiaryService = getIt<BeneficiaryService>();
setState(() {
_isValidating = true;
_validationError = null;
});
try {
final name = await beneficiaryService
.validateBeneficiaryWithinBank(accountNumberController.text);
setState(() {
_beneficiaryName = name;
_isBeneficiaryValidated = true;
_isValidating = false;
});
} catch (e) {
setState(() {
_validationError = "Account Number not from KCCB";
_isValidating = false;
_isBeneficiaryValidated = false;
_beneficiaryName = null;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
@@ -35,7 +95,8 @@ class _QuickPayWithinBankScreen extends State<QuickPayWithinBankScreen> {
),
title: Text(
AppLocalizations.of(context).quickPayOwnBank,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
style:
const TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
),
centerTitle: false,
actions: [
@@ -64,7 +125,7 @@ class _QuickPayWithinBankScreen extends State<QuickPayWithinBankScreen> {
TextFormField(
decoration: InputDecoration(
labelText: AppLocalizations.of(context).debitAccountNumber,
border: OutlineInputBorder(),
border: const OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
@@ -79,14 +140,14 @@ class _QuickPayWithinBankScreen extends State<QuickPayWithinBankScreen> {
TextFormField(
decoration: InputDecoration(
labelText: AppLocalizations.of(context).accountNumber,
border: OutlineInputBorder(),
border: const OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
@@ -118,14 +179,14 @@ class _QuickPayWithinBankScreen extends State<QuickPayWithinBankScreen> {
decoration: InputDecoration(
labelText: AppLocalizations.of(context).confirmAccountNumber,
// prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
border: const OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
@@ -141,19 +202,73 @@ class _QuickPayWithinBankScreen extends State<QuickPayWithinBankScreen> {
return null;
},
),
if (!_isBeneficiaryValidated)
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _isValidating
? null
: () {
if (accountNumberController.text.length == 11 &&
confirmAccountNumberController.text ==
accountNumberController.text) {
_validateBeneficiary();
} else {
setState(() {
_validationError =
'Please enter a valid and matching account number.';
});
}
},
child: _isValidating
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Text('Validate Beneficiary'),
),
),
),
if (_beneficiaryName != null && _isBeneficiaryValidated)
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: Row(
children: [
const Icon(Icons.check_circle, color: Colors.green),
const SizedBox(width: 8),
Text(
'Beneficiary: $_beneficiaryName',
style: const TextStyle(
color: Colors.green, fontWeight: FontWeight.bold),
),
],
),
),
if (_validationError != null)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
_validationError!,
style: const TextStyle(color: Colors.red),
),
),
const SizedBox(height: 24),
DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText:
AppLocalizations.of(context).beneficiaryAccountType,
border: OutlineInputBorder(),
labelText: AppLocalizations.of(
context,
).beneficiaryAccountType,
border: const OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
@@ -193,14 +308,14 @@ class _QuickPayWithinBankScreen extends State<QuickPayWithinBankScreen> {
TextFormField(
decoration: InputDecoration(
labelText: AppLocalizations.of(context).amount,
border: OutlineInputBorder(),
border: const OutlineInputBorder(),
isDense: true,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
focusedBorder: OutlineInputBorder(
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black, width: 2),
),
),
@@ -222,33 +337,40 @@ class _QuickPayWithinBankScreen extends State<QuickPayWithinBankScreen> {
Align(
alignment: Alignment.center,
child: SwipeButton.expand(
thumb: const Icon(
Icons.arrow_forward,
color: Colors.white,
),
thumb: const Icon(Icons.arrow_forward, color: Colors.white),
activeThumbColor: Theme.of(context).primaryColor,
activeTrackColor:
Theme.of(context).colorScheme.secondary.withAlpha(100),
activeTrackColor: Theme.of(
context,
).colorScheme.secondary.withAlpha(100),
borderRadius: BorderRadius.circular(30),
height: 56,
child: Text(
AppLocalizations.of(context).swipeToPay,
style: TextStyle(fontSize: 16),
style: const TextStyle(fontSize: 16),
),
onSwipe: () {
if (_formKey.currentState!.validate()) {
if (!_isBeneficiaryValidated) {
setState(() {
_validationError =
'Please validate beneficiary before proceeding.';
});
return;
}
// Perform payment logic
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TransactionPinScreen(
transactionData: Transfer(
fromAccount: widget.debitAccount,
toAccount: accountNumberController.text,
toAccountType: _selectedAccountType!,
amount: amountController.text,
),
)));
context,
MaterialPageRoute(
builder: (context) => TransactionPinScreen(
transactionData: Transfer(
fromAccount: widget.debitAccount,
toAccount: accountNumberController.text,
toAccountType: _selectedAccountType!,
amount: amountController.text,
),
),
),
);
}
},
),