part of '../rooms_panel.dart'; class _VoiceParticipantList extends StatelessWidget { final List> participants; final Client? client; final PyramidTheme pt; const _VoiceParticipantList( {required this.participants, required this.client, required this.pt}); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: participants.map((p) { final avatarUrl = p['avatarUrl'] as String?; final name = (p['displayName'] as String? ?? '?'); final letter = name.isNotEmpty ? name[0].toUpperCase() : '?'; return Padding( padding: const EdgeInsets.only(top: 3), child: Row( children: [ SizedBox( width: 16, height: 16, child: client != null && avatarUrl != null ? MxcAvatar( mxcUri: Uri.tryParse(avatarUrl), client: client!, size: 16, borderRadius: BorderRadius.circular(8), placeholder: (_) => _Initials(letter: letter, pt: pt, size: 16), ) : _Initials(letter: letter, pt: pt, size: 16), ), const SizedBox(width: 6), Expanded( child: Text( name, style: TextStyle( color: const Color(0xFF57F287).withAlpha(200), fontSize: 12, fontWeight: FontWeight.w500, ), overflow: TextOverflow.ellipsis, ), ), Icon(Icons.mic_rounded, size: 11, color: const Color(0xFF57F287).withAlpha(140)), ], ), ); }).toList(), ); } } class _Initials extends StatelessWidget { final String letter; final PyramidTheme pt; final double size; const _Initials({required this.letter, required this.pt, this.size = 18}); @override Widget build(BuildContext context) { return Container( width: size, height: size, decoration: BoxDecoration( color: pt.bg3, borderRadius: BorderRadius.circular(size / 2), ), child: Center( child: Text(letter, style: TextStyle( color: pt.fg, fontSize: size * 0.5, fontWeight: FontWeight.w700)), ), ); } } class _VoiceBarBtn extends StatefulWidget { final IconData icon; final bool active; final Color activeColor; final Color inactiveColor; final PyramidTheme pt; final VoidCallback onTap; const _VoiceBarBtn({ required this.icon, required this.active, required this.activeColor, required this.inactiveColor, required this.pt, required this.onTap, }); @override State<_VoiceBarBtn> createState() => _VoiceBarBtnState(); } class _VoiceBarBtnState extends State<_VoiceBarBtn> { bool _hovered = false; @override Widget build(BuildContext context) { final pt = widget.pt; final color = widget.active ? widget.activeColor : widget.inactiveColor; return MouseRegion( cursor: SystemMouseCursors.click, onEnter: (_) => setState(() => _hovered = true), onExit: (_) => setState(() => _hovered = false), child: GestureDetector( onTap: widget.onTap, child: AnimatedContainer( duration: const Duration(milliseconds: 120), width: 28, height: 28, decoration: BoxDecoration( color: _hovered ? pt.bg3 : Colors.transparent, borderRadius: BorderRadius.circular(6), ), child: Center(child: Icon(widget.icon, size: 16, color: color)), ), ), ); } }