diff --git a/ts/components/conversation/message/message-item/GroupUpdateMessage.tsx b/ts/components/conversation/message/message-item/GroupUpdateMessage.tsx
index 96afe7bc3..ff6e7f99c 100644
--- a/ts/components/conversation/message/message-item/GroupUpdateMessage.tsx
+++ b/ts/components/conversation/message/message-item/GroupUpdateMessage.tsx
@@ -5,7 +5,7 @@ import {
PropsForGroupUpdateType,
} from '../../../../state/ducks/conversations';
import { NotificationBubble } from './notification-bubble/NotificationBubble';
-import { ReadableMessage } from './ReadableMessage';
+import { ExpirableReadableMessage } from './ExpirableReadableMessage';
import { arrayContainsUsOnly } from '../../../../models/message';
import { useConversationsUsernameWithQuoteOrFullPubkey } from '../../../../hooks/useParamSelector';
@@ -71,16 +71,29 @@ const ChangeItem = (change: PropsForGroupUpdateType): string => {
};
export const GroupUpdateMessage = (props: PropsForGroupUpdate) => {
- const { change, messageId, receivedAt, isUnread } = props;
+ const {
+ change,
+ messageId,
+ receivedAt,
+ isUnread,
+ direction,
+ expirationLength,
+ expirationTimestamp,
+ isExpired,
+ } = props;
return (
-
-
+
);
};
diff --git a/ts/interactions/conversationInteractions.ts b/ts/interactions/conversationInteractions.ts
index c9b2f21e5..9ed727b46 100644
--- a/ts/interactions/conversationInteractions.ts
+++ b/ts/interactions/conversationInteractions.ts
@@ -362,6 +362,7 @@ export async function setDisappearingMessagesByConvoId(
if (!expirationType || expirationType === 'off' || !seconds || seconds <= 0) {
await conversation.updateExpireTimer({
providedExpirationType: 'off',
+ providedExpireTimer: 0,
providedChangeTimestamp,
});
} else {
diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts
index 393bd2867..2665e697f 100644
--- a/ts/models/conversation.ts
+++ b/ts/models/conversation.ts
@@ -1036,17 +1036,20 @@ export class ConversationModel extends Backbone.Model {
receivedAt, // is set if it comes from outside
fromSync,
shouldCommit = true,
+ existingMessage,
}: {
providedExpirationType: DisappearingMessageConversationType;
providedExpireTimer?: number;
- providedChangeTimestamp?: number;
+ providedChangeTimestamp: number;
providedSource?: string;
receivedAt?: number; // is set if it comes from outside
fromSync?: boolean;
shouldCommit?: boolean;
+ existingMessage?: MessageModel;
}): Promise {
let expirationType = providedExpirationType;
let expireTimer = providedExpireTimer;
+ const lastDisappearingMessageChangeTimestamp = providedChangeTimestamp;
let source = providedSource;
defaults({ fromSync }, { fromSync: false });
@@ -1057,12 +1060,19 @@ export class ConversationModel extends Backbone.Model {
}
// TODO does this actually work?
+ if (
+ this.get('lastDisappearingMessageChangeTimestamp') > lastDisappearingMessageChangeTimestamp
+ ) {
+ window.log.info('WIP: updateExpireTimer() This is an outdated disappearing message setting');
+ return;
+ }
+
if (
isEqual(expirationType, this.get('expirationType')) &&
isEqual(expireTimer, this.get('expireTimer'))
) {
window.log.info(
- 'WIP: Dropping ExpireTimerUpdate message as we already have the same one set.'
+ 'WIP:updateExpireTimer() Dropping ExpireTimerUpdate message as we already have the same one set.'
);
return;
}
@@ -1077,17 +1087,17 @@ export class ConversationModel extends Backbone.Model {
this.set({
expirationType,
expireTimer,
- lastDisappearingMessageChangeTimestamp: providedChangeTimestamp || undefined,
+ lastDisappearingMessageChangeTimestamp,
});
- window?.log?.info('WIP: Updated conversation disappearing messages setting', {
+ window?.log?.info('WIP: Updating conversation disappearing messages setting', {
id: this.idForLogging(),
expirationType,
expireTimer,
+ lastDisappearingMessageChangeTimestamp,
source,
});
- const lastDisappearingMessageChangeTimestamp = providedChangeTimestamp || 0;
const commonAttributes = {
flags: SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE,
expirationTimerUpdate: {
@@ -1097,28 +1107,30 @@ export class ConversationModel extends Backbone.Model {
source,
fromSync,
},
- expirationType,
- expireTimer,
+ expirationType: expirationType !== 'off' ? expirationType : undefined,
+ expireTimer: expirationType !== 'off' ? expireTimer : undefined,
};
- let message: MessageModel | undefined;
+ let message: MessageModel | undefined = existingMessage || undefined;
- if (isOutgoing) {
- message = await this.addSingleOutgoingMessage({
- ...commonAttributes,
- sent_at: timestamp,
- });
- } else {
- // TODO do we still want to handle expiration in incoming messages?
- message = await this.addSingleIncomingMessage({
- ...commonAttributes,
- // Even though this isn't reflected to the user, we want to place the last seen
- // indicator above it. We set it to 'unread' to trigger that placement.
- unread: 1,
- source,
- sent_at: timestamp,
- received_at: timestamp,
- });
+ if (!message) {
+ if (isOutgoing) {
+ message = await this.addSingleOutgoingMessage({
+ ...commonAttributes,
+ sent_at: timestamp,
+ });
+ } else {
+ // TODO do we still want to handle expiration in incoming messages?
+ message = await this.addSingleIncomingMessage({
+ ...commonAttributes,
+ // Even though this isn't reflected to the user, we want to place the last seen
+ // indicator above it. We set it to 'unread' to trigger that placement.
+ unread: 1,
+ source,
+ sent_at: timestamp,
+ received_at: timestamp,
+ });
+ }
}
if (this.isActive()) {
@@ -1144,6 +1156,7 @@ export class ConversationModel extends Backbone.Model {
if (this.isMe()) {
// TODO Check that the args are correct
+ // This might be happening too late in the message pipeline. Maybe should be moved to handleExpirationTimerUpdateNoCommit()
if (expireUpdate.expirationType === 'deleteAfterRead') {
window.log.info('WIP: Note to Self messages cannot be delete after read!');
return;
@@ -1159,7 +1172,6 @@ export class ConversationModel extends Backbone.Model {
const pubkey = new PubKey(this.get('id'));
await getMessageQueue().sendToPubKey(pubkey, expirationTimerMessage);
} else {
- // TODO Check that the args are correct
// Cannot be an open group
window?.log?.warn('TODO: Expiration update for closed groups are to be updated');
const expireUpdateForGroup = {
diff --git a/ts/models/message.ts b/ts/models/message.ts
index 70b9e89ed..b59a18957 100644
--- a/ts/models/message.ts
+++ b/ts/models/message.ts
@@ -250,18 +250,12 @@ export class MessageModel extends Backbone.Model {
return window.i18n('mediaMessage');
}
if (this.isExpirationTimerUpdate()) {
- // Backwards compatibility for Disappearing Messages in old clients
+ // TODO Backwards compatibility for Disappearing Messages in old clients
+ // TODO What does this comment refer to mean?
const expireTimerUpdate = this.get('expirationTimerUpdate');
- const expirationType = this.get('expirationType');
- const expireTimer = this.get('expireTimer');
- if (
- !expireTimerUpdate ||
- expireTimerUpdate.expirationType === 'off' ||
- !expireTimerUpdate.expireTimer ||
- expirationType === 'off' ||
- !expireTimer ||
- expireTimer === 0
- ) {
+ const expirationType = expireTimerUpdate?.expirationType;
+ const expireTimer = expireTimerUpdate?.expireTimer;
+ if (!expireTimerUpdate || expirationType === 'off' || !expireTimer || expireTimer === 0) {
return window.i18n('disappearingMessagesDisabled');
}
@@ -417,6 +411,7 @@ export class MessageModel extends Backbone.Model {
messageId: this.id,
isUnread: this.isUnread(),
receivedAt: this.get('received_at'),
+ ...this.getPropsForExpiringMessage(),
};
if (groupUpdate.joined?.length) {
@@ -1063,20 +1058,20 @@ export class MessageModel extends Backbone.Model {
}
public async sendSyncMessageOnly(dataMessage: DataMessage) {
+ const contentMessage = dataMessage.contentProto();
const now = Date.now();
+
this.set({
sent_to: [UserUtils.getOurPubKeyStrFromCache()],
sent: true,
- // NOTE if disappearing message is deleteAfterRead then we don't use this
- expirationStartTimestamp: now,
});
- const contentMessage = dataMessage.contentProto();
let expireUpdate = null;
+ const expirationType = dataMessage.getDisappearingMessageType();
- if (contentMessage.expirationType && contentMessage.expirationTimer) {
+ if (expirationType && contentMessage.expirationTimer) {
expireUpdate = {
- expirationType: contentMessage.expirationType,
+ expirationType,
expireTimer: contentMessage.expirationTimer,
lastDisappearingMessageChangeTimestamp:
contentMessage.lastDisappearingMessageChangeTimestamp,
@@ -1091,6 +1086,7 @@ export class MessageModel extends Backbone.Model {
public async sendSyncMessage(
data: DataMessage | SignalService.DataMessage,
sentTimestamp: number,
+ // TODO add proper types
expireUpdate?: any
) {
if (this.get('synced') || this.get('sentSync')) {
@@ -1174,6 +1170,7 @@ export class MessageModel extends Backbone.Model {
await this.commit();
// the line below makes sure that getNextExpiringMessage will find this message as expiring.
// getNextExpiringMessage is used on app start to clean already expired messages which should have been removed already, but are not
+
await this.setToExpire();
const convo = this.getConversation();
diff --git a/ts/receiver/contentMessage.ts b/ts/receiver/contentMessage.ts
index df4d62c23..7577e29cd 100644
--- a/ts/receiver/contentMessage.ts
+++ b/ts/receiver/contentMessage.ts
@@ -3,7 +3,7 @@ import { handleSwarmDataMessage } from './dataMessage';
import { removeFromCache, updateCache } from './cache';
import { SignalService } from '../protobuf';
-import { compact, flatten, identity, isEmpty, pickBy, toNumber } from 'lodash';
+import { compact, flatten, identity, isEmpty, isEqual, pickBy, toNumber } from 'lodash';
import { KeyPrefixType, PubKey } from '../session/types';
import { BlockedNumberController } from '../util/blockedNumberController';
@@ -406,31 +406,28 @@ export async function innerHandleSwarmContentMessage(
perfStart(`handleSwarmDataMessage-${envelope.id}`);
- let expireUpdate = null;
-
- const expirationType =
- DisappearingMessageConversationSetting[content.expirationType] || 'off';
- let expireTimer = content.expirationTimer || 0;
+ const expireUpdate = {
+ expirationType: DisappearingMessageConversationSetting[content.expirationType] || 'off',
+ // TODO rename to expirationTimer?
+ expireTimer: content.expirationTimer || 0,
+ // This is used for the expirationTimerUpdate
+ lastDisappearingMessageChangeTimestamp: content.lastDisappearingMessageChangeTimestamp
+ ? Number(content.lastDisappearingMessageChangeTimestamp)
+ : undefined,
+ };
// TODO in the future we will remove the dataMessage expireTimer
// Backwards compatibility for Disappearing Messages in old clients
- if (dataMessage.expireTimer) {
+ if (
+ expireUpdate.expireTimer > 0 &&
+ dataMessage.expireTimer &&
+ !isEqual(expireUpdate.expireTimer, dataMessage.expireTimer)
+ ) {
// TODO Trigger banner in UI?
- expireTimer = dataMessage.expireTimer;
+ expireUpdate.expireTimer = dataMessage.expireTimer;
window.log.info('WIP: Received outdated disappearing message data message', content);
}
- // NOTE In the protobuf this is a long
- const lastDisappearingMessageChangeTimestamp =
- Number(content.lastDisappearingMessageChangeTimestamp) || null;
-
- expireUpdate = {
- expirationType,
- // TODO rename to expirationTimer?
- expireTimer,
- lastDisappearingMessageChangeTimestamp,
- };
-
await handleSwarmDataMessage(
envelope,
sentAtTimestamp,
diff --git a/ts/receiver/dataMessage.ts b/ts/receiver/dataMessage.ts
index 554b8b759..92cac808f 100644
--- a/ts/receiver/dataMessage.ts
+++ b/ts/receiver/dataMessage.ts
@@ -154,7 +154,8 @@ export async function handleSwarmDataMessage(
rawDataMessage: SignalService.DataMessage,
messageHash: string,
senderConversationModel: ConversationModel,
- expireUpdate: any
+ // TODO add proper types
+ expireUpdate?: any
): Promise {
window.log.info('handleSwarmDataMessage');
@@ -245,6 +246,25 @@ export async function handleSwarmDataMessage(
if (isSyncedMessage) {
// TODO handle sync messages separately
window.log.info('WIP: Sync Message dropping');
+ } else {
+ const { expirationType, expireTimer, lastDisappearingMessageChangeTimestamp } = expireUpdate;
+
+ msgModel.set({
+ expirationType,
+ expireTimer,
+ });
+
+ // This message is conversation setting change message
+ if (expireUpdate.lastDisappearingMessageChangeTimestamp) {
+ msgModel.set({
+ expirationTimerUpdate: {
+ expirationType,
+ expireTimer,
+ lastDisappearingMessageChangeTimestamp,
+ source: msgModel.get('source'),
+ },
+ });
+ }
}
await handleSwarmMessage(
@@ -253,8 +273,7 @@ export async function handleSwarmDataMessage(
sentAtTimestamp,
cleanDataMessage,
convoToAddMessageTo,
- () => removeFromCache(envelope),
- isSyncedMessage ? expireUpdate : null
+ () => removeFromCache(envelope)
);
}
@@ -301,8 +320,7 @@ async function handleSwarmMessage(
sentAt: number,
rawDataMessage: SignalService.DataMessage,
convoToAddMessageTo: ConversationModel,
- confirm: () => void,
- expireUpdate?: any
+ confirm: () => void
): Promise {
if (!rawDataMessage || !msgModel) {
window?.log?.warn('Invalid data passed to handleSwarmMessage.');
@@ -350,8 +368,7 @@ async function handleSwarmMessage(
toRegularMessage(rawDataMessage),
confirm,
msgModel.get('source'),
- messageHash,
- expireUpdate
+ messageHash
);
});
}
diff --git a/ts/receiver/queuedJob.ts b/ts/receiver/queuedJob.ts
index aa64de826..9b83d37e8 100644
--- a/ts/receiver/queuedJob.ts
+++ b/ts/receiver/queuedJob.ts
@@ -1,7 +1,7 @@
import { queueAttachmentDownloads } from './attachments';
import { Quote } from './types';
-import _, { isEmpty, isEqual } from 'lodash';
+import _, { isEqual } from 'lodash';
import { getConversationController } from '../session/conversations';
import { ConversationModel } from '../models/conversation';
import { MessageModel, sliceQuoteText } from '../models/message';
@@ -308,16 +308,9 @@ async function handleExpirationTimerUpdateNoCommit(
message: MessageModel,
source: string,
expirationType: DisappearingMessageConversationType,
- expireTimer: number
+ expireTimer: number,
+ lastDisappearingMessageChangeTimestamp: number
) {
- const providedChangeTimestamp = getNowWithNetworkOffset();
-
- // TODO Not entirely sure that this works
- if (conversation.get('lastDisappearingMessageChangeTimestamp') > providedChangeTimestamp) {
- window.log.info('WIP: This is an outdated disappearing message setting');
- return;
- }
-
message.set({
unread: 0, // mark the message as read.
});
@@ -325,10 +318,11 @@ async function handleExpirationTimerUpdateNoCommit(
await conversation.updateExpireTimer({
providedExpirationType: expirationType,
providedExpireTimer: expireTimer,
- providedChangeTimestamp,
+ providedChangeTimestamp: lastDisappearingMessageChangeTimestamp,
providedSource: source,
receivedAt: message.get('received_at'),
shouldCommit: false,
+ existingMessage: message,
});
}
@@ -338,14 +332,14 @@ export async function handleMessageJob(
regularDataMessage: RegularMessageType,
confirm: () => void,
source: string,
- messageHash: string,
- expireUpdate?: any
+ messageHash: string
) {
window?.log?.info(
`Starting handleMessageJob for message ${messageModel.idForLogging()}, ${messageModel.get(
'serverTimestamp'
) || messageModel.get('timestamp')} in conversation ${conversation.idForLogging()}`
);
+
const sendingDeviceConversation = await getConversationController().getOrCreateAndWait(
source,
ConversationTypeEnum.PRIVATE
@@ -353,36 +347,33 @@ export async function handleMessageJob(
try {
messageModel.set({ flags: regularDataMessage.flags });
- if (!isEmpty(expireUpdate)) {
+ if (
+ messageModel.isIncoming() &&
+ messageModel.get('expirationType') === 'deleteAfterSend' &&
+ Boolean(messageModel.get('expirationStartTimestamp')) === false
+ ) {
messageModel.set({
- expirationType: expireUpdate.expirationType,
- expireTimer: expireUpdate.expireTimer,
+ expirationStartTimestamp: setExpirationStartTimestamp(
+ 'deleteAfterSend',
+ messageModel.get('sent_at')
+ ),
});
-
- if (
- messageModel.isIncoming() &&
- messageModel.get('expirationType') === 'deleteAfterSend' &&
- Boolean(messageModel.get('expirationStartTimestamp')) === false
- ) {
- messageModel.set({
- expirationStartTimestamp: setExpirationStartTimestamp(
- 'deleteAfterSend',
- messageModel.get('sent_at')
- ),
- });
- }
}
if (messageModel.isExpirationTimerUpdate()) {
- // TODO account for lastDisappearingMessageChangeTimestamp
- let expirationType = messageModel.get('expirationType');
- const expireTimer = messageModel.get('expireTimer');
+ const expirationTimerUpdate = messageModel.get('expirationTimerUpdate');
+ let expirationType = expirationTimerUpdate?.expirationType;
+ const expireTimer = expirationTimerUpdate?.expireTimer || 0;
+ const lastDisappearingMessageChangeTimestamp =
+ expirationTimerUpdate?.lastDisappearingMessageChangeTimestamp || getNowWithNetworkOffset();
+ // TODO This could happen when we receive a legacy disappearing message
if (!expirationType) {
expirationType = conversation.isPrivate() ? 'deleteAfterRead' : 'deleteAfterSend';
}
- // TODO compare types and change timestamps
+ // Compare mode and timestamp
+
const oldTypeValue = conversation.get('expirationType');
const oldTimerValue = conversation.get('expireTimer');
if (isEqual(expirationType, oldTypeValue) && isEqual(expireTimer, oldTimerValue)) {
@@ -398,7 +389,8 @@ export async function handleMessageJob(
messageModel,
source,
expirationType,
- expireTimer
+ expireTimer,
+ lastDisappearingMessageChangeTimestamp
);
} else {
// this does not commit to db nor UI unless we need to approve a convo
diff --git a/ts/session/messages/outgoing/ContentMessage.ts b/ts/session/messages/outgoing/ContentMessage.ts
index 4dab60ab4..a43e06de6 100644
--- a/ts/session/messages/outgoing/ContentMessage.ts
+++ b/ts/session/messages/outgoing/ContentMessage.ts
@@ -10,5 +10,6 @@ export abstract class ContentMessage extends Message {
public ttl(): number {
return TTL_DEFAULT.TTL_MAX;
}
+
public abstract contentProto(): SignalService.Content;
}
diff --git a/ts/session/messages/outgoing/DataMessage.ts b/ts/session/messages/outgoing/DataMessage.ts
index 4508b9827..abfe20f07 100644
--- a/ts/session/messages/outgoing/DataMessage.ts
+++ b/ts/session/messages/outgoing/DataMessage.ts
@@ -1,11 +1,12 @@
-import { ContentMessage } from '.';
import { SignalService } from '../../../protobuf';
+import { ExpirableMessage } from './ExpirableMessage';
-export abstract class DataMessage extends ContentMessage {
+export abstract class DataMessage extends ExpirableMessage {
public abstract dataProto(): SignalService.DataMessage;
public contentProto(): SignalService.Content {
return new SignalService.Content({
+ ...super.contentProto(),
dataMessage: this.dataProto(),
});
}
diff --git a/ts/session/messages/outgoing/ExpirableMessage.ts b/ts/session/messages/outgoing/ExpirableMessage.ts
new file mode 100644
index 000000000..c79f404b7
--- /dev/null
+++ b/ts/session/messages/outgoing/ExpirableMessage.ts
@@ -0,0 +1,34 @@
+import { SignalService } from '../../../protobuf';
+import { DisappearingMessageType } from '../../../util/expiringMessages';
+import { ContentMessage } from './ContentMessage';
+import { MessageParams } from './Message';
+
+export interface ExpirableMessageParams extends MessageParams {
+ expirationType?: DisappearingMessageType;
+ expireTimer?: number;
+}
+
+export class ExpirableMessage extends ContentMessage {
+ public readonly expirationType?: DisappearingMessageType;
+ public readonly expireTimer?: number;
+
+ constructor(params: ExpirableMessageParams) {
+ super({ timestamp: params.timestamp, identifier: params.identifier });
+ this.expirationType = params.expirationType;
+ this.expireTimer = params.expireTimer;
+ }
+
+ public contentProto(): SignalService.Content {
+ return new SignalService.Content({
+ expirationType:
+ this.expirationType === 'deleteAfterSend'
+ ? SignalService.Content.ExpirationType.DELETE_AFTER_SEND
+ : SignalService.Content.ExpirationType.DELETE_AFTER_READ,
+ expirationTimer: this.expireTimer,
+ });
+ }
+
+ public getDisappearingMessageType(): DisappearingMessageType | undefined {
+ return this.expirationType;
+ }
+}
diff --git a/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts b/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts
index bc3cb6d4d..f4be6c8f3 100644
--- a/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts
+++ b/ts/session/messages/outgoing/controlMessage/ExpirationTimerUpdateMessage.ts
@@ -1,23 +1,22 @@
import { SignalService } from '../../../../protobuf';
-import { DisappearingMessageType } from '../../../../util/expiringMessages';
import { PubKey } from '../../../types';
import { StringUtils } from '../../../utils';
-import { MessageParams } from '../Message';
-import { VisibleMessage } from '../visibleMessage/VisibleMessage';
+import { DataMessage } from '../DataMessage';
+import { ExpirableMessageParams } from '../ExpirableMessage';
-interface ExpirationTimerUpdateMessageParams extends MessageParams {
+interface ExpirationTimerUpdateMessageParams extends ExpirableMessageParams {
groupId?: string | PubKey;
syncTarget?: string | PubKey;
- expirationType: DisappearingMessageType | null;
- expireTimer: number | null;
lastDisappearingMessageChangeTimestamp: number | null;
}
// Note the old disappearing messages used a data message for the expiration time.
// The new ones use properties on the Content Message
// We will remove support for the old one 2 weeks after the release
-export class ExpirationTimerUpdateMessage extends VisibleMessage {
+export class ExpirationTimerUpdateMessage extends DataMessage {
public readonly groupId?: PubKey;
+ public readonly syncTarget?: string;
+ // TODO should this typing be updated
public readonly lastDisappearingMessageChangeTimestamp: number | null;
constructor(params: ExpirationTimerUpdateMessageParams) {
@@ -25,30 +24,26 @@ export class ExpirationTimerUpdateMessage extends VisibleMessage {
timestamp: params.timestamp,
identifier: params.identifier,
expirationType: params.expirationType,
- expireTimer: params.expireTimer || undefined,
- syncTarget: params.syncTarget ? PubKey.cast(params.syncTarget).key : undefined,
+ expireTimer: params.expireTimer,
});
this.lastDisappearingMessageChangeTimestamp = params.lastDisappearingMessageChangeTimestamp;
const { groupId } = params;
this.groupId = groupId ? PubKey.cast(groupId) : undefined;
+ this.syncTarget = params.syncTarget ? PubKey.cast(params.syncTarget).key : undefined;
}
public contentProto(): SignalService.Content {
return new SignalService.Content({
+ ...super.contentProto(),
dataMessage: this.dataProto(),
- expirationType:
- this.expirationType === 'deleteAfterSend'
- ? SignalService.Content.ExpirationType.DELETE_AFTER_SEND
- : SignalService.Content.ExpirationType.DELETE_AFTER_READ,
- expirationTimer: this.expireTimer,
lastDisappearingMessageChangeTimestamp: this.lastDisappearingMessageChangeTimestamp,
});
}
public dataProto(): SignalService.DataMessage {
- const data = super.dataProto();
+ const data = new SignalService.DataMessage();
data.flags = SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE;
@@ -65,7 +60,11 @@ export class ExpirationTimerUpdateMessage extends VisibleMessage {
data.group = groupMessage;
}
- // TODO remove 2 weeks after the release
+ if (this.syncTarget) {
+ data.syncTarget = this.syncTarget;
+ }
+
+ // TODO Legacy support remove 2 weeks after the release
if (this.expireTimer) {
data.expireTimer = this.expireTimer;
}
diff --git a/ts/session/messages/outgoing/visibleMessage/VisibleMessage.ts b/ts/session/messages/outgoing/visibleMessage/VisibleMessage.ts
index 1c0bbdb10..58758527f 100644
--- a/ts/session/messages/outgoing/visibleMessage/VisibleMessage.ts
+++ b/ts/session/messages/outgoing/visibleMessage/VisibleMessage.ts
@@ -1,12 +1,10 @@
import ByteBuffer from 'bytebuffer';
import { isEmpty } from 'lodash';
-import { ContentMessage } from '..';
import { SignalService } from '../../../../protobuf';
import { LokiProfile } from '../../../../types/Message';
import { Reaction } from '../../../../types/Reaction';
-import { DisappearingMessageType } from '../../../../util/expiringMessages';
import { DURATION, TTL_DEFAULT } from '../../../constants';
-import { MessageParams } from '../Message';
+import { ExpirableMessage, ExpirableMessageParams } from '../ExpirableMessage';
interface AttachmentPointerCommon {
contentType?: string;
@@ -64,21 +62,17 @@ export interface Quote {
attachments?: Array;
}
-export interface VisibleMessageParams extends MessageParams {
+export interface VisibleMessageParams extends ExpirableMessageParams {
attachments?: Array;
body?: string;
quote?: Quote;
- expirationType?: DisappearingMessageType;
- expireTimer?: number;
lokiProfile?: LokiProfile;
preview?: Array;
reaction?: Reaction;
syncTarget?: string; // undefined means it is not a synced message
}
-export class VisibleMessage extends ContentMessage {
- public readonly expirationType?: DisappearingMessageType;
- public readonly expireTimer?: number;
+export class VisibleMessage extends ExpirableMessage {
public readonly reaction?: Reaction;
private readonly attachments?: Array;
@@ -93,12 +87,15 @@ export class VisibleMessage extends ContentMessage {
private readonly syncTarget?: string;
constructor(params: VisibleMessageParams) {
- super({ timestamp: params.timestamp, identifier: params.identifier });
+ super({
+ timestamp: params.timestamp,
+ identifier: params.identifier,
+ expirationType: params.expirationType,
+ expireTimer: params.expireTimer,
+ });
this.attachments = params.attachments;
this.body = params.body;
this.quote = params.quote;
- this.expirationType = params.expirationType;
- this.expireTimer = params.expireTimer;
const profile = buildProfileForOutgoingMessage(params);
@@ -112,12 +109,8 @@ export class VisibleMessage extends ContentMessage {
public contentProto(): SignalService.Content {
return new SignalService.Content({
+ ...super.contentProto(),
dataMessage: this.dataProto(),
- expirationType:
- this.expirationType === 'deleteAfterSend'
- ? SignalService.Content.ExpirationType.DELETE_AFTER_SEND
- : SignalService.Content.ExpirationType.DELETE_AFTER_READ,
- expirationTimer: this.expireTimer,
});
}
@@ -200,6 +193,7 @@ export class VisibleMessage extends ContentMessage {
return this.identifier === comparator.identifier && this.timestamp === comparator.timestamp;
}
+ // TODO should this be on the Expirable message? Probably
public ttl(): number {
switch (this.expirationType) {
case 'deleteAfterSend':
diff --git a/ts/session/utils/syncUtils.ts b/ts/session/utils/syncUtils.ts
index 8fc8ee92b..45d88cc82 100644
--- a/ts/session/utils/syncUtils.ts
+++ b/ts/session/utils/syncUtils.ts
@@ -324,6 +324,7 @@ export const buildSyncMessage = (
data: DataMessage | SignalService.DataMessage,
syncTarget: string,
sentTimestamp: number,
+ // TODO add proper types
expireUpdate?: any
): VisibleMessage | ExpirationTimerUpdateMessage => {
if (
diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts
index 053b7ef58..8f384fec0 100644
--- a/ts/state/ducks/conversations.ts
+++ b/ts/state/ducks/conversations.ts
@@ -130,12 +130,12 @@ export type PropsForGroupUpdateType =
| PropsForGroupUpdateName
| PropsForGroupUpdateLeft;
-export type PropsForGroupUpdate = {
+export interface PropsForGroupUpdate extends PropsForExpiringMessage {
change: PropsForGroupUpdateType;
messageId: string;
receivedAt: number | undefined;
isUnread: boolean;
-};
+}
export interface PropsForGroupInvitation extends PropsForExpiringMessage {
serverName: string;