import 'package:flutter/material.dart'; import '../providers/voice_provider.dart'; /// Animated mic button that reflects the current [VoiceMode]. /// /// - idle: muted background, mic_none icon /// - recording: red with pulsing shadow ring /// - transcribing: indigo with spinner /// - playing: indigo with volume_up icon class VoiceMicButton extends StatefulWidget { final VoiceMode mode; final bool voiceModeActive; final VoidCallback? onTap; const VoiceMicButton({ super.key, required this.mode, required this.voiceModeActive, this.onTap, }); @override State createState() => _VoiceMicButtonState(); } class _VoiceMicButtonState extends State with SingleTickerProviderStateMixin { late AnimationController _pulseController; late Animation _pulseAnimation; @override void initState() { super.initState(); _pulseController = AnimationController( vsync: this, duration: const Duration(milliseconds: 900), )..repeat(reverse: true); _pulseAnimation = Tween(begin: 1.0, end: 1.25).animate( CurvedAnimation(parent: _pulseController, curve: Curves.easeInOut), ); } @override void dispose() { _pulseController.dispose(); super.dispose(); } Color _bgColor(BuildContext context) { final cs = Theme.of(context).colorScheme; return switch (widget.mode) { VoiceMode.recording => const Color(0xFFEF4444), VoiceMode.transcribing || VoiceMode.playing => cs.primary, VoiceMode.idle => cs.surfaceContainerHighest, }; } Widget _icon(BuildContext context) { final cs = Theme.of(context).colorScheme; final iconColor = widget.mode == VoiceMode.idle ? cs.onSurfaceVariant : Colors.white; return switch (widget.mode) { VoiceMode.transcribing => SizedBox( width: 18, height: 18, child: CircularProgressIndicator( strokeWidth: 2, color: iconColor, ), ), VoiceMode.playing => Icon(Icons.volume_up, color: iconColor, size: 20), _ => Icon(Icons.mic, color: iconColor, size: 20), }; } @override Widget build(BuildContext context) { final isRecording = widget.mode == VoiceMode.recording; final button = Material( color: _bgColor(context), shape: const CircleBorder(), child: InkWell( customBorder: const CircleBorder(), onTap: widget.onTap, child: SizedBox( width: 40, height: 40, child: Center(child: _icon(context)), ), ), ); if (!isRecording) return button; return AnimatedBuilder( animation: _pulseAnimation, builder: (_, child) => Container( decoration: BoxDecoration( shape: BoxShape.circle, boxShadow: [ BoxShadow( color: const Color(0xFFEF4444).withValues(alpha: 0.35), blurRadius: 8 * _pulseAnimation.value, spreadRadius: 2 * _pulseAnimation.value, ), ], ), child: child, ), child: button, ); } }