import 'package:flutter/material.dart'; /// A pulsing placeholder card shown while recipes are loading from the AI. class SkeletonCard extends StatefulWidget { const SkeletonCard({super.key}); @override State createState() => _SkeletonCardState(); } class _SkeletonCardState extends State with SingleTickerProviderStateMixin { late final AnimationController _ctrl; late final Animation _anim; @override void initState() { super.initState(); _ctrl = AnimationController( vsync: this, duration: const Duration(milliseconds: 900), )..repeat(reverse: true); _anim = Tween(begin: 0.25, end: 0.55).animate( CurvedAnimation(parent: _ctrl, curve: Curves.easeInOut), ); } @override void dispose() { _ctrl.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _anim, builder: (context, _) { final color = Colors.grey.withValues(alpha: _anim.value); return Card( clipBehavior: Clip.antiAlias, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container(height: 180, color: color), Padding( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _Bar(width: 220, height: 18, color: color), const SizedBox(height: 8), _Bar(width: 160, height: 14, color: color), const SizedBox(height: 12), Row( children: [ _Bar(width: 60, height: 12, color: color), const SizedBox(width: 12), _Bar(width: 60, height: 12, color: color), const SizedBox(width: 12), _Bar(width: 60, height: 12, color: color), ], ), ], ), ), ], ), ); }, ); } } class _Bar extends StatelessWidget { final double width; final double height; final Color color; const _Bar({required this.width, required this.height, required this.color}); @override Widget build(BuildContext context) => Container( width: width, height: height, decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(4), ), ); }