Re-enable reaction notifications and improve message modifier typing
This commit is contained in:
parent
14861aff50
commit
54e252ecc2
7 changed files with 120 additions and 40 deletions
144
ts/background.ts
144
ts/background.ts
|
@ -20,6 +20,7 @@ import {
|
||||||
import type {
|
import type {
|
||||||
MessageAttributesType,
|
MessageAttributesType,
|
||||||
ConversationAttributesType,
|
ConversationAttributesType,
|
||||||
|
ReactionAttributesType,
|
||||||
} from './model-types.d';
|
} from './model-types.d';
|
||||||
import * as Bytes from './Bytes';
|
import * as Bytes from './Bytes';
|
||||||
import * as Timers from './Timers';
|
import * as Timers from './Timers';
|
||||||
|
@ -107,6 +108,12 @@ import { Reactions } from './messageModifiers/Reactions';
|
||||||
import { ReadSyncs } from './messageModifiers/ReadSyncs';
|
import { ReadSyncs } from './messageModifiers/ReadSyncs';
|
||||||
import { ViewSyncs } from './messageModifiers/ViewSyncs';
|
import { ViewSyncs } from './messageModifiers/ViewSyncs';
|
||||||
import { ViewOnceOpenSyncs } from './messageModifiers/ViewOnceOpenSyncs';
|
import { ViewOnceOpenSyncs } from './messageModifiers/ViewOnceOpenSyncs';
|
||||||
|
import type { DeleteAttributesType } from './messageModifiers/Deletes';
|
||||||
|
import type { MessageReceiptAttributesType } from './messageModifiers/MessageReceipts';
|
||||||
|
import type { MessageRequestAttributesType } from './messageModifiers/MessageRequests';
|
||||||
|
import type { ReadSyncAttributesType } from './messageModifiers/ReadSyncs';
|
||||||
|
import type { ViewSyncAttributesType } from './messageModifiers/ViewSyncs';
|
||||||
|
import type { ViewOnceOpenSyncAttributesType } from './messageModifiers/ViewOnceOpenSyncs';
|
||||||
import { ReadStatus } from './messages/MessageReadStatus';
|
import { ReadStatus } from './messages/MessageReadStatus';
|
||||||
import type { SendStateByConversationId } from './messages/MessageSendState';
|
import type { SendStateByConversationId } from './messages/MessageSendState';
|
||||||
import { SendStatus } from './messages/MessageSendState';
|
import { SendStatus } from './messages/MessageSendState';
|
||||||
|
@ -120,8 +127,8 @@ import { onRetryRequest, onDecryptionError } from './util/handleRetry';
|
||||||
import { themeChanged } from './shims/themeChanged';
|
import { themeChanged } from './shims/themeChanged';
|
||||||
import { createIPCEvents } from './util/createIPCEvents';
|
import { createIPCEvents } from './util/createIPCEvents';
|
||||||
import { RemoveAllConfiguration } from './types/RemoveAllConfiguration';
|
import { RemoveAllConfiguration } from './types/RemoveAllConfiguration';
|
||||||
|
import { isValidUuid, UUIDKind } from './types/UUID';
|
||||||
import type { UUID } from './types/UUID';
|
import type { UUID } from './types/UUID';
|
||||||
import { UUIDKind } from './types/UUID';
|
|
||||||
import * as log from './logging/log';
|
import * as log from './logging/log';
|
||||||
import {
|
import {
|
||||||
loadRecentEmojis,
|
loadRecentEmojis,
|
||||||
|
@ -136,6 +143,7 @@ import { showToast } from './util/showToast';
|
||||||
import { startInteractionMode } from './windows/startInteractionMode';
|
import { startInteractionMode } from './windows/startInteractionMode';
|
||||||
import { deliveryReceiptsJobQueue } from './jobs/deliveryReceiptsJobQueue';
|
import { deliveryReceiptsJobQueue } from './jobs/deliveryReceiptsJobQueue';
|
||||||
import { updateOurUsername } from './util/updateOurUsername';
|
import { updateOurUsername } from './util/updateOurUsername';
|
||||||
|
import { ReactionSource } from './reactions/ReactionSource';
|
||||||
|
|
||||||
const MAX_ATTACHMENT_DOWNLOAD_AGE = 3600 * 72 * 1000;
|
const MAX_ATTACHMENT_DOWNLOAD_AGE = 3600 * 72 * 1000;
|
||||||
|
|
||||||
|
@ -2878,18 +2886,27 @@ export async function startApp(): Promise<void> {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strictAssert(
|
||||||
|
reaction.targetTimestamp,
|
||||||
|
'Reaction without targetTimestamp'
|
||||||
|
);
|
||||||
|
const fromId = window.ConversationController.ensureContactIds({
|
||||||
|
e164: data.source,
|
||||||
|
uuid: data.sourceUuid,
|
||||||
|
});
|
||||||
|
strictAssert(fromId, 'Reaction without fromId');
|
||||||
|
|
||||||
log.info('Queuing incoming reaction for', reaction.targetTimestamp);
|
log.info('Queuing incoming reaction for', reaction.targetTimestamp);
|
||||||
const reactionModel = Reactions.getSingleton().add({
|
const attributes: ReactionAttributesType = {
|
||||||
emoji: reaction.emoji,
|
emoji: reaction.emoji,
|
||||||
remove: reaction.remove,
|
remove: reaction.remove,
|
||||||
targetAuthorUuid,
|
targetAuthorUuid,
|
||||||
targetTimestamp: reaction.targetTimestamp,
|
targetTimestamp: reaction.targetTimestamp,
|
||||||
timestamp,
|
timestamp,
|
||||||
fromId: window.ConversationController.ensureContactIds({
|
fromId,
|
||||||
e164: data.source,
|
source: ReactionSource.FromSomeoneElse,
|
||||||
uuid: data.sourceUuid,
|
};
|
||||||
}),
|
const reactionModel = Reactions.getSingleton().add(attributes);
|
||||||
});
|
|
||||||
// Note: We do not wait for completion here
|
// Note: We do not wait for completion here
|
||||||
Reactions.getSingleton().onReaction(reactionModel);
|
Reactions.getSingleton().onReaction(reactionModel);
|
||||||
confirm();
|
confirm();
|
||||||
|
@ -2899,16 +2916,28 @@ export async function startApp(): Promise<void> {
|
||||||
if (data.message.delete) {
|
if (data.message.delete) {
|
||||||
const { delete: del } = data.message;
|
const { delete: del } = data.message;
|
||||||
log.info('Queuing incoming DOE for', del.targetSentTimestamp);
|
log.info('Queuing incoming DOE for', del.targetSentTimestamp);
|
||||||
const deleteModel = Deletes.getSingleton().add({
|
|
||||||
|
strictAssert(
|
||||||
|
del.targetSentTimestamp,
|
||||||
|
'Delete missing targetSentTimestamp'
|
||||||
|
);
|
||||||
|
strictAssert(data.serverTimestamp, 'Delete missing serverTimestamp');
|
||||||
|
const fromId = window.ConversationController.ensureContactIds({
|
||||||
|
e164: data.source,
|
||||||
|
uuid: data.sourceUuid,
|
||||||
|
});
|
||||||
|
strictAssert(fromId, 'Delete missing fromId');
|
||||||
|
|
||||||
|
const attributes: DeleteAttributesType = {
|
||||||
targetSentTimestamp: del.targetSentTimestamp,
|
targetSentTimestamp: del.targetSentTimestamp,
|
||||||
serverTimestamp: data.serverTimestamp,
|
serverTimestamp: data.serverTimestamp,
|
||||||
fromId: window.ConversationController.ensureContactIds({
|
fromId,
|
||||||
e164: data.source,
|
};
|
||||||
uuid: data.sourceUuid,
|
const deleteModel = Deletes.getSingleton().add(attributes);
|
||||||
}),
|
|
||||||
});
|
|
||||||
// Note: We do not wait for completion here
|
// Note: We do not wait for completion here
|
||||||
Deletes.getSingleton().onDelete(deleteModel);
|
Deletes.getSingleton().onDelete(deleteModel);
|
||||||
|
|
||||||
confirm();
|
confirm();
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
@ -3218,6 +3247,10 @@ export async function startApp(): Promise<void> {
|
||||||
);
|
);
|
||||||
|
|
||||||
const { reaction, timestamp } = data.message;
|
const { reaction, timestamp } = data.message;
|
||||||
|
strictAssert(
|
||||||
|
reaction.targetTimestamp,
|
||||||
|
'Reaction without targetAuthorUuid'
|
||||||
|
);
|
||||||
|
|
||||||
if (!isValidReactionEmoji(reaction.emoji)) {
|
if (!isValidReactionEmoji(reaction.emoji)) {
|
||||||
log.warn('Received an invalid reaction emoji. Dropping it');
|
log.warn('Received an invalid reaction emoji. Dropping it');
|
||||||
|
@ -3226,15 +3259,16 @@ export async function startApp(): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info('Queuing sent reaction for', reaction.targetTimestamp);
|
log.info('Queuing sent reaction for', reaction.targetTimestamp);
|
||||||
const reactionModel = Reactions.getSingleton().add({
|
const attributes: ReactionAttributesType = {
|
||||||
emoji: reaction.emoji,
|
emoji: reaction.emoji,
|
||||||
remove: reaction.remove,
|
remove: reaction.remove,
|
||||||
targetAuthorUuid,
|
targetAuthorUuid,
|
||||||
targetTimestamp: reaction.targetTimestamp,
|
targetTimestamp: reaction.targetTimestamp,
|
||||||
timestamp,
|
timestamp,
|
||||||
fromId: window.ConversationController.getOurConversationId(),
|
fromId: window.ConversationController.getOurConversationIdOrThrow(),
|
||||||
fromSync: true,
|
source: ReactionSource.FromSync,
|
||||||
});
|
};
|
||||||
|
const reactionModel = Reactions.getSingleton().add(attributes);
|
||||||
// Note: We do not wait for completion here
|
// Note: We do not wait for completion here
|
||||||
Reactions.getSingleton().onReaction(reactionModel);
|
Reactions.getSingleton().onReaction(reactionModel);
|
||||||
|
|
||||||
|
@ -3244,12 +3278,20 @@ export async function startApp(): Promise<void> {
|
||||||
|
|
||||||
if (data.message.delete) {
|
if (data.message.delete) {
|
||||||
const { delete: del } = data.message;
|
const { delete: del } = data.message;
|
||||||
|
strictAssert(
|
||||||
|
del.targetSentTimestamp,
|
||||||
|
'Delete without targetSentTimestamp'
|
||||||
|
);
|
||||||
|
strictAssert(data.serverTimestamp, 'Data has no serverTimestamp');
|
||||||
|
|
||||||
log.info('Queuing sent DOE for', del.targetSentTimestamp);
|
log.info('Queuing sent DOE for', del.targetSentTimestamp);
|
||||||
const deleteModel = Deletes.getSingleton().add({
|
|
||||||
|
const attributes: DeleteAttributesType = {
|
||||||
targetSentTimestamp: del.targetSentTimestamp,
|
targetSentTimestamp: del.targetSentTimestamp,
|
||||||
serverTimestamp: data.serverTimestamp,
|
serverTimestamp: data.serverTimestamp,
|
||||||
fromId: window.ConversationController.getOurConversationId(),
|
fromId: window.ConversationController.getOurConversationIdOrThrow(),
|
||||||
});
|
};
|
||||||
|
const deleteModel = Deletes.getSingleton().add(attributes);
|
||||||
// Note: We do not wait for completion here
|
// Note: We do not wait for completion here
|
||||||
Deletes.getSingleton().onDelete(deleteModel);
|
Deletes.getSingleton().onDelete(deleteModel);
|
||||||
confirm();
|
confirm();
|
||||||
|
@ -3425,12 +3467,16 @@ export async function startApp(): Promise<void> {
|
||||||
|
|
||||||
const { source, sourceUuid, timestamp } = ev;
|
const { source, sourceUuid, timestamp } = ev;
|
||||||
log.info(`view once open sync ${source} ${timestamp}`);
|
log.info(`view once open sync ${source} ${timestamp}`);
|
||||||
|
strictAssert(source, 'ViewOnceOpen without source');
|
||||||
|
strictAssert(sourceUuid, 'ViewOnceOpen without sourceUuid');
|
||||||
|
strictAssert(timestamp, 'ViewOnceOpen without timestamp');
|
||||||
|
|
||||||
const sync = ViewOnceOpenSyncs.getSingleton().add({
|
const attributes: ViewOnceOpenSyncAttributesType = {
|
||||||
source,
|
source,
|
||||||
sourceUuid,
|
sourceUuid,
|
||||||
timestamp,
|
timestamp,
|
||||||
});
|
};
|
||||||
|
const sync = ViewOnceOpenSyncs.getSingleton().add(attributes);
|
||||||
|
|
||||||
ViewOnceOpenSyncs.getSingleton().onSync(sync);
|
ViewOnceOpenSyncs.getSingleton().onSync(sync);
|
||||||
}
|
}
|
||||||
|
@ -3501,13 +3547,19 @@ export async function startApp(): Promise<void> {
|
||||||
messageRequestResponseType,
|
messageRequestResponseType,
|
||||||
});
|
});
|
||||||
|
|
||||||
const sync = MessageRequests.getSingleton().add({
|
strictAssert(
|
||||||
|
messageRequestResponseType,
|
||||||
|
'onMessageRequestResponse: missing type'
|
||||||
|
);
|
||||||
|
|
||||||
|
const attributes: MessageRequestAttributesType = {
|
||||||
threadE164,
|
threadE164,
|
||||||
threadUuid,
|
threadUuid,
|
||||||
groupId,
|
groupId,
|
||||||
groupV2Id,
|
groupV2Id,
|
||||||
type: messageRequestResponseType,
|
type: messageRequestResponseType,
|
||||||
});
|
};
|
||||||
|
const sync = MessageRequests.getSingleton().add(attributes);
|
||||||
|
|
||||||
MessageRequests.getSingleton().onResponse(sync);
|
MessageRequests.getSingleton().onResponse(sync);
|
||||||
}
|
}
|
||||||
|
@ -3563,14 +3615,21 @@ export async function startApp(): Promise<void> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const receipt = MessageReceipts.getSingleton().add({
|
strictAssert(
|
||||||
|
isValidUuid(sourceUuid),
|
||||||
|
'onReadOrViewReceipt: Missing sourceUuid'
|
||||||
|
);
|
||||||
|
strictAssert(sourceDevice, 'onReadOrViewReceipt: Missing sourceDevice');
|
||||||
|
|
||||||
|
const attributes: MessageReceiptAttributesType = {
|
||||||
messageSentAt: timestamp,
|
messageSentAt: timestamp,
|
||||||
receiptTimestamp: envelopeTimestamp,
|
receiptTimestamp: envelopeTimestamp,
|
||||||
sourceConversationId,
|
sourceConversationId,
|
||||||
sourceUuid,
|
sourceUuid,
|
||||||
sourceDevice,
|
sourceDevice,
|
||||||
type,
|
type,
|
||||||
});
|
};
|
||||||
|
const receipt = MessageReceipts.getSingleton().add(attributes);
|
||||||
|
|
||||||
// Note: We do not wait for completion here
|
// Note: We do not wait for completion here
|
||||||
MessageReceipts.getSingleton().onReceipt(receipt);
|
MessageReceipts.getSingleton().onReceipt(receipt);
|
||||||
|
@ -3594,13 +3653,18 @@ export async function startApp(): Promise<void> {
|
||||||
timestamp
|
timestamp
|
||||||
);
|
);
|
||||||
|
|
||||||
const receipt = ReadSyncs.getSingleton().add({
|
strictAssert(senderId, 'onReadSync missing senderId');
|
||||||
|
strictAssert(senderUuid, 'onReadSync missing senderUuid');
|
||||||
|
strictAssert(timestamp, 'onReadSync missing timestamp');
|
||||||
|
|
||||||
|
const attributes: ReadSyncAttributesType = {
|
||||||
senderId,
|
senderId,
|
||||||
sender,
|
sender,
|
||||||
senderUuid,
|
senderUuid,
|
||||||
timestamp,
|
timestamp,
|
||||||
readAt,
|
readAt,
|
||||||
});
|
};
|
||||||
|
const receipt = ReadSyncs.getSingleton().add(attributes);
|
||||||
|
|
||||||
receipt.on('remove', ev.confirm);
|
receipt.on('remove', ev.confirm);
|
||||||
|
|
||||||
|
@ -3626,13 +3690,18 @@ export async function startApp(): Promise<void> {
|
||||||
timestamp
|
timestamp
|
||||||
);
|
);
|
||||||
|
|
||||||
const receipt = ViewSyncs.getSingleton().add({
|
strictAssert(senderId, 'onViewSync missing senderId');
|
||||||
|
strictAssert(senderUuid, 'onViewSync missing senderUuid');
|
||||||
|
strictAssert(timestamp, 'onViewSync missing timestamp');
|
||||||
|
|
||||||
|
const attributes: ViewSyncAttributesType = {
|
||||||
senderId,
|
senderId,
|
||||||
senderE164,
|
senderE164,
|
||||||
senderUuid,
|
senderUuid,
|
||||||
timestamp,
|
timestamp,
|
||||||
viewedAt: envelopeTimestamp,
|
viewedAt: envelopeTimestamp,
|
||||||
});
|
};
|
||||||
|
const receipt = ViewSyncs.getSingleton().add(attributes);
|
||||||
|
|
||||||
receipt.on('remove', ev.confirm);
|
receipt.on('remove', ev.confirm);
|
||||||
|
|
||||||
|
@ -3742,14 +3811,25 @@ export async function startApp(): Promise<void> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const receipt = MessageReceipts.getSingleton().add({
|
strictAssert(
|
||||||
|
envelopeTimestamp,
|
||||||
|
'onDeliveryReceipt: missing envelopeTimestamp'
|
||||||
|
);
|
||||||
|
strictAssert(
|
||||||
|
isValidUuid(sourceUuid),
|
||||||
|
'onDeliveryReceipt: missing valid sourceUuid'
|
||||||
|
);
|
||||||
|
strictAssert(sourceDevice, 'onDeliveryReceipt: missing sourceDevice');
|
||||||
|
|
||||||
|
const attributes: MessageReceiptAttributesType = {
|
||||||
messageSentAt: timestamp,
|
messageSentAt: timestamp,
|
||||||
receiptTimestamp: envelopeTimestamp,
|
receiptTimestamp: envelopeTimestamp,
|
||||||
sourceConversationId,
|
sourceConversationId,
|
||||||
sourceUuid,
|
sourceUuid,
|
||||||
sourceDevice,
|
sourceDevice,
|
||||||
type: MessageReceiptType.Delivery,
|
type: MessageReceiptType.Delivery,
|
||||||
});
|
};
|
||||||
|
const receipt = MessageReceipts.getSingleton().add(attributes);
|
||||||
|
|
||||||
// Note: We don't wait for completion here
|
// Note: We don't wait for completion here
|
||||||
MessageReceipts.getSingleton().onReceipt(receipt);
|
MessageReceipts.getSingleton().onReceipt(receipt);
|
||||||
|
|
|
@ -8,7 +8,7 @@ import type { MessageModel } from '../models/messages';
|
||||||
import { getContactId } from '../messages/helpers';
|
import { getContactId } from '../messages/helpers';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
|
|
||||||
type DeleteAttributesType = {
|
export type DeleteAttributesType = {
|
||||||
targetSentTimestamp: number;
|
targetSentTimestamp: number;
|
||||||
serverTimestamp: number;
|
serverTimestamp: number;
|
||||||
fromId: string;
|
fromId: string;
|
||||||
|
|
|
@ -32,7 +32,7 @@ export enum MessageReceiptType {
|
||||||
View = 'View',
|
View = 'View',
|
||||||
}
|
}
|
||||||
|
|
||||||
type MessageReceiptAttributesType = {
|
export type MessageReceiptAttributesType = {
|
||||||
messageSentAt: number;
|
messageSentAt: number;
|
||||||
receiptTimestamp: number;
|
receiptTimestamp: number;
|
||||||
sourceUuid: UUIDStringType;
|
sourceUuid: UUIDStringType;
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { Collection, Model } from 'backbone';
|
||||||
import type { ConversationModel } from '../models/conversations';
|
import type { ConversationModel } from '../models/conversations';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
|
|
||||||
type MessageRequestAttributesType = {
|
export type MessageRequestAttributesType = {
|
||||||
threadE164?: string;
|
threadE164?: string;
|
||||||
threadUuid?: string;
|
threadUuid?: string;
|
||||||
groupId?: string;
|
groupId?: string;
|
||||||
|
|
|
@ -11,9 +11,9 @@ import { isMessageUnread } from '../util/isMessageUnread';
|
||||||
import { notificationService } from '../services/notifications';
|
import { notificationService } from '../services/notifications';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
|
|
||||||
type ReadSyncAttributesType = {
|
export type ReadSyncAttributesType = {
|
||||||
senderId: string;
|
senderId: string;
|
||||||
sender: string;
|
sender?: string;
|
||||||
senderUuid: string;
|
senderUuid: string;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
readAt: number;
|
readAt: number;
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { Collection, Model } from 'backbone';
|
||||||
import type { MessageModel } from '../models/messages';
|
import type { MessageModel } from '../models/messages';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
|
|
||||||
type ViewOnceOpenSyncAttributesType = {
|
export type ViewOnceOpenSyncAttributesType = {
|
||||||
source?: string;
|
source?: string;
|
||||||
sourceUuid: string;
|
sourceUuid: string;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
|
|
|
@ -12,9 +12,9 @@ import { isIncoming } from '../state/selectors/message';
|
||||||
import { notificationService } from '../services/notifications';
|
import { notificationService } from '../services/notifications';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
|
|
||||||
type ViewSyncAttributesType = {
|
export type ViewSyncAttributesType = {
|
||||||
senderId: string;
|
senderId: string;
|
||||||
senderE164: string;
|
senderE164?: string;
|
||||||
senderUuid: string;
|
senderUuid: string;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
viewedAt: number;
|
viewedAt: number;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue