import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:lucide_icons/lucide_icons.dart'; import '../../core/core.dart'; class VoiceModeOverlay extends StatefulWidget { final CharacterModel character; final VoidCallback onClose; const VoiceModeOverlay({ super.key, required this.character, required this.onClose, }); @override State createState() => _VoiceModeOverlayState(); } class _VoiceModeOverlayState extends State with SingleTickerProviderStateMixin { bool _isMicMuted = false; bool _isSpeakerOn = true; late AnimationController _controller; String get _avatarUrl => CharacterRepository.getAvatarUrl(widget.character.avatarPath); @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: const Duration(seconds: 2)) ..repeat(reverse: true); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Positioned.fill( child: Material( type: MaterialType.transparency, child: Container( color: const Color(0xFF2E1065), child: Stack( children: [ // Background Image with Blur Positioned.fill( child: Image.network( _avatarUrl, fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) { return Container(color: const Color(0xFF2E1065)); }, ), ), Positioned.fill( child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20), child: Container( color: const Color(0xFF2E1065).withOpacity(0.8), ), ), ), // Main Content SafeArea( child: Column( children: [ // Header Padding( padding: const EdgeInsets.all(16.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( onPressed: widget.onClose, icon: const Icon(LucideIcons.chevronLeft, color: Colors.white70), style: IconButton.styleFrom( backgroundColor: Colors.white.withOpacity(0.1), ), ), ], ), ), const Spacer(), // Character Info & Status Column( children: [ Text( widget.character.name, style: const TextStyle( color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Text( _isMicMuted ? 'Mic Muted' : 'Listening...', style: TextStyle( color: Colors.white.withOpacity(0.6), fontSize: 12, letterSpacing: 2, fontWeight: FontWeight.w500, ), ), ], ), const SizedBox(height: 48), // Avatar pulsing animation SizedBox( width: 200, height: 200, child: Stack( alignment: Alignment.center, children: [ if (!_isMicMuted) AnimatedBuilder( animation: _controller, builder: (context, child) { return Container( width: 200 * (0.8 + 0.2 * _controller.value), height: 200 * (0.8 + 0.2 * _controller.value), decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all( color: Colors.white.withOpacity(0.2 * (1 - _controller.value)), width: 1, ), ), ); }, ), Container( width: 160, height: 160, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all(color: Colors.white.withOpacity(0.3), width: 2), boxShadow: [ BoxShadow( color: const Color(0xFFC084FC).withOpacity(0.5), blurRadius: 30, spreadRadius: 0 ) ], image: DecorationImage( image: NetworkImage(_avatarUrl), fit: BoxFit.cover, ), ), ), ], ), ), const Spacer(), // Waveform (Simulated) SizedBox( height: 32, child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: List.generate(5, (index) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 2.0), child: AnimatedBuilder( animation: _controller, builder: (context, child) { return Container( width: 4, height: _isMicMuted ? 4 : 10 + (20 * (index % 2 == 0 ? _controller.value : 1 - _controller.value)), decoration: BoxDecoration( color: Colors.white.withOpacity(_isMicMuted ? 0.2 : 0.8), borderRadius: BorderRadius.circular(2), ), ); } ), ); }), ), ), const SizedBox(height: 48), // Bottom Controls Padding( padding: const EdgeInsets.symmetric(horizontal: 48.0, vertical: 32.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // Mic Toggle IconButton( onPressed: () => setState(() => _isMicMuted = !_isMicMuted), icon: Icon(_isMicMuted ? LucideIcons.micOff : LucideIcons.mic), iconSize: 24, style: IconButton.styleFrom( backgroundColor: _isMicMuted ? Colors.white : Colors.white.withOpacity(0.1), foregroundColor: _isMicMuted ? const Color(0xFF2E1065) : Colors.white, padding: const EdgeInsets.all(16), minimumSize: const Size(64, 64), ), ), // End Call IconButton( onPressed: widget.onClose, icon: const Icon(LucideIcons.phoneOff), iconSize: 32, style: IconButton.styleFrom( backgroundColor: Colors.red, foregroundColor: Colors.white, padding: const EdgeInsets.all(20), minimumSize: const Size(80, 80), ), ), // Speaker Toggle IconButton( onPressed: () => setState(() => _isSpeakerOn = !_isSpeakerOn), icon: Icon( _isSpeakerOn ? LucideIcons.volume2 : LucideIcons.volumeX ), iconSize: 24, style: IconButton.styleFrom( backgroundColor: _isSpeakerOn ? Colors.white.withOpacity(0.1) : Colors.white.withOpacity(0.05), foregroundColor: _isSpeakerOn ? Colors.white : Colors.white.withOpacity(0.5), padding: const EdgeInsets.all(16), minimumSize: const Size(64, 64), ), ), ], ), ), ], ), ), ], ), ), ), ); } }