import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class DynamicIslandConnectionBanner extends StatefulWidget { final bool connected; final String message; final Color backgroundColor; final Duration animationDuration; const DynamicIslandConnectionBanner({ required this.connected, this.message = 'Connection unstable — retrying...', this.backgroundColor = const Color(0xFF1C1C1E), this.animationDuration = const Duration(milliseconds: 300), super.key, }); @override State createState() => _DynamicIslandConnectionBannerState(); } class _DynamicIslandConnectionBannerState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _animation; @override void initState() { super.initState(); _controller = AnimationController( duration: widget.animationDuration, vsync: this, // Initialize based on the initial connection state value: widget.connected ? 0.0 : 1.0, ); _animation = CurvedAnimation(parent: _controller, curve: Curves.easeOutBack); } @override void didUpdateWidget(DynamicIslandConnectionBanner oldWidget) { super.didUpdateWidget(oldWidget); if (widget.connected != oldWidget.connected) { if (widget.connected) { // If connected, hide the banner _controller.reverse(); } else { // If disconnected, show the banner _controller.forward(); } } } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { // Use AnimatedBuilder to only build when the animation value changes return AnimatedBuilder( animation: _animation, // If the animation is at the beginning (hidden), return an empty box // This is more efficient than building the whole widget off-screen child: _buildBannerContent(), builder: (context, child) { if (_animation.value == 0.0) { return const SizedBox.shrink(); } return Transform.translate( offset: Offset(0, (_animation.value - 1.0) * 80), // Slide from top child: Opacity( opacity: _animation.value, child: child, ), ); }, ); } Widget _buildBannerContent() { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Container( width: double.infinity, decoration: BoxDecoration( color: widget.backgroundColor, borderRadius: BorderRadius.circular(25), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.15), blurRadius: 10, offset: const Offset(0, 4), ), ], ), padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 20), child: Row( children: [ const SizedBox( width: 16, height: 16, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.white70, strokeCap: StrokeCap.round, ), ), const SizedBox(width: 12), Expanded( child: Text( widget.message, style: const TextStyle( color: Colors.white, fontSize: 14, fontWeight: FontWeight.w500, ), ), ), Container( width: 8, height: 8, decoration: BoxDecoration( color: Colors.orange, shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.orange.withOpacity(0.6), blurRadius: 4, ), ], ), ), ], ), ), ); } }