From f9979e4f328db5b35d9c77850c4537cbb497c75a Mon Sep 17 00:00:00 2001 From: Bernd Steckmeister Date: Fri, 3 Jul 2026 14:37:48 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20beim=20Gott-Datei-Split=20verlorene=20Er?= =?UTF-8?q?kl=C3=A4rkommentare=20wiederhergestellt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Qualitäts-Review-Befund (a): Alle 6 part/part-of-Aufteilungen hatten Code vollständig übernommen (Zeilen-Multiset-Vergleich Original vs. heutiger Stand: keine Code-Zeile verloren, keine hinzugefügt), ABER erklärende Kommentare über den Klassen gingen verloren (24 Blöcke, u. a. die HTML-Subset-Doku über _MatrixHtmlText, die Selbst-Aussperr-Warnung über updatePowerLevelsSafely, TURN-Verbrauchskarte, PDF-Cache/Viewer-Doku). Alle an den richtigen Klassen wiederhergestellt; reine Trennlinien und ALL-CAPS-Abschnittslabels bewusst nicht (Gott-Datei-Navigation, durch die neuen Dateinamen ersetzt). Co-Authored-By: Claude Fable 5 --- .../chat/document/document_viewer_archive.dart | 3 +++ lib/features/chat/document/document_viewer_pdf.dart | 11 +++++++++++ lib/features/chat/message/message_group_core.dart | 5 +++++ lib/features/chat/message/message_media.dart | 7 +++++++ lib/features/chat/message/message_shared.dart | 5 +++++ lib/features/chat/message/message_text.dart | 12 ++++++++++++ lib/features/chat/view/chat_connection.dart | 2 ++ lib/features/chat/view/chat_header.dart | 3 +++ lib/features/chat/view/chat_misc.dart | 1 + lib/features/rooms/panel/rooms_header.dart | 2 ++ lib/features/spaces/admin/space_admin_core.dart | 6 ++++++ lib/widgets/settings/settings_encryption.dart | 1 + lib/widgets/settings/settings_voice.dart | 4 ++++ 13 files changed, 62 insertions(+) diff --git a/lib/features/chat/document/document_viewer_archive.dart b/lib/features/chat/document/document_viewer_archive.dart index 426e2e4..6df53ee 100644 --- a/lib/features/chat/document/document_viewer_archive.dart +++ b/lib/features/chat/document/document_viewer_archive.dart @@ -112,6 +112,7 @@ class _ArchiveEntry { final bool isDir; const _ArchiveEntry({required this.name, required this.size, required this.isDir}); } +// Extracts the JPEG thumbnail stored in PSD Image Resource 1036. Uint8List? _extractPsdThumbnail(Uint8List bytes) { try { if (bytes.length < 34) return null; @@ -220,6 +221,8 @@ class _PsdThumbViewer extends StatelessWidget { ); } } +// ZIP-preview viewer (Sketch, XD). +// These formats are ZIP archives that embed a preview PNG. class _ZipPreviewViewer extends StatefulWidget { final Uint8List bytes; final String filename; diff --git a/lib/features/chat/document/document_viewer_pdf.dart b/lib/features/chat/document/document_viewer_pdf.dart index b943bfb..be3155e 100644 --- a/lib/features/chat/document/document_viewer_pdf.dart +++ b/lib/features/chat/document/document_viewer_pdf.dart @@ -1,5 +1,9 @@ part of '../document_viewer.dart'; +// Static render cache. +// Survives widget dispose/recreate (e.g. scroll in chat list). +// Key: filename + file-size-bytes + page + render-dimensions. +// Evicts the oldest entry (FIFO) when the limit is reached. class _RenderCache { static const _max = 80; static final _data = {}; @@ -37,6 +41,10 @@ Future _saveBytes(BuildContext context, Uint8List bytes, String filename) } } } +// Inline chat preview. +// Used by _DocPreviewContent in message_group.dart. +// Shows the first page of a PDF as an image with page navigation arrows. +// Tap → opens the full DocumentViewer overlay. class PdfInlinePreview extends StatefulWidget { final Uint8List bytes; final String filename; @@ -454,6 +462,9 @@ class _PdfFullViewerState extends State<_PdfFullViewer> { ); } } +// Immersive fullscreen PDF viewer. +// Launched from the enlarged preview. Per-page high-res render, pan via drag, +// zoom via +/− buttons (20%/click) and Ctrl+wheel, page nav via wheel/arrows. class _PdfFullscreenViewer extends StatefulWidget { final Uint8List bytes; final String filename; diff --git a/lib/features/chat/message/message_group_core.dart b/lib/features/chat/message/message_group_core.dart index d958283..cdfb6c6 100644 --- a/lib/features/chat/message/message_group_core.dart +++ b/lib/features/chat/message/message_group_core.dart @@ -6,6 +6,7 @@ String _formatMessageTime(DateTime t) { return '$h:$m'; } +// Wraps a group of consecutive messages from the same sender class MessageGroup extends StatefulWidget { final List events; final String currentUserId; @@ -304,6 +305,8 @@ class _MessageGroupState extends State { } } +// Shown under a message whose send failed (e.g. offline) — keeps the message +// visible with retry / delete instead of letting it silently disappear. class _SendFailedRow extends StatelessWidget { final Event event; final PyramidTheme pt; @@ -346,6 +349,7 @@ class _SendFailedRow extends StatelessWidget { ); } +// Single message (first in group) with full avatar + name shown class _MessageBody extends StatelessWidget { final Event event; final PyramidTheme pt; @@ -374,6 +378,7 @@ class _MessageBody extends StatelessWidget { } } +// Continuation message — no avatar, just indented text with timestamp on hover class _ContinuationMessage extends StatefulWidget { final Event event; final PyramidTheme pt; diff --git a/lib/features/chat/message/message_media.dart b/lib/features/chat/message/message_media.dart index 6ef71ad..9cdd8bb 100644 --- a/lib/features/chat/message/message_media.dart +++ b/lib/features/chat/message/message_media.dart @@ -155,6 +155,7 @@ Size? _reservedImageSize(Event event, {required double maxW, required double max return Size(w * scale, h * scale); } +// Downloads media bytes then hands off to PyramidAudioPlayer / PyramidVideoPlayer class _AudioContent extends ConsumerStatefulWidget { final Event event; final PyramidTheme pt; @@ -433,6 +434,7 @@ class _MediaContentState extends ConsumerState<_MediaContent> { _mediaFallback(pt, error, widget.event.body); } +// Downloads bytes for a PDF/SVG file and shows PdfInlinePreview or SvgImage. class _DocPreviewContent extends ConsumerStatefulWidget { final Event event; final PyramidTheme pt; @@ -572,6 +574,8 @@ class _DocPreviewContentState extends ConsumerState<_DocPreviewContent> { } } +// Inline card for proprietary formats — shows immediately from event metadata, +// downloads lazily only when the user taps or hits the download button. class _ProprietaryInlineCard extends ConsumerStatefulWidget { final Event event; final PyramidTheme pt; @@ -953,6 +957,9 @@ String _classifyMediaError(Object e) { return 'Download fehlgeschlagen'; } +// Thin wrapper over the shared MediaCache so document previews share the same +// LRU byte budget as chat images (keeps the last-viewed media instantly +// available, evicts the oldest). class _DocBytesCache { static Uint8List? get(String eventId) => MediaCache.instance.get(eventId); static void put(String eventId, Uint8List bytes) => diff --git a/lib/features/chat/message/message_shared.dart b/lib/features/chat/message/message_shared.dart index af54f72..535ed44 100644 --- a/lib/features/chat/message/message_shared.dart +++ b/lib/features/chat/message/message_shared.dart @@ -89,6 +89,8 @@ class _InitialBox extends StatelessWidget { } } +// Inline "Neue Nachrichten" divider rendered inside a MessageGroup when the +// fullyRead event is in the middle of the group (same sender, <5 min window). class _InlineUnreadDivider extends StatelessWidget { final PyramidTheme pt; const _InlineUnreadDivider({required this.pt}); @@ -114,6 +116,7 @@ class _InlineUnreadDivider extends StatelessWidget { } } +// Date divider between message groups class DateDivider extends StatelessWidget { final DateTime date; @@ -183,6 +186,8 @@ class _MessageStatus extends StatelessWidget { } } +// Read receipt: a ✓✓ shown at the partner's last-read message (any sender), +// so it moves next to their own message when they reply. class _ReadMarker extends StatelessWidget { final PyramidTheme pt; const _ReadMarker({required this.pt}); diff --git a/lib/features/chat/message/message_text.dart b/lib/features/chat/message/message_text.dart index 3c4608b..9481d5d 100644 --- a/lib/features/chat/message/message_text.dart +++ b/lib/features/chat/message/message_text.dart @@ -186,6 +186,18 @@ class _MessageContent extends StatelessWidget { } } +// Handles the subset of HTML that Matrix clients emit in formatted_body: +// / → bold +// / → italic +// / → strikethrough +// → underline +// → monospace, slightly different background +// → tappable link (url_launcher) +//
→ newline +// HTML entities → decoded +// Anything else → text content preserved, tags stripped +// +// Note:
 and 
are simplified (rendered as indented code/text). class _MatrixHtmlText extends StatelessWidget { final String html; final TextStyle baseStyle; diff --git a/lib/features/chat/view/chat_connection.dart b/lib/features/chat/view/chat_connection.dart index 80bd909..37f89d4 100644 --- a/lib/features/chat/view/chat_connection.dart +++ b/lib/features/chat/view/chat_connection.dart @@ -1,5 +1,7 @@ part of '../chat_view.dart'; +// Shows a slim banner when the client loses its connection to the homeserver. +// Debounced so brief transient sync errors don't flicker a banner. class _ConnectionBanner extends ConsumerStatefulWidget { const _ConnectionBanner(); @override diff --git a/lib/features/chat/view/chat_header.dart b/lib/features/chat/view/chat_header.dart index 0acab78..150ade7 100644 --- a/lib/features/chat/view/chat_header.dart +++ b/lib/features/chat/view/chat_header.dart @@ -182,6 +182,9 @@ class _ChatHeader extends ConsumerWidget { } } +/// DM-Header, der sich per Klick aufklappt: Das Banner blendet als Hintergrund +/// ein, Avatar und Name skalieren mit, Handle + Bio erscheinen darunter +/// (Design nach Nutzer-Mockup, Twitter/Discord-artig). class _DmExpandingHeader extends ConsumerStatefulWidget { final Room room; final String roomId; diff --git a/lib/features/chat/view/chat_misc.dart b/lib/features/chat/view/chat_misc.dart index a758426..4f10baf 100644 --- a/lib/features/chat/view/chat_misc.dart +++ b/lib/features/chat/view/chat_misc.dart @@ -99,6 +99,7 @@ class _DragOverlayState extends State<_DragOverlay> } } +// Placeholder shown when no room is selected class NoChatSelected extends StatelessWidget { const NoChatSelected({super.key}); diff --git a/lib/features/rooms/panel/rooms_header.dart b/lib/features/rooms/panel/rooms_header.dart index f9022a1..0a7ef28 100644 --- a/lib/features/rooms/panel/rooms_header.dart +++ b/lib/features/rooms/panel/rooms_header.dart @@ -341,6 +341,8 @@ class _MenuRow extends StatelessWidget { ]); } +/// Glocke im Header: Popup mit allen Räumen, die ungelesene Nachrichten oder +/// Mentions haben. Tippen öffnet den jeweiligen Raum. class _NotificationsButton extends ConsumerWidget { final PyramidTheme pt; final bool hasBanner; diff --git a/lib/features/spaces/admin/space_admin_core.dart b/lib/features/spaces/admin/space_admin_core.dart index 55d2917..534af23 100644 --- a/lib/features/spaces/admin/space_admin_core.dart +++ b/lib/features/spaces/admin/space_admin_core.dart @@ -2,6 +2,11 @@ part of '../space_admin_dialog.dart'; const _kSpaceBannerEvent = 'io.pyramid.space.banner'; +/// Ändert die Power-Levels auf Basis des aktuellen SERVER-Stands (nicht des +/// lokalen Caches!). Das SDK-`setPower` und ein lokal fehlendes +/// power_levels-Event haben sonst zur Folge, dass die users-Map des Servers +/// mit einem Minimal-Event überschrieben wird — und Admins sich selbst +/// aussperren (genau das ist hier bereits passiert). Future updatePowerLevelsSafely( Room room, void Function(Map content) mutate, @@ -50,6 +55,7 @@ Future updatePowerLevelsSafely( .setRoomStateWithKey(room.id, EventTypes.RoomPowerLevels, '', content); } +// Power level labels const _kPowerAdmin = 100; const _kPowerMod = 50; const _kPowerMember = 0; diff --git a/lib/widgets/settings/settings_encryption.dart b/lib/widgets/settings/settings_encryption.dart index 01b8597..f06ab95 100644 --- a/lib/widgets/settings/settings_encryption.dart +++ b/lib/widgets/settings/settings_encryption.dart @@ -1332,6 +1332,7 @@ class _FingerprintGroup extends ConsumerWidget { } } +// Passphrase dialog (for key export/import) class _PassphraseDialog extends StatefulWidget { final PyramidTheme pt; final bool forExport; diff --git a/lib/widgets/settings/settings_voice.dart b/lib/widgets/settings/settings_voice.dart index 216c2b7..98b1d2f 100644 --- a/lib/widgets/settings/settings_voice.dart +++ b/lib/widgets/settings/settings_voice.dart @@ -334,6 +334,10 @@ class _VoiceSectionState extends State<_VoiceSection> { } } +/// Zeigt den TURN-Relay-Verbrauch des laufenden Monats an. Die Daten kommen +/// aus der turn-status.json, die der Guard-Cron auf dem Pi stündlich schreibt. +/// Solange der Endpoint nicht existiert (Analytics-Token fehlt), bleibt die +/// Karte unsichtbar. class _TurnUsageCard extends StatefulWidget { final PyramidTheme pt; const _TurnUsageCard({required this.pt});