import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../../l10n/l10n_x.dart'; enum EmptyStateType { noGroups, noMembers, noPayments, noActivities, noResults, error, noInternet, } class EmptyStateWidget extends StatelessWidget { final EmptyStateType type; final String? customTitle; final String? customMessage; final String? actionLabel; final VoidCallback? onActionPressed; final Widget? customIllustration; const EmptyStateWidget({ super.key, required this.type, this.customTitle, this.customMessage, this.actionLabel, this.onActionPressed, this.customIllustration, }); @override Widget build(BuildContext context) { final config = _getEmptyStateConfig(context, type); return Center( child: SingleChildScrollView( padding: EdgeInsets.all(32.w), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // Illustration or Icon customIllustration ?? TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: const Duration(milliseconds: 600), curve: Curves.easeOutBack, builder: (context, value, child) { return Transform.scale( scale: value, child: child, ); }, child: Container( width: 140.w, height: 140.h, decoration: BoxDecoration( color: config.backgroundColor, shape: BoxShape.circle, ), child: Icon( config.icon, size: 70.w, color: config.iconColor, ), ), ), SizedBox(height: 32.h), // Title TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: const Duration(milliseconds: 800), curve: Curves.easeOut, builder: (context, value, child) { return Opacity( opacity: value, child: Transform.translate( offset: Offset(0, 20 * (1 - value)), child: child, ), ); }, child: Text( customTitle ?? config.title, style: TextStyle( fontSize: 24.sp, fontWeight: FontWeight.bold, color: Colors.grey.shade800, ), textAlign: TextAlign.center, ), ), SizedBox(height: 12.h), // Message TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: const Duration(milliseconds: 1000), curve: Curves.easeOut, builder: (context, value, child) { return Opacity( opacity: value, child: Transform.translate( offset: Offset(0, 20 * (1 - value)), child: child, ), ); }, child: Text( customMessage ?? config.message, style: TextStyle( fontSize: 16.sp, color: Colors.grey.shade600, height: 1.5, ), textAlign: TextAlign.center, ), ), SizedBox(height: 32.h), // Action Button if (onActionPressed != null) TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: const Duration(milliseconds: 1200), curve: Curves.easeOut, builder: (context, value, child) { return Opacity( opacity: value, child: Transform.translate( offset: Offset(0, 20 * (1 - value)), child: child, ), ); }, child: ElevatedButton.icon( onPressed: onActionPressed, icon: Icon(config.actionIcon, size: 20.w), label: Text( actionLabel ?? config.actionLabel, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w600, ), ), style: ElevatedButton.styleFrom( backgroundColor: config.buttonColor, foregroundColor: Colors.white, padding: EdgeInsets.symmetric( horizontal: 32.w, vertical: 16.h, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.r), ), elevation: 2, ), ), ), ], ), ), ); } _EmptyStateConfig _getEmptyStateConfig(BuildContext context, EmptyStateType type) { final l = context.l10n; switch (type) { case EmptyStateType.noGroups: return _EmptyStateConfig( icon: Icons.group_add_rounded, iconColor: Colors.green.shade600, backgroundColor: Colors.green.shade50, title: l.emptyNoGroupsTitle, message: l.emptyNoGroupsMessage, actionLabel: l.emptyNoGroupsAction, actionIcon: Icons.add_circle_outline, buttonColor: Colors.green.shade600, ); case EmptyStateType.noMembers: return _EmptyStateConfig( icon: Icons.people_outline_rounded, iconColor: Colors.blue.shade600, backgroundColor: Colors.blue.shade50, title: l.emptyNoMembersTitle, message: l.emptyNoMembersMessage, actionLabel: l.emptyNoMembersAction, actionIcon: Icons.person_add, buttonColor: Colors.blue.shade600, ); case EmptyStateType.noPayments: return _EmptyStateConfig( icon: Icons.payment_rounded, iconColor: Colors.orange.shade600, backgroundColor: Colors.orange.shade50, title: l.emptyNoPaymentsTitle, message: l.emptyNoPaymentsMessage, actionLabel: l.emptyNoPaymentsAction, actionIcon: Icons.add, buttonColor: Colors.orange.shade600, ); case EmptyStateType.noActivities: return _EmptyStateConfig( icon: Icons.history_rounded, iconColor: Colors.purple.shade600, backgroundColor: Colors.purple.shade50, title: l.emptyNoActivitiesTitle, message: l.emptyNoActivitiesMessage, actionLabel: l.emptyNoActivitiesAction, actionIcon: Icons.refresh, buttonColor: Colors.purple.shade600, ); case EmptyStateType.noResults: return _EmptyStateConfig( icon: Icons.search_off_rounded, iconColor: Colors.grey.shade600, backgroundColor: Colors.grey.shade100, title: l.emptyNoResultsTitle, message: l.emptyNoResultsMessage, actionLabel: l.emptyNoResultsAction, actionIcon: Icons.clear_all, buttonColor: Colors.grey.shade600, ); case EmptyStateType.error: return _EmptyStateConfig( icon: Icons.error_outline_rounded, iconColor: Colors.red.shade600, backgroundColor: Colors.red.shade50, title: l.emptyErrorTitle, message: l.emptyErrorMessage, actionLabel: l.emptyErrorAction, actionIcon: Icons.refresh, buttonColor: Colors.red.shade600, ); case EmptyStateType.noInternet: return _EmptyStateConfig( icon: Icons.wifi_off_rounded, iconColor: Colors.red.shade600, backgroundColor: Colors.red.shade50, title: l.emptyNoInternetTitle, message: l.emptyNoInternetMessage, actionLabel: l.emptyNoInternetAction, actionIcon: Icons.refresh, buttonColor: Colors.red.shade600, ); } } } class _EmptyStateConfig { final IconData icon; final Color iconColor; final Color backgroundColor; final String title; final String message; final String actionLabel; final IconData actionIcon; final Color buttonColor; _EmptyStateConfig({ required this.icon, required this.iconColor, required this.backgroundColor, required this.title, required this.message, required this.actionLabel, required this.actionIcon, required this.buttonColor, }); } /// Compact version for smaller spaces class CompactEmptyState extends StatelessWidget { final IconData icon; final String message; final Color? color; const CompactEmptyState({ super.key, required this.icon, required this.message, this.color, }); @override Widget build(BuildContext context) { final stateColor = color ?? Colors.grey.shade600; return Padding( padding: EdgeInsets.all(24.w), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( icon, size: 48.w, color: stateColor.withOpacity(0.5), ), SizedBox(height: 12.h), Text( message, style: TextStyle( fontSize: 14.sp, color: Colors.grey.shade600, ), textAlign: TextAlign.center, ), ], ), ); } }