Add expiration timer to pinned message notification

This commit is contained in:
Jamie
2026-01-13 10:12:10 -08:00
committed by GitHub
parent 8ca20a37ad
commit 897c051c99
6 changed files with 49 additions and 29 deletions

View File

@@ -2493,6 +2493,7 @@ export async function startApp(): Promise<void> {
targetAuthorAci: data.message.pinMessage.targetAuthorAci,
pinDuration: data.message.pinMessage.pinDuration,
pinnedByAci: data.sourceAci,
sentAtTimestamp: data.timestamp,
receivedAtTimestamp: data.receivedAtDate,
});
confirm();
@@ -3000,6 +3001,7 @@ export async function startApp(): Promise<void> {
targetAuthorAci: data.message.pinMessage.targetAuthorAci,
pinDuration: data.message.pinMessage.pinDuration,
pinnedByAci: sourceServiceId,
sentAtTimestamp: data.timestamp,
receivedAtTimestamp: data.receivedAtDate,
});
confirm();

View File

@@ -27,6 +27,7 @@ export type PinnedMessageAddProps = Readonly<{
targetAuthorAci: AciString;
pinDuration: DurationInSeconds | null;
pinnedByAci: AciString;
sentAtTimestamp: number;
receivedAtTimestamp: number;
}>;
@@ -115,12 +116,14 @@ export async function onPinnedMessageAdd(
drop(pinnedMessagesCleanupService.trigger('onPinnedMessageAdd'));
if (result.change?.inserted) {
await targetConversation.addNotification('pinned-message-notification', {
await targetConversation.addPinnedMessageNotification({
pinMessage: {
targetSentTimestamp: props.targetSentTimestamp,
targetAuthorAci: props.targetAuthorAci,
},
sourceServiceId: props.pinnedByAci,
senderAci: props.pinnedByAci,
sentAtTimestamp: props.sentAtTimestamp,
receivedAtTimestamp: props.receivedAtTimestamp,
});
}

View File

@@ -12,6 +12,7 @@ import type {
ConversationLastProfileType,
ConversationRenderInfoType,
MessageAttributesType,
PinMessageData,
QuotedMessageType,
SenderKeyInfoType,
SettableConversationAttributesType,
@@ -3561,6 +3562,36 @@ export class ConversationModel {
await maybeNotify({ message: message.attributes, conversation: this });
}
async addPinnedMessageNotification(params: {
pinMessage: PinMessageData;
senderAci: AciString;
sentAtTimestamp: number;
receivedAtTimestamp: number;
}): Promise<void> {
const ourAci = itemStorage.user.getCheckedAci();
const senderIsMe = params.senderAci === ourAci;
const message = new MessageModel({
...generateMessageId(incrementMessageCounter()),
conversationId: this.id,
type: 'pinned-message-notification',
sent_at: params.sentAtTimestamp,
received_at_ms: params.receivedAtTimestamp,
timestamp: params.sentAtTimestamp,
readStatus: senderIsMe ? ReadStatus.Read : ReadStatus.Unread,
seenStatus: senderIsMe ? SeenStatus.Seen : SeenStatus.Unseen,
sourceServiceId: params.senderAci,
expireTimer: this.get('expireTimer'),
expirationStartTimestamp: senderIsMe ? params.sentAtTimestamp : null,
pinMessage: params.pinMessage,
});
await window.MessageCache.saveMessage(message, { forceSave: true });
window.MessageCache.register(message);
drop(this.onNewMessage(message));
}
async addNotification(
type: MessageAttributesType['type'],
extra: Partial<MessageAttributesType> = {}

View File

@@ -3462,7 +3462,7 @@ function getUnreadByConversationAndMarkRead(
WHERE
conversationId = ${conversationId} AND
${storyReplyFilter} AND
type IN ('incoming', 'poll-terminate') AND
type IS NOT 'outgoing' AND
hasExpireTimer IS 1 AND
received_at <= ${readMessageReceivedAt}
`;
@@ -5901,16 +5901,11 @@ function getMessagesUnexpectedlyMissingExpirationStartTimestamp(
INDEXED BY messages_unexpectedly_missing_expiration_start_timestamp
WHERE
expireTimer > 0 AND
expirationStartTimestamp IS NULL AND
(
type IS 'outgoing' OR
(type IS 'incoming' AND (
readStatus = ${ReadStatus.Read} OR
readStatus = ${ReadStatus.Viewed} OR
readStatus IS NULL
)) OR
(type IS 'poll-terminate')
);
expirationStartTimestamp IS NULL AND (
readStatus = ${ReadStatus.Read} OR
readStatus = ${ReadStatus.Viewed} OR
readStatus IS NULL
)
`
)
.all();

View File

@@ -5218,12 +5218,14 @@ function onPinnedMessageAdd(
});
drop(pinnedMessagesCleanupService.trigger('onPinnedMessageAdd'));
await targetConversation.addNotification('pinned-message-notification', {
await targetConversation.addPinnedMessageNotification({
pinMessage: {
targetSentTimestamp: target.targetSentTimestamp,
targetAuthorAci: target.targetAuthorAci,
},
sourceServiceId: itemStorage.user.getCheckedAci(),
senderAci: itemStorage.user.getCheckedAci(),
sentAtTimestamp: pinnedAt,
receivedAtTimestamp: pinnedAt,
});
dispatch(onPinnedMessagesChanged(target.conversationId));

View File

@@ -251,7 +251,7 @@ export const _withSchemaVersion = ({
upgradedMessage = await upgrade(message, context);
} catch (error) {
logger.error(
`Message._withSchemaVersion: error updating message ${message.id},
`Message._withSchemaVersion: error updating message ${message.id},
attempt ${message.schemaMigrationAttempts}:`,
Errors.toLogFormat(error)
);
@@ -1121,20 +1121,7 @@ export async function migrateBodyAttachmentToDisk(
export const isUserMessage = (message: MessageAttributesType): boolean =>
message.type === 'incoming' || message.type === 'outgoing';
// NB: if adding more expiring message types, be sure to also update
// getUnreadByConversationAndMarkRead &
// getMessagesUnexpectedlyMissingExpirationStartTimestamp
export const EXPIRING_MESSAGE_TYPES = new Set([
'incoming',
'outgoing',
'poll-terminate',
]);
export const isExpiringMessage = (message: MessageAttributesType): boolean => {
if (!EXPIRING_MESSAGE_TYPES.has(message.type)) {
return false;
}
const { expireTimer } = message;
return typeof expireTimer === 'number' && expireTimer > 0;