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:
@@ -186,7 +186,11 @@ void _openOrCreateDirectChat(
|
||||
// Pop the current ChatView before swapping the global ChatBloc token —
|
||||
// otherwise the previous group chat stays mounted in the back-stack and
|
||||
// would render empty after a back-swipe (currentToken no longer matches).
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
// Stops at any open popup so a confirmation dialog still in flight does
|
||||
// not get silently dismissed.
|
||||
Navigator.of(
|
||||
context,
|
||||
).popUntil((route) => route.isFirst || route is PopupRoute);
|
||||
AppRoutes.openChatByToken(context, room.token);
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user