a863fa3b9a
Gleiche Technik wie bei settings_modal.dart/message_group.dart: reine Verschiebung per Dart part/part-of, keine Logikänderung. rooms_panel.dart schrumpft von 2555 auf 31 Zeilen (nur noch Bibliothekskopf). Verifiziert per automatisiertem Blockvergleich gegen das Original und flutter analyze. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
133 lines
3.9 KiB
Dart
133 lines
3.9 KiB
Dart
part of '../rooms_panel.dart';
|
|
|
|
class _VoiceParticipantList extends StatelessWidget {
|
|
final List<Map<String, dynamic>> 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)),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|