// ==================== EMPTY WIDGET ==================== import 'package:flutter/material.dart'; import '../../../common/theme/theme.dart'; class EmptyWidget extends StatefulWidget { final String? title; final String? message; final VoidCallback? onRefresh; final IconData? emptyIcon; final String? buttonText; final double? width; final double? height; final bool showButton; final EdgeInsets? padding; final Color? iconColor; const EmptyWidget({ super.key, this.title, this.message, this.onRefresh, this.emptyIcon, this.buttonText, this.width, this.height, this.showButton = true, this.padding, this.iconColor, }); @override State createState() => _EmptyWidgetState(); } class _EmptyWidgetState extends State with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation _fadeAnimation; late Animation _slideAnimation; @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(milliseconds: 800), vsync: this, ); _fadeAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation(parent: _animationController, curve: Curves.easeInOut), ); _slideAnimation = Tween(begin: const Offset(0.0, 0.3), end: Offset.zero).animate( CurvedAnimation( parent: _animationController, curve: Curves.easeOutCubic, ), ); _animationController.forward(); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Container( width: widget.width, height: widget.height, padding: widget.padding ?? const EdgeInsets.all(24), child: FadeTransition( opacity: _fadeAnimation, child: SlideTransition( position: _slideAnimation, child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ // Empty Illustration Stack( alignment: Alignment.center, children: [ // Background Circle Container( width: 120, height: 120, decoration: BoxDecoration( shape: BoxShape.circle, gradient: LinearGradient( colors: [ AppColor.primary.withOpacity(0.05), AppColor.secondary.withOpacity(0.05), ], ), ), ), // Icon Container Container( width: 80, height: 80, decoration: BoxDecoration( shape: BoxShape.circle, color: AppColor.surface, border: Border.all(color: AppColor.border, width: 2), boxShadow: [ BoxShadow( color: AppColor.primary.withOpacity(0.08), blurRadius: 20, offset: const Offset(0, 4), ), ], ), child: Icon( widget.emptyIcon ?? Icons.inbox_outlined, size: 40, color: widget.iconColor ?? AppColor.textLight, ), ), ], ), const SizedBox(height: 24), // Title Text( widget.title ?? 'Tidak Ada Data', style: AppStyle.xl.copyWith( fontWeight: FontWeight.bold, color: AppColor.textPrimary, ), textAlign: TextAlign.center, ), const SizedBox(height: 8), // Message Text( widget.message ?? 'Belum ada data untuk ditampilkan', style: AppStyle.md.copyWith( color: AppColor.textSecondary, height: 1.4, ), textAlign: TextAlign.center, ), // Action Button if (widget.showButton && widget.onRefresh != null) ...[ const SizedBox(height: 24), OutlinedButton.icon( onPressed: widget.onRefresh, icon: const Icon(Icons.refresh_rounded, size: 18), label: Text(widget.buttonText ?? 'Muat Ulang'), style: OutlinedButton.styleFrom( foregroundColor: AppColor.primary, side: BorderSide(color: AppColor.primary, width: 1.5), padding: const EdgeInsets.symmetric( horizontal: 20, vertical: 12, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), ), ], ], ), ), ), ); } }