Language Change
This commit is contained in:
39
lib/app.dart
39
lib/app.dart
@@ -14,7 +14,7 @@ import 'features/auth/screens/welcome_screen.dart';
|
||||
import 'features/auth/screens/login_screen.dart';
|
||||
import 'features/service/screens/service_screen.dart';
|
||||
import 'features/dashboard/screens/dashboard_screen.dart';
|
||||
//import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||
import 'features/auth/screens/mpin_screen.dart';
|
||||
import 'package:local_auth/local_auth.dart';
|
||||
|
||||
@@ -186,7 +186,7 @@ class _AuthGateState extends State<AuthGate> {
|
||||
if (!canCheck) return false;
|
||||
try {
|
||||
final didAuth = await localAuth.authenticate(
|
||||
localizedReason: 'Authenticate to access kMobile',
|
||||
localizedReason: AppLocalizations.of(context).authenticateToAccess,
|
||||
options: const AuthenticationOptions(
|
||||
stickyAuth: true,
|
||||
biometricOnly: true,
|
||||
@@ -353,18 +353,19 @@ class _AuthGateState extends State<AuthGate> {
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: const Text('Enable Fingerprint Login?'),
|
||||
content: const Text(
|
||||
'Would you like to enable fingerprint authentication for faster login?',
|
||||
title:
|
||||
Text(AppLocalizations.of(context).enableFingerprintLogin),
|
||||
content: Text(
|
||||
AppLocalizations.of(context).enableFingerprintMessage,
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(false),
|
||||
child: const Text('No'),
|
||||
child: Text(AppLocalizations.of(context).no),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(true),
|
||||
child: const Text('Yes'),
|
||||
child: Text(AppLocalizations.of(context).yes),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -376,7 +377,8 @@ class _AuthGateState extends State<AuthGate> {
|
||||
|
||||
if (canCheck) {
|
||||
didAuth = await localAuth.authenticate(
|
||||
localizedReason: 'Authenticate to enable fingerprint login.',
|
||||
localizedReason:
|
||||
AppLocalizations.of(context).authenticateToEnable,
|
||||
options: const AuthenticationOptions(
|
||||
stickyAuth: true,
|
||||
biometricOnly: true,
|
||||
@@ -449,16 +451,16 @@ class _NavigationScaffoldState extends State<NavigationScaffold> {
|
||||
final shouldExit = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Exit App'),
|
||||
content: const Text('Do you really want to exit?'),
|
||||
title: Text(AppLocalizations.of(context).exitApp),
|
||||
content: Text(AppLocalizations.of(context).exitConfirmation),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(false),
|
||||
child: const Text('No'),
|
||||
child: Text(AppLocalizations.of(context).no),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(true),
|
||||
child: const Text('Yes'),
|
||||
child: Text(AppLocalizations.of(context).yes),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -515,7 +517,7 @@ class SplashScreen extends StatelessWidget {
|
||||
children: [
|
||||
const CircularProgressIndicator(),
|
||||
const SizedBox(height: 20),
|
||||
Text('Loading...',
|
||||
Text(AppLocalizations.of(context).loading,
|
||||
style: Theme.of(context).textTheme.headlineMedium),
|
||||
],
|
||||
),
|
||||
@@ -537,7 +539,7 @@ class BiometricPromptScreen extends StatelessWidget {
|
||||
return;
|
||||
}
|
||||
final didAuth = await localAuth.authenticate(
|
||||
localizedReason: 'Enable fingerprint authentication for quick login?',
|
||||
localizedReason: AppLocalizations.of(context).enableFingerprintQuick,
|
||||
options: const AuthenticationOptions(
|
||||
stickyAuth: true,
|
||||
biometricOnly: true,
|
||||
@@ -563,21 +565,20 @@ class BiometricPromptScreen extends StatelessWidget {
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: const Text('Enable Fingerprint Login?'),
|
||||
content: const Text(
|
||||
'Would you like to enable fingerprint authentication for faster login?'),
|
||||
title: Text(AppLocalizations.of(context).enableFingerprintLogin),
|
||||
content: Text(AppLocalizations.of(context).enableFingerprintMessage),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(ctx).pop(false);
|
||||
},
|
||||
child: const Text('No'),
|
||||
child: Text(AppLocalizations.of(context).no),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(ctx).pop(true);
|
||||
},
|
||||
child: const Text('Yes'),
|
||||
child: Text(AppLocalizations.of(context).yes),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@@ -44,7 +44,9 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Failed to load transactions: $e')),
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'${AppLocalizations.of(context).failedToLoadTransactions} $e')),
|
||||
);
|
||||
} finally {
|
||||
setState(() => _txLoading = false);
|
||||
@@ -70,7 +72,8 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
|
||||
Future<void> _selectToDate(BuildContext context) async {
|
||||
if (fromDate == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Please select From Date first')),
|
||||
SnackBar(
|
||||
content: Text(AppLocalizations.of(context).pleaseSelectDateFirst)),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:kmobile/di/injection.dart';
|
||||
@@ -110,8 +112,8 @@ class LoginScreenState extends State<LoginScreen>
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Title
|
||||
const Text(
|
||||
'KCCB',
|
||||
Text(
|
||||
AppLocalizations.of(context).kccb,
|
||||
style: TextStyle(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.bold,
|
||||
@@ -121,8 +123,8 @@ class LoginScreenState extends State<LoginScreen>
|
||||
|
||||
TextFormField(
|
||||
controller: _customerNumberController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Customer Number',
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).customerNumber,
|
||||
// prefixIcon: Icon(Icons.person),
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
@@ -139,7 +141,7 @@ class LoginScreenState extends State<LoginScreen>
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Please enter your username';
|
||||
return AppLocalizations.of(context).pleaseEnterUsername;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -153,7 +155,7 @@ class LoginScreenState extends State<LoginScreen>
|
||||
onFieldSubmitted: (_) =>
|
||||
_submitForm(), // ⌨️ Enter key submits
|
||||
decoration: InputDecoration(
|
||||
labelText: 'Password',
|
||||
labelText: AppLocalizations.of(context).password,
|
||||
border: const OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
@@ -179,7 +181,7 @@ class LoginScreenState extends State<LoginScreen>
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Please enter your password';
|
||||
return AppLocalizations.of(context).pleaseEnterPassword;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -200,22 +202,22 @@ class LoginScreenState extends State<LoginScreen>
|
||||
),
|
||||
child: state is AuthLoading
|
||||
? const CircularProgressIndicator()
|
||||
: const Text(
|
||||
"Login",
|
||||
: Text(
|
||||
AppLocalizations.of(context).login,
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
|
||||
const Padding(
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(child: Divider()),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Text('OR'),
|
||||
child: Text(AppLocalizations.of(context).or),
|
||||
),
|
||||
Expanded(child: Divider()),
|
||||
],
|
||||
@@ -235,7 +237,7 @@ class LoginScreenState extends State<LoginScreen>
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
backgroundColor: Colors.lightBlue[100],
|
||||
foregroundColor: Colors.black),
|
||||
child: const Text('Register'),
|
||||
child: Text(AppLocalizations.of(context).register),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -471,4 +473,4 @@ class LoginScreenState extends State<LoginScreen> {
|
||||
);
|
||||
}
|
||||
}
|
||||
*/
|
||||
*/
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -44,7 +46,7 @@ class _MPinScreenState extends State<MPinScreen> {
|
||||
final auth = LocalAuthentication();
|
||||
if (await auth.canCheckBiometrics) {
|
||||
final didAuth = await auth.authenticate(
|
||||
localizedReason: 'Authenticate to access kMobile',
|
||||
localizedReason: AppLocalizations.of(context).authenticateToAccess,
|
||||
options: const AuthenticationOptions(biometricOnly: true),
|
||||
);
|
||||
if (didAuth && mounted) {
|
||||
@@ -91,7 +93,7 @@ class _MPinScreenState extends State<MPinScreen> {
|
||||
widget.onCompleted?.call(pin);
|
||||
} else {
|
||||
setState(() {
|
||||
errorText = "Incorrect mPIN. Try again.";
|
||||
errorText = AppLocalizations.of(context).incorrectMPIN;
|
||||
mPin.clear();
|
||||
});
|
||||
}
|
||||
@@ -123,7 +125,7 @@ class _MPinScreenState extends State<MPinScreen> {
|
||||
}
|
||||
} else {
|
||||
setState(() {
|
||||
errorText = "Pins do not match. Try again.";
|
||||
errorText = AppLocalizations.of(context).pinsDoNotMatch;
|
||||
mPin.clear();
|
||||
});
|
||||
}
|
||||
@@ -172,7 +174,8 @@ class _MPinScreenState extends State<MPinScreen> {
|
||||
_handleComplete();
|
||||
} else {
|
||||
setState(() {
|
||||
errorText = "Please enter 4 digits";
|
||||
errorText =
|
||||
AppLocalizations.of(context).pleaseEnter4Digits;
|
||||
});
|
||||
}
|
||||
} else if (key.isNotEmpty) {
|
||||
@@ -208,11 +211,11 @@ class _MPinScreenState extends State<MPinScreen> {
|
||||
String getTitle() {
|
||||
switch (widget.mode) {
|
||||
case MPinMode.enter:
|
||||
return "Enter your mPIN";
|
||||
return AppLocalizations.of(context).enterMPIN;
|
||||
case MPinMode.set:
|
||||
return "Set your new mPIN";
|
||||
return AppLocalizations.of(context).setMPIN;
|
||||
case MPinMode.confirm:
|
||||
return "Confirm your mPIN";
|
||||
return AppLocalizations.of(context).confirmMPIN;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:async';
|
||||
|
||||
@@ -38,9 +40,9 @@ class _WelcomeScreenState extends State<WelcomeScreen> {
|
||||
Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: const [
|
||||
children: [
|
||||
Text(
|
||||
'Kconnect',
|
||||
AppLocalizations.of(context).kconnect,
|
||||
style: TextStyle(
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.bold,
|
||||
@@ -50,7 +52,7 @@ class _WelcomeScreenState extends State<WelcomeScreen> {
|
||||
),
|
||||
SizedBox(height: 12),
|
||||
Text(
|
||||
'Kangra Central Co-operative Bank',
|
||||
AppLocalizations.of(context).kccBankFull,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
|
@@ -36,7 +36,7 @@ class _BlockCardScreen extends State<BlockCardScreen> {
|
||||
// Call your backend logic here
|
||||
|
||||
final snackBar = SnackBar(
|
||||
content: const Text('Card has been blocked'),
|
||||
content: Text(AppLocalizations.of(context).cardBlocked),
|
||||
action: SnackBarAction(
|
||||
label: 'X',
|
||||
onPressed: () {
|
||||
@@ -62,8 +62,8 @@ class _BlockCardScreen extends State<BlockCardScreen> {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
title: const Text(
|
||||
'Block Card',
|
||||
title: Text(
|
||||
AppLocalizations.of(context).blockCard,
|
||||
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
|
||||
),
|
||||
centerTitle: false,
|
||||
@@ -109,7 +109,7 @@ class _BlockCardScreen extends State<BlockCardScreen> {
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) => value != null && value.length == 11
|
||||
? null
|
||||
: 'Enter valid card number',
|
||||
: AppLocalizations.of(context).enterValidCardNumber,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Row(
|
||||
@@ -135,7 +135,7 @@ class _BlockCardScreen extends State<BlockCardScreen> {
|
||||
obscureText: true,
|
||||
validator: (value) => value != null && value.length == 3
|
||||
? null
|
||||
: 'CVV must be 3 digits',
|
||||
: AppLocalizations.of(context).cvv3Digits,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
@@ -160,7 +160,7 @@ class _BlockCardScreen extends State<BlockCardScreen> {
|
||||
),
|
||||
validator: (value) => value != null && value.isNotEmpty
|
||||
? null
|
||||
: 'Select expiry date',
|
||||
: AppLocalizations.of(context).selectExpiryDate,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@@ -18,8 +18,8 @@ class _CardManagementScreen extends State<CardManagementScreen> {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
title: const Text(
|
||||
'Card Management',
|
||||
title: Text(
|
||||
AppLocalizations.of(context).cardManagement,
|
||||
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
|
||||
),
|
||||
centerTitle: false,
|
||||
|
@@ -52,8 +52,8 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
title: const Text(
|
||||
'Card Details',
|
||||
title: Text(
|
||||
AppLocalizations.of(context).cardDetails,
|
||||
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
|
||||
),
|
||||
centerTitle: false,
|
||||
@@ -99,7 +99,7 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) => value != null && value.length == 11
|
||||
? null
|
||||
: 'Enter valid card number',
|
||||
: AppLocalizations.of(context).enterValidCardNumber,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Row(
|
||||
@@ -125,7 +125,7 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
||||
obscureText: true,
|
||||
validator: (value) => value != null && value.length == 3
|
||||
? null
|
||||
: 'CVV must be 3 digits',
|
||||
: AppLocalizations.of(context).cvv3Digits,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
@@ -150,7 +150,7 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
||||
),
|
||||
validator: (value) => value != null && value.isNotEmpty
|
||||
? null
|
||||
: 'Select expiry date',
|
||||
: AppLocalizations.of(context).selectExpiryDate,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -176,7 +176,7 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
|
||||
keyboardType: TextInputType.phone,
|
||||
validator: (value) => value != null && value.length >= 10
|
||||
? null
|
||||
: 'Enter valid phone number',
|
||||
: AppLocalizations.of(context).enterValidPhone,
|
||||
),
|
||||
const SizedBox(height: 45),
|
||||
Align(
|
||||
|
@@ -19,7 +19,7 @@ class _CardPinSetScreen extends State<CardPinSetScreen> {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
// Handle PIN submission logic here
|
||||
final snackBar = SnackBar(
|
||||
content: const Text('PIN set successfully'),
|
||||
content: Text(AppLocalizations.of(context).pinSetSuccess),
|
||||
action: SnackBarAction(
|
||||
label: 'X',
|
||||
onPressed: () {
|
||||
@@ -52,8 +52,8 @@ class _CardPinSetScreen extends State<CardPinSetScreen> {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
title: const Text(
|
||||
'Card PIN',
|
||||
title: Text(
|
||||
AppLocalizations.of(context).cardPin,
|
||||
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
|
||||
),
|
||||
centerTitle: false,
|
||||
@@ -82,8 +82,8 @@ class _CardPinSetScreen extends State<CardPinSetScreen> {
|
||||
TextFormField(
|
||||
controller: _pinController,
|
||||
obscureText: true,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Enter new PIN',
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).enterNewPin,
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
@@ -99,10 +99,10 @@ class _CardPinSetScreen extends State<CardPinSetScreen> {
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Please enter new PIN';
|
||||
return AppLocalizations.of(context).pleaseEnterNewPin;
|
||||
}
|
||||
if (value.length < 4) {
|
||||
return 'PIN must be at least 4 digits';
|
||||
return AppLocalizations.of(context).pin4Digits;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -111,8 +111,8 @@ class _CardPinSetScreen extends State<CardPinSetScreen> {
|
||||
TextFormField(
|
||||
controller: _confirmPinController,
|
||||
obscureText: true,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Enter Again',
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).enterAgain,
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
@@ -128,7 +128,7 @@ class _CardPinSetScreen extends State<CardPinSetScreen> {
|
||||
textInputAction: TextInputAction.done,
|
||||
validator: (value) {
|
||||
if (value != _pinController.text) {
|
||||
return 'PINs do not match';
|
||||
return AppLocalizations.of(context).pinsDoNotMatch;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -146,7 +146,7 @@ class _CardPinSetScreen extends State<CardPinSetScreen> {
|
||||
backgroundColor: Colors.blue[900],
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: const Text('Submit'),
|
||||
child: Text(AppLocalizations.of(context).submit),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@@ -22,8 +22,8 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
title: const Text(
|
||||
'Cheque Management',
|
||||
title: Text(
|
||||
AppLocalizations.of(context).chequeManagement,
|
||||
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
|
||||
),
|
||||
centerTitle: false,
|
||||
@@ -48,7 +48,7 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
||||
const SizedBox(height: 15),
|
||||
ChequeManagementTile(
|
||||
icon: Symbols.add,
|
||||
label: 'Request Checkbook',
|
||||
label: AppLocalizations.of(context).requestChequeBook,
|
||||
onTap: () {},
|
||||
),
|
||||
const Divider(
|
||||
@@ -56,7 +56,7 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
||||
),
|
||||
ChequeManagementTile(
|
||||
icon: Symbols.data_alert,
|
||||
label: 'Enquiry',
|
||||
label: AppLocalizations.of(context).enquiry,
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
@@ -69,7 +69,7 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
||||
),
|
||||
ChequeManagementTile(
|
||||
icon: Symbols.approval_delegation,
|
||||
label: 'Cheque Deposit',
|
||||
label: AppLocalizations.of(context).chequeDeposit,
|
||||
onTap: () {},
|
||||
),
|
||||
const Divider(
|
||||
@@ -77,7 +77,7 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
||||
),
|
||||
ChequeManagementTile(
|
||||
icon: Symbols.front_hand,
|
||||
label: 'Stop Cheque',
|
||||
label: AppLocalizations.of(context).stopCheque,
|
||||
onTap: () {},
|
||||
),
|
||||
const Divider(
|
||||
@@ -85,7 +85,7 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
||||
),
|
||||
ChequeManagementTile(
|
||||
icon: Symbols.cancel_presentation,
|
||||
label: 'Revoke Stop',
|
||||
label: AppLocalizations.of(context).revokeStop,
|
||||
onTap: () {},
|
||||
),
|
||||
const Divider(
|
||||
@@ -93,7 +93,7 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
|
||||
),
|
||||
ChequeManagementTile(
|
||||
icon: Symbols.payments,
|
||||
label: 'Positive Pay',
|
||||
label: AppLocalizations.of(context).positivePay,
|
||||
onTap: () {},
|
||||
),
|
||||
const Divider(
|
||||
|
@@ -1,9 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../accounts/models/account.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class AccountCard extends StatelessWidget {
|
||||
final Account account;
|
||||
|
||||
|
||||
const AccountCard({
|
||||
super.key,
|
||||
required this.account,
|
||||
@@ -48,8 +49,8 @@ class AccountCard extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
account.accountType == 'Savings'
|
||||
? Icons.savings
|
||||
account.accountType == 'Savings'
|
||||
? Icons.savings
|
||||
: Icons.account_balance,
|
||||
color: Colors.white,
|
||||
),
|
||||
@@ -73,8 +74,8 @@ class AccountCard extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
const Text(
|
||||
'Available Balance',
|
||||
Text(
|
||||
AppLocalizations.of(context).availableBalance,
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: 12,
|
||||
@@ -84,4 +85,4 @@ class AccountCard extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ class _FundTransferScreen extends State<FundTransferScreen> {
|
||||
}
|
||||
} else if (key == 'done') {
|
||||
if (kDebugMode) {
|
||||
print('Amount entered: $amount');
|
||||
print('${AppLocalizations.of(context).amountEntered} $amount');
|
||||
// Navigator.push(
|
||||
// context,
|
||||
// MaterialPageRoute(
|
||||
|
@@ -7,6 +7,7 @@ import 'package:kmobile/data/models/payment_response.dart';
|
||||
import 'package:lottie/lottie.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class PaymentAnimationScreen extends StatefulWidget {
|
||||
final Future<PaymentResponse> paymentResponse;
|
||||
@@ -36,11 +37,14 @@ class _PaymentAnimationScreenState extends State<PaymentAnimationScreen> {
|
||||
final file = await File('${tempDir.path}/payment_result.png').create();
|
||||
await file.writeAsBytes(pngBytes);
|
||||
|
||||
await Share.shareXFiles([XFile(file.path)], text: 'Payment Result');
|
||||
await Share.shareXFiles([XFile(file.path)],
|
||||
text: '${AppLocalizations.of(context).paymentResult}');
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Failed to share screenshot: $e')),
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'${AppLocalizations.of(context).failedToShareScreenshot}: $e')),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -88,8 +92,9 @@ class _PaymentAnimationScreenState extends State<PaymentAnimationScreen> {
|
||||
isSuccess
|
||||
? Column(
|
||||
children: [
|
||||
const Text(
|
||||
'Payment Successful!',
|
||||
Text(
|
||||
AppLocalizations.of(context)
|
||||
.paymentSuccessful,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
@@ -98,7 +103,7 @@ class _PaymentAnimationScreenState extends State<PaymentAnimationScreen> {
|
||||
const SizedBox(height: 16),
|
||||
if (response.amount != null)
|
||||
Text(
|
||||
'Amount: ${response.amount} ${response.currency ?? ''}',
|
||||
'${AppLocalizations.of(context).amount}: ${response.amount} ${response.currency ?? ''}',
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w700,
|
||||
@@ -106,7 +111,7 @@ class _PaymentAnimationScreenState extends State<PaymentAnimationScreen> {
|
||||
),
|
||||
if (response.creditedAccount != null)
|
||||
Text(
|
||||
'Credited Account: ${response.creditedAccount}',
|
||||
'${AppLocalizations.of(context).creditedAccount}: ${response.creditedAccount}',
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
@@ -121,8 +126,8 @@ class _PaymentAnimationScreenState extends State<PaymentAnimationScreen> {
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
const Text(
|
||||
'Payment Failed',
|
||||
Text(
|
||||
AppLocalizations.of(context).paymentFailed,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
@@ -156,7 +161,7 @@ class _PaymentAnimationScreenState extends State<PaymentAnimationScreen> {
|
||||
Icons.share_rounded,
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
label: Text('Share',
|
||||
label: Text(AppLocalizations.of(context).share,
|
||||
style:
|
||||
TextStyle(color: Theme.of(context).primaryColor)),
|
||||
style: ElevatedButton.styleFrom(
|
||||
@@ -182,7 +187,7 @@ class _PaymentAnimationScreenState extends State<PaymentAnimationScreen> {
|
||||
Navigator.of(context)
|
||||
.popUntil((route) => route.isFirst);
|
||||
},
|
||||
label: const Text('Done'),
|
||||
label: Text(AppLocalizations.of(context).done),
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 45, vertical: 12),
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:kmobile/features/fund_transfer/screens/tpin_set_screen.dart';
|
||||
|
||||
@@ -46,7 +48,7 @@ class _TpinOtpScreenState extends State<TpinOtpScreen> {
|
||||
);
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Invalid OTP')),
|
||||
SnackBar(content: Text(AppLocalizations.of(context).invalidOtp)),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -56,7 +58,7 @@ class _TpinOtpScreenState extends State<TpinOtpScreen> {
|
||||
final theme = Theme.of(context);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Enter OTP'),
|
||||
title: Text(AppLocalizations.of(context).enterOtp),
|
||||
centerTitle: true,
|
||||
elevation: 0,
|
||||
),
|
||||
@@ -69,7 +71,7 @@ class _TpinOtpScreenState extends State<TpinOtpScreen> {
|
||||
size: 48, color: theme.colorScheme.primary),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'OTP Verification',
|
||||
AppLocalizations.of(context).otpVerification,
|
||||
style: theme.textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.colorScheme.primary,
|
||||
@@ -77,7 +79,7 @@ class _TpinOtpScreenState extends State<TpinOtpScreen> {
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Enter the 4-digit OTP sent to your mobile number.',
|
||||
AppLocalizations.of(context).otpSentMessage,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: Colors.grey[700],
|
||||
@@ -125,8 +127,8 @@ class _TpinOtpScreenState extends State<TpinOtpScreen> {
|
||||
const SizedBox(height: 32),
|
||||
ElevatedButton.icon(
|
||||
icon: const Icon(Icons.verified_user_rounded),
|
||||
label: const Text(
|
||||
'Verify OTP',
|
||||
label: Text(
|
||||
AppLocalizations.of(context).verifyOtp,
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
@@ -144,10 +146,11 @@ class _TpinOtpScreenState extends State<TpinOtpScreen> {
|
||||
onPressed: () {
|
||||
// Resend OTP logic here
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('OTP resent (mock)')),
|
||||
SnackBar(
|
||||
content: Text(AppLocalizations.of(context).otpResent)),
|
||||
);
|
||||
},
|
||||
child: const Text('Resend OTP'),
|
||||
child: Text(AppLocalizations.of(context).resendOtp),
|
||||
),
|
||||
const SizedBox(height: 60),
|
||||
],
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:kmobile/features/fund_transfer/screens/tpin_otp_screen.dart';
|
||||
|
||||
@@ -9,7 +11,7 @@ class TpinSetupPromptScreen extends StatelessWidget {
|
||||
final theme = Theme.of(context);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Set TPIN'),
|
||||
title: Text(AppLocalizations.of(context).setTpin),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 100.0),
|
||||
@@ -20,7 +22,7 @@ class TpinSetupPromptScreen extends StatelessWidget {
|
||||
size: 60, color: theme.colorScheme.primary),
|
||||
const SizedBox(height: 18),
|
||||
Text(
|
||||
'TPIN Required',
|
||||
AppLocalizations.of(context).tpinRequired,
|
||||
style: theme.textTheme.titleLarge?.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: theme.colorScheme.primary,
|
||||
@@ -28,7 +30,7 @@ class TpinSetupPromptScreen extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
'You need to set your TPIN to continue with secure transactions.',
|
||||
AppLocalizations.of(context).tpinRequiredMessage,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: Colors.grey[700],
|
||||
@@ -37,8 +39,8 @@ class TpinSetupPromptScreen extends StatelessWidget {
|
||||
const SizedBox(height: 32),
|
||||
ElevatedButton.icon(
|
||||
icon: const Icon(Icons.arrow_forward_rounded),
|
||||
label: const Text(
|
||||
'Set TPIN',
|
||||
label: Text(
|
||||
AppLocalizations.of(context).setTpin,
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
@@ -62,7 +64,7 @@ class TpinSetupPromptScreen extends StatelessWidget {
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18.0),
|
||||
child: Text(
|
||||
'Your TPIN is a 6-digit code used to authorize transactions. Keep it safe and do not share it with anyone.',
|
||||
AppLocalizations.of(context).tpinInfo,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: Colors.grey[600],
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:kmobile/api/services/auth_service.dart';
|
||||
import 'package:kmobile/di/injection.dart';
|
||||
@@ -53,7 +55,7 @@ class _TpinSetScreenState extends State<TpinSetScreen> {
|
||||
await authService.setTpin(pin);
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
_errorText = "Failed to set TPIN. Please try again.";
|
||||
_errorText = "${AppLocalizations.of(context).tpinFailed}";
|
||||
_tpin.clear();
|
||||
});
|
||||
return;
|
||||
@@ -66,15 +68,16 @@ class _TpinSetScreenState extends State<TpinSetScreen> {
|
||||
builder: (ctx) => AlertDialog(
|
||||
shape:
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(18)),
|
||||
title: const Column(
|
||||
title: Column(
|
||||
children: [
|
||||
Icon(Icons.check_circle, color: Colors.green, size: 60),
|
||||
SizedBox(height: 12),
|
||||
Text('Success!', style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
Text(AppLocalizations.of(context).success,
|
||||
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
],
|
||||
),
|
||||
content: const Text(
|
||||
'Your TPIN was set up successfully.',
|
||||
content: Text(
|
||||
AppLocalizations.of(context).tpinSetSuccess,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
actions: [
|
||||
@@ -82,7 +85,8 @@ class _TpinSetScreenState extends State<TpinSetScreen> {
|
||||
onPressed: () {
|
||||
Navigator.of(ctx).pop();
|
||||
},
|
||||
child: const Text('OK', style: TextStyle(fontSize: 16)),
|
||||
child: Text(AppLocalizations.of(context).ok,
|
||||
style: TextStyle(fontSize: 16)),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -92,7 +96,7 @@ class _TpinSetScreenState extends State<TpinSetScreen> {
|
||||
}
|
||||
} else {
|
||||
setState(() {
|
||||
_errorText = "Pins do not match. Try again.";
|
||||
_errorText = AppLocalizations.of(context).pinsMismatchRetry;
|
||||
_tpin.clear();
|
||||
});
|
||||
}
|
||||
@@ -140,7 +144,8 @@ class _TpinSetScreenState extends State<TpinSetScreen> {
|
||||
_handleComplete();
|
||||
} else {
|
||||
setState(() {
|
||||
_errorText = "Please enter 6 digits";
|
||||
_errorText =
|
||||
AppLocalizations.of(context).pleaseEnter6Digits;
|
||||
});
|
||||
}
|
||||
} else if (key.isNotEmpty) {
|
||||
@@ -176,16 +181,16 @@ class _TpinSetScreenState extends State<TpinSetScreen> {
|
||||
String getTitle() {
|
||||
switch (_mode) {
|
||||
case TPinMode.set:
|
||||
return "Set your new TPIN";
|
||||
return AppLocalizations.of(context).setNewTpin;
|
||||
case TPinMode.confirm:
|
||||
return "Confirm your new TPIN";
|
||||
return AppLocalizations.of(context).confirmNewTpin;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Set TPIN')),
|
||||
appBar: AppBar(title: Text(AppLocalizations.of(context).setTpin)),
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:kmobile/api/services/auth_service.dart';
|
||||
import 'package:kmobile/api/services/payment_service.dart';
|
||||
@@ -45,7 +47,8 @@ class _TransactionPinScreen extends State<TransactionPinScreen> {
|
||||
if (mounted) {
|
||||
setState(() => _loading = false);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Failed to check TPIN status')),
|
||||
SnackBar(
|
||||
content: Text(AppLocalizations.of(context).tpinStatusFailed)),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -91,7 +94,9 @@ class _TransactionPinScreen extends State<TransactionPinScreen> {
|
||||
await sendTransaction();
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("Please enter a 6-digit TPIN")),
|
||||
SnackBar(
|
||||
content:
|
||||
Text(AppLocalizations.of(context).enter6DigitTpin)),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@@ -131,12 +136,13 @@ class _TransactionPinScreen extends State<TransactionPinScreen> {
|
||||
final transfer = widget.transactionData;
|
||||
transfer.tpin = _pin.join();
|
||||
try {
|
||||
final paymentResponse = paymentService.processQuickPayWithinBank(transfer);
|
||||
final paymentResponse =
|
||||
paymentService.processQuickPayWithinBank(transfer);
|
||||
|
||||
Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => PaymentAnimationScreen(paymentResponse: paymentResponse)
|
||||
),
|
||||
builder: (_) =>
|
||||
PaymentAnimationScreen(paymentResponse: paymentResponse)),
|
||||
);
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
@@ -157,28 +163,28 @@ class _TransactionPinScreen extends State<TransactionPinScreen> {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
title: const Text(
|
||||
'TPIN',
|
||||
title: Text(
|
||||
AppLocalizations.of(context).tpin,
|
||||
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
|
||||
),
|
||||
centerTitle: false,
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 20.0),
|
||||
child: Column(
|
||||
children: [
|
||||
const Spacer(),
|
||||
const Text(
|
||||
'Enter Your TPIN',
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_buildPinIndicators(),
|
||||
const Spacer(),
|
||||
_buildKeypad(),
|
||||
],
|
||||
),
|
||||
padding: const EdgeInsets.only(bottom: 20.0),
|
||||
child: Column(
|
||||
children: [
|
||||
const Spacer(),
|
||||
Text(
|
||||
AppLocalizations.of(context).enterTpin,
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_buildPinIndicators(),
|
||||
const Spacer(),
|
||||
_buildKeypad(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -57,8 +59,8 @@ class _TransactionSuccessScreen extends State<TransactionSuccessScreen> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const Text(
|
||||
"Transaction Successful",
|
||||
Text(
|
||||
AppLocalizations.of(context).transactionSuccess,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -76,7 +78,7 @@ class _TransactionSuccessScreen extends State<TransactionSuccessScreen> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
"To Account Number: $creditAccount",
|
||||
"${AppLocalizations.of(context).toAccountNumber}: $creditAccount",
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.black87,
|
||||
@@ -98,7 +100,7 @@ class _TransactionSuccessScreen extends State<TransactionSuccessScreen> {
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: _shareScreenshot,
|
||||
icon: const Icon(Icons.share, size: 18),
|
||||
label: const Text("Share"),
|
||||
label: Text(AppLocalizations.of(context).share),
|
||||
style: ElevatedButton.styleFrom(
|
||||
shape: const StadiumBorder(),
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
@@ -126,7 +128,7 @@ class _TransactionSuccessScreen extends State<TransactionSuccessScreen> {
|
||||
backgroundColor: Colors.blue[900],
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: const Text("Done"),
|
||||
child: Text(AppLocalizations.of(context).done),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@@ -1,9 +1,10 @@
|
||||
import 'package:flutter_gen/gen_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';
|
||||
|
||||
|
||||
class QuickPayOutsideBankScreen extends StatefulWidget {
|
||||
final String debitAccount;
|
||||
const QuickPayOutsideBankScreen({super.key, required this.debitAccount});
|
||||
@@ -26,8 +27,28 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
final phoneController = TextEditingController();
|
||||
final amountController = TextEditingController();
|
||||
|
||||
String accountType = 'Savings';
|
||||
final List<String> transactionModes = ['NEFT', 'RTGS', 'IMPS'];
|
||||
//String accountType = 'Savings';
|
||||
late String accountType;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
setState(() {
|
||||
accountType = AppLocalizations.of(context).savings;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//final List<String> transactionModes = ['NEFT', 'RTGS', 'IMPS'];
|
||||
List<String> transactionModes(BuildContext context) {
|
||||
return [
|
||||
AppLocalizations.of(context).neft,
|
||||
AppLocalizations.of(context).rtgs,
|
||||
AppLocalizations.of(context).imps,
|
||||
];
|
||||
}
|
||||
|
||||
int selectedTransactionIndex = 0;
|
||||
|
||||
@override
|
||||
@@ -54,8 +75,8 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
title: const Text(
|
||||
'Quick Pay - Outside Bank',
|
||||
title: Text(
|
||||
AppLocalizations.of(context).quickPayOutsideBank,
|
||||
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
|
||||
),
|
||||
centerTitle: false,
|
||||
@@ -84,17 +105,18 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
children: [
|
||||
const Text('Debit from:'),
|
||||
Text(AppLocalizations.of(context).debitFrom),
|
||||
Text(
|
||||
widget.debitAccount,
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
|
||||
style: const TextStyle(
|
||||
fontSize: 18, fontWeight: FontWeight.w500),
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Account Number',
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).accountNumber,
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
@@ -112,9 +134,9 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Account number is required';
|
||||
return AppLocalizations.of(context).accountNumberRequired;
|
||||
} else if (value.length != 11) {
|
||||
return 'Enter a valid account number';
|
||||
return AppLocalizations.of(context).validAccountNumber;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -122,8 +144,8 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
const SizedBox(height: 24),
|
||||
TextFormField(
|
||||
controller: confirmAccountNumberController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Confirm Account Number',
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).confirmAccountNumber,
|
||||
// prefixIcon: Icon(Icons.person),
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
@@ -140,18 +162,18 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Re-enter account number';
|
||||
return AppLocalizations.of(context).reenterAccountNumber;
|
||||
}
|
||||
if (value != accountNumberController.text) {
|
||||
return 'Account numbers do not match';
|
||||
return AppLocalizations.of(context).accountMismatch;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Name',
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).name,
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
@@ -168,15 +190,15 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Name is required';
|
||||
return AppLocalizations.of(context).nameRequired;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Beneficiary Bank Name",
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).bankName,
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
@@ -192,15 +214,15 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Beneficiary Bank Name is required';
|
||||
return AppLocalizations.of(context).bankNameRequired;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Branch Name",
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).branchName,
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
@@ -216,7 +238,7 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Branch Name is required';
|
||||
return AppLocalizations.of(context).branchNameRequired;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -226,8 +248,8 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
labelText: "IFSC Code",
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).ifscCode,
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
@@ -243,7 +265,7 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'IFSC Code is required';
|
||||
return AppLocalizations.of(context).ifscRequired;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -252,8 +274,8 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
Expanded(
|
||||
child: DropdownButtonFormField<String>(
|
||||
value: accountType,
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Account Type",
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).accountType,
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
@@ -265,7 +287,10 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
borderSide: BorderSide(color: Colors.black, width: 2),
|
||||
),
|
||||
),
|
||||
items: ['Savings', 'Current']
|
||||
items: [
|
||||
AppLocalizations.of(context).savings,
|
||||
AppLocalizations.of(context).current
|
||||
]
|
||||
.map((e) => DropdownMenuItem(
|
||||
value: e,
|
||||
child: Text(e),
|
||||
@@ -285,8 +310,8 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
child: TextFormField(
|
||||
controller: phoneController,
|
||||
keyboardType: TextInputType.phone,
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Phone",
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).phone,
|
||||
prefixIcon: Icon(Icons.phone),
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
@@ -301,15 +326,15 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
),
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) => value == null || value.isEmpty
|
||||
? "Phone number is Required"
|
||||
? AppLocalizations.of(context).phoneRequired
|
||||
: null,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Amount',
|
||||
decoration: InputDecoration(
|
||||
labelText: AppLocalizations.of(context).amount,
|
||||
border: OutlineInputBorder(),
|
||||
isDense: true,
|
||||
filled: true,
|
||||
@@ -326,11 +351,11 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Amount is required';
|
||||
return AppLocalizations.of(context).amountRequired;
|
||||
}
|
||||
final amount = double.tryParse(value);
|
||||
if (amount == null || amount <= 0) {
|
||||
return 'Enter a valid amount';
|
||||
return AppLocalizations.of(context).validAmount;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -341,7 +366,7 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
const SizedBox(height: 30),
|
||||
Row(
|
||||
children: [
|
||||
const Text("Transaction Mode",
|
||||
Text(AppLocalizations.of(context).transactionMode,
|
||||
style: TextStyle(fontWeight: FontWeight.w500)),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(child: buildTransactionModeSelector()),
|
||||
@@ -359,8 +384,8 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
activeTrackColor: Colors.blue.shade100,
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
height: 56,
|
||||
child: const Text(
|
||||
"Swipe to Pay",
|
||||
child: Text(
|
||||
AppLocalizations.of(context).swipeToPay,
|
||||
style:
|
||||
TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||
),
|
||||
@@ -368,10 +393,11 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
// Perform payment logic
|
||||
final selectedMode =
|
||||
transactionModes[selectedTransactionIndex];
|
||||
transactionModes(context)[selectedTransactionIndex];
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Paying via $selectedMode...')),
|
||||
content: Text(
|
||||
'${AppLocalizations.of(context).payingVia} $selectedMode...')),
|
||||
);
|
||||
// Navigator.push(
|
||||
// context,
|
||||
@@ -395,7 +421,7 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Row(
|
||||
children: List.generate(transactionModes.length, (index) {
|
||||
children: List.generate(transactionModes(context).length, (index) {
|
||||
bool isSelected = selectedTransactionIndex == index;
|
||||
return Expanded(
|
||||
child: GestureDetector(
|
||||
@@ -415,7 +441,7 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
transactionModes[index],
|
||||
transactionModes(context)[index],
|
||||
style: const TextStyle(
|
||||
color: Colors.black,
|
||||
),
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||
|
||||
@@ -8,14 +10,16 @@ class ServiceScreen extends StatefulWidget {
|
||||
State<ServiceScreen> createState() => _ServiceScreen();
|
||||
}
|
||||
|
||||
class _ServiceScreen extends State<ServiceScreen>{
|
||||
class _ServiceScreen extends State<ServiceScreen> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
title: const Text('Services', style: TextStyle(color: Colors.black,
|
||||
fontWeight: FontWeight.w500),),
|
||||
title: Text(
|
||||
AppLocalizations.of(context).services,
|
||||
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
|
||||
),
|
||||
centerTitle: false,
|
||||
actions: [
|
||||
// IconButton(
|
||||
@@ -28,61 +32,53 @@ class _ServiceScreen extends State<ServiceScreen>{
|
||||
padding: const EdgeInsets.only(right: 10.0),
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
onTap: (){
|
||||
onTap: () {
|
||||
// Navigator.push(context, MaterialPageRoute(
|
||||
// builder: (context) => const CustomerInfoScreen()));
|
||||
},
|
||||
child: const CircleAvatar(
|
||||
backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image
|
||||
backgroundImage: AssetImage(
|
||||
'assets/images/avatar.jpg'), // Replace with your image
|
||||
radius: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
body: ListView(
|
||||
children: [
|
||||
ServiceManagementTile(
|
||||
icon: Symbols.add,
|
||||
label: 'Account Opening Request - Deposit',
|
||||
onTap: () {
|
||||
|
||||
},
|
||||
label: AppLocalizations.of(context).accountOpeningDeposit,
|
||||
onTap: () {},
|
||||
),
|
||||
const Divider(
|
||||
height: 1,
|
||||
),
|
||||
|
||||
const Divider(height: 1,),
|
||||
|
||||
ServiceManagementTile(
|
||||
icon: Symbols.add,
|
||||
label: 'Account Opening Request - Loan',
|
||||
onTap: () {
|
||||
|
||||
},
|
||||
label: AppLocalizations.of(context).accountOpeningLoan,
|
||||
onTap: () {},
|
||||
),
|
||||
const Divider(
|
||||
height: 1,
|
||||
),
|
||||
|
||||
const Divider(height: 1,),
|
||||
|
||||
ServiceManagementTile(
|
||||
icon: Symbols.captive_portal,
|
||||
label: 'Quick Links',
|
||||
onTap: () {
|
||||
|
||||
},
|
||||
label: AppLocalizations.of(context).quickLinks,
|
||||
onTap: () {},
|
||||
),
|
||||
const Divider(
|
||||
height: 1,
|
||||
),
|
||||
|
||||
const Divider(height: 1,),
|
||||
|
||||
ServiceManagementTile(
|
||||
icon: Symbols.missing_controller,
|
||||
label: 'Branch Locator',
|
||||
onTap: () {
|
||||
|
||||
},
|
||||
label: AppLocalizations.of(context).branchLocator,
|
||||
onTap: () {},
|
||||
),
|
||||
|
||||
const Divider(height: 1,)
|
||||
|
||||
const Divider(
|
||||
height: 1,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -110,4 +106,4 @@ class ServiceManagementTile extends StatelessWidget {
|
||||
onTap: onTap,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -194,6 +194,31 @@
|
||||
"transactionSuccess": "Transaction Successful",
|
||||
"on": "On",
|
||||
"toAccountNumber": "To Account Number",
|
||||
"shareText": "Share"
|
||||
"shareText": "Share",
|
||||
"enableFingerprintLogin": "Enable Fingerprint Login?",
|
||||
"enableFingerprintMessage": "Would you like to enable fingerprint authentication for faster login?",
|
||||
"no": "No",
|
||||
"yes": "Yes",
|
||||
"authenticateToEnable": "Authenticate to enable fingerprint login",
|
||||
"exitApp": "Exit App",
|
||||
"exitConfirmation": "Do you really want to exit?",
|
||||
"loading": "Loading......",
|
||||
"enableFingerprintQuick": "Enable fingerprint authentication for quick login?",
|
||||
"kccb": "KCCB",
|
||||
"password": "Password",
|
||||
"pleaseEnterUsername": "Please enter your username",
|
||||
"pleaseEnterPassword": "Please enter your password",
|
||||
"login": "Login",
|
||||
"or": "OR",
|
||||
"register": "Register",
|
||||
"authenticateToAccess": "Authenticate to access kmobile",
|
||||
"incorrectMPIN": "Incorrect mPIN. Try again.",
|
||||
"pinsDoNotMatch": "PINs do not match. Try again.",
|
||||
"pleaseEnter4Digits": "Please enter 4 digits.",
|
||||
"enterMPIN": "Enter your mPIN",
|
||||
"setMPIN": "Set your mPIN",
|
||||
"confirmMPIN": "Confirm your mPIN",
|
||||
"kconnect": "Kconnect",
|
||||
"kccBankFull": "Kangra Central Co-operative Bank"
|
||||
}
|
||||
|
||||
|
@@ -194,5 +194,30 @@
|
||||
"transactionSuccess": "लेन-देन सफल रहा",
|
||||
"on": "पर",
|
||||
"toAccountNumber": "खाते संख्या में",
|
||||
"shareText": "साझा करें"
|
||||
}
|
||||
"shareText": "साझा करें",
|
||||
"enableFingerprintLogin": "फिंगरप्रिंट लॉगिन सक्षम करें?",
|
||||
"enableFingerprintMessage": "क्या आप तेज लॉगिन के लिए फिंगरप्रिंट प्रमाणीकरण सक्षम करना चाहेंगे?",
|
||||
"no": "नहीं",
|
||||
"yes": "हाँ",
|
||||
"authenticateToEnable": "फिंगरप्रिंट लॉगिन सक्षम करने के लिए प्रमाणीकरण करें",
|
||||
"exitApp": "ऐप बंद करें",
|
||||
"exitConfirmation": "क्या आप वाकई ऐप से बाहर निकलना चाहते हैं?",
|
||||
"loading": "लोड हो रहा है......",
|
||||
"enableFingerprintQuick": "तेज़ लॉगिन के लिए फिंगरप्रिंट प्रमाणीकरण सक्षम करें?",
|
||||
"kccb": "केसीसीबी",
|
||||
"password": "पासवर्ड",
|
||||
"pleaseEnterUsername": "कृपया उपयोगकर्ता नाम दर्ज करें",
|
||||
"pleaseEnterPassword": "कृपया पासवर्ड दर्ज करें",
|
||||
"login": "लॉगिन",
|
||||
"or": "या",
|
||||
"register": "रजिस्टर करें",
|
||||
"authenticateToAccess": "kmobile तक पहुंच के लिए प्रमाणीकरण करें",
|
||||
"incorrectMPIN": "गलत mPIN. कृपया पुनः प्रयास करें।",
|
||||
"pinsDoNotMatch": "PIN मेल नहीं खा रहे हैं। पुनः प्रयास करें।",
|
||||
"pleaseEnter4Digits": "कृपया 4 अंक दर्ज करें।",
|
||||
"enterMPIN": "अपना mPIN दर्ज करें",
|
||||
"setMPIN": "अपना mPIN सेट करें",
|
||||
"confirmMPIN": "अपना mPIN की पुष्टि करें",
|
||||
"kconnect": "केकनेक्ट",
|
||||
"kccBankFull": "कांगड़ा सेंट्रल को-ऑपरेटिव बैंक"
|
||||
}
|
||||
|
Reference in New Issue
Block a user