import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../../application/analytic/profit_loss_loader/profit_loss_loader_bloc.dart'; import '../../../common/theme/theme.dart'; import '../../../injection.dart'; import 'widgets/cost_breakdown.dart'; import 'widgets/profit_loss_header.dart'; import 'widgets/profit_loss_report.dart'; @RoutePage() class FinancePage extends StatefulWidget implements AutoRouteWrapper { const FinancePage({super.key}); @override State createState() => _FinancePageState(); @override Widget wrappedRoute(BuildContext context) => BlocProvider( create: (_) => getIt()..add(ProfitLossLoaderEvent.fetched()), child: this, ); } class _FinancePageState extends State with SingleTickerProviderStateMixin { late AnimationController _fadeController; late Animation _fadeAnimation; int _selectedTabIndex = 0; @override void initState() { super.initState(); _fadeController = AnimationController( duration: const Duration(milliseconds: 1000), vsync: this, ); _fadeAnimation = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation(parent: _fadeController, curve: Curves.easeIn)); _fadeController.forward(); } @override void dispose() { _fadeController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColor.background, body: BlocListener( listenWhen: (previous, current) => previous.dateFrom != current.dateFrom || previous.dateTo != current.dateTo, listener: (context, state) { context.read().add( ProfitLossLoaderEvent.fetched(), ); }, child: BlocBuilder( builder: (context, state) { return CustomScrollView( slivers: [ // Header with gradient background, tabs, and summary SliverToBoxAdapter( child: FadeTransition( opacity: _fadeAnimation, child: ProfitLossHeader( state: state, selectedTabIndex: _selectedTabIndex, onTabChanged: (index) { setState(() { _selectedTabIndex = index; }); _onTabChanged(context, index); }, ), ), ), // Profit Loss Report Table SliverToBoxAdapter( child: FadeTransition( opacity: _fadeAnimation, child: ProfitLossReport( mainSummary: state.profitLoss.mainSummary, summary: state.profitLoss.summary, selectedTabIndex: _selectedTabIndex, ), ), ), // Cost Breakdown SliverToBoxAdapter( child: FadeTransition( opacity: _fadeAnimation, child: CostBreakdown( purchasing: state.profitLoss.purchasing, selectedTabIndex: _selectedTabIndex, dateFrom: state.dateFrom, dateTo: state.dateTo, ), ), ), // Bottom spacing const SliverToBoxAdapter(child: SizedBox(height: 100)), ], ); }, ), ), ); } void _onTabChanged(BuildContext context, int index) { final now = DateTime.now(); DateTime dateFrom; DateTime dateTo; if (index == 0) { // Today dateFrom = DateTime(now.year, now.month, now.day); dateTo = DateTime(now.year, now.month, now.day, 23, 59, 59); } else { // MTD (Month-to-Date) dateFrom = DateTime(now.year, now.month, 1); dateTo = now; } context.read().add( ProfitLossLoaderEvent.rangeDateChanged(dateFrom, dateTo), ); } }