From 0c1d6fc7185fb6baf924d4bae8712898587093e1 Mon Sep 17 00:00:00 2001 From: Trina Bakshi Date: Sat, 31 May 2025 21:49:09 +0530 Subject: [PATCH] updated screens design for demo --- .../accounts/screens/account_info_screen.dart | 2 +- .../screens/account_statement_screen.dart | 228 +++++++++++------- lib/features/auth/screens/mpin_screen.dart | 8 +- .../screens/add_beneficiary_screen.dart | 32 +++ .../dashboard/screens/dashboard_screen.dart | 16 +- .../screens/fund_transfer_screen.dart | 11 + .../quick_pay_outside_bank_screen.dart | 73 +++++- .../screens/quick_pay_within_bank_screen.dart | 49 +++- 8 files changed, 309 insertions(+), 110 deletions(-) diff --git a/lib/features/accounts/screens/account_info_screen.dart b/lib/features/accounts/screens/account_info_screen.dart index b432cda..ec25e4e 100644 --- a/lib/features/accounts/screens/account_info_screen.dart +++ b/lib/features/accounts/screens/account_info_screen.dart @@ -35,7 +35,7 @@ class _AccountInfoScreen extends State{ padding: const EdgeInsets.all(16.0), children: const [ InfoRow(title: 'Account Number', value: '700127638009871'), - InfoRow(title: 'Nominee Customer No', value: '700127638009871'), + // InfoRow(title: 'Nominee Customer No', value: '700127638009871'), InfoRow(title: 'SMS Service', value: 'Active'), InfoRow(title: 'Missed Call Service', value: 'Active'), InfoRow(title: 'Customer Number', value: '9000875272000212'), diff --git a/lib/features/accounts/screens/account_statement_screen.dart b/lib/features/accounts/screens/account_statement_screen.dart index 04cfa9e..153a5fc 100644 --- a/lib/features/accounts/screens/account_statement_screen.dart +++ b/lib/features/accounts/screens/account_statement_screen.dart @@ -8,46 +8,96 @@ class AccountStatementScreen extends StatefulWidget { State createState() => _AccountStatementScreen(); } -class _AccountStatementScreen extends State{ +class _AccountStatementScreen extends State { DateTime? fromDate; DateTime? toDate; final _amountRangeController = TextEditingController(text: ""); final transactions = [ - {"desc": "Transfer From ICICI Bank subsidy", "amount": "+₹133.98", "type": "Cr", "time": "21-02-2024 13:09:30"}, - {"desc": "Mobile recharge", "amount": "-₹299.00", "type": "Dr", "time": "21-02-2024 13:09:30"}, - {"desc": "NEFT received from Jaya Saha", "amount": "+₹987.80", "type": "Cr", "time": "21-02-2024 13:09:30"}, - {"desc": "Transfer From ICICI Bank subsidy", "amount": "+₹100.00", "type": "Cr", "time": "21-02-2024 13:09:30"}, - {"desc": "Transfer From ICICI Bank subsidy", "amount": "-₹100.00", "type": "Dr", "time": "21-02-2024 13:09:30"}, - {"desc": "Transfer From ICICI Bank subsidy", "amount": "+₹100.00", "type": "Cr", "time": "21-02-2024 13:09:30"}, - {"desc": "Transfer From ICICI Bank subsidy", "amount": "+₹100.00", "type": "Cr", "time": "21-02-2024 13:09:30"}, + { + "desc": "Transfer From ICICI Bank subsidy", + "amount": "+₹133.98", + "type": "Cr", + "time": "21-02-2024 13:09:30" + }, + { + "desc": "Mobile recharge", + "amount": "-₹299.00", + "type": "Dr", + "time": "21-02-2024 13:09:30" + }, + { + "desc": "NEFT received from Jaya Saha", + "amount": "+₹987.80", + "type": "Cr", + "time": "21-02-2024 13:09:30" + }, + { + "desc": "Transfer From ICICI Bank subsidy", + "amount": "+₹100.00", + "type": "Cr", + "time": "21-02-2024 13:09:30" + }, + { + "desc": "Transfer From ICICI Bank subsidy", + "amount": "-₹100.00", + "type": "Dr", + "time": "21-02-2024 13:09:30" + }, + { + "desc": "Transfer From ICICI Bank subsidy", + "amount": "+₹100.00", + "type": "Cr", + "time": "21-02-2024 13:09:30" + }, + { + "desc": "Transfer From ICICI Bank subsidy", + "amount": "+₹100.00", + "type": "Cr", + "time": "21-02-2024 13:09:30" + }, ]; - void _selectDate({required bool isFromDate}) async { - final DateTime initial = isFromDate ? fromDate ?? DateTime.now() : toDate ?? fromDate ?? DateTime.now(); + Future _selectFromDate(BuildContext context) async { + final DateTime now = DateTime.now(); final DateTime? picked = await showDatePicker( context: context, - initialDate: initial, - firstDate: DateTime(2023), - lastDate: DateTime(2030), + initialDate: fromDate ?? now, + firstDate: DateTime(2020), // or your app's start limit + lastDate: now, // No future date ); if (picked != null) { setState(() { - if (isFromDate) { - fromDate = picked; - if (toDate != null && toDate!.isBefore(fromDate!)) { - toDate = null; // reset invalid toDate - } - } else { - if (fromDate != null && picked.isBefore(fromDate!)) { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar( - content: Text("To Date cannot be before From Date"), - )); - } else { - toDate = picked; - } - } + fromDate = picked; + toDate = null; // reset toDate when fromDate changes + }); + } + } + + Future _selectToDate(BuildContext context) async { + if (fromDate == null) { + ScaffoldMessenger.of(context).showSnackBar(const SnackBar( + content: Text('Please select From Date first'), + )); + return; + } + + final DateTime now = DateTime.now(); + + final DateTime lastAllowedDate = fromDate!.add(const Duration(days: 31)); + final DateTime maxToDate = lastAllowedDate.isBefore(now) ? lastAllowedDate : now; + + final DateTime? picked = await showDatePicker( + context: context, + initialDate: toDate ?? fromDate!, + firstDate: fromDate!, // 🔒 can't be before fromDate + lastDate: maxToDate, // 🔒 not more than 1 month or future + ); + + if (picked != null) { + setState(() { + toDate = picked; }); } } @@ -68,40 +118,76 @@ class _AccountStatementScreen extends State{ Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - leading: IconButton(icon: const Icon(Symbols.arrow_back_ios_new), + leading: IconButton( + icon: const Icon(Symbols.arrow_back_ios_new), onPressed: () { Navigator.pop(context); - },), - title: const Text('Account Statement', style: TextStyle(color: Colors.black, - fontWeight: FontWeight.w500),), + }, + ), + title: const Text( + 'Account Statement', + style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500), + ), centerTitle: false, actions: const [ Padding( padding: EdgeInsets.only(right: 10.0), child: CircleAvatar( - backgroundImage: AssetImage('assets/images/avatar.jpg'), // Replace with your image + backgroundImage: AssetImage('assets/images/avatar.jpg'), + // Replace with your image radius: 20, ), ), ], ), - body: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Text('Filters', style: TextStyle(fontSize: 17),), - const SizedBox(height: 15,), + const Text( + 'Filters', + style: TextStyle(fontSize: 17), + ), + const SizedBox( + height: 15, + ), Row( children: [ - Expanded(child: _buildFromDateSelector()), + Expanded(child: GestureDetector( + onTap: () => _selectFromDate(context), + child: buildDateBox("From Date", fromDate), + ),), const SizedBox(width: 10), - Expanded(child: _buildToDateSelector()), + Expanded(child: GestureDetector( + onTap: () => _selectToDate(context), + child: buildDateBox("To Date", toDate), + ),), ], ), const SizedBox(height: 20), - _buildFilterBox(""), + Row( + children: [ + Expanded( + child: _buildFilterBox(""), + ), + const SizedBox( + width: 8, + ), + SizedBox( + width: 75, + child: ElevatedButton( + onPressed: () {}, + style: ElevatedButton.styleFrom( + backgroundColor: Theme.of(context).primaryColor, + ), + child: const Text( + 'Go', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), + )), + ) + ], + ), const SizedBox(height: 35), Expanded( child: ListView.builder( @@ -115,54 +201,26 @@ class _AccountStatementScreen extends State{ ], ), ), - ); } - Widget _buildFromDateSelector() { - return GestureDetector( - onTap: () => _selectDate(isFromDate: true), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - Expanded( - child: Text( - fromDate != null ? _formatDate(fromDate!) : "From Date", - style: const TextStyle(fontSize: 16), - ), - ), - const Icon(Icons.arrow_drop_down), - ], - ), + Widget buildDateBox(String label, DateTime? date) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16), + decoration: BoxDecoration( + border: Border.all(color: Colors.grey), + borderRadius: BorderRadius.circular(6), ), - ); - } - - Widget _buildToDateSelector() { - return GestureDetector( - onTap: () => _selectDate(isFromDate: false), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), - decoration: BoxDecoration( - border: Border.all(color: Colors.grey), - borderRadius: BorderRadius.circular(8), - ), - child: Row( - children: [ - Expanded( - child: Text( - toDate != null ? _formatDate(toDate!) : "To Date", - style: const TextStyle(fontSize: 16), - ), - ), - const Icon(Icons.arrow_drop_down), - ], - ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + date != null ? _formatDate(date) : label, + style: TextStyle(fontSize: 16, + color: date != null ? Colors.black: Colors.grey), + ), + const Icon(Icons.arrow_drop_down), + ], ), ); } @@ -206,7 +264,9 @@ class _AccountStatementScreen extends State{ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded(child: Text(txn['desc']!, style: const TextStyle(fontSize: 16))), + Expanded( + child: + Text(txn['desc']!, style: const TextStyle(fontSize: 16))), Text( "${txn['amount']} ${txn['type']}", style: TextStyle(color: amountColor, fontWeight: FontWeight.bold), @@ -217,4 +277,4 @@ class _AccountStatementScreen extends State{ ], ); } -} \ No newline at end of file +} diff --git a/lib/features/auth/screens/mpin_screen.dart b/lib/features/auth/screens/mpin_screen.dart index 5c79487..5683286 100644 --- a/lib/features/auth/screens/mpin_screen.dart +++ b/lib/features/auth/screens/mpin_screen.dart @@ -69,15 +69,15 @@ class MPinScreenState extends State { deleteDigit(); } else if (key == 'Enter') { if (mPin.length == 4) { - String storedMpin = await SecureStorage().read("mpin"); - if(!mounted) return; - if(storedMpin == mPin.join()) { + // String storedMpin = await SecureStorage().read("mpin"); + // if(!mounted) return; + // if(storedMpin == mPin.join()) { Navigator.push( context, MaterialPageRoute( builder: (context) => const NavigationScaffold()), ); - } + // } } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("Please enter 4 digits")), diff --git a/lib/features/beneficiaries/screens/add_beneficiary_screen.dart b/lib/features/beneficiaries/screens/add_beneficiary_screen.dart index e97c22e..b79127a 100644 --- a/lib/features/beneficiaries/screens/add_beneficiary_screen.dart +++ b/lib/features/beneficiaries/screens/add_beneficiary_screen.dart @@ -12,6 +12,7 @@ class _AddBeneficiaryScreen extends State{ final _formKey = GlobalKey(); final TextEditingController accountNumberController = TextEditingController(); + final TextEditingController confirmAccountNumberController = TextEditingController(); final TextEditingController nameController = TextEditingController(); final TextEditingController bankNameController = TextEditingController(); final TextEditingController branchNameController = TextEditingController(); @@ -109,6 +110,7 @@ class _AddBeneficiaryScreen extends State{ borderSide: BorderSide(color: Colors.black, width: 2), ), ), + obscureText: true, keyboardType: TextInputType.number, textInputAction: TextInputAction.next, validator: (value) { @@ -119,6 +121,36 @@ class _AddBeneficiaryScreen extends State{ }, ), const SizedBox(height: 24), + // Confirm Account Number + TextFormField( + controller: confirmAccountNumberController, + decoration: const InputDecoration( + labelText: 'Confirm Account Number', + // prefixIcon: Icon(Icons.person), + border: OutlineInputBorder(), + isDense: true, + filled: true, + fillColor: Colors.white, + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.black), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.black, width: 2), + ), + ), + keyboardType: TextInputType.number, + textInputAction: TextInputAction.next, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Re-enter account number'; + } + if (value != accountNumberController.text) { + return 'Account numbers do not match'; + } + return null; + }, + ), + const SizedBox(height: 24), TextFormField( controller: nameController, decoration: const InputDecoration( diff --git a/lib/features/dashboard/screens/dashboard_screen.dart b/lib/features/dashboard/screens/dashboard_screen.dart index 9a33be9..82e2f91 100644 --- a/lib/features/dashboard/screens/dashboard_screen.dart +++ b/lib/features/dashboard/screens/dashboard_screen.dart @@ -221,7 +221,7 @@ class _DashboardScreenState extends State { MaterialPageRoute( builder: (context) => const AccountInfoScreen())); }), - _buildQuickLink(Symbols.receipt_long, "Account \n History", + _buildQuickLink(Symbols.receipt_long, "Account \n Statement", () { Navigator.push( context, @@ -229,13 +229,13 @@ class _DashboardScreenState extends State { builder: (context) => const AccountStatementScreen())); }), - _buildQuickLink(Symbols.checkbook, "Handle \n Cheque", () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - const ChequeManagementScreen())); - }), + // _buildQuickLink(Symbols.checkbook, "Handle \n Cheque", () { + // Navigator.push( + // context, + // MaterialPageRoute( + // builder: (context) => + // const ChequeManagementScreen())); + // }), _buildQuickLink(Icons.group, "Manage \n Beneficiary", () { Navigator.push( context, diff --git a/lib/features/fund_transfer/screens/fund_transfer_screen.dart b/lib/features/fund_transfer/screens/fund_transfer_screen.dart index 441b5de..ffba8a8 100644 --- a/lib/features/fund_transfer/screens/fund_transfer_screen.dart +++ b/lib/features/fund_transfer/screens/fund_transfer_screen.dart @@ -98,6 +98,17 @@ class _FundTransferScreen extends State { body: Column( children: [ const Spacer(), + const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('Debit from:'), + Text( + '0300015678903456', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500), + ) + ], + ), + const SizedBox(height: 20), const Text('Enter Amount', style: TextStyle(fontSize: 20)), const SizedBox(height: 20), Container( 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 f129c8a..af3bce5 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 @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_swipe_button/flutter_swipe_button.dart'; import 'package:material_symbols_icons/material_symbols_icons.dart'; +import '../../fund_transfer/screens/transaction_pin_screen.dart'; + class QuickPayOutsideBankScreen extends StatefulWidget { const QuickPayOutsideBankScreen({super.key}); @@ -15,6 +17,7 @@ class _QuickPayOutsideBankScreen extends State { // Controllers final accountNumberController = TextEditingController(); + final confirmAccountNumberController = TextEditingController(); final nameController = TextEditingController(); final bankNameController = TextEditingController(); final branchNameController = TextEditingController(); @@ -30,6 +33,7 @@ class _QuickPayOutsideBankScreen extends State { void dispose() { // Dispose controllers accountNumberController.dispose(); + confirmAccountNumberController.dispose(); nameController.dispose(); bankNameController.dispose(); branchNameController.dispose(); @@ -50,7 +54,7 @@ class _QuickPayOutsideBankScreen extends State { }, ), title: const Text( - 'Quick Pay - Other Bank', + 'Quick Pay - Outside Bank', style: TextStyle(color: Colors.black, fontWeight: FontWeight.w500), ), centerTitle: false, @@ -71,7 +75,17 @@ class _QuickPayOutsideBankScreen extends State { key: _formKey, child: ListView( children: [ - const SizedBox(height: 25), + const SizedBox(height: 10), + const Row( + children: [ + Text('Debit from:'), + Text( + '0300015678903456', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500), + ) + ], + ), + const SizedBox(height: 20), TextFormField( decoration: const InputDecoration( labelText: 'Account Number', @@ -88,6 +102,7 @@ class _QuickPayOutsideBankScreen extends State { ), controller: accountNumberController, keyboardType: TextInputType.number, + obscureText: true, textInputAction: TextInputAction.next, validator: (value) { if (value == null || value.isEmpty) { @@ -98,6 +113,35 @@ class _QuickPayOutsideBankScreen extends State { return null; }, ), + const SizedBox(height: 24), + TextFormField( + controller: confirmAccountNumberController, + decoration: const InputDecoration( + labelText: 'Confirm Account Number', + // prefixIcon: Icon(Icons.person), + border: OutlineInputBorder(), + isDense: true, + filled: true, + fillColor: Colors.white, + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.black), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.black, width: 2), + ), + ), + keyboardType: TextInputType.number, + textInputAction: TextInputAction.next, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Re-enter account number'; + } + if (value != accountNumberController.text) { + return 'Account numbers do not match'; + } + return null; + }, + ), const SizedBox(height: 25), TextFormField( decoration: const InputDecoration( @@ -297,11 +341,10 @@ class _QuickPayOutsideBankScreen extends State { Expanded(child: buildTransactionModeSelector()), ], ), - const SizedBox(height: 45), Align( - alignment: Alignment.center, - child: SwipeButton.expand( + alignment: Alignment.center, + child: SwipeButton.expand( thumb: const Icon( Icons.arrow_forward, color: Colors.white, @@ -312,20 +355,26 @@ class _QuickPayOutsideBankScreen extends State { height: 56, child: const Text( "Swipe to Pay", - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + style: + TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), onSwipe: () { if (_formKey.currentState!.validate()) { // Perform payment logic - final selectedMode = transactionModes[selectedTransactionIndex]; + final selectedMode = + transactionModes[selectedTransactionIndex]; ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Paying via $selectedMode...')), + SnackBar( + content: Text('Paying via $selectedMode...')), ); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + const TransactionPinScreen())); } }, - ) - - ), + )), ], ), ), @@ -351,7 +400,7 @@ class _QuickPayOutsideBankScreen extends State { color: isSelected ? Colors.blue[200] : Colors.white, borderRadius: BorderRadius.circular(5), border: Border.all( - color: isSelected? Colors.blue : Colors.grey, + color: isSelected ? Colors.blue : Colors.grey, width: isSelected ? 0 : 1.2, ), ), 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 44ea63c..e273746 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 @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_swipe_button/flutter_swipe_button.dart'; import 'package:material_symbols_icons/material_symbols_icons.dart'; +import '../../fund_transfer/screens/transaction_pin_screen.dart'; + class QuickPayWithinBankScreen extends StatefulWidget { const QuickPayWithinBankScreen({super.key}); @@ -13,6 +15,7 @@ class _QuickPayWithinBankScreen extends State { final _formKey = GlobalKey(); final TextEditingController accountNumberController = TextEditingController(); + final TextEditingController confirmAccountNumberController = TextEditingController(); final TextEditingController nameController = TextEditingController(); final TextEditingController amountController = TextEditingController(); @@ -48,7 +51,17 @@ class _QuickPayWithinBankScreen extends State { key: _formKey, child: Column( children: [ - const SizedBox(height: 25), + const SizedBox(height: 10), + const Row( + children: [ + Text('Debit from:'), + Text( + '0300015678903456', + style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500), + ) + ], + ), + const SizedBox(height: 20), TextFormField( decoration: const InputDecoration( labelText: 'Account Number', @@ -65,6 +78,7 @@ class _QuickPayWithinBankScreen extends State { ), controller: accountNumberController, keyboardType: TextInputType.number, + obscureText: true, textInputAction: TextInputAction.next, validator: (value) { if (value == null || value.isEmpty) { @@ -85,6 +99,35 @@ class _QuickPayWithinBankScreen extends State { ), )), const SizedBox(height: 25), + TextFormField( + controller: confirmAccountNumberController, + decoration: const InputDecoration( + labelText: 'Confirm Account Number', + // prefixIcon: Icon(Icons.person), + border: OutlineInputBorder(), + isDense: true, + filled: true, + fillColor: Colors.white, + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.black), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.black, width: 2), + ), + ), + keyboardType: TextInputType.number, + textInputAction: TextInputAction.next, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Re-enter account number'; + } + if (value != accountNumberController.text) { + return 'Account numbers do not match'; + } + return null; + }, + ), + const SizedBox(height: 24), TextFormField( decoration: const InputDecoration( labelText: 'Name', @@ -170,6 +213,10 @@ class _QuickPayWithinBankScreen extends State { const SnackBar( content: Text('Processing Payment...')), ); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const TransactionPinScreen())); } }, ),