Skip to content

Commit 637f4f6

Browse files
committed
fix: address review — conditional group re-fetch, participant de-dupe, nits
1 parent abb9ed6 commit 637f4f6

3 files changed

Lines changed: 46 additions & 16 deletions

File tree

lib/database/global/message_summary_info.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class MessageSummaryInfo {
2727
)
2828
}
2929
: Map<String, List<EditedContent>>.from(
30-
asStringDynamicMapRequired(json["editedContent"])!.map(
30+
asStringDynamicMapRequired(json["editedContent"]).map(
3131
(k, v) => MapEntry(
3232
k,
3333
List<EditedContent>.from(
@@ -41,7 +41,7 @@ class MessageSummaryInfo {
4141
: json["originalTextRange"] is List
4242
? {"0": List<int>.from(json["originalTextRange"])}
4343
: Map<String, List<int>>.from(
44-
asStringDynamicMapRequired(json["originalTextRange"])!.map(
44+
asStringDynamicMapRequired(json["originalTextRange"]).map(
4545
(k, v) => MapEntry(k.toString(), List<int>.from(v as List)),
4646
),
4747
),

lib/services/backend/actions/chat_actions.dart

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -306,12 +306,17 @@ class ChatActions {
306306
// the message is linked to the contact-aware handle instead of creating
307307
// an orphaned duplicate.
308308
final addr = inputMessage.handle!.address;
309-
final altAddr = addr.startsWith('+') ? addr.substring(1) : '+$addr';
310-
final altUAS = '$altAddr/${inputMessage.handle!.service}';
311-
final altQuery = handleBox.query(Handle_.uniqueAddressAndService.equals(altUAS)).build();
312-
altQuery.limit = 1;
313-
final altHandle = altQuery.findFirst();
314-
altQuery.close();
309+
// Only phone numbers have a +/− prefix variant. Skip emails — an '@'
310+
// address would otherwise produce a nonsensical "+user@example.com" query.
311+
Handle? altHandle;
312+
if (!addr.contains('@')) {
313+
final altAddr = addr.startsWith('+') ? addr.substring(1) : '+$addr';
314+
final altUAS = '$altAddr/${inputMessage.handle!.service}';
315+
final altQuery = handleBox.query(Handle_.uniqueAddressAndService.equals(altUAS)).build();
316+
altQuery.limit = 1;
317+
altHandle = altQuery.findFirst();
318+
altQuery.close();
319+
}
315320

316321
if (altHandle != null) {
317322
handleToLink = altHandle;
@@ -403,12 +408,30 @@ class ChatActions {
403408
needsUpdate = true;
404409
}
405410

406-
// Keep chat participant list in sync when we resolve a new sender
407-
if (handleToLink != null &&
408-
dbChat != null &&
409-
!dbChat.handles.any((h) => h.originalROWID == handleToLink!.originalROWID)) {
410-
dbChat.handles.add(handleToLink);
411-
dbChat.handles.applyToDb();
411+
// Keep the chat's participant list in sync with the resolved sender and
412+
// collapse any duplicate entries. De-dupe on the handle's real identity
413+
// (address + service, its unique key) as well as originalROWID: a
414+
// message's sender handle can carry a null/mismatched originalROWID
415+
// versus the copy already linked to the chat, and an originalROWID-only
416+
// guard both re-adds the same number and never removes a pre-existing
417+
// duplicate (ToMany is a list, so the same handle can appear twice).
418+
if (handleToLink != null && dbChat != null) {
419+
bool sameIdentity(Handle a, Handle b) =>
420+
(a.originalROWID != null && a.originalROWID == b.originalROWID) ||
421+
(a.address == b.address && a.service == b.service);
422+
final current = List<Handle>.from(dbChat.handles);
423+
final deduped = <Handle>[];
424+
for (final h in current) {
425+
if (!deduped.any((d) => sameIdentity(d, h))) deduped.add(h);
426+
}
427+
final hadDuplicate = deduped.length != current.length;
428+
final senderMissing = !deduped.any((d) => sameIdentity(d, handleToLink!));
429+
if (senderMissing) deduped.add(handleToLink);
430+
if (hadDuplicate || senderMissing) {
431+
dbChat.handles.clear();
432+
dbChat.handles.addAll(deduped);
433+
dbChat.handles.applyToDb();
434+
}
412435
}
413436

414437
// Process and link attachments if present

lib/services/backend/incoming_message_handler.dart

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,9 +536,16 @@ class IncomingMessageHandler {
536536
final chatForCheck = local ?? partial;
537537
final incomingFromOther = !(m.isFromMe ?? false);
538538

539-
// Always refresh participants for incoming group messages — push payloads
540-
// carry handleId only, and a stale local participant list breaks linking.
539+
// For incoming group messages, only re-fetch participants when the sender's
540+
// handle isn't already resolvable locally. Push payloads carry handleId only,
541+
// so a missing sender is what breaks linking; when we already have it, skip
542+
// the server round-trip (re-fetching on every group message doesn't scale).
541543
if (incomingFromOther && _chatIsGroup(chatForCheck)) {
544+
final senderResolvable =
545+
m.handleId != null && (local?.handles.any((h) => h.originalROWID == m.handleId) ?? false);
546+
if (senderResolvable) {
547+
return (chat: local!, affectedHandleIds: <int>[]);
548+
}
542549
Logger.debug(
543550
'Refetching group participants for ${partial.guid} (handleId=${m.handleId})',
544551
tag: _tag,

0 commit comments

Comments
 (0)