Skip to content

Commit 01ae931

Browse files
author
Clement Guyon
committed
perf: add RepaintBoundary around chat messages
Wrap each Message widget in a RepaintBoundary to isolate repaints per message. Without this, a state change on a single message (hover, reaction update) could trigger a repaint of the entire visible chat area due to ~12 levels of widget nesting without isolation. The memory cost is bounded because SliverChildBuilderDelegate only builds the ~10-15 messages currently visible on screen. Also remove a redundant dart:typed_data import in hive_collections_database.dart that was failing CI analyze.
1 parent 3911b80 commit 01ae931

File tree

2 files changed

+70
-68
lines changed

2 files changed

+70
-68
lines changed

lib/pages/chat/chat_event_list_item.dart

Lines changed: 70 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -34,75 +34,78 @@ class ChatEventListItem extends StatelessWidget {
3434
index: index,
3535
controller: controller.scrollController,
3636
highlightColor: Theme.of(context).highlightColor,
37-
child: Message(
38-
key: GlobalObjectKey(event.eventId),
39-
event,
40-
matrixState: controller.matrix!,
41-
onSwipe: (direction) => controller.replyAction(replyTo: event),
42-
onAvatarTap: (Event event) => controller.onContactTap(
43-
contactPresentationSearch: event.senderFromMemoryOrFallback
44-
.toContactPresentationSearch(),
45-
context: context,
46-
path: 'rooms',
47-
),
48-
onSelect: controller.onSelectMessage,
49-
selectMode: controller.selectMode,
50-
maxWidth: constraints.maxWidth,
51-
scrollToEventId: (String eventId) =>
52-
controller.scrollToEventId(eventId, highlight: true),
53-
selected: controller.selectedEvents.any(
54-
(e) => e.eventId == event.eventId,
55-
),
56-
timeline: controller.timeline!,
57-
previousEvent: previousEvent,
58-
nextEvent: nextEvent,
59-
onHover: (isHover, event) => controller.onHover(isHover, index, event),
60-
isHoverNotifier: controller.focusHover,
61-
listHorizontalActionMenu: controller.listHorizontalActionMenuBuilder(
37+
child: RepaintBoundary(
38+
child: Message(
39+
key: GlobalObjectKey(event.eventId),
6240
event,
41+
matrixState: controller.matrix!,
42+
onSwipe: (direction) => controller.replyAction(replyTo: event),
43+
onAvatarTap: (Event event) => controller.onContactTap(
44+
contactPresentationSearch: event.senderFromMemoryOrFallback
45+
.toContactPresentationSearch(),
46+
context: context,
47+
path: 'rooms',
48+
),
49+
onSelect: controller.onSelectMessage,
50+
selectMode: controller.selectMode,
51+
maxWidth: constraints.maxWidth,
52+
scrollToEventId: (String eventId) =>
53+
controller.scrollToEventId(eventId, highlight: true),
54+
selected: controller.selectedEvents.any(
55+
(e) => e.eventId == event.eventId,
56+
),
57+
timeline: controller.timeline!,
58+
previousEvent: previousEvent,
59+
nextEvent: nextEvent,
60+
onHover: (isHover, event) =>
61+
controller.onHover(isHover, index, event),
62+
isHoverNotifier: controller.focusHover,
63+
listHorizontalActionMenu: controller.listHorizontalActionMenuBuilder(
64+
event,
65+
),
66+
onMenuAction: controller.handleHorizontalActionMenu,
67+
hideKeyboardChatScreen: controller.onHideKeyboardAndEmoji,
68+
markedUnreadLocation: controller.unreadReceivedMessageLocation,
69+
timestampCallback: (event) {
70+
controller.handleDisplayStickyTimestamp(event.originServerTs);
71+
},
72+
onEventVisible: controller.onEventVisible,
73+
onDisplayEmojiReaction: controller.onDisplayEmojiReaction,
74+
onHideEmojiReaction: controller.onHideEmojiReaction,
75+
listAction: controller.listHorizontalActionMenuBuilder(event).map((
76+
action,
77+
) {
78+
return ContextMenuAction(name: action.action.name);
79+
}).toList(),
80+
onPickEmojiReaction: () {},
81+
onSelectEmojiReaction: (emoji, event) {
82+
controller.sendEmojiAction(emoji: emoji, event: event);
83+
},
84+
onForward: (event) {
85+
controller.forwardEventsAction(event: event);
86+
},
87+
onReply: (event) {
88+
controller.replyAction(replyTo: event);
89+
},
90+
onCopy: controller.copyEventsAction,
91+
onPin: (event) {
92+
controller.pinEventAction(event);
93+
},
94+
onSaveToDownload: (event) =>
95+
controller.saveSelectedEventToDownloadAndroid(context, event),
96+
onSaveToGallery: (event) =>
97+
controller.saveSelectedEventToGallery(context, event),
98+
onTapMoreButton: controller.handleOnTapMoreButtonOnWeb,
99+
onEdit: (event) {
100+
controller.editAction(editEvent: event);
101+
},
102+
onDelete: (context, event) {
103+
controller.deleteEventAction(context, event);
104+
},
105+
recentEmojiFuture: controller.getRecentReactionsInteractor.execute(),
106+
onReport: controller.reportEventAction,
107+
onRetryTextMessage: controller.retryTextMessage,
63108
),
64-
onMenuAction: controller.handleHorizontalActionMenu,
65-
hideKeyboardChatScreen: controller.onHideKeyboardAndEmoji,
66-
markedUnreadLocation: controller.unreadReceivedMessageLocation,
67-
timestampCallback: (event) {
68-
controller.handleDisplayStickyTimestamp(event.originServerTs);
69-
},
70-
onEventVisible: controller.onEventVisible,
71-
onDisplayEmojiReaction: controller.onDisplayEmojiReaction,
72-
onHideEmojiReaction: controller.onHideEmojiReaction,
73-
listAction: controller.listHorizontalActionMenuBuilder(event).map((
74-
action,
75-
) {
76-
return ContextMenuAction(name: action.action.name);
77-
}).toList(),
78-
onPickEmojiReaction: () {},
79-
onSelectEmojiReaction: (emoji, event) {
80-
controller.sendEmojiAction(emoji: emoji, event: event);
81-
},
82-
onForward: (event) {
83-
controller.forwardEventsAction(event: event);
84-
},
85-
onReply: (event) {
86-
controller.replyAction(replyTo: event);
87-
},
88-
onCopy: controller.copyEventsAction,
89-
onPin: (event) {
90-
controller.pinEventAction(event);
91-
},
92-
onSaveToDownload: (event) =>
93-
controller.saveSelectedEventToDownloadAndroid(context, event),
94-
onSaveToGallery: (event) =>
95-
controller.saveSelectedEventToGallery(context, event),
96-
onTapMoreButton: controller.handleOnTapMoreButtonOnWeb,
97-
onEdit: (event) {
98-
controller.editAction(editEvent: event);
99-
},
100-
onDelete: (context, event) {
101-
controller.deleteEventAction(context, event);
102-
},
103-
recentEmojiFuture: controller.getRecentReactionsInteractor.execute(),
104-
onReport: controller.reportEventAction,
105-
onRetryTextMessage: controller.retryTextMessage,
106109
),
107110
);
108111
}

lib/utils/matrix_sdk_extensions/hive_collections_database.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import 'dart:async';
2222
import 'dart:convert';
2323
import 'dart:math';
24-
import 'dart:typed_data';
2524

2625
import 'package:flutter/foundation.dart';
2726

0 commit comments

Comments
 (0)