From 72a2c563926587afa7ab02b38e80a46a3a560676 Mon Sep 17 00:00:00 2001 From: asif Date: Fri, 5 Dec 2025 16:02:49 +0530 Subject: [PATCH] Code Formatting --- lib/api/services/limit_service.dart | 2 +- .../screens/account_statement_screen.dart | 1091 +++++++++-------- .../accounts/screens/all_accounts_screen.dart | 26 +- .../screens/customer_info_screen.dart | 18 +- .../dashboard/screens/dashboard_screen.dart | 338 +++-- .../screens/fund_transfer_screen.dart | 6 +- .../profile/change_limit_otp_screen.dart | 8 +- lib/features/profile/profile_screen.dart | 453 +++---- .../service/screens/atm_locator_screen.dart | 3 +- lib/features/service/screens/faqs_screen.dart | 2 +- 10 files changed, 962 insertions(+), 985 deletions(-) diff --git a/lib/api/services/limit_service.dart b/lib/api/services/limit_service.dart index 710ae96..32f2deb 100644 --- a/lib/api/services/limit_service.dart +++ b/lib/api/services/limit_service.dart @@ -84,4 +84,4 @@ class LimitService { } return response.toString(); } -} \ No newline at end of file +} diff --git a/lib/features/accounts/screens/account_statement_screen.dart b/lib/features/accounts/screens/account_statement_screen.dart index 1890398..b8247b0 100644 --- a/lib/features/accounts/screens/account_statement_screen.dart +++ b/lib/features/accounts/screens/account_statement_screen.dart @@ -450,599 +450,604 @@ class _AccountStatementScreen extends State { ); } - Future _exportToPdf() async { - if (_transactions.isEmpty) { - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('No transactions to export.')), - ); - } - return; + Future _exportToPdf() async { + if (_transactions.isEmpty) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('No transactions to export.')), + ); } - + return; + } + + await flutterLocalNotificationsPlugin.show( + 0, + 'Downloading PDF', + 'Your account statement is being downloaded...', + const NotificationDetails( + android: AndroidNotificationDetails( + 'download_channel', + 'Download Notifications', + channelDescription: 'Notifications for PDF downloads', + importance: Importance.low, + priority: Priority.low, + showProgress: true, + maxProgress: 0, + ongoing: true, + icon: 'notification_icon', + ), + ), + ); + + // --- 1. LOAD ASSETS --- + final logoImage = pw.MemoryImage( + (await rootBundle.load('assets/images/logo.png')).buffer.asUint8List()); + final timesFont = await rootBundle.load("assets/fonts/Rubik-Regular.ttf"); + final timesBoldFont = await rootBundle.load("assets/fonts/Rubik-Bold.ttf"); + final ttf = pw.Font.ttf(timesFont); + final ttfBold = pw.Font.ttf(timesBoldFont); + + // --- 2. DEFINE COLORS --- + final primaryColor = PdfColor.fromHex("#1a5f3a"); + final secondaryColor = PdfColor.fromHex("#2e7d32"); + final debitColor = PdfColor.fromHex("#d32f2f"); + final lightGreyColor = PdfColor.fromHex("#666"); + final tableBorderColor = PdfColor.fromHex("#d0d0d0"); + final lightBgColor = PdfColor.fromHex("#f9f9f9"); + final warningBgColor = PdfColor.fromHex("#f8d7da"); + final warningBorderColor = PdfColor.fromHex("#f5c6cb"); + final warningTextColor = PdfColor.fromHex("#721c24"); + + // --- 3. CREATE PDF --- + final pdf = pw.Document( + theme: pw.ThemeData.withFont(base: ttf, bold: ttfBold), + ); + + // --- 4. BUILD PAGES --- + pdf.addPage( + pw.MultiPage( + pageFormat: PdfPageFormat.a4.copyWith( + marginTop: 15 * PdfPageFormat.mm, + marginLeft: 10 * PdfPageFormat.mm, + marginRight: 10 * PdfPageFormat.mm, + marginBottom: 20 * PdfPageFormat.mm, + ), + header: (context) => + _buildHeader(logoImage, primaryColor, lightGreyColor), + footer: (context) { + return pw.Center( + child: pw.Text( + '** This is only for information purpose and not for legal use **', + style: pw.TextStyle( + fontSize: 9, + color: lightGreyColor, + fontStyle: pw.FontStyle.italic))); + }, + build: (context) => [ + _buildAccountDetails( + customerName: selectedUser.name ?? '', + branchCode: selectedUser.branchId ?? '', + accountNo: selectedUser.accountNo ?? '', + cifNumber: selectedUser.cifNumber ?? '', + address: selectedUser.address ?? '', + lightGreyColor: lightGreyColor, + tableBorderColor: tableBorderColor, + lightBgColor: lightBgColor, + ), + _buildWarning( + warningBgColor, warningBorderColor, debitColor, warningTextColor), + _buildPeriodHeader( + primaryColor: primaryColor, + fromDate: fromDate, + toDate: toDate, + ), + _buildTransactionsTable( + transactions: _transactions, + primaryColor: primaryColor, + secondaryColor: secondaryColor, + debitColor: debitColor, + tableBorderColor: tableBorderColor, + ), + pw.SizedBox(height: 20), + pw.Text('END OF STATEMENT', style: const pw.TextStyle(fontSize: 12)), + ], + ), + ); + + pdf.addPage( + pw.Page( + pageFormat: PdfPageFormat.a4.copyWith( + marginTop: 15 * PdfPageFormat.mm, + marginLeft: 10 * PdfPageFormat.mm, + marginRight: 10 * PdfPageFormat.mm, + marginBottom: 20 * PdfPageFormat.mm, + ), + build: (context) => _buildLastPage(), + ), + ); + + // --- 5. SAVE AND NOTIFY --- + try { + final Uint8List pdfBytes = await pdf.save(); + final String timestamp = + DateFormat("ddMMyyyy_HHmm").format(DateTime.now()); + final String fileName = + 'Statement_${selectedUser.accountNo}_$timestamp.pdf'; + + String? filePath; + + if (Platform.isAndroid) { + final directory = Directory('/storage/emulated/0/Download'); + if (!await directory.exists()) { + await directory.create(recursive: true); + } + final file = File('${directory.path}/$fileName'); + await file.writeAsBytes(pdfBytes); + filePath = file.path; + } else { + final tempDir = await getTemporaryDirectory(); + final file = await File('${tempDir.path}/$fileName').create(); + await file.writeAsBytes(pdfBytes); + filePath = file.path; + } + await flutterLocalNotificationsPlugin.show( 0, - 'Downloading PDF', - 'Your account statement is being downloaded...', + 'PDF Download Complete', + 'Your account statement has been saved.', const NotificationDetails( android: AndroidNotificationDetails( 'download_channel', 'Download Notifications', channelDescription: 'Notifications for PDF downloads', - importance: Importance.low, - priority: Priority.low, - showProgress: true, - maxProgress: 0, - ongoing: true, + importance: Importance.high, + priority: Priority.high, + showProgress: false, + ongoing: false, + autoCancel: true, icon: 'notification_icon', + actions: [ + AndroidNotificationAction('open_pdf', 'Open PDF', + showsUserInterface: true) + ], ), ), + payload: filePath, ); - - // --- 1. LOAD ASSETS --- - final logoImage = - pw.MemoryImage((await rootBundle.load('assets/images/logo.png')).buffer.asUint8List()); - final timesFont = await rootBundle.load("assets/fonts/Rubik-Regular.ttf"); - final timesBoldFont = await rootBundle.load("assets/fonts/Rubik-Bold.ttf"); - final ttf = pw.Font.ttf(timesFont); - final ttfBold = pw.Font.ttf(timesBoldFont); - - // --- 2. DEFINE COLORS --- - final primaryColor = PdfColor.fromHex("#1a5f3a"); - final secondaryColor = PdfColor.fromHex("#2e7d32"); - final debitColor = PdfColor.fromHex("#d32f2f"); - final lightGreyColor = PdfColor.fromHex("#666"); - final tableBorderColor = PdfColor.fromHex("#d0d0d0"); - final lightBgColor = PdfColor.fromHex("#f9f9f9"); - final warningBgColor = PdfColor.fromHex("#f8d7da"); - final warningBorderColor = PdfColor.fromHex("#f5c6cb"); - final warningTextColor = PdfColor.fromHex("#721c24"); - - // --- 3. CREATE PDF --- - final pdf = pw.Document( - theme: pw.ThemeData.withFont(base: ttf, bold: ttfBold), - ); - - // --- 4. BUILD PAGES --- - pdf.addPage( - pw.MultiPage( - pageFormat: PdfPageFormat.a4.copyWith( - marginTop: 15 * PdfPageFormat.mm, - marginLeft: 10 * PdfPageFormat.mm, - marginRight: 10 * PdfPageFormat.mm, - marginBottom: 20 * PdfPageFormat.mm, + + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('PDF saved to: $filePath'), ), - header: (context) => - _buildHeader(logoImage, primaryColor, lightGreyColor), - footer: (context) { - return pw.Center( - child: pw.Text( - '** This is only for information purpose and not for legal use **', - style: pw.TextStyle( - fontSize: 9, - color: lightGreyColor, - fontStyle: pw.FontStyle.italic))); - }, - build: (context) => [ - _buildAccountDetails( - customerName: selectedUser.name ?? '', - branchCode: selectedUser.branchId ?? '', - accountNo: selectedUser.accountNo ?? '', - cifNumber: selectedUser.cifNumber ?? '', - address: selectedUser.address ?? '', - lightGreyColor: lightGreyColor, - tableBorderColor: tableBorderColor, - lightBgColor: lightBgColor, - ), - _buildWarning(warningBgColor, warningBorderColor, debitColor, - warningTextColor), - _buildPeriodHeader( - primaryColor: primaryColor, - fromDate: fromDate, - toDate: toDate, - ), - _buildTransactionsTable( - transactions: _transactions, - primaryColor: primaryColor, - secondaryColor: secondaryColor, - debitColor: debitColor, - tableBorderColor: tableBorderColor, - ), - pw.SizedBox(height: 20), - pw.Text('END OF STATEMENT', - style: const pw.TextStyle(fontSize: 12)), - ], - ), - ); - - pdf.addPage( - pw.Page( - pageFormat: PdfPageFormat.a4.copyWith( - marginTop: 15 * PdfPageFormat.mm, - marginLeft: 10 * PdfPageFormat.mm, - marginRight: 10 * PdfPageFormat.mm, - marginBottom: 20 * PdfPageFormat.mm, - ), - build: (context) => _buildLastPage(), - ), - ); - - // --- 5. SAVE AND NOTIFY --- - try { - final Uint8List pdfBytes = await pdf.save(); - final String timestamp = - DateFormat("ddMMyyyy_HHmm").format(DateTime.now()); - final String fileName = 'Statement_${selectedUser.accountNo}_$timestamp.pdf'; - - String? filePath; - - if (Platform.isAndroid) { - final directory = Directory('/storage/emulated/0/Download'); - if (!await directory.exists()) { - await directory.create(recursive: true); - } - final file = File('${directory.path}/$fileName'); - await file.writeAsBytes(pdfBytes); - filePath = file.path; - } else { - final tempDir = await getTemporaryDirectory(); - final file = await File('${tempDir.path}/$fileName').create(); - await file.writeAsBytes(pdfBytes); - filePath = file.path; - } - - await flutterLocalNotificationsPlugin.show( - 0, - 'PDF Download Complete', - 'Your account statement has been saved.', - const NotificationDetails( - android: AndroidNotificationDetails( - 'download_channel', - 'Download Notifications', + ); + } + } catch (e) { + await flutterLocalNotificationsPlugin.show( + 0, + 'PDF Download Failed', + 'Error saving PDF: $e', + const NotificationDetails( + android: AndroidNotificationDetails( + 'download_channel', 'Download Notifications', channelDescription: 'Notifications for PDF downloads', importance: Importance.high, priority: Priority.high, showProgress: false, ongoing: false, - autoCancel: true, - icon: 'notification_icon', - actions: [ - AndroidNotificationAction('open_pdf', 'Open PDF', - showsUserInterface: true) + icon: 'notification_icon'), + ), + ); + + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error saving PDF: $e'), + ), + ); + } + } + } + + pw.Widget _buildHeader(pw.MemoryImage logoImage, PdfColor primaryColor, + PdfColor lightGreyColor) { + return pw.Container( + margin: const pw.EdgeInsets.only(bottom: 15), + padding: const pw.EdgeInsets.only(bottom: 12), + decoration: pw.BoxDecoration( + border: pw.Border(bottom: pw.BorderSide(color: primaryColor, width: 2)), + ), + child: pw.Row( + children: [ + pw.Image(logoImage, height: 55, width: 55), + pw.SizedBox(width: 12), + pw.Expanded( + child: pw.Column( + crossAxisAlignment: pw.CrossAxisAlignment.start, + children: [ + pw.Text( + 'THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.', + style: pw.TextStyle( + fontSize: 18, + color: primaryColor, + fontWeight: pw.FontWeight.bold, + letterSpacing: 0.3), + ), + pw.Text( + 'Head Office: Dharmsala, District Kangra (H.P.), Pin. 176215', + style: pw.TextStyle(fontSize: 10, color: lightGreyColor), + ), ], ), ), - payload: filePath, - ); - - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('PDF saved to: $filePath'), - ), - ); - } - } catch (e) { - await flutterLocalNotificationsPlugin.show( - 0, - 'PDF Download Failed', - 'Error saving PDF: $e', - const NotificationDetails( - android: AndroidNotificationDetails('download_channel', 'Download Notifications', - channelDescription: 'Notifications for PDF downloads', - importance: Importance.high, - priority: Priority.high, - showProgress: false, - ongoing: false, - icon: 'notification_icon'), + pw.Column( + crossAxisAlignment: pw.CrossAxisAlignment.end, + children: [ + pw.Text( + 'e-Statement Service', + style: pw.TextStyle( + fontSize: 11, + color: primaryColor, + fontWeight: pw.FontWeight.bold), + ), + pw.SizedBox(height: 2), + pw.Text( + 'Generated: ${DateFormat("dd/MM/yyyy HH:mm").format(DateTime.now())}', + style: pw.TextStyle(fontSize: 9, color: lightGreyColor), + ), + ], ), - ); + ], + ), + ); + } - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Error saving PDF: $e'), - ), - ); - } - } - } - - pw.Widget _buildHeader(pw.MemoryImage logoImage, PdfColor primaryColor, - PdfColor lightGreyColor) { - return pw.Container( - margin: const pw.EdgeInsets.only(bottom: 15), - padding: const pw.EdgeInsets.only(bottom: 12), - decoration: pw.BoxDecoration( - border: pw.Border(bottom: pw.BorderSide(color: primaryColor, width: 2)), - ), - child: pw.Row( + pw.Widget _buildAccountDetails({ + required String customerName, + required String branchCode, + required String accountNo, + required String cifNumber, + required String address, + required PdfColor lightGreyColor, + required PdfColor tableBorderColor, + required PdfColor lightBgColor, + }) { + const cellPadding = pw.EdgeInsets.symmetric(horizontal: 12, vertical: 8); + final border = pw.BorderSide(color: tableBorderColor, width: 1); + + return pw.Table( + border: pw.TableBorder( + top: border, + bottom: border, + left: border, + right: border, + horizontalInside: border, + verticalInside: border, + ), + columnWidths: { + 0: const pw.FlexColumnWidth(1), + 1: const pw.FlexColumnWidth(1), + }, + children: [ + pw.TableRow( children: [ - pw.Image(logoImage, height: 55, width: 55), - pw.SizedBox(width: 12), - pw.Expanded( + _buildDetailCell( + 'Customer Name', customerName, cellPadding, lightGreyColor), + _buildDetailCell( + 'CIF Number', cifNumber, cellPadding, lightGreyColor), + ], + ), + pw.TableRow( + children: [ + _buildDetailCell( + 'Account Number', accountNo, cellPadding, lightGreyColor), + _buildDetailCell( + 'Branch Code', branchCode, cellPadding, lightGreyColor), + ], + ), + pw.TableRow( + children: [ + pw.Container( + padding: cellPadding, + // Using a Column inside a single cell to potentially wrap long address child: pw.Column( crossAxisAlignment: pw.CrossAxisAlignment.start, children: [ pw.Text( - 'THE KANGRA CENTRAL CO-OPERATIVE BANK LTD.', - style: pw.TextStyle( - fontSize: 18, - color: primaryColor, - fontWeight: pw.FontWeight.bold, - letterSpacing: 0.3), - ), - pw.Text( - 'Head Office: Dharmsala, District Kangra (H.P.), Pin. 176215', + 'Customer Address', style: pw.TextStyle(fontSize: 10, color: lightGreyColor), ), + pw.SizedBox(height: 2), + pw.Text( + address, + style: pw.TextStyle( + fontSize: 11, fontWeight: pw.FontWeight.bold), + ), ], ), ), - pw.Column( - crossAxisAlignment: pw.CrossAxisAlignment.end, - children: [ - pw.Text( - 'e-Statement Service', + // Empty container for the second column in this row, as it's a single spanning column + pw.Container(), + ], + ), + ], + ); + } + + pw.Widget _buildDetailCell(String label, String value, pw.EdgeInsets padding, + PdfColor lightGreyColor, + {bool vertical = false}) { + final children = [ + pw.Text( + label, + style: pw.TextStyle(fontSize: 10, color: lightGreyColor), + ), + if (vertical) pw.SizedBox(height: 2), + pw.Text( + value, + style: pw.TextStyle(fontSize: 11, fontWeight: pw.FontWeight.bold), + ), + ]; + return pw.Padding( + padding: padding, + child: vertical + ? pw.Column( + crossAxisAlignment: pw.CrossAxisAlignment.start, + mainAxisAlignment: pw.MainAxisAlignment.start, + children: children) + : pw.Row( + mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, + children: children), + ); + } + + pw.Widget _buildWarning(PdfColor warningBgColor, PdfColor warningBorderColor, + PdfColor debitColor, PdfColor warningTextColor) { + return pw.Container( + margin: const pw.EdgeInsets.symmetric(vertical: 15), + padding: const pw.EdgeInsets.all(10), + decoration: pw.BoxDecoration( + color: warningBgColor, + border: pw.Border.all(color: warningBorderColor, width: 1), + borderRadius: pw.BorderRadius.circular(4), + ), + child: pw.Row( + crossAxisAlignment: pw.CrossAxisAlignment.start, + children: [ + pw.SizedBox(width: 10), + pw.Expanded( + child: pw.RichText( + text: pw.TextSpan( + style: pw.TextStyle( + fontSize: 10, color: warningTextColor, lineSpacing: 1.5), + children: [ + pw.TextSpan( + text: 'NEVER SHARE ', + style: pw.TextStyle(fontWeight: pw.FontWeight.bold)), + const pw.TextSpan( + text: + 'your Card number, CVV, PIN, OTP, Internet Banking User ID, Password or URB with anyone even if the caller claims to be a bank employee. Sharing these details can lead to unauthorized access to your account.'), + ], + ), + ), + ), + ], + ), + ); + } + + pw.Widget _buildPeriodHeader( + {required PdfColor primaryColor, DateTime? fromDate, DateTime? toDate}) { + String from = fromDate != null + ? DateFormat('dd/MM/yyyy').format(fromDate) + : 'the beginning'; + String to = + toDate != null ? DateFormat('dd/MM/yyyy').format(toDate) : 'today'; + + return pw.Container( + margin: const pw.EdgeInsets.only(bottom: 12), + padding: const pw.EdgeInsets.all(10), + decoration: pw.BoxDecoration( + border: pw.Border.symmetric( + horizontal: pw.BorderSide(color: primaryColor, width: 2)), + color: PdfColor.fromHex("#f5f5f5"), + ), + alignment: pw.Alignment.center, + child: pw.RichText( + text: pw.TextSpan( + style: pw.TextStyle( + fontSize: 13, + color: primaryColor, + fontWeight: pw.FontWeight.bold), + children: [ + const pw.TextSpan(text: 'Account statement from '), + pw.TextSpan( + text: from, + style: pw.TextStyle(fontWeight: pw.FontWeight.bold)), + const pw.TextSpan(text: ' to '), + pw.TextSpan( + text: to, style: pw.TextStyle(fontWeight: pw.FontWeight.bold)), + ], + ), + ), + ); + } + + pw.Widget _buildTransactionsTable({ + required List transactions, + required PdfColor primaryColor, + required PdfColor secondaryColor, + required PdfColor debitColor, + required PdfColor tableBorderColor, + }) { + //final border = pw.BorderSide(color: tableBorderColor, width: 1); + + return pw.Table( + border: pw.TableBorder.all(color: tableBorderColor, width: 1), + columnWidths: { + 0: const pw.FlexColumnWidth(1.5), + 1: const pw.FlexColumnWidth(4), + 2: const pw.FlexColumnWidth(2.2), + 3: const pw.FlexColumnWidth(2.2), + }, + children: [ + pw.TableRow( + decoration: pw.BoxDecoration(color: secondaryColor), + children: [ + pw.Padding( + padding: const pw.EdgeInsets.all(10), + child: pw.Text('Date', + textAlign: pw.TextAlign.center, style: pw.TextStyle( fontSize: 11, - color: primaryColor, - fontWeight: pw.FontWeight.bold), - ), - pw.SizedBox(height: 2), - pw.Text( - 'Generated: ${DateFormat("dd/MM/yyyy HH:mm").format(DateTime.now())}', - style: pw.TextStyle(fontSize: 9, color: lightGreyColor), - ), - ], + fontWeight: pw.FontWeight.bold, + color: PdfColors.white)), + ), + pw.Padding( + padding: const pw.EdgeInsets.all(10), + child: pw.Text('Mode / Particulars', + textAlign: pw.TextAlign.left, + style: pw.TextStyle( + fontSize: 11, + fontWeight: pw.FontWeight.bold, + color: PdfColors.white)), + ), + pw.Padding( + padding: const pw.EdgeInsets.all(10), + child: pw.Text('Withdrawals / Deposits', + textAlign: pw.TextAlign.center, + style: pw.TextStyle( + fontSize: 11, + fontWeight: pw.FontWeight.bold, + color: PdfColors.white)), + ), + pw.Padding( + padding: const pw.EdgeInsets.all(10), + child: pw.Text('Balance', + textAlign: pw.TextAlign.center, + style: pw.TextStyle( + fontSize: 11, + fontWeight: pw.FontWeight.bold, + color: PdfColors.white)), ), ], ), - ); - } - - pw.Widget _buildAccountDetails({ - required String customerName, - required String branchCode, - required String accountNo, - required String cifNumber, - required String address, - required PdfColor lightGreyColor, - required PdfColor tableBorderColor, - required PdfColor lightBgColor, - }) { - const cellPadding = pw.EdgeInsets.symmetric(horizontal: 12, vertical: 8); - final border = pw.BorderSide(color: tableBorderColor, width: 1); - - return pw.Table( - border: pw.TableBorder( - top: border, - bottom: border, - left: border, - right: border, - horizontalInside: border, - verticalInside: border, - ), - columnWidths: { - 0: const pw.FlexColumnWidth(1), - 1: const pw.FlexColumnWidth(1), - }, - children: [ - pw.TableRow( + ...transactions.map((tx) { + final amount = double.tryParse(tx.amount ?? '0') ?? 0; + final isDebit = tx.type == 'DR'; + return pw.TableRow( + decoration: const pw.BoxDecoration(color: PdfColors.white), children: [ - _buildDetailCell('Customer Name', customerName, cellPadding, lightGreyColor), - _buildDetailCell('CIF Number', cifNumber, cellPadding, lightGreyColor), - ], - ), - pw.TableRow( - children: [ - _buildDetailCell('Account Number', accountNo, cellPadding, lightGreyColor), - _buildDetailCell('Branch Code', branchCode, cellPadding, lightGreyColor), - ], - ), - pw.TableRow( - children: [ - pw.Container( - padding: cellPadding, - // Using a Column inside a single cell to potentially wrap long address - child: pw.Column( - crossAxisAlignment: pw.CrossAxisAlignment.start, - children: [ - pw.Text( - 'Customer Address', - style: pw.TextStyle(fontSize: 10, color: lightGreyColor), - ), - pw.SizedBox(height: 2), - pw.Text( - address, - style: pw.TextStyle(fontSize: 11, fontWeight: pw.FontWeight.bold), - ), - ], + pw.Padding( + padding: const pw.EdgeInsets.all(8), + child: pw.Text(tx.date ?? '', + textAlign: pw.TextAlign.center, + style: const pw.TextStyle(fontSize: 11)), + ), + pw.Padding( + padding: const pw.EdgeInsets.all(8), + child: pw.Text(tx.name ?? '', + textAlign: pw.TextAlign.left, + style: const pw.TextStyle(fontSize: 11)), + ), + pw.Padding( + padding: const pw.EdgeInsets.all(8), + child: pw.Text( + '${NumberFormat.currency(locale: 'en_IN', symbol: '₹').format(amount)} ${tx.type}', + textAlign: pw.TextAlign.right, + style: pw.TextStyle( + fontSize: 11, + color: isDebit ? debitColor : secondaryColor, + fontWeight: pw.FontWeight.bold, + ), + ), + ), + pw.Padding( + padding: const pw.EdgeInsets.all(8), + child: pw.Text( + '${NumberFormat.currency(locale: 'en_IN', symbol: '₹').format(double.tryParse(tx.balance ?? '0') ?? 0)} ${tx.balanceType ?? ''}', + textAlign: pw.TextAlign.right, + style: pw.TextStyle( + fontSize: 11, fontWeight: pw.FontWeight.bold), ), ), - // Empty container for the second column in this row, as it's a single spanning column - pw.Container(), ], + ); + }), + ], + ); + } + + pw.Widget _buildLastPage() { + return pw.Container( + padding: const pw.EdgeInsets.all(20), + decoration: pw.BoxDecoration( + border: pw.Border.all(color: PdfColors.black, width: 2), + color: PdfColor.fromHex("#fafafa"), + borderRadius: pw.BorderRadius.circular(4), + ), + child: pw.Column( + crossAxisAlignment: pw.CrossAxisAlignment.start, + children: [ + pw.Text( + 'IMPORTANT INFORMATION:', + style: pw.TextStyle( + fontSize: 11, + fontWeight: pw.FontWeight.bold, + color: PdfColors.black, + ), ), + pw.SizedBox(height: 15), + ..._buildInfoPoints(PdfColors.black, [ + 'The Kangra Central Cooperative Bank Officials or representatives will NEVER ask you for your personal information i.e. your card details, passwords, PIN, CVV, OTP etc. Do not share such details with anyone over phone, SMS or email.', + 'Always stay vigilant to suspicious emails. Do not open any suspicious emails.', + 'Always stay vigilant when giving out sensitive personal or account information.', + 'Beware of messages that instill a sense of urgency (e.g., account will expire unless you "verify" your information). Contact the Bank directly if unsure.', + 'Always log out of secondary devices and reset your passwords frequently.', + 'Use strong passwords: Create strong passwords that are difficult for hackers to guess.', + 'Use public Wi-Fi with caution: Be careful when using public Wi-Fi networks.', + 'Back up your data regularly to a secure, encrypted, off-site location.', + 'Follow corporate security policies: Adhere to your company\'s security guidelines.', + 'Assess third-party app permissions carefully before granting access.', + 'Lock your computer and mobile phone when not in use.', + 'Don\'t leave devices unattended. Keep all mobile devices, such as laptops and cell phones, physically secured.', + 'Don\'t leave Bluetooth / Wireless turned on when not in use. Enable them only when needed and in a safe environment.', + ]), ], - ); - } - - pw.Widget _buildDetailCell(String label, String value, pw.EdgeInsets padding, - PdfColor lightGreyColor, {bool vertical = false}) { - final children = [ - pw.Text( - label, - style: pw.TextStyle(fontSize: 10, color: lightGreyColor), - ), - if (vertical) pw.SizedBox(height: 2), - pw.Text( - value, - style: pw.TextStyle(fontSize: 11, fontWeight: pw.FontWeight.bold), - ), - ]; + ), + ); + } + + List _buildInfoPoints(PdfColor primaryColor, List points) { + return points.map((point) { return pw.Padding( - padding: padding, - child: vertical - ? pw.Column( - crossAxisAlignment: pw.CrossAxisAlignment.start, - mainAxisAlignment: pw.MainAxisAlignment.start, - children: children) - : pw.Row( - mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, - children: children), - ); - } - - pw.Widget _buildWarning(PdfColor warningBgColor, PdfColor warningBorderColor, - PdfColor debitColor, PdfColor warningTextColor) { - return pw.Container( - margin: const pw.EdgeInsets.symmetric(vertical: 15), - padding: const pw.EdgeInsets.all(10), - decoration: pw.BoxDecoration( - color: warningBgColor, - border: pw.Border.all(color: warningBorderColor, width: 1), - borderRadius: pw.BorderRadius.circular(4), - ), + padding: const pw.EdgeInsets.only(bottom: 10), child: pw.Row( crossAxisAlignment: pw.CrossAxisAlignment.start, children: [ - pw.SizedBox(width: 10), - pw.Expanded( - child: pw.RichText( - text: pw.TextSpan( - style: pw.TextStyle( - fontSize: 10, - color: warningTextColor, - lineSpacing: 1.5), - children: [ - pw.TextSpan( - text: 'NEVER SHARE ', - style: pw.TextStyle(fontWeight: pw.FontWeight.bold)), - const pw.TextSpan( - text: - 'your Card number, CVV, PIN, OTP, Internet Banking User ID, Password or URB with anyone even if the caller claims to be a bank employee. Sharing these details can lead to unauthorized access to your account.'), - ], - ), - ), - ), - ], - ), - ); - } - - pw.Widget _buildPeriodHeader( - {required PdfColor primaryColor, DateTime? fromDate, DateTime? toDate}) { - String from = fromDate != null - ? DateFormat('dd/MM/yyyy').format(fromDate) - : 'the beginning'; - String to = - toDate != null ? DateFormat('dd/MM/yyyy').format(toDate) : 'today'; - - return pw.Container( - margin: const pw.EdgeInsets.only(bottom: 12), - padding: const pw.EdgeInsets.all(10), - decoration: pw.BoxDecoration( - border: pw.Border.symmetric( - horizontal: pw.BorderSide(color: primaryColor, width: 2)), - color: PdfColor.fromHex("#f5f5f5"), - ), - alignment: pw.Alignment.center, - child: pw.RichText( - text: pw.TextSpan( - style: pw.TextStyle( - fontSize: 13, - color: primaryColor, - fontWeight: pw.FontWeight.bold), - children: [ - const pw.TextSpan(text: 'Account statement from '), - pw.TextSpan( - text: from, - style: pw.TextStyle(fontWeight: pw.FontWeight.bold)), - const pw.TextSpan(text: ' to '), - pw.TextSpan( - text: to, - style: pw.TextStyle(fontWeight: pw.FontWeight.bold)), - ], - ), - ), - ); - } - - pw.Widget _buildTransactionsTable({ - required List transactions, - required PdfColor primaryColor, - required PdfColor secondaryColor, - required PdfColor debitColor, - required PdfColor tableBorderColor, - }) { - //final border = pw.BorderSide(color: tableBorderColor, width: 1); - - return pw.Table( - border: pw.TableBorder.all(color: tableBorderColor, width: 1), - columnWidths: { - 0: const pw.FlexColumnWidth(1.5), - 1: const pw.FlexColumnWidth(4), - 2: const pw.FlexColumnWidth(2.2), - 3: const pw.FlexColumnWidth(2.2), - }, - children: [ - pw.TableRow( - decoration: pw.BoxDecoration(color: secondaryColor), - children: [ - pw.Padding( - padding: const pw.EdgeInsets.all(10), - child: pw.Text('Date', - textAlign: pw.TextAlign.center, - style: pw.TextStyle( - fontSize: 11, - fontWeight: pw.FontWeight.bold, - color: PdfColors.white)), - ), - pw.Padding( - padding: const pw.EdgeInsets.all(10), - child: pw.Text('Mode / Particulars', - textAlign: pw.TextAlign.left, - style: pw.TextStyle( - fontSize: 11, - fontWeight: pw.FontWeight.bold, - color: PdfColors.white)), - ), - pw.Padding( - padding: const pw.EdgeInsets.all(10), - child: pw.Text('Withdrawals / Deposits', - textAlign: pw.TextAlign.center, - style: pw.TextStyle( - fontSize: 11, - fontWeight: pw.FontWeight.bold, - color: PdfColors.white)), - ), - pw.Padding( - padding: const pw.EdgeInsets.all(10), - child: pw.Text('Balance', - textAlign: pw.TextAlign.center, - style: pw.TextStyle( - fontSize: 11, - fontWeight: pw.FontWeight.bold, - color: PdfColors.white)), - ), - ], - ), - ...transactions.map((tx) { - final amount = double.tryParse(tx.amount ?? '0') ?? 0; - final isDebit = tx.type == 'DR'; - return pw.TableRow( - decoration: const pw.BoxDecoration(color: PdfColors.white), - children: [ - pw.Padding( - padding: const pw.EdgeInsets.all(8), - child: pw.Text(tx.date ?? '', - textAlign: pw.TextAlign.center, - style: const pw.TextStyle(fontSize: 11)), - ), - pw.Padding( - padding: const pw.EdgeInsets.all(8), - child: pw.Text(tx.name ?? '', - textAlign: pw.TextAlign.left, - style: const pw.TextStyle(fontSize: 11)), - ), - pw.Padding( - padding: const pw.EdgeInsets.all(8), - child: pw.Text( - '${NumberFormat.currency(locale: 'en_IN', symbol: '₹').format(amount)} ${tx.type}', - textAlign: pw.TextAlign.right, - style: pw.TextStyle( - fontSize: 11, - color: isDebit ? debitColor : secondaryColor, - fontWeight: pw.FontWeight.bold, - ), - ), - ), - pw.Padding( - padding: const pw.EdgeInsets.all(8), - child: pw.Text( - '${NumberFormat.currency(locale: 'en_IN', symbol: '₹').format(double.tryParse(tx.balance ?? '0') ?? 0)} ${tx.balanceType ?? ''}', - textAlign: pw.TextAlign.right, - style: pw.TextStyle( - fontSize: 11, fontWeight: pw.FontWeight.bold), - ), - ), - ], - ); - }), - ], - ); - } - - - pw.Widget _buildLastPage() { - return pw.Container( - padding: const pw.EdgeInsets.all(20), - decoration: pw.BoxDecoration( - border: pw.Border.all(color: PdfColors.black, width: 2), - color: PdfColor.fromHex("#fafafa"), - borderRadius: pw.BorderRadius.circular(4), - ), - child: pw.Column( - crossAxisAlignment: pw.CrossAxisAlignment.start, - children: [ - pw.Text( - 'IMPORTANT INFORMATION:', - style: pw.TextStyle( - fontSize: 11, - fontWeight: pw.FontWeight.bold, - color: PdfColors.black, - ), - ), - pw.SizedBox(height: 15), - ..._buildInfoPoints(PdfColors.black, [ - 'The Kangra Central Cooperative Bank Officials or representatives will NEVER ask you for your personal information i.e. your card details, passwords, PIN, CVV, OTP etc. Do not share such details with anyone over phone, SMS or email.', - 'Always stay vigilant to suspicious emails. Do not open any suspicious emails.', - 'Always stay vigilant when giving out sensitive personal or account information.', - 'Beware of messages that instill a sense of urgency (e.g., account will expire unless you "verify" your information). Contact the Bank directly if unsure.', - 'Always log out of secondary devices and reset your passwords frequently.', - 'Use strong passwords: Create strong passwords that are difficult for hackers to guess.', - 'Use public Wi-Fi with caution: Be careful when using public Wi-Fi networks.', - 'Back up your data regularly to a secure, encrypted, off-site location.', - 'Follow corporate security policies: Adhere to your company\'s security guidelines.', - 'Assess third-party app permissions carefully before granting access.', - 'Lock your computer and mobile phone when not in use.', - 'Don\'t leave devices unattended. Keep all mobile devices, such as laptops and cell phones, physically secured.', - 'Don\'t leave Bluetooth / Wireless turned on when not in use. Enable them only when needed and in a safe environment.', - ]), - ], - ), - ); - } - List _buildInfoPoints( - PdfColor primaryColor, List points) { - return points.map((point) { - return pw.Padding( - padding: const pw.EdgeInsets.only(bottom: 10), - child: pw.Row( - crossAxisAlignment: pw.CrossAxisAlignment.start, - children: [ - pw.Container( - width: 15, - child: pw.Text('*', - style: pw.TextStyle( - color: primaryColor, - fontSize: 12, - fontWeight: pw.FontWeight.bold))), - pw.Expanded( - child: pw.Text( - point, + pw.Container( + width: 15, + child: pw.Text('*', style: pw.TextStyle( - fontSize: 11, - lineSpacing: 1.6, - fontWeight: pw.FontWeight.bold), - ), - ), - ], + color: primaryColor, + fontSize: 12, + fontWeight: pw.FontWeight.bold))), + pw.Expanded( + child: pw.Text( + point, + style: pw.TextStyle( + fontSize: 11, + lineSpacing: 1.6, + fontWeight: pw.FontWeight.bold), + ), ), - ); - }).toList(); - } Widget buildDateBox(String label, DateTime? date) { + ], + ), + ); + }).toList(); + } + + Widget buildDateBox(String label, DateTime? date) { return Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16), decoration: BoxDecoration( diff --git a/lib/features/accounts/screens/all_accounts_screen.dart b/lib/features/accounts/screens/all_accounts_screen.dart index 64b93a2..f2582b0 100644 --- a/lib/features/accounts/screens/all_accounts_screen.dart +++ b/lib/features/accounts/screens/all_accounts_screen.dart @@ -20,7 +20,7 @@ class _AllAccountsScreenState extends State { // In a real app, this should be moved to a utility/helper class. if (accountType == null || accountType.isEmpty) return 'N/A'; switch (accountType.toLowerCase()) { - case 'sa': + case 'sa': return AppLocalizations.of(context).savingsAccount; case 'sb': return AppLocalizations.of(context).savingsAccount; @@ -36,7 +36,7 @@ class _AllAccountsScreenState extends State { return "Cash Credit Account"; case 'od': return "Overdraft Account"; - default: + default: return AppLocalizations.of(context).unknownAccount; } } @@ -52,19 +52,19 @@ class _AllAccountsScreenState extends State { const SizedBox(height: 16.0), // Added space below the app bar Expanded( child: ListView.builder( - itemCount: widget.users.length, - itemBuilder: (context, index) { - final user = widget.users[index]; - return Padding( - padding: - const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), - child: _buildAccountCard(user), - ); - }, - ), + itemCount: widget.users.length, + itemBuilder: (context, index) { + final user = widget.users[index]; + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, vertical: 8.0), + child: _buildAccountCard(user), + ); + }, + ), ), // Closing Expanded ], // Closing Column - ), + ), ); } diff --git a/lib/features/customer_info/screens/customer_info_screen.dart b/lib/features/customer_info/screens/customer_info_screen.dart index 2b2cd4f..4fae5c2 100644 --- a/lib/features/customer_info/screens/customer_info_screen.dart +++ b/lib/features/customer_info/screens/customer_info_screen.dart @@ -104,7 +104,9 @@ class _CustomerInfoScreenState extends State { width: double.infinity, child: CupertinoSlidingSegmentedControl( groupValue: _selectedCard, - thumbColor: Theme.of(context).colorScheme.onPrimary, // Set selected switch color to theme primary color + thumbColor: Theme.of(context) + .colorScheme + .onPrimary, // Set selected switch color to theme primary color onValueChanged: (int? newValue) { if (newValue != null) { setState(() { @@ -112,14 +114,18 @@ class _CustomerInfoScreenState extends State { }); } }, - children: { + children: { 0: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), - child: Text(AppLocalizations.of(context).personaldetails), + padding: const EdgeInsets.symmetric( + horizontal: 20, vertical: 10), + child: Text( + AppLocalizations.of(context).personaldetails), ), 1: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), - child: Text(AppLocalizations.of(context).kycdetails), + padding: const EdgeInsets.symmetric( + horizontal: 20, vertical: 10), + child: + Text(AppLocalizations.of(context).kycdetails), ), }, ), diff --git a/lib/features/dashboard/screens/dashboard_screen.dart b/lib/features/dashboard/screens/dashboard_screen.dart index 9871065..6e5be62 100644 --- a/lib/features/dashboard/screens/dashboard_screen.dart +++ b/lib/features/dashboard/screens/dashboard_screen.dart @@ -9,7 +9,6 @@ import 'package:kmobile/features/accounts/screens/all_accounts_screen.dart'; import 'package:kmobile/features/auth/controllers/auth_cubit.dart'; import 'package:kmobile/features/auth/controllers/auth_state.dart'; import 'package:kmobile/features/customer_info/screens/customer_info_screen.dart'; -import 'package:kmobile/features/cheque/screens/cheque_management_screen.dart'; import 'package:kmobile/features/beneficiaries/screens/manage_beneficiaries_screen.dart'; import 'package:kmobile/features/enquiry/screens/enquiry_screen.dart'; import 'package:kmobile/features/fund_transfer/screens/fund_transfer_screen.dart'; @@ -65,8 +64,6 @@ class _DashboardScreenState extends State }); } - - Widget _buildAccountCard(User user, bool isSelected) { final theme = Theme.of(context); final bool isCardVisible = _visibilityMap[user.accountNo] ?? false; @@ -78,143 +75,143 @@ class _DashboardScreenState extends State duration: const Duration(milliseconds: 200), scale: scale, child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 18, - vertical: 10, - ), - decoration: BoxDecoration( - color: const Color(0xFF01A04C), - borderRadius: BorderRadius.circular(20), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Top section with account type and number (no refresh button here) - Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - getFullAccountType(user.accountType), - style: TextStyle( - color: theme.colorScheme.onPrimary, - fontSize: 16, - fontWeight: FontWeight.w700, - ), + padding: const EdgeInsets.symmetric( + horizontal: 18, + vertical: 10, + ), + decoration: BoxDecoration( + color: const Color(0xFF01A04C), + borderRadius: BorderRadius.circular(20), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Top section with account type and number (no refresh button here) + Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + getFullAccountType(user.accountType), + style: TextStyle( + color: theme.colorScheme.onPrimary, + fontSize: 16, + fontWeight: FontWeight.w700, ), - Text( - user.accountNo ?? 'N/A', - style: TextStyle( - color: theme.colorScheme.onPrimary, - fontSize: 14, - fontWeight: FontWeight.w700, - ), - overflow: TextOverflow.ellipsis, + ), + Text( + user.accountNo ?? 'N/A', + style: TextStyle( + color: theme.colorScheme.onPrimary, + fontSize: 14, + fontWeight: FontWeight.w700, ), - ], + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), + if (isSelected) // Show logo only if card is selected + CircleAvatar( + radius: 20, + backgroundColor: Colors.white, + child: Padding( + padding: const EdgeInsets.all(2.0), + child: ClipOval( + child: Image.asset( + 'assets/images/logo.png', + width: 30, + height: 30, + fit: BoxFit.cover, + ), + ), ), ), - if (isSelected) // Show logo only if card is selected - CircleAvatar( - radius: 20, - backgroundColor: Colors.white, - child: Padding( - padding: const EdgeInsets.all(2.0), - child: ClipOval( - child: Image.asset( - 'assets/images/logo.png', - width: 30, - height: 30, - fit: BoxFit.cover, + ], + ), + const Spacer(), + // Bottom section with balance and combined toggle/refresh + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + if (isRefreshing && isSelected) + Expanded(child: _buildBalanceShimmer()) + else + Expanded( + child: FittedBox( + fit: BoxFit.scaleDown, + alignment: Alignment.centerLeft, + child: Row( + children: [ + Text( + "₹ ", + style: TextStyle( + color: theme.colorScheme.onPrimary, + fontSize: 40, + fontWeight: FontWeight.w700, + ), ), - ), + Text( + isCardVisible + ? user.currentBalance ?? '0.00' + : '*****', + style: TextStyle( + color: theme.colorScheme.onPrimary, + fontSize: 40, + fontWeight: FontWeight.w700, + ), + ), + ], ), ), - ], - ), - const Spacer(), - // Bottom section with balance and combined toggle/refresh - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - if (isRefreshing && isSelected) - Expanded(child: _buildBalanceShimmer()) - else - Expanded( - child: FittedBox( - fit: BoxFit.scaleDown, - alignment: Alignment.centerLeft, - child: Row( - children: [ - Text( - "₹ ", - style: TextStyle( - color: theme.colorScheme.onPrimary, - fontSize: 40, - fontWeight: FontWeight.w700, - ), - ), - Text( - isCardVisible - ? user.currentBalance ?? '0.00' - : '*****', - style: TextStyle( - color: theme.colorScheme.onPrimary, - fontSize: 40, - fontWeight: FontWeight.w700, - ), - ), - ], - ), - ), - ), - const SizedBox(width: 10), // A steady space - if (isSelected) // Only show toggle for selected card - InkWell( - onTap: () async { - if (isRefreshing) - return; // Prevent taps while refreshing - final accountNo = user.accountNo; - if (accountNo == null) return; + ), + const SizedBox(width: 10), // A steady space + if (isSelected) // Only show toggle for selected card + InkWell( + onTap: () async { + if (isRefreshing) + return; // Prevent taps while refreshing + final accountNo = user.accountNo; + if (accountNo == null) return; - final bool currentVisibility = - _visibilityMap[accountNo] ?? false; + final bool currentVisibility = + _visibilityMap[accountNo] ?? false; - if (!currentVisibility) { - // If hidden, refresh data and then show the balance - await _refreshAccountData(context); - if (mounted) { - setState(() { - _visibilityMap[accountNo] = true; - }); - } - } else { - // If visible, just hide it + if (!currentVisibility) { + // If hidden, refresh data and then show the balance + await _refreshAccountData(context); + if (mounted) { setState(() { - _visibilityMap[accountNo] = false; + _visibilityMap[accountNo] = true; }); } - }, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Icon( - isCardVisible - ? Symbols.visibility_lock - : Symbols.visibility, - color: theme.scaffoldBackgroundColor, - weight: 800, - ), + } else { + // If visible, just hide it + setState(() { + _visibilityMap[accountNo] = false; + }); + } + }, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Icon( + isCardVisible + ? Symbols.visibility_lock + : Symbols.visibility, + color: theme.scaffoldBackgroundColor, + weight: 800, ), ), - ], - ), - const Spacer(), - ], - ), + ), + ], + ), + const Spacer(), + ], ), ), + ), ); } @@ -296,7 +293,7 @@ class _DashboardScreenState extends State return "Cash Credit Account"; case 'od': return "Overdraft Account"; - default: + default: return AppLocalizations.of(context).unknownAccount; } } @@ -346,21 +343,19 @@ class _DashboardScreenState extends State @override Widget build(BuildContext context) { final theme = Theme.of(context); - final authState = context.read().state; - String mobileNumberToPass = ''; - String customerNo = ''; - String customerName = ''; - if (authState is Authenticated) { - if (selectedAccountIndex >= 0 && - selectedAccountIndex < authState.users.length) { - mobileNumberToPass = - authState.users[selectedAccountIndex].mobileNo ?? ''; - customerNo = - authState.users[selectedAccountIndex].cifNumber ?? ''; - customerName = - authState.users[selectedAccountIndex].name ?? ''; - } - } + final authState = context.read().state; + String mobileNumberToPass = ''; + String customerNo = ''; + String customerName = ''; + if (authState is Authenticated) { + if (selectedAccountIndex >= 0 && + selectedAccountIndex < authState.users.length) { + mobileNumberToPass = + authState.users[selectedAccountIndex].mobileNo ?? ''; + customerNo = authState.users[selectedAccountIndex].cifNumber ?? ''; + customerName = authState.users[selectedAccountIndex].name ?? ''; + } + } return BlocListener( listener: (context, state) async { if (state is Authenticated && !_biometricPromptShown) { @@ -416,8 +411,6 @@ class _DashboardScreenState extends State child: InkWell( borderRadius: BorderRadius.circular(20), onTap: () { - - Navigator.push( context, MaterialPageRoute( @@ -431,7 +424,7 @@ class _DashboardScreenState extends State child: const CircleAvatar( radius: 21, child: Icon( - Symbols.person, + Symbols.person, size: 30, ), ), @@ -454,8 +447,7 @@ class _DashboardScreenState extends State // first‐time load if (!_txInitialized) { _txInitialized = true; - WidgetsBinding.instance.addPostFrameCallback((_) { - }); + WidgetsBinding.instance.addPostFrameCallback((_) {}); } _pageController ??= PageController( initialPage: selectedAccountIndex, @@ -489,11 +481,11 @@ class _DashboardScreenState extends State child: PageView.builder( clipBehavior: Clip.none, controller: _pageController, - itemCount: users.length, // Keep this to show adjacent cards + itemCount: + users.length, // Keep this to show adjacent cards onPageChanged: (int newIndex) async { - if (newIndex == selectedAccountIndex) - return; + if (newIndex == selectedAccountIndex) return; // Hide the balance of the old card when scrolling away final oldAccountNo = @@ -508,10 +500,8 @@ class _DashboardScreenState extends State }, itemBuilder: (context, index) { final user = users[index]; - final isSelected = - index == selectedAccountIndex; - return _buildAccountCard( - user, isSelected); + final isSelected = index == selectedAccountIndex; + return _buildAccountCard(user, isSelected); }, ), ), @@ -524,7 +514,8 @@ class _DashboardScreenState extends State Navigator.push( context, MaterialPageRoute( - builder: (context) => AllAccountsScreen(users: users), + builder: (context) => + AllAccountsScreen(users: users), ), ); }, @@ -625,8 +616,8 @@ class _DashboardScreenState extends State selectedIndex: selectedAccountIndex, ))); }), - _buildQuickLink(Icons.location_pin, AppLocalizations.of(context).branchlocator, - () { + _buildQuickLink(Icons.location_pin, + AppLocalizations.of(context).branchlocator, () { Navigator.push( context, MaterialPageRoute( @@ -658,12 +649,11 @@ class _DashboardScreenState extends State Navigator.push( context, MaterialPageRoute( - builder: (context) => - ProfileScreen( - mobileNumber: mobileNumberToPass, - customerNo: customerNo, - customerName: customerName), - ), + builder: (context) => ProfileScreen( + mobileNumber: mobileNumberToPass, + customerNo: customerNo, + customerName: customerName), + ), ); }, disable: false, @@ -684,32 +674,6 @@ class _DashboardScreenState extends State ); } - List _buildTransactionShimmer() { - final theme = Theme.of(context); - return List.generate(3, (i) { - return ListTile( - leading: Shimmer.fromColors( - baseColor: Colors.grey[300]!, - highlightColor: Colors.grey[100]!, - child: CircleAvatar( - radius: 12, backgroundColor: theme.scaffoldBackgroundColor), - ), - title: Shimmer.fromColors( - baseColor: Colors.grey[300]!, - highlightColor: Colors.grey[100]!, - child: Container( - height: 10, width: 100, color: theme.scaffoldBackgroundColor), - ), - subtitle: Shimmer.fromColors( - baseColor: Colors.grey[300]!, - highlightColor: Colors.grey[100]!, - child: Container( - height: 8, width: 60, color: theme.scaffoldBackgroundColor), - ), - ); - }); - } - Widget _buildQuickLink( IconData icon, String label, diff --git a/lib/features/fund_transfer/screens/fund_transfer_screen.dart b/lib/features/fund_transfer/screens/fund_transfer_screen.dart index fcdd8cd..9c14d4a 100644 --- a/lib/features/fund_transfer/screens/fund_transfer_screen.dart +++ b/lib/features/fund_transfer/screens/fund_transfer_screen.dart @@ -43,7 +43,8 @@ class FundTransferScreen extends StatelessWidget { child: FundTransferManagementTile( icon: Symbols.person, label: "Self Pay", - subtitle: AppLocalizations.of(context).ftselfpaysubtitle, + subtitle: + AppLocalizations.of(context).ftselfpaysubtitle, onTap: () { Navigator.push( context, @@ -86,7 +87,8 @@ class FundTransferScreen extends StatelessWidget { child: FundTransferManagementTile( icon: Symbols.output_circle, label: AppLocalizations.of(context).outsideBank, - subtitle: AppLocalizations.of(context).ftoutsidesubtitle, + subtitle: + AppLocalizations.of(context).ftoutsidesubtitle, onTap: () { Navigator.push( context, diff --git a/lib/features/profile/change_limit_otp_screen.dart b/lib/features/profile/change_limit_otp_screen.dart index 50e4c66..0b47156 100644 --- a/lib/features/profile/change_limit_otp_screen.dart +++ b/lib/features/profile/change_limit_otp_screen.dart @@ -45,11 +45,9 @@ class _ChangeLimitOTPScreenState extends State { double.parse(widget.newLimit), ); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text("Limit has been Changed"), - ) - ); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text("Limit has been Changed"), + )); // Navigate back to profile or login Navigator.of(context).popUntil((route) => route.isFirst); diff --git a/lib/features/profile/profile_screen.dart b/lib/features/profile/profile_screen.dart index 7ac550b..a469c3c 100644 --- a/lib/features/profile/profile_screen.dart +++ b/lib/features/profile/profile_screen.dart @@ -172,241 +172,242 @@ 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( + 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: const CircleAvatar( + radius: 50, + child: Icon( + Symbols.person, + size: 56, + ), + ), + ), + const SizedBox(width: 12), + // Name + mobile + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Avatar - Container( - width: 56, - height: 56, - child: const CircleAvatar( - radius: 50, - child: Icon( - Symbols.person, - size: 56, - ), + 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(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: 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, - ), - ), - ); - }, - ), - _SectionTile( - leadingIcon: Icons.currency_rupee, - title: loc.dailylimit, - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - DailyLimitScreen(mobileNumber: widget.mobileNumber), - ), - ); - }, - ), - 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), - ], + ], + ), ), - ], - ), ); + ), + + 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, + ), + ), + ); + }, + ), + _SectionTile( + leadingIcon: Icons.currency_rupee, + title: loc.dailylimit, + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + DailyLimitScreen(mobileNumber: widget.mobileNumber), + ), + ); + }, + ), + 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/features/service/screens/atm_locator_screen.dart b/lib/features/service/screens/atm_locator_screen.dart index db72734..0a39ebe 100644 --- a/lib/features/service/screens/atm_locator_screen.dart +++ b/lib/features/service/screens/atm_locator_screen.dart @@ -62,7 +62,8 @@ class _ATMLocatorScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(AppLocalizations.of(context).atmlocator), // Title for the app bar + title: Text( + AppLocalizations.of(context).atmlocator), // Title for the app bar ), body: Stack( children: [ diff --git a/lib/features/service/screens/faqs_screen.dart b/lib/features/service/screens/faqs_screen.dart index cd8da78..303bab0 100644 --- a/lib/features/service/screens/faqs_screen.dart +++ b/lib/features/service/screens/faqs_screen.dart @@ -50,7 +50,7 @@ class _FaqsScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(AppLocalizations.of(context).faq), + title: Text(AppLocalizations.of(context).faq), ), body: Stack( children: [