feat: Call Notifications now expire properlly

include the direction in the expiration props, setting the start timer doesnt directly update the model
pull/2660/head
William Grant 2 years ago
parent f122c206da
commit 5c697572a7

@ -94,6 +94,7 @@ export const ExpirableReadableMessage = (props: ExpirableReadableMessageProps) =
expirationLength,
expirationTimestamp,
isExpired: props.isExpired,
direction: props.direction,
};
const { isExpired } = useIsExpired(expiringProps);
const isIncoming = direction === 'incoming';

@ -9,7 +9,7 @@ import {
import { getSelectedConversation } from '../../../../../state/selectors/conversations';
import { LocalizerKeys } from '../../../../../types/LocalizerKeys';
import { SessionIconType } from '../../../../icon';
import { ReadableMessage } from '../ReadableMessage';
import { ExpirableReadableMessage } from '../ExpirableReadableMessage';
import { NotificationBubble } from './NotificationBubble';
type StyleType = Record<
@ -36,7 +36,16 @@ const style: StyleType = {
};
export const CallNotification = (props: PropsForCallNotification) => {
const { messageId, receivedAt, isUnread, notificationType } = props;
const {
messageId,
receivedAt,
isUnread,
notificationType,
direction,
expirationLength,
expirationTimestamp,
isExpired,
} = props;
const selectedConvoProps = useSelector(getSelectedConversation);
@ -54,10 +63,14 @@ export const CallNotification = (props: PropsForCallNotification) => {
const iconColor = styleItem.iconColor;
return (
<ReadableMessage
<ExpirableReadableMessage
messageId={messageId}
receivedAt={receivedAt}
direction={direction}
isUnread={isUnread}
expirationLength={expirationLength}
expirationTimestamp={expirationTimestamp}
isExpired={isExpired}
key={`readable-message-${messageId}`}
>
<NotificationBubble
@ -65,6 +78,6 @@ export const CallNotification = (props: PropsForCallNotification) => {
iconType={iconType}
iconColor={iconColor}
/>
</ReadableMessage>
</ExpirableReadableMessage>
);
};

@ -1215,6 +1215,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
}
}
}
return this.addSingleMessage({
...messageAttributes,
conversationId: this.id,

@ -171,6 +171,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
messageId: this.id,
receivedAt: this.get('received_at') || Date.now(),
isUnread: this.isUnread(),
...this.getPropsForExpiringMessage(),
};
}
perfEnd(`getPropsMessage-${this.id}`, 'getPropsMessage');
@ -280,7 +281,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
await deleteExternalMessageFiles(this.attributes);
}
public getPropsForExpiringMessage(): PropsForExpiringMessage | null {
public getPropsForExpiringMessage(): PropsForExpiringMessage | { direction: MessageModelType } {
const expirationType = this.get('expirationType');
const expirationLength = this.get('expireTimer') || null;
@ -291,9 +292,13 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
? expireTimerStart + expirationLength * DURATION.SECONDS
: null;
const direction =
this.get('direction') || this.get('type') === 'outgoing' ? 'outgoing' : 'incoming';
return {
convoId: this.get('conversationId'),
messageId: this.get('id'),
direction,
expirationLength,
expirationTimestamp,
isExpired: this.isExpired(),
@ -309,12 +314,6 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
return null;
}
// TODO should direction be parts of expiration props?
let direction = this.get('direction');
if (!direction) {
direction = this.get('type') === 'outgoing' ? 'outgoing' : 'incoming';
}
const { expirationType, expireTimer, fromSync, source } = timerUpdate;
const timespan = ExpirationTimerOptions.getName(expireTimer || 0);
const disabled = !expireTimer;
@ -328,7 +327,6 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
receivedAt: this.get('received_at'),
isUnread: this.isUnread(),
expirationType: expirationType || 'off',
direction,
...this.getPropsForExpiringMessage(),
};
@ -357,7 +355,6 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
return {
serverName: invitation.name,
url: serverAddress,
direction,
acceptUrl: invitation.url,
messageId: this.id as string,
receivedAt: this.get('received_at'),
@ -1211,10 +1208,11 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
if (
this.get('expirationType') === 'deleteAfterRead' &&
this.get('expireTimer') &&
!this.get('expirationStartTimestamp')
Boolean(this.get('expirationStartTimestamp')) === false
) {
const message = setExpirationStartTimestamp(this, 'deleteAfterRead', readAt);
this.set({ expirationStartTimestamp: message?.get('expirationStartTimestamp') });
this.set({
expirationStartTimestamp: setExpirationStartTimestamp('deleteAfterRead', readAt),
});
}
Notifications.clearByMessageId(this.id);

@ -359,13 +359,17 @@ export async function handleMessageJob(
expireTimer: expireUpdate.expireTimer,
});
if (messageModel.isIncoming() && messageModel.get('expirationType') === 'deleteAfterSend') {
messageModel =
setExpirationStartTimestamp(
messageModel,
if (
messageModel.isIncoming() &&
messageModel.get('expirationType') === 'deleteAfterSend' &&
Boolean(messageModel.get('expirationStartTimestamp')) === false
) {
messageModel.set({
expirationStartTimestamp: setExpirationStartTimestamp(
'deleteAfterSend',
messageModel.get('sent_at')
) || messageModel;
),
});
}
}

@ -136,13 +136,13 @@ async function handleMessageSentSuccess(
if (!shouldMarkMessageAsSynced) {
const expirationType = fetchedMessage.get('expirationType');
if (expirationType) {
fetchedMessage =
setExpirationStartTimestamp(
fetchedMessage,
if (expirationType && Boolean(fetchedMessage.get('expirationStartTimestamp')) === false) {
fetchedMessage.set({
expirationStartTimestamp: setExpirationStartTimestamp(
expirationType,
expirationType === 'deleteAfterSend' ? effectiveTimestamp : undefined
) || fetchedMessage;
),
});
}
}

@ -28,6 +28,7 @@ import { getCallMediaPermissionsSettings } from '../../../components/settings/Se
import { PnServer } from '../../apis/push_notification_api';
import { getNowWithNetworkOffset } from '../../apis/snode_api/SNodeAPI';
import { approveConvoAndSendResponse } from '../../../interactions/conversationInteractions';
import { setExpirationStartTimestamp } from '../../../util/expiringMessages';
// tslint:disable: function-name
@ -503,10 +504,16 @@ export async function USER_callRecipient(recipient: string) {
calledConvo.set('active_at', Date.now()); // addSingleOutgoingMessage does the commit for us on the convo
weAreCallerOnCurrentCall = true;
const expirationType = calledConvo.get('expirationType');
await calledConvo?.addSingleOutgoingMessage({
sent_at: now,
expireTimer: 0,
callNotificationType: 'started-call',
sent_at: now,
expirationType: expirationType !== 'off' ? expirationType : undefined,
expireTimer: calledConvo.get('expireTimer') ? calledConvo.get('expireTimer') : 0,
expirationStartTimestamp: setExpirationStartTimestamp(
expirationType,
expirationType === 'deleteAfterSend' ? now : undefined
),
});
// initiating a call is analogous to sending a message request
@ -841,13 +848,20 @@ export async function USER_acceptIncomingCallRequest(fromSender: string) {
const networkTimestamp = getNowWithNetworkOffset();
const callerConvo = getConversationController().get(fromSender);
callerConvo.set('active_at', networkTimestamp);
const expirationType = callerConvo.get('expirationType');
await callerConvo?.addSingleIncomingMessage({
callNotificationType: 'answered-a-call',
source: UserUtils.getOurPubKeyStrFromCache(),
sent_at: networkTimestamp,
received_at: networkTimestamp,
expireTimer: 0,
callNotificationType: 'answered-a-call',
unread: 0,
expirationType: expirationType !== 'off' ? expirationType : undefined,
expireTimer: callerConvo.get('expireTimer') ? callerConvo.get('expireTimer') : 0,
expirationStartTimestamp: setExpirationStartTimestamp(
expirationType,
expirationType === 'deleteAfterSend' ? networkTimestamp : undefined
),
});
await buildAnswerAndSendIt(fromSender);
@ -1167,13 +1181,21 @@ async function addMissedCallMessage(callerPubkey: string, sentAt: number) {
incomingCallConversation.set('active_at', getNowWithNetworkOffset());
}
const expirationType = incomingCallConversation.get('expirationType');
await incomingCallConversation?.addSingleIncomingMessage({
callNotificationType: 'missed-call',
source: callerPubkey,
sent_at: sentAt,
received_at: getNowWithNetworkOffset(),
expireTimer: 0,
callNotificationType: 'missed-call',
unread: 1,
expirationType: expirationType !== 'off' ? expirationType : undefined,
expireTimer: incomingCallConversation.get('expireTimer')
? incomingCallConversation.get('expireTimer')
: 0,
expirationStartTimestamp: setExpirationStartTimestamp(
expirationType,
expirationType === 'deleteAfterSend' ? sentAt : undefined
),
});
}

@ -22,12 +22,12 @@ import {
} from '../../util/expiringMessages';
export type CallNotificationType = 'missed-call' | 'started-call' | 'answered-a-call';
export type PropsForCallNotification = {
export interface PropsForCallNotification extends PropsForExpiringMessage {
notificationType: CallNotificationType;
messageId: string;
receivedAt: number;
isUnread: boolean;
};
}
export type MessageModelPropsWithoutConvoProps = {
propsForMessage: PropsForMessageWithoutConvoProps;
@ -78,6 +78,7 @@ export type FindAndFormatContactType = {
export type PropsForExpiringMessage = {
convoId?: string;
messageId: string;
direction: MessageModelType;
expirationTimestamp?: number | null;
expirationLength?: number | null;
isExpired?: boolean;
@ -96,7 +97,6 @@ export interface PropsForExpirationTimer extends PropsForExpiringMessage {
messageId: string;
isUnread: boolean;
receivedAt: number | undefined;
direction: MessageModelType;
}
export type PropsForGroupUpdateGeneral = {
@ -140,7 +140,6 @@ export type PropsForGroupUpdate = {
export interface PropsForGroupInvitation extends PropsForExpiringMessage {
serverName: string;
url: string;
direction: MessageModelType;
acceptUrl: string;
messageId: string;
receivedAt?: number;

@ -7,7 +7,6 @@ import { initWallClockListener } from './wallClockListener';
import { Data } from '../data/data';
import { getConversationController } from '../session/conversations';
import { MessageModel } from '../models/message';
import { getNowWithNetworkOffset } from '../session/apis/snode_api/SNodeAPI';
// TODO Might need to be improved by using an enum
@ -198,16 +197,10 @@ export const ExpirationTimerOptions = {
};
export function setExpirationStartTimestamp(
message: MessageModel,
mode: DisappearingMessageType,
timestamp?: number
): MessageModel | null {
if (message.get('expirationStartTimestamp') > 0) {
window.log.info(`WIP: Expiration Timer already set. Ignoring new value.`);
return null;
}
let expirationStartTimestamp = getNowWithNetworkOffset();
): number | undefined {
let expirationStartTimestamp: number | undefined = getNowWithNetworkOffset();
if (timestamp) {
window.log.info(
@ -221,26 +214,25 @@ export function setExpirationStartTimestamp(
expirationStartTimestamp = Math.min(expirationStartTimestamp, timestamp);
}
message.set('expirationStartTimestamp', expirationStartTimestamp);
if (mode === 'deleteAfterRead') {
window.log.info(
`WIP: We set the start timestamp for a delete after read message to ${new Date(
expirationStartTimestamp
).toLocaleTimeString()}`,
message
).toLocaleTimeString()}`
);
} else if (mode === 'deleteAfterSend') {
window.log.info(
`WIP: We set the start timestamp for a delete after send message to ${new Date(
expirationStartTimestamp
).toLocaleTimeString()}`,
message
).toLocaleTimeString()}`
);
} else if (mode === 'off') {
window.log.info(`WIP: Disappearing message mode "${mode}" set. We can safely ignore this.`);
expirationStartTimestamp = undefined;
} else {
console.log(`WIP: Invalid disappearing message mode "${mode}" set. Ignoring`);
return null;
window.log.info(`WIP: Invalid disappearing message mode "${mode}" set. Ignoring`);
expirationStartTimestamp = undefined;
}
return message;
return expirationStartTimestamp;
}

Loading…
Cancel
Save