diff --git a/lib/shared/dm-ops/add-members-spec.js b/lib/shared/dm-ops/add-members-spec.js --- a/lib/shared/dm-ops/add-members-spec.js +++ b/lib/shared/dm-ops/add-members-spec.js @@ -11,6 +11,7 @@ DMOperationSpec, ProcessDMOperationUtilities, } from './dm-op-spec.js'; +import { createUpdateUnreadCountUpdate } from './dm-op-utils.js'; import type { DMAddMembersOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; import { @@ -79,6 +80,17 @@ unread: true, }, ); + const repliesCountUpdate = createUpdateUnreadCountUpdate(newThread, [ + addMembersMessage, + ]); + if ( + repliesCountUpdate && + repliesCountUpdate.type === updateTypes.UPDATE_THREAD + ) { + updateInfos.push(repliesCountUpdate); + resultThreadInfo.repliesCount = + repliesCountUpdate.threadInfo.repliesCount; + } } else { const currentThreadInfoOptional = utilities.threadInfos[existingThreadDetails.threadID]; @@ -117,8 +129,12 @@ members: [...currentThreadInfo.members, ...newMembers], }; resultThreadInfo = newThreadInfo; + const updateWithRepliesCount = createUpdateUnreadCountUpdate( + newThreadInfo, + [addMembersMessage], + ); updateInfos.push( - { + updateWithRepliesCount ?? { type: updateTypes.UPDATE_THREAD, id: uuid.v4(), time, diff --git a/lib/shared/dm-ops/change-thread-settings-spec.js b/lib/shared/dm-ops/change-thread-settings-spec.js --- a/lib/shared/dm-ops/change-thread-settings-spec.js +++ b/lib/shared/dm-ops/change-thread-settings-spec.js @@ -7,6 +7,7 @@ DMOperationSpec, ProcessDMOperationUtilities, } from './dm-op-spec.js'; +import { createUpdateUnreadCountUpdate } from './dm-op-utils.js'; import type { DMChangeThreadSettingsOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; import type { RawMessageInfo } from '../../types/message-types.js'; @@ -126,7 +127,13 @@ }); } - if (values(changedFields).length > 0) { + const repliesCountUpdate = createUpdateUnreadCountUpdate( + threadInfoToUpdate, + rawMessageInfos, + ); + if (repliesCountUpdate) { + updateInfos.push(repliesCountUpdate); + } else if (values(changedFields).length > 0) { updateInfos.push({ type: updateTypes.UPDATE_THREAD, id: uuid.v4(), diff --git a/lib/shared/dm-ops/create-sidebar-spec.js b/lib/shared/dm-ops/create-sidebar-spec.js --- a/lib/shared/dm-ops/create-sidebar-spec.js +++ b/lib/shared/dm-ops/create-sidebar-spec.js @@ -48,6 +48,7 @@ creatorID, sourceMessageID, containingThreadID: parentThreadID, + repliesCount: 1, }, viewerID, ); diff --git a/lib/shared/dm-ops/dm-op-utils.js b/lib/shared/dm-ops/dm-op-utils.js --- a/lib/shared/dm-ops/dm-op-utils.js +++ b/lib/shared/dm-ops/dm-op-utils.js @@ -4,13 +4,21 @@ import type { AuxUserStore } from '../../types/aux-user-types.js'; import type { DMOperation } from '../../types/dm-ops.js'; +import { messageTypes } from '../../types/message-types-enum.js'; +import type { RawMessageInfo } from '../../types/message-types.js'; +import type { RawThreadInfo } from '../../types/minimally-encoded-thread-permissions-types.js'; import { outboundP2PMessageStatuses, type OutboundP2PMessage, } from '../../types/sqlite-types.js'; +import { threadTypes } from '../../types/thread-types-enum.js'; +import type { LegacyRawThreadInfo } from '../../types/thread-types.js'; +import { updateTypes } from '../../types/update-types-enum.js'; +import type { ClientUpdateInfo } from '../../types/update-types.js'; import type { CurrentUserInfo } from '../../types/user-types.js'; import { getContentSigningKey } from '../../utils/crypto-utils.js'; import { values } from '../../utils/objects.js'; +import { messageSpecs } from '../messages/message-specs.js'; function generateMessagesToPeers( message: DMOperation, @@ -66,4 +74,35 @@ ); } -export { createMessagesToPeersFromDMOp }; +function createUpdateUnreadCountUpdate( + threadInfo: RawThreadInfo | LegacyRawThreadInfo, + newMessages: $ReadOnlyArray, +): ?ClientUpdateInfo { + if (threadInfo.type !== threadTypes.THICK_SIDEBAR) { + return null; + } + const includedMessageTypes = new Set( + Object.keys(messageTypes) + .map(key => messageTypes[key]) + .filter(type => messageSpecs[type].includedInRepliesCount), + ); + const filteredMessages = newMessages.filter(message => + includedMessageTypes.has(message.type), + ); + const countIncrease = filteredMessages.length; + if (countIncrease === 0) { + return null; + } + const time = Math.max(...filteredMessages.map(message => message.time)); + return { + type: updateTypes.UPDATE_THREAD, + id: uuid.v4(), + time, + threadInfo: { + ...threadInfo, + repliesCount: threadInfo.repliesCount + countIncrease, + }, + }; +} + +export { createMessagesToPeersFromDMOp, createUpdateUnreadCountUpdate }; diff --git a/lib/shared/dm-ops/join-thread-spec.js b/lib/shared/dm-ops/join-thread-spec.js --- a/lib/shared/dm-ops/join-thread-spec.js +++ b/lib/shared/dm-ops/join-thread-spec.js @@ -11,6 +11,7 @@ DMOperationSpec, ProcessDMOperationUtilities, } from './dm-op-spec.js'; +import { createUpdateUnreadCountUpdate } from './dm-op-utils.js'; import type { DMJoinThreadOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; import { @@ -64,18 +65,19 @@ const updateInfos: Array = []; const rawMessageInfos: Array = []; if (viewerID === editorID) { + const newThreadInfo = createThickRawThreadInfo( + { + ...existingThreadDetails, + allMemberIDs: [...existingThreadDetails.allMemberIDs, editorID], + }, + viewerID, + ); updateInfos.push( { type: updateTypes.JOIN_THREAD, id: uuid.v4(), time, - threadInfo: createThickRawThreadInfo( - { - ...existingThreadDetails, - allMemberIDs: [...existingThreadDetails.allMemberIDs, editorID], - }, - viewerID, - ), + threadInfo: newThreadInfo, rawMessageInfos: [joinThreadMessage], truncationStatus: messageTruncationStatus.EXHAUSTIVE, rawEntryInfos: [], @@ -88,6 +90,12 @@ unread: true, }, ); + const repliesCountUpdate = createUpdateUnreadCountUpdate(newThreadInfo, [ + joinThreadMessage, + ]); + if (repliesCountUpdate) { + updateInfos.push(repliesCountUpdate); + } } else { if (!currentThreadInfoOptional || !currentThreadInfoOptional.thick) { // We can't perform this operation now. It should be queued for later. @@ -120,8 +128,12 @@ ...currentThreadInfo, members: [...currentThreadInfo.members, member], }; + const updateWithRepliesCount = createUpdateUnreadCountUpdate( + updatedThreadInfo, + [joinThreadMessage], + ); updateInfos.push( - { + updateWithRepliesCount ?? { type: updateTypes.UPDATE_THREAD, id: uuid.v4(), time, diff --git a/lib/shared/dm-ops/leave-thread-spec.js b/lib/shared/dm-ops/leave-thread-spec.js --- a/lib/shared/dm-ops/leave-thread-spec.js +++ b/lib/shared/dm-ops/leave-thread-spec.js @@ -6,6 +6,7 @@ DMOperationSpec, ProcessDMOperationUtilities, } from './dm-op-spec.js'; +import { createUpdateUnreadCountUpdate } from './dm-op-utils.js'; import type { DMLeaveThreadOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; import type { ThickRawThreadInfo } from '../../types/minimally-encoded-thread-permissions-types.js'; @@ -59,8 +60,12 @@ ...threadInfo, members: threadInfo.members.filter(member => member.id !== editorID), }; + const updateWithRepliesCount = createUpdateUnreadCountUpdate( + updatedThreadInfo, + [leaveThreadMessage], + ); updateInfos.push( - { + updateWithRepliesCount ?? { type: updateTypes.UPDATE_THREAD, id: uuid.v4(), time, diff --git a/lib/shared/dm-ops/remove-members-spec.js b/lib/shared/dm-ops/remove-members-spec.js --- a/lib/shared/dm-ops/remove-members-spec.js +++ b/lib/shared/dm-ops/remove-members-spec.js @@ -6,6 +6,7 @@ DMOperationSpec, ProcessDMOperationUtilities, } from './dm-op-spec.js'; +import { createUpdateUnreadCountUpdate } from './dm-op-utils.js'; import type { DMRemoveMembersOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; import type { ThickRawThreadInfo } from '../../types/minimally-encoded-thread-permissions-types.js'; @@ -64,8 +65,12 @@ member => !removedUserIDsSet.has(member.id), ), }; + const updateWithRepliesCount = createUpdateUnreadCountUpdate( + updatedThreadInfo, + [removeMembersMessage], + ); updateInfos.push( - { + updateWithRepliesCount ?? { type: updateTypes.UPDATE_THREAD, id: uuid.v4(), time, diff --git a/lib/shared/dm-ops/send-edit-message-spec.js b/lib/shared/dm-ops/send-edit-message-spec.js --- a/lib/shared/dm-ops/send-edit-message-spec.js +++ b/lib/shared/dm-ops/send-edit-message-spec.js @@ -2,7 +2,11 @@ import uuid from 'uuid'; -import type { DMOperationSpec } from './dm-op-spec.js'; +import type { + DMOperationSpec, + ProcessDMOperationUtilities, +} from './dm-op-spec.js'; +import { createUpdateUnreadCountUpdate } from './dm-op-utils.js'; import type { DMSendEditMessageOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; import { updateTypes } from '../../types/update-types-enum.js'; @@ -13,6 +17,7 @@ processDMOperation: async ( dmOperation: DMSendEditMessageOperation, viewerID: string, + utilities: ProcessDMOperationUtilities, ) => { const { threadID, creatorID, time, messageID, targetMessageID, text } = dmOperation; @@ -36,6 +41,15 @@ unread: true, }); } + const threadInfo = utilities.threadInfos[threadID]; + if (threadInfo) { + const repliesCountUpdate = createUpdateUnreadCountUpdate(threadInfo, [ + editMessage, + ]); + if (repliesCountUpdate) { + updateInfos.push(repliesCountUpdate); + } + } return { rawMessageInfos: [editMessage], updateInfos, diff --git a/lib/shared/dm-ops/send-reaction-message-spec.js b/lib/shared/dm-ops/send-reaction-message-spec.js --- a/lib/shared/dm-ops/send-reaction-message-spec.js +++ b/lib/shared/dm-ops/send-reaction-message-spec.js @@ -2,7 +2,11 @@ import uuid from 'uuid'; -import type { DMOperationSpec } from './dm-op-spec.js'; +import type { + DMOperationSpec, + ProcessDMOperationUtilities, +} from './dm-op-spec.js'; +import { createUpdateUnreadCountUpdate } from './dm-op-utils.js'; import type { DMSendReactionMessageOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; import { updateTypes } from '../../types/update-types-enum.js'; @@ -13,6 +17,7 @@ processDMOperation: async ( dmOperation: DMSendReactionMessageOperation, viewerID: string, + utilities: ProcessDMOperationUtilities, ) => { const { threadID, @@ -44,6 +49,15 @@ unread: true, }); } + const threadInfo = utilities.threadInfos[threadID]; + if (threadInfo) { + const repliesCountUpdate = createUpdateUnreadCountUpdate(threadInfo, [ + reactionMessage, + ]); + if (repliesCountUpdate) { + updateInfos.push(repliesCountUpdate); + } + } return { rawMessageInfos: [reactionMessage], updateInfos, diff --git a/lib/shared/dm-ops/send-text-message-spec.js b/lib/shared/dm-ops/send-text-message-spec.js --- a/lib/shared/dm-ops/send-text-message-spec.js +++ b/lib/shared/dm-ops/send-text-message-spec.js @@ -2,7 +2,11 @@ import uuid from 'uuid'; -import type { DMOperationSpec } from './dm-op-spec.js'; +import type { + DMOperationSpec, + ProcessDMOperationUtilities, +} from './dm-op-spec.js'; +import { createUpdateUnreadCountUpdate } from './dm-op-utils.js'; import type { DMSendTextMessageOperation } from '../../types/dm-ops.js'; import { messageTypes } from '../../types/message-types-enum.js'; import { updateTypes } from '../../types/update-types-enum.js'; @@ -13,6 +17,7 @@ processDMOperation: async ( dmOperation: DMSendTextMessageOperation, viewerID: string, + utilities: ProcessDMOperationUtilities, ) => { const { threadID, creatorID, time, messageID, text } = dmOperation; const textMessage = { @@ -33,6 +38,15 @@ unread: true, }); } + const threadInfo = utilities.threadInfos[threadID]; + if (threadInfo) { + const repliesCountUpdate = createUpdateUnreadCountUpdate(threadInfo, [ + textMessage, + ]); + if (repliesCountUpdate) { + updateInfos.push(repliesCountUpdate); + } + } return { rawMessageInfos: [textMessage], updateInfos,