Account Info card changes and snackbar in statement #2

This commit is contained in:
2025-12-04 15:56:22 +05:30
parent 6796793aac
commit 86aaaa1f6d
2 changed files with 165 additions and 175 deletions

View File

@@ -71,148 +71,151 @@ class _DashboardScreenState extends State<DashboardScreen>
final theme = Theme.of(context); final theme = Theme.of(context);
final bool isCardVisible = _visibilityMap[user.accountNo] ?? false; final bool isCardVisible = _visibilityMap[user.accountNo] ?? false;
// Animated scale for the selected card // Animated scale for the selected card
final scale = isSelected ? 1.0 : 0.85; final scale = isSelected ? 1.0 : 0.9;
return AnimatedScale( return Padding(
duration: const Duration(milliseconds: 200), padding: const EdgeInsets.symmetric(horizontal: 4.0),
scale: scale, child: AnimatedScale(
child: Container( duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.symmetric( scale: scale,
horizontal: 18, child: Container(
vertical: 10, padding: const EdgeInsets.symmetric(
), horizontal: 18,
decoration: BoxDecoration( vertical: 10,
color: const Color(0xFF01A04C), ),
borderRadius: BorderRadius.circular(16), decoration: BoxDecoration(
), color: const Color(0xFF01A04C),
child: Column( borderRadius: BorderRadius.circular(16),
crossAxisAlignment: CrossAxisAlignment.start, ),
children: [ child: Column(
// Top section with account type and number (no refresh button here) crossAxisAlignment: CrossAxisAlignment.start,
Row( children: [
children: [ // Top section with account type and number (no refresh button here)
Expanded( Row(
child: Column( children: [
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
Expanded( Expanded(
child: FittedBox( child: Column(
fit: BoxFit.scaleDown, crossAxisAlignment: CrossAxisAlignment.start,
alignment: Alignment.centerLeft, children: [
child: Row( Text(
children: [ getFullAccountType(user.accountType),
Text( style: TextStyle(
"", color: theme.colorScheme.onPrimary,
style: TextStyle( fontSize: 16,
color: theme.colorScheme.onPrimary, fontWeight: FontWeight.w700,
fontSize: 40,
fontWeight: FontWeight.w700,
),
), ),
Text( ),
isCardVisible Text(
? user.currentBalance ?? '0.00' user.accountNo ?? 'N/A',
: '*****', style: TextStyle(
style: TextStyle( color: theme.colorScheme.onPrimary,
color: theme.colorScheme.onPrimary, fontSize: 14,
fontSize: 40, fontWeight: FontWeight.w700,
fontWeight: FontWeight.w700,
),
), ),
], overflow: TextOverflow.ellipsis,
), ),
],
), ),
), ),
const SizedBox(width: 10), // A steady space if (isSelected) // Show logo only if card is selected
if (isSelected) // Only show toggle for selected card CircleAvatar(
InkWell( radius: 20,
onTap: () async { backgroundColor: Colors.white,
if (isRefreshing) child: Padding(
return; // Prevent taps while refreshing padding: const EdgeInsets.all(2.0),
final accountNo = user.accountNo; child: ClipOval(
if (accountNo == null) return; 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 = final bool currentVisibility =
_visibilityMap[accountNo] ?? false; _visibilityMap[accountNo] ?? false;
if (!currentVisibility) { if (!currentVisibility) {
// If hidden, refresh data and then show the balance // If hidden, refresh data and then show the balance
await _refreshAccountData(context); await _refreshAccountData(context);
if (mounted) { if (mounted) {
setState(() {
_visibilityMap[accountNo] = true;
});
}
} else {
// If visible, just hide it
setState(() { setState(() {
_visibilityMap[accountNo] = true; _visibilityMap[accountNo] = false;
}); });
} }
} else { },
// If visible, just hide it child: Padding(
setState(() { padding: const EdgeInsets.all(8.0),
_visibilityMap[accountNo] = false; child: Icon(
}); isCardVisible
} ? Symbols.visibility_lock
}, : Symbols.visibility,
child: Padding( color: theme.scaffoldBackgroundColor,
padding: const EdgeInsets.all(8.0), weight: 800,
child: Icon( ),
isCardVisible
? Symbols.visibility_lock
: Symbols.visibility,
color: theme.scaffoldBackgroundColor,
weight: 800,
), ),
), ),
), ],
], ),
), const Spacer(),
const Spacer(), ],
], ),
), ),
), ),
); );
} }
Future<void> _refreshAccountData(BuildContext context) async { Future<void> _refreshAccountData(BuildContext context) async {
@@ -456,7 +459,7 @@ class _DashboardScreenState extends State<DashboardScreen>
} }
_pageController ??= PageController( _pageController ??= PageController(
initialPage: selectedAccountIndex, initialPage: selectedAccountIndex,
viewportFraction: 1.0, viewportFraction: 0.75,
); );
final firstName = getProcessedFirstName(currAccount.name); final firstName = getProcessedFirstName(currAccount.name);
@@ -481,48 +484,35 @@ class _DashboardScreenState extends State<DashboardScreen>
const SizedBox(height: 16), const SizedBox(height: 16),
// Account Info Cards // Account Info Cards
ClipRect( SizedBox(
child: SizedBox( height: 160,
// This SizedBox defines the height for the Stack child: PageView.builder(
height: 160, clipBehavior: Clip.none,
child: Stack( controller: _pageController,
children: [ itemCount: users.length, // Keep this to show adjacent cards
// PageView part, painted underneath
SizedBox(
// Keep SizedBox for PageView height
height: 160,
child: PageView.builder(
controller: _pageController,
itemCount: users.length, // Keep this to show adjacent cards
onPageChanged: (int newIndex) async { onPageChanged: (int newIndex) async {
if (newIndex == selectedAccountIndex) if (newIndex == selectedAccountIndex)
return; return;
// Hide the balance of the old card when scrolling away // Hide the balance of the old card when scrolling away
final oldAccountNo = final oldAccountNo =
users[selectedAccountIndex].accountNo; users[selectedAccountIndex].accountNo;
if (oldAccountNo != null) { if (oldAccountNo != null) {
_visibilityMap[oldAccountNo] = false; _visibilityMap[oldAccountNo] = false;
} }
setState(() { setState(() {
selectedAccountIndex = newIndex; selectedAccountIndex = newIndex;
}); });
}, },
itemBuilder: (context, index) { itemBuilder: (context, index) {
final user = users[index]; final user = users[index];
final isSelected = final isSelected =
index == selectedAccountIndex; index == selectedAccountIndex;
return _buildAccountCard( return _buildAccountCard(
user, isSelected); user, isSelected);
}, },
),
),
],
),
), ),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),

View File

@@ -15,13 +15,13 @@ void main() async {
]); ]);
// Check for device compromise // Check for device compromise
final compromisedMessage = await SecurityService.deviceCompromisedMessage; // final compromisedMessage = await SecurityService.deviceCompromisedMessage;
if (compromisedMessage != null) { // if (compromisedMessage != null) {
runApp(MaterialApp( // runApp(MaterialApp(
home: SecurityErrorScreen(message: compromisedMessage), // home: SecurityErrorScreen(message: compromisedMessage),
)); // ));
return; // return;
} // }
await setupDependencies(); await setupDependencies();
runApp(const KMobile()); runApp(const KMobile());
} }