Get the correct unread count for a conversation

This commit is contained in:
Josh Perez 2021-05-10 14:49:13 -04:00 committed by GitHub
parent c68d65ea0b
commit 887b2c1db1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 47 additions and 14 deletions

View File

@ -3975,11 +3975,19 @@ export class ConversationModel extends window.Backbone
sendReadReceipts: true, sendReadReceipts: true,
} }
): Promise<void> { ): Promise<void> {
const unreadCount = await markConversationRead( const markedUnread = await markConversationRead(
this.attributes, this.attributes,
newestUnreadId, newestUnreadId,
options options
); );
if (!markedUnread) {
return;
}
const unreadCount = await window.Signal.Data.getUnreadCountForConversation(
this.id
);
this.set({ unreadCount }); this.set({ unreadCount });
window.Signal.Data.updateConversation(this.attributes); window.Signal.Data.updateConversation(this.attributes);
} }

View File

@ -167,6 +167,7 @@ const dataInterface: ClientInterface = {
saveMessages, saveMessages,
removeMessage, removeMessage,
removeMessages, removeMessages,
getUnreadCountForConversation,
getUnreadByConversationAndMarkRead, getUnreadByConversationAndMarkRead,
getUnreadReactionsAndMarkRead, getUnreadReactionsAndMarkRead,
markReactionAsRead, markReactionAsRead,
@ -1046,6 +1047,10 @@ async function getMessageBySender(
return new Message(messages[0]); return new Message(messages[0]);
} }
async function getUnreadCountForConversation(conversationId: string) {
return channels.getUnreadCountForConversation(conversationId);
}
async function getUnreadByConversationAndMarkRead( async function getUnreadByConversationAndMarkRead(
conversationId: string, conversationId: string,
newestUnreadId: number, newestUnreadId: number,

View File

@ -343,6 +343,7 @@ export type ServerInterface = DataInterface & {
getNextTapToViewMessageToAgeOut: () => Promise<MessageType | undefined>; getNextTapToViewMessageToAgeOut: () => Promise<MessageType | undefined>;
getOutgoingWithoutExpiresAt: () => Promise<Array<MessageType>>; getOutgoingWithoutExpiresAt: () => Promise<Array<MessageType>>;
getTapToViewMessagesNeedingErase: () => Promise<Array<MessageType>>; getTapToViewMessagesNeedingErase: () => Promise<Array<MessageType>>;
getUnreadCountForConversation: (conversationId: string) => Promise<number>;
getUnreadByConversationAndMarkRead: ( getUnreadByConversationAndMarkRead: (
conversationId: string, conversationId: string,
newestUnreadId: number, newestUnreadId: number,
@ -486,6 +487,7 @@ export type ClientInterface = DataInterface & {
getTapToViewMessagesNeedingErase: (options: { getTapToViewMessagesNeedingErase: (options: {
MessageCollection: typeof MessageModelCollectionType; MessageCollection: typeof MessageModelCollectionType;
}) => Promise<MessageModelCollectionType>; }) => Promise<MessageModelCollectionType>;
getUnreadCountForConversation: (conversationId: string) => Promise<number>;
getUnreadByConversationAndMarkRead: ( getUnreadByConversationAndMarkRead: (
conversationId: string, conversationId: string,
newestUnreadId: number, newestUnreadId: number,

View File

@ -157,6 +157,7 @@ const dataInterface: ServerInterface = {
saveMessages, saveMessages,
removeMessage, removeMessage,
removeMessages, removeMessages,
getUnreadCountForConversation,
getUnreadByConversationAndMarkRead, getUnreadByConversationAndMarkRead,
getUnreadReactionsAndMarkRead, getUnreadReactionsAndMarkRead,
markReactionAsRead, markReactionAsRead,
@ -3092,6 +3093,24 @@ function updateExpirationTimers(
); );
} }
async function getUnreadCountForConversation(
conversationId: string
): Promise<number> {
const db = getInstance();
const row = db
.prepare<Query>(
`
SELECT COUNT(*) AS unreadCount FROM messages
WHERE unread = 1 AND
conversationId = $conversationId
`
)
.get({
conversationId,
});
return row.unreadCount;
}
async function getUnreadByConversationAndMarkRead( async function getUnreadByConversationAndMarkRead(
conversationId: string, conversationId: string,
newestUnreadId: number, newestUnreadId: number,
@ -3118,6 +3137,10 @@ async function getUnreadByConversationAndMarkRead(
newestUnreadId, newestUnreadId,
}); });
if (!rows.length) {
return [];
}
const messagesWithExpireTimer: Map< const messagesWithExpireTimer: Map<
string, string,
{ {

View File

@ -11,7 +11,7 @@ export async function markConversationRead(
options: { readAt?: number; sendReadReceipts: boolean } = { options: { readAt?: number; sendReadReceipts: boolean } = {
sendReadReceipts: true, sendReadReceipts: true,
} }
): Promise<number> { ): Promise<boolean> {
const { id: conversationId } = conversationAttrs; const { id: conversationId } = conversationAttrs;
window.Whisper.Notifications.removeBy({ conversationId }); window.Whisper.Notifications.removeBy({ conversationId });
@ -27,6 +27,10 @@ export async function markConversationRead(
), ),
]); ]);
if (!unreadMessages.length && !unreadReactions.length) {
return false;
}
const unreadReactionSyncData = new Map< const unreadReactionSyncData = new Map<
string, string,
{ {
@ -67,22 +71,13 @@ export async function markConversationRead(
}); });
// Some messages we're marking read are local notifications with no sender // Some messages we're marking read are local notifications with no sender
const messagesWithSenderId = allReadMessagesSync.filter(syncMessage =>
Boolean(syncMessage.senderId)
);
const incomingUnreadMessages = unreadMessages.filter(
message => message.type === 'incoming'
);
const unreadCount =
incomingUnreadMessages.length - messagesWithSenderId.length;
// If a message has errors, we don't want to send anything out about it. // If a message has errors, we don't want to send anything out about it.
// read syncs - let's wait for a client that really understands the message // read syncs - let's wait for a client that really understands the message
// to mark it read. we'll mark our local error read locally, though. // to mark it read. we'll mark our local error read locally, though.
// read receipts - here we can run into infinite loops, where each time the // read receipts - here we can run into infinite loops, where each time the
// conversation is viewed, another error message shows up for the contact // conversation is viewed, another error message shows up for the contact
const unreadMessagesSyncData = messagesWithSenderId.filter( const unreadMessagesSyncData = allReadMessagesSync.filter(
item => !item.hasErrors item => Boolean(item.senderId) && !item.hasErrors
); );
const readSyncs = [ const readSyncs = [
@ -107,5 +102,5 @@ export async function markConversationRead(
await sendReadReceiptsFor(conversationAttrs, unreadMessagesSyncData); await sendReadReceiptsFor(conversationAttrs, unreadMessagesSyncData);
} }
return unreadCount; return true;
} }