import 'package:flutter/material.dart'; class DestinationSkeletonList extends StatefulWidget { const DestinationSkeletonList({super.key}); @override State createState() => _DestinationSkeletonListState(); } class _DestinationSkeletonListState extends State with SingleTickerProviderStateMixin { late final AnimationController _controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 1200), )..repeat(); @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Column( children: List.generate( 2, (index) => AnimatedBuilder( animation: _controller, builder: (context, child) { return Container( height: 286, margin: const EdgeInsets.only(bottom: 20), decoration: BoxDecoration( borderRadius: BorderRadius.circular(28), gradient: LinearGradient( begin: Alignment(-1 + (_controller.value * 2), -0.6), end: Alignment(0.2 + (_controller.value * 2), 0.8), colors: const [ Color(0xFFE6EFEA), Color(0xFFF8FCFA), Color(0xFFE6EFEA), ], ), boxShadow: [ BoxShadow( color: const Color(0xFF0F172A).withValues(alpha: 0.06), blurRadius: 24, offset: const Offset(0, 14), ), ], ), ); }, ), ), ); } } class DestinationStateMessage extends StatelessWidget { const DestinationStateMessage({ super.key, required this.icon, required this.title, required this.message, this.actionLabel, this.onAction, }); final IconData icon; final String title; final String message; final String? actionLabel; final VoidCallback? onAction; @override Widget build(BuildContext context) { final colors = Theme.of(context).colorScheme; return Container( width: double.infinity, padding: const EdgeInsets.all(22), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(24), border: Border.all(color: colors.outlineVariant), ), child: Column( children: [ Icon(icon, color: colors.primary, size: 42), const SizedBox(height: 12), Text( title, textAlign: TextAlign.center, style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w900, ), ), const SizedBox(height: 8), Text( message, textAlign: TextAlign.center, style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: colors.onSurfaceVariant, height: 1.45, ), ), if (actionLabel != null && onAction != null) ...[ const SizedBox(height: 16), FilledButton.icon( onPressed: onAction, icon: const Icon(Icons.refresh_rounded), label: Text(actionLabel!), ), ], ], ), ); } }