Language Change

This commit is contained in:
Nilanjan Chakrabarti
2025-07-10 13:19:31 +05:30
parent 9b439338a9
commit d4de89a91f
22 changed files with 334 additions and 227 deletions

View File

@@ -14,7 +14,7 @@ import 'features/auth/screens/welcome_screen.dart';
import 'features/auth/screens/login_screen.dart'; import 'features/auth/screens/login_screen.dart';
import 'features/service/screens/service_screen.dart'; import 'features/service/screens/service_screen.dart';
import 'features/dashboard/screens/dashboard_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 'features/auth/screens/mpin_screen.dart';
import 'package:local_auth/local_auth.dart'; import 'package:local_auth/local_auth.dart';
@@ -186,7 +186,7 @@ class _AuthGateState extends State<AuthGate> {
if (!canCheck) return false; if (!canCheck) return false;
try { try {
final didAuth = await localAuth.authenticate( final didAuth = await localAuth.authenticate(
localizedReason: 'Authenticate to access kMobile', localizedReason: AppLocalizations.of(context).authenticateToAccess,
options: const AuthenticationOptions( options: const AuthenticationOptions(
stickyAuth: true, stickyAuth: true,
biometricOnly: true, biometricOnly: true,
@@ -353,18 +353,19 @@ class _AuthGateState extends State<AuthGate> {
context: context, context: context,
barrierDismissible: false, barrierDismissible: false,
builder: (ctx) => AlertDialog( builder: (ctx) => AlertDialog(
title: const Text('Enable Fingerprint Login?'), title:
content: const Text( Text(AppLocalizations.of(context).enableFingerprintLogin),
'Would you like to enable fingerprint authentication for faster login?', content: Text(
AppLocalizations.of(context).enableFingerprintMessage,
), ),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Navigator.of(ctx).pop(false), onPressed: () => Navigator.of(ctx).pop(false),
child: const Text('No'), child: Text(AppLocalizations.of(context).no),
), ),
TextButton( TextButton(
onPressed: () => Navigator.of(ctx).pop(true), 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) { if (canCheck) {
didAuth = await localAuth.authenticate( didAuth = await localAuth.authenticate(
localizedReason: 'Authenticate to enable fingerprint login.', localizedReason:
AppLocalizations.of(context).authenticateToEnable,
options: const AuthenticationOptions( options: const AuthenticationOptions(
stickyAuth: true, stickyAuth: true,
biometricOnly: true, biometricOnly: true,
@@ -449,16 +451,16 @@ class _NavigationScaffoldState extends State<NavigationScaffold> {
final shouldExit = await showDialog<bool>( final shouldExit = await showDialog<bool>(
context: context, context: context,
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
title: const Text('Exit App'), title: Text(AppLocalizations.of(context).exitApp),
content: const Text('Do you really want to exit?'), content: Text(AppLocalizations.of(context).exitConfirmation),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Navigator.of(context).pop(false), onPressed: () => Navigator.of(context).pop(false),
child: const Text('No'), child: Text(AppLocalizations.of(context).no),
), ),
TextButton( TextButton(
onPressed: () => Navigator.of(context).pop(true), 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: [ children: [
const CircularProgressIndicator(), const CircularProgressIndicator(),
const SizedBox(height: 20), const SizedBox(height: 20),
Text('Loading...', Text(AppLocalizations.of(context).loading,
style: Theme.of(context).textTheme.headlineMedium), style: Theme.of(context).textTheme.headlineMedium),
], ],
), ),
@@ -537,7 +539,7 @@ class BiometricPromptScreen extends StatelessWidget {
return; return;
} }
final didAuth = await localAuth.authenticate( final didAuth = await localAuth.authenticate(
localizedReason: 'Enable fingerprint authentication for quick login?', localizedReason: AppLocalizations.of(context).enableFingerprintQuick,
options: const AuthenticationOptions( options: const AuthenticationOptions(
stickyAuth: true, stickyAuth: true,
biometricOnly: true, biometricOnly: true,
@@ -563,21 +565,20 @@ class BiometricPromptScreen extends StatelessWidget {
context: context, context: context,
barrierDismissible: true, barrierDismissible: true,
builder: (ctx) => AlertDialog( builder: (ctx) => AlertDialog(
title: const Text('Enable Fingerprint Login?'), title: Text(AppLocalizations.of(context).enableFingerprintLogin),
content: const Text( content: Text(AppLocalizations.of(context).enableFingerprintMessage),
'Would you like to enable fingerprint authentication for faster login?'),
actions: [ actions: [
TextButton( TextButton(
onPressed: () { onPressed: () {
Navigator.of(ctx).pop(false); Navigator.of(ctx).pop(false);
}, },
child: const Text('No'), child: Text(AppLocalizations.of(context).no),
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
Navigator.of(ctx).pop(true); Navigator.of(ctx).pop(true);
}, },
child: const Text('Yes'), child: Text(AppLocalizations.of(context).yes),
), ),
], ],
), ),

View File

@@ -44,7 +44,9 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
} catch (e) { } catch (e) {
if (!mounted) return; if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to load transactions: $e')), SnackBar(
content: Text(
'${AppLocalizations.of(context).failedToLoadTransactions} $e')),
); );
} finally { } finally {
setState(() => _txLoading = false); setState(() => _txLoading = false);
@@ -70,7 +72,8 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
Future<void> _selectToDate(BuildContext context) async { Future<void> _selectToDate(BuildContext context) async {
if (fromDate == null) { if (fromDate == null) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please select From Date first')), SnackBar(
content: Text(AppLocalizations.of(context).pleaseSelectDateFirst)),
); );
return; return;
} }

View File

@@ -1,3 +1,5 @@
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:kmobile/di/injection.dart'; import 'package:kmobile/di/injection.dart';
@@ -110,8 +112,8 @@ class LoginScreenState extends State<LoginScreen>
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
// Title // Title
const Text( Text(
'KCCB', AppLocalizations.of(context).kccb,
style: TextStyle( style: TextStyle(
fontSize: 32, fontSize: 32,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -121,8 +123,8 @@ class LoginScreenState extends State<LoginScreen>
TextFormField( TextFormField(
controller: _customerNumberController, controller: _customerNumberController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Customer Number', labelText: AppLocalizations.of(context).customerNumber,
// prefixIcon: Icon(Icons.person), // prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(), border: OutlineInputBorder(),
isDense: true, isDense: true,
@@ -139,7 +141,7 @@ class LoginScreenState extends State<LoginScreen>
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Please enter your username'; return AppLocalizations.of(context).pleaseEnterUsername;
} }
return null; return null;
}, },
@@ -153,7 +155,7 @@ class LoginScreenState extends State<LoginScreen>
onFieldSubmitted: (_) => onFieldSubmitted: (_) =>
_submitForm(), // ⌨️ Enter key submits _submitForm(), // ⌨️ Enter key submits
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'Password', labelText: AppLocalizations.of(context).password,
border: const OutlineInputBorder(), border: const OutlineInputBorder(),
isDense: true, isDense: true,
filled: true, filled: true,
@@ -179,7 +181,7 @@ class LoginScreenState extends State<LoginScreen>
), ),
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Please enter your password'; return AppLocalizations.of(context).pleaseEnterPassword;
} }
return null; return null;
}, },
@@ -200,22 +202,22 @@ class LoginScreenState extends State<LoginScreen>
), ),
child: state is AuthLoading child: state is AuthLoading
? const CircularProgressIndicator() ? const CircularProgressIndicator()
: const Text( : Text(
"Login", AppLocalizations.of(context).login,
style: TextStyle(fontSize: 16), style: TextStyle(fontSize: 16),
), ),
), ),
), ),
const SizedBox(height: 15), const SizedBox(height: 15),
const Padding( Padding(
padding: EdgeInsets.symmetric(vertical: 16), padding: EdgeInsets.symmetric(vertical: 16),
child: Row( child: Row(
children: [ children: [
Expanded(child: Divider()), Expanded(child: Divider()),
Padding( Padding(
padding: EdgeInsets.symmetric(horizontal: 8), padding: EdgeInsets.symmetric(horizontal: 8),
child: Text('OR'), child: Text(AppLocalizations.of(context).or),
), ),
Expanded(child: Divider()), Expanded(child: Divider()),
], ],
@@ -235,7 +237,7 @@ class LoginScreenState extends State<LoginScreen>
padding: const EdgeInsets.symmetric(vertical: 16), padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor: Colors.lightBlue[100], backgroundColor: Colors.lightBlue[100],
foregroundColor: Colors.black), foregroundColor: Colors.black),
child: const Text('Register'), child: Text(AppLocalizations.of(context).register),
), ),
), ),
], ],

View File

@@ -1,3 +1,5 @@
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'dart:developer'; import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -44,7 +46,7 @@ class _MPinScreenState extends State<MPinScreen> {
final auth = LocalAuthentication(); final auth = LocalAuthentication();
if (await auth.canCheckBiometrics) { if (await auth.canCheckBiometrics) {
final didAuth = await auth.authenticate( final didAuth = await auth.authenticate(
localizedReason: 'Authenticate to access kMobile', localizedReason: AppLocalizations.of(context).authenticateToAccess,
options: const AuthenticationOptions(biometricOnly: true), options: const AuthenticationOptions(biometricOnly: true),
); );
if (didAuth && mounted) { if (didAuth && mounted) {
@@ -91,7 +93,7 @@ class _MPinScreenState extends State<MPinScreen> {
widget.onCompleted?.call(pin); widget.onCompleted?.call(pin);
} else { } else {
setState(() { setState(() {
errorText = "Incorrect mPIN. Try again."; errorText = AppLocalizations.of(context).incorrectMPIN;
mPin.clear(); mPin.clear();
}); });
} }
@@ -123,7 +125,7 @@ class _MPinScreenState extends State<MPinScreen> {
} }
} else { } else {
setState(() { setState(() {
errorText = "Pins do not match. Try again."; errorText = AppLocalizations.of(context).pinsDoNotMatch;
mPin.clear(); mPin.clear();
}); });
} }
@@ -172,7 +174,8 @@ class _MPinScreenState extends State<MPinScreen> {
_handleComplete(); _handleComplete();
} else { } else {
setState(() { setState(() {
errorText = "Please enter 4 digits"; errorText =
AppLocalizations.of(context).pleaseEnter4Digits;
}); });
} }
} else if (key.isNotEmpty) { } else if (key.isNotEmpty) {
@@ -208,11 +211,11 @@ class _MPinScreenState extends State<MPinScreen> {
String getTitle() { String getTitle() {
switch (widget.mode) { switch (widget.mode) {
case MPinMode.enter: case MPinMode.enter:
return "Enter your mPIN"; return AppLocalizations.of(context).enterMPIN;
case MPinMode.set: case MPinMode.set:
return "Set your new mPIN"; return AppLocalizations.of(context).setMPIN;
case MPinMode.confirm: case MPinMode.confirm:
return "Confirm your mPIN"; return AppLocalizations.of(context).confirmMPIN;
} }
} }

View File

@@ -1,3 +1,5 @@
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'dart:async'; import 'dart:async';
@@ -38,9 +40,9 @@ class _WelcomeScreenState extends State<WelcomeScreen> {
Center( Center(
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: const [ children: [
Text( Text(
'Kconnect', AppLocalizations.of(context).kconnect,
style: TextStyle( style: TextStyle(
fontSize: 36, fontSize: 36,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -50,7 +52,7 @@ class _WelcomeScreenState extends State<WelcomeScreen> {
), ),
SizedBox(height: 12), SizedBox(height: 12),
Text( Text(
'Kangra Central Co-operative Bank', AppLocalizations.of(context).kccBankFull,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 18, fontSize: 18,

View File

@@ -36,7 +36,7 @@ class _BlockCardScreen extends State<BlockCardScreen> {
// Call your backend logic here // Call your backend logic here
final snackBar = SnackBar( final snackBar = SnackBar(
content: const Text('Card has been blocked'), content: Text(AppLocalizations.of(context).cardBlocked),
action: SnackBarAction( action: SnackBarAction(
label: 'X', label: 'X',
onPressed: () { onPressed: () {
@@ -62,8 +62,8 @@ class _BlockCardScreen extends State<BlockCardScreen> {
Navigator.pop(context); Navigator.pop(context);
}, },
), ),
title: const Text( title: Text(
'Block Card', AppLocalizations.of(context).blockCard,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500), style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
), ),
centerTitle: false, centerTitle: false,
@@ -109,7 +109,7 @@ class _BlockCardScreen extends State<BlockCardScreen> {
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (value) => value != null && value.length == 11 validator: (value) => value != null && value.length == 11
? null ? null
: 'Enter valid card number', : AppLocalizations.of(context).enterValidCardNumber,
), ),
const SizedBox(height: 24), const SizedBox(height: 24),
Row( Row(
@@ -135,7 +135,7 @@ class _BlockCardScreen extends State<BlockCardScreen> {
obscureText: true, obscureText: true,
validator: (value) => value != null && value.length == 3 validator: (value) => value != null && value.length == 3
? null ? null
: 'CVV must be 3 digits', : AppLocalizations.of(context).cvv3Digits,
), ),
), ),
const SizedBox(width: 16), const SizedBox(width: 16),
@@ -160,7 +160,7 @@ class _BlockCardScreen extends State<BlockCardScreen> {
), ),
validator: (value) => value != null && value.isNotEmpty validator: (value) => value != null && value.isNotEmpty
? null ? null
: 'Select expiry date', : AppLocalizations.of(context).selectExpiryDate,
), ),
), ),
], ],

View File

@@ -18,8 +18,8 @@ class _CardManagementScreen extends State<CardManagementScreen> {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
title: const Text( title: Text(
'Card Management', AppLocalizations.of(context).cardManagement,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500), style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
), ),
centerTitle: false, centerTitle: false,

View File

@@ -52,8 +52,8 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
Navigator.pop(context); Navigator.pop(context);
}, },
), ),
title: const Text( title: Text(
'Card Details', AppLocalizations.of(context).cardDetails,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500), style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
), ),
centerTitle: false, centerTitle: false,
@@ -99,7 +99,7 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (value) => value != null && value.length == 11 validator: (value) => value != null && value.length == 11
? null ? null
: 'Enter valid card number', : AppLocalizations.of(context).enterValidCardNumber,
), ),
const SizedBox(height: 24), const SizedBox(height: 24),
Row( Row(
@@ -125,7 +125,7 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
obscureText: true, obscureText: true,
validator: (value) => value != null && value.length == 3 validator: (value) => value != null && value.length == 3
? null ? null
: 'CVV must be 3 digits', : AppLocalizations.of(context).cvv3Digits,
), ),
), ),
const SizedBox(width: 16), const SizedBox(width: 16),
@@ -150,7 +150,7 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
), ),
validator: (value) => value != null && value.isNotEmpty validator: (value) => value != null && value.isNotEmpty
? null ? null
: 'Select expiry date', : AppLocalizations.of(context).selectExpiryDate,
), ),
), ),
], ],
@@ -176,7 +176,7 @@ class _CardPinChangeDetailsScreen extends State<CardPinChangeDetailsScreen> {
keyboardType: TextInputType.phone, keyboardType: TextInputType.phone,
validator: (value) => value != null && value.length >= 10 validator: (value) => value != null && value.length >= 10
? null ? null
: 'Enter valid phone number', : AppLocalizations.of(context).enterValidPhone,
), ),
const SizedBox(height: 45), const SizedBox(height: 45),
Align( Align(

View File

@@ -19,7 +19,7 @@ class _CardPinSetScreen extends State<CardPinSetScreen> {
if (_formKey.currentState!.validate()) { if (_formKey.currentState!.validate()) {
// Handle PIN submission logic here // Handle PIN submission logic here
final snackBar = SnackBar( final snackBar = SnackBar(
content: const Text('PIN set successfully'), content: Text(AppLocalizations.of(context).pinSetSuccess),
action: SnackBarAction( action: SnackBarAction(
label: 'X', label: 'X',
onPressed: () { onPressed: () {
@@ -52,8 +52,8 @@ class _CardPinSetScreen extends State<CardPinSetScreen> {
Navigator.pop(context); Navigator.pop(context);
}, },
), ),
title: const Text( title: Text(
'Card PIN', AppLocalizations.of(context).cardPin,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500), style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
), ),
centerTitle: false, centerTitle: false,
@@ -82,8 +82,8 @@ class _CardPinSetScreen extends State<CardPinSetScreen> {
TextFormField( TextFormField(
controller: _pinController, controller: _pinController,
obscureText: true, obscureText: true,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Enter new PIN', labelText: AppLocalizations.of(context).enterNewPin,
border: OutlineInputBorder(), border: OutlineInputBorder(),
isDense: true, isDense: true,
filled: true, filled: true,
@@ -99,10 +99,10 @@ class _CardPinSetScreen extends State<CardPinSetScreen> {
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Please enter new PIN'; return AppLocalizations.of(context).pleaseEnterNewPin;
} }
if (value.length < 4) { if (value.length < 4) {
return 'PIN must be at least 4 digits'; return AppLocalizations.of(context).pin4Digits;
} }
return null; return null;
}, },
@@ -111,8 +111,8 @@ class _CardPinSetScreen extends State<CardPinSetScreen> {
TextFormField( TextFormField(
controller: _confirmPinController, controller: _confirmPinController,
obscureText: true, obscureText: true,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Enter Again', labelText: AppLocalizations.of(context).enterAgain,
border: OutlineInputBorder(), border: OutlineInputBorder(),
isDense: true, isDense: true,
filled: true, filled: true,
@@ -128,7 +128,7 @@ class _CardPinSetScreen extends State<CardPinSetScreen> {
textInputAction: TextInputAction.done, textInputAction: TextInputAction.done,
validator: (value) { validator: (value) {
if (value != _pinController.text) { if (value != _pinController.text) {
return 'PINs do not match'; return AppLocalizations.of(context).pinsDoNotMatch;
} }
return null; return null;
}, },
@@ -146,7 +146,7 @@ class _CardPinSetScreen extends State<CardPinSetScreen> {
backgroundColor: Colors.blue[900], backgroundColor: Colors.blue[900],
foregroundColor: Colors.white, foregroundColor: Colors.white,
), ),
child: const Text('Submit'), child: Text(AppLocalizations.of(context).submit),
), ),
), ),
), ),

View File

@@ -22,8 +22,8 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
Navigator.pop(context); Navigator.pop(context);
}, },
), ),
title: const Text( title: Text(
'Cheque Management', AppLocalizations.of(context).chequeManagement,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500), style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
), ),
centerTitle: false, centerTitle: false,
@@ -48,7 +48,7 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
const SizedBox(height: 15), const SizedBox(height: 15),
ChequeManagementTile( ChequeManagementTile(
icon: Symbols.add, icon: Symbols.add,
label: 'Request Checkbook', label: AppLocalizations.of(context).requestChequeBook,
onTap: () {}, onTap: () {},
), ),
const Divider( const Divider(
@@ -56,7 +56,7 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
), ),
ChequeManagementTile( ChequeManagementTile(
icon: Symbols.data_alert, icon: Symbols.data_alert,
label: 'Enquiry', label: AppLocalizations.of(context).enquiry,
onTap: () { onTap: () {
Navigator.push( Navigator.push(
context, context,
@@ -69,7 +69,7 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
), ),
ChequeManagementTile( ChequeManagementTile(
icon: Symbols.approval_delegation, icon: Symbols.approval_delegation,
label: 'Cheque Deposit', label: AppLocalizations.of(context).chequeDeposit,
onTap: () {}, onTap: () {},
), ),
const Divider( const Divider(
@@ -77,7 +77,7 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
), ),
ChequeManagementTile( ChequeManagementTile(
icon: Symbols.front_hand, icon: Symbols.front_hand,
label: 'Stop Cheque', label: AppLocalizations.of(context).stopCheque,
onTap: () {}, onTap: () {},
), ),
const Divider( const Divider(
@@ -85,7 +85,7 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
), ),
ChequeManagementTile( ChequeManagementTile(
icon: Symbols.cancel_presentation, icon: Symbols.cancel_presentation,
label: 'Revoke Stop', label: AppLocalizations.of(context).revokeStop,
onTap: () {}, onTap: () {},
), ),
const Divider( const Divider(
@@ -93,7 +93,7 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
), ),
ChequeManagementTile( ChequeManagementTile(
icon: Symbols.payments, icon: Symbols.payments,
label: 'Positive Pay', label: AppLocalizations.of(context).positivePay,
onTap: () {}, onTap: () {},
), ),
const Divider( const Divider(

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../accounts/models/account.dart'; import '../../accounts/models/account.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class AccountCard extends StatelessWidget { class AccountCard extends StatelessWidget {
final Account account; final Account account;
@@ -73,8 +74,8 @@ class AccountCard extends StatelessWidget {
), ),
), ),
const SizedBox(height: 5), const SizedBox(height: 5),
const Text( Text(
'Available Balance', AppLocalizations.of(context).availableBalance,
style: TextStyle( style: TextStyle(
color: Colors.white70, color: Colors.white70,
fontSize: 12, fontSize: 12,

View File

@@ -22,7 +22,7 @@ class _FundTransferScreen extends State<FundTransferScreen> {
} }
} else if (key == 'done') { } else if (key == 'done') {
if (kDebugMode) { if (kDebugMode) {
print('Amount entered: $amount'); print('${AppLocalizations.of(context).amountEntered} $amount');
// Navigator.push( // Navigator.push(
// context, // context,
// MaterialPageRoute( // MaterialPageRoute(

View File

@@ -7,6 +7,7 @@ import 'package:kmobile/data/models/payment_response.dart';
import 'package:lottie/lottie.dart'; import 'package:lottie/lottie.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class PaymentAnimationScreen extends StatefulWidget { class PaymentAnimationScreen extends StatefulWidget {
final Future<PaymentResponse> paymentResponse; final Future<PaymentResponse> paymentResponse;
@@ -36,11 +37,14 @@ class _PaymentAnimationScreenState extends State<PaymentAnimationScreen> {
final file = await File('${tempDir.path}/payment_result.png').create(); final file = await File('${tempDir.path}/payment_result.png').create();
await file.writeAsBytes(pngBytes); 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) { } catch (e) {
if (!mounted) return; if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar( 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 isSuccess
? Column( ? Column(
children: [ children: [
const Text( Text(
'Payment Successful!', AppLocalizations.of(context)
.paymentSuccessful,
style: TextStyle( style: TextStyle(
fontSize: 22, fontSize: 22,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -98,7 +103,7 @@ class _PaymentAnimationScreenState extends State<PaymentAnimationScreen> {
const SizedBox(height: 16), const SizedBox(height: 16),
if (response.amount != null) if (response.amount != null)
Text( Text(
'Amount: ${response.amount} ${response.currency ?? ''}', '${AppLocalizations.of(context).amount}: ${response.amount} ${response.currency ?? ''}',
style: const TextStyle( style: const TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
@@ -106,7 +111,7 @@ class _PaymentAnimationScreenState extends State<PaymentAnimationScreen> {
), ),
if (response.creditedAccount != null) if (response.creditedAccount != null)
Text( Text(
'Credited Account: ${response.creditedAccount}', '${AppLocalizations.of(context).creditedAccount}: ${response.creditedAccount}',
style: const TextStyle( style: const TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@@ -121,8 +126,8 @@ class _PaymentAnimationScreenState extends State<PaymentAnimationScreen> {
) )
: Column( : Column(
children: [ children: [
const Text( Text(
'Payment Failed', AppLocalizations.of(context).paymentFailed,
style: TextStyle( style: TextStyle(
fontSize: 22, fontSize: 22,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -156,7 +161,7 @@ class _PaymentAnimationScreenState extends State<PaymentAnimationScreen> {
Icons.share_rounded, Icons.share_rounded,
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
), ),
label: Text('Share', label: Text(AppLocalizations.of(context).share,
style: style:
TextStyle(color: Theme.of(context).primaryColor)), TextStyle(color: Theme.of(context).primaryColor)),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
@@ -182,7 +187,7 @@ class _PaymentAnimationScreenState extends State<PaymentAnimationScreen> {
Navigator.of(context) Navigator.of(context)
.popUntil((route) => route.isFirst); .popUntil((route) => route.isFirst);
}, },
label: const Text('Done'), label: Text(AppLocalizations.of(context).done),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 45, vertical: 12), horizontal: 45, vertical: 12),

View File

@@ -1,3 +1,5 @@
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kmobile/features/fund_transfer/screens/tpin_set_screen.dart'; import 'package:kmobile/features/fund_transfer/screens/tpin_set_screen.dart';
@@ -46,7 +48,7 @@ class _TpinOtpScreenState extends State<TpinOtpScreen> {
); );
} else { } else {
ScaffoldMessenger.of(context).showSnackBar( 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); final theme = Theme.of(context);
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('Enter OTP'), title: Text(AppLocalizations.of(context).enterOtp),
centerTitle: true, centerTitle: true,
elevation: 0, elevation: 0,
), ),
@@ -69,7 +71,7 @@ class _TpinOtpScreenState extends State<TpinOtpScreen> {
size: 48, color: theme.colorScheme.primary), size: 48, color: theme.colorScheme.primary),
const SizedBox(height: 16), const SizedBox(height: 16),
Text( Text(
'OTP Verification', AppLocalizations.of(context).otpVerification,
style: theme.textTheme.titleLarge?.copyWith( style: theme.textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: theme.colorScheme.primary, color: theme.colorScheme.primary,
@@ -77,7 +79,7 @@ class _TpinOtpScreenState extends State<TpinOtpScreen> {
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Text( Text(
'Enter the 4-digit OTP sent to your mobile number.', AppLocalizations.of(context).otpSentMessage,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: theme.textTheme.bodyMedium?.copyWith( style: theme.textTheme.bodyMedium?.copyWith(
color: Colors.grey[700], color: Colors.grey[700],
@@ -125,8 +127,8 @@ class _TpinOtpScreenState extends State<TpinOtpScreen> {
const SizedBox(height: 32), const SizedBox(height: 32),
ElevatedButton.icon( ElevatedButton.icon(
icon: const Icon(Icons.verified_user_rounded), icon: const Icon(Icons.verified_user_rounded),
label: const Text( label: Text(
'Verify OTP', AppLocalizations.of(context).verifyOtp,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
), ),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
@@ -144,10 +146,11 @@ class _TpinOtpScreenState extends State<TpinOtpScreen> {
onPressed: () { onPressed: () {
// Resend OTP logic here // Resend OTP logic here
ScaffoldMessenger.of(context).showSnackBar( 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), const SizedBox(height: 60),
], ],

View File

@@ -1,3 +1,5 @@
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kmobile/features/fund_transfer/screens/tpin_otp_screen.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); final theme = Theme.of(context);
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('Set TPIN'), title: Text(AppLocalizations.of(context).setTpin),
), ),
body: Padding( body: Padding(
padding: const EdgeInsets.symmetric(vertical: 100.0), padding: const EdgeInsets.symmetric(vertical: 100.0),
@@ -20,7 +22,7 @@ class TpinSetupPromptScreen extends StatelessWidget {
size: 60, color: theme.colorScheme.primary), size: 60, color: theme.colorScheme.primary),
const SizedBox(height: 18), const SizedBox(height: 18),
Text( Text(
'TPIN Required', AppLocalizations.of(context).tpinRequired,
style: theme.textTheme.titleLarge?.copyWith( style: theme.textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: theme.colorScheme.primary, color: theme.colorScheme.primary,
@@ -28,7 +30,7 @@ class TpinSetupPromptScreen extends StatelessWidget {
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
Text( Text(
'You need to set your TPIN to continue with secure transactions.', AppLocalizations.of(context).tpinRequiredMessage,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: theme.textTheme.bodyMedium?.copyWith( style: theme.textTheme.bodyMedium?.copyWith(
color: Colors.grey[700], color: Colors.grey[700],
@@ -37,8 +39,8 @@ class TpinSetupPromptScreen extends StatelessWidget {
const SizedBox(height: 32), const SizedBox(height: 32),
ElevatedButton.icon( ElevatedButton.icon(
icon: const Icon(Icons.arrow_forward_rounded), icon: const Icon(Icons.arrow_forward_rounded),
label: const Text( label: Text(
'Set TPIN', AppLocalizations.of(context).setTpin,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
), ),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
@@ -62,7 +64,7 @@ class TpinSetupPromptScreen extends StatelessWidget {
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 18.0), padding: const EdgeInsets.symmetric(horizontal: 18.0),
child: Text( 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, textAlign: TextAlign.center,
style: theme.textTheme.bodySmall?.copyWith( style: theme.textTheme.bodySmall?.copyWith(
color: Colors.grey[600], color: Colors.grey[600],

View File

@@ -1,3 +1,5 @@
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kmobile/api/services/auth_service.dart'; import 'package:kmobile/api/services/auth_service.dart';
import 'package:kmobile/di/injection.dart'; import 'package:kmobile/di/injection.dart';
@@ -53,7 +55,7 @@ class _TpinSetScreenState extends State<TpinSetScreen> {
await authService.setTpin(pin); await authService.setTpin(pin);
} catch (e) { } catch (e) {
setState(() { setState(() {
_errorText = "Failed to set TPIN. Please try again."; _errorText = "${AppLocalizations.of(context).tpinFailed}";
_tpin.clear(); _tpin.clear();
}); });
return; return;
@@ -66,15 +68,16 @@ class _TpinSetScreenState extends State<TpinSetScreen> {
builder: (ctx) => AlertDialog( builder: (ctx) => AlertDialog(
shape: shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(18)), RoundedRectangleBorder(borderRadius: BorderRadius.circular(18)),
title: const Column( title: Column(
children: [ children: [
Icon(Icons.check_circle, color: Colors.green, size: 60), Icon(Icons.check_circle, color: Colors.green, size: 60),
SizedBox(height: 12), SizedBox(height: 12),
Text('Success!', style: TextStyle(fontWeight: FontWeight.bold)), Text(AppLocalizations.of(context).success,
style: TextStyle(fontWeight: FontWeight.bold)),
], ],
), ),
content: const Text( content: Text(
'Your TPIN was set up successfully.', AppLocalizations.of(context).tpinSetSuccess,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
actions: [ actions: [
@@ -82,7 +85,8 @@ class _TpinSetScreenState extends State<TpinSetScreen> {
onPressed: () { onPressed: () {
Navigator.of(ctx).pop(); 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 { } else {
setState(() { setState(() {
_errorText = "Pins do not match. Try again."; _errorText = AppLocalizations.of(context).pinsMismatchRetry;
_tpin.clear(); _tpin.clear();
}); });
} }
@@ -140,7 +144,8 @@ class _TpinSetScreenState extends State<TpinSetScreen> {
_handleComplete(); _handleComplete();
} else { } else {
setState(() { setState(() {
_errorText = "Please enter 6 digits"; _errorText =
AppLocalizations.of(context).pleaseEnter6Digits;
}); });
} }
} else if (key.isNotEmpty) { } else if (key.isNotEmpty) {
@@ -176,16 +181,16 @@ class _TpinSetScreenState extends State<TpinSetScreen> {
String getTitle() { String getTitle() {
switch (_mode) { switch (_mode) {
case TPinMode.set: case TPinMode.set:
return "Set your new TPIN"; return AppLocalizations.of(context).setNewTpin;
case TPinMode.confirm: case TPinMode.confirm:
return "Confirm your new TPIN"; return AppLocalizations.of(context).confirmNewTpin;
} }
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar(title: const Text('Set TPIN')), appBar: AppBar(title: Text(AppLocalizations.of(context).setTpin)),
body: SafeArea( body: SafeArea(
child: Column( child: Column(
children: [ children: [

View File

@@ -1,3 +1,5 @@
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kmobile/api/services/auth_service.dart'; import 'package:kmobile/api/services/auth_service.dart';
import 'package:kmobile/api/services/payment_service.dart'; import 'package:kmobile/api/services/payment_service.dart';
@@ -45,7 +47,8 @@ class _TransactionPinScreen extends State<TransactionPinScreen> {
if (mounted) { if (mounted) {
setState(() => _loading = false); setState(() => _loading = false);
ScaffoldMessenger.of(context).showSnackBar( 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(); await sendTransaction();
} else { } else {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Please enter a 6-digit TPIN")), SnackBar(
content:
Text(AppLocalizations.of(context).enter6DigitTpin)),
); );
} }
} else { } else {
@@ -131,12 +136,13 @@ class _TransactionPinScreen extends State<TransactionPinScreen> {
final transfer = widget.transactionData; final transfer = widget.transactionData;
transfer.tpin = _pin.join(); transfer.tpin = _pin.join();
try { try {
final paymentResponse = paymentService.processQuickPayWithinBank(transfer); final paymentResponse =
paymentService.processQuickPayWithinBank(transfer);
Navigator.of(context).pushReplacement( Navigator.of(context).pushReplacement(
MaterialPageRoute( MaterialPageRoute(
builder: (_) => PaymentAnimationScreen(paymentResponse: paymentResponse) builder: (_) =>
), PaymentAnimationScreen(paymentResponse: paymentResponse)),
); );
} catch (e) { } catch (e) {
if (mounted) { if (mounted) {
@@ -157,8 +163,8 @@ class _TransactionPinScreen extends State<TransactionPinScreen> {
Navigator.pop(context); Navigator.pop(context);
}, },
), ),
title: const Text( title: Text(
'TPIN', AppLocalizations.of(context).tpin,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500), style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
), ),
centerTitle: false, centerTitle: false,
@@ -168,8 +174,8 @@ class _TransactionPinScreen extends State<TransactionPinScreen> {
child: Column( child: Column(
children: [ children: [
const Spacer(), const Spacer(),
const Text( Text(
'Enter Your TPIN', AppLocalizations.of(context).enterTpin,
style: TextStyle(fontSize: 18), style: TextStyle(fontSize: 18),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),

View File

@@ -1,3 +1,5 @@
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'dart:io'; import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -57,8 +59,8 @@ class _TransactionSuccessScreen extends State<TransactionSuccessScreen> {
), ),
), ),
const SizedBox(height: 24), const SizedBox(height: 24),
const Text( Text(
"Transaction Successful", AppLocalizations.of(context).transactionSuccess,
style: TextStyle( style: TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@@ -76,7 +78,7 @@ class _TransactionSuccessScreen extends State<TransactionSuccessScreen> {
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
Text( Text(
"To Account Number: $creditAccount", "${AppLocalizations.of(context).toAccountNumber}: $creditAccount",
style: const TextStyle( style: const TextStyle(
fontSize: 12, fontSize: 12,
color: Colors.black87, color: Colors.black87,
@@ -98,7 +100,7 @@ class _TransactionSuccessScreen extends State<TransactionSuccessScreen> {
child: OutlinedButton.icon( child: OutlinedButton.icon(
onPressed: _shareScreenshot, onPressed: _shareScreenshot,
icon: const Icon(Icons.share, size: 18), icon: const Icon(Icons.share, size: 18),
label: const Text("Share"), label: Text(AppLocalizations.of(context).share),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
shape: const StadiumBorder(), shape: const StadiumBorder(),
padding: const EdgeInsets.symmetric(vertical: 16), padding: const EdgeInsets.symmetric(vertical: 16),
@@ -126,7 +128,7 @@ class _TransactionSuccessScreen extends State<TransactionSuccessScreen> {
backgroundColor: Colors.blue[900], backgroundColor: Colors.blue[900],
foregroundColor: Colors.white, foregroundColor: Colors.white,
), ),
child: const Text("Done"), child: Text(AppLocalizations.of(context).done),
), ),
), ),
], ],

View File

@@ -1,9 +1,10 @@
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:flutter_swipe_button/flutter_swipe_button.dart'; import 'package:flutter_swipe_button/flutter_swipe_button.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart'; import 'package:material_symbols_icons/material_symbols_icons.dart';
class QuickPayOutsideBankScreen extends StatefulWidget { class QuickPayOutsideBankScreen extends StatefulWidget {
final String debitAccount; final String debitAccount;
const QuickPayOutsideBankScreen({super.key, required this.debitAccount}); const QuickPayOutsideBankScreen({super.key, required this.debitAccount});
@@ -26,8 +27,28 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
final phoneController = TextEditingController(); final phoneController = TextEditingController();
final amountController = TextEditingController(); final amountController = TextEditingController();
String accountType = 'Savings'; //String accountType = 'Savings';
final List<String> transactionModes = ['NEFT', 'RTGS', 'IMPS']; 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; int selectedTransactionIndex = 0;
@override @override
@@ -54,8 +75,8 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
Navigator.pop(context); Navigator.pop(context);
}, },
), ),
title: const Text( title: Text(
'Quick Pay - Outside Bank', AppLocalizations.of(context).quickPayOutsideBank,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500), style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
), ),
centerTitle: false, centerTitle: false,
@@ -84,17 +105,18 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
const SizedBox(height: 10), const SizedBox(height: 10),
Row( Row(
children: [ children: [
const Text('Debit from:'), Text(AppLocalizations.of(context).debitFrom),
Text( Text(
widget.debitAccount, widget.debitAccount,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500), style: const TextStyle(
fontSize: 18, fontWeight: FontWeight.w500),
) )
], ],
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
TextFormField( TextFormField(
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Account Number', labelText: AppLocalizations.of(context).accountNumber,
border: OutlineInputBorder(), border: OutlineInputBorder(),
isDense: true, isDense: true,
filled: true, filled: true,
@@ -112,9 +134,9 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Account number is required'; return AppLocalizations.of(context).accountNumberRequired;
} else if (value.length != 11) { } else if (value.length != 11) {
return 'Enter a valid account number'; return AppLocalizations.of(context).validAccountNumber;
} }
return null; return null;
}, },
@@ -122,8 +144,8 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
const SizedBox(height: 24), const SizedBox(height: 24),
TextFormField( TextFormField(
controller: confirmAccountNumberController, controller: confirmAccountNumberController,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Confirm Account Number', labelText: AppLocalizations.of(context).confirmAccountNumber,
// prefixIcon: Icon(Icons.person), // prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(), border: OutlineInputBorder(),
isDense: true, isDense: true,
@@ -140,18 +162,18 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Re-enter account number'; return AppLocalizations.of(context).reenterAccountNumber;
} }
if (value != accountNumberController.text) { if (value != accountNumberController.text) {
return 'Account numbers do not match'; return AppLocalizations.of(context).accountMismatch;
} }
return null; return null;
}, },
), ),
const SizedBox(height: 25), const SizedBox(height: 25),
TextFormField( TextFormField(
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Name', labelText: AppLocalizations.of(context).name,
border: OutlineInputBorder(), border: OutlineInputBorder(),
isDense: true, isDense: true,
filled: true, filled: true,
@@ -168,15 +190,15 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Name is required'; return AppLocalizations.of(context).nameRequired;
} }
return null; return null;
}, },
), ),
const SizedBox(height: 25), const SizedBox(height: 25),
TextFormField( TextFormField(
decoration: const InputDecoration( decoration: InputDecoration(
labelText: "Beneficiary Bank Name", labelText: AppLocalizations.of(context).bankName,
border: OutlineInputBorder(), border: OutlineInputBorder(),
isDense: true, isDense: true,
filled: true, filled: true,
@@ -192,15 +214,15 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Beneficiary Bank Name is required'; return AppLocalizations.of(context).bankNameRequired;
} }
return null; return null;
}, },
), ),
const SizedBox(height: 25), const SizedBox(height: 25),
TextFormField( TextFormField(
decoration: const InputDecoration( decoration: InputDecoration(
labelText: "Branch Name", labelText: AppLocalizations.of(context).branchName,
border: OutlineInputBorder(), border: OutlineInputBorder(),
isDense: true, isDense: true,
filled: true, filled: true,
@@ -216,7 +238,7 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Branch Name is required'; return AppLocalizations.of(context).branchNameRequired;
} }
return null; return null;
}, },
@@ -226,8 +248,8 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
children: [ children: [
Expanded( Expanded(
child: TextFormField( child: TextFormField(
decoration: const InputDecoration( decoration: InputDecoration(
labelText: "IFSC Code", labelText: AppLocalizations.of(context).ifscCode,
border: OutlineInputBorder(), border: OutlineInputBorder(),
isDense: true, isDense: true,
filled: true, filled: true,
@@ -243,7 +265,7 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'IFSC Code is required'; return AppLocalizations.of(context).ifscRequired;
} }
return null; return null;
}, },
@@ -252,8 +274,8 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
Expanded( Expanded(
child: DropdownButtonFormField<String>( child: DropdownButtonFormField<String>(
value: accountType, value: accountType,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: "Account Type", labelText: AppLocalizations.of(context).accountType,
border: OutlineInputBorder(), border: OutlineInputBorder(),
isDense: true, isDense: true,
filled: true, filled: true,
@@ -265,7 +287,10 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
borderSide: BorderSide(color: Colors.black, width: 2), borderSide: BorderSide(color: Colors.black, width: 2),
), ),
), ),
items: ['Savings', 'Current'] items: [
AppLocalizations.of(context).savings,
AppLocalizations.of(context).current
]
.map((e) => DropdownMenuItem( .map((e) => DropdownMenuItem(
value: e, value: e,
child: Text(e), child: Text(e),
@@ -285,8 +310,8 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
child: TextFormField( child: TextFormField(
controller: phoneController, controller: phoneController,
keyboardType: TextInputType.phone, keyboardType: TextInputType.phone,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: "Phone", labelText: AppLocalizations.of(context).phone,
prefixIcon: Icon(Icons.phone), prefixIcon: Icon(Icons.phone),
border: OutlineInputBorder(), border: OutlineInputBorder(),
isDense: true, isDense: true,
@@ -301,15 +326,15 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
), ),
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (value) => value == null || value.isEmpty validator: (value) => value == null || value.isEmpty
? "Phone number is Required" ? AppLocalizations.of(context).phoneRequired
: null, : null,
), ),
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
Expanded( Expanded(
child: TextFormField( child: TextFormField(
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Amount', labelText: AppLocalizations.of(context).amount,
border: OutlineInputBorder(), border: OutlineInputBorder(),
isDense: true, isDense: true,
filled: true, filled: true,
@@ -326,11 +351,11 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Amount is required'; return AppLocalizations.of(context).amountRequired;
} }
final amount = double.tryParse(value); final amount = double.tryParse(value);
if (amount == null || amount <= 0) { if (amount == null || amount <= 0) {
return 'Enter a valid amount'; return AppLocalizations.of(context).validAmount;
} }
return null; return null;
}, },
@@ -341,7 +366,7 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
const SizedBox(height: 30), const SizedBox(height: 30),
Row( Row(
children: [ children: [
const Text("Transaction Mode", Text(AppLocalizations.of(context).transactionMode,
style: TextStyle(fontWeight: FontWeight.w500)), style: TextStyle(fontWeight: FontWeight.w500)),
const SizedBox(width: 12), const SizedBox(width: 12),
Expanded(child: buildTransactionModeSelector()), Expanded(child: buildTransactionModeSelector()),
@@ -359,8 +384,8 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
activeTrackColor: Colors.blue.shade100, activeTrackColor: Colors.blue.shade100,
borderRadius: BorderRadius.circular(30), borderRadius: BorderRadius.circular(30),
height: 56, height: 56,
child: const Text( child: Text(
"Swipe to Pay", AppLocalizations.of(context).swipeToPay,
style: style:
TextStyle(fontSize: 16, fontWeight: FontWeight.bold), TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
), ),
@@ -368,10 +393,11 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
if (_formKey.currentState!.validate()) { if (_formKey.currentState!.validate()) {
// Perform payment logic // Perform payment logic
final selectedMode = final selectedMode =
transactionModes[selectedTransactionIndex]; transactionModes(context)[selectedTransactionIndex];
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text('Paying via $selectedMode...')), content: Text(
'${AppLocalizations.of(context).payingVia} $selectedMode...')),
); );
// Navigator.push( // Navigator.push(
// context, // context,
@@ -395,7 +421,7 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
return Container( return Container(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
child: Row( child: Row(
children: List.generate(transactionModes.length, (index) { children: List.generate(transactionModes(context).length, (index) {
bool isSelected = selectedTransactionIndex == index; bool isSelected = selectedTransactionIndex == index;
return Expanded( return Expanded(
child: GestureDetector( child: GestureDetector(
@@ -415,7 +441,7 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
), ),
alignment: Alignment.center, alignment: Alignment.center,
child: Text( child: Text(
transactionModes[index], transactionModes(context)[index],
style: const TextStyle( style: const TextStyle(
color: Colors.black, color: Colors.black,
), ),

View File

@@ -1,3 +1,5 @@
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart'; import 'package:material_symbols_icons/material_symbols_icons.dart';
@@ -14,8 +16,10 @@ class _ServiceScreen extends State<ServiceScreen>{
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
title: const Text('Services', style: TextStyle(color: Colors.black, title: Text(
fontWeight: FontWeight.w500),), AppLocalizations.of(context).services,
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500),
),
centerTitle: false, centerTitle: false,
actions: [ actions: [
// IconButton( // IconButton(
@@ -33,56 +37,48 @@ class _ServiceScreen extends State<ServiceScreen>{
// builder: (context) => const CustomerInfoScreen())); // builder: (context) => const CustomerInfoScreen()));
}, },
child: const CircleAvatar( 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, radius: 20,
), ),
), ),
), ),
], ],
), ),
body: ListView( body: ListView(
children: [ children: [
ServiceManagementTile( ServiceManagementTile(
icon: Symbols.add, icon: Symbols.add,
label: 'Account Opening Request - Deposit', label: AppLocalizations.of(context).accountOpeningDeposit,
onTap: () { onTap: () {},
),
}, const Divider(
height: 1,
), ),
const Divider(height: 1,),
ServiceManagementTile( ServiceManagementTile(
icon: Symbols.add, icon: Symbols.add,
label: 'Account Opening Request - Loan', label: AppLocalizations.of(context).accountOpeningLoan,
onTap: () { onTap: () {},
),
}, const Divider(
height: 1,
), ),
const Divider(height: 1,),
ServiceManagementTile( ServiceManagementTile(
icon: Symbols.captive_portal, icon: Symbols.captive_portal,
label: 'Quick Links', label: AppLocalizations.of(context).quickLinks,
onTap: () { onTap: () {},
),
}, const Divider(
height: 1,
), ),
const Divider(height: 1,),
ServiceManagementTile( ServiceManagementTile(
icon: Symbols.missing_controller, icon: Symbols.missing_controller,
label: 'Branch Locator', label: AppLocalizations.of(context).branchLocator,
onTap: () { onTap: () {},
},
), ),
const Divider(
const Divider(height: 1,) height: 1,
)
], ],
), ),
); );

View File

@@ -194,6 +194,31 @@
"transactionSuccess": "Transaction Successful", "transactionSuccess": "Transaction Successful",
"on": "On", "on": "On",
"toAccountNumber": "To Account Number", "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"
} }

View File

@@ -194,5 +194,30 @@
"transactionSuccess": "लेन-देन सफल रहा", "transactionSuccess": "लेन-देन सफल रहा",
"on": "पर", "on": "पर",
"toAccountNumber": "खाते संख्या में", "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": "कांगड़ा सेंट्रल को-ऑपरेटिव बैंक"
} }