This commit is contained in:
2025-08-25 17:48:40 +05:30
17 changed files with 207 additions and 3295 deletions

View File

@@ -11,33 +11,6 @@ class TransactionDetailsScreen extends StatelessWidget {
Widget build(BuildContext context) {
final bool isCredit = transaction.type?.toUpperCase() == 'CR';
// Future<void> _shareScreenshot() async {
// try {
// RenderRepaintBoundary boundary =
// _shareKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
// ui.Image image = await boundary.toImage(pixelRatio: 3.0);
// ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
// Uint8List pngBytes = byteData!.buffer.asUint8List();
// final tempDir = await getTemporaryDirectory();
// final file = await File('${tempDir.path}/payment_result.png').create();
// await file.writeAsBytes(pngBytes);
// await Share.shareXFiles(
// [XFile(file.path)],
// text: AppLocalizations.of(context).paymentResult,
// );
// } catch (e) {
// if (!mounted) return;
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(
// content: Text(
// '${AppLocalizations.of(context).failedToShareScreenshot}: $e',
// ),
// ),
// );
// }
// }
return Scaffold(
appBar:
AppBar(title: Text(AppLocalizations.of(context).transactionDetails)),
@@ -45,7 +18,6 @@ class TransactionDetailsScreen extends StatelessWidget {
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
// Absolute center for amount + icon + date + details
Expanded(
flex: 3,
child: Center(
@@ -85,17 +57,12 @@ class TransactionDetailsScreen extends StatelessWidget {
),
),
),
const Divider(),
// All details
Expanded(
flex: 5,
child: ListView(
children: [
// ignore: unnecessary_cast
_buildDetailRow(
AppLocalizations.of(context).transactionType as String,
_buildDetailRow(AppLocalizations.of(context).transactionType,
transaction.type ?? ""),
_buildDetailRow(AppLocalizations.of(context).transferType,
transaction.name.split("/").first ?? ""),
@@ -109,30 +76,6 @@ class TransactionDetailsScreen extends StatelessWidget {
],
),
),
// ElevatedButton.icon(
// onPressed: _shareScreenshot,
// icon: Icon(
// Icons.share_rounded,
// color: Theme.of(context).primaryColor,
// ),
// label: Text(
// AppLocalizations.of(context).share,
// style: TextStyle(color: Theme.of(context).primaryColor),
// ),
// style: ElevatedButton.styleFrom(
// backgroundColor: Theme.of(context).scaffoldBackgroundColor,
// padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 12),
// shape: RoundedRectangleBorder(
// side: BorderSide(color: Theme.of(context).primaryColor, width: 1),
// borderRadius: BorderRadius.circular(30),
// ),
// textStyle: const TextStyle(
// fontSize: 18,
// fontWeight: FontWeight.w600,
// color: Colors.black,
// ),
// ),
// ),
],
),
),

View File

@@ -23,23 +23,9 @@ class LoginScreenState extends State<LoginScreen>
final _passwordController = TextEditingController();
bool _obscurePassword = true;
//bool _showWelcome = true;
late AnimationController _logoController;
late Animation<double> _logoAnimation;
@override
void initState() {
super.initState();
_logoController = AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
)..repeat(reverse: true);
_logoAnimation = Tween<double>(begin: 0.2, end: 1).animate(_logoController);
}
@override
void dispose() {
_logoController.dispose();
_customerNumberController.dispose();
_passwordController.dispose();
super.dispose();
@@ -63,8 +49,8 @@ class LoginScreenState extends State<LoginScreen>
if (state is Authenticated) {
final storage = getIt<SecureStorage>();
final mpin = await storage.read('mpin');
if (!context.mounted) return;
if (mpin == null) {
// ignore: use_build_context_synchronously
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (_) => MPinScreen(
@@ -83,7 +69,6 @@ class LoginScreenState extends State<LoginScreen>
),
);
} else {
// ignore: use_build_context_synchronously
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (_) => const NavigationScaffold()),
);
@@ -102,21 +87,17 @@ class LoginScreenState extends State<LoginScreen>
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 🔁 Animated Blinking Logo
FadeTransition(
opacity: _logoAnimation,
child: Image.asset(
'assets/images/logo.png',
width: 150,
height: 150,
errorBuilder: (context, error, stackTrace) {
return Icon(
Icons.account_balance,
size: 100,
color: Theme.of(context).primaryColor,
);
},
),
Image.asset(
'assets/images/logo.png',
width: 150,
height: 150,
errorBuilder: (context, error, stackTrace) {
return Icon(
Icons.account_balance,
size: 100,
color: Theme.of(context).primaryColor,
);
},
),
const SizedBox(height: 16),
// Title
@@ -161,8 +142,7 @@ class LoginScreenState extends State<LoginScreen>
controller: _passwordController,
obscureText: _obscurePassword,
textInputAction: TextInputAction.done,
onFieldSubmitted: (_) =>
_submitForm(), // ⌨️ Enter key submits
onFieldSubmitted: (_) => _submitForm(),
decoration: InputDecoration(
labelText: AppLocalizations.of(context).password,
border: const OutlineInputBorder(),

View File

@@ -13,14 +13,6 @@ class AccountCard extends StatelessWidget {
width: 300,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
// gradient: LinearGradient(
// begin: Alignment.topLeft,
// end: Alignment.bottomRight,
// colors: [
// Theme.of(context).primaryColor,
// Theme.of(context).primaryColor.withBlue(200),
// ],
// ),
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.circular(12),
boxShadow: [
@@ -58,7 +50,7 @@ class AccountCard extends StatelessWidget {
Text(
account.accountNumber,
style: TextStyle(
color: Theme.of(context).dialogBackgroundColor, fontSize: 16),
color: const DialogThemeData().backgroundColor, fontSize: 16),
),
const SizedBox(height: 30),
Text(
@@ -73,7 +65,7 @@ class AccountCard extends StatelessWidget {
Text(
AppLocalizations.of(context).availableBalance,
style: TextStyle(
color: Theme.of(context).dialogBackgroundColor, fontSize: 12),
color: const DialogThemeData().backgroundColor, fontSize: 16),
),
],
),

View File

@@ -135,9 +135,9 @@ class _FundTransferAmountScreenState extends State<FundTransferAmountScreen> {
completer.complete(paymentResponse);
}
}
//IMPS transaction
else if (_selectedMode == TransactionMode.imps){
//IMPS transaction
else if (_selectedMode == TransactionMode.imps) {
final impsTx = ImpsTransaction(
fromAccount: widget.debitAccountNo,
toAccount: widget.creditBeneficiary.accountNo,
@@ -169,18 +169,19 @@ class _FundTransferAmountScreenState extends State<FundTransferAmountScreen> {
utr: impsResponse.utr,
);
completer.complete(paymentResponse);
} on DioException catch(e) {
} on DioException catch (e) {
print('dio exception');
print(e.toString());
final error = jsonDecode(e.response.toString())['error'];
var errorMessage =
{
"INCORRECT_TPIN" : "Please Enter the correct TPIN",
"INSUFFICIENT_FUNDS": "Your account does not have sufficient balance"
}[error] ?? "Something Went Wrong";
var errorMessage = {
"INCORRECT_TPIN": "Please Enter the correct TPIN",
"INSUFFICIENT_FUNDS":
"Your account does not have sufficient balance"
}[error] ??
"Something Went Wrong";
final paymentResponse = PaymentResponse(
final paymentResponse = PaymentResponse(
isSuccess: false,
errorMessage: errorMessage,
);
@@ -194,8 +195,7 @@ class _FundTransferAmountScreenState extends State<FundTransferAmountScreen> {
);
completer.complete(paymentResponse);
}
}
else {
} else {
final rtgsTx = RtgsTransaction(
fromAccount: widget.debitAccountNo,
toAccount: widget.creditBeneficiary.accountNo,
@@ -329,9 +329,8 @@ class _FundTransferAmountScreenState extends State<FundTransferAmountScreen> {
child: ToggleButtons(
isSelected: [
_selectedMode == TransactionMode.neft,
_selectedMode == TransactionMode.rtgs,
_selectedMode == TransactionMode.rtgs,
_selectedMode == TransactionMode.imps,
],
onPressed: (index) {
setState(() {
@@ -358,8 +357,9 @@ class _FundTransferAmountScreenState extends State<FundTransferAmountScreen> {
horizontal: 24.0, vertical: 12.0),
child: Text(AppLocalizations.of(context).rtgs),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 12.0),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 24.0, vertical: 12.0),
child: Text(AppLocalizations.of(context).imps),
),
],

View File

@@ -188,7 +188,7 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
toAccount: accountNumberController.text,
amount: amountController.text,
ifscCode: ifscController.text,
remitterName: "Unknown",
remitterName: "Unknown",
beneficiaryName: nameController.text,
tpin: tpin,
);
@@ -221,7 +221,7 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
);
completer.complete(paymentResponse);
}
}
}
if (isImps) {
// IMPS
@@ -230,7 +230,7 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
toAccount: accountNumberController.text,
amount: amountController.text,
ifscCode: ifscController.text,
remitterName: "Unknown",
remitterName: "Unknown",
beneficiaryName: nameController.text,
tpin: tpin,
);
@@ -263,16 +263,16 @@ class _QuickPayOutsideBankScreen extends State<QuickPayOutsideBankScreen> {
);
completer.complete(paymentResponse);
}
}
}
if(isRtgs) {
if (isRtgs) {
// RTGS
final rtgsTx = RtgsTransaction(
fromAccount: widget.debitAccount,
toAccount: accountNumberController.text,
amount: amountController.text,
ifscCode: ifscController.text,
remitterName: "Unknown",
remitterName: "Unknown",
beneficiaryName: nameController.text,
tpin: tpin,
);

View File

@@ -7,50 +7,61 @@ class Branch {
final String ifsc;
final String address;
Branch({required this.name, required this.code, required this.ifsc, required this.address,});
Branch({
required this.name,
required this.code,
required this.ifsc,
required this.address,
});
}
class BranchLocatorScreen extends StatefulWidget {
const BranchLocatorScreen({super.key});
@override
State<BranchLocatorScreen> createState() => _BranchLocatorScreenState();
@override
State<BranchLocatorScreen> createState() => _BranchLocatorScreenState();
}
class _BranchLocatorScreenState extends State<BranchLocatorScreen> {
final TextEditingController _searchController = TextEditingController();
final TextEditingController _searchController = TextEditingController();
// Static list of 5 branches
final List<Branch> _branches = [
Branch(name: "Dharamsala - Head Office", code: "002", ifsc: "KACE0000002", address: "Civil Lines Dharmashala, Kangra, HP - 176215"),
Branch(name: "Kangra", code: "033", ifsc: "KACE0000033", address: "Rajput Bhawankangrapo Kangra, Kangra, HP "),
];
final List<Branch> _branches = [
Branch(
name: "Dharamsala - Head Office",
code: "002",
ifsc: "KACE0000002",
address: "Civil Lines Dharmashala, Kangra, HP - 176215"),
Branch(
name: "Kangra",
code: "033",
ifsc: "KACE0000033",
address: "Rajput Bhawankangrapo Kangra, Kangra, HP "),
];
List<Branch> _filteredBranches = [];
@override
void initState() {
super.initState();
_filteredBranches = _branches; // Initially show all branches
}
void _filterBranches(String query) {
setState(() {
if (query.isEmpty) {
_filteredBranches = _branches;
} else {
_filteredBranches = _branches.where((branch) {
final lowerQuery = query.toLowerCase();
return branch.name.toLowerCase().contains(lowerQuery) ||
branch.code.toLowerCase().contains(lowerQuery) ||
branch.ifsc.toLowerCase().contains(lowerQuery) ||
branch.address.toLowerCase().contains(lowerQuery);
}).toList();
}
});
}
List<Branch> _filteredBranches = [];
@override
void initState() {
super.initState();
_filteredBranches = _branches; // Initially show all branches
}
void _filterBranches(String query) {
setState(() {
if (query.isEmpty) {
_filteredBranches = _branches;
} else {
_filteredBranches = _branches.where((branch) {
final lowerQuery = query.toLowerCase();
return branch.name.toLowerCase().contains(lowerQuery) ||
branch.code.toLowerCase().contains(lowerQuery) ||
branch.ifsc.toLowerCase().contains(lowerQuery) ||
branch.address.toLowerCase().contains(lowerQuery);
}).toList();
}
});
}
// @override
// Widget build(BuildContext context) {
@@ -78,7 +89,7 @@ branch.address.toLowerCase().contains(lowerQuery);
// label: Text( AppLocalizations.of(context).searchbranch),
// onPressed: () {
// // Place API here
// // ScaffoldMessenger.of(context).showSnackBar(
// // SnackBar(content: Text( AppLocalizations.of(context).branchsearchsoon)),
// // );
@@ -91,58 +102,62 @@ branch.address.toLowerCase().contains(lowerQuery);
// }
// }
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context).branchLocator),
),
body: Column(
children: [
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context).branchLocator),
),
body: Column(
children: [
// Search bar
Padding(
padding: const EdgeInsets.all(12.0),
child: TextField(
controller: _searchController,
onChanged: _filterBranches,
decoration: InputDecoration(
hintText: AppLocalizations.of(context).searchbranchby,
prefixIcon: const Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
),
),
),
Padding(
padding: const EdgeInsets.all(12.0),
child: TextField(
controller: _searchController,
onChanged: _filterBranches,
decoration: InputDecoration(
hintText: AppLocalizations.of(context).searchbranchby,
prefixIcon: const Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
),
),
),
// List of branches
Expanded(
child: _filteredBranches.isEmpty
? const Center(child: Text("No matching branches found"))
: ListView.builder(
itemCount: _filteredBranches.length,
itemBuilder: (context, index) {
final branch = _filteredBranches[index];
return Card(
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
child: ListTile(
leading: Icon(Icons.location_city, color: Theme.of(context).primaryColor),
title: Text(branch.name, style: const TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text("Code: ${branch.code} | IFSC: ${branch.ifsc} \nBranch Address: ${branch.address}"),
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Selected ${branch.name}")),
);
},
),
);
},
),
),
],
),
);
Expanded(
child: _filteredBranches.isEmpty
? const Center(child: Text("No matching branches found"))
: ListView.builder(
itemCount: _filteredBranches.length,
itemBuilder: (context, index) {
final branch = _filteredBranches[index];
return Card(
margin: const EdgeInsets.symmetric(
horizontal: 12, vertical: 6),
child: ListTile(
leading: Icon(Icons.location_city,
color: Theme.of(context).primaryColor),
title: Text(branch.name,
style:
const TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text(
"Code: ${branch.code} | IFSC: ${branch.ifsc} \nBranch Address: ${branch.address}"),
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Selected ${branch.name}")),
);
},
),
);
},
),
),
],
),
);
}
}
}

View File

@@ -74,10 +74,9 @@ class _ServiceScreen extends State<ServiceScreen> {
label: AppLocalizations.of(context).branchLocator,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const BranchLocatorScreen())
);
context,
MaterialPageRoute(
builder: (context) => const BranchLocatorScreen()));
},
),
const Divider(height: 1),