import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import 'package:qpay/screens/home/home_controller.dart'; import 'package:qpay/screens/pay/pay_controller.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'dart:async'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _alignAnimation; final List> _animations = []; final List> _alignListAnimations = []; late bool _loading = true; Timer? _loadingTimer; bool get _isLoggedIn => true; String _selectedFilter = 'All'; final HomeController homeController = HomeController(); @override void initState() { super.initState(); homeController.getCategories(); homeController.getProviders(); _controller = AnimationController( duration: const Duration(milliseconds: 600), vsync: this, )..forward(); _alignAnimation = Tween( begin: Alignment.centerLeft, end: Alignment.center, ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeOut)); List tranListIndices = [0, 1]; for (int i = 0; i < tranListIndices.length; i++) { _alignListAnimations.add( Tween(begin: Offset(0, -0.25), end: Offset.zero).animate( CurvedAnimation( parent: _controller, curve: Interval(0.075 * i, 1.0, curve: Curves.easeOut), ), ), ); } List buttonIndices = [0, 1, 2]; for (int i = 0; i < buttonIndices.length; i++) { _animations.add( Tween(begin: Offset(-0.15, 0), end: Offset.zero).animate( CurvedAnimation( parent: _controller, curve: Interval(0.075 * i, 1.0, curve: Curves.easeOut), ), ), ); } // Simulate a delay to mimic loading state _loadingTimer = Timer(const Duration(seconds: 1), () { if (mounted) { setState(() { _loading = false; }); } }); } getBoxDecoration(String? clientId) { // BillProvider? provider = homeController.model.selectedProvider; // // if (provider != null && clientId != provider.clientId) { // return BoxDecoration( // border: Border.all(color: Colors.black87.withAlpha(20)), // borderRadius: BorderRadius.circular(12), // ); // } return BoxDecoration( // border: Border.all( // color: Theme.of(context).colorScheme.primary.withValues(alpha: 0.7), // width: 3, // ), border: Border.all(color: Colors.black87.withAlpha(20)), borderRadius: BorderRadius.circular(12), gradient: LinearGradient( colors: [ Theme.of(context).colorScheme.primary.withValues(alpha: 0.1), Theme.of(context).colorScheme.tertiary.withValues(alpha: 0.05), ], stops: const [0.3, 0.7], begin: Alignment.topRight, end: Alignment.bottomLeft, ), ); } void _showErrorSnackBar(String? message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message.toString()), behavior: SnackBarBehavior.floating, ), ); } @override void dispose() { _loadingTimer?.cancel(); _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: CustomScrollView( slivers: [ SliverAppBar( floating: true, title: Image(image: AssetImage('assets/icon.png'), width: 85), actions: [ IconButton( icon: const Icon(Icons.notifications_outlined), onPressed: () {}, ), ], ), SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.all(16.0), child: ListenableBuilder( listenable: homeController, builder: (context, child) { if (homeController.model.errorMessage != null) { WidgetsBinding.instance.addPostFrameCallback((_) { _showErrorSnackBar(homeController.model.errorMessage); }); } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (_isLoggedIn) AlignTransition( alignment: _alignAnimation, child: Skeletonizer( enabled: _loading, child: Column( children: [ Text( "Vusumuzi Khoza", style: TextStyle(fontSize: 15), ), Text( "USD 4.02", style: TextStyle( fontSize: 30, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 20), ], ), ), ), _buildFilterChips(homeController), SizedBox(height: 10), Column( children: [ ...homeController.model.filterableProviders.map( (e) => _buildProviderItem(e, context), ), ], ), SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Recent Activity', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), GestureDetector( onTap: () { context.go('/history'); }, child: const Text( 'View All', style: TextStyle( fontSize: 16, fontWeight: FontWeight.normal, ), ), ), ], ), const SizedBox(height: 20), Skeletonizer( enabled: _loading, child: ListView( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), children: [ SlideTransition( position: _alignListAnimations[0], child: ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Theme.of(context) .colorScheme .primary .withValues(alpha: 0.1), shape: BoxShape.circle, ), child: Icon( Icons.electric_bolt, color: Theme.of(context).colorScheme.primary, ), ), title: Text( 'Electricity Bill', style: TextStyle( fontWeight: FontWeight.bold, ), ), subtitle: Text( 'Paid USD 50.00', style: TextStyle( fontWeight: FontWeight.normal, ), ), trailing: Text( '-USD 50.00', style: TextStyle( color: Colors.red, fontWeight: FontWeight.bold, ), ), ), ), SlideTransition( position: _alignListAnimations[1], child: ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Theme.of(context) .colorScheme .primary .withValues(alpha: 0.1), shape: BoxShape.circle, ), child: Icon( Icons.phone_android, color: Theme.of(context).colorScheme.primary, ), ), title: Text( 'Airtime Purchase', style: TextStyle( fontWeight: FontWeight.bold, ), ), subtitle: Text( 'Purchased USD 10.00', style: TextStyle( fontWeight: FontWeight.normal, ), ), trailing: Text( '-USD 10.00', style: TextStyle( color: Colors.red, fontWeight: FontWeight.bold, ), ), ), ), ], ), ), ], ); }, ), ), ), ], ), ), ); } Column _buildProviderItem(BillProvider e, BuildContext context) { return Column( children: [ Skeletonizer( enabled: homeController.model.isLoading, child: SlideTransition( position: _alignListAnimations[1], child: Container( decoration: getBoxDecoration(e.clientId), child: InkWell( customBorder: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), onTap: () { homeController.updateSelectedProvider(e); context.go("/make-payment"); }, child: ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Theme.of( context, ).colorScheme.primary.withValues(alpha: 0.1), shape: BoxShape.circle, ), child: Image(image: AssetImage("assets/${e.image}")), ), title: Text( e.name, style: TextStyle(fontWeight: FontWeight.bold), ), subtitle: Text( e.description, style: TextStyle(fontWeight: FontWeight.normal, fontSize: 10), ), trailing: Icon( Icons.chevron_right, color: Theme.of( context, ).colorScheme.secondary.withValues(alpha: 0.7), ), ), ), ), ), ), SizedBox(height: 10), ], ); } Widget _buildFilterChips(HomeController controller) { return SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: [ _buildFilterChip('All', controller), ...controller.model.categories.map((category) { return _buildFilterChip(category.name, controller, category); }), ], ), ); } Widget _buildFilterChip( String label, HomeController controller, [ Category? category, ]) { final isSelected = _selectedFilter == label; return Padding( padding: const EdgeInsets.only(right: 8), child: FilterChip( selected: isSelected, label: Text(label), onSelected: (selected) { setState(() { _selectedFilter = label; }); if (category != null) { controller.updateSelectedCategory(category); } else { controller.updateSelectedCategory(null); } }, backgroundColor: Theme.of(context).colorScheme.surface, selectedColor: Theme.of(context).colorScheme.primary.withOpacity(0.2), checkmarkColor: Theme.of(context).colorScheme.primary, labelStyle: TextStyle( color: isSelected ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onSurface, ), ), ); } }