From 22e02633a97ef58665b8256d70111fd732292f2c Mon Sep 17 00:00:00 2001 From: William Grant Date: Mon, 3 Apr 2023 14:09:05 +0200 Subject: [PATCH] feat: started consolidating send and receive dm logic. updated in parts but haven't test what happens --- .../conversation/TimerNotification.tsx | 21 +++++++++++++--- ts/models/message.ts | 18 ++++++++++---- ts/receiver/dataMessage.ts | 10 ++++++++ ts/session/sending/MessageSentHandler.ts | 17 ++++++++++++- ts/util/expiringMessages.ts | 24 +++++++++++++++++++ ts/util/readReceipts.ts | 13 ++++++++-- 6 files changed, 92 insertions(+), 11 deletions(-) diff --git a/ts/components/conversation/TimerNotification.tsx b/ts/components/conversation/TimerNotification.tsx index 698740657..94ea5091e 100644 --- a/ts/components/conversation/TimerNotification.tsx +++ b/ts/components/conversation/TimerNotification.tsx @@ -6,22 +6,37 @@ import { NotificationBubble } from './message/message-item/notification-bubble/N import { ReadableMessage } from './message/message-item/ReadableMessage'; export const TimerNotification = (props: PropsForExpirationTimer) => { - const { messageId, receivedAt, isUnread, pubkey, profileName, timespan, type, disabled } = props; + const { + messageId, + receivedAt, + isUnread, + pubkey, + profileName, + expirationType, + timespan, + type, + disabled, + } = props; const contact = profileName || pubkey; + const mode = + expirationType === 'deleteAfterRead' + ? window.i18n('timerModeRead') + : window.i18n('timerModeSent'); let textToRender: string | undefined; switch (type) { case 'fromOther': textToRender = disabled ? window.i18n('disabledDisappearingMessages', [contact, timespan]) - : window.i18n('theyChangedTheTimer', [contact, timespan]); + : window.i18n('theyChangedTheTimer', [contact, timespan, mode]); break; case 'fromMe': textToRender = disabled ? window.i18n('youDisabledDisappearingMessages') - : window.i18n('youChangedTheTimer', [timespan]); + : window.i18n('youChangedTheTimer', [timespan, mode]); break; + // TODO update synced control message? case 'fromSync': textToRender = disabled ? window.i18n('disappearingMessagesDisabled') diff --git a/ts/models/message.ts b/ts/models/message.ts index b2709b1c7..ff7c397ba 100644 --- a/ts/models/message.ts +++ b/ts/models/message.ts @@ -80,7 +80,7 @@ import { loadPreviewData, loadQuoteData, } from '../types/MessageAttachment'; -import { ExpirationTimerOptions } from '../util/expiringMessages'; +import { ExpirationTimerOptions, setExpirationStartTimestamp } from '../util/expiringMessages'; import { Notifications } from '../util/notifications'; import { Storage } from '../util/storage'; import { LinkPreviews } from '../util/linkPreviews'; @@ -277,7 +277,7 @@ export class MessageModel extends Backbone.Model { return null; } - const { expireTimer, fromSync, source } = timerUpdate; + const { expirationType, expireTimer, fromSync, source } = timerUpdate; const timespan = ExpirationTimerOptions.getName(expireTimer || 0); const disabled = !expireTimer; @@ -289,6 +289,7 @@ export class MessageModel extends Backbone.Model { messageId: this.id, receivedAt: this.get('received_at'), isUnread: this.isUnread(), + expirationType: expirationType || 'off', }; return basicProps; @@ -457,6 +458,7 @@ export class MessageModel extends Backbone.Model { // tslint:disable-next-line: cyclomatic-complexity public getPropsForMessage(options: any = {}): PropsForMessageWithoutConvoProps { const sender = this.getSource(); + const expirationType = this.get('expirationType'); const expirationLength = this.get('expireTimer') * 1000; const expireTimerStart = this.get('expirationStartTimestamp'); const expirationTimestamp = @@ -491,6 +493,9 @@ export class MessageModel extends Backbone.Model { if (this.get('serverId')) { props.serverId = this.get('serverId'); } + if (expirationType) { + props.expirationType = expirationType; + } if (expirationLength) { props.expirationLength = expirationLength; } @@ -1162,9 +1167,12 @@ export class MessageModel extends Backbone.Model { public markReadNoCommit(readAt: number) { this.set({ unread: 0 }); - // TODO This logic needs to depend no the dm mode - if (this.get('expireTimer') && !this.get('expirationStartTimestamp')) { - const expirationStartTimestamp = Math.min(Date.now(), readAt || Date.now()); + if ( + this.get('expirationType') === 'deleteAfterRead' && + this.get('expireTimer') && + !this.get('expirationStartTimestamp') + ) { + const expirationStartTimestamp = setExpirationStartTimestamp(this, 'deleteAfterRead', readAt); this.set({ expirationStartTimestamp }); } diff --git a/ts/receiver/dataMessage.ts b/ts/receiver/dataMessage.ts index 496df44b6..0580ff939 100644 --- a/ts/receiver/dataMessage.ts +++ b/ts/receiver/dataMessage.ts @@ -23,6 +23,7 @@ import { toLogFormat } from '../types/attachments/Errors'; import { ConversationTypeEnum } from '../models/conversationAttributes'; import { Reactions } from '../util/reactions'; import { Action, Reaction } from '../types/Reaction'; +import { setExpirationStartTimestamp } from '../util/expiringMessages'; function cleanAttachment(attachment: any) { return { @@ -241,6 +242,15 @@ export async function handleSwarmDataMessage( sentAt: sentAtTimestamp, }); + if (expireUpdate.expirationType === 'deleteAfterSend') { + const expirationStartTimestamp = setExpirationStartTimestamp( + msgModel, + 'deleteAfterSend', + msgModel.get('sent_at') + ); + msgModel.set('expirationStartTimestamp', expirationStartTimestamp); + } + await handleSwarmMessage( msgModel, messageHash, diff --git a/ts/session/sending/MessageSentHandler.ts b/ts/session/sending/MessageSentHandler.ts index da599e6e3..9ba72dfff 100644 --- a/ts/session/sending/MessageSentHandler.ts +++ b/ts/session/sending/MessageSentHandler.ts @@ -1,6 +1,7 @@ import _ from 'lodash'; import { Data } from '../../data/data'; import { SignalService } from '../../protobuf'; +import { setExpirationStartTimestamp } from '../../util/expiringMessages'; import { PnServer } from '../apis/push_notification_api'; import { OpenGroupVisibleMessage } from '../messages/outgoing/visibleMessage/OpenGroupVisibleMessage'; import { RawMessage } from '../types'; @@ -124,10 +125,15 @@ async function handleMessageSentSuccess( sentTo = _.union(sentTo, [sentMessage.device]); + if (fetchedMessage.get('expirationType') === 'deleteAfterSend') { + const expirationStartTimestamp = setExpirationStartTimestamp(fetchedMessage, 'deleteAfterSend'); + fetchedMessage.set('expirationStartTimestamp', expirationStartTimestamp); + } + fetchedMessage.set({ sent_to: sentTo, sent: true, - expirationStartTimestamp: Date.now(), + // TODO do we need to use this for the timestamp for the delete after send logic sent_at: effectiveTimestamp, }); @@ -157,6 +163,15 @@ async function handleMessageSentFailure( fetchedMessage.set({ sentSync: false }); } + // TODO Need to handle messages failing to send differently? + if (fetchedMessage.get('expirationType') === 'deleteAfterSend') { + const expirationStartTimestamp = setExpirationStartTimestamp( + fetchedMessage, + 'deleteAfterSend' + ); + fetchedMessage.set('expirationStartTimestamp', expirationStartTimestamp); + } + fetchedMessage.set({ expirationStartTimestamp: Date.now(), }); diff --git a/ts/util/expiringMessages.ts b/ts/util/expiringMessages.ts index 92d594d39..7b44126ac 100644 --- a/ts/util/expiringMessages.ts +++ b/ts/util/expiringMessages.ts @@ -7,6 +7,7 @@ import { initWallClockListener } from './wallClockListener'; import { Data } from '../data/data'; import { getConversationController } from '../session/conversations'; +import { MessageModel } from '../models/message'; // TODO Might need to be improved by using an enum export const DisappearingMessageMode = ['deleteAfterRead', 'deleteAfterSend']; @@ -194,3 +195,26 @@ export const ExpirationTimerOptions = { initExpiringMessageListener, getTimerSecondsWithName, }; + +export function setExpirationStartTimestamp( + message: MessageModel, + mode: DisappearingMessageType, + timestamp?: number +) { + let expirationStartTimestamp = Date.now(); + + if (timestamp) { + expirationStartTimestamp = Math.min(expirationStartTimestamp, timestamp); + } + + if (mode === 'deleteAfterRead') { + window.log.info(`WIP: we set the start timetamp for a delete after read message`, message); + } else if (mode === 'deleteAfterSend') { + window.log.info(`WIP: we set the start timetamp for a delete after send message`, message); + } else { + console.log(`WIP: Invalid disappearing message mode set, ignoring this message`, message); + return; + } + + return expirationStartTimestamp; +} diff --git a/ts/util/readReceipts.ts b/ts/util/readReceipts.ts index e730f907c..2c2e811b0 100644 --- a/ts/util/readReceipts.ts +++ b/ts/util/readReceipts.ts @@ -3,6 +3,7 @@ import { MessageCollection } from '../models/message'; import { Data } from '../data/data'; import { getConversationController } from '../session/conversations'; +import { setExpirationStartTimestamp } from './expiringMessages'; async function getTargetMessage(reader: string, messages: MessageCollection) { if (messages.length === 0) { @@ -45,7 +46,14 @@ async function onReadReceipt(receipt: { source: string; timestamp: number; readA // readBy is only used for private conversations // we do not care of who read it. If the length is > 0 , it is read and false otherwise let readBy = message.get('read_by') || []; - const expirationStartTimestamp = message.get('expirationStartTimestamp'); + let expirationStartTimestamp = undefined; + if (message.get('expirationType') === 'deleteAfterRead') { + expirationStartTimestamp = setExpirationStartTimestamp( + message, + 'deleteAfterRead', + message.get('expirationStartTimestamp') + ); + } if (!readBy.length) { readBy.push(receipt.source); @@ -53,9 +61,10 @@ async function onReadReceipt(receipt: { source: string; timestamp: number; readA if (readBy.length > 1) { readBy = readBy.slice(0, 1); } + message.set({ read_by: readBy, - expirationStartTimestamp: expirationStartTimestamp || Date.now(), + expirationStartTimestamp, sent: true, });