feat: Implement major features and fix theming bug
This commit introduces several new features and a critical bug fix. - Implemented a full "Quick Pay" flow for both within and outside the bank, including IFSC validation, beneficiary verification, and a TPIN-based payment process. - Added a date range filter to the Account Statement screen and streamlined the UI by removing the amount filters. - Fixed a major bug that prevented dynamic theme changes from being applied. The app now correctly switches between color themes. - Refactored and improved beneficiary management, transaction models, and the fund transfer flow to support NEFT/RTGS.
This commit is contained in:
@@ -1,9 +1,19 @@
|
||||
import 'dart:async';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:kmobile/api/services/neft_service.dart';
|
||||
import 'package:kmobile/api/services/rtgs_service.dart';
|
||||
import 'package:kmobile/data/models/neft_transaction.dart';
|
||||
import 'package:kmobile/data/models/payment_response.dart';
|
||||
import 'package:kmobile/data/models/rtgs_transaction.dart';
|
||||
import 'package:kmobile/features/fund_transfer/screens/payment_animation.dart';
|
||||
import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:flutter_swipe_button/flutter_swipe_button.dart';
|
||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||
import '../../../../di/injection.dart';
|
||||
import '../../../../api/services/beneficiary_service.dart';
|
||||
|
||||
class QuickPayOutsideBankScreen extends StatefulWidget {
|
||||
final String debitAccount;
|
||||
@@ -26,9 +36,12 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
final ifscController = TextEditingController();
|
||||
final phoneController = TextEditingController();
|
||||
final amountController = TextEditingController();
|
||||
final service = getIt<BeneficiaryService>();
|
||||
|
||||
//String accountType = 'Savings';
|
||||
late String accountType;
|
||||
bool _isValidating = false;
|
||||
bool _isBeneficiaryValidated = false;
|
||||
String? _validationError;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -40,12 +53,71 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
});
|
||||
}
|
||||
|
||||
//final List<String> transactionModes = ['NEFT', 'RTGS', 'IMPS'];
|
||||
void _validateIFSC() async {
|
||||
final ifsc = ifscController.text.trim().toUpperCase();
|
||||
if (ifsc.isEmpty) return;
|
||||
|
||||
final result = await service.validateIFSC(ifsc);
|
||||
|
||||
if (mounted) {
|
||||
if (result.bankName == '') {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(AppLocalizations.of(context).invalidIfsc)),
|
||||
);
|
||||
bankNameController.clear();
|
||||
branchNameController.clear();
|
||||
} else {
|
||||
bankNameController.text = result.bankName;
|
||||
branchNameController.text = result.branchName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _validateBeneficiary() async {
|
||||
FocusScope.of(context).unfocus();
|
||||
setState(() {
|
||||
_isValidating = true;
|
||||
_validationError = null;
|
||||
_isBeneficiaryValidated = false;
|
||||
nameController.text = ''; // clear previous name
|
||||
});
|
||||
|
||||
final String accountNo = accountNumberController.text.trim();
|
||||
final String ifsc = ifscController.text.trim();
|
||||
// TODO: Replace with actual remitter name
|
||||
final String remitter = "Unknown";
|
||||
|
||||
final service = getIt<BeneficiaryService>();
|
||||
try {
|
||||
final String beneficiaryName = await service.validateBeneficiary(
|
||||
accountNo: accountNo,
|
||||
ifscCode: ifsc,
|
||||
remitterName: remitter,
|
||||
);
|
||||
|
||||
setState(() {
|
||||
nameController.text = beneficiaryName;
|
||||
_isBeneficiaryValidated = true;
|
||||
_validationError = null;
|
||||
});
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
_validationError = e.toString();
|
||||
_isBeneficiaryValidated = false;
|
||||
});
|
||||
} finally {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isValidating = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> transactionModes(BuildContext context) {
|
||||
return [
|
||||
AppLocalizations.of(context).neft,
|
||||
AppLocalizations.of(context).rtgs,
|
||||
AppLocalizations.of(context).imps,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -65,6 +137,131 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onProceedToPay() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
if (!_isBeneficiaryValidated) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Please validate beneficiary details first.')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final amount = double.tryParse(amountController.text) ?? 0;
|
||||
final selectedMode = transactionModes(context)[selectedTransactionIndex];
|
||||
final isRtgs = selectedMode == AppLocalizations.of(context).rtgs;
|
||||
|
||||
if (isRtgs && amount < 200000) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: const Text('Invalid Amount for RTGS'),
|
||||
content: const Text(
|
||||
'RTGS transactions require a minimum amount of 200,000. Please enter a higher amount or select NEFT as the transaction mode.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(),
|
||||
child: const Text('OK'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => TransactionPinScreen(
|
||||
onPinCompleted: (pinScreenContext, tpin) async {
|
||||
if (!isRtgs) {
|
||||
// NEFT
|
||||
final neftTx = NeftTransaction(
|
||||
fromAccount: widget.debitAccount,
|
||||
toAccount: accountNumberController.text,
|
||||
amount: amountController.text,
|
||||
ifscCode: ifscController.text,
|
||||
remitterName: "Unknown", // TODO: Get actual remitter name
|
||||
beneficiaryName: nameController.text,
|
||||
tpin: tpin,
|
||||
);
|
||||
final neftService = getIt<NeftService>();
|
||||
final completer = Completer<PaymentResponse>();
|
||||
|
||||
Navigator.of(pinScreenContext).pushReplacement(
|
||||
MaterialPageRoute(
|
||||
builder: (_) =>
|
||||
PaymentAnimationScreen(paymentResponse: completer.future),
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
final neftResponse =
|
||||
await neftService.processNeftTransaction(neftTx);
|
||||
final paymentResponse = PaymentResponse(
|
||||
isSuccess: neftResponse.message.toUpperCase() == 'SUCCESS',
|
||||
date: DateTime.now(),
|
||||
creditedAccount: neftTx.toAccount,
|
||||
amount: neftTx.amount,
|
||||
currency: 'INR',
|
||||
utr: neftResponse.utr,
|
||||
);
|
||||
completer.complete(paymentResponse);
|
||||
} catch (e) {
|
||||
final paymentResponse = PaymentResponse(
|
||||
isSuccess: false,
|
||||
errorMessage: e.toString(),
|
||||
);
|
||||
completer.complete(paymentResponse);
|
||||
}
|
||||
} else {
|
||||
// RTGS
|
||||
final rtgsTx = RtgsTransaction(
|
||||
fromAccount: widget.debitAccount,
|
||||
toAccount: accountNumberController.text,
|
||||
amount: amountController.text,
|
||||
ifscCode: ifscController.text,
|
||||
remitterName: "Unknown", // TODO: Get actual remitter name
|
||||
beneficiaryName: nameController.text,
|
||||
tpin: tpin,
|
||||
);
|
||||
final rtgsService = getIt<RtgsService>();
|
||||
final completer = Completer<PaymentResponse>();
|
||||
|
||||
Navigator.of(pinScreenContext).pushReplacement(
|
||||
MaterialPageRoute(
|
||||
builder: (_) =>
|
||||
PaymentAnimationScreen(paymentResponse: completer.future),
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
final rtgsResponse =
|
||||
await rtgsService.processRtgsTransaction(rtgsTx);
|
||||
final paymentResponse = PaymentResponse(
|
||||
isSuccess: rtgsResponse.message.toUpperCase() == 'SUCCESS',
|
||||
date: DateTime.now(),
|
||||
creditedAccount: rtgsTx.toAccount,
|
||||
amount: rtgsTx.amount,
|
||||
currency: 'INR',
|
||||
utr: rtgsResponse.utr,
|
||||
);
|
||||
completer.complete(paymentResponse);
|
||||
} catch (e) {
|
||||
final paymentResponse = PaymentResponse(
|
||||
isSuccess: false,
|
||||
errorMessage: e.toString(),
|
||||
);
|
||||
completer.complete(paymentResponse);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@@ -103,19 +300,24 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
child: ListView(
|
||||
children: [
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
children: [
|
||||
Text(AppLocalizations.of(context).debitFrom),
|
||||
Text(
|
||||
widget.debitAccount,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
Text(
|
||||
AppLocalizations.of(context).debitFrom,
|
||||
style: Theme.of(context).textTheme.titleSmall,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Card(
|
||||
elevation: 0,
|
||||
margin: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: ListTile(
|
||||
leading: Image.asset(
|
||||
'assets/images/logo.png',
|
||||
width: 40,
|
||||
height: 40,
|
||||
),
|
||||
title: Text(widget.debitAccount),
|
||||
subtitle: Text(AppLocalizations.of(context).ownBank),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
TextFormField(
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).accountNumber,
|
||||
@@ -134,11 +336,17 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
keyboardType: TextInputType.number,
|
||||
obscureText: true,
|
||||
textInputAction: TextInputAction.next,
|
||||
onChanged: (value) {
|
||||
nameController.clear();
|
||||
setState(() {
|
||||
_isBeneficiaryValidated = false;
|
||||
});
|
||||
},
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return AppLocalizations.of(context).accountNumberRequired;
|
||||
} else if (value.length != 11) {
|
||||
return AppLocalizations.of(context).validAccountNumber;
|
||||
} else if (value.length < 7 || value.length > 20) {
|
||||
return 'Account number must be between 7 and 20 digits';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -173,79 +381,6 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
TextFormField(
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).name,
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
fillColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.black),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.black, width: 2),
|
||||
),
|
||||
),
|
||||
controller: nameController,
|
||||
keyboardType: TextInputType.name,
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return AppLocalizations.of(context).nameRequired;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
TextFormField(
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).bankName,
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
fillColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.black),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.black, width: 2),
|
||||
),
|
||||
),
|
||||
controller: bankNameController,
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return AppLocalizations.of(context).bankNameRequired;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
TextFormField(
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).branchName,
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
fillColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.black),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.black, width: 2),
|
||||
),
|
||||
),
|
||||
controller: branchNameController,
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return AppLocalizations.of(context).branchNameRequired;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
@@ -265,9 +400,27 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
),
|
||||
controller: ifscController,
|
||||
textInputAction: TextInputAction.next,
|
||||
onFieldSubmitted: (_) {
|
||||
_validateIFSC();
|
||||
},
|
||||
onChanged: (value) {
|
||||
final trimmed = value.trim().toUpperCase();
|
||||
if (trimmed.length < 11) {
|
||||
// clear bank/branch if backspace or changed
|
||||
bankNameController.clear();
|
||||
branchNameController.clear();
|
||||
}
|
||||
},
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return AppLocalizations.of(context).ifscRequired;
|
||||
final pattern = RegExp(r'^[A-Z]{4}0[A-Z0-9]{6}$');
|
||||
if (value == null || value.trim().isEmpty) {
|
||||
return AppLocalizations.of(context).enterIfsc;
|
||||
} else if (!pattern.hasMatch(
|
||||
value.trim().toUpperCase(),
|
||||
)) {
|
||||
return AppLocalizations.of(
|
||||
context,
|
||||
).invalidIfscFormat;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -307,6 +460,113 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 25),
|
||||
TextFormField(
|
||||
controller: bankNameController,
|
||||
enabled: false,
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).bankName,
|
||||
border: const OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
fillColor: Theme.of(context).dialogBackgroundColor,
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.black),
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.black,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
TextFormField(
|
||||
controller: branchNameController,
|
||||
enabled: false,
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).branchName,
|
||||
border: const OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
fillColor: Theme.of(context).dialogBackgroundColor,
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.black),
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Colors.black,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
if (!_isBeneficiaryValidated)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 24),
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: _isValidating
|
||||
? null
|
||||
: () {
|
||||
if (confirmAccountNumberController
|
||||
.text ==
|
||||
accountNumberController.text) {
|
||||
_validateBeneficiary();
|
||||
} else {
|
||||
setState(() {
|
||||
_validationError =
|
||||
'Account numbers do not match.';
|
||||
});
|
||||
}
|
||||
},
|
||||
child: _isValidating
|
||||
? const SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2),
|
||||
)
|
||||
: const Text('Validate Beneficiary'),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (_validationError != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 24.0),
|
||||
child: Text(
|
||||
_validationError!,
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
),
|
||||
TextFormField(
|
||||
controller: nameController,
|
||||
enabled: false,
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).name,
|
||||
border: const OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
fillColor: Theme.of(context).dialogBackgroundColor,
|
||||
enabledBorder: const OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.black),
|
||||
),
|
||||
focusedBorder: const OutlineInputBorder(
|
||||
borderSide:
|
||||
BorderSide(color: Colors.black, width: 2),
|
||||
),
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return AppLocalizations.of(context).nameRequired;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
Row(
|
||||
children: [
|
||||
@@ -382,38 +642,16 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: SwipeButton.expand(
|
||||
thumb: Icon(Icons.arrow_forward, color: Theme.of(context).scaffoldBackgroundColor),
|
||||
activeThumbColor: Theme.of(context).primaryColorDark,
|
||||
activeTrackColor: Theme.of(context).primaryColorLight,
|
||||
thumb: Icon(Icons.arrow_forward, color: Theme.of(context).dialogBackgroundColor),
|
||||
activeThumbColor: Theme.of(context).primaryColor,
|
||||
activeTrackColor: Theme.of(context).colorScheme.secondary.withAlpha(100),
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
height: 56,
|
||||
onSwipe: _onProceedToPay,
|
||||
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',
|
||||
// )));
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -457,4 +695,4 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@@ -64,7 +64,6 @@ class _QuickPayScreen extends State<QuickPayScreen> {
|
||||
),
|
||||
const Divider(height: 1),
|
||||
QuickPayManagementTile(
|
||||
disable: true,
|
||||
icon: Symbols.output_circle,
|
||||
label: AppLocalizations.of(context).outsideBank,
|
||||
onTap: () {
|
||||
|
@@ -1,9 +1,13 @@
|
||||
import 'dart:async';
|
||||
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/api/services/payment_service.dart';
|
||||
import 'package:kmobile/data/models/payment_response.dart';
|
||||
import 'package:kmobile/data/models/transfer.dart';
|
||||
import 'package:kmobile/di/injection.dart';
|
||||
import 'package:kmobile/features/fund_transfer/screens/payment_animation.dart';
|
||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
import '../../fund_transfer/screens/transaction_pin_screen.dart';
|
||||
@@ -363,12 +367,26 @@ class _QuickPayWithinBankScreen extends State<QuickPayWithinBankScreen> {
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => TransactionPinScreen(
|
||||
transactionData: Transfer(
|
||||
fromAccount: widget.debitAccount,
|
||||
toAccount: accountNumberController.text,
|
||||
toAccountType: _selectedAccountType!,
|
||||
amount: amountController.text,
|
||||
),
|
||||
onPinCompleted: (pinScreenContext, tpin) async {
|
||||
final transfer = Transfer(
|
||||
fromAccount: widget.debitAccount,
|
||||
toAccount: accountNumberController.text,
|
||||
toAccountType: _selectedAccountType!,
|
||||
amount: amountController.text,
|
||||
tpin: tpin,
|
||||
);
|
||||
|
||||
final paymentService = getIt<PaymentService>();
|
||||
final paymentResponseFuture = paymentService
|
||||
.processQuickPayWithinBank(transfer);
|
||||
|
||||
Navigator.of(pinScreenContext).pushReplacement(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => PaymentAnimationScreen(
|
||||
paymentResponse: paymentResponseFuture),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
Reference in New Issue
Block a user