fix: beim Gott-Datei-Split verlorene Erklärkommentare wiederhergestellt

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 <noreply@anthropic.com>
This commit is contained in:
Bernd Steckmeister
2026-07-03 14:37:48 +02:00
parent d254a36de7
commit f9979e4f32
13 changed files with 62 additions and 0 deletions
@@ -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;
@@ -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 = <String, Uint8List>{};
@@ -37,6 +41,10 @@ Future<void> _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;
@@ -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<Event> events;
final String currentUserId;
@@ -304,6 +305,8 @@ class _MessageGroupState extends State<MessageGroup> {
}
}
// 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;
@@ -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) =>
@@ -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});
@@ -186,6 +186,18 @@ class _MessageContent extends StatelessWidget {
}
}
// Handles the subset of HTML that Matrix clients emit in formatted_body:
// <b>/<strong> → bold
// <i>/<em> → italic
// <del>/<s> → strikethrough
// <u> → underline
// <code> → monospace, slightly different background
// <a href> → tappable link (url_launcher)
// <br> → newline
// HTML entities → decoded
// Anything else → text content preserved, tags stripped
//
// Note: <pre> and <blockquote> are simplified (rendered as indented code/text).
class _MatrixHtmlText extends StatelessWidget {
final String html;
final TextStyle baseStyle;
@@ -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
+3
View File
@@ -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;
+1
View File
@@ -99,6 +99,7 @@ class _DragOverlayState extends State<_DragOverlay>
}
}
// Placeholder shown when no room is selected
class NoChatSelected extends StatelessWidget {
const NoChatSelected({super.key});
@@ -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;
@@ -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<void> updatePowerLevelsSafely(
Room room,
void Function(Map<String, dynamic> content) mutate,
@@ -50,6 +55,7 @@ Future<void> updatePowerLevelsSafely(
.setRoomStateWithKey(room.id, EventTypes.RoomPowerLevels, '', content);
}
// Power level labels
const _kPowerAdmin = 100;
const _kPowerMod = 50;
const _kPowerMember = 0;