From 0b0c0724732409f644c809ccb5247613ce76c6af Mon Sep 17 00:00:00 2001 From: Vaibhav Surve Date: Wed, 5 Nov 2025 17:26:32 +0530 Subject: [PATCH] updates finance screen --- lib/view/finance/finance_screen.dart | 515 ++++----------------------- 1 file changed, 72 insertions(+), 443 deletions(-) diff --git a/lib/view/finance/finance_screen.dart b/lib/view/finance/finance_screen.dart index 49d3e8a..8e08aea 100644 --- a/lib/view/finance/finance_screen.dart +++ b/lib/view/finance/finance_screen.dart @@ -3,6 +3,7 @@ import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:get/get.dart'; import 'package:marco/controller/project_controller.dart'; import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; +import 'package:marco/helpers/widgets/my_card.dart'; import 'package:marco/helpers/widgets/my_spacing.dart'; import 'package:marco/helpers/widgets/my_text.dart'; @@ -106,484 +107,112 @@ class _FinanceScreenState extends State opacity: _fadeAnimation, child: SingleChildScrollView( padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildWelcomeSection(), - MySpacing.height(24), - _buildFinanceModules(), - MySpacing.height(24), - _buildQuickStatsSection(), - ], - ), + child: _buildFinanceModulesCompact(), ), ), + ); } - Widget _buildWelcomeSection() { - final projectSelected = projectController.selectedProject != null; - - return Container( - width: double.infinity, - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - contentTheme.primary.withValues(alpha: 0.1), - contentTheme.info.withValues(alpha: 0.05), - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: contentTheme.primary.withValues(alpha: 0.2), - width: 1, - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: contentTheme.primary.withValues(alpha: 0.1), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], - ), - child: Icon( - LucideIcons.landmark, - color: contentTheme.primary, - size: 24, - ), - ), - MySpacing.width(12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - MyText.titleMedium( - 'Financial Management', - fontWeight: 700, - color: Colors.black87, - ), - MySpacing.height(2), - MyText.bodySmall( - projectSelected - ? 'Manage your project finances' - : 'Select a project to get started', - color: Colors.grey[600], - ), - ], - ), - ), - ], - ), - if (!projectSelected) ...[ - MySpacing.height(12), - Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.orange.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Colors.orange.withValues(alpha: 0.3)), - ), - child: Row( - children: [ - Icon( - LucideIcons.badge_alert, - size: 16, - color: Colors.orange[700], - ), - MySpacing.width(8), - Expanded( - child: MyText.bodySmall( - 'Please select a project to access finance modules', - color: Colors.orange[700], - fontWeight: 500, - ), - ), - ], - ), - ), - ], - ], - ), - ); - } - - Widget _buildFinanceModules() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - MyText.titleMedium( - 'Finance Modules', - fontWeight: 700, - color: Colors.black87, - ), - MySpacing.height(4), - MyText.bodySmall( - 'Select a module to manage', - color: Colors.grey[600], - ), - MySpacing.height(16), - _buildModuleGrid(), - ], - ); - } - - Widget _buildModuleGrid() { + // --- Finance Modules (Single Row, Equally Spaced) --- + Widget _buildFinanceModulesCompact() { final stats = [ - _FinanceStatItem( - LucideIcons.badge_dollar_sign, - "Expense", - "Track and manage expenses", - contentTheme.info, - "/dashboard/expense-main-page", - ), - _FinanceStatItem( - LucideIcons.receipt_text, - "Payment Request", - "Submit payment requests", - contentTheme.primary, - "/dashboard/payment-request", - ), - _FinanceStatItem( - LucideIcons.wallet, - "Advance Payment", - "Manage advance payments", - contentTheme.warning, - "/dashboard/advance-payment", - ), + _FinanceStatItem(LucideIcons.badge_dollar_sign, "Expense", + contentTheme.info, "/dashboard/expense-main-page"), + _FinanceStatItem(LucideIcons.receipt_text, "Payment Request", + contentTheme.primary, "/dashboard/payment-request"), + _FinanceStatItem(LucideIcons.wallet, "Advance Payment", + contentTheme.warning, "/dashboard/advance-payment"), ]; final projectSelected = projectController.selectedProject != null; - return GridView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 12, - mainAxisSpacing: 12, - childAspectRatio: 1.1, - ), - itemCount: stats.length, - itemBuilder: (context, index) { - return _buildModernFinanceCard( - stats[index], - projectSelected, - index, - ); - }, - ); - } - - Widget _buildModernFinanceCard( - _FinanceStatItem statItem, - bool isProjectSelected, - int index, - ) { - final bool isEnabled = isProjectSelected; - - return TweenAnimationBuilder( - duration: Duration(milliseconds: 400 + (index * 100)), - tween: Tween(begin: 0.0, end: 1.0), - curve: Curves.easeOutCubic, - builder: (context, value, child) { - return Transform.scale( - scale: value, - child: Opacity( - opacity: isEnabled ? 1.0 : 0.5, - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: () => _onCardTap(statItem, isEnabled), - borderRadius: BorderRadius.circular(16), - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: isEnabled - ? statItem.color.withValues(alpha: 0.2) - : Colors.grey.withValues(alpha: 0.2), - width: 1.5, - ), - ), - child: Stack( - children: [ - // Content - Padding( - padding: const EdgeInsets.all(16), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: const EdgeInsets.all(12), - child: Icon( - statItem.icon, - size: 28, - color: statItem.color, - ), - ), - MySpacing.height(12), - MyText.titleSmall( - statItem.title, - fontWeight: 700, - color: Colors.black87, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - MySpacing.height(4), - if (isEnabled) - Row( - children: [ - MyText.bodySmall( - 'View Details', - color: statItem.color, - fontWeight: 600, - fontSize: 11, - ), - MySpacing.width(4), - Icon( - LucideIcons.arrow_right, - size: 14, - color: statItem.color, - ), - ], - ), - ], - ), - ), - // Lock icon for disabled state - if (!isEnabled) - Positioned( - top: 12, - right: 12, - child: Container( - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - color: Colors.grey[200], - borderRadius: BorderRadius.circular(6), - ), - child: Icon( - LucideIcons.lock, - size: 14, - color: Colors.grey[600], - ), - ), - ), - ], - ), - ), - ), - ), - ), - ); - }, - ); - } - - Widget _buildQuickStatsSection() { - final projectSelected = projectController.selectedProject != null; - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - MyText.titleMedium( - 'Quick Stats', - fontWeight: 700, - color: Colors.black87, - ), - MySpacing.height(4), - MyText.bodySmall( - 'Overview of your finances', - color: Colors.grey[600], - ), - MySpacing.height(16), - _buildStatsRow(projectSelected), - ], - ); - } - - Widget _buildStatsRow(bool projectSelected) { - final stats = [ - _QuickStat( - icon: LucideIcons.trending_up, - label: 'Total Expenses', - value: projectSelected ? '₹0' : '--', - color: contentTheme.danger, - ), - _QuickStat( - icon: LucideIcons.clock, - label: 'Pending', - value: projectSelected ? '0' : '--', - color: contentTheme.warning, - ), - ]; - return Row( - children: stats - .map((stat) => Expanded( - child: Padding( - padding: const EdgeInsets.only(right: 8), - child: _buildStatCard(stat, projectSelected), - ), - )) - .toList(), - ); - } - - Widget _buildStatCard(_QuickStat stat, bool isEnabled) { - return Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: stat.color.withValues(alpha: 0.2), - width: 1, - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: stat.color.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(8), - ), - child: Icon( - stat.icon, - size: 20, - color: stat.color, - ), - ), - MySpacing.height(12), - MyText.bodySmall( - stat.label, - color: Colors.grey[600], - fontSize: 11, - ), - MySpacing.height(4), - MyText.titleLarge( - stat.value, - fontWeight: 700, - color: isEnabled ? Colors.black87 : Colors.grey[400], - ), - ], - ), - ); - } - - void _onCardTap(_FinanceStatItem statItem, bool isEnabled) { - if (!isEnabled) { - Get.dialog( - Dialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: stats.map((stat) { + return Expanded( child: Padding( - padding: const EdgeInsets.all(24), + padding: const EdgeInsets.symmetric(horizontal: 8), + child: _buildFinanceModuleCard(stat, projectSelected), + ), + ); + }).toList(), + ); + } + + Widget _buildFinanceModuleCard( + _FinanceStatItem stat, bool isProjectSelected) { + final bool isEnabled = isProjectSelected; + + return Opacity( + opacity: isEnabled ? 1.0 : 0.4, + child: IgnorePointer( + ignoring: !isEnabled, + child: InkWell( + onTap: () => _onCardTap(stat, isEnabled), + borderRadius: BorderRadius.circular(5), + child: MyCard.bordered( + height: 80, + paddingAll: 5, + borderRadiusAll: 5, + border: Border.all(color: Colors.grey.withOpacity(0.15)), child: Column( - mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, children: [ Container( - padding: const EdgeInsets.all(16), + padding: const EdgeInsets.all(6), decoration: BoxDecoration( - color: Colors.orange.withValues(alpha: 0.1), - shape: BoxShape.circle, + color: stat.color.withOpacity(0.1), + borderRadius: BorderRadius.circular(4), ), child: Icon( - LucideIcons.badge_alert, - color: Colors.orange[700], - size: 32, + stat.icon, + size: 20, + color: stat.color, ), ), - MySpacing.height(16), - MyText.titleMedium( - "No Project Selected", - fontWeight: 700, - color: Colors.black87, - textAlign: TextAlign.center, - ), - MySpacing.height(8), - MyText.bodyMedium( - "Please select a project before accessing this section.", - color: Colors.grey[600], - textAlign: TextAlign.center, - ), - MySpacing.height(24), - SizedBox( - width: double.infinity, - child: ElevatedButton( - onPressed: () => Get.back(), - style: ElevatedButton.styleFrom( - backgroundColor: contentTheme.primary, - foregroundColor: Colors.white, - padding: const EdgeInsets.symmetric(vertical: 12), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - elevation: 0, - ), - child: MyText.bodyMedium( - "OK", - color: Colors.white, - fontWeight: 600, + MySpacing.height(6), + Flexible( + child: Text( + stat.title, + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 12, + overflow: TextOverflow.ellipsis, ), + maxLines: 2, + softWrap: true, ), ), ], ), ), ), - ); - return; - } + ), + ); + } - Get.toNamed(statItem.route); + void _onCardTap(_FinanceStatItem statItem, bool isEnabled) { + if (!isEnabled) { + Get.defaultDialog( + title: "No Project Selected", + middleText: "Please select a project before accessing this section.", + confirm: ElevatedButton( + onPressed: () => Get.back(), + child: const Text("OK"), + ), + ); + } else { + Get.toNamed(statItem.route); + } } } class _FinanceStatItem { final IconData icon; final String title; - final String subtitle; final Color color; final String route; - _FinanceStatItem( - this.icon, - this.title, - this.subtitle, - this.color, - this.route, - ); -} - -class _QuickStat { - final IconData icon; - final String label; - final String value; - final Color color; - - _QuickStat({ - required this.icon, - required this.label, - required this.value, - required this.color, - }); + _FinanceStatItem(this.icon, this.title, this.color, this.route); }