Code Formatted

This commit is contained in:
2025-11-24 18:18:36 +05:30
parent b7fe6a9d18
commit 18db360a45
19 changed files with 805 additions and 754 deletions

View File

@@ -1,47 +1,47 @@
import 'package:dio/dio.dart';
class Branch{
final String branch_code;
final String branch_name;
final String zone;
final String tehsil;
final String block;
final String block_code;
final String distt_name;
final String distt_code_slbc;
final String date_of_opening;
final String rbi_code_1;
final String rbi_code_2;
final String telephone_no;
final String type_of_branch;
final String rtgs_acct_no;
final String br_lattitude;
final String br_longitude;
final String pincode;
final String post_office;
class Branch {
final String branch_code;
final String branch_name;
final String zone;
final String tehsil;
final String block;
final String block_code;
final String distt_name;
final String distt_code_slbc;
final String date_of_opening;
final String rbi_code_1;
final String rbi_code_2;
final String telephone_no;
final String type_of_branch;
final String rtgs_acct_no;
final String br_lattitude;
final String br_longitude;
final String pincode;
final String post_office;
Branch({
required this.branch_code,
required this.branch_name,
required this.zone,
required this.tehsil,
required this.block,
required this.block_code,
required this.distt_name,
required this.distt_code_slbc,
required this.date_of_opening,
required this.rbi_code_1,
required this.rbi_code_2,
required this.telephone_no,
required this.type_of_branch,
required this.rtgs_acct_no,
required this.br_lattitude,
required this.br_longitude,
required this.pincode,
required this.post_office,
});
Branch({
required this.branch_code,
required this.branch_name,
required this.zone,
required this.tehsil,
required this.block,
required this.block_code,
required this.distt_name,
required this.distt_code_slbc,
required this.date_of_opening,
required this.rbi_code_1,
required this.rbi_code_2,
required this.telephone_no,
required this.type_of_branch,
required this.rtgs_acct_no,
required this.br_lattitude,
required this.br_longitude,
required this.pincode,
required this.post_office,
});
factory Branch.fromJson(Map<String, dynamic> json) {
factory Branch.fromJson(Map<String, dynamic> json) {
return Branch(
branch_code: json['branch_code'] ?? json['branch_code'] ?? '',
branch_name: json['branch_name'] ?? json['branch_name'] ?? '',
@@ -60,33 +60,32 @@ factory Branch.fromJson(Map<String, dynamic> json) {
br_lattitude: json['br_lattitude'] ?? json['br_lattitude'] ?? '',
br_longitude: json['br_longitude'] ?? json['br_longitude'] ?? '',
pincode: json['pincode'] ?? json['pincode'] ?? '',
post_office: json['post_office'] ?? json['post_office'] ?? '',
post_office: json['post_office'] ?? json['post_office'] ?? '',
);
}
static List<Branch> listFromJson(List<dynamic> jsonList) {
final beneficiaryList = jsonList
.map((beneficiary) => Branch.fromJson(beneficiary))
.toList();
static List<Branch> listFromJson(List<dynamic> jsonList) {
final beneficiaryList =
jsonList.map((beneficiary) => Branch.fromJson(beneficiary)).toList();
return beneficiaryList;
}
}
class Atm {
final String name;
class Atm {
final String name;
Atm({required this.name});
Atm({required this.name});
factory Atm.fromJson(Map<String, dynamic> json) {
return Atm(
name: json['name'] ?? '', // Assuming the API returns a 'name' field
);
}
factory Atm.fromJson(Map<String, dynamic> json) {
return Atm(
name: json['name'] ?? '', // Assuming the API returns a 'name' field
);
}
static List<Atm> listFromJson(List<dynamic> jsonList) {
return jsonList.map((atm) => Atm.fromJson(atm)).toList();
}
}
static List<Atm> listFromJson(List<dynamic> jsonList) {
return jsonList.map((atm) => Atm.fromJson(atm)).toList();
}
}
class BranchService {
final Dio _dio;
@@ -113,7 +112,7 @@ class BranchService {
}
}
Future<List<Atm>> fetchAtmList() async {
Future<List<Atm>> fetchAtmList() async {
try {
final response = await _dio.get(
"/api/atm",
@@ -134,4 +133,4 @@ class BranchService {
return [];
}
}
}
}

View File

@@ -74,7 +74,7 @@ Dio _createDioClient() {
final dio = Dio(
BaseOptions(
baseUrl:
'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com:8080', //test
'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com:8080', //test
//'http://lb-kccb-mobile-banking-app-848675342.ap-south-1.elb.amazonaws.com', //prod
//'https://kccbmbnk.net', //prod small
connectTimeout: const Duration(seconds: 60),

View File

@@ -101,7 +101,8 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
? fromDate!.add(const Duration(days: 183))
: now;
final initialToDate = toDate ?? now;
final clampedInitialToDate = initialToDate.isBefore(fromDate!) ? fromDate! : initialToDate;
final clampedInitialToDate =
initialToDate.isBefore(fromDate!) ? fromDate! : initialToDate;
final picked = await showDatePicker(
context: context,
initialDate: clampedInitialToDate,
@@ -238,8 +239,11 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
itemCount: 3,
itemBuilder: (_, __) => ListTile(
leading: Shimmer.fromColors(
baseColor: Theme.of(context).colorScheme.surfaceVariant,
highlightColor: Theme.of(context).colorScheme.onSurfaceVariant,
baseColor:
Theme.of(context).colorScheme.surfaceVariant,
highlightColor: Theme.of(context)
.colorScheme
.onSurfaceVariant,
child: CircleAvatar(
radius: 12,
backgroundColor:
@@ -247,8 +251,11 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
),
),
title: Shimmer.fromColors(
baseColor: Theme.of(context).colorScheme.surfaceVariant,
highlightColor: Theme.of(context).colorScheme.onSurfaceVariant,
baseColor:
Theme.of(context).colorScheme.surfaceVariant,
highlightColor: Theme.of(context)
.colorScheme
.onSurfaceVariant,
child: Container(
height: 10,
width: 100,
@@ -257,8 +264,11 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
),
),
subtitle: Shimmer.fromColors(
baseColor: Theme.of(context).colorScheme.surfaceVariant,
highlightColor: Theme.of(context).colorScheme.onSurfaceVariant,
baseColor:
Theme.of(context).colorScheme.surfaceVariant,
highlightColor: Theme.of(context)
.colorScheme
.onSurfaceVariant,
child: Container(
height: 8,
width: 60,
@@ -288,7 +298,9 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
? Symbols.call_received
: Symbols.call_made,
color: tx.type == 'CR'
? Theme.of(context).colorScheme.secondary
? Theme.of(context)
.colorScheme
.secondary
: Theme.of(context).colorScheme.error,
),
title: Text(
@@ -332,7 +344,8 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
);
},
separatorBuilder: (context, index) {
return Divider(color: Theme.of(context).dividerColor);
return Divider(
color: Theme.of(context).dividerColor);
},
),
),

View File

@@ -46,7 +46,8 @@ class _AllAccountsScreenState extends State<AllAccountsScreen> {
itemBuilder: (context, index) {
final user = widget.users[index];
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
padding:
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: _buildAccountCard(user),
);
},

View File

@@ -22,7 +22,9 @@ class BeneficiaryDetailsScreen extends StatelessWidget {
_showSuccessDialog(context);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('${AppLocalizations.of(context).failedToDeleteBeneficiary} : $e')),
SnackBar(
content: Text(
'${AppLocalizations.of(context).failedToDeleteBeneficiary} : $e')),
);
}
}
@@ -33,7 +35,8 @@ class BeneficiaryDetailsScreen extends StatelessWidget {
builder: (BuildContext context) {
return AlertDialog(
title: Text(AppLocalizations.of(context).success),
content: Text(AppLocalizations.of(context).beneficiaryDeletedSuccessfully),
content:
Text(AppLocalizations.of(context).beneficiaryDeletedSuccessfully),
actions: <Widget>[
TextButton(
child: Text(AppLocalizations.of(context).ok),
@@ -53,8 +56,8 @@ class BeneficiaryDetailsScreen extends StatelessWidget {
builder: (BuildContext context) {
return AlertDialog(
title: Text(AppLocalizations.of(context).deleteBeneficiary),
content:
Text(AppLocalizations.of(context).areYouSureYouWantToDeleteThisBeneficiary),
content: Text(AppLocalizations.of(context)
.areYouSureYouWantToDeleteThisBeneficiary),
actions: <Widget>[
TextButton(
child: Text(AppLocalizations.of(context).cancel),

View File

@@ -17,8 +17,9 @@ class _ChequeManagementScreen extends State<ChequeManagementScreen> {
appBar: AppBar(
title: Text(
AppLocalizations.of(context).chequeManagement,
style:
TextStyle(color: Theme.of(context).textTheme.titleLarge?.color, fontWeight: FontWeight.w500),
style: TextStyle(
color: Theme.of(context).textTheme.titleLarge?.color,
fontWeight: FontWeight.w500),
),
centerTitle: false,
),

View File

@@ -125,143 +125,144 @@ class _DashboardScreenState extends State<DashboardScreen>
child: Transform.translate(
offset: isSelected ? const Offset(10.0, 0.0) : Offset.zero,
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 2),
padding: const EdgeInsets.symmetric(
horizontal: 18,
vertical: 10,
),
decoration: BoxDecoration(
color: const Color(0xFF01A04C),
borderRadius: BorderRadius.circular(16),
),
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,
),
],
),
),
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
margin: const EdgeInsets.symmetric(horizontal: 2),
padding: const EdgeInsets.symmetric(
horizontal: 18,
vertical: 10,
),
decoration: BoxDecoration(
color: const Color(0xFF01A04C),
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Top section with account type and number (no refresh button here)
Row(
children: [
Expanded(
child: FittedBox(
fit: BoxFit.scaleDown,
alignment: Alignment.centerLeft,
child: Row(
children: [
Text(
"",
style: TextStyle(
color: theme.colorScheme.onPrimary,
fontSize: 40,
fontWeight: FontWeight.w700,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
getFullAccountType(user.accountType),
style: TextStyle(
color: theme.colorScheme.onPrimary,
fontSize: 16,
fontWeight: FontWeight.w700,
),
Text(
isCardVisible
? user.currentBalance ?? '0.00'
: '*****',
style: TextStyle(
color: theme.colorScheme.onPrimary,
fontSize: 40,
fontWeight: FontWeight.w700,
),
),
Text(
user.accountNo ?? 'N/A',
style: TextStyle(
color: theme.colorScheme.onPrimary,
fontSize: 14,
fontWeight: FontWeight.w700,
),
],
),
overflow: TextOverflow.ellipsis,
),
],
),
),
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;
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 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) {
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
setState(() {
_visibilityMap[accountNo] = true;
_visibilityMap[accountNo] = false;
});
}
} 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,
},
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(),
],
),
),
),
),
);
}
@@ -325,8 +326,7 @@ class _DashboardScreenState extends State<DashboardScreen>
return Shimmer.fromColors(
baseColor: theme.colorScheme.primary,
highlightColor: theme.colorScheme.onPrimary,
child: Container(
height: 36, color: theme.scaffoldBackgroundColor),
child: Container(height: 36, color: theme.scaffoldBackgroundColor),
);
}
@@ -445,8 +445,8 @@ class _DashboardScreenState extends State<DashboardScreen>
onTap: () {
final authState = context.read<AuthCubit>().state;
String mobileNumberToPass = '';
String customerNo ='';
String customerName = '';
String customerNo = '';
String customerName = '';
if (authState is Authenticated) {
if (selectedAccountIndex >= 0 &&
selectedAccountIndex < authState.users.length) {
@@ -454,7 +454,7 @@ class _DashboardScreenState extends State<DashboardScreen>
authState.users[selectedAccountIndex].mobileNo ?? '';
customerNo =
authState.users[selectedAccountIndex].cifNumber ?? '';
customerName=
customerName =
authState.users[selectedAccountIndex].name ?? '';
}
}
@@ -462,8 +462,10 @@ class _DashboardScreenState extends State<DashboardScreen>
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ProfileScreen(mobileNumber: mobileNumberToPass, customerNo: customerNo, customerName: customerName),
builder: (context) => ProfileScreen(
mobileNumber: mobileNumberToPass,
customerNo: customerNo,
customerName: customerName),
),
);
},
@@ -535,25 +537,31 @@ class _DashboardScreenState extends State<DashboardScreen>
// Account Info Cards
ClipRect(
child: SizedBox( // This SizedBox defines the height for the Stack
child: SizedBox(
// This SizedBox defines the height for the Stack
height: 160,
child: Stack(
children: [
// PageView part, painted underneath
Padding(
padding: const EdgeInsets.only(left: 48.0), // Space for tab (40) + gap (8)
child: SizedBox( // Keep SizedBox for PageView height
padding: const EdgeInsets.only(
left: 48.0), // Space for tab (40) + gap (8)
child: SizedBox(
// Keep SizedBox for PageView height
height: 160,
child: PageView.builder(
controller: _pageController,
itemCount: users.length,
clipBehavior: Clip.none, // Keep this to show adjacent cards
clipBehavior: Clip
.none, // Keep this to show adjacent cards
padEnds: false,
onPageChanged: (int newIndex) async {
if (newIndex == selectedAccountIndex) return;
if (newIndex == selectedAccountIndex)
return;
// Hide the balance of the old card when scrolling away
final oldAccountNo = users[selectedAccountIndex].accountNo;
final oldAccountNo =
users[selectedAccountIndex].accountNo;
if (oldAccountNo != null) {
_visibilityMap[oldAccountNo] = false;
}
@@ -561,15 +569,17 @@ class _DashboardScreenState extends State<DashboardScreen>
setState(() {
selectedAccountIndex = newIndex;
});
await _loadTransactions(
users[newIndex].accountNo!,
);
},
itemBuilder: (context, index) {
final user = users[index];
final isSelected = index == selectedAccountIndex;
return _buildAccountCard(user, isSelected);
final isSelected =
index == selectedAccountIndex;
return _buildAccountCard(
user, isSelected);
},
),
),
@@ -715,7 +725,6 @@ class _DashboardScreenState extends State<DashboardScreen>
),
],
),
],
),
),
@@ -777,9 +786,7 @@ class _DashboardScreenState extends State<DashboardScreen>
Icon(
icon,
size: 30,
color: disable
? theme.disabledColor
: theme.colorScheme.primary,
color: disable ? theme.disabledColor : theme.colorScheme.primary,
),
const SizedBox(height: 4),
Text(
@@ -788,9 +795,8 @@ class _DashboardScreenState extends State<DashboardScreen>
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
fontSize: 12,
color: disable
? theme.disabledColor
: theme.colorScheme.onSurface,
color:
disable ? theme.disabledColor : theme.colorScheme.onSurface,
),
),
],
@@ -799,4 +805,3 @@ class _DashboardScreenState extends State<DashboardScreen>
);
}
}

View File

@@ -68,8 +68,10 @@ class _EnquiryScreen extends State<EnquiryScreen> {
GestureDetector(
onTap: () => _launchPhoneNumber(phone),
child: Text(phone,
style:
TextStyle(color: Theme.of(context).colorScheme.primary)), // Changed color for visibility
style: TextStyle(
color: Theme.of(context)
.colorScheme
.primary)), // Changed color for visibility
),
],
);
@@ -91,14 +93,16 @@ class _EnquiryScreen extends State<EnquiryScreen> {
children: [
const SizedBox(height: 20),
GestureDetector(
onTap: () => _launchUrl("https://kccbhp.bank.in/complaint-form/"),
onTap: () =>
_launchUrl("https://kccbhp.bank.in/complaint-form/"),
child: Row(mainAxisSize: MainAxisSize.min, children: [
Text(
"Complaint Form",
style: TextStyle(
fontSize: 17,
color: Theme.of(context).colorScheme.primary,
decoration: TextDecoration.underline, // Added underline for link clarity
decoration: TextDecoration
.underline, // Added underline for link clarity
decorationColor:
Theme.of(context).colorScheme.primary,
),
@@ -165,4 +169,4 @@ class _EnquiryScreen extends State<EnquiryScreen> {
),
);
}
}
}

View File

@@ -492,7 +492,8 @@ class _FundTransferAmountScreenState extends State<FundTransferAmountScreen> {
},
),
const SizedBox(height: 8),
if (_isLoadingLimit) Text(AppLocalizations.of(context).fetchingDailyLimit),
if (_isLoadingLimit)
Text(AppLocalizations.of(context).fetchingDailyLimit),
if (!_isLoadingLimit && _limit != null)
Text(
'Remaining Daily Limit: ${_formatCurrency.format(_limit!.dailyLimit - _limit!.usedLimit)}',

View File

@@ -148,7 +148,8 @@ class FundTransferManagementTile extends StatelessWidget {
),
elevation: 4, // Add some elevation for better visual separation
child: InkWell(
onTap: disable ? null : onTap, // Disable InkWell if the tile is disabled
onTap:
disable ? null : onTap, // Disable InkWell if the tile is disabled
borderRadius: BorderRadius.circular(12.0),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 16.0),

View File

@@ -17,7 +17,11 @@ class ProfileScreen extends StatefulWidget {
final String mobileNumber;
final String customerNo;
final String customerName;
const ProfileScreen({super.key, required this.mobileNumber, required this.customerNo, required this.customerName});
const ProfileScreen(
{super.key,
required this.mobileNumber,
required this.customerNo,
required this.customerName});
@override
State<ProfileScreen> createState() => _ProfileScreenState();
@@ -306,283 +310,283 @@ class _ProfileScreenState extends State<ProfileScreen> {
// );
// }
@override
Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
final theme = Theme.of(context);
final isDarkMode = theme.brightness == Brightness.dark;
Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
final theme = Theme.of(context);
final isDarkMode = theme.brightness == Brightness.dark;
return Scaffold(
appBar: AppBar(
title: Text(loc.profile),
elevation: 0,
),
body: Stack(
children: [
ListView(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
children: [
// ===== Profile Header =====
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
// Avatar
Container(
width: 56,
height: 56,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: theme.colorScheme.surface,
image: const DecorationImage(
image: AssetImage('assets/images/logo.png'),
fit: BoxFit.cover,
return Scaffold(
appBar: AppBar(
title: Text(loc.profile),
elevation: 0,
),
body: Stack(
children: [
ListView(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
children: [
// ===== Profile Header =====
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
// Avatar
Container(
width: 56,
height: 56,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: theme.colorScheme.surface,
image: const DecorationImage(
image: AssetImage('assets/images/logo.png'),
fit: BoxFit.cover,
),
),
),
),
const SizedBox(width: 12),
// Name + mobile
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
// If you want to show the user's name instead, replace below.
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),
),
),
),
],
],
),
),
),
// Edit/Profile button (optional)
TextButton.icon(
onPressed: () {
// TODO: Navigate to edit profile if required
},
icon: const Icon(Icons.edit, size: 18),
label: const Text("Edit"),
style: TextButton.styleFrom(
foregroundColor: theme.colorScheme.onSurface,
),
),
],
),
),
),
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) => const DailyLimitScreen(),
),
);
},
),
Card(
child: SwitchListTile(
title: Text(loc.enableFingerprintLogin),
value: _isBiometricEnabled,
onChanged: (bool value) {
_handleBiometricToggle(value);
},
secondary: const Icon(Icons.fingerprint),
contentPadding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
),
),
const SizedBox(height: 16),
const Divider(height: 24),
// ===== Section: Security & App =====
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
loc.appVersion,
style: theme.textTheme.labelLarge?.copyWith(
fontWeight: FontWeight.w600,
letterSpacing: 0.2,
),
),
),
const SizedBox(height: 8),
// Fingerprint toggle inside a styled container
Card(
child: ListTile(
leading: const Icon(Icons.smartphone),
title: Text(loc.appVersion),
trailing: FutureBuilder<String>(
future: _getAppVersion(),
builder:
(BuildContext context, AsyncSnapshot<String> 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<bool>(
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),
// Edit/Profile button (optional)
TextButton.icon(
onPressed: () {
// TODO: Navigate to edit profile if required
},
icon: const Icon(Icons.edit, size: 18),
label: const Text("Edit"),
style: TextButton.styleFrom(
foregroundColor: theme.colorScheme.onSurface,
),
),
],
),
);
),
),
if (shouldExit == true) {
if (Platform.isAndroid) {
SystemNavigator.pop();
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) => const DailyLimitScreen(),
),
);
},
),
Card(
child: SwitchListTile(
title: Text(loc.enableFingerprintLogin),
value: _isBiometricEnabled,
onChanged: (bool value) {
_handleBiometricToggle(value);
},
secondary: const Icon(Icons.fingerprint),
contentPadding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
),
),
const SizedBox(height: 16),
const Divider(height: 24),
// ===== Section: Security & App =====
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
loc.appVersion,
style: theme.textTheme.labelLarge?.copyWith(
fontWeight: FontWeight.w600,
letterSpacing: 0.2,
),
),
),
const SizedBox(height: 8),
// Fingerprint toggle inside a styled container
Card(
child: ListTile(
leading: const Icon(Icons.smartphone),
title: Text(loc.appVersion),
trailing: FutureBuilder<String>(
future: _getAppVersion(),
builder:
(BuildContext context, AsyncSnapshot<String> 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<bool>(
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);
}
exit(0);
}
},
),
_SectionTile(
leadingIcon: Icons.logout,
title: loc.deregister,
trailChevron: false,
onTap: () async {
final shouldLogout = await showDialog<bool>(
context: context,
builder: (_) => const LogoutDialog(),
);
},
),
_SectionTile(
leadingIcon: Icons.logout,
title: loc.deregister,
trailChevron: false,
onTap: () async {
final shouldLogout = await showDialog<bool>(
context: context,
builder: (_) => const LogoutDialog(),
);
if (shouldLogout == true) {
await _handleLogout(context);
}
},
),
if (shouldLogout == true) {
await _handleLogout(context);
}
},
),
const SizedBox(height: 24),
],
),
const SizedBox(height: 24),
],
),
// ===== Watermark (kept subtle, no theme change) =====
IgnorePointer(
child: Positioned.fill(
child: Center(
child: Opacity(
opacity: 0.06,
child: ClipOval(
child: Image.asset(
'assets/images/logo.png',
width: 200,
height: 200,
filterQuality: FilterQuality.medium,
// ===== Watermark (kept subtle, no theme change) =====
IgnorePointer(
child: Positioned.fill(
child: Center(
child: Opacity(
opacity: 0.06,
child: ClipOval(
child: Image.asset(
'assets/images/logo.png',
width: 200,
height: 200,
filterQuality: FilterQuality.medium,
),
),
),
),
),
),
),
],
),
);
}
],
),
);
}
}
class _SectionTile extends StatelessWidget {
@@ -611,8 +615,7 @@ class _SectionTile extends StatelessWidget {
? Icon(Icons.chevron_right, color: theme.colorScheme.onSurface)
: null,
onTap: onTap,
contentPadding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),

View File

@@ -57,7 +57,8 @@ class SecuritySettingsScreen extends StatelessWidget {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(loc.mpinChangedSuccessfully),
backgroundColor: Theme.of(context).colorScheme.secondary,
backgroundColor:
Theme.of(context).colorScheme.secondary,
),
);
}

View File

@@ -108,7 +108,8 @@ class QuickPayManagementTile extends StatelessWidget {
),
elevation: 4, // Add some elevation for better visual separation
child: InkWell(
onTap: disable ? null : onTap, // Disable InkWell if the tile is disabled
onTap:
disable ? null : onTap, // Disable InkWell if the tile is disabled
borderRadius: BorderRadius.circular(12.0),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 36.0, horizontal: 16.0),

View File

@@ -15,10 +15,12 @@ class ATMLocatorScreen extends StatefulWidget {
class _ATMLocatorScreenState extends State<ATMLocatorScreen> {
final TextEditingController _searchController = TextEditingController();
var service = getIt<BranchService>(); // Added: Instance of BranchService for API calls
var service =
getIt<BranchService>(); // Added: Instance of BranchService for API calls
bool _isLoading = true; // State variable to manage loading status
List<Atm> _allAtms = []; // Changed: List to hold all fetched Atm objects
List<Atm> _filteredAtms = []; // Changed: List to hold filtered Atm objects for display
List<Atm> _filteredAtms =
[]; // Changed: List to hold filtered Atm objects for display
@override
void initState() {
@@ -28,7 +30,8 @@ class _ATMLocatorScreenState extends State<ATMLocatorScreen> {
/// Fetches the list of ATMs from the API using BranchService.
Future<void> _loadAtms() async {
final data = await service.fetchAtmList(); // Call the new fetchAtmList method
final data =
await service.fetchAtmList(); // Call the new fetchAtmList method
setState(() {
_allAtms = data; // Update the list of all ATMs
_filteredAtms = data; // Initialize filtered list with all ATMs
@@ -37,14 +40,18 @@ class _ATMLocatorScreenState extends State<ATMLocatorScreen> {
}
/// Filters the list of ATMs based on the search query.
void _filterAtms(String query) { // Changed: Renamed from _filterLocations
void _filterAtms(String query) {
// Changed: Renamed from _filterLocations
setState(() {
if (query.isEmpty) {
_filteredAtms = _allAtms; // If query is empty, show all ATMs
} else {
_filteredAtms = _allAtms.where((atm) { // Changed: Filter based on Atm object
_filteredAtms = _allAtms.where((atm) {
// Changed: Filter based on Atm object
final lowerQuery = query.toLowerCase();
return atm.name.toLowerCase().contains(lowerQuery); // Filter by atm.name
return atm.name
.toLowerCase()
.contains(lowerQuery); // Filter by atm.name
}).toList();
}
});
@@ -64,7 +71,8 @@ class _ATMLocatorScreenState extends State<ATMLocatorScreen> {
padding: const EdgeInsets.all(12.0),
child: TextField(
controller: _searchController,
onChanged: _filterAtms, // Updated: Call _filterAtms on text change
onChanged:
_filterAtms, // Updated: Call _filterAtms on text change
decoration: InputDecoration(
hintText: "Name/Address", // Hint text for the search bar
prefixIcon: const Icon(Icons.search), // Search icon
@@ -81,12 +89,16 @@ class _ATMLocatorScreenState extends State<ATMLocatorScreen> {
? _buildShimmerList() // Display shimmer while loading
: _filteredAtms.isEmpty
? const Center(
child: Text("No matching ATMs found")) // Message if no ATMs found
child: Text(
"No matching ATMs found")) // Message if no ATMs found
: ListView.builder(
itemCount: _filteredAtms.length, // Number of items in the filtered list
itemCount: _filteredAtms
.length, // Number of items in the filtered list
itemBuilder: (context, index) {
final atm = _filteredAtms[index]; // Get the current Atm object
return _buildAtmItem(atm); // Build the ATM list item
final atm = _filteredAtms[
index]; // Get the current Atm object
return _buildAtmItem(
atm); // Build the ATM list item
},
),
),
@@ -111,9 +123,9 @@ class _ATMLocatorScreenState extends State<ATMLocatorScreen> {
);
}
/// Helper widget to build a single ATM list item.
Widget _buildAtmItem(Atm atm) { // Changed: Takes an Atm object
Widget _buildAtmItem(Atm atm) {
// Changed: Takes an Atm object
return Card(
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
child: ListTile(

View File

@@ -1,107 +1,109 @@
import 'package:flutter/material.dart';
import 'package:kmobile/api/services/branch_service.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter/material.dart';
import 'package:kmobile/api/services/branch_service.dart';
import 'package:url_launcher/url_launcher.dart';
class BranchDetailsScreen extends StatelessWidget {
final Branch branch;
class BranchDetailsScreen extends StatelessWidget {
final Branch branch;
const BranchDetailsScreen({super.key, required this.branch});
const BranchDetailsScreen({super.key, required this.branch});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(branch.branch_name),
),
body: Stack(
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildDetailRow(context, "Branch Name", branch.branch_name),
_buildDetailRow(context, "Branch Code", branch.branch_code),
_buildDetailRow(context, "Zone", branch.zone),
_buildDetailRow(context, "Tehsil", branch.tehsil),
_buildDetailRow(context, "Block", branch.block),
_buildDetailRow(context, "District", branch.distt_name),
_buildDetailRow(context, "Pincode", branch.pincode),
// _buildDetailRow(context, "Post Office", branch.post_office),
// _buildDetailRow(context, "Date of Opening", branch.date_of_opening),
// _buildDetailRow(context, "Branch Type", branch.type_of_branch),
_buildDetailRow(context, "Telephone No.", branch.telephone_no),
// _buildDetailRow("RTGS Account No.", branch.rtgs_acct_no),
// _buildDetailRow("RBI Code 1", branch.rbi_code_1),
// _buildDetailRow("RBI Code 2", branch.rbi_code_2),
// _buildDetailRow("Latitude", branch.br_lattitude),
// _buildDetailRow("Longitude", branch.br_longitude),
],
),
),
IgnorePointer(
child: Center(
child: Opacity(
opacity: 0.07, // Reduced opacity
child: ClipOval(
child: Image.asset(
'assets/images/logo.png',
width: 200, // Adjust size as needed
height: 200, // Adjust size as needed
),
),
),
),
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(branch.branch_name),
),
body: Stack(
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildDetailRow(context, "Branch Name", branch.branch_name),
_buildDetailRow(context, "Branch Code", branch.branch_code),
_buildDetailRow(context, "Zone", branch.zone),
_buildDetailRow(context, "Tehsil", branch.tehsil),
_buildDetailRow(context, "Block", branch.block),
_buildDetailRow(context, "District", branch.distt_name),
_buildDetailRow(context, "Pincode", branch.pincode),
// _buildDetailRow(context, "Post Office", branch.post_office),
// _buildDetailRow(context, "Date of Opening", branch.date_of_opening),
// _buildDetailRow(context, "Branch Type", branch.type_of_branch),
_buildDetailRow(context, "Telephone No.", branch.telephone_no),
// _buildDetailRow("RTGS Account No.", branch.rtgs_acct_no),
// _buildDetailRow("RBI Code 1", branch.rbi_code_1),
// _buildDetailRow("RBI Code 2", branch.rbi_code_2),
// _buildDetailRow("Latitude", branch.br_lattitude),
// _buildDetailRow("Longitude", branch.br_longitude),
],
),
),
IgnorePointer(
child: Center(
child: Opacity(
opacity: 0.07, // Reduced opacity
child: ClipOval(
child: Image.asset(
'assets/images/logo.png',
width: 200, // Adjust size as needed
height: 200, // Adjust size as needed
),
),
),
),
),
],
),
);
}
Widget _buildDetailRow(BuildContext context, String label, String value) {
final theme = Theme.of(context);
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 14,
color: theme.textTheme.bodySmall?.color,
),
),
const SizedBox(height: 4),
label == "Telephone No."
? InkWell(
onTap: () => _launchUrl('tel:$value'),
child: Text(
value,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: theme.colorScheme.primary, // Indicate it's clickable
decoration: TextDecoration.underline,
),
),
)
: Text(
value,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
Divider(height: 16, color: theme.dividerColor),
],
),
);
}
Future<void> _launchUrl(String urlString) async {
final Uri url = Uri.parse(urlString);
if (!await launchUrl(url)) {
throw 'Could not launch $urlString';
}
}
}
Widget _buildDetailRow(BuildContext context, String label, String value) {
final theme = Theme.of(context);
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 14,
color: theme.textTheme.bodySmall?.color,
),
),
const SizedBox(height: 4),
label == "Telephone No."
? InkWell(
onTap: () => _launchUrl('tel:$value'),
child: Text(
value,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color:
theme.colorScheme.primary, // Indicate it's clickable
decoration: TextDecoration.underline,
),
),
)
: Text(
value,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
Divider(height: 16, color: theme.dividerColor),
],
),
);
}
Future<void> _launchUrl(String urlString) async {
final Uri url = Uri.parse(urlString);
if (!await launchUrl(url)) {
throw 'Could not launch $urlString';
}
}
}

View File

@@ -7,7 +7,6 @@ import 'package:kmobile/di/injection.dart';
import 'package:shimmer/shimmer.dart';
import 'package:kmobile/features/service/screens/branch_details_screen.dart';
class BranchLocatorScreen extends StatefulWidget {
const BranchLocatorScreen({super.key});
@@ -15,52 +14,51 @@ class BranchLocatorScreen extends StatefulWidget {
State<BranchLocatorScreen> createState() => _BranchLocatorScreenState();
}
class _BranchLocatorScreenState extends State<BranchLocatorScreen> {
final TextEditingController _searchController = TextEditingController();
var service = getIt<BranchService>();
bool _isLoading = true;
List<Branch> _allBranches = [];
List<Branch> _filteredBranches = [];
class _BranchLocatorScreenState extends State<BranchLocatorScreen> {
final TextEditingController _searchController = TextEditingController();
var service = getIt<BranchService>();
bool _isLoading = true;
List<Branch> _allBranches = [];
List<Branch> _filteredBranches = [];
@override
@override
void initState() {
super.initState();
// _fetchAndSetLocations();
_loadBranches();
}
Future<void> _loadBranches() async {
final data = await service.fetchBranchList();
setState(() {
_allBranches = data;
_filteredBranches = data;
_isLoading = false;
});
}
Future<void> _loadBranches() async {
final data = await service.fetchBranchList();
setState(() {
_allBranches = data;
_filteredBranches = data;
_isLoading = false;
});
}
void _filterBranches(String query) {
setState(() {
if (query.isEmpty) {
_filteredBranches = _allBranches;
} else {
_filteredBranches = _allBranches.where((branch) {
final lowerQuery = query.toLowerCase();
return branch.branch_name.toLowerCase().contains(lowerQuery);
}).toList();
}
});
}
setState(() {
if (query.isEmpty) {
_filteredBranches = _allBranches;
} else {
_filteredBranches = _allBranches.where((branch) {
final lowerQuery = query.toLowerCase();
return branch.branch_name.toLowerCase().contains(lowerQuery);
}).toList();
}
});
}
@override
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Branch Locator",
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: Theme.of(context).colorScheme.onSurface,
),
color: Theme.of(context).colorScheme.onSurface,
),
),
),
body: Stack(
@@ -88,11 +86,13 @@ class BranchLocatorScreen extends StatefulWidget {
? _buildShimmerList() // Changed to shimmer
: _filteredBranches.isEmpty
? const Center(
child: Text("No matching branches found")) // Updated tex
child: Text(
"No matching branches found")) // Updated tex
: ListView.builder(
itemCount: _filteredBranches.length,
itemBuilder: (context, index) {
final branch = _filteredBranches[index]; // Changed to
final branch =
_filteredBranches[index]; // Changed to
return _buildBranchItem(branch); // Updated
},
),
@@ -132,7 +132,7 @@ class BranchLocatorScreen extends StatefulWidget {
}
// Helper widget to build a single branch item
Widget _buildBranchItem(Branch branch) {
return Card(
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
@@ -155,7 +155,6 @@ class BranchLocatorScreen extends StatefulWidget {
);
}
// Shimmer loading list
Widget _buildShimmerList() {
return ListView.builder(

View File

@@ -110,4 +110,4 @@ class _FaqsScreenState extends State<FaqsScreen> {
),
);
}
}
}

View File

@@ -1,113 +1,113 @@
//
//
import 'package:flutter/material.dart';
import 'package:kmobile/l10n/app_localizations.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter/material.dart';
import 'package:kmobile/l10n/app_localizations.dart';
import 'package:url_launcher/url_launcher.dart';
// Data model for a single Quick Link item
class QuickLink {
final String title;
final String url;
// The icon is no longer used in the UI but is kept in the model for potential future use.
final IconData icon;
// Data model for a single Quick Link item
class QuickLink {
final String title;
final String url;
// The icon is no longer used in the UI but is kept in the model for potential future use.
final IconData icon;
QuickLink({required this.title, required this.url, required this.icon});
}
QuickLink({required this.title, required this.url, required this.icon});
}
class QuickLinksScreen extends StatefulWidget {
const QuickLinksScreen({super.key});
class QuickLinksScreen extends StatefulWidget {
const QuickLinksScreen({super.key});
@override
State<QuickLinksScreen> createState() => _QuickLinksScreenState();
}
@override
State<QuickLinksScreen> createState() => _QuickLinksScreenState();
}
class _QuickLinksScreenState extends State<QuickLinksScreen> {
// List of Quick Links
final List<QuickLink> _quickLinks = [
QuickLink(
title: "National Bank of Agriculture & Rural Development",
url: "http://www.nabard.org/",
icon: Icons.account_balance),
QuickLink(
title: "Reserve Bank of India",
url: "http://www.rbi.org.in/home.aspx",
icon: Icons.account_balance_wallet),
QuickLink(
title: "Indian Institute of Banking & Finance",
url: "http://www.iibf.org.in/",
icon: Icons.school),
QuickLink(
title: "Indian Bank Association",
url: "http://www.iba.org.in/",
icon: Icons.group_work),
QuickLink(
title: "Ministry of Finance",
url: "http://www.finmin.nic.in/",
icon: Icons.business),
QuickLink(
title: "Securities Exchange Board of India",
url: "http://www.sebi.gov.in/",
icon: Icons.show_chart),
QuickLink(
title: "Insurance Regulatory & Development Authority",
url: "https://www.irdai.gov.in/",
icon: Icons.shield_outlined),
];
class _QuickLinksScreenState extends State<QuickLinksScreen> {
// List of Quick Links
final List<QuickLink> _quickLinks = [
QuickLink(
title: "National Bank of Agriculture & Rural Development",
url: "http://www.nabard.org/",
icon: Icons.account_balance),
QuickLink(
title: "Reserve Bank of India",
url: "http://www.rbi.org.in/home.aspx",
icon: Icons.account_balance_wallet),
QuickLink(
title: "Indian Institute of Banking & Finance",
url: "http://www.iibf.org.in/",
icon: Icons.school),
QuickLink(
title: "Indian Bank Association",
url: "http://www.iba.org.in/",
icon: Icons.group_work),
QuickLink(
title: "Ministry of Finance",
url: "http://www.finmin.nic.in/",
icon: Icons.business),
QuickLink(
title: "Securities Exchange Board of India",
url: "http://www.sebi.gov.in/",
icon: Icons.show_chart),
QuickLink(
title: "Insurance Regulatory & Development Authority",
url: "https://www.irdai.gov.in/",
icon: Icons.shield_outlined),
];
// Function to launch a URL
Future<void> _launchURL(String url, BuildContext context) async {
final Uri uri = Uri.parse(url);
if (await canLaunchUrl(uri)) {
await launchUrl(uri, mode: LaunchMode.externalApplication);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Could not launch $url')),
);
}
}
// Function to launch a URL
Future<void> _launchURL(String url, BuildContext context) async {
final Uri uri = Uri.parse(url);
if (await canLaunchUrl(uri)) {
await launchUrl(uri, mode: LaunchMode.externalApplication);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Could not launch $url')),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context).quickLinks),
),
body: Stack(
children: [
// Background logo
IgnorePointer(
child: Center(
child: Opacity(
opacity: 0.07,
child: ClipOval(
child: Image.asset(
'assets/images/logo.png',
width: 200,
height: 200,
),
),
),
),
),
// UPDATED: List of Quick Links
ListView.builder(
padding: const EdgeInsets.symmetric(vertical: 8.0),
itemCount: _quickLinks.length,
itemBuilder: (context, index) {
final link = _quickLinks[index];
return Card(
margin:
const EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0),
child: ListTile(
title: Text(link.title),
trailing: const Icon(Icons.open_in_new, size: 20),
onTap: () => _launchURL(link.url, context),
),
);
},
),
],
),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context).quickLinks),
),
body: Stack(
children: [
// Background logo
IgnorePointer(
child: Center(
child: Opacity(
opacity: 0.07,
child: ClipOval(
child: Image.asset(
'assets/images/logo.png',
width: 200,
height: 200,
),
),
),
),
),
// UPDATED: List of Quick Links
ListView.builder(
padding: const EdgeInsets.symmetric(vertical: 8.0),
itemCount: _quickLinks.length,
itemBuilder: (context, index) {
final link = _quickLinks[index];
return Card(
margin:
const EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0),
child: ListTile(
title: Text(link.title),
trailing: const Icon(Icons.open_in_new, size: 20),
onTap: () => _launchURL(link.url, context),
),
);
},
),
],
),
);
}
}

View File

@@ -52,7 +52,8 @@ class _ServiceScreen extends State<ServiceScreen> {
label: AppLocalizations.of(context).faq,
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const FaqsScreen()),
MaterialPageRoute(
builder: (context) => const FaqsScreen()),
);
},
disabled: false,
@@ -120,7 +121,8 @@ class ServiceManagementTile extends StatelessWidget {
),
elevation: 4, // Add some elevation for better visual separation
child: InkWell(
onTap: disabled ? null : onTap, // Disable InkWell if the tile is disabled
onTap:
disabled ? null : onTap, // Disable InkWell if the tile is disabled
borderRadius: BorderRadius.circular(12.0),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 16.0),
@@ -130,7 +132,8 @@ class ServiceManagementTile extends StatelessWidget {
Icon(
icon,
size: 48, // Make icon larger
color: disabled ? theme.disabledColor : theme.colorScheme.primary,
color:
disabled ? theme.disabledColor : theme.colorScheme.primary,
),
const SizedBox(height: 12),
Text(
@@ -138,7 +141,9 @@ class ServiceManagementTile extends StatelessWidget {
textAlign: TextAlign.center,
style: theme.textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold,
color: disabled ? theme.disabledColor : theme.colorScheme.onSurface,
color: disabled
? theme.disabledColor
: theme.colorScheme.onSurface,
),
),
],