Fix expiring call messages missing timer icon

This commit is contained in:
Jamie
2026-07-15 12:49:51 -07:00
committed by GitHub
parent 42c6fb92ed
commit 728cda4014
7 changed files with 226 additions and 129 deletions
+93 -31
View File
@@ -202,6 +202,7 @@ import type {
MaybeStaleCallHistory,
ExistingAttachmentData,
ExistingAttachmentUploadData,
GetUnreadCallMessagesAndMarkReadResult,
} from './Interface.std.ts';
import {
AttachmentDownloadSource,
@@ -672,9 +673,9 @@ export const DataWriter: ServerWritableInterface = {
_removeAllCallHistory,
markCallHistoryDeleted,
cleanupCallHistoryMessages,
markCallHistoryRead,
markAllCallHistoryRead,
markAllCallHistoryReadInConversation,
getUnreadCallMessageAndMarkRead,
getUnreadCallMessagesAndMarkRead,
getUnreadCallMessagesInConversationAndMarkRead,
saveCallHistory,
markCallHistoryMissed,
insertCallLink,
@@ -4877,22 +4878,6 @@ function getCallHistoryUnreadCount(db: ReadableDB): number {
return row ?? 0;
}
function markCallHistoryRead(db: WritableDB, callId: string): void {
const jsonPatch = JSON.stringify({
seenStatus: SeenStatus.Seen,
});
const [query, params] = sql`
UPDATE messages
SET
seenStatus = ${SEEN_STATUS_SEEN},
json = json_patch(json, ${jsonPatch})
WHERE type IS 'call-history'
AND callId IS ${callId}
`;
db.prepare(query).run(params);
}
function getCallHistoryForCallLogEventTarget(
db: ReadableDB,
target: CallLogEventTarget
@@ -5032,18 +5017,59 @@ function getMessageReceivedAtForCall(
return receivedAt;
}
export function markAllCallHistoryRead(
function getUnreadCallMessageAndMarkRead(
db: WritableDB,
callId: string,
readAt: number
): GetUnreadCallMessagesAndMarkReadResult | null {
const jsonPatch = JSON.stringify({
readStatus: ReadStatus.Read,
seenStatus: SeenStatus.Seen,
});
const [query, params] = sql`
UPDATE messages
SET
readStatus = ${READ_STATUS_READ},
seenStatus = ${SEEN_STATUS_SEEN},
json = json_patch(json, ${jsonPatch}),
expirationStartTimestamp = CASE
WHEN messages.hasExpireTimer IS 1
AND messages.expirationStartTimestamp IS NULL
THEN
${readAt}
ELSE
expirationStartTimestamp
END
WHERE messages.type IS 'call-history'
AND messages.callId IS ${callId}
RETURNING
messages.id,
messages.conversationId,
messages.readStatus,
messages.seenStatus,
messages.expirationStartTimestamp
`;
const result = db
.prepare(query)
.get<GetUnreadCallMessagesAndMarkReadResult>(params);
return result ?? null;
}
export function getUnreadCallMessagesAndMarkRead(
db: WritableDB,
target: CallLogEventTarget,
readAt: number,
activeCallIds: Set<string>,
inConversation = false
): number {
): ReadonlyArray<GetUnreadCallMessagesAndMarkReadResult> {
return db.transaction(() => {
const callHistory = getCallHistoryForCallLogEventTarget(db, target);
if (callHistory == null) {
logger.warn('markAllCallHistoryRead: Target call not found');
return 0;
return [];
}
const { callId } = callHistory;
@@ -5069,7 +5095,7 @@ export function markAllCallHistoryRead(
const conversationId = getConversationIdForCallHistory(db, callHistory);
if (conversationId == null) {
logger.warn('markAllCallHistoryRead: Conversation not found for call');
return 0;
return [];
}
logger.info(
@@ -5084,7 +5110,7 @@ export function markAllCallHistoryRead(
if (receivedAt == null) {
logger.warn('markAllCallHistoryRead: Message not found for call');
return 0;
return [];
}
const jsonPatch = JSON.stringify({
@@ -5096,6 +5122,15 @@ export function markAllCallHistoryRead(
`markAllCallHistoryRead: Marking calls before ${receivedAt} read`
);
const returning = sqlFragment`
RETURNING
messages.id,
messages.conversationId,
messages.readStatus,
messages.seenStatus,
messages.expirationStartTimestamp
`;
const [updateQuery, updateParams] = sql`
UPDATE messages
SET
@@ -5105,10 +5140,13 @@ export function markAllCallHistoryRead(
WHERE messages.type IS 'call-history'
AND ${predicate}
AND messages.seenStatus IS ${SEEN_STATUS_UNSEEN}
AND messages.received_at <= ${receivedAt};
AND messages.received_at <= ${receivedAt}
${returning}
`;
const result = db.prepare(updateQuery).run(updateParams);
const updateResult = db
.prepare(updateQuery)
.all<GetUnreadCallMessagesAndMarkReadResult>(updateParams);
const [updateExpirationQuery, updateExpirationParams] = sql`
UPDATE messages
@@ -5121,20 +5159,44 @@ export function markAllCallHistoryRead(
AND hasExpireTimer IS 1
AND expirationStartTimestamp IS NULL
AND messages.callId NOT IN (${sqlJoin(Array.from(activeCallIds))})
${returning}
`;
db.prepare(updateExpirationQuery).run(updateExpirationParams);
const updateExpirationResult = db
.prepare(updateExpirationQuery)
.all<GetUnreadCallMessagesAndMarkReadResult>(updateExpirationParams);
return result.changes;
const seen = new Set<string>();
const merged: Array<GetUnreadCallMessagesAndMarkReadResult> = [];
for (const item of updateExpirationResult) {
seen.add(item.id);
merged.push(item);
}
for (const item of updateResult) {
if (seen.has(item.id)) {
continue; // prefer data from the second update
}
merged.push(item);
}
return merged;
})();
}
function markAllCallHistoryReadInConversation(
function getUnreadCallMessagesInConversationAndMarkRead(
db: WritableDB,
target: CallLogEventTarget,
readAt: number,
activeCallIds: Set<string>
): number {
return markAllCallHistoryRead(db, target, readAt, activeCallIds, true);
): ReadonlyArray<GetUnreadCallMessagesAndMarkReadResult> {
return getUnreadCallMessagesAndMarkRead(
db,
target,
readAt,
activeCallIds,
true
);
}
function getCallHistoryGroupData(