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/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),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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,
|
||||||
|
@@ -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,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@@ -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,
|
||||||
|
@@ -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(
|
||||||
|
@@ -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),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@@ -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(
|
||||||
|
@@ -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,
|
||||||
|
@@ -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(
|
||||||
|
@@ -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),
|
||||||
|
@@ -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),
|
||||||
],
|
],
|
||||||
|
@@ -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],
|
||||||
|
@@ -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: [
|
||||||
|
@@ -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,28 +163,28 @@ 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,
|
||||||
),
|
),
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 20.0),
|
padding: const EdgeInsets.only(bottom: 20.0),
|
||||||
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),
|
|
||||||
_buildPinIndicators(),
|
|
||||||
const Spacer(),
|
|
||||||
_buildKeypad(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
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: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),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@@ -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,
|
||||||
),
|
),
|
||||||
|
@@ -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';
|
||||||
|
|
||||||
@@ -8,14 +10,16 @@ class ServiceScreen extends StatefulWidget {
|
|||||||
State<ServiceScreen> createState() => _ServiceScreen();
|
State<ServiceScreen> createState() => _ServiceScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ServiceScreen extends State<ServiceScreen>{
|
class _ServiceScreen extends State<ServiceScreen> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
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(
|
||||||
@@ -28,61 +32,53 @@ class _ServiceScreen extends State<ServiceScreen>{
|
|||||||
padding: const EdgeInsets.only(right: 10.0),
|
padding: const EdgeInsets.only(right: 10.0),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
onTap: (){
|
onTap: () {
|
||||||
// Navigator.push(context, MaterialPageRoute(
|
// Navigator.push(context, MaterialPageRoute(
|
||||||
// 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,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@@ -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"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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": "कांगड़ा सेंट्रल को-ऑपरेटिव बैंक"
|
||||||
}
|
}
|
Reference in New Issue
Block a user