fix: Improve message key handling and enhance contact tile key uniqueness

This commit is contained in:
Winston Lowe
2026-05-11 18:19:45 -07:00
parent a270e2e6d1
commit 61c897630c
4 changed files with 18 additions and 4 deletions
+9 -2
View File
@@ -377,6 +377,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
final reversedMessages = messages.reversed.toList(); final reversedMessages = messages.reversed.toList();
final itemCount = final itemCount =
reversedMessages.length + (_isLoadingOlder ? 1 : 0); reversedMessages.length + (_isLoadingOlder ? 1 : 0);
final keyedMessageIds = <String>{};
// Auto-scroll to bottom if user is already at bottom // Auto-scroll to bottom if user is already at bottom
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -413,14 +414,20 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
} }
final messageIndex = index; final messageIndex = index;
final message = reversedMessages[messageIndex]; final message = reversedMessages[messageIndex];
if (!_messageKeys.containsKey(message.messageId)) { final shouldAttachMessageKey = keyedMessageIds.add(
message.messageId,
);
if (shouldAttachMessageKey &&
!_messageKeys.containsKey(message.messageId)) {
_messageKeys[message.messageId] = GlobalKey(); _messageKeys[message.messageId] = GlobalKey();
} }
final isUnreadAnchor = final isUnreadAnchor =
_unreadDividerMessageId != null && _unreadDividerMessageId != null &&
message.messageId == _unreadDividerMessageId; message.messageId == _unreadDividerMessageId;
return Container( return Container(
key: _messageKeys[message.messageId]!, key: shouldAttachMessageKey
? _messageKeys[message.messageId]
: null,
child: Builder( child: Builder(
builder: (context) { builder: (context) {
final textScale = context final textScale = context
+1 -1
View File
@@ -394,7 +394,7 @@ class _ChannelsScreenState extends State<ChannelsScreen> {
} }
return Card( return Card(
key: ValueKey('channel_${channel.index}'), key: ValueKey('${channel.index}_${channel.pskHex}_${channel.name}'),
margin: const EdgeInsets.only(bottom: 12), margin: const EdgeInsets.only(bottom: 12),
child: GestureDetector( child: GestureDetector(
onSecondaryTapUp: PlatformInfo.isDesktop onSecondaryTapUp: PlatformInfo.isDesktop
+6 -1
View File
@@ -451,6 +451,7 @@ class _ChatScreenState extends State<ChatScreen> {
) { ) {
// Reverse messages so newest appear at bottom with reverse: true // Reverse messages so newest appear at bottom with reverse: true
final reversedMessages = messages.reversed.toList(); final reversedMessages = messages.reversed.toList();
var unreadAnchorKeyAssigned = false;
final itemCount = reversedMessages.length + (_isLoadingOlder ? 1 : 0); final itemCount = reversedMessages.length + (_isLoadingOlder ? 1 : 0);
// Auto-scroll to bottom if user is already at bottom // Auto-scroll to bottom if user is already at bottom
@@ -525,7 +526,11 @@ class _ChatScreenState extends State<ChatScreen> {
children: [const UnreadDivider(), bubble], children: [const UnreadDivider(), bubble],
) )
: bubble; : bubble;
if (identical(message, _pendingUnreadScrollTarget)) { final shouldAttachUnreadScrollKey =
!unreadAnchorKeyAssigned &&
identical(message, _pendingUnreadScrollTarget);
if (shouldAttachUnreadScrollKey) {
unreadAnchorKeyAssigned = true;
return KeyedSubtree(key: _unreadScrollKey, child: child); return KeyedSubtree(key: _unreadScrollKey, child: child);
} }
return child; return child;
+2
View File
@@ -827,6 +827,7 @@ class _ContactsScreenState extends State<ContactsScreen> {
contact, contact,
); );
return _ContactTile( return _ContactTile(
key: ValueKey(contact.publicKeyHex),
contact: contact, contact: contact,
lastSeen: _resolveLastSeen(contact), lastSeen: _resolveLastSeen(contact),
unreadCount: unreadCount, unreadCount: unreadCount,
@@ -1495,6 +1496,7 @@ class _ContactTile extends StatelessWidget {
final VoidCallback onLongPress; final VoidCallback onLongPress;
const _ContactTile({ const _ContactTile({
super.key,
required this.contact, required this.contact,
required this.lastSeen, required this.lastSeen,
required this.unreadCount, required this.unreadCount,