diff --git a/assets/images/profile.png b/assets/images/profile.png new file mode 100644 index 0000000..82d41fe Binary files /dev/null and b/assets/images/profile.png differ diff --git a/lib/app.dart b/lib/app.dart index 0410684..c6b6c1a 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -12,10 +12,8 @@ import 'package:kmobile/features/auth/controllers/theme_state.dart'; import 'config/routes.dart'; import 'di/injection.dart'; import 'features/auth/controllers/auth_cubit.dart'; -import 'features/card/screens/card_management_screen.dart'; import 'features/accounts/screens/account_statement_screen.dart'; import 'package:kmobile/features/auth/controllers/auth_state.dart'; - import 'features/auth/screens/login_screen.dart'; import 'features/service/screens/service_screen.dart'; import 'features/dashboard/screens/dashboard_screen.dart'; @@ -330,7 +328,6 @@ class _NavigationScaffoldState extends State { return const Center(child: CircularProgressIndicator()); }, ), - const CardManagementScreen(), const ServiceScreen(), ]; @@ -392,10 +389,6 @@ class _NavigationScaffoldState extends State { icon: const Icon(Icons.swap_vert_sharp), label: AppLocalizations.of(context).transactions, ), - BottomNavigationBarItem( - icon: const Icon(Icons.credit_card), - label: AppLocalizations.of(context).card, - ), BottomNavigationBarItem( icon: const Icon(Icons.miscellaneous_services), label: AppLocalizations.of(context).services, diff --git a/lib/features/accounts/screens/account_info_screen.dart b/lib/features/accounts/screens/account_info_screen.dart index 9eea9f5..1628b2e 100644 --- a/lib/features/accounts/screens/account_info_screen.dart +++ b/lib/features/accounts/screens/account_info_screen.dart @@ -42,10 +42,10 @@ class _AccountInfoScreen extends State { return AppLocalizations.of(context).recurringDeposit; case 'ca': return "Current Account"; - case 'cc': + case 'cc': return "Cash Credit Account"; case 'od': - return "Overdraft Account"; + return "Overdraft Account"; default: return AppLocalizations.of(context).unknownAccount; } diff --git a/lib/features/accounts/screens/account_statement_screen.dart b/lib/features/accounts/screens/account_statement_screen.dart index d9e9a83..39ce2e1 100644 --- a/lib/features/accounts/screens/account_statement_screen.dart +++ b/lib/features/accounts/screens/account_statement_screen.dart @@ -150,36 +150,42 @@ class _AccountStatementScreen extends State { margin: const EdgeInsets.only(bottom: 10), child: Padding( padding: const EdgeInsets.all(16.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - AppLocalizations.of(context).accountNumber, - style: const TextStyle( - fontWeight: FontWeight.w500, fontSize: 17), - ), - const VerticalDivider(width: 20, thickness: 1, indent: 5, endIndent: 5, color: Colors.grey), - DropdownButton( - value: selectedUser, - onChanged: (User? newUser) { - if (newUser != null) { - setState(() { - selectedUser = newUser; - }); - _loadTransactions(); - } - }, - items: widget.users.map((user) { - return DropdownMenuItem( - value: user, - child: Text(user.accountNo.toString()), - ); - }).toList(), - underline: Container(), // Remove the underline - ), - Spacer(), - ], - ), ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + AppLocalizations.of(context).accountNumber, + style: const TextStyle( + fontWeight: FontWeight.w500, fontSize: 17), + ), + const VerticalDivider( + width: 20, + thickness: 1, + indent: 5, + endIndent: 5, + color: Colors.grey), + DropdownButton( + value: selectedUser, + onChanged: (User? newUser) { + if (newUser != null) { + setState(() { + selectedUser = newUser; + }); + _loadTransactions(); + } + }, + items: widget.users.map((user) { + return DropdownMenuItem( + value: user, + child: Text(user.accountNo.toString()), + ); + }).toList(), + underline: Container(), // Remove the underline + ), + Spacer(), + ], + ), + ), ), Card( margin: const EdgeInsets.only(bottom: 10), diff --git a/lib/features/customer_info/screens/customer_info_screen.dart b/lib/features/customer_info/screens/customer_info_screen.dart index cf3b3a7..b5631ff 100644 --- a/lib/features/customer_info/screens/customer_info_screen.dart +++ b/lib/features/customer_info/screens/customer_info_screen.dart @@ -26,149 +26,152 @@ class _CustomerInfoScreenState extends State { Widget build(BuildContext context) { final theme = Theme.of(context); return Scaffold( - appBar: AppBar( - title: Text( - AppLocalizations.of(context) - .customerInfo - .replaceFirst(RegExp('\n'), ''), + appBar: AppBar( + title: Text( + AppLocalizations.of(context) + .customerInfo + .replaceFirst(RegExp('\n'), ''), + ), ), - ), - body: SafeArea( - child: Stack( - children: [ - SingleChildScrollView( - physics: const AlwaysScrollableScrollPhysics(), - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - Card( - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - side: BorderSide( - color: theme.colorScheme.outline.withOpacity(0.2), - width: 1, - ), - ), - child: Padding( padding: const EdgeInsets.all(16.0), - child: Row( - children: [ - SizedBox( - width: 56, - height: 56, - child: CircleAvatar( - radius: 50, - child: SvgPicture.asset( - 'assets/images/avatar_male.svg', - fit: BoxFit.cover, + body: SafeArea( + child: Stack( + children: [ + SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + children: [ + Card( + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + side: BorderSide( + color: theme.colorScheme.outline.withOpacity(0.2), + width: 1, + ), + ), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + children: [ + SizedBox( + width: 56, + height: 56, + child: CircleAvatar( + radius: 50, + child: SvgPicture.asset( + 'assets/images/avatar_male.svg', + fit: BoxFit.cover, + ), ), ), - ), - const SizedBox(width: 12), - // Name + mobile - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - // If you want to show the user's name instead, replace below. - user.name ?? '', - style: - theme.textTheme.titleLarge?.copyWith( - fontWeight: FontWeight.w600, + const SizedBox(width: 12), + // Name + mobile + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + // If you want to show the user's name instead, replace below. + user.name ?? '', + style: + theme.textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.w600, + ), ), - ), - const SizedBox(height: 4), - Text( - user.cifNumber ?? '', - style: theme.textTheme.bodyMedium?.copyWith( - color: theme.colorScheme.onSurface - .withOpacity(0.7), + const SizedBox(height: 4), + Text( + user.cifNumber ?? '', + style: + theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurface + .withOpacity(0.7), + ), ), - ), - ], + ], + ), ), - ), - ], + ], + ), ), ), - ), - const SizedBox(height: 16), - Card( - elevation: 0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - side: BorderSide( - color: theme.colorScheme.outline.withOpacity(0.2), - width: 1, + const SizedBox(height: 16), + Card( + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + side: BorderSide( + color: theme.colorScheme.outline.withOpacity(0.2), + width: 1, + ), ), - ), - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Personal Information', - style: theme.textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.w600, + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Personal Information', + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + ), ), - ), - const SizedBox(height: 16), - InfoField( - label: AppLocalizations.of(context).activeAccounts, - value: user.activeAccounts?.toString() ?? 'N/A', - ), - InfoField( - label: AppLocalizations.of(context).mobileNumber, - value: user.mobileNo ?? 'N/A', - ), - InfoField( - label: AppLocalizations.of(context).dateOfBirth, - value: (user.dateOfBirth != null && - user.dateOfBirth!.length == 8) - ? '${user.dateOfBirth!.substring(0, 2)}-${user.dateOfBirth!.substring(2, 4)}-${user.dateOfBirth!.substring(4, 8)}' - : 'N/A', - ), // Replace with DOB if available - InfoField( - label: AppLocalizations.of(context).branchCode, - value: user.branchId ?? 'N/A', - ), - InfoField( - label: AppLocalizations.of(context).address, - value: user.address ?? 'N/A', - ), // Replace with Aadhar if available - InfoField( - label: AppLocalizations.of(context).primaryId, - value: _maskPrimaryId(user.primaryId), - ), - ], + const SizedBox(height: 16), + InfoField( + label: + AppLocalizations.of(context).activeAccounts, + value: user.activeAccounts?.toString() ?? 'N/A', + ), + InfoField( + label: + AppLocalizations.of(context).mobileNumber, + value: user.mobileNo ?? 'N/A', + ), + InfoField( + label: AppLocalizations.of(context).dateOfBirth, + value: (user.dateOfBirth != null && + user.dateOfBirth!.length == 8) + ? '${user.dateOfBirth!.substring(0, 2)}-${user.dateOfBirth!.substring(2, 4)}-${user.dateOfBirth!.substring(4, 8)}' + : 'N/A', + ), // Replace with DOB if available + InfoField( + label: AppLocalizations.of(context).branchCode, + value: user.branchId ?? 'N/A', + ), + InfoField( + label: AppLocalizations.of(context).address, + value: user.address ?? 'N/A', + ), // Replace with Aadhar if available + InfoField( + label: AppLocalizations.of(context).primaryId, + value: _maskPrimaryId(user.primaryId), + ), + ], + ), ), ), - ), - ], + ], + ), ), ), - ), - IgnorePointer( - child: Center( - child: Opacity( - opacity: 0.07, // Reduced opacity - child: ClipOval( - child: Image.asset( - 'assets/images/logo.png', - width: 200, // Adjust size as needed - height: 200, // Adjust size as needed + IgnorePointer( + child: Center( + child: Opacity( + opacity: 0.07, // Reduced opacity + child: ClipOval( + child: Image.asset( + 'assets/images/logo.png', + width: 200, // Adjust size as needed + height: 200, // Adjust size as needed + ), ), ), ), ), - ), - ], - ), - ) - ); + ], + ), + )); } } diff --git a/lib/features/dashboard/screens/dashboard_screen.dart b/lib/features/dashboard/screens/dashboard_screen.dart index 95d1990..095ee73 100644 --- a/lib/features/dashboard/screens/dashboard_screen.dart +++ b/lib/features/dashboard/screens/dashboard_screen.dart @@ -337,7 +337,7 @@ class _DashboardScreenState extends State case 'cc': return "Cash Credit Account"; case 'od': - return "Overdraft Account"; + return "Overdraft Account"; default: return AppLocalizations.of(context).unknownAccount; } diff --git a/lib/features/profile/profile_screen.dart b/lib/features/profile/profile_screen.dart index 5e08d9f..3bee767 100644 --- a/lib/features/profile/profile_screen.dart +++ b/lib/features/profile/profile_screen.dart @@ -174,260 +174,240 @@ class _ProfileScreenState extends State { title: Text(loc.profile), elevation: 0, ), - body: Stack( - children: [ - ListView( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - children: [ - // ===== Profile Header ===== - Card( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Row( - children: [ - // Avatar - Container( - width: 56, - height: 56, -child: CircleAvatar( - radius: 50, - child: SvgPicture.asset( - 'assets/images/avatar_male.svg', - fit: BoxFit.cover, - ), - ), - ), - const SizedBox(width: 12), - // Name + mobile - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + body: Stack( + children: [ + ListView( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + children: [ + // ===== Profile Header ===== + Card( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( children: [ - Text( - // If you want to show the user's name instead, replace below. - widget.customerName, - style: theme.textTheme.titleLarge?.copyWith( - fontWeight: FontWeight.w600, + // Avatar + Container( + width: 56, + height: 56, + child: CircleAvatar( + radius: 50, + child: SvgPicture.asset( + 'assets/images/avatar_male.svg', + fit: BoxFit.cover, + ), ), ), - const SizedBox(height: 4), - Text( - widget.customerNo, - style: theme.textTheme.bodyMedium?.copyWith( - color: theme.colorScheme.onSurface - .withOpacity(0.7), + const SizedBox(width: 12), + // Name + mobile + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + // If you want to show the user's name instead, replace below. + widget.customerName, + style: theme.textTheme.titleLarge?.copyWith( + fontWeight: FontWeight.w600, + ), + ), + const SizedBox(height: 4), + Text( + widget.customerNo, + style: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.onSurface + .withOpacity(0.7), + ), + ), + ], ), ), ], ), ), - ], - ), - ), - ), - - const SizedBox(height: 16), - - // ===== Section: Settings ===== - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Text( - "Settings", - style: theme.textTheme.labelLarge?.copyWith( - fontWeight: FontWeight.w600, - letterSpacing: 0.2, - ), - ), - ), - const SizedBox(height: 8), - - _SectionTile( - leadingIcon: Icons.settings, - title: loc.preferences, - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const PreferenceScreen(), ), - ); - }, - ), - _SectionTile( - leadingIcon: Icons.security, - title: loc.securitySettings, - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SecuritySettingsScreen( - mobileNumber: widget.mobileNumber, + + const SizedBox(height: 16), + + // ===== Section: Settings ===== + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Text( + "Settings", + style: theme.textTheme.labelLarge?.copyWith( + fontWeight: FontWeight.w600, + letterSpacing: 0.2, + ), ), ), - ); - }, - ), - _SectionTile( - leadingIcon: Icons.currency_rupee, - title: loc.dailylimit, - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const DailyLimitScreen(), - ), - ); - }, - ), - Card( - child: SwitchListTile( - title: Text(loc.enableFingerprintLogin), - value: _isBiometricEnabled, - onChanged: (bool value) { - _handleBiometricToggle(value); - }, - secondary: const Icon(Icons.fingerprint), - contentPadding: - const EdgeInsets.symmetric(horizontal: 16, vertical: 4), - ), - ), - - const SizedBox(height: 16), - const Divider(height: 24), - - // ===== Section: Security & App ===== - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Text( - loc.appVersion, - style: theme.textTheme.labelLarge?.copyWith( - fontWeight: FontWeight.w600, - letterSpacing: 0.2, - ), - ), - ), - const SizedBox(height: 8), - - // Fingerprint toggle inside a styled container - Card( - child: ListTile( - leading: const Icon(Icons.smartphone), - title: Text(loc.appVersion), - trailing: FutureBuilder( - future: _getAppVersion(), - builder: - (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const SizedBox( - width: 18, - height: 18, - child: CircularProgressIndicator(strokeWidth: 2), + const SizedBox(height: 8), + + _SectionTile( + leadingIcon: Icons.settings, + title: loc.preferences, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const PreferenceScreen(), + ), ); - } else if (snapshot.hasError) { - return Text(loc.error); - } else { - return Text( - snapshot.data ?? "N/A", + }, + ), + _SectionTile( + leadingIcon: Icons.security, + title: loc.securitySettings, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SecuritySettingsScreen( + mobileNumber: widget.mobileNumber, + ), + ), ); - } - }, - ), - contentPadding: - const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - ), - ), - - const SizedBox(height: 16), - const Divider(height: 24), - - // ===== Section: Actions ===== - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Text( - "Exit", - style: theme.textTheme.labelLarge?.copyWith( - fontWeight: FontWeight.w600, - letterSpacing: 0.2, - ), - ), - ), - const SizedBox(height: 8), - - _SectionTile( - leadingIcon: Icons.exit_to_app, - title: loc.logout, - trailChevron: false, // action tile, no chevron - onTap: () async { - final shouldExit = await showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text(loc.logout), - content: Text(loc.logoutCheck), - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(false), - child: Text(loc.no), - ), - TextButton( - onPressed: () => Navigator.of(context).pop(true), - child: Text(loc.yes), - ), - ], + }, ), - ); - - if (shouldExit == true) { - if (Platform.isAndroid) { - SystemNavigator.pop(); - } - exit(0); - } - }, - ), - _SectionTile( - leadingIcon: Icons.logout, - title: loc.deregister, - trailChevron: false, - onTap: () async { - final shouldLogout = await showDialog( - context: context, - builder: (_) => const LogoutDialog(), - ); - - if (shouldLogout == true) { - await _handleLogout(context); - } - }, - ), - - const SizedBox(height: 24), - ], - ), - - // ===== Watermark (kept subtle, no theme change) ===== - IgnorePointer( - child: Positioned.fill( - child: Center( - child: Opacity( - opacity: 0.06, - child: ClipOval( - child: Image.asset( - 'assets/images/logo.png', - width: 200, - height: 200, - filterQuality: FilterQuality.medium, + _SectionTile( + leadingIcon: Icons.currency_rupee, + title: loc.dailylimit, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const DailyLimitScreen(), + ), + ); + }, ), - ), + Card( + child: SwitchListTile( + title: Text(loc.enableFingerprintLogin), + value: _isBiometricEnabled, + onChanged: (bool value) { + _handleBiometricToggle(value); + }, + secondary: const Icon(Icons.fingerprint), + contentPadding: + const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + ), + ), + + const SizedBox(height: 16), + const Divider(height: 24), + + // ===== Section: Security & App ===== + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Text( + loc.appVersion, + style: theme.textTheme.labelLarge?.copyWith( + fontWeight: FontWeight.w600, + letterSpacing: 0.2, + ), + ), + ), + const SizedBox(height: 8), + + // Fingerprint toggle inside a styled container + Card( + child: ListTile( + leading: const Icon(Icons.smartphone), + title: Text(loc.appVersion), + trailing: FutureBuilder( + future: _getAppVersion(), + builder: + (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const SizedBox( + width: 18, + height: 18, + child: CircularProgressIndicator(strokeWidth: 2), + ); + } else if (snapshot.hasError) { + return Text(loc.error); + } else { + return Text( + snapshot.data ?? "N/A", + ); + } + }, + ), + contentPadding: + const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + ), + ), + + const SizedBox(height: 16), + const Divider(height: 24), + + // ===== Section: Actions ===== + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Text( + "Exit", + style: theme.textTheme.labelLarge?.copyWith( + fontWeight: FontWeight.w600, + letterSpacing: 0.2, + ), + ), + ), + const SizedBox(height: 8), + + _SectionTile( + leadingIcon: Icons.exit_to_app, + title: loc.logout, + trailChevron: false, // action tile, no chevron + onTap: () async { + final shouldExit = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(loc.logout), + content: Text(loc.logoutCheck), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: Text(loc.no), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + child: Text(loc.yes), + ), + ], + ), + ); + + if (shouldExit == true) { + if (Platform.isAndroid) { + SystemNavigator.pop(); + } + exit(0); + } + }, + ), + _SectionTile( + leadingIcon: Icons.logout, + title: loc.deregister, + trailChevron: false, + onTap: () async { + final shouldLogout = await showDialog( + context: context, + builder: (_) => const LogoutDialog(), + ); + + if (shouldLogout == true) { + await _handleLogout(context); + } + }, + ), + + const SizedBox(height: 24), + ], ), - ), - ), - ), - ], - ), - ); + ], + ), ); } } diff --git a/lib/main.dart b/lib/main.dart index b73e538..a4e7953 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -15,7 +15,7 @@ void main() async { ]); // Check for device compromise - //final compromisedMessage = await SecurityService.deviceCompromisedMessage; + // final compromisedMessage = await SecurityService.deviceCompromisedMessage; // if (compromisedMessage != null) { // runApp(MaterialApp( // home: SecurityErrorScreen(message: compromisedMessage), diff --git a/pubspec.yaml b/pubspec.yaml index 194aad6..f013478 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -115,6 +115,7 @@ flutter: - assets/images/uco_logo.png - assets/images/ipos_logo.png - assets/images/profile.svg + - assets/images/profile.png - assets/animations/rupee.json - assets/animations/error.json - assets/animations/done.json