optimized avatar and linkify performance, refined navigation to preserve popups, implemented read marker caching, and added file size limits for saving, minor timetable details changes

This commit is contained in:
2026-05-10 16:40:39 +02:00
parent 1458d8ce49
commit a0bc46f522
12 changed files with 234 additions and 64 deletions
@@ -78,22 +78,48 @@ class HighlightedLinkify extends StatefulWidget {
}
class _HighlightedLinkifyState extends State<HighlightedLinkify> {
final List<TapGestureRecognizer> _recognizers = [];
// Cached per link text so character-by-character search rebuilds don't
// churn through allocate/dispose on every keystroke. Stale entries are
// pruned at the end of each build via [_seenLinkKeys].
final Map<String, TapGestureRecognizer> _recognizers = {};
final Set<String> _seenLinkKeys = {};
@override
void dispose() {
for (final r in _recognizers) {
for (final r in _recognizers.values) {
r.dispose();
}
_recognizers.clear();
super.dispose();
}
TapGestureRecognizer _recognizerFor(LinkableElement el) {
final key = el.text;
final existing = _recognizers[key];
if (existing != null) {
// Refresh onTap so a new widget.onOpen callback (from a parent
// rebuild) picks up the latest closure.
existing.onTap = () => widget.onOpen?.call(el);
return existing;
}
final created = TapGestureRecognizer()
..onTap = () => widget.onOpen?.call(el);
_recognizers[key] = created;
return created;
}
void _pruneUnseen() {
final stale = _recognizers.keys
.where((k) => !_seenLinkKeys.contains(k))
.toList(growable: false);
for (final k in stale) {
_recognizers.remove(k)?.dispose();
}
}
@override
Widget build(BuildContext context) {
for (final r in _recognizers) {
r.dispose();
}
_recognizers.clear();
_seenLinkKeys.clear();
final defaultStyle = widget.style ??
Theme.of(context).textTheme.bodyMedium ??
@@ -124,9 +150,8 @@ class _HighlightedLinkifyState extends State<HighlightedLinkify> {
for (final el in elements) {
if (el is LinkableElement) {
final recognizer = TapGestureRecognizer()
..onTap = () => widget.onOpen?.call(el);
_recognizers.add(recognizer);
_seenLinkKeys.add(el.text);
final recognizer = _recognizerFor(el);
spans.addAll(
buildHighlightedSpans(
text: el.text,
@@ -147,6 +172,8 @@ class _HighlightedLinkifyState extends State<HighlightedLinkify> {
}
}
_pruneUnseen();
return Text.rich(TextSpan(children: spans));
}
}