From 58e53d0aeb740909ab3f0b3f564e791d8a56cfd1 Mon Sep 17 00:00:00 2001 From: Nilanjan Chakrabarti Date: Tue, 21 Oct 2025 13:32:14 +0530 Subject: [PATCH] App Version added and dart format --- lib/api/services/beneficiary_service.dart | 5 +- lib/api/services/change_password_service.dart | 39 +-- lib/app.dart | 59 ++-- lib/data/models/imps_transaction.dart | 2 +- lib/data/models/neft_transaction.dart | 2 +- lib/data/models/transfer.dart | 2 +- lib/data/repositories/auth_repository.dart | 4 +- .../repositories/transaction_repository.dart | 2 - lib/di/injection.dart | 10 +- .../screens/account_statement_screen.dart | 55 ++-- .../screens/transaction_details_screen.dart | 4 +- .../auth/controllers/theme_state.dart | 21 +- .../auth/screens/set_password_screen.dart | 7 +- lib/features/auth/screens/splash_screen.dart | 38 ++- .../screens/add_beneficiary_screen.dart | 110 ++++--- .../screens/beneficiary_result_page.dart | 5 +- .../card/screens/card_management_screen.dart | 108 +++--- .../screens/customer_info_screen.dart | 24 +- .../dashboard/screens/dashboard_screen.dart | 98 +++--- .../dashboard/widgets/account_card.dart | 1 - .../enquiry/screens/enquiry_screen.dart | 60 ++-- .../screens/fund_transfer_amount_screen.dart | 10 +- .../screens/payment_animation.dart | 3 +- .../screens/tpin_otp_screen.dart | 309 +++++++++--------- .../screens/tpin_prompt_screen.dart | 134 ++++---- .../screens/transaction_pin_screen.dart | 1 - .../screens/transaction_success_screen.dart | 22 +- .../change_password_otp_screen.dart | 51 +-- .../change_password_screen.dart | 58 ++-- lib/features/profile/logout_dialog.dart | 2 +- .../preferences/theme_mode_dialog.dart | 6 +- lib/features/profile/profile_screen.dart | 308 +++++++++-------- .../quick_pay_outside_bank_screen.dart | 100 +++--- .../screens/quick_pay_within_bank_screen.dart | 38 +-- .../security/security_error_screen.dart | 6 +- .../screens/branch_locator_screen.dart | 250 +++++++------- .../screens/daily_transaction_limit.dart | 266 +++++++-------- lib/features/service/screens/faqs_screen.dart | 82 ++--- .../service/screens/quick_links_screen.dart | 2 +- .../service/screens/service_screen.dart | 163 ++++----- lib/main.dart | 2 +- lib/widgets/bank_logos.dart | 8 +- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 80 +++-- pubspec.yaml | 5 +- 45 files changed, 1334 insertions(+), 1230 deletions(-) diff --git a/lib/api/services/beneficiary_service.dart b/lib/api/services/beneficiary_service.dart index 912b943..fa2308d 100644 --- a/lib/api/services/beneficiary_service.dart +++ b/lib/api/services/beneficiary_service.dart @@ -40,8 +40,7 @@ class BeneficiaryService { } on DioException catch (e) { if (e.response?.statusCode == 404) { throw Exception('INVALID IFSC CODE'); - } - else if (e.response?.statusCode == 401) { + } else if (e.response?.statusCode == 401) { throw Exception('INVALID IFSC CODE'); } } catch (e) { @@ -127,4 +126,4 @@ class BeneficiaryService { throw Exception('Unexpected error: ${e.toString()}'); } } -} \ No newline at end of file +} diff --git a/lib/api/services/change_password_service.dart b/lib/api/services/change_password_service.dart index 5d90bd4..f438b34 100644 --- a/lib/api/services/change_password_service.dart +++ b/lib/api/services/change_password_service.dart @@ -10,10 +10,7 @@ class ChangePasswordService { }) async { final response = await _dio.post( '/api/otp/send', - data: { - 'mobileNumber': mobileNumber, - 'type': "CHANGE_LPWORD" - }, + data: {'mobileNumber': mobileNumber, 'type': "CHANGE_LPWORD"}, ); if (response.statusCode != 200) { throw Exception("Invalid Mobile Number/Type"); @@ -22,15 +19,12 @@ class ChangePasswordService { return response.toString(); } - Future getOtpTpin({ + Future getOtpTpin({ required String mobileNumber, }) async { final response = await _dio.post( '/api/otp/send', - data: { - 'mobileNumber': mobileNumber, - 'type': "CHANGE_TPIN" - }, + data: {'mobileNumber': mobileNumber, 'type': "CHANGE_TPIN"}, ); if (response.statusCode != 200) { throw Exception("Invalid Mobile Number/Type"); @@ -39,15 +33,14 @@ class ChangePasswordService { return response.toString(); } - - Future validateOtp({ + Future validateOtp({ required String otp, required String mobileNumber, }) async { final response = await _dio.post( '/api/otp/verify?mobileNumber=$mobileNumber', data: { - 'otp' : otp, + 'otp': otp, }, ); if (response.statusCode != 200) { @@ -56,22 +49,22 @@ class ChangePasswordService { return response.toString(); } - Future validateChangePwd({ - required String OldLPsw, - required String newLPsw, - required String confirmLPsw, - }) async { - final response = await _dio.post( + Future validateChangePwd({ + required String OldLPsw, + required String newLPsw, + required String confirmLPsw, + }) async { + final response = await _dio.post( '/api/auth/change/login_password', data: { - 'OldLPsw': OldLPsw, - 'newLPsw': newLPsw, - 'confirmLPsw': confirmLPsw, + 'OldLPsw': OldLPsw, + 'newLPsw': newLPsw, + 'confirmLPsw': confirmLPsw, }, ); if (response.statusCode != 200) { throw Exception("Wrong OTP"); } return response.toString(); - } -} \ No newline at end of file + } +} diff --git a/lib/app.dart b/lib/app.dart index 200cba5..5203543 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -43,7 +43,7 @@ class _KMobileState extends State with WidgetsBindingObserver { @override void initState() { super.initState(); - WidgetsBinding.instance.addObserver(this); + WidgetsBinding.instance.addObserver(this); loadPreferences(); Future.delayed(const Duration(seconds: 3), () { setState(() { @@ -52,32 +52,32 @@ class _KMobileState extends State with WidgetsBindingObserver { }); } - @override - void dispose() { - WidgetsBinding.instance.removeObserver(this); - _backgroundTimer?.cancel(); - super.dispose(); - } - -@override -void didChangeAppLifecycleState(AppLifecycleState state) { - super.didChangeAppLifecycleState(state); - switch (state) { - case AppLifecycleState.resumed: - _backgroundTimer?.cancel(); - break; - case AppLifecycleState.paused: - _backgroundTimer = Timer(const Duration(minutes: 2), () { - if (Platform.isAndroid) { - SystemNavigator.pop(); - } - exit(0); - }); - break; - default: - break; + @override + void dispose() { + WidgetsBinding.instance.removeObserver(this); + _backgroundTimer?.cancel(); + super.dispose(); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + super.didChangeAppLifecycleState(state); + switch (state) { + case AppLifecycleState.resumed: + _backgroundTimer?.cancel(); + break; + case AppLifecycleState.paused: + _backgroundTimer = Timer(const Duration(minutes: 2), () { + if (Platform.isAndroid) { + SystemNavigator.pop(); + } + exit(0); + }); + break; + default: + break; + } } -} Future loadPreferences() async { final prefs = await SharedPreferences.getInstance(); @@ -217,7 +217,7 @@ class _AuthGateState extends State { return const SplashScreen(); } if (snapshot.data == true) { - return const NavigationScaffold(); + return const NavigationScaffold(); } return MPinScreen( mode: MPinMode.enter, @@ -362,8 +362,7 @@ class _NavigationScaffoldState extends State { type: BottomNavigationBarType.fixed, backgroundColor: const Color(0XFF1E58AD), selectedItemColor: Theme.of(context).colorScheme.onPrimary, - unselectedItemColor: - Theme.of(context).colorScheme.onSecondary, + unselectedItemColor: Theme.of(context).colorScheme.onSecondary, onTap: (index) { setState(() { _selectedIndex = index; @@ -460,4 +459,4 @@ class BiometricPromptScreen extends StatelessWidget { onCompleted(); } } -} \ No newline at end of file +} diff --git a/lib/data/models/imps_transaction.dart b/lib/data/models/imps_transaction.dart index 15a3914..cb90fe6 100644 --- a/lib/data/models/imps_transaction.dart +++ b/lib/data/models/imps_transaction.dart @@ -15,7 +15,7 @@ class ImpsTransaction { required this.ifscCode, this.remitterName, required this.beneficiaryName, - required this.tpin, + required this.tpin, this.remarks, }); diff --git a/lib/data/models/neft_transaction.dart b/lib/data/models/neft_transaction.dart index 6ffc6ff..2836fbc 100644 --- a/lib/data/models/neft_transaction.dart +++ b/lib/data/models/neft_transaction.dart @@ -15,7 +15,7 @@ class NeftTransaction { required this.ifscCode, required this.remitterName, required this.beneficiaryName, - required this.tpin, + required this.tpin, this.remarks, }); diff --git a/lib/data/models/transfer.dart b/lib/data/models/transfer.dart index 766c9c5..ec25ba7 100644 --- a/lib/data/models/transfer.dart +++ b/lib/data/models/transfer.dart @@ -11,7 +11,7 @@ class Transfer { required this.toAccount, required this.toAccountType, required this.amount, - this.tpin, + this.tpin, this.remarks, }); diff --git a/lib/data/repositories/auth_repository.dart b/lib/data/repositories/auth_repository.dart index 3ecf8c7..9a96026 100644 --- a/lib/data/repositories/auth_repository.dart +++ b/lib/data/repositories/auth_repository.dart @@ -49,12 +49,10 @@ class AuthRepository { _tokenExpiryKey, token.expiresAt.toIso8601String()); } -Future clearAuthTokens() async { + Future clearAuthTokens() async { await _secureStorage.deleteAll(); - } - Future _getAuthToken() async { final accessToken = await _secureStorage.read(_accessTokenKey); final expiryString = await _secureStorage.read(_tokenExpiryKey); diff --git a/lib/data/repositories/transaction_repository.dart b/lib/data/repositories/transaction_repository.dart index 5d31c10..b9e248a 100644 --- a/lib/data/repositories/transaction_repository.dart +++ b/lib/data/repositories/transaction_repository.dart @@ -1,5 +1,3 @@ - - import 'package:dio/dio.dart'; import 'package:intl/intl.dart'; import 'package:kmobile/data/models/transaction.dart'; diff --git a/lib/di/injection.dart b/lib/di/injection.dart index f0ee81b..465e5b2 100644 --- a/lib/di/injection.dart +++ b/lib/di/injection.dart @@ -49,7 +49,9 @@ Future setupDependencies() async { getIt.registerSingleton(NeftService(getIt())); getIt.registerSingleton(RtgsService(getIt())); getIt.registerSingleton(ImpsService(getIt())); - getIt.registerLazySingleton(() => ChangePasswordService(getIt()),); + getIt.registerLazySingleton( + () => ChangePasswordService(getIt()), + ); // Add auth interceptor after repository is available getIt().interceptors.add( @@ -65,9 +67,9 @@ Dio _createDioClient() { final dio = Dio( BaseOptions( baseUrl: - //'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com:8080', //test - //'http://lb-kccb-mobile-banking-app-848675342.ap-south-1.elb.amazonaws.com', //prod - 'https://kccbmbnk.net', + 'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com:8080', //test + //'http://lb-kccb-mobile-banking-app-848675342.ap-south-1.elb.amazonaws.com', //prod + //'https://kccbmbnk.net', connectTimeout: const Duration(seconds: 60), receiveTimeout: const Duration(seconds: 60), headers: { diff --git a/lib/features/accounts/screens/account_statement_screen.dart b/lib/features/accounts/screens/account_statement_screen.dart index e0f9425..15c0b54 100644 --- a/lib/features/accounts/screens/account_statement_screen.dart +++ b/lib/features/accounts/screens/account_statement_screen.dart @@ -11,8 +11,8 @@ import 'transaction_details_screen.dart'; import 'package:pdf/widgets.dart' as pw; import 'package:permission_handler/permission_handler.dart'; import 'package:device_info_plus/device_info_plus.dart'; - import 'package:path_provider/path_provider.dart'; - import 'package:share_plus/share_plus.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:share_plus/share_plus.dart'; class AccountStatementScreen extends StatefulWidget { final String accountNo; @@ -295,20 +295,21 @@ class _AccountStatementScreen extends State { : '', style: const TextStyle(fontSize: 12), ), - trailing: Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - "₹${tx.amount}", - style: const TextStyle(fontSize: 17), - ), - Text( - "Bal: ₹${tx.balance}", - style: const TextStyle(fontSize: 12), // Style matches tx.name - ), - ], -), + trailing: Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + "₹${tx.amount}", + style: const TextStyle(fontSize: 17), + ), + Text( + "Bal: ₹${tx.balance}", + style: const TextStyle( + fontSize: 12), // Style matches tx.name + ), + ], + ), onTap: () { Navigator.push( context, @@ -491,19 +492,17 @@ class _AccountStatementScreen extends State { } } // Add for IOS -else if (Platform.isIOS) { - // On iOS, we save to a temporary directory and then open the share sheet. - final tempDir = await getTemporaryDirectory(); - final file = await File('${tempDir.path}/$fileName').create(); - await file.writeAsBytes(pdfBytes); + else if (Platform.isIOS) { + // On iOS, we save to a temporary directory and then open the share sheet. + final tempDir = await getTemporaryDirectory(); + final file = await File('${tempDir.path}/$fileName').create(); + await file.writeAsBytes(pdfBytes); - // Use share_plus to open the iOS share dialog - await Share.shareXFiles( - [XFile(file.path)], - ); -} - - + // Use share_plus to open the iOS share dialog + await Share.shareXFiles( + [XFile(file.path)], + ); + } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( diff --git a/lib/features/accounts/screens/transaction_details_screen.dart b/lib/features/accounts/screens/transaction_details_screen.dart index 5041cbd..af01bdd 100644 --- a/lib/features/accounts/screens/transaction_details_screen.dart +++ b/lib/features/accounts/screens/transaction_details_screen.dart @@ -73,8 +73,8 @@ class TransactionDetailsScreen extends StatelessWidget { // AppLocalizations.of(context).beneficiaryAccountNo, // transaction.name.split("A/C ").last ?? "") // ] - _buildDetailRow(AppLocalizations.of(context).details, - transaction.name), + _buildDetailRow( + AppLocalizations.of(context).details, transaction.name), ], ), ), diff --git a/lib/features/auth/controllers/theme_state.dart b/lib/features/auth/controllers/theme_state.dart index d3b1507..48d8672 100644 --- a/lib/features/auth/controllers/theme_state.dart +++ b/lib/features/auth/controllers/theme_state.dart @@ -16,26 +16,23 @@ class ThemeState extends Equatable { List get props => [themeType]; }*/ - import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; import 'package:kmobile/config/theme_type.dart'; import 'package:kmobile/config/themes.dart'; + class ThemeState extends Equatable { final ThemeType themeType; const ThemeState({required this.themeType}); - ThemeData getLightThemeData() { - return AppThemes.getLightTheme(themeType); - } - - ThemeData getDarkThemeData() { - return AppThemes.getDarkTheme(themeType); - } - - @override - List get props => [themeType]; + ThemeData getLightThemeData() { + return AppThemes.getLightTheme(themeType); } + ThemeData getDarkThemeData() { + return AppThemes.getDarkTheme(themeType); + } - + @override + List get props => [themeType]; +} diff --git a/lib/features/auth/screens/set_password_screen.dart b/lib/features/auth/screens/set_password_screen.dart index 0a8a82e..9aeb91e 100644 --- a/lib/features/auth/screens/set_password_screen.dart +++ b/lib/features/auth/screens/set_password_screen.dart @@ -140,9 +140,10 @@ class _SetPasswordScreenState extends State { if (_error != null) ...[ Text( _error!, - style: const TextStyle(color: Colors.red, - fontWeight: FontWeight.bold, - fontSize: 20), + style: const TextStyle( + color: Colors.red, + fontWeight: FontWeight.bold, + fontSize: 20), textAlign: TextAlign.center, ), const SizedBox(height: 16), diff --git a/lib/features/auth/screens/splash_screen.dart b/lib/features/auth/screens/splash_screen.dart index 139f4ba..3dc58be 100644 --- a/lib/features/auth/screens/splash_screen.dart +++ b/lib/features/auth/screens/splash_screen.dart @@ -1,3 +1,5 @@ +import 'package:package_info_plus/package_info_plus.dart'; + import '../../../l10n/app_localizations.dart'; import 'package:flutter/material.dart'; @@ -10,11 +12,29 @@ class SplashScreen extends StatefulWidget { } class _SplashScreenState extends State { + String _version = ''; + @override + void initState() { + super.initState(); + _loadVersion(); + } + + Future _loadVersion() async { + final PackageInfo info = await PackageInfo.fromPlatform(); + if (mounted) { + // Check if the widget is still in the tree + setState(() { + _version = 'Version ${info.version} (${info.buildNumber})'; + }); + } + } + @override Widget build(BuildContext context) { return Scaffold( body: Stack( - children: [ + fit: StackFit.expand, + children: [ Positioned.fill( child: Image.asset( 'assets/images/kconnect2.webp', @@ -51,8 +71,20 @@ class _SplashScreenState extends State { left: 0, right: 0, child: Center( - child: CircularProgressIndicator( - color: Color(0xFFFFFFFF)), + child: CircularProgressIndicator(color: Color(0xFFFFFFFF)), + ), + ), + Positioned( + bottom: 90, + left: 0, + right: 0, + child: Text( + _version, + textAlign: TextAlign.center, + style: const TextStyle( + color: Color(0xFFFFFFFF), + fontSize: 14, + ), ), ), ], diff --git a/lib/features/beneficiaries/screens/add_beneficiary_screen.dart b/lib/features/beneficiaries/screens/add_beneficiary_screen.dart index c93970d..c0b970a 100644 --- a/lib/features/beneficiaries/screens/add_beneficiary_screen.dart +++ b/lib/features/beneficiaries/screens/add_beneficiary_screen.dart @@ -24,8 +24,8 @@ class AddBeneficiaryScreen extends StatefulWidget { class _AddBeneficiaryScreen extends State { final _formKey = GlobalKey(); final _accountNumberFieldKey = GlobalKey(); -final _confirmAccountNumberFieldKey = GlobalKey(); -final _ifscFieldKey = GlobalKey(); + final _confirmAccountNumberFieldKey = GlobalKey(); + final _ifscFieldKey = GlobalKey(); final TextEditingController accountNumberController = TextEditingController(); final TextEditingController confirmAccountNumberController = TextEditingController(); @@ -47,10 +47,10 @@ final _ifscFieldKey = GlobalKey(); void initState() { super.initState(); _ifscFocusNode.addListener(() { - if (!_ifscFocusNode.hasFocus && ifscController.text.trim().length == 11) { - _validateIFSC(); - } -}); + if (!_ifscFocusNode.hasFocus && ifscController.text.trim().length == 11) { + _validateIFSC(); + } + }); WidgetsBinding.instance.addPostFrameCallback((_) { setState(() { accountType = 'Savings'; @@ -58,26 +58,26 @@ final _ifscFieldKey = GlobalKey(); }); } - @override - void dispose() { - accountNumberController.dispose(); - confirmAccountNumberController.dispose(); - nameController.dispose(); - bankNameController.dispose(); - branchNameController.dispose(); - ifscController.dispose(); - phoneController.dispose(); - _ifscFocusNode.dispose(); - super.dispose(); - } + @override + void dispose() { + accountNumberController.dispose(); + confirmAccountNumberController.dispose(); + nameController.dispose(); + bankNameController.dispose(); + branchNameController.dispose(); + ifscController.dispose(); + phoneController.dispose(); + _ifscFocusNode.dispose(); + super.dispose(); + } - void _validateIFSC() async { - var beneficiaryService = getIt(); - final ifsc = ifscController.text.trim().toUpperCase(); - if (ifsc.isEmpty) return; + void _validateIFSC() async { + var beneficiaryService = getIt(); + final ifsc = ifscController.text.trim().toUpperCase(); + if (ifsc.isEmpty) return; - try { - final result = await beneficiaryService.validateIFSC(ifsc); + try { + final result = await beneficiaryService.validateIFSC(ifsc); if (mounted) { if (result.bankName.isEmpty) { @@ -94,7 +94,8 @@ final _ifscFieldKey = GlobalKey(); } catch (e) { if (mounted) { final errorMessage = e.toString().toUpperCase(); - String snackbarMessage = AppLocalizations.of(context).somethingWentWrong; + String snackbarMessage = + AppLocalizations.of(context).somethingWentWrong; if (errorMessage.contains('INVALID') && errorMessage.contains('IFSC')) { snackbarMessage = AppLocalizations.of(context).invalidIfsc; @@ -107,7 +108,7 @@ final _ifscFieldKey = GlobalKey(); branchNameController.clear(); } } - } + } void _validateBeneficiary() async { FocusScope.of(context).unfocus(); @@ -325,7 +326,9 @@ final _ifscFieldKey = GlobalKey(); ).reenterAccountNumber; } if (value != accountNumberController.text) { - return AppLocalizations.of(context,).accountMismatch; + return AppLocalizations.of( + context, + ).accountMismatch; } return null; }, @@ -346,16 +349,16 @@ final _ifscFieldKey = GlobalKey(); ), textCapitalization: TextCapitalization.characters, textInputAction: TextInputAction.next, - onChanged: (value) { - setState(() { - final trimmed = value.trim().toUpperCase(); - if (trimmed.length < 11) { - // clear bank/branch if backspace or changed - bankNameController.clear(); - branchNameController.clear(); - } - }); - }, + onChanged: (value) { + setState(() { + final trimmed = value.trim().toUpperCase(); + if (trimmed.length < 11) { + // clear bank/branch if backspace or changed + bankNameController.clear(); + branchNameController.clear(); + } + }); + }, validator: (value) { final pattern = RegExp(r'^[A-Z]{4}0[A-Z0-9]{6}$'); if (value == null || value.trim().isEmpty) { @@ -429,20 +432,27 @@ final _ifscFieldKey = GlobalKey(); child: SizedBox( width: double.infinity, child: ElevatedButton( -onPressed: _isValidating || ifscController.text.length != 11 -? null -: () { - final isAccountValid = - _accountNumberFieldKey.currentState!.validate(); - final isConfirmAccountValid = - _confirmAccountNumberFieldKey.currentState!.validate(); - final isIfscValid = _ifscFieldKey.currentState!.validate(); - - if (isAccountValid && isConfirmAccountValid && isIfscValid) { - _validateBeneficiary(); - } - }, + onPressed: _isValidating || + ifscController.text.length != 11 + ? null + : () { + final isAccountValid = + _accountNumberFieldKey.currentState! + .validate(); + final isConfirmAccountValid = + _confirmAccountNumberFieldKey + .currentState! + .validate(); + final isIfscValid = _ifscFieldKey + .currentState! + .validate(); + if (isAccountValid && + isConfirmAccountValid && + isIfscValid) { + _validateBeneficiary(); + } + }, child: _isValidating ? const SizedBox( width: 20, diff --git a/lib/features/beneficiaries/screens/beneficiary_result_page.dart b/lib/features/beneficiaries/screens/beneficiary_result_page.dart index c416fd4..1fb54e0 100644 --- a/lib/features/beneficiaries/screens/beneficiary_result_page.dart +++ b/lib/features/beneficiaries/screens/beneficiary_result_page.dart @@ -90,7 +90,10 @@ class _BeneficiaryResultPageState extends State { ), child: Text( AppLocalizations.of(context).done, - style: TextStyle(color: Theme.of(context).colorScheme.onPrimaryContainer), // slightly bigger text + style: TextStyle( + color: Theme.of(context) + .colorScheme + .onPrimaryContainer), // slightly bigger text ), ), ), diff --git a/lib/features/card/screens/card_management_screen.dart b/lib/features/card/screens/card_management_screen.dart index 158dd62..eb65e7d 100644 --- a/lib/features/card/screens/card_management_screen.dart +++ b/lib/features/card/screens/card_management_screen.dart @@ -17,83 +17,83 @@ class CardManagementScreen extends StatefulWidget { class _CardManagementScreen extends State { @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - automaticallyImplyLeading: false, - title: Text( - AppLocalizations.of(context).cardManagement, - ), - centerTitle: false, - ), - body: ListView( - children: [ - CardManagementTile( - icon: Symbols.add, - label: AppLocalizations.of(context).applyDebitCard, - onTap: () {}, - disabled: true, // Add this + return Scaffold( + appBar: AppBar( + automaticallyImplyLeading: false, + title: Text( + AppLocalizations.of(context).cardManagement, ), - const Divider(height: 1), - CardManagementTile( - icon: Symbols.remove_moderator, - label: AppLocalizations.of(context).blockUnblockCard, - onTap: () { - Navigator.push( + centerTitle: false, + ), + body: ListView( + children: [ + CardManagementTile( + icon: Symbols.add, + label: AppLocalizations.of(context).applyDebitCard, + onTap: () {}, + disabled: true, // Add this + ), + const Divider(height: 1), + CardManagementTile( + icon: Symbols.remove_moderator, + label: AppLocalizations.of(context).blockUnblockCard, + onTap: () { + Navigator.push( context, MaterialPageRoute( builder: (context) => const BlockCardScreen(), ), ); - }, - disabled: true, - ), - const Divider(height: 1), - CardManagementTile( - icon: Symbols.password_2, - label: AppLocalizations.of(context).changeCardPin, - onTap: () { - Navigator.push( + }, + disabled: true, + ), + const Divider(height: 1), + CardManagementTile( + icon: Symbols.password_2, + label: AppLocalizations.of(context).changeCardPin, + onTap: () { + Navigator.push( context, MaterialPageRoute( builder: (context) => const CardPinChangeDetailsScreen(), ), ); - }, - disabled: true, - ), - const Divider(height: 1), - CardManagementTile( - icon: Symbols.payment_card, - label: AppLocalizations.of(context).viewCardDeatils, - onTap: () { - Navigator.push( + }, + disabled: true, + ), + const Divider(height: 1), + CardManagementTile( + icon: Symbols.payment_card, + label: AppLocalizations.of(context).viewCardDeatils, + onTap: () { + Navigator.push( context, MaterialPageRoute( builder: (context) => const CardDetailsScreen(), ), ); - }, - disabled: true, - ), - const Divider(height: 1), - ], - ), - ); - } + }, + disabled: true, + ), + const Divider(height: 1), + ], + ), + ); + } } class CardManagementTile extends StatelessWidget { final IconData icon; final String label; final VoidCallback onTap; - final bool disabled; + final bool disabled; const CardManagementTile({ super.key, required this.icon, required this.label, required this.onTap, - this.disabled = false, + this.disabled = false, }); @override @@ -102,20 +102,20 @@ class CardManagementTile extends StatelessWidget { return ListTile( leading: Icon( icon, - color: disabled ? theme.disabledColor : null, + color: disabled ? theme.disabledColor : null, ), title: Text( label, style: TextStyle( - color: disabled ? theme.disabledColor : null, + color: disabled ? theme.disabledColor : null, ), ), trailing: Icon( Symbols.arrow_right, size: 20, - color: disabled ? theme.disabledColor : null, + color: disabled ? theme.disabledColor : null, ), - onTap: disabled ? null : onTap, + onTap: disabled ? null : onTap, ); } -} \ No newline at end of file +} diff --git a/lib/features/customer_info/screens/customer_info_screen.dart b/lib/features/customer_info/screens/customer_info_screen.dart index f561b38..4da2df4 100644 --- a/lib/features/customer_info/screens/customer_info_screen.dart +++ b/lib/features/customer_info/screens/customer_info_screen.dart @@ -13,14 +13,14 @@ class CustomerInfoScreen extends StatefulWidget { class _CustomerInfoScreenState extends State { late final User user = widget.user; - - String _maskPrimaryId(String? primaryId) { - if (primaryId == null || primaryId.length <= 4) { - return primaryId ?? 'N/A'; - } - final lastFour = primaryId.substring(primaryId.length - 4); - return '*' * (primaryId.length - 4) + lastFour; - } + + String _maskPrimaryId(String? primaryId) { + if (primaryId == null || primaryId.length <= 4) { + return primaryId ?? 'N/A'; + } + final lastFour = primaryId.substring(primaryId.length - 4); + return '*' * (primaryId.length - 4) + lastFour; + } @override Widget build(BuildContext context) { @@ -92,10 +92,10 @@ class _CustomerInfoScreenState extends State { label: AppLocalizations.of(context).branchAddress, value: user.address ?? 'N/A', ), // Replace with Aadhar if available - InfoField( - label: AppLocalizations.of(context).primaryId, - value: _maskPrimaryId(user.primaryId), - ), // Replace with PAN if available + InfoField( + label: AppLocalizations.of(context).primaryId, + value: _maskPrimaryId(user.primaryId), + ), // Replace with PAN if available ], ), ), diff --git a/lib/features/dashboard/screens/dashboard_screen.dart b/lib/features/dashboard/screens/dashboard_screen.dart index 9eafb18..957b846 100644 --- a/lib/features/dashboard/screens/dashboard_screen.dart +++ b/lib/features/dashboard/screens/dashboard_screen.dart @@ -30,7 +30,8 @@ class DashboardScreen extends StatefulWidget { State createState() => _DashboardScreenState(); } -class _DashboardScreenState extends State with SingleTickerProviderStateMixin { +class _DashboardScreenState extends State + with SingleTickerProviderStateMixin { int selectedAccountIndex = 0; bool isVisible = false; bool isRefreshing = false; @@ -139,7 +140,7 @@ class _DashboardScreenState extends State with SingleTickerProv case 'sa': return AppLocalizations.of(context).savingsAccount; case 'sb': - return AppLocalizations.of(context).savingsAccount; + return AppLocalizations.of(context).savingsAccount; case 'ln': return AppLocalizations.of(context).loanAccount; case 'td': @@ -209,54 +210,54 @@ class _DashboardScreenState extends State with SingleTickerProv }, child: Scaffold( backgroundColor: theme.scaffoldBackgroundColor, -appBar: AppBar( - backgroundColor: theme.scaffoldBackgroundColor, - leading: Padding( - padding: const EdgeInsets.only(left: 10.0), - child: InkWell( - borderRadius: BorderRadius.circular(20), - onTap: () { - final authState = context.read().state; - String mobileNumberToPass = ''; + appBar: AppBar( + backgroundColor: theme.scaffoldBackgroundColor, + leading: Padding( + padding: const EdgeInsets.only(left: 10.0), + child: InkWell( + borderRadius: BorderRadius.circular(20), + onTap: () { + final authState = context.read().state; + String mobileNumberToPass = ''; - if (authState is Authenticated) { - if (selectedAccountIndex >= 0 && - selectedAccountIndex < authState.users.length) { - mobileNumberToPass = - authState.users[selectedAccountIndex].mobileNo ?? ''; - } - } + if (authState is Authenticated) { + if (selectedAccountIndex >= 0 && + selectedAccountIndex < authState.users.length) { + mobileNumberToPass = + authState.users[selectedAccountIndex].mobileNo ?? ''; + } + } - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - ProfileScreen(mobileNumber: mobileNumberToPass), + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + ProfileScreen(mobileNumber: mobileNumberToPass), + ), + ); + }, + child: CircleAvatar( + backgroundColor: Colors.grey[200], + radius: 20, + child: SvgPicture.asset( + 'assets/images/avatar_male.svg', + width: 40, + height: 40, + fit: BoxFit.cover, + ), + ), ), - ); - }, - child: CircleAvatar( - backgroundColor: Colors.grey[200], - radius: 20, - child: SvgPicture.asset( - 'assets/images/avatar_male.svg', - width: 40, - height: 40, - fit: BoxFit.cover, + ), + title: Text( + AppLocalizations.of(context).kccbMobile, + textAlign: TextAlign.left, + style: TextStyle( + color: theme.colorScheme.primary, + fontWeight: FontWeight.w700, + ), + ), + centerTitle: true, ), - ), - ), - ), - title: Text( - AppLocalizations.of(context).kccbMobile, - textAlign: TextAlign.left, - style: TextStyle( - color: theme.colorScheme.primary, - fontWeight: FontWeight.w700, - ), - ), - centerTitle: true, -), body: BlocBuilder( builder: (context, state) { if (state is AuthLoading || state is AuthInitial) { @@ -533,8 +534,9 @@ appBar: AppBar( .accountNo!, balance: users[selectedAccountIndex] .availableBalance!, - accountType: users[selectedAccountIndex] - .accountType!, + accountType: + users[selectedAccountIndex] + .accountType!, ))); }), _buildQuickLink(Symbols.checkbook, diff --git a/lib/features/dashboard/widgets/account_card.dart b/lib/features/dashboard/widgets/account_card.dart index 02228c0..66cacc1 100644 --- a/lib/features/dashboard/widgets/account_card.dart +++ b/lib/features/dashboard/widgets/account_card.dart @@ -72,4 +72,3 @@ class AccountCard extends StatelessWidget { ); } } - diff --git a/lib/features/enquiry/screens/enquiry_screen.dart b/lib/features/enquiry/screens/enquiry_screen.dart index 158d832..699e68f 100644 --- a/lib/features/enquiry/screens/enquiry_screen.dart +++ b/lib/features/enquiry/screens/enquiry_screen.dart @@ -30,15 +30,15 @@ class _EnquiryScreen extends State { } } - Future _launchUrl(String url) async { - final Uri uri = Uri.parse(url); - if (await canLaunchUrl(uri)) { - await launchUrl(uri); - } else { - // Consider adding a 'urlLaunchError' key to your AppLocalizations - debugPrint('Could not launch $url'); - } - } + Future _launchUrl(String url) async { + final Uri uri = Uri.parse(url); + if (await canLaunchUrl(uri)) { + await launchUrl(uri); + } else { + // Consider adding a 'urlLaunchError' key to your AppLocalizations + debugPrint('Could not launch $url'); + } + } Widget _buildContactItem(String role, String email, String phone) { return Column( @@ -75,29 +75,25 @@ class _EnquiryScreen extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const SizedBox(height: 20), - GestureDetector( - onTap: () => _launchUrl("https://kccb.in/complaint-form"), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text("Complaint Form", - style: TextStyle( - fontSize: 17, - color: Theme.of(context).colorScheme.primary, - decorationColor: Theme.of(context).colorScheme.primary, - ), - ), - const SizedBox(width: 4), - Icon( - Icons.open_in_new, - color: Theme.of(context).colorScheme.primary, - size: 16.0, - ), - ] -) - ), - + const SizedBox(height: 20), + GestureDetector( + onTap: () => _launchUrl("https://kccb.in/complaint-form"), + child: Row(mainAxisSize: MainAxisSize.min, children: [ + Text( + "Complaint Form", + style: TextStyle( + fontSize: 17, + color: Theme.of(context).colorScheme.primary, + decorationColor: Theme.of(context).colorScheme.primary, + ), + ), + const SizedBox(width: 4), + Icon( + Icons.open_in_new, + color: Theme.of(context).colorScheme.primary, + size: 16.0, + ), + ])), const SizedBox(height: 40), Text( AppLocalizations.of(context).keyContacts, diff --git a/lib/features/fund_transfer/screens/fund_transfer_amount_screen.dart b/lib/features/fund_transfer/screens/fund_transfer_amount_screen.dart index abbf314..98898f9 100644 --- a/lib/features/fund_transfer/screens/fund_transfer_amount_screen.dart +++ b/lib/features/fund_transfer/screens/fund_transfer_amount_screen.dart @@ -402,14 +402,14 @@ class _FundTransferAmountScreenState extends State { const SizedBox(height: 24), ], //Remarks - TextFormField( + TextFormField( controller: _remarksController, decoration: InputDecoration( - labelText: AppLocalizations.of(context).remarks, - border: const OutlineInputBorder(), - ), + labelText: AppLocalizations.of(context).remarks, + border: const OutlineInputBorder(), ), - const SizedBox(height: 24), + ), + const SizedBox(height: 24), // Amount TextFormField( controller: _amountController, diff --git a/lib/features/fund_transfer/screens/payment_animation.dart b/lib/features/fund_transfer/screens/payment_animation.dart index f53937a..b1aa521 100644 --- a/lib/features/fund_transfer/screens/payment_animation.dart +++ b/lib/features/fund_transfer/screens/payment_animation.dart @@ -213,7 +213,8 @@ class _PaymentAnimationScreenState extends State { ), label: Text( AppLocalizations.of(context).share, - style: TextStyle(color: Theme.of(context).colorScheme.primary), + style: TextStyle( + color: Theme.of(context).colorScheme.primary), ), style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric( diff --git a/lib/features/fund_transfer/screens/tpin_otp_screen.dart b/lib/features/fund_transfer/screens/tpin_otp_screen.dart index b26b10b..e632a44 100644 --- a/lib/features/fund_transfer/screens/tpin_otp_screen.dart +++ b/lib/features/fund_transfer/screens/tpin_otp_screen.dart @@ -18,8 +18,9 @@ class _TpinOtpScreenState extends State { 6, (_) => TextEditingController(), ); - bool _isLoading = false; - final ChangePasswordService _changePasswordService = getIt(); + bool _isLoading = false; + final ChangePasswordService _changePasswordService = + getIt(); @override void dispose() { @@ -33,7 +34,7 @@ class _TpinOtpScreenState extends State { } void _onOtpChanged(int idx, String value) { - if (value.length == 1 && idx <5) { + if (value.length == 1 && idx < 5) { _focusNodes[idx + 1].requestFocus(); } if (value.isEmpty && idx > 0) { @@ -44,160 +45,160 @@ class _TpinOtpScreenState extends State { String get _enteredOtp => _controllers.map((c) => c.text).join(); -void _verifyOtp() async { - setState(() { - _isLoading = true; - }); + void _verifyOtp() async { + setState(() { + _isLoading = true; + }); - try { - await _changePasswordService.validateOtp( - otp: _enteredOtp, - mobileNumber: widget.mobileNumber, - ); + try { + await _changePasswordService.validateOtp( + otp: _enteredOtp, + mobileNumber: widget.mobileNumber, + ); - if (mounted) { - Navigator.pushReplacement( - context, - MaterialPageRoute(builder: (_) => const TpinSetScreen()), - ); - } - } catch (e) { - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(AppLocalizations.of(context).invalidOtp)), - ); - } - } finally { - if (mounted) { - setState(() { - _isLoading = false; - }); + if (mounted) { + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (_) => const TpinSetScreen()), + ); + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(AppLocalizations.of(context).invalidOtp)), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } } } -} @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - return Scaffold( - appBar: AppBar( - title: Text(AppLocalizations.of(context).enterOtp), - centerTitle: true, - elevation: 0, - ), - body: Center( - child: SingleChildScrollView( - child: Column( - children: [ - Icon( - Icons.lock_outline, - size: 48, - color: theme.colorScheme.primary, - ), - const SizedBox(height: 16), - Text( - AppLocalizations.of(context).otpVerification, - style: theme.textTheme.titleLarge?.copyWith( - fontWeight: FontWeight.bold, - color: theme.colorScheme.primary, - ), - ), - const SizedBox(height: 8), - Text( - AppLocalizations.of(context).otpSentMessage, - textAlign: TextAlign.center, - style: theme.textTheme.bodyMedium?.copyWith( - color: Colors.grey[700], - ), - ), - const SizedBox(height: 32), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: List.generate(6, (i) { - return Container( - width: 32, - margin: const EdgeInsets.symmetric(horizontal: 8), - child: TextField( - controller: _controllers[i], - focusNode: _focusNodes[i], - keyboardType: TextInputType.number, - textAlign: TextAlign.center, - maxLength: 1, - obscureText: true, - obscuringCharacter: '*', - decoration: InputDecoration( - counterText: '', - filled: true, - fillColor: Theme.of(context).primaryColorLight, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide( - color: theme.colorScheme.primary, - width: 2, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide( - color: theme.colorScheme.primary, - width: 2.5, - ), - ), - ), - onChanged: (val) => _onOtpChanged(i, val), - ), - ); - }), - ), - const SizedBox(height: 32), - ElevatedButton.icon( - icon: _isLoading - ? const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - color: Colors.white, - strokeWidth: 2, - ), - ) - : const Icon(Icons.verified_user_rounded), - label: Text( - AppLocalizations.of(context).verifyOtp, - style: const TextStyle( - fontSize: 18, fontWeight: FontWeight.w600), - ), - style: ElevatedButton.styleFrom( - backgroundColor: theme.colorScheme.onPrimary, - padding: const EdgeInsets.symmetric( - vertical: 14, - horizontal: 28, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(30), - ), - ), - // Update onPressed to handle loading state - onPressed: (_enteredOtp.length == 6 && !_isLoading) - ? _verifyOtp - : null, - ), - const SizedBox(height: 16), - TextButton( - onPressed: () { - // You can also add a getOtp call here for resending - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(AppLocalizations.of(context).otpResent), - ), - ); - }, - child: Text(AppLocalizations.of(context).resendOtp), - ), - const SizedBox(height: 60), - ], - ), - ), - ), - ); - } - } + Widget build(BuildContext context) { + final theme = Theme.of(context); + return Scaffold( + appBar: AppBar( + title: Text(AppLocalizations.of(context).enterOtp), + centerTitle: true, + elevation: 0, + ), + body: Center( + child: SingleChildScrollView( + child: Column( + children: [ + Icon( + Icons.lock_outline, + size: 48, + color: theme.colorScheme.primary, + ), + const SizedBox(height: 16), + Text( + AppLocalizations.of(context).otpVerification, + style: theme.textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.bold, + color: theme.colorScheme.primary, + ), + ), + const SizedBox(height: 8), + Text( + AppLocalizations.of(context).otpSentMessage, + textAlign: TextAlign.center, + style: theme.textTheme.bodyMedium?.copyWith( + color: Colors.grey[700], + ), + ), + const SizedBox(height: 32), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: List.generate(6, (i) { + return Container( + width: 32, + margin: const EdgeInsets.symmetric(horizontal: 8), + child: TextField( + controller: _controllers[i], + focusNode: _focusNodes[i], + keyboardType: TextInputType.number, + textAlign: TextAlign.center, + maxLength: 1, + obscureText: true, + obscuringCharacter: '*', + decoration: InputDecoration( + counterText: '', + filled: true, + fillColor: Theme.of(context).primaryColorLight, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: theme.colorScheme.primary, + width: 2, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: theme.colorScheme.primary, + width: 2.5, + ), + ), + ), + onChanged: (val) => _onOtpChanged(i, val), + ), + ); + }), + ), + const SizedBox(height: 32), + ElevatedButton.icon( + icon: _isLoading + ? const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + color: Colors.white, + strokeWidth: 2, + ), + ) + : const Icon(Icons.verified_user_rounded), + label: Text( + AppLocalizations.of(context).verifyOtp, + style: const TextStyle( + fontSize: 18, fontWeight: FontWeight.w600), + ), + style: ElevatedButton.styleFrom( + backgroundColor: theme.colorScheme.onPrimary, + padding: const EdgeInsets.symmetric( + vertical: 14, + horizontal: 28, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(30), + ), + ), + // Update onPressed to handle loading state + onPressed: (_enteredOtp.length == 6 && !_isLoading) + ? _verifyOtp + : null, + ), + const SizedBox(height: 16), + TextButton( + onPressed: () { + // You can also add a getOtp call here for resending + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(AppLocalizations.of(context).otpResent), + ), + ); + }, + child: Text(AppLocalizations.of(context).resendOtp), + ), + const SizedBox(height: 60), + ], + ), + ), + ), + ); + } +} diff --git a/lib/features/fund_transfer/screens/tpin_prompt_screen.dart b/lib/features/fund_transfer/screens/tpin_prompt_screen.dart index 00f5c99..e12f972 100644 --- a/lib/features/fund_transfer/screens/tpin_prompt_screen.dart +++ b/lib/features/fund_transfer/screens/tpin_prompt_screen.dart @@ -15,44 +15,50 @@ class TpinSetupPromptScreen extends StatefulWidget { State createState() => _TpinSetupPromptScreenState(); } - class _TpinSetupPromptScreenState extends State { - int selectedAccountIndex = 0; - bool _isLoading = false; - final ChangePasswordService _changePasswordService = getIt(); - Future _getOtp() async { - setState(() { - _isLoading = true; - }); +class _TpinSetupPromptScreenState extends State { + int selectedAccountIndex = 0; + bool _isLoading = false; + final ChangePasswordService _changePasswordService = + getIt(); + Future _getOtp() async { + setState(() { + _isLoading = true; + }); - try { - final authState = context.read().state; - String mobileNumberToPass = ''; - if (authState is Authenticated) { - if (selectedAccountIndex >= 0 && selectedAccountIndex < authState.users.length) { - mobileNumberToPass = authState.users[selectedAccountIndex].mobileNo ?? ''; - } - } - await _changePasswordService.getOtpTpin(mobileNumber: mobileNumberToPass); - if (mounted) { - Navigator.pushReplacement( - context, - MaterialPageRoute(builder: (_) => TpinOtpScreen(mobileNumber: mobileNumberToPass,)), - ); - } - } catch (e) { - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Error: ${e.toString()}')), - ); - } - } finally { - if (mounted) { - setState(() { - _isLoading = false; - }); + try { + final authState = context.read().state; + String mobileNumberToPass = ''; + if (authState is Authenticated) { + if (selectedAccountIndex >= 0 && + selectedAccountIndex < authState.users.length) { + mobileNumberToPass = + authState.users[selectedAccountIndex].mobileNo ?? ''; + } + } + await _changePasswordService.getOtpTpin(mobileNumber: mobileNumberToPass); + if (mounted) { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (_) => TpinOtpScreen( + mobileNumber: mobileNumberToPass, + )), + ); + } + } catch (e) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Error: ${e.toString()}')), + ); + } + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } } } -} @override Widget build(BuildContext context) { @@ -86,33 +92,35 @@ class TpinSetupPromptScreen extends StatefulWidget { ), ), const SizedBox(height: 32), -ElevatedButton.icon( - icon: _isLoading - ? const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - color: Colors.white, - strokeWidth: 2, - ), - ) - : const Icon(Icons.arrow_forward_rounded), - label: Text( - AppLocalizations.of(context).setTpin, - style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600), - ), - style: ElevatedButton.styleFrom( - backgroundColor: theme.colorScheme.onPrimary, - padding: const EdgeInsets.symmetric( - vertical: 14, - horizontal: 32, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - ), - onPressed: _isLoading ? null : _getOtp, // <-- Use the new function -), + ElevatedButton.icon( + icon: _isLoading + ? const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + color: Colors.white, + strokeWidth: 2, + ), + ) + : const Icon(Icons.arrow_forward_rounded), + label: Text( + AppLocalizations.of(context).setTpin, + style: + const TextStyle(fontSize: 18, fontWeight: FontWeight.w600), + ), + style: ElevatedButton.styleFrom( + backgroundColor: theme.colorScheme.onPrimary, + padding: const EdgeInsets.symmetric( + vertical: 14, + horizontal: 32, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + onPressed: + _isLoading ? null : _getOtp, // <-- Use the new function + ), const SizedBox(height: 18), Padding( padding: const EdgeInsets.symmetric(horizontal: 18.0), @@ -129,4 +137,4 @@ ElevatedButton.icon( ), ); } -} \ No newline at end of file +} diff --git a/lib/features/fund_transfer/screens/transaction_pin_screen.dart b/lib/features/fund_transfer/screens/transaction_pin_screen.dart index ecf76dc..8721769 100644 --- a/lib/features/fund_transfer/screens/transaction_pin_screen.dart +++ b/lib/features/fund_transfer/screens/transaction_pin_screen.dart @@ -212,4 +212,3 @@ class _TransactionPinScreenState extends State ); } } - diff --git a/lib/features/fund_transfer/screens/transaction_success_screen.dart b/lib/features/fund_transfer/screens/transaction_success_screen.dart index 6f5ac8e..b2c921e 100644 --- a/lib/features/fund_transfer/screens/transaction_success_screen.dart +++ b/lib/features/fund_transfer/screens/transaction_success_screen.dart @@ -67,13 +67,23 @@ class _TransactionSuccessScreen extends State { const SizedBox(height: 6), Text( "On $transactionDate", - style: TextStyle(fontSize: 14, color: Theme.of(context).colorScheme.onSurface.withOpacity(0.6)), + style: TextStyle( + fontSize: 14, + color: Theme.of(context) + .colorScheme + .onSurface + .withOpacity(0.6)), textAlign: TextAlign.center, ), const SizedBox(height: 16), Text( "${AppLocalizations.of(context).toAccountNumber}: $creditAccount", - style: TextStyle(fontSize: 12, color: Theme.of(context).colorScheme.onSurface.withOpacity(0.8)), + style: TextStyle( + fontSize: 12, + color: Theme.of(context) + .colorScheme + .onSurface + .withOpacity(0.8)), textAlign: TextAlign.center, ), ], @@ -91,8 +101,12 @@ class _TransactionSuccessScreen extends State { child: OutlinedButton.icon( onPressed: _shareScreenshot, icon: const Icon(Icons.share, size: 18), - label: Text(AppLocalizations.of(context).share, - style: TextStyle(color: Theme.of(context).colorScheme.onPrimaryContainer), + label: Text( + AppLocalizations.of(context).share, + style: TextStyle( + color: Theme.of(context) + .colorScheme + .onPrimaryContainer), ), style: ElevatedButton.styleFrom( shape: const StadiumBorder(), diff --git a/lib/features/profile/change_password/change_password_otp_screen.dart b/lib/features/profile/change_password/change_password_otp_screen.dart index 5ca964b..562c3d1 100644 --- a/lib/features/profile/change_password/change_password_otp_screen.dart +++ b/lib/features/profile/change_password/change_password_otp_screen.dart @@ -14,12 +14,13 @@ class ChangePasswordOTPScreen extends StatefulWidget { const ChangePasswordOTPScreen({ required this.currentPassword, required this.newPassword, - required this.confirmPassword, + required this.confirmPassword, required this.mobileNumber, }); @override - State createState() => _ChangePasswordOTPScreenState(); + State createState() => + _ChangePasswordOTPScreenState(); } class _ChangePasswordOTPScreenState extends State { @@ -36,33 +37,33 @@ class _ChangePasswordOTPScreenState extends State { }); }); } + final changePasswordService = getIt(); Future _validateOTP() async { - try { - await changePasswordService.validateOtp( - otp: otpController.text, - mobileNumber: widget.mobileNumber, - ); + try { + await changePasswordService.validateOtp( + otp: otpController.text, + mobileNumber: widget.mobileNumber, + ); - // If OTP is valid, then change the password - await changePasswordService.validateChangePwd( - OldLPsw: widget.currentPassword, - newLPsw: widget.newPassword, - confirmLPsw: widget.confirmPassword, - ); - - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(AppLocalizations.of(context).pwdchangeSuccess)), - ); + // If OTP is valid, then change the password + await changePasswordService.validateChangePwd( + OldLPsw: widget.currentPassword, + newLPsw: widget.newPassword, + confirmLPsw: widget.confirmPassword, + ); - // Navigate back to profile or login - Navigator.of(context).popUntil((route) => route.isFirst); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(AppLocalizations.of(context).pwdchangeSuccess)), + ); -} catch (e) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(AppLocalizations.of(context).invalidOtp)), - ); -} + // Navigate back to profile or login + Navigator.of(context).popUntil((route) => route.isFirst); + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(AppLocalizations.of(context).invalidOtp)), + ); + } } @override @@ -106,4 +107,4 @@ class _ChangePasswordOTPScreenState extends State { ), ); } -} \ No newline at end of file +} diff --git a/lib/features/profile/change_password/change_password_screen.dart b/lib/features/profile/change_password/change_password_screen.dart index 0f0c880..3a60a9f 100644 --- a/lib/features/profile/change_password/change_password_screen.dart +++ b/lib/features/profile/change_password/change_password_screen.dart @@ -56,38 +56,40 @@ class _ChangePasswordScreenState extends State { } return null; } -final ChangePasswordService _changePasswordService = getIt(); -void _proceed() async { - if (_formKey.currentState!.validate()) { + final ChangePasswordService _changePasswordService = + getIt(); + void _proceed() async { + if (_formKey.currentState!.validate()) { + try { + await _changePasswordService.getOtp(mobileNumber: widget.mobileNumber); - try { - await _changePasswordService.getOtp(mobileNumber: widget.mobileNumber); - - - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ChangePasswordOTPScreen( - currentPassword: currentPasswordController.text, - newPassword: newPasswordController.text, - confirmPassword: confirmPasswordController.text, - mobileNumber: widget.mobileNumber, + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ChangePasswordOTPScreen( + currentPassword: currentPasswordController.text, + newPassword: newPasswordController.text, + confirmPassword: confirmPasswordController.text, + mobileNumber: widget.mobileNumber, + ), ), - ), - ); - } catch (e) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('${AppLocalizations.of(context).failedtosentOTP}: $e')), - ); + ); + } catch (e) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: + Text('${AppLocalizations.of(context).failedtosentOTP}: $e')), + ); + } } } -} @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text(AppLocalizations.of(context).changeLoginPassword)), + appBar: + AppBar(title: Text(AppLocalizations.of(context).changeLoginPassword)), body: Padding( padding: const EdgeInsets.all(16), child: Form( @@ -103,8 +105,8 @@ void _proceed() async { icon: Icon(_showCurrentPassword ? Icons.visibility : Icons.visibility_off), - onPressed: () => - setState(() => _showCurrentPassword = !_showCurrentPassword), + onPressed: () => setState( + () => _showCurrentPassword = !_showCurrentPassword), ), ), validator: validateCurrentPassword, @@ -135,8 +137,8 @@ void _proceed() async { icon: Icon(_showConfirmPassword ? Icons.visibility : Icons.visibility_off), - onPressed: () => - setState(() => _showConfirmPassword = !_showConfirmPassword), + onPressed: () => setState( + () => _showConfirmPassword = !_showConfirmPassword), ), ), validator: validateConfirmPassword, @@ -152,4 +154,4 @@ void _proceed() async { ), ); } -} \ No newline at end of file +} diff --git a/lib/features/profile/logout_dialog.dart b/lib/features/profile/logout_dialog.dart index 101ccd6..cdbdf17 100644 --- a/lib/features/profile/logout_dialog.dart +++ b/lib/features/profile/logout_dialog.dart @@ -22,4 +22,4 @@ class LogoutDialog extends StatelessWidget { ], ); } -} \ No newline at end of file +} diff --git a/lib/features/profile/preferences/theme_mode_dialog.dart b/lib/features/profile/preferences/theme_mode_dialog.dart index 6cffc3f..2ed7a25 100644 --- a/lib/features/profile/preferences/theme_mode_dialog.dart +++ b/lib/features/profile/preferences/theme_mode_dialog.dart @@ -17,13 +17,13 @@ String _getThemeModeText(ThemeMode mode, AppLocalizations l10n) { Future showThemeModeDialog(BuildContext context) async { final cubit = context.read(); final currentMode = context.read().state.mode; - final l10n = AppLocalizations.of(context); + final l10n = AppLocalizations.of(context); await showDialog( context: context, builder: (context) { return AlertDialog( - title: Text(l10n.selectThemeMode), + title: Text(l10n.selectThemeMode), content: Column( mainAxisSize: MainAxisSize.min, children: ThemeMode.values.map((mode) { @@ -43,4 +43,4 @@ Future showThemeModeDialog(BuildContext context) async { ); }, ); -} \ No newline at end of file +} diff --git a/lib/features/profile/profile_screen.dart b/lib/features/profile/profile_screen.dart index 2910e3c..6798f75 100644 --- a/lib/features/profile/profile_screen.dart +++ b/lib/features/profile/profile_screen.dart @@ -6,6 +6,7 @@ import 'package:kmobile/features/profile/change_password/change_password_screen. import 'package:kmobile/features/profile/logout_dialog.dart'; import 'package:kmobile/security/secure_storage.dart'; import 'package:local_auth/local_auth.dart'; +import 'package:package_info_plus/package_info_plus.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../di/injection.dart'; import '../../l10n/app_localizations.dart'; @@ -20,22 +21,27 @@ class ProfileScreen extends StatefulWidget { } class _ProfileScreenState extends State { - bool _isBiometricEnabled = false; - @override - void initState() { - super.initState(); - _loadBiometricStatus(); - } + bool _isBiometricEnabled = false; + @override + void initState() { + super.initState(); + _loadBiometricStatus(); + } - Future _loadBiometricStatus() async { - final storage = getIt(); - final isEnabled = await storage.read('biometric_enabled'); - setState(() { - _isBiometricEnabled = isEnabled == 'true'; - }); - } + Future _getAppVersion() async { + final PackageInfo info = await PackageInfo.fromPlatform(); + return 'Version ${info.version} (${info.buildNumber})'; + } - Future _handleLogout(BuildContext context) async { + Future _loadBiometricStatus() async { + final storage = getIt(); + final isEnabled = await storage.read('biometric_enabled'); + setState(() { + _isBiometricEnabled = isEnabled == 'true'; + }); + } + + Future _handleLogout(BuildContext context) async { final auth = getIt(); final prefs = await SharedPreferences.getInstance(); await prefs.clear(); // clear saved session/token @@ -44,89 +50,89 @@ class _ProfileScreenState extends State { Navigator.pushNamedAndRemoveUntil(context, '/login', (route) => false); } - - Future _handleBiometricToggle(bool enable) async { - final localAuth = LocalAuthentication(); - final storage = getIt(); - final canCheck = await localAuth.canCheckBiometrics; + Future _handleBiometricToggle(bool enable) async { + final localAuth = LocalAuthentication(); + final storage = getIt(); + final canCheck = await localAuth.canCheckBiometrics; - if (!canCheck) { - // Optional: Show a snackbar or dialog if biometrics are not available - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(AppLocalizations.of(context).biometricsNotAvailable)), - ); - return; - } + if (!canCheck) { + // Optional: Show a snackbar or dialog if biometrics are not available + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(AppLocalizations.of(context).biometricsNotAvailable)), + ); + return; + } - if (enable) { - // Show "Enable" dialog - final optIn = await showDialog( - context: context, - barrierDismissible: false, - builder: (ctx) => AlertDialog( - title: Text(AppLocalizations.of(context).enableFingerprintLogin), - content: Text(AppLocalizations.of(context).enableFingerprintMessage), - actions: [ - TextButton( - onPressed: () => Navigator.of(ctx).pop(false), - child: Text(AppLocalizations.of(context).no), - ), - TextButton( - onPressed: () => Navigator.of(ctx).pop(true), - child: Text(AppLocalizations.of(context).yes), - ), - ], - ), - ); + if (enable) { + // Show "Enable" dialog + final optIn = await showDialog( + context: context, + barrierDismissible: false, + builder: (ctx) => AlertDialog( + title: Text(AppLocalizations.of(context).enableFingerprintLogin), + content: Text(AppLocalizations.of(context).enableFingerprintMessage), + actions: [ + TextButton( + onPressed: () => Navigator.of(ctx).pop(false), + child: Text(AppLocalizations.of(context).no), + ), + TextButton( + onPressed: () => Navigator.of(ctx).pop(true), + child: Text(AppLocalizations.of(context).yes), + ), + ], + ), + ); - if (optIn == true) { - try { - final didAuth = await localAuth.authenticate( - localizedReason: AppLocalizations.of(context).authenticateToEnable, - options: const AuthenticationOptions( - stickyAuth: true, - biometricOnly: true, - ), - ); - if (didAuth) { - await storage.write('biometric_enabled', 'true'); - setState(() { - _isBiometricEnabled = true; - }); - } - } catch (e) { - // Handle authentication errors - } - } - } else { - // Show "Disable" dialog - final optOut = await showDialog( - context: context, - barrierDismissible: false, - builder: (ctx) => AlertDialog( - title: Text(AppLocalizations.of(context).disableFingerprintLogin), - content: Text(AppLocalizations.of(context).disableFingerprintMessage), - actions: [ - TextButton( - onPressed: () => Navigator.of(ctx).pop(false), - child: Text(AppLocalizations.of(context).no), - ), - TextButton( - onPressed: () => Navigator.of(ctx).pop(true), - child: Text(AppLocalizations.of(context).yes), - ), - ], - ), - ); + if (optIn == true) { + try { + final didAuth = await localAuth.authenticate( + localizedReason: AppLocalizations.of(context).authenticateToEnable, + options: const AuthenticationOptions( + stickyAuth: true, + biometricOnly: true, + ), + ); + if (didAuth) { + await storage.write('biometric_enabled', 'true'); + setState(() { + _isBiometricEnabled = true; + }); + } + } catch (e) { + // Handle authentication errors + } + } + } else { + // Show "Disable" dialog + final optOut = await showDialog( + context: context, + barrierDismissible: false, + builder: (ctx) => AlertDialog( + title: Text(AppLocalizations.of(context).disableFingerprintLogin), + content: Text(AppLocalizations.of(context).disableFingerprintMessage), + actions: [ + TextButton( + onPressed: () => Navigator.of(ctx).pop(false), + child: Text(AppLocalizations.of(context).no), + ), + TextButton( + onPressed: () => Navigator.of(ctx).pop(true), + child: Text(AppLocalizations.of(context).yes), + ), + ], + ), + ); - if (optOut == true) { - await storage.write('biometric_enabled', 'false'); - setState(() { - _isBiometricEnabled = false; - }); - } - } - } + if (optOut == true) { + await storage.write('biometric_enabled', 'false'); + setState(() { + _isBiometricEnabled = false; + }); + } + } + } @override Widget build(BuildContext context) { @@ -140,7 +146,7 @@ class _ProfileScreenState extends State { children: [ ListTile( leading: const Icon(Icons.settings), - title: Text(loc.preferences), + title: Text(loc.preferences), onTap: () { Navigator.push( context, @@ -149,71 +155,93 @@ class _ProfileScreenState extends State { ); }, ), - SwitchListTile( - title: Text(AppLocalizations.of(context).enableFingerprintLogin), - value: _isBiometricEnabled, - onChanged: (bool value) { - _handleBiometricToggle(value); - }, - secondary: const Icon(Icons.fingerprint), - ), + SwitchListTile( + title: Text(AppLocalizations.of(context).enableFingerprintLogin), + value: _isBiometricEnabled, + onChanged: (bool value) { + _handleBiometricToggle(value); + }, + secondary: const Icon(Icons.fingerprint), + ), ListTile( leading: const Icon(Icons.password), - title: Text(loc.changeLoginPassword), + title: Text(loc.changeLoginPassword), onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => ChangePasswordScreen( - mobileNumber: widget.mobileNumber, - )), - ); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ChangePasswordScreen( + mobileNumber: widget.mobileNumber, + )), + ); }, ), // ListTile( // leading: const Icon(Icons.password), - // title: const Text("Manage TPIN"), + // title: const Text("Manage TPIN"), // onTap: () async { // }, // ), // ListTile( // leading: const Icon(Icons.password), - // title: const Text("Change Login MPIN"), + // title: const Text("Change Login MPIN"), // onTap: () async { // }, // ), ListTile( - leading: const Icon(Icons.exit_to_app), - title: Text(AppLocalizations.of(context).logout), - onTap: () async { - final shouldExit = await showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text(AppLocalizations.of(context).logout), - content: Text(AppLocalizations.of(context).logoutCheck), - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(false), - child: Text(AppLocalizations.of(context).no), + leading: const Icon(Icons.smartphone), + title: const Text("App Version"), + trailing: FutureBuilder( + future: _getAppVersion(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + // Show a loading indicator while waiting for the future to complete + return const CircularProgressIndicator(); + } else if (snapshot.hasError) { + return const Text("Error"); + } else { + // Display the version number once the future is complete + return Text( + snapshot.data ?? "N/A", + selectionColor: const Color(0xFFFFFFFF), + ); + } + }, + ), ), - TextButton( - onPressed: () => Navigator.of(context).pop(true), - child: Text(AppLocalizations.of(context).yes), - ), - ], - ), - ); + ListTile( + leading: const Icon(Icons.exit_to_app), + title: Text(AppLocalizations.of(context).logout), + onTap: () async { + final shouldExit = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(AppLocalizations.of(context).logout), + content: Text(AppLocalizations.of(context).logoutCheck), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: Text(AppLocalizations.of(context).no), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + child: Text(AppLocalizations.of(context).yes), + ), + ], + ), + ); - if (shouldExit == true) { - if (Platform.isAndroid) { - SystemNavigator.pop(); - } - exit(0); - } - }, -), - ListTile( + if (shouldExit == true) { + if (Platform.isAndroid) { + SystemNavigator.pop(); + } + exit(0); + } + }, + ), + ListTile( leading: const Icon(Icons.logout), - title: Text(AppLocalizations.of(context).deregister), + title: Text(AppLocalizations.of(context).deregister), onTap: () async { final shouldLogout = await showDialog( context: context, diff --git a/lib/features/quick_pay/screens/quick_pay_outside_bank_screen.dart b/lib/features/quick_pay/screens/quick_pay_outside_bank_screen.dart index 7fe9408..ea1b36a 100644 --- a/lib/features/quick_pay/screens/quick_pay_outside_bank_screen.dart +++ b/lib/features/quick_pay/screens/quick_pay_outside_bank_screen.dart @@ -51,10 +51,10 @@ class _QuickPayOutsideBankScreen extends State { void initState() { super.initState(); _ifscFocusNode.addListener(() { - if (!_ifscFocusNode.hasFocus && ifscController.text.trim().length == 11) { - _validateIFSC(); - } -}); + if (!_ifscFocusNode.hasFocus && ifscController.text.trim().length == 11) { + _validateIFSC(); + } + }); WidgetsBinding.instance.addPostFrameCallback((_) { setState(() { accountType = 'Savings'; @@ -67,7 +67,7 @@ class _QuickPayOutsideBankScreen extends State { if (ifsc.isEmpty) return; try { - final result = await service.validateIFSC(ifsc); + final result = await service.validateIFSC(ifsc); if (mounted) { if (result.bankName.isEmpty) { @@ -84,7 +84,8 @@ class _QuickPayOutsideBankScreen extends State { } catch (e) { if (mounted) { final errorMessage = e.toString().toUpperCase(); - String snackbarMessage = AppLocalizations.of(context).somethingWentWrong; + String snackbarMessage = + AppLocalizations.of(context).somethingWentWrong; if (errorMessage.contains('INVALID') && errorMessage.contains('IFSC')) { snackbarMessage = AppLocalizations.of(context).invalidIfsc; @@ -97,7 +98,7 @@ class _QuickPayOutsideBankScreen extends State { branchNameController.clear(); } } - } + } void _validateBeneficiary() async { FocusScope.of(context).unfocus(); @@ -527,15 +528,15 @@ class _QuickPayOutsideBankScreen extends State { controller: ifscController, textInputAction: TextInputAction.next, onChanged: (value) { - setState(() { - final trimmed = value.trim().toUpperCase(); - if (trimmed.length < 11) { - // clear bank/branch if backspace or changed - bankNameController.clear(); - branchNameController.clear(); - } - }); - }, + setState(() { + final trimmed = value.trim().toUpperCase(); + if (trimmed.length < 11) { + // clear bank/branch if backspace or changed + bankNameController.clear(); + branchNameController.clear(); + } + }); + }, validator: (value) { final pattern = RegExp(r'^[A-Z]{4}0[A-Z0-9]{6}$'); if (value == null || value.trim().isEmpty) { @@ -637,20 +638,21 @@ class _QuickPayOutsideBankScreen extends State { child: SizedBox( width: double.infinity, child: ElevatedButton( - onPressed: _isValidating || ifscController.text.length != 11 - ? null - : () { - if (confirmAccountNumberController.text == - accountNumberController.text) { - _validateBeneficiary(); - } else { - setState(() { - _validationError = - AppLocalizations.of(context) - .accountMismatch; - }); - } - }, + onPressed: + _isValidating || ifscController.text.length != 11 + ? null + : () { + if (confirmAccountNumberController.text == + accountNumberController.text) { + _validateBeneficiary(); + } else { + setState(() { + _validationError = + AppLocalizations.of(context) + .accountMismatch; + }); + } + }, child: _isValidating ? const SizedBox( width: 20, @@ -696,25 +698,25 @@ class _QuickPayOutsideBankScreen extends State { return null; }, ), - const SizedBox(height: 25), - TextFormField( - controller: remarksController, - decoration: InputDecoration( - labelText: AppLocalizations.of(context).remarks, - border: const OutlineInputBorder(), - isDense: true, - filled: true, - fillColor: Theme.of(context).scaffoldBackgroundColor, - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context).colorScheme.outline), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context).colorScheme.primary, width: 2), - ), - ), - ), + const SizedBox(height: 25), + TextFormField( + controller: remarksController, + decoration: InputDecoration( + labelText: AppLocalizations.of(context).remarks, + border: const OutlineInputBorder(), + isDense: true, + filled: true, + fillColor: Theme.of(context).scaffoldBackgroundColor, + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.outline), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.primary, width: 2), + ), + ), + ), const SizedBox(height: 25), Row( children: [ diff --git a/lib/features/quick_pay/screens/quick_pay_within_bank_screen.dart b/lib/features/quick_pay/screens/quick_pay_within_bank_screen.dart index 6c27b99..1f1c3d9 100644 --- a/lib/features/quick_pay/screens/quick_pay_within_bank_screen.dart +++ b/lib/features/quick_pay/screens/quick_pay_within_bank_screen.dart @@ -58,7 +58,7 @@ class _QuickPayWithinBankScreen extends State { accountNumberController.dispose(); confirmAccountNumberController.dispose(); amountController.dispose(); - remarksController.dispose(); + remarksController.dispose(); super.dispose(); } @@ -278,24 +278,24 @@ class _QuickPayWithinBankScreen extends State { }, ), const SizedBox(height: 25), -TextFormField( - controller: remarksController, - decoration: InputDecoration( - labelText: AppLocalizations.of(context).remarks, - border: const OutlineInputBorder(), - isDense: true, - filled: true, - fillColor: Theme.of(context).scaffoldBackgroundColor, - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context).colorScheme.outline), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: Theme.of(context).colorScheme.primary, width: 2), - ), - ), -), + TextFormField( + controller: remarksController, + decoration: InputDecoration( + labelText: AppLocalizations.of(context).remarks, + border: const OutlineInputBorder(), + isDense: true, + filled: true, + fillColor: Theme.of(context).scaffoldBackgroundColor, + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.outline), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.primary, width: 2), + ), + ), + ), const SizedBox(height: 25), TextFormField( decoration: InputDecoration( diff --git a/lib/features/security/security_error_screen.dart b/lib/features/security/security_error_screen.dart index 01698a1..302d931 100644 --- a/lib/features/security/security_error_screen.dart +++ b/lib/features/security/security_error_screen.dart @@ -5,7 +5,8 @@ import 'package:lottie/lottie.dart'; class SecurityErrorScreen extends StatelessWidget { final String message; - const SecurityErrorScreen({Key? key, required this.message}) : super(key: key); + const SecurityErrorScreen({Key? key, required this.message}) + : super(key: key); @override Widget build(BuildContext context) { @@ -24,7 +25,8 @@ class SecurityErrorScreen extends StatelessWidget { ), const SizedBox(height: 40), ElevatedButton( - onPressed: () => SystemChannels.platform.invokeMethod('SystemNavigator.pop'), + onPressed: () => + SystemChannels.platform.invokeMethod('SystemNavigator.pop'), child: const Text('Okay'), ), ], diff --git a/lib/features/service/screens/branch_locator_screen.dart b/lib/features/service/screens/branch_locator_screen.dart index e0080e6..8f5f3b8 100644 --- a/lib/features/service/screens/branch_locator_screen.dart +++ b/lib/features/service/screens/branch_locator_screen.dart @@ -29,45 +29,45 @@ class BranchLocatorScreen extends StatefulWidget { State createState() => _BranchLocatorScreenState(); } - class _BranchLocatorScreenState extends State { - final TextEditingController _searchController = TextEditingController(); +class _BranchLocatorScreenState extends State { + final TextEditingController _searchController = TextEditingController(); - final List _allLocations = [ - Location( - name: "Dharamsala - Head Office", - code: "002", - ifsc: "KACE0000002", - address: "Civil Lines Dharmashala, Kangra, HP - 176215", - type: LocationType.branch, - ), - Location( - name: "Kangra", - code: "033", - ifsc: "KACE0000033", - address: "Rajput Bhawankangrapo, Kangra, HP ", - type: LocationType.branch, - ), - Location( - name: "Dharamsala ATM", - address: "Near Main Square, Dharamsala", - type: LocationType.atm, - ), - Location( - name: "Kangra ATM", - address: "Opposite Bus Stand, Kangra", - type: LocationType.atm, - ), - ]; + final List _allLocations = [ + Location( + name: "Dharamsala - Head Office", + code: "002", + ifsc: "KACE0000002", + address: "Civil Lines Dharmashala, Kangra, HP - 176215", + type: LocationType.branch, + ), + Location( + name: "Kangra", + code: "033", + ifsc: "KACE0000033", + address: "Rajput Bhawankangrapo, Kangra, HP ", + type: LocationType.branch, + ), + Location( + name: "Dharamsala ATM", + address: "Near Main Square, Dharamsala", + type: LocationType.atm, + ), + Location( + name: "Kangra ATM", + address: "Opposite Bus Stand, Kangra", + type: LocationType.atm, + ), + ]; - List _filteredLocations = []; - bool _isLoading = false; + List _filteredLocations = []; + bool _isLoading = false; -@override -void initState() { - super.initState(); - // _fetchAndSetLocations(); - _filteredLocations = _allLocations; -} + @override + void initState() { + super.initState(); + // _fetchAndSetLocations(); + _filteredLocations = _allLocations; + } // Example of a future API fetching function /* @@ -90,99 +90,99 @@ Future _fetchAndSetLocations() async { } } */ -void _filterLocations(String query) { - setState(() { - if (query.isEmpty) { - _filteredLocations = _allLocations; - } else { - _filteredLocations = _allLocations.where((location) { - final lowerQuery = query.toLowerCase(); - return location.name.toLowerCase().contains(lowerQuery) || - (location.code?.toLowerCase().contains(lowerQuery) ?? false) || - (location.ifsc?.toLowerCase().contains(lowerQuery) ?? false) || - location.address.toLowerCase().contains(lowerQuery); - }).toList(); - } - }); -} + void _filterLocations(String query) { + setState(() { + if (query.isEmpty) { + _filteredLocations = _allLocations; + } else { + _filteredLocations = _allLocations.where((location) { + final lowerQuery = query.toLowerCase(); + return location.name.toLowerCase().contains(lowerQuery) || + (location.code?.toLowerCase().contains(lowerQuery) ?? false) || + (location.ifsc?.toLowerCase().contains(lowerQuery) ?? false) || + location.address.toLowerCase().contains(lowerQuery); + }).toList(); + } + }); + } - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(AppLocalizations.of(context).branchLocator), - ), - body: Column( - children: [ - Padding( - padding: const EdgeInsets.all(12.0), - child: TextField( - controller: _searchController, - onChanged: _filterLocations, - decoration: InputDecoration( - hintText: AppLocalizations.of(context).searchbranchby, - prefixIcon: const Icon(Icons.search), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - ), - ), - - // Content area -Expanded( - child: _isLoading - ? const Center(child: CircularProgressIndicator()) - : _filteredLocations.isEmpty - ? const Center(child: Text("No matching locations found")) - : ListView.builder( - itemCount: _filteredLocations.length, - itemBuilder: (context, index) { - final location = _filteredLocations[index]; - return _buildLocationItem(location); - }, + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(AppLocalizations.of(context).branchLocator), + ), + body: Column( + children: [ + Padding( + padding: const EdgeInsets.all(12.0), + child: TextField( + controller: _searchController, + onChanged: _filterLocations, + decoration: InputDecoration( + hintText: AppLocalizations.of(context).searchbranchby, + prefixIcon: const Icon(Icons.search), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + ), + ), ), -), - ], - ), - ); - } - - Widget _buildHeader(String title) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), - child: Text( - title, - style: Theme.of(context).textTheme.titleLarge?.copyWith( - fontWeight: FontWeight.bold, - color: Theme.of(context).colorScheme.primary, ), - ), - ); -} + + // Content area + Expanded( + child: _isLoading + ? const Center(child: CircularProgressIndicator()) + : _filteredLocations.isEmpty + ? const Center(child: Text("No matching locations found")) + : ListView.builder( + itemCount: _filteredLocations.length, + itemBuilder: (context, index) { + final location = _filteredLocations[index]; + return _buildLocationItem(location); + }, + ), + ), + ], + ), + ); + } + + Widget _buildHeader(String title) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), + child: Text( + title, + style: Theme.of(context).textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.bold, + color: Theme.of(context).colorScheme.primary, + ), + ), + ); + } // Helper widget to build a single location item -Widget _buildLocationItem(Location location) { - final isBranch = location.type == LocationType.branch; - return Card( - margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), - child: ListTile( - leading: CircleAvatar( - child: Icon(isBranch ? Icons.location_city : Icons.currency_rupee), + Widget _buildLocationItem(Location location) { + final isBranch = location.type == LocationType.branch; + return Card( + margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + child: ListTile( + leading: CircleAvatar( + child: Icon(isBranch ? Icons.location_city : Icons.currency_rupee), + ), + title: Text(location.name, + style: const TextStyle(fontWeight: FontWeight.bold)), + subtitle: Text( + isBranch + ? "Code: ${location.code} | IFSC: ${location.ifsc}\nAddress: ${location.address}" + : "Address: ${location.address}", + ), + onTap: () { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text("Selected ${location.name}")), + ); + }, ), - title: Text(location.name, - style: const TextStyle(fontWeight: FontWeight.bold)), - subtitle: Text( - isBranch - ? "Code: ${location.code} | IFSC: ${location.ifsc}\nAddress: ${location.address}" - : "Address: ${location.address}", - ), - onTap: () { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text("Selected ${location.name}")), - ); - }, - ), - ); + ); + } } -} \ No newline at end of file diff --git a/lib/features/service/screens/daily_transaction_limit.dart b/lib/features/service/screens/daily_transaction_limit.dart index 5f150a8..fd242b4 100644 --- a/lib/features/service/screens/daily_transaction_limit.dart +++ b/lib/features/service/screens/daily_transaction_limit.dart @@ -20,142 +20,142 @@ class _DailyLimitScreenState extends State { _currentLimit = null; } - @override - void dispose() { - _limitController.dispose(); - super.dispose(); - } + @override + void dispose() { + _limitController.dispose(); + super.dispose(); + } - Future _showAddOrEditLimitDialog() async { - _limitController.text = _currentLimit?.toStringAsFixed(0) ?? ''; - final newLimit = await showDialog( - context: context, - builder: (context) { - final localizations = AppLocalizations.of(context); - return AlertDialog( - title: Text( - _currentLimit == null - ? localizations.addLimit - : localizations.editLimit, - ), - content: TextField( - controller: _limitController, - autofocus: true, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.allow(RegExp(r'^\d+')), + Future _showAddOrEditLimitDialog() async { + _limitController.text = _currentLimit?.toStringAsFixed(0) ?? ''; + final newLimit = await showDialog( + context: context, + builder: (context) { + final localizations = AppLocalizations.of(context); + return AlertDialog( + title: Text( + _currentLimit == null + ? localizations.addLimit + : localizations.editLimit, + ), + content: TextField( + controller: _limitController, + autofocus: true, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.allow(RegExp(r'^\d+')), + ], + decoration: InputDecoration( + labelText: localizations.limitAmount, + prefixText: '₹', + border: const OutlineInputBorder(), + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: Text(localizations.cancel), + ), + ElevatedButton( + onPressed: () { + final value = double.tryParse(_limitController.text); + if (value != null && value > 0) { + Navigator.of(context).pop(value); + } + }, + child: Text(localizations.save), + ), ], - decoration: InputDecoration( - labelText: localizations.limitAmount, - prefixText: '₹', - border: const OutlineInputBorder(), - ), - ), - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(), - child: Text(localizations.cancel), - ), - ElevatedButton( - onPressed: () { - final value = double.tryParse(_limitController.text); - if (value != null && value > 0) { - Navigator.of(context).pop(value); - } - }, - child: Text(localizations.save), - ), - ], - ); - }, - ); - if (newLimit != null) { + ); + }, + ); + if (newLimit != null) { + setState(() { + _currentLimit = newLimit; + }); + } + } + + void _removeLimit() { setState(() { - _currentLimit = newLimit; + _currentLimit = null; }); } + + @override + Widget build(BuildContext context) { + final localizations = AppLocalizations.of(context); + final theme = Theme.of(context); + final formatCurrency = NumberFormat.currency(locale: 'en_IN', symbol: '₹'); + return Scaffold( + appBar: AppBar( + title: Text(localizations.dailylimit), + ), + body: Center( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + localizations.currentDailyLimit, + style: theme.textTheme.headlineSmall?.copyWith( + color: theme.colorScheme.onSurface.withOpacity(0.7), + ), + ), + const SizedBox(height: 16), + Text( + _currentLimit == null + ? localizations.noLimitSet + : formatCurrency.format(_currentLimit), + style: theme.textTheme.headlineMedium?.copyWith( + fontWeight: FontWeight.bold, + color: _currentLimit == null + ? theme.colorScheme.secondary + : theme.colorScheme.primary, + ), + ), + const SizedBox(height: 48), + if (_currentLimit == null) + ElevatedButton.icon( + onPressed: _showAddOrEditLimitDialog, + icon: const Icon(Icons.add_circle_outline), + label: Text(localizations.addLimit), + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric( + horizontal: 24, vertical: 12), + textStyle: theme.textTheme.titleMedium, + ), + ) + else + Column( + children: [ + ElevatedButton.icon( + onPressed: _showAddOrEditLimitDialog, + icon: const Icon(Icons.edit_outlined), + label: Text(localizations.editLimit), + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric( + horizontal: 24, vertical: 12), + textStyle: theme.textTheme.titleMedium, + ), + ), + const SizedBox(height: 16), + TextButton.icon( + onPressed: _removeLimit, + icon: const Icon(Icons.remove_circle_outline), + label: Text(localizations.removeLimit), + style: TextButton.styleFrom( + foregroundColor: theme.colorScheme.error, + ), + ), + ], + ), + ], + ), + ), + ), + ); + } } - - void _removeLimit() { - setState(() { - _currentLimit = null; - }); - } - - @override - Widget build(BuildContext context) { - final localizations = AppLocalizations.of(context); - final theme = Theme.of(context); - final formatCurrency = NumberFormat.currency(locale: 'en_IN', symbol: '₹'); - return Scaffold( - appBar: AppBar( - title: Text(localizations.dailylimit), - ), - body: Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - localizations.currentDailyLimit, - style: theme.textTheme.headlineSmall?.copyWith( - color: theme.colorScheme.onSurface.withOpacity(0.7), - ), - ), - const SizedBox(height: 16), - Text( - _currentLimit == null - ? localizations.noLimitSet - : formatCurrency.format(_currentLimit), - style: theme.textTheme.headlineMedium?.copyWith( - fontWeight: FontWeight.bold, - color: _currentLimit == null - ? theme.colorScheme.secondary - : theme.colorScheme.primary, - ), - ), - const SizedBox(height: 48), - if (_currentLimit == null) - ElevatedButton.icon( - onPressed: _showAddOrEditLimitDialog, - icon: const Icon(Icons.add_circle_outline), - label: Text(localizations.addLimit), - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric( - horizontal: 24, vertical: 12), - textStyle: theme.textTheme.titleMedium, - ), - ) - else - Column( - children: [ - ElevatedButton.icon( - onPressed: _showAddOrEditLimitDialog, - icon: const Icon(Icons.edit_outlined), - label: Text(localizations.editLimit), - style: ElevatedButton.styleFrom( - padding: const EdgeInsets.symmetric( - horizontal: 24, vertical: 12), - textStyle: theme.textTheme.titleMedium, - ), - ), - const SizedBox(height: 16), - TextButton.icon( - onPressed: _removeLimit, - icon: const Icon(Icons.remove_circle_outline), - label: Text(localizations.removeLimit), - style: TextButton.styleFrom( - foregroundColor: theme.colorScheme.error, - ), - ), - ], - ), - ], - ), - ), - ), - ); - } -} \ No newline at end of file diff --git a/lib/features/service/screens/faqs_screen.dart b/lib/features/service/screens/faqs_screen.dart index 561c0f0..8b01a24 100644 --- a/lib/features/service/screens/faqs_screen.dart +++ b/lib/features/service/screens/faqs_screen.dart @@ -1,47 +1,47 @@ - import 'package:flutter/material.dart'; +import 'package:flutter/material.dart'; import 'package:kmobile/l10n/app_localizations.dart'; - class FaqsScreen extends StatefulWidget { - const FaqsScreen({super.key}); +class FaqsScreen extends StatefulWidget { + const FaqsScreen({super.key}); - @override - State createState() => _FaqsScreenState(); - } + @override + State createState() => _FaqsScreenState(); +} - class _FaqsScreenState extends State { - @override - void initState() { - super.initState(); - _getFaqs(); - } +class _FaqsScreenState extends State { + @override + void initState() { + super.initState(); + _getFaqs(); + } - // A placeholder for your future API call - Future _getFaqs() async { - // TODO: Implement API call to fetch FAQs data - // For now, simulating a network call with a delay - await Future.delayed(const Duration(seconds: 1)); - // In a real implementation, you would process the API response here - } + // A placeholder for your future API call + Future _getFaqs() async { + // TODO: Implement API call to fetch FAQs data + // For now, simulating a network call with a delay + await Future.delayed(const Duration(seconds: 1)); + // In a real implementation, you would process the API response here + } - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Row( - children: [ - Flexible( - child: Text( - AppLocalizations.of(context).faq, - softWrap: true, - style: const TextStyle( - fontSize: 16.5, - ), - textAlign: TextAlign.left, - ), - ), - ], - ), - ), - ); - } - } \ No newline at end of file + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Row( + children: [ + Flexible( + child: Text( + AppLocalizations.of(context).faq, + softWrap: true, + style: const TextStyle( + fontSize: 16.5, + ), + textAlign: TextAlign.left, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/features/service/screens/quick_links_screen.dart b/lib/features/service/screens/quick_links_screen.dart index d2966bb..55335b0 100644 --- a/lib/features/service/screens/quick_links_screen.dart +++ b/lib/features/service/screens/quick_links_screen.dart @@ -31,4 +31,4 @@ class _QuickLinksScreenState extends State { ), ); } -} \ No newline at end of file +} diff --git a/lib/features/service/screens/service_screen.dart b/lib/features/service/screens/service_screen.dart index 3e8adbf..218d4a5 100644 --- a/lib/features/service/screens/service_screen.dart +++ b/lib/features/service/screens/service_screen.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:material_symbols_icons/material_symbols_icons.dart'; import 'package:kmobile/features/service/screens/quick_links_screen.dart'; import 'package:kmobile/features/service/screens/faqs_screen.dart'; + class ServiceScreen extends StatefulWidget { const ServiceScreen({super.key}); @@ -13,95 +14,97 @@ class ServiceScreen extends StatefulWidget { } class _ServiceScreen extends State { -@override -Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - automaticallyImplyLeading: false, - title: Text( - AppLocalizations.of(context).services, + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + automaticallyImplyLeading: false, + title: Text( + AppLocalizations.of(context).services, + ), + centerTitle: false, ), - centerTitle: false, - ), - body: ListView( - children: [ - ServiceManagementTile( - icon: Symbols.add, - label: AppLocalizations.of(context).accountOpeningDeposit, - onTap: () {}, - disabled: true, - ), - const Divider(height: 1), - ServiceManagementTile( - icon: Symbols.add, - label: AppLocalizations.of(context).accountOpeningLoan, - onTap: () {}, - disabled: true, - ), - const Divider(height: 1), - ServiceManagementTile( - icon: Symbols.currency_rupee, - label: AppLocalizations.of(context).dailylimit, - onTap: () { - Navigator.of(context).push( - MaterialPageRoute(builder: (context) => const DailyLimitScreen()), - ); - }, - disabled: true, - ), - const Divider(height: 1), - ServiceManagementTile( - icon: Symbols.captive_portal, - label: AppLocalizations.of(context).quickLinks, - onTap: () { - Navigator.of(context).push( - MaterialPageRoute(builder: (context) => const QuickLinksScreen()), - ); - }, - disabled: true, - ), - const Divider(height: 1), - ServiceManagementTile( - icon: Symbols.question_mark, - label: AppLocalizations.of(context).faq, - onTap: () { - Navigator.of(context).push( - MaterialPageRoute(builder: (context) => const FaqsScreen()), - ); - }, - disabled: true, - ), - const Divider(height: 1), - ServiceManagementTile( - icon: Symbols.location_pin, - label: AppLocalizations.of(context).branchLocator, - onTap: () { - Navigator.push( - context, + body: ListView( + children: [ + ServiceManagementTile( + icon: Symbols.add, + label: AppLocalizations.of(context).accountOpeningDeposit, + onTap: () {}, + disabled: true, + ), + const Divider(height: 1), + ServiceManagementTile( + icon: Symbols.add, + label: AppLocalizations.of(context).accountOpeningLoan, + onTap: () {}, + disabled: true, + ), + const Divider(height: 1), + ServiceManagementTile( + icon: Symbols.currency_rupee, + label: AppLocalizations.of(context).dailylimit, + onTap: () { + Navigator.of(context).push( MaterialPageRoute( - builder: (context) => const BranchLocatorScreen())); - }, - disabled: true, - ), - const Divider(height: 1), - ], - ), - ); -} + builder: (context) => const DailyLimitScreen()), + ); + }, + disabled: true, + ), + const Divider(height: 1), + ServiceManagementTile( + icon: Symbols.captive_portal, + label: AppLocalizations.of(context).quickLinks, + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const QuickLinksScreen()), + ); + }, + disabled: true, + ), + const Divider(height: 1), + ServiceManagementTile( + icon: Symbols.question_mark, + label: AppLocalizations.of(context).faq, + onTap: () { + Navigator.of(context).push( + MaterialPageRoute(builder: (context) => const FaqsScreen()), + ); + }, + disabled: true, + ), + const Divider(height: 1), + ServiceManagementTile( + icon: Symbols.location_pin, + label: AppLocalizations.of(context).branchLocator, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const BranchLocatorScreen())); + }, + disabled: true, + ), + const Divider(height: 1), + ], + ), + ); + } } class ServiceManagementTile extends StatelessWidget { final IconData icon; final String label; final VoidCallback onTap; - final bool disabled; + final bool disabled; const ServiceManagementTile({ super.key, required this.icon, required this.label, required this.onTap, - this.disabled = false, + this.disabled = false, }); @override @@ -110,20 +113,20 @@ class ServiceManagementTile extends StatelessWidget { return ListTile( leading: Icon( icon, - color: disabled ? theme.disabledColor : null, + color: disabled ? theme.disabledColor : null, ), title: Text( label, style: TextStyle( - color: disabled ? theme.disabledColor : null, + color: disabled ? theme.disabledColor : null, ), ), trailing: Icon( Symbols.arrow_right, size: 20, - color: disabled ? theme.disabledColor : null, + color: disabled ? theme.disabledColor : null, ), - onTap: disabled ? null : onTap, + onTap: disabled ? null : onTap, ); } -} \ No newline at end of file +} diff --git a/lib/main.dart b/lib/main.dart index f951798..a4e7953 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -24,4 +24,4 @@ void main() async { // } await setupDependencies(); runApp(const KMobile()); -} \ No newline at end of file +} diff --git a/lib/widgets/bank_logos.dart b/lib/widgets/bank_logos.dart index b1b92bc..a641b3a 100644 --- a/lib/widgets/bank_logos.dart +++ b/lib/widgets/bank_logos.dart @@ -35,7 +35,7 @@ Widget getBankLogo(String? bankName, BuildContext context) { width: 40, height: 40, ); - } + } if (bankName != null && bankName.toLowerCase().contains('punjab national bank')) { return Image.asset( @@ -86,14 +86,14 @@ Widget getBankLogo(String? bankName, BuildContext context) { height: 40, ); } - if (bankName != null && bankName.toLowerCase().contains('ipsbank') || bankName != null && bankName.toLowerCase().contains('india post') ) { + if (bankName != null && bankName.toLowerCase().contains('ipsbank') || + bankName != null && bankName.toLowerCase().contains('india post')) { return Image.asset( 'assets/images/ipos_logo.png', width: 40, height: 40, ); - } - else { + } else { return Icon( Icons.account_balance, size: 40, diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 1e2316e..d8b913c 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -8,6 +8,7 @@ import Foundation import device_info_plus import flutter_secure_storage_macos import local_auth_darwin +import package_info_plus import path_provider_foundation import share_plus import shared_preferences_foundation @@ -17,6 +18,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) FLALocalAuthPlugin.register(with: registry.registrar(forPlugin: "FLALocalAuthPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 162b0fe..167c712 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -69,10 +69,10 @@ packages: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.3.0" checked_yaml: dependency: transitive description: @@ -93,18 +93,18 @@ packages: dependency: transitive description: name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.1" collection: dependency: transitive description: name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.19.1" + version: "1.18.0" confetti: dependency: "direct main" description: @@ -181,10 +181,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" url: "https://pub.dev" source: hosted - version: "1.3.3" + version: "1.3.1" ffi: dependency: transitive description: @@ -385,10 +385,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.20.2" + version: "0.19.0" jailbreak_root_detection: dependency: "direct main" description: @@ -417,26 +417,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "11.0.2" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.10" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.1" lints: dependency: transitive description: @@ -497,10 +497,10 @@ packages: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: @@ -521,10 +521,10 @@ packages: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.15.0" mime: dependency: transitive description: @@ -541,14 +541,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + sha256: "7e76fad405b3e4016cd39d08f455a4eb5199723cf594cd1b8916d47140d93017" + url: "https://pub.dev" + source: hosted + version: "4.2.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" + url: "https://pub.dev" + source: hosted + version: "2.0.1" path: dependency: transitive description: name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.9.0" path_parsing: dependency: transitive description: @@ -801,7 +817,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.0" + version: "0.0.99" source_span: dependency: transitive description: @@ -822,18 +838,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.12.1" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -854,10 +870,10 @@ packages: dependency: transitive description: name: test_api - sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.6" + version: "0.7.2" typed_data: dependency: transitive description: @@ -966,10 +982,10 @@ packages: dependency: transitive description: name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.1.4" vm_service: dependency: transitive description: @@ -1027,5 +1043,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.8.0-0 <4.0.0" + dart: ">=3.5.0 <4.0.0" flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index 4ee1573..2bf26a7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,10 +31,6 @@ dependencies: flutter: sdk: flutter flutter_neumorphic : 3.2.0 - - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.6 jailbreak_root_detection: ^1.1.6 equatable: ^2.0.7 @@ -64,6 +60,7 @@ dependencies: permission_handler: ^12.0.1 device_info_plus: ^11.3.0 showcaseview: ^2.0.3 + package_info_plus: ^4.2.0 # jailbreak_root_detection: "^1.1.6"