part of '../rooms_panel.dart'; // Chatlisten-Eintrag im Handy-Layout (Bernds Feedback 2026-10-07: die Handy-App // soll sich wie ein gewohnter Messenger anfühlen): großer Avatar, Name mit // Uhrzeit der letzten Nachricht, darunter die letzte Nachricht als Vorschau // und der Ungelesen-Zähler. Am PC bleibt die kompakte Discord-Liste // (_RoomItem); Voice-Kanäle behalten ihre eigene Darstellung. const _kTileAvatar = 46.0; class _MobileRoomTile extends StatelessWidget { final Room room; final bool isActive; final PyramidTheme pt; final String? myUserId; final VoidCallback onTap; final VoidCallback onLongPress; const _MobileRoomTile({ required this.room, required this.isActive, required this.pt, required this.myUserId, required this.onTap, required this.onLongPress, }); @override Widget build(BuildContext context) { final name = room.getLocalizedDisplayname(); final unread = room.notificationCount; final mention = room.highlightCount > 0; final last = room.lastEvent; final preview = _roomPreview(room, myUserId); final time = last == null ? null : chatListTime(last.originServerTs); return GestureDetector( behavior: HitTestBehavior.opaque, onTap: onTap, onLongPress: onLongPress, child: Container( color: isActive ? pt.accentSoft : Colors.transparent, padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 9), child: Row( children: [ room.isDirectChat ? _DmAvatar(room: room, pt: pt, size: _kTileAvatar) : _RoomTileAvatar(room: room, pt: pt), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Row( children: [ Expanded( child: Text( name, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( color: pt.fg, fontSize: 15, fontWeight: unread > 0 ? FontWeight.w700 : FontWeight.w600, ), ), ), if (time != null) ...[ const SizedBox(width: 8), Text( time, style: TextStyle( color: unread > 0 ? pt.accent : pt.fgDim, fontSize: 12, fontWeight: unread > 0 ? FontWeight.w600 : FontWeight.w400, ), ), ], ], ), const SizedBox(height: 3), Row( children: [ Expanded( child: Text( preview ?? '', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( color: unread > 0 ? pt.fgMuted : pt.fgDim, fontSize: 13.5, ), ), ), // Immer im Baum, damit der Zähler beim Erscheinen und // Hochzählen federnd aufploppen kann. SpringBump( value: unread, child: unread > 0 ? Padding( padding: const EdgeInsets.only(left: 8), child: _UnreadBadge( count: unread, isMention: mention, pt: pt), ) : const SizedBox.shrink(), ), ], ), ], ), ), ], ), ), ); } } /// Avatar für Räume (kein DM): Raumbild oder Symbol. Gruppen (kein /// Server-Kanal) sind rund wie Personen, Server-Kanäle abgerundet mit „#“. class _RoomTileAvatar extends ConsumerWidget { final Room room; final PyramidTheme pt; final double size; const _RoomTileAvatar( {required this.room, required this.pt, this.size = _kTileAvatar}); @override Widget build(BuildContext context, WidgetRef ref) { final client = ref.watch(matrixClientProvider).valueOrNull; final isChannel = ref.watch(spaceChannelIdsProvider).contains(room.id); final radius = BorderRadius.circular(isChannel ? size * 0.3 : size / 2); final fallback = Container( width: size, height: size, decoration: BoxDecoration( color: isChannel ? pt.bg3 : pt.accentSoft, borderRadius: radius, ), child: Icon( isChannel ? (room.encrypted ? Icons.lock_outline_rounded : Icons.tag_rounded) : Icons.groups_rounded, size: size * 0.5, color: isChannel ? pt.fgMuted : pt.accent, ), ); if (client == null || room.avatar == null) return fallback; return MxcAvatar( mxcUri: room.avatar, client: client, size: size, borderRadius: radius, placeholder: (_) => fallback, ); } } /// Vorschau der letzten Nachricht: gleiche Texte wie in Benachrichtigungen /// (Medien als „📷 Foto“ usw., Antwort-Zitat entfernt), in Gruppen mit /// Absender, eigene Nachrichten mit „Du:“. String? _roomPreview(Room room, String? myUserId) { final e = room.lastEvent; if (e == null) return null; if (e.type == EventTypes.Encrypted) return '🔒 Verschlüsselte Nachricht'; final body = notificationBody(e); if (body == null) return null; if (e.senderId == myUserId) return 'Du: $body'; if (room.isDirectChat) return body; return '${e.senderFromMemoryOrFallback.calcDisplayname()}: $body'; }