import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; /// Skeleton loader widget for displaying loading states class SkeletonLoader extends StatefulWidget { final double? width; final double? height; final BorderRadius? borderRadius; final EdgeInsets? margin; const SkeletonLoader({ super.key, this.width, this.height, this.borderRadius, this.margin, }); @override State createState() => _SkeletonLoaderState(); } class _SkeletonLoaderState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _animation; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 1500), )..repeat(reverse: true); _animation = Tween(begin: 0.3, end: 1.0).animate( CurvedAnimation(parent: _controller, curve: Curves.easeInOut), ); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation, builder: (context, child) { return Container( width: widget.width, height: widget.height, margin: widget.margin, decoration: BoxDecoration( color: Colors.grey.shade300.withOpacity(_animation.value), borderRadius: widget.borderRadius ?? BorderRadius.circular(8.r), ), ); }, ); } } /// Skeleton loader for card-based layouts class SkeletonCard extends StatelessWidget { const SkeletonCard({super.key}); @override Widget build(BuildContext context) { return Card( elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16.r), ), child: Padding( padding: EdgeInsets.all(16.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ SkeletonLoader( width: 120.w, height: 24.h, borderRadius: BorderRadius.circular(8.r), ), SkeletonLoader( width: 80.w, height: 28.h, borderRadius: BorderRadius.circular(16.r), ), ], ), SizedBox(height: 16.h), Row( children: [ Expanded( child: SkeletonLoader( height: 60.h, borderRadius: BorderRadius.circular(12.r), ), ), SizedBox(width: 8.w), Expanded( child: SkeletonLoader( height: 60.h, borderRadius: BorderRadius.circular(12.r), ), ), ], ), SizedBox(height: 12.h), Row( children: [ Expanded( child: SkeletonLoader( height: 60.h, borderRadius: BorderRadius.circular(12.r), ), ), SizedBox(width: 8.w), Expanded( child: SkeletonLoader( height: 60.h, borderRadius: BorderRadius.circular(12.r), ), ), ], ), SizedBox(height: 16.h), SkeletonLoader( width: double.infinity, height: 48.h, borderRadius: BorderRadius.circular(12.r), ), ], ), ), ); } } /// Skeleton loader for stats cards class SkeletonStatsCard extends StatelessWidget { const SkeletonStatsCard({super.key}); @override Widget build(BuildContext context) { return Card( elevation: 2, child: Padding( padding: EdgeInsets.all(16.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ SkeletonLoader( width: 32.w, height: 32.h, borderRadius: BorderRadius.circular(8.r), ), SkeletonLoader( width: 24.w, height: 24.h, borderRadius: BorderRadius.circular(6.r), ), ], ), SizedBox(height: 12.h), SkeletonLoader( width: 60.w, height: 28.h, borderRadius: BorderRadius.circular(8.r), ), SizedBox(height: 4.h), SkeletonLoader( width: 100.w, height: 16.h, borderRadius: BorderRadius.circular(8.r), ), ], ), ), ); } } /// Skeleton loader for list items class SkeletonListItem extends StatelessWidget { const SkeletonListItem({super.key}); @override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.only(bottom: 12.h), child: Row( children: [ SkeletonLoader( width: 48.w, height: 48.h, borderRadius: BorderRadius.circular(12.r), ), SizedBox(width: 16.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SkeletonLoader( width: double.infinity, height: 16.h, borderRadius: BorderRadius.circular(8.r), ), SizedBox(height: 8.h), SkeletonLoader( width: 150.w, height: 14.h, borderRadius: BorderRadius.circular(8.r), ), ], ), ), SizedBox(width: 16.w), SkeletonLoader( width: 60.w, height: 14.h, borderRadius: BorderRadius.circular(8.r), ), ], ), ); } } /// Skeleton loader for dashboard layout class SkeletonDashboard extends StatelessWidget { const SkeletonDashboard({super.key}); @override Widget build(BuildContext context) { return SingleChildScrollView( padding: EdgeInsets.all(16.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Welcome section skeleton SkeletonLoader( width: 200.w, height: 24.h, borderRadius: BorderRadius.circular(8.r), ), SizedBox(height: 8.h), SkeletonLoader( width: double.infinity, height: 16.h, borderRadius: BorderRadius.circular(8.r), ), SizedBox(height: 24.h), // Stats grid skeleton Row( children: [ Expanded(child: SkeletonStatsCard()), SizedBox(width: 12.w), Expanded(child: SkeletonStatsCard()), ], ), SizedBox(height: 12.h), Row( children: [ Expanded(child: SkeletonStatsCard()), SizedBox(width: 12.w), Expanded(child: SkeletonStatsCard()), ], ), SizedBox(height: 24.h), // Quick actions section Card( child: Padding( padding: EdgeInsets.all(20.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SkeletonLoader( width: 120.w, height: 20.h, borderRadius: BorderRadius.circular(8.r), ), SizedBox(height: 16.h), ...List.generate( 4, (index) => Padding( padding: EdgeInsets.only(bottom: 8.h), child: SkeletonLoader( width: double.infinity, height: 48.h, borderRadius: BorderRadius.circular(12.r), ), ), ), ], ), ), ), SizedBox(height: 24.h), // Recent activities section Card( child: Padding( padding: EdgeInsets.all(20.w), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SkeletonLoader( width: 150.w, height: 20.h, borderRadius: BorderRadius.circular(8.r), ), SizedBox(height: 16.h), ...List.generate(4, (index) => const SkeletonListItem()), ], ), ), ), ], ), ); } }