dart format

This commit is contained in:
2025-11-10 16:50:29 +05:30
parent d6f61ebb31
commit 8cfca113bf
28 changed files with 1995 additions and 1973 deletions

View File

@@ -142,7 +142,7 @@ class AuthService {
return; return;
} }
Future setTncflag() async{ Future setTncflag() async {
try { try {
final response = await _dio.post( final response = await _dio.post(
'/api/auth/tnc', '/api/auth/tnc',
@@ -151,15 +151,13 @@ class AuthService {
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw AuthException('Failed to proceed with T&C'); throw AuthException('Failed to proceed with T&C');
} }
} } on DioException catch (e) {
on DioException catch (e) {
if (kDebugMode) { if (kDebugMode) {
print(e.toString()); print(e.toString());
} }
throw NetworkException('Network error during T&C Setup'); throw NetworkException('Network error during T&C Setup');
} catch (e) { } catch (e) {
throw UnexpectedException( throw UnexpectedException('Unexpected error: ${e.toString()}');
'Unexpected error: ${e.toString()}');
} }
} }
} }

View File

@@ -39,7 +39,7 @@ class LimitService {
} }
} }
void editLimit( double newLimit) async { void editLimit(double newLimit) async {
try { try {
final response = await _dio.post('/api/customer/daily-limit', final response = await _dio.post('/api/customer/daily-limit',
data: '{"amount": $newLimit}'); data: '{"amount": $newLimit}');

View File

@@ -10,7 +10,7 @@ import '../features/dashboard/screens/dashboard_screen.dart';
// import '../features/transactions/screens/transactions_screen.dart'; // import '../features/transactions/screens/transactions_screen.dart';
// import '../features/payments/screens/payments_screen.dart'; // import '../features/payments/screens/payments_screen.dart';
// import '../features/settings/screens/settings_screen.dart'; // import '../features/settings/screens/settings_screen.dart';
import 'package:kmobile/features/auth/screens/tnc_required_screen.dart'; import 'package:kmobile/features/auth/screens/tnc_required_screen.dart';
class AppRoutes { class AppRoutes {
// Private constructor to prevent instantiation // Private constructor to prevent instantiation
@@ -36,7 +36,8 @@ class AppRoutes {
case login: case login:
return MaterialPageRoute(builder: (_) => const LoginScreen()); return MaterialPageRoute(builder: (_) => const LoginScreen());
case TncRequiredScreen.routeName: // Renamed class case TncRequiredScreen.routeName: // Renamed class
return MaterialPageRoute(builder: (_) => const TncRequiredScreen()); // Renamed class return MaterialPageRoute(
builder: (_) => const TncRequiredScreen()); // Renamed class
case mPin: case mPin:
return MaterialPageRoute( return MaterialPageRoute(
builder: (_) => const MPinScreen( builder: (_) => const MPinScreen(

View File

@@ -25,7 +25,9 @@ class Beneficiary {
return Beneficiary( return Beneficiary(
accountNo: json['account_no'] ?? json['accountNo'] ?? '', accountNo: json['account_no'] ?? json['accountNo'] ?? '',
accountType: json['account_type'] ?? json['accountType'] ?? '', accountType: json['account_type'] ?? json['accountType'] ?? '',
createdAt: json['createdAt'] == null ? null : DateTime.tryParse(json['createdAt']), createdAt: json['createdAt'] == null
? null
: DateTime.tryParse(json['createdAt']),
name: json['name'] ?? '', name: json['name'] ?? '',
ifscCode: json['ifsc_code'] ?? json['ifscCode'] ?? '', ifscCode: json['ifsc_code'] ?? json['ifscCode'] ?? '',
bankName: json['bank_name'] ?? json['bankName'] ?? '', bankName: json['bank_name'] ?? json['bankName'] ?? '',

View File

@@ -17,7 +17,8 @@ class AuthRepository {
AuthRepository(this._authService, this._userService, this._secureStorage); AuthRepository(this._authService, this._userService, this._secureStorage);
Future<(List<User>, AuthToken)> login(String customerNo, String password) async { Future<(List<User>, AuthToken)> login(
String customerNo, String password) async {
// Create credentials and call service // Create credentials and call service
final credentials = final credentials =
AuthCredentials(customerNo: customerNo, password: password); AuthCredentials(customerNo: customerNo, password: password);
@@ -64,7 +65,8 @@ class AuthRepository {
final authToken = AuthToken( final authToken = AuthToken(
accessToken: accessToken, accessToken: accessToken,
expiresAt: DateTime.parse(expiryString), expiresAt: DateTime.parse(expiryString),
tnc: tncString == 'true', // Parse 'true' string to true, otherwise false tnc:
tncString == 'true', // Parse 'true' string to true, otherwise false
); );
return authToken; return authToken;
} }

View File

@@ -61,8 +61,8 @@ Future<void> setupDependencies() async {
); );
// Register controllers/cubits // Register controllers/cubits
getIt.registerFactory<AuthCubit>( getIt.registerFactory<AuthCubit>(() => AuthCubit(
() => AuthCubit(getIt<AuthRepository>(), getIt<UserService>(), getIt<SecureStorage>())); getIt<AuthRepository>(), getIt<UserService>(), getIt<SecureStorage>()));
} }
Dio _createDioClient() { Dio _createDioClient() {

View File

@@ -45,7 +45,8 @@ class AuthCubit extends Cubit<AuthState> {
Future<void> login(String customerNo, String password) async { Future<void> login(String customerNo, String password) async {
emit(AuthLoading()); emit(AuthLoading());
try { try {
final (users, authToken) = await _authRepository.login(customerNo, password); final (users, authToken) =
await _authRepository.login(customerNo, password);
if (authToken.tnc == false) { if (authToken.tnc == false) {
emit(ShowTncDialog(authToken, users)); emit(ShowTncDialog(authToken, users));
@@ -57,7 +58,6 @@ class AuthCubit extends Cubit<AuthState> {
} }
} }
Future<void> onTncDialogResult( Future<void> onTncDialogResult(
bool agreed, AuthToken authToken, List<User> users) async { bool agreed, AuthToken authToken, List<User> users) async {
if (agreed) { if (agreed) {
@@ -83,7 +83,6 @@ class AuthCubit extends Cubit<AuthState> {
} }
} }
Future<void> _checkMpinAndNavigate(List<User> users) async { Future<void> _checkMpinAndNavigate(List<User> users) async {
final mpin = await _secureStorage.read('mpin'); final mpin = await _secureStorage.read('mpin');
if (mpin == null) { if (mpin == null) {
@@ -94,5 +93,4 @@ class AuthCubit extends Cubit<AuthState> {
emit(Authenticated(users)); emit(Authenticated(users));
} }
} }
} }

View File

@@ -46,13 +46,13 @@ class ShowTncDialog extends AuthState {
// States to trigger specific navigations from the UI // States to trigger specific navigations from the UI
class NavigateToTncRequiredScreen extends AuthState {} class NavigateToTncRequiredScreen extends AuthState {}
class NavigateToMpinSetupScreen extends AuthState { class NavigateToMpinSetupScreen extends AuthState {
final List<User> users; final List<User> users;
const NavigateToMpinSetupScreen(this.users); const NavigateToMpinSetupScreen(this.users);
@override @override
List<Object> get props => [users]; List<Object> get props => [users];
} }
class NavigateToDashboardScreen extends AuthState {} class NavigateToDashboardScreen extends AuthState {}

View File

@@ -28,10 +28,11 @@ class AuthToken extends Equatable {
return AuthToken( return AuthToken(
accessToken: token, accessToken: token,
expiresAt: _decodeExpiryFromToken(token), // This method is still valid for JWT expiry expiresAt: _decodeExpiryFromToken(
token), // This method is still valid for JWT expiry
tnc: tncMobileValue, // Use the correctly extracted value tnc: tncMobileValue, // Use the correctly extracted value
); );
} }
static DateTime _decodeExpiryFromToken(String token) { static DateTime _decodeExpiryFromToken(String token) {
try { try {

View File

@@ -255,7 +255,8 @@ class LoginScreenState extends State<LoginScreen>
} else if (state is NavigateToTncRequiredScreen) { } else if (state is NavigateToTncRequiredScreen) {
Navigator.of(context).pushNamed(TncRequiredScreen.routeName); Navigator.of(context).pushNamed(TncRequiredScreen.routeName);
} else if (state is NavigateToMpinSetupScreen) { } else if (state is NavigateToMpinSetupScreen) {
Navigator.of(context).push( // Use push, NOT pushReplacement Navigator.of(context).push(
// Use push, NOT pushReplacement
MaterialPageRoute( MaterialPageRoute(
builder: (_) => MPinScreen( builder: (_) => MPinScreen(
mode: MPinMode.set, mode: MPinMode.set,

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class TncRequiredScreen extends StatelessWidget { // Renamed class class TncRequiredScreen extends StatelessWidget {
// Renamed class
const TncRequiredScreen({Key? key}) : super(key: key); const TncRequiredScreen({Key? key}) : super(key: key);
static const routeName = '/tnc-required'; static const routeName = '/tnc-required';
@@ -36,4 +37,4 @@
), ),
); );
} }
} }

View File

@@ -269,7 +269,9 @@ class _DashboardScreenState extends State<DashboardScreen>
final users = state.users; final users = state.users;
final currAccount = users[selectedAccountIndex]; final currAccount = users[selectedAccountIndex];
final accountType = currAccount.accountType?.toLowerCase(); final accountType = currAccount.accountType?.toLowerCase();
final isPaymentDisabled = accountType != 'sa' && accountType != 'sb' && accountType != 'ca'; final isPaymentDisabled = accountType != 'sa' &&
accountType != 'sb' &&
accountType != 'ca';
// firsttime load // firsttime load
if (!_txInitialized) { if (!_txInitialized) {
_txInitialized = true; _txInitialized = true;
@@ -509,8 +511,7 @@ class _DashboardScreenState extends State<DashboardScreen>
users[selectedAccountIndex] users[selectedAccountIndex]
.accountNo!, .accountNo!,
remitterName: remitterName:
users[selectedAccountIndex] users[selectedAccountIndex].name!,
.name!,
// Pass the full list of accounts // Pass the full list of accounts
accounts: users))); accounts: users)));
}, disable: isPaymentDisabled), }, disable: isPaymentDisabled),

View File

@@ -1,7 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class CooldownTimer extends StatefulWidget { class CooldownTimer extends StatefulWidget {
final DateTime createdAt; final DateTime createdAt;
final VoidCallback onTimerFinish; final VoidCallback onTimerFinish;
@@ -13,9 +13,9 @@
@override @override
_CooldownTimerState createState() => _CooldownTimerState(); _CooldownTimerState createState() => _CooldownTimerState();
} }
class _CooldownTimerState extends State<CooldownTimer> { class _CooldownTimerState extends State<CooldownTimer> {
late Timer _timer; late Timer _timer;
late Duration _timeRemaining; late Duration _timeRemaining;
@@ -62,7 +62,8 @@
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (_timeRemaining == Duration.zero) { if (_timeRemaining == Duration.zero) {
return const SizedBox.shrink(); // Or some other widget indicating it's enabled return const SizedBox
.shrink(); // Or some other widget indicating it's enabled
} }
return Column( return Column(
@@ -87,4 +88,4 @@
], ],
); );
} }
} }

View File

@@ -43,21 +43,22 @@ class FundTransferAmountScreen extends StatefulWidget {
class _FundTransferAmountScreenState extends State<FundTransferAmountScreen> { class _FundTransferAmountScreenState extends State<FundTransferAmountScreen> {
final _limitService = getIt<LimitService>(); final _limitService = getIt<LimitService>();
Limit? _limit; Limit? _limit;
bool _isLoadingLimit = true; bool _isLoadingLimit = true;
bool _isAmountOverLimit = false; bool _isAmountOverLimit = false;
final _formatCurrency = NumberFormat.currency(locale: 'en_IN', symbol: ''); final _formatCurrency = NumberFormat.currency(locale: 'en_IN', symbol: '');
final _amountController = TextEditingController(); final _amountController = TextEditingController();
final _remarksController = TextEditingController(); final _remarksController = TextEditingController();
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
TransactionMode _selectedMode = TransactionMode.neft; TransactionMode _selectedMode = TransactionMode.neft;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_loadLimit(); // Call the new method _loadLimit(); // Call the new method
_amountController.addListener(_checkAmountLimit); _amountController.addListener(_checkAmountLimit);
} }
Future<void> _loadLimit() async { Future<void> _loadLimit() async {
setState(() { setState(() {
_isLoadingLimit = true; _isLoadingLimit = true;
@@ -77,7 +78,7 @@ void initState() {
} }
// Add this method to check the amount against the limit // Add this method to check the amount against the limit
void _checkAmountLimit() { void _checkAmountLimit() {
if (_limit == null) return; if (_limit == null) return;
final amount = double.tryParse(_amountController.text) ?? 0; final amount = double.tryParse(_amountController.text) ?? 0;
@@ -87,7 +88,8 @@ void _checkAmountLimit() {
if (isOverLimit) { if (isOverLimit) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text('Amount exceeds remaining daily limit of ${_formatCurrency.format(remainingLimit)}'), content: Text(
'Amount exceeds remaining daily limit of ${_formatCurrency.format(remainingLimit)}'),
backgroundColor: Colors.red, backgroundColor: Colors.red,
), ),
); );
@@ -98,7 +100,7 @@ void _checkAmountLimit() {
_isAmountOverLimit = isOverLimit; _isAmountOverLimit = isOverLimit;
}); });
} }
} }
@override @override
void dispose() { void dispose() {
@@ -487,8 +489,7 @@ void _checkAmountLimit() {
}, },
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
if (_isLoadingLimit) if (_isLoadingLimit) const Text('Fetching daily limit...'),
const Text('Fetching daily limit...'),
if (!_isLoadingLimit && _limit != null) if (!_isLoadingLimit && _limit != null)
Text( Text(
'Remaining Daily Limit: ${_formatCurrency.format(_limit!.dailyLimit - _limit!.usedLimit)}', 'Remaining Daily Limit: ${_formatCurrency.format(_limit!.dailyLimit - _limit!.usedLimit)}',
@@ -506,7 +507,7 @@ void _checkAmountLimit() {
), ),
child: Text(AppLocalizations.of(context).proceed), child: Text(AppLocalizations.of(context).proceed),
), ),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
], ],
), ),

View File

@@ -73,7 +73,6 @@ class _FundTransferBeneficiaryScreenState
); );
} }
Widget _buildBeneficiaryList() { Widget _buildBeneficiaryList() {
if (_beneficiaries.isEmpty) { if (_beneficiaries.isEmpty) {
return Center( return Center(
@@ -155,7 +154,6 @@ class _FundTransferBeneficiaryScreenState
); );
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(

View File

@@ -1,14 +1,14 @@
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/data/models/user.dart'; import 'package:kmobile/data/models/user.dart';
import 'package:kmobile/features/auth/controllers/auth_cubit.dart'; import 'package:kmobile/features/auth/controllers/auth_cubit.dart';
import 'package:kmobile/features/auth/controllers/auth_state.dart'; import 'package:kmobile/features/auth/controllers/auth_state.dart';
import 'package:kmobile/features/fund_transfer/screens/fund_transfer_beneficiary_screen.dart'; import 'package:kmobile/features/fund_transfer/screens/fund_transfer_beneficiary_screen.dart';
import 'package:kmobile/features/fund_transfer/screens/fund_transfer_self_accounts_screen.dart'; import 'package:kmobile/features/fund_transfer/screens/fund_transfer_self_accounts_screen.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import '../../../l10n/app_localizations.dart'; // Keep localizations import '../../../l10n/app_localizations.dart'; // Keep localizations
class FundTransferScreen extends StatelessWidget { class FundTransferScreen extends StatelessWidget {
final String creditAccountNo; final String creditAccountNo;
final String remitterName; final String remitterName;
final List<User> accounts; // Continue to accept the list of accounts final List<User> accounts; // Continue to accept the list of accounts
@@ -97,9 +97,9 @@
), ),
); );
} }
} }
class FundTransferManagementTile extends StatelessWidget { class FundTransferManagementTile extends StatelessWidget {
final IconData icon; final IconData icon;
final String label; final String label;
final VoidCallback onTap; final VoidCallback onTap;
@@ -123,4 +123,4 @@
enabled: !disable, enabled: !disable,
); );
} }
} }

View File

@@ -1,9 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kmobile/data/models/user.dart'; import 'package:kmobile/data/models/user.dart';
import 'package:kmobile/features/fund_transfer/screens/fund_transfer_self_amount_screen.dart'; import 'package:kmobile/features/fund_transfer/screens/fund_transfer_self_amount_screen.dart';
import 'package:kmobile/widgets/bank_logos.dart'; import 'package:kmobile/widgets/bank_logos.dart';
class FundTransferSelfAccountsScreen extends StatelessWidget { class FundTransferSelfAccountsScreen extends StatelessWidget {
final String debitAccountNo; final String debitAccountNo;
final String remitterName; final String remitterName;
final List<User> accounts; final List<User> accounts;
@@ -57,8 +57,8 @@
leading: CircleAvatar( leading: CircleAvatar(
radius: 24, radius: 24,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
child: child: getBankLogo(
getBankLogo('Kangra Central Co-operative Bank', context), 'Kangra Central Co-operative Bank', context),
), ),
title: Text(account.name ?? 'N/A'), title: Text(account.name ?? 'N/A'),
subtitle: Column( subtitle: Column(
@@ -67,8 +67,7 @@
Text(account.accountNo ?? 'N/A'), Text(account.accountNo ?? 'N/A'),
Text( Text(
_getFullAccountType(account.accountType), _getFullAccountType(account.accountType),
style: style: TextStyle(fontSize: 12, color: Colors.grey[600]),
TextStyle(fontSize: 12, color: Colors.grey[600]),
), ),
], ],
), ),
@@ -91,4 +90,4 @@
), ),
); );
} }
} }

View File

@@ -1,15 +1,15 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:kmobile/api/services/limit_service.dart'; import 'package:kmobile/api/services/limit_service.dart';
import 'package:kmobile/api/services/payment_service.dart'; import 'package:kmobile/api/services/payment_service.dart';
import 'package:kmobile/data/models/transfer.dart'; import 'package:kmobile/data/models/transfer.dart';
import 'package:kmobile/data/models/user.dart'; import 'package:kmobile/data/models/user.dart';
import 'package:kmobile/di/injection.dart'; import 'package:kmobile/di/injection.dart';
import 'package:kmobile/features/fund_transfer/screens/payment_animation.dart'; import 'package:kmobile/features/fund_transfer/screens/payment_animation.dart';
import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart'; import 'package:kmobile/features/fund_transfer/screens/transaction_pin_screen.dart';
import 'package:kmobile/widgets/bank_logos.dart'; import 'package:kmobile/widgets/bank_logos.dart';
class FundTransferSelfAmountScreen extends StatefulWidget { class FundTransferSelfAmountScreen extends StatefulWidget {
final String debitAccountNo; final String debitAccountNo;
final User creditAccount; final User creditAccount;
final String remitterName; final String remitterName;
@@ -24,9 +24,9 @@ import 'package:kmobile/widgets/bank_logos.dart';
@override @override
State<FundTransferSelfAmountScreen> createState() => State<FundTransferSelfAmountScreen> createState() =>
_FundTransferSelfAmountScreenState(); _FundTransferSelfAmountScreenState();
} }
class _FundTransferSelfAmountScreenState class _FundTransferSelfAmountScreenState
extends State<FundTransferSelfAmountScreen> { extends State<FundTransferSelfAmountScreen> {
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final _amountController = TextEditingController(); final _amountController = TextEditingController();
@@ -39,12 +39,12 @@ import 'package:kmobile/widgets/bank_logos.dart';
bool _isAmountOverLimit = false; bool _isAmountOverLimit = false;
final _formatCurrency = NumberFormat.currency(locale: 'en_IN', symbol: ''); final _formatCurrency = NumberFormat.currency(locale: 'en_IN', symbol: '');
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_loadLimit(); // Fetch the daily limit _loadLimit(); // Fetch the daily limit
_amountController.addListener(_checkAmountLimit); // Listen for amount changes _amountController
.addListener(_checkAmountLimit); // Listen for amount changes
} }
@override @override
@@ -119,8 +119,8 @@ import 'package:kmobile/widgets/bank_logos.dart';
Navigator.of(pinScreenContext).pushReplacement( Navigator.of(pinScreenContext).pushReplacement(
MaterialPageRoute( MaterialPageRoute(
builder: (_) => builder: (_) => PaymentAnimationScreen(
PaymentAnimationScreen(paymentResponse: paymentResponseFuture), paymentResponse: paymentResponseFuture),
), ),
); );
}, },
@@ -173,8 +173,8 @@ import 'package:kmobile/widgets/bank_logos.dart';
elevation: 0, elevation: 0,
margin: const EdgeInsets.symmetric(vertical: 8.0), margin: const EdgeInsets.symmetric(vertical: 8.0),
child: ListTile( child: ListTile(
leading: leading: getBankLogo(
getBankLogo('Kangra Central Co-operative Bank', context), 'Kangra Central Co-operative Bank', context),
title: Text(widget.creditAccount.name ?? 'N/A'), title: Text(widget.creditAccount.name ?? 'N/A'),
subtitle: Text(widget.creditAccount.accountNo ?? 'N/A'), subtitle: Text(widget.creditAccount.accountNo ?? 'N/A'),
), ),
@@ -214,8 +214,7 @@ import 'package:kmobile/widgets/bank_logos.dart';
const SizedBox(height: 8), const SizedBox(height: 8),
// Daily Limit Display // Daily Limit Display
if (_isLoadingLimit) if (_isLoadingLimit) const Text('Fetching daily limit...'),
const Text('Fetching daily limit...'),
if (!_isLoadingLimit && _limit != null) if (!_isLoadingLimit && _limit != null)
Text( Text(
'Remaining Daily Limit: ${_formatCurrency.format(_limit!.dailyLimit - _limit!.usedLimit)}', 'Remaining Daily Limit: ${_formatCurrency.format(_limit!.dailyLimit - _limit!.usedLimit)}',
@@ -242,4 +241,4 @@ import 'package:kmobile/widgets/bank_logos.dart';
), ),
); );
} }
} }

View File

@@ -42,7 +42,7 @@ class _DailyLimitScreenState extends State<DailyLimitScreen> {
super.dispose(); super.dispose();
} }
Future<void> _showAddOrEditLimitDialog() async { Future<void> _showAddOrEditLimitDialog() async {
_limitController.text = _currentLimit?.toStringAsFixed(0) ?? ''; _limitController.text = _currentLimit?.toStringAsFixed(0) ?? '';
final newLimit = await showDialog<double>( final newLimit = await showDialog<double>(
context: context, context: context,
@@ -81,7 +81,8 @@ Future<void> _showAddOrEditLimitDialog() async {
if (value > 200000) { if (value > 200000) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: const Text("Limit To be Set must be less than 200000"), content: const Text(
"Limit To be Set must be less than 200000"),
behavior: SnackBarBehavior.floating, behavior: SnackBarBehavior.floating,
backgroundColor: theme.colorScheme.error, backgroundColor: theme.colorScheme.error,
), ),
@@ -108,8 +109,7 @@ Future<void> _showAddOrEditLimitDialog() async {
), ),
); );
} }
} }
void _removeLimit() { void _removeLimit() {
setState(() { setState(() {
@@ -129,13 +129,14 @@ Future<void> _showAddOrEditLimitDialog() async {
child: CircularProgressIndicator(), child: CircularProgressIndicator(),
), ),
); );
} }
_currentLimit = limit?.dailyLimit; _currentLimit = limit?.dailyLimit;
_spentAmount = limit?.usedLimit; _spentAmount = limit?.usedLimit;
final localizations = AppLocalizations.of(context); final localizations = AppLocalizations.of(context);
final theme = Theme.of(context); final theme = Theme.of(context);
final formatCurrency = NumberFormat.currency(locale: 'en_IN', symbol: ''); final formatCurrency = NumberFormat.currency(locale: 'en_IN', symbol: '');
final remainingLimit = _currentLimit != null ? _currentLimit! - _spentAmount! : 0.0; final remainingLimit =
_currentLimit != null ? _currentLimit! - _spentAmount! : 0.0;
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(

View File

@@ -16,7 +16,6 @@ import 'package:kmobile/features/profile/preferences/preference_screen.dart';
import 'package:kmobile/api/services/auth_service.dart'; import 'package:kmobile/api/services/auth_service.dart';
import 'package:kmobile/features/fund_transfer/screens/tpin_set_screen.dart'; import 'package:kmobile/features/fund_transfer/screens/tpin_set_screen.dart';
class ProfileScreen extends StatefulWidget { class ProfileScreen extends StatefulWidget {
final String mobileNumber; final String mobileNumber;
const ProfileScreen({super.key, required this.mobileNumber}); const ProfileScreen({super.key, required this.mobileNumber});
@@ -210,7 +209,8 @@ class _ProfileScreenState extends State<ProfileScreen> {
builder: (BuildContext context) { builder: (BuildContext context) {
return AlertDialog( return AlertDialog(
title: Text('TPIN Not Set'), title: Text('TPIN Not Set'),
content: Text('You have not set a TPIN yet. Please set a TPIN to proceed.'), content: Text(
'You have not set a TPIN yet. Please set a TPIN to proceed.'),
actions: <Widget>[ actions: <Widget>[
TextButton( TextButton(
child: Text('Back'), child: Text('Back'),
@@ -236,14 +236,15 @@ class _ProfileScreenState extends State<ProfileScreen> {
); );
} else { } else {
// Case 2: TPIN is set // Case 2: TPIN is set
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (context) => ChangeTpinScreen(mobileNumber: widget.mobileNumber), builder: (context) =>
ChangeTpinScreen(mobileNumber: widget.mobileNumber),
), ),
); );
} }
}, },
), ),
// ListTile( // ListTile(
// leading: const Icon(Icons.password), // leading: const Icon(Icons.password),
// title: const Text("Change Login MPIN"), // title: const Text("Change Login MPIN"),

View File

@@ -1,9 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kmobile/di/injection.dart'; import 'package:kmobile/di/injection.dart';
import 'package:kmobile/widgets/pin_input_field.dart'; import 'package:kmobile/widgets/pin_input_field.dart';
import '../../../api/services/change_password_service.dart'; import '../../../api/services/change_password_service.dart';
class ChangeTpinOtpScreen extends StatefulWidget { class ChangeTpinOtpScreen extends StatefulWidget {
final String oldTpin; final String oldTpin;
final String newTpin; final String newTpin;
final String mobileNumber; final String mobileNumber;
@@ -17,9 +17,9 @@
@override @override
State<ChangeTpinOtpScreen> createState() => _ChangeTpinOtpScreenState(); State<ChangeTpinOtpScreen> createState() => _ChangeTpinOtpScreenState();
} }
class _ChangeTpinOtpScreenState extends State<ChangeTpinOtpScreen> { class _ChangeTpinOtpScreenState extends State<ChangeTpinOtpScreen> {
final _otpController = TextEditingController(); final _otpController = TextEditingController();
final ChangePasswordService _changePasswordService = final ChangePasswordService _changePasswordService =
getIt<ChangePasswordService>(); getIt<ChangePasswordService>();
@@ -122,4 +122,4 @@
), ),
); );
} }
} }

View File

@@ -36,7 +36,8 @@ class _ChangeTpinScreenState extends State<ChangeTpinScreen> {
}); });
try { try {
// 1. Get OTP for TPIN change. // 1. Get OTP for TPIN change.
await _changePasswordService.getOtpTpin(mobileNumber: widget.mobileNumber); await _changePasswordService.getOtpTpin(
mobileNumber: widget.mobileNumber);
// 2. Navigate to the OTP screen on success. // 2. Navigate to the OTP screen on success.
if (mounted) { if (mounted) {

View File

@@ -31,9 +31,9 @@ class QuickPayOutsideBankScreen extends StatefulWidget {
class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> { class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final _limitService = getIt<LimitService>(); final _limitService = getIt<LimitService>();
Limit? _limit; Limit? _limit;
bool _isLoadingLimit = true; bool _isLoadingLimit = true;
final _formatCurrency = NumberFormat.currency(locale: 'en_IN', symbol: ''); final _formatCurrency = NumberFormat.currency(locale: 'en_IN', symbol: '');
// Controllers // Controllers
final accountNumberController = TextEditingController(); final accountNumberController = TextEditingController();
final confirmAccountNumberController = TextEditingController(); final confirmAccountNumberController = TextEditingController();
@@ -70,7 +70,7 @@ final _formatCurrency = NumberFormat.currency(locale: 'en_IN', symbol: '₹');
amountController.addListener(_checkAmountLimit); amountController.addListener(_checkAmountLimit);
} }
Future<void> _loadLimit() async { Future<void> _loadLimit() async {
setState(() { setState(() {
_isLoadingLimit = true; _isLoadingLimit = true;
}); });
@@ -86,7 +86,7 @@ Future<void> _loadLimit() async {
_isLoadingLimit = false; _isLoadingLimit = false;
}); });
} }
} }
// Add this method to check the amount against the limit // Add this method to check the amount against the limit
void _checkAmountLimit() { void _checkAmountLimit() {
@@ -99,7 +99,8 @@ Future<void> _loadLimit() async {
if (isOverLimit) { if (isOverLimit) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text('Amount exceeds remaining daily limit of ${_formatCurrency.format(remainingLimit)}'), content: Text(
'Amount exceeds remaining daily limit of ${_formatCurrency.format(remainingLimit)}'),
backgroundColor: Colors.red, backgroundColor: Colors.red,
), ),
); );
@@ -783,7 +784,8 @@ Future<void> _loadLimit() async {
border: const OutlineInputBorder(), border: const OutlineInputBorder(),
isDense: true, isDense: true,
filled: true, filled: true,
fillColor: Theme.of(context).scaffoldBackgroundColor, fillColor:
Theme.of(context).scaffoldBackgroundColor,
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Theme.of(context).colorScheme.outline), color: Theme.of(context).colorScheme.outline),
@@ -808,7 +810,8 @@ Future<void> _loadLimit() async {
border: const OutlineInputBorder(), border: const OutlineInputBorder(),
isDense: true, isDense: true,
filled: true, filled: true,
fillColor: Theme.of(context).scaffoldBackgroundColor, fillColor:
Theme.of(context).scaffoldBackgroundColor,
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Theme.of(context).colorScheme.outline), color: Theme.of(context).colorScheme.outline),
@@ -824,7 +827,8 @@ Future<void> _loadLimit() async {
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return AppLocalizations.of(context).amountRequired; 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) {
@@ -839,12 +843,12 @@ Future<void> _loadLimit() async {
], ],
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
if (_isLoadingLimit) if (_isLoadingLimit)
const Padding( const Padding(
padding: EdgeInsets.only(left: 8.0), padding: EdgeInsets.only(left: 8.0),
child: Text('Fetching daily limit...'), child: Text('Fetching daily limit...'),
), ),
if (!_isLoadingLimit && _limit != null) if (!_isLoadingLimit && _limit != null)
Padding( Padding(
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: Text( child: Text(
@@ -868,9 +872,12 @@ if (!_isLoadingLimit && _limit != null)
alignment: Alignment.center, alignment: Alignment.center,
child: SwipeButton.expand( child: SwipeButton.expand(
thumb: Icon(Icons.arrow_forward, thumb: Icon(Icons.arrow_forward,
color: _isAmountOverLimit ? Colors.grey : Theme.of(context).dialogBackgroundColor), color: _isAmountOverLimit
activeThumbColor: _isAmountOverLimit ? Colors.grey.shade700 : ? Colors.grey
Theme.of(context).colorScheme.primary, : Theme.of(context).dialogBackgroundColor),
activeThumbColor: _isAmountOverLimit
? Colors.grey.shade700
: Theme.of(context).colorScheme.primary,
activeTrackColor: _isAmountOverLimit activeTrackColor: _isAmountOverLimit
? Colors.grey.shade300 ? Colors.grey.shade300
: Theme.of(context).colorScheme.secondary.withAlpha(100), : Theme.of(context).colorScheme.secondary.withAlpha(100),

View File

@@ -22,9 +22,9 @@ class QuickPayWithinBankScreen extends StatefulWidget {
class _QuickPayWithinBankScreen extends State<QuickPayWithinBankScreen> { class _QuickPayWithinBankScreen extends State<QuickPayWithinBankScreen> {
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
final _limitService = getIt<LimitService>(); final _limitService = getIt<LimitService>();
Limit? _limit; Limit? _limit;
bool _isLoadingLimit = true; bool _isLoadingLimit = true;
final _formatCurrency = NumberFormat.currency(locale: 'en_IN', symbol: ''); final _formatCurrency = NumberFormat.currency(locale: 'en_IN', symbol: '');
final TextEditingController accountNumberController = TextEditingController(); final TextEditingController accountNumberController = TextEditingController();
final TextEditingController confirmAccountNumberController = final TextEditingController confirmAccountNumberController =
TextEditingController(); TextEditingController();
@@ -46,7 +46,7 @@ final _formatCurrency = NumberFormat.currency(locale: 'en_IN', symbol: '₹');
amountController.addListener(_checkAmountLimit); amountController.addListener(_checkAmountLimit);
} }
Future<void> _loadLimit() async { Future<void> _loadLimit() async {
setState(() { setState(() {
_isLoadingLimit = true; _isLoadingLimit = true;
}); });
@@ -62,9 +62,9 @@ Future<void> _loadLimit() async {
_isLoadingLimit = false; _isLoadingLimit = false;
}); });
} }
} }
void _checkAmountLimit() { void _checkAmountLimit() {
if (_limit == null) return; if (_limit == null) return;
final amount = double.tryParse(amountController.text) ?? 0; final amount = double.tryParse(amountController.text) ?? 0;
@@ -74,7 +74,8 @@ void _checkAmountLimit() {
if (isOverLimit) { if (isOverLimit) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text('Amount exceeds remaining daily limit of ${_formatCurrency.format(remainingLimit)}'), content: Text(
'Amount exceeds remaining daily limit of ${_formatCurrency.format(remainingLimit)}'),
backgroundColor: Colors.red, backgroundColor: Colors.red,
), ),
); );
@@ -86,7 +87,7 @@ void _checkAmountLimit() {
_isAmountOverLimit = isOverLimit; _isAmountOverLimit = isOverLimit;
}); });
} }
} }
void _resetBeneficiaryValidation() { void _resetBeneficiaryValidation() {
if (_isBeneficiaryValidated || if (_isBeneficiaryValidated ||
@@ -184,7 +185,8 @@ void _checkAmountLimit() {
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Theme.of(context).colorScheme.primary, width: 2), color: Theme.of(context).colorScheme.primary,
width: 2),
), ),
), ),
controller: accountNumberController, controller: accountNumberController,
@@ -204,7 +206,8 @@ void _checkAmountLimit() {
TextFormField( TextFormField(
controller: confirmAccountNumberController, controller: confirmAccountNumberController,
decoration: InputDecoration( decoration: InputDecoration(
labelText: AppLocalizations.of(context).confirmAccountNumber, labelText:
AppLocalizations.of(context).confirmAccountNumber,
// prefixIcon: Icon(Icons.person), // prefixIcon: Icon(Icons.person),
border: const OutlineInputBorder(), border: const OutlineInputBorder(),
isDense: true, isDense: true,
@@ -216,7 +219,8 @@ void _checkAmountLimit() {
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Theme.of(context).colorScheme.primary, width: 2), color: Theme.of(context).colorScheme.primary,
width: 2),
), ),
), ),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
@@ -256,10 +260,11 @@ void _checkAmountLimit() {
? const SizedBox( ? const SizedBox(
width: 20, width: 20,
height: 20, height: 20,
child: CircularProgressIndicator(strokeWidth: 2), child:
CircularProgressIndicator(strokeWidth: 2),
) )
: Text( : Text(AppLocalizations.of(context)
AppLocalizations.of(context).validateBeneficiary), .validateBeneficiary),
), ),
), ),
), ),
@@ -302,7 +307,8 @@ void _checkAmountLimit() {
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Theme.of(context).colorScheme.primary, width: 2), color: Theme.of(context).colorScheme.primary,
width: 2),
), ),
), ),
value: _selectedAccountType, value: _selectedAccountType,
@@ -343,12 +349,12 @@ void _checkAmountLimit() {
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Theme.of(context).colorScheme.primary, width: 2), color: Theme.of(context).colorScheme.primary,
width: 2),
), ),
), ),
), ),
const SizedBox(height: 25), const SizedBox(height: 25),
TextFormField( TextFormField(
decoration: InputDecoration( decoration: InputDecoration(
labelText: AppLocalizations.of(context).amount, labelText: AppLocalizations.of(context).amount,
@@ -362,7 +368,8 @@ void _checkAmountLimit() {
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: Theme.of(context).colorScheme.primary, width: 2), color: Theme.of(context).colorScheme.primary,
width: 2),
), ),
), ),
controller: amountController, controller: amountController,
@@ -380,9 +387,8 @@ void _checkAmountLimit() {
}, },
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
if (_isLoadingLimit) if (_isLoadingLimit) const Text('Fetching daily limit...'),
const Text('Fetching daily limit...'), if (!_isLoadingLimit && _limit != null)
if (!_isLoadingLimit && _limit != null)
Text( Text(
'Remaining Daily Limit: ${_formatCurrency.format(_limit!.dailyLimit - _limit!.usedLimit)}', 'Remaining Daily Limit: ${_formatCurrency.format(_limit!.dailyLimit - _limit!.usedLimit)}',
style: Theme.of(context).textTheme.bodySmall, style: Theme.of(context).textTheme.bodySmall,
@@ -392,9 +398,12 @@ if (!_isLoadingLimit && _limit != null)
alignment: Alignment.center, alignment: Alignment.center,
child: SwipeButton.expand( child: SwipeButton.expand(
thumb: Icon(Icons.arrow_forward, thumb: Icon(Icons.arrow_forward,
color: _isAmountOverLimit ? Colors.grey : Theme.of(context).dialogBackgroundColor), color: _isAmountOverLimit
activeThumbColor: _isAmountOverLimit ? Colors.grey.shade700 : ? Colors.grey
Theme.of(context).colorScheme.primary, : Theme.of(context).dialogBackgroundColor),
activeThumbColor: _isAmountOverLimit
? Colors.grey.shade700
: Theme.of(context).colorScheme.primary,
activeTrackColor: _isAmountOverLimit activeTrackColor: _isAmountOverLimit
? Colors.grey.shade300 ? Colors.grey.shade300
: Theme.of( : Theme.of(

View File

@@ -15,13 +15,13 @@ void main() async {
]); ]);
// Check for device compromise // Check for device compromise
// final compromisedMessage = await SecurityService.deviceCompromisedMessage; final compromisedMessage = await SecurityService.deviceCompromisedMessage;
// if (compromisedMessage != null) { if (compromisedMessage != null) {
// runApp(MaterialApp( runApp(MaterialApp(
// home: SecurityErrorScreen(message: compromisedMessage), home: SecurityErrorScreen(message: compromisedMessage),
// )); ));
// return; return;
// } }
await setupDependencies(); await setupDependencies();
runApp(const KMobile()); runApp(const KMobile());
} }

View File

@@ -1,15 +1,15 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class TncDialog extends StatefulWidget { class TncDialog extends StatefulWidget {
final Future<void> Function() onProceed; final Future<void> Function() onProceed;
const TncDialog({Key? key, required this.onProceed}) : super(key: key); const TncDialog({Key? key, required this.onProceed}) : super(key: key);
@override @override
_TncDialogState createState() => _TncDialogState(); _TncDialogState createState() => _TncDialogState();
} }
class _TncDialogState extends State<TncDialog> { class _TncDialogState extends State<TncDialog> {
bool _isAgreed = false; bool _isAgreed = false;
bool _isLoading = false; bool _isLoading = false;
// --- NEW: ScrollController for the TNC text --- // --- NEW: ScrollController for the TNC text ---
@@ -208,4 +208,4 @@
], ],
); );
} }
} }