import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:line_icons/line_icons.dart'; import '../../../application/order/order_loader/order_loader_bloc.dart'; import '../../../common/theme/theme.dart'; import '../../../injection.dart'; import '../../components/appbar/appbar.dart'; import '../../components/button/button.dart'; import '../../components/spacer/spacer.dart'; import '../../components/widgets/empty_widget.dart'; import 'widgets/status_tile.dart'; import 'widgets/order_tile.dart'; @RoutePage() class OrderPage extends StatefulWidget implements AutoRouteWrapper { const OrderPage({super.key}); @override State createState() => _OrderPageState(); @override Widget wrappedRoute(BuildContext context) => BlocProvider( create: (_) => getIt() ..add(OrderLoaderEvent.fetched(isRefresh: true)), child: this, ); } class _OrderPageState extends State with TickerProviderStateMixin { late AnimationController _fadeController; late AnimationController _slideController; late Animation _fadeAnimation; late Animation _slideAnimation; final ScrollController _scrollController = ScrollController(); // Filter state String selectedFilter = 'All'; final List filterOptions = ['All', 'Completed', 'Pending']; @override void initState() { super.initState(); _fadeController = AnimationController( duration: const Duration(milliseconds: 800), vsync: this, ); _slideController = AnimationController( duration: const Duration(milliseconds: 1000), vsync: this, ); _fadeAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation(parent: _fadeController, curve: Curves.easeInOut), ); _slideAnimation = Tween(begin: const Offset(0, 0.3), end: Offset.zero).animate( CurvedAnimation(parent: _slideController, curve: Curves.elasticOut), ); _fadeController.forward(); _slideController.forward(); } @override void dispose() { _fadeController.dispose(); _slideController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColor.background, body: BlocListener( listenWhen: (p, c) => p.status != c.status, listener: (context, state) { context.read().add( OrderLoaderEvent.fetched(isRefresh: true), ); }, child: BlocBuilder( builder: (context, state) { return NotificationListener( onNotification: (notification) { if (notification is ScrollEndNotification && _scrollController.position.extentAfter == 0) { context.read().add( OrderLoaderEvent.fetched(), ); return true; } return true; }, child: CustomScrollView( controller: _scrollController, slivers: [ // Custom App Bar with Hero Effect SliverAppBar( expandedHeight: 120, floating: true, pinned: true, backgroundColor: AppColor.primary, centerTitle: false, flexibleSpace: CustomAppBar(title: 'Order', isBack: false), actions: [ ActionIconButton(onTap: () {}, icon: LineIcons.filter), SpaceWidth(8), ], ), // Pinned Filter Section SliverPersistentHeader( pinned: true, delegate: _FilterHeaderDelegate( child: Container( color: AppColor.background, padding: EdgeInsets.fromLTRB( AppValue.padding, 10, AppValue.padding, 10, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: filterOptions.map((option) { final index = filterOptions.indexOf(option); return Padding( padding: EdgeInsets.only( right: index < filterOptions.length - 1 ? 8 : 0, ), child: OrderStatusTile( label: option, isSelected: option == selectedFilter, onSelected: (isSelected) { if (isSelected) { setState(() { selectedFilter = option; }); if (option.toLowerCase() == 'all') { context.read().add( OrderLoaderEvent.statusChanged( '', ), ); } else { context.read().add( OrderLoaderEvent.statusChanged( option.toLowerCase(), ), ); } } }, ), ); }).toList(), ), ), ], ), ), ), ), // Content SliverPadding( padding: EdgeInsets.all(AppValue.padding), sliver: SliverList( delegate: SliverChildListDelegate([ FadeTransition( opacity: _fadeAnimation, child: SlideTransition( position: _slideAnimation, child: Column( children: [ // Show filtered transaction count if (selectedFilter != 'All') Padding( padding: const EdgeInsets.only(bottom: 16), child: Row( children: [ Text( '${state.orders.length} ${selectedFilter.toLowerCase()} order${state.orders.length != 1 ? 's' : ''}', style: TextStyle( color: AppColor.textSecondary, fontSize: 14, ), ), ], ), ), // Transaction List state.orders.isEmpty ? EmptyWidget( title: 'Order', message: 'No ${selectedFilter.toLowerCase()} orders found', ) : ListView.builder( itemCount: state.orders.length, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemBuilder: (context, index) { return OrderTile( onTap: () {}, order: state.orders[index], ); }, ), ], ), ), ), ]), ), ), ], ), ); }, ), ), ); } } // Custom delegate for pinned filter header class _FilterHeaderDelegate extends SliverPersistentHeaderDelegate { final Widget child; _FilterHeaderDelegate({required this.child}); @override double get minExtent => 70; // Minimum height when collapsed @override double get maxExtent => 70; // Maximum height when expanded @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent, ) { return child; } @override bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) { return false; } }