part of '../voice_channel.dart'; class _BigAvatar extends StatelessWidget { final _ParticipantData data; final PyramidTheme pt; const _BigAvatar({required this.data, required this.pt}); @override Widget build(BuildContext context) { return Center( child: Container( width: 100, height: 100, decoration: BoxDecoration( gradient: LinearGradient(colors: [data.avatarColor, data.avatarColor.withAlpha(150)], begin: Alignment.topLeft, end: Alignment.bottomRight), shape: BoxShape.circle, ), child: Center(child: Text(data.name.isNotEmpty ? data.name[0].toUpperCase() : '?', style: const TextStyle(color: Colors.white, fontSize: 40, fontWeight: FontWeight.bold))), ), ); } } class _SmallAvatar extends StatelessWidget { final _ParticipantData data; final PyramidTheme pt; const _SmallAvatar({required this.data, required this.pt}); @override Widget build(BuildContext context) { return Center( child: Container( width: 44, height: 44, decoration: BoxDecoration( gradient: LinearGradient(colors: [data.avatarColor, data.avatarColor.withAlpha(150)], begin: Alignment.topLeft, end: Alignment.bottomRight), shape: BoxShape.circle, ), child: Center(child: Text(data.name.isNotEmpty ? data.name[0].toUpperCase() : '?', style: const TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold))), ), ); } } class _CallControls extends StatelessWidget { final bool isMuted; final bool isDeafened; final bool isCameraOff; final bool isScreenSharing; final VoidCallback onToggleMic; final VoidCallback onToggleDeafen; final VoidCallback onToggleCam; final VoidCallback onToggleScreen; final VoidCallback onHangUp; final PyramidTheme pt; const _CallControls({ required this.isMuted, required this.isDeafened, required this.isCameraOff, required this.isScreenSharing, required this.onToggleMic, required this.onToggleDeafen, required this.onToggleCam, required this.onToggleScreen, required this.onHangUp, required this.pt, }); @override Widget build(BuildContext context) { return SafeArea( top: false, child: Container( padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 20), decoration: BoxDecoration(color: pt.bg1, border: Border(top: BorderSide(color: pt.border))), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ _VoiceCtrlBtn(icon: isMuted ? Icons.mic_off_rounded : Icons.mic_rounded, danger: isMuted, pt: pt, onTap: onToggleMic), const SizedBox(width: 16), _VoiceCtrlBtn(icon: isDeafened ? Icons.headset_off_rounded : Icons.headphones_rounded, danger: isDeafened, pt: pt, onTap: onToggleDeafen), const SizedBox(width: 16), _VoiceCtrlBtn(icon: isCameraOff ? Icons.videocam_off_rounded : Icons.videocam_rounded, active: !isCameraOff, pt: pt, onTap: onToggleCam), const SizedBox(width: 16), _VoiceCtrlBtn(icon: Icons.screen_share_rounded, active: isScreenSharing, pt: pt, onTap: onToggleScreen), const SizedBox(width: 24), Container(width: 1, height: 32, color: pt.border), const SizedBox(width: 24), _VoiceCtrlBtn(icon: Icons.call_end_rounded, isDanger: true, pt: pt, onTap: onHangUp), ], ), ), ); } } class _NoCall extends StatelessWidget { final PyramidTheme pt; final WidgetRef ref; const _NoCall({required this.pt, required this.ref}); @override Widget build(BuildContext context) { return Container( color: pt.bg1, child: Column( children: [ Container( height: 52, padding: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration(border: Border(bottom: BorderSide(color: pt.border))), child: Row( children: [ PyrIconBtn( icon: const Icon(Icons.menu_rounded), tooltip: 'Toggle sidebar', onPressed: () => ref.read(railCollapsedProvider.notifier).update((s) => !s), ), const SizedBox(width: 8), Icon(Icons.headphones_rounded, size: 16, color: pt.fgMuted), const SizedBox(width: 8), Text('No active call', style: TextStyle(color: pt.fg, fontSize: 15, fontWeight: FontWeight.w600)), ], ), ), Expanded( child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text('𐃏', style: TextStyle(fontSize: 48, color: pt.fgDim.withAlpha(100))), const SizedBox(height: 12), Text('Join a voice room to start a call', style: TextStyle(color: pt.fgMuted, fontSize: 14)), ], ), ), ), ], ), ); } } class _FullscreenVideoPage extends StatelessWidget { final _ParticipantData data; const _FullscreenVideoPage({required this.data}); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, body: Stack(children: [ Positioned.fill( child: data.videoWidget != null ? _MirrorWrapper( isLocal: data.id == 'local' || (data.originalParticipant is LocalParticipant), isScreenShare: data.isScreenShare, child: data.videoWidget!, ) : _BigAvatar(data: data, pt: PyramidTheme.of(context)), ), Positioned( top: 0, right: 0, child: SafeArea( child: IconButton( icon: const Icon(Icons.fullscreen_exit_rounded, color: Colors.white, size: 28), onPressed: () => Navigator.of(context).pop(), ), ), ), ]), ); } }