import 'package:fluent_ui/fluent_ui.dart'; class TypingIndicator extends StatefulWidget { const TypingIndicator({super.key}); @override State createState() => _TypingIndicatorState(); } class _TypingIndicatorState extends State with TickerProviderStateMixin { late List _controllers; late List> _animations; @override void initState() { super.initState(); _controllers = List.generate( 3, (index) => AnimationController( duration: const Duration(milliseconds: 600), vsync: this, ), ); _animations = _controllers.map((controller) { return Tween( begin: 0, end: -8, ).animate(CurvedAnimation(parent: controller, curve: Curves.easeInOut)); }).toList(); for (int i = 0; i < _controllers.length; i++) { Future.delayed(Duration(milliseconds: i * 150), () { if (mounted) { _controllers[i].repeat(reverse: true); } }); } } @override void dispose() { for (var controller in _controllers) { controller.dispose(); } super.dispose(); } @override Widget build(BuildContext context) { final theme = FluentTheme.of(context); return Padding( padding: const EdgeInsets.only(bottom: 16), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: 36, height: 36, decoration: BoxDecoration( color: theme.accentColor, borderRadius: BorderRadius.circular(8), ), child: const Icon(FluentIcons.robot, color: Colors.white, size: 18), ), const SizedBox(width: 12), Card( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), child: Row( mainAxisSize: MainAxisSize.min, children: List.generate(3, (index) { return AnimatedBuilder( animation: _animations[index], builder: (context, child) { return Transform.translate( offset: Offset(0, _animations[index].value), child: child, ); }, child: Container( margin: EdgeInsets.only(right: index < 2 ? 6 : 0), width: 8, height: 8, decoration: BoxDecoration( color: theme.accentColor, shape: BoxShape.circle, ), ), ); }), ), ), ], ), ); } }