wip: added new legacy mode to panel, improved backwards compatibility

legacy mode support in conversation header, added typing for the expireUpdate, next is sending support
pull/2660/head
William Grant 2 years ago
parent 190357b006
commit 7d0673f7f2

@ -217,6 +217,8 @@
"disappearingMessagesModeAfterReadSubtitle": "Messages delete after they have been read.",
"disappearingMessagesModeAfterSend": "Disappear After Send",
"disappearingMessagesModeAfterSendSubtitle": "Messages delete after they have been sent.",
"disappearingMessagesModeLegacy": "Legacy",
"disappearingMessagesModeLegacySubtitle": "Original version of disappearing messages.",
"disappearingMessagesDisabled": "Disappearing messages disabled",
"disabledDisappearingMessages": "$name$ has turned off disappearing messages.",
"youDisabledDisappearingMessages": "You have turned off disappearing messages.",

@ -139,7 +139,12 @@ export const ConversationHeaderTitle = () => {
? null
: expirationType === 'deleteAfterRead'
? window.i18n('disappearingMessagesModeAfterRead')
: window.i18n('disappearingMessagesModeAfterSend');
: expirationType === 'deleteAfterSend'
? window.i18n('disappearingMessagesModeAfterSend')
: // legacy mode support
isGroup
? window.i18n('disappearingMessagesModeAfterSend')
: window.i18n('disappearingMessagesModeAfterRead');
const abbreviatedExpireTime = Boolean(expireTimer)
? ExpirationTimerOptions.getAbbreviated(expireTimer)
: null;

@ -16,7 +16,10 @@ import {
getSelectedConversationExpirationSettings,
getSelectedConversationKey,
} from '../../../../state/selectors/conversations';
import { DisappearingMessageConversationType } from '../../../../util/expiringMessages';
import {
DisappearingMessageConversationSetting,
DisappearingMessageConversationType,
} from '../../../../util/expiringMessages';
import { TimerOptionsArray } from '../../../../state/ducks/timerOptions';
import { useTimerOptionsByMode } from '../../../../hooks/useParamSelector';
import { isEmpty } from 'lodash';
@ -108,14 +111,18 @@ const DisappearingModes = (props: DisappearingModesProps) => {
<PanelButtonGroup>
{options.map((option: DisappearingMessageConversationType) => {
const optionI18n =
option === 'off'
? window.i18n('disappearingMessagesModeOff')
option === 'legacy'
? window.i18n('disappearingMessagesModeLegacy')
: option === 'deleteAfterRead'
? window.i18n('disappearingMessagesModeAfterRead')
: window.i18n('disappearingMessagesModeAfterSend');
: option === 'deleteAfterSend'
? window.i18n('disappearingMessagesModeAfterSend')
: window.i18n('disappearingMessagesModeOff');
const subtitleI18n =
option === 'deleteAfterRead'
option === 'legacy'
? window.i18n('disappearingMessagesModeLegacySubtitle')
: option === 'deleteAfterRead'
? window.i18n('disappearingMessagesModeAfterReadSubtitle')
: option === 'deleteAfterSend'
? window.i18n('disappearingMessagesModeAfterSendSubtitle')
@ -185,9 +192,19 @@ export const OverlayDisappearingMessages = () => {
return null;
}
const { isGroup } = convoProps;
const [modeSelected, setModeSelected] = useState(convoProps.expirationType);
const [timeSelected, setTimeSelected] = useState(convoProps.expireTimer);
const timerOptions = useTimerOptionsByMode(modeSelected);
// Legacy mode uses the default timer options depending on the conversation type
// TODO verify that this if fine compared to updating in the useEffect
const timerOptions = useTimerOptionsByMode(
modeSelected === 'legacy'
? isGroup
? DisappearingMessageConversationSetting[2]
: DisappearingMessageConversationSetting[1]
: modeSelected
);
useEffect(() => {
if (modeSelected !== convoProps.expirationType) {

@ -1061,7 +1061,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
expireTimer = 0;
}
// TODO does this actually work?
if (
this.get('lastDisappearingMessageChangeTimestamp') > lastDisappearingMessageChangeTimestamp
) {
@ -1079,6 +1078,11 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
return;
}
if (expirationType === 'legacy') {
// TODO If we are the new client then we ignore these updates
// TODO trigger UI
}
const isOutgoing = Boolean(!receivedAt);
source = source || UserUtils.getOurPubKeyStrFromCache();

@ -81,7 +81,11 @@ import {
loadPreviewData,
loadQuoteData,
} from '../types/MessageAttachment';
import { ExpirationTimerOptions, setExpirationStartTimestamp } from '../util/expiringMessages';
import {
DisappearingMessageUpdate,
ExpirationTimerOptions,
setExpirationStartTimestamp,
} from '../util/expiringMessages';
import { Notifications } from '../util/notifications';
import { Storage } from '../util/storage';
import { LinkPreviews } from '../util/linkPreviews';
@ -250,8 +254,6 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
return window.i18n('mediaMessage');
}
if (this.isExpirationTimerUpdate()) {
// TODO Backwards compatibility for Disappearing Messages in old clients
// TODO What does this comment refer to mean?
const expireTimerUpdate = this.get('expirationTimerUpdate');
const expirationType = expireTimerUpdate?.expirationType;
const expireTimer = expireTimerUpdate?.expireTimer;
@ -1070,28 +1072,28 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
sent: true,
});
let expireUpdate = null;
let expireUpdate: DisappearingMessageUpdate | null = null;
const expirationType = dataMessage.getDisappearingMessageType();
if (expirationType && contentMessage.expirationTimer) {
expireUpdate = {
expirationType,
expireTimer: contentMessage.expirationTimer,
lastDisappearingMessageChangeTimestamp:
contentMessage.lastDisappearingMessageChangeTimestamp,
lastDisappearingMessageChangeTimestamp: Number(
contentMessage.lastDisappearingMessageChangeTimestamp
),
};
}
await this.commit();
await this.sendSyncMessage(dataMessage, now, expireUpdate);
await this.sendSyncMessage(dataMessage, now, expireUpdate || undefined);
}
public async sendSyncMessage(
data: DataMessage | SignalService.DataMessage,
sentTimestamp: number,
// TODO add proper types
expireUpdate?: any
expireUpdate?: DisappearingMessageUpdate
) {
if (this.get('synced') || this.get('sentSync')) {
return;

@ -3,7 +3,7 @@ import { handleSwarmDataMessage } from './dataMessage';
import { removeFromCache, updateCache } from './cache';
import { SignalService } from '../protobuf';
import { compact, flatten, identity, isEmpty, isEqual, pickBy, toNumber } from 'lodash';
import { compact, flatten, identity, isEmpty, pickBy, toNumber } from 'lodash';
import { KeyPrefixType, PubKey } from '../session/types';
import { BlockedNumberController } from '../util/blockedNumberController';
@ -30,6 +30,7 @@ import { findCachedBlindedMatchOrLookupOnAllServers } from '../session/apis/open
import { appendFetchAvatarAndProfileJob } from './userProfileImageUpdates';
import {
DisappearingMessageConversationSetting,
DisappearingMessageUpdate,
setExpirationStartTimestamp,
} from '../util/expiringMessages';
@ -406,28 +407,26 @@ export async function innerHandleSwarmContentMessage(
perfStart(`handleSwarmDataMessage-${envelope.id}`);
const expireUpdate = {
expirationType: DisappearingMessageConversationSetting[content.expirationType] || 'off',
// TODO rename to expirationTimer?
expireTimer: content.expirationTimer || 0,
// This is used for the expirationTimerUpdate
// TODO Trigger banner in UI?
// TODO maybe trigger the banner later based on the expirationType for the conversation
const isLegacyMode = dataMessage.expireTimer && dataMessage.expireTimer > 0;
if (isLegacyMode) {
window.log.info('WIP: Received legacy disappearing message', content);
}
const expireUpdate: DisappearingMessageUpdate = {
// TODO When sending a message if it's a legacy message then we need to set the type to the default for compatiblity reasons
expirationType: isLegacyMode
? DisappearingMessageConversationSetting[3]
: DisappearingMessageConversationSetting[content.expirationType] || 'off',
// TODO in the future we will remove the dataMessage expireTimer
expireTimer: isLegacyMode ? Number(dataMessage.expireTimer) : content.expirationTimer,
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 (
expireUpdate.expireTimer > 0 &&
dataMessage.expireTimer &&
!isEqual(expireUpdate.expireTimer, dataMessage.expireTimer)
) {
// TODO Trigger banner in UI?
expireUpdate.expireTimer = dataMessage.expireTimer;
window.log.info('WIP: Received outdated disappearing message data message', content);
}
await handleSwarmDataMessage(
envelope,
sentAtTimestamp,

@ -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 { DisappearingMessageUpdate } from '../util/expiringMessages';
function cleanAttachment(attachment: any) {
return {
@ -154,8 +155,7 @@ export async function handleSwarmDataMessage(
rawDataMessage: SignalService.DataMessage,
messageHash: string,
senderConversationModel: ConversationModel,
// TODO add proper types
expireUpdate?: any
expireUpdate: DisappearingMessageUpdate
): Promise<void> {
window.log.info('handleSwarmDataMessage');
@ -255,7 +255,7 @@ export async function handleSwarmDataMessage(
});
// This message is conversation setting change message
if (expireUpdate.lastDisappearingMessageChangeTimestamp) {
if (lastDisappearingMessageChangeTimestamp) {
msgModel.set({
expirationTimerUpdate: {
expirationType,

@ -1,7 +1,7 @@
import { queueAttachmentDownloads } from './attachments';
import { Quote } from './types';
import _, { isEqual } from 'lodash';
import _, { isEmpty, isEqual } from 'lodash';
import { getConversationController } from '../session/conversations';
import { ConversationModel } from '../models/conversation';
import { MessageModel, sliceQuoteText } from '../models/message';
@ -364,18 +364,17 @@ export async function handleMessageJob(
if (messageModel.isExpirationTimerUpdate()) {
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';
if (!expirationTimerUpdate || isEmpty(expirationTimerUpdate)) {
window.log.info(`WIP: There is a problem with the expiration timer update`, messageModel);
return;
}
// Compare mode and timestamp
const expirationType = expirationTimerUpdate.expirationType || 'off';
const expireTimer = expirationTimerUpdate.expireTimer;
const lastDisappearingMessageChangeTimestamp =
expirationTimerUpdate.lastDisappearingMessageChangeTimestamp || getNowWithNetworkOffset();
// Compare mode and timestamp
const oldTypeValue = conversation.get('expirationType');
const oldTimerValue = conversation.get('expireTimer');
if (isEqual(expirationType, oldTypeValue) && isEqual(expireTimer, oldTimerValue)) {

@ -27,7 +27,7 @@ import { UnsendMessage } from '../messages/outgoing/controlMessage/UnsendMessage
import { MessageRequestResponse } from '../messages/outgoing/controlMessage/MessageRequestResponse';
import { PubKey } from '../types';
import { DataMessage } from '../messages/outgoing';
import { DisappearingMessageType } from '../../util/expiringMessages';
import { DisappearingMessageUpdate } from '../../util/expiringMessages';
const ITEM_ID_LAST_SYNC_TIMESTAMP = 'lastSyncedTimestamp';
@ -296,16 +296,16 @@ const buildSyncVisibleMessage = (
const buildSyncExpireTimerMessage = (
identifier: string,
expirationType: DisappearingMessageType,
expireTimer: number,
lastDisappearingMessageChangeTimestamp: number | null,
expireUpdate: DisappearingMessageUpdate,
timestamp: number,
syncTarget: string
) => {
const { expirationType, expireTimer, lastDisappearingMessageChangeTimestamp } = expireUpdate;
return new ExpirationTimerUpdateMessage({
identifier,
timestamp,
expirationType: expirationType || null,
expirationType,
expireTimer,
lastDisappearingMessageChangeTimestamp: lastDisappearingMessageChangeTimestamp || null,
syncTarget,
@ -324,8 +324,7 @@ export const buildSyncMessage = (
data: DataMessage | SignalService.DataMessage,
syncTarget: string,
sentTimestamp: number,
// TODO add proper types
expireUpdate?: any
expireUpdate?: DisappearingMessageUpdate
): VisibleMessage | ExpirationTimerUpdateMessage => {
if (
(data as any).constructor.name !== 'DataMessage' &&
@ -342,17 +341,13 @@ export const buildSyncMessage = (
// don't include our profileKey on syncing message. This is to be done by a ConfigurationMessage now
const timestamp = _.toNumber(sentTimestamp);
if (
expireUpdate &&
!isEmpty(expireUpdate) &&
dataMessage.flags === SignalService.DataMessage.Flags.EXPIRATION_TIMER_UPDATE
) {
return buildSyncExpireTimerMessage(
identifier,
expireUpdate.expirationType,
expireUpdate.expireTimer,
expireUpdate.lastDisappearingMessageChangeTimestamp,
timestamp,
syncTarget
);
return buildSyncExpireTimerMessage(identifier, expireUpdate, timestamp, syncTarget);
} else {
window.log.info(`WIP: Something went wrong when syncing a disappearing message`);
}
return buildSyncVisibleMessage(identifier, dataMessage, timestamp, syncTarget);
};

@ -1184,12 +1184,15 @@ export const getSelectedConversationExpirationModes = createSelector(
(convo: ReduxConversationType | undefined) => {
let modes = DisappearingMessageConversationSetting;
// Note to Self and Closed Groups only support deleteAfterSend
// Note to Self and Closed Groups only support deleteAfterSend and legacy modes
if (convo?.isMe || (convo?.isGroup && !convo.isPublic)) {
// only deleteAfterSend
modes = [modes[0], modes[2]];
modes = [modes[0], modes[2], modes[modes.length - 1]];
}
// Legacy mode is the 2nd option in the UI
modes = [modes[0], modes[modes.length - 1], ...modes.slice(1, modes.length - 1)];
return modes;
}
);
@ -1199,5 +1202,6 @@ export const getSelectedConversationExpirationSettings = createSelector(
(convo: ReduxConversationType | undefined) => ({
expirationType: convo?.expirationType,
expireTimer: convo?.expireTimer,
isGroup: convo?.isGroup,
})
);

@ -217,6 +217,8 @@ export type LocalizerKeys =
| 'disappearingMessagesModeAfterReadSubtitle'
| 'disappearingMessagesModeAfterSend'
| 'disappearingMessagesModeAfterSendSubtitle'
| 'disappearingMessagesModeLegacy'
| 'disappearingMessagesModeLegacySubtitle'
| 'disappearingMessagesDisabled'
| 'disabledDisappearingMessages'
| 'youDisabledDisappearingMessages'

@ -13,9 +13,17 @@ import { getNowWithNetworkOffset } from '../session/apis/snode_api/SNodeAPI';
export const DisappearingMessageMode = ['deleteAfterRead', 'deleteAfterSend'];
export type DisappearingMessageType = typeof DisappearingMessageMode[number] | null;
export const DisappearingMessageConversationSetting = ['off', ...DisappearingMessageMode];
export const DisappearingMessageConversationSetting = ['off', ...DisappearingMessageMode, 'legacy'];
export type DisappearingMessageConversationType = typeof DisappearingMessageConversationSetting[number];
export type DisappearingMessageUpdate = {
expirationType: DisappearingMessageType;
// TODO rename to expirationTimer?
expireTimer: number;
// This is used for the expirationTimerUpdate
lastDisappearingMessageChangeTimestamp?: number;
};
export async function destroyMessagesAndUpdateRedux(
messages: Array<{
conversationKey: string;

Loading…
Cancel
Save