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, expirationLength,
expirationTimestamp, expirationTimestamp,
isExpired: props.isExpired, isExpired: props.isExpired,
direction: props.direction,
}; };
const { isExpired } = useIsExpired(expiringProps); const { isExpired } = useIsExpired(expiringProps);
const isIncoming = direction === 'incoming'; const isIncoming = direction === 'incoming';

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

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

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

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

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

@ -28,6 +28,7 @@ import { getCallMediaPermissionsSettings } from '../../../components/settings/Se
import { PnServer } from '../../apis/push_notification_api'; import { PnServer } from '../../apis/push_notification_api';
import { getNowWithNetworkOffset } from '../../apis/snode_api/SNodeAPI'; import { getNowWithNetworkOffset } from '../../apis/snode_api/SNodeAPI';
import { approveConvoAndSendResponse } from '../../../interactions/conversationInteractions'; import { approveConvoAndSendResponse } from '../../../interactions/conversationInteractions';
import { setExpirationStartTimestamp } from '../../../util/expiringMessages';
// tslint:disable: function-name // 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 calledConvo.set('active_at', Date.now()); // addSingleOutgoingMessage does the commit for us on the convo
weAreCallerOnCurrentCall = true; weAreCallerOnCurrentCall = true;
const expirationType = calledConvo.get('expirationType');
await calledConvo?.addSingleOutgoingMessage({ await calledConvo?.addSingleOutgoingMessage({
sent_at: now,
expireTimer: 0,
callNotificationType: 'started-call', 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 // 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 networkTimestamp = getNowWithNetworkOffset();
const callerConvo = getConversationController().get(fromSender); const callerConvo = getConversationController().get(fromSender);
callerConvo.set('active_at', networkTimestamp); callerConvo.set('active_at', networkTimestamp);
const expirationType = callerConvo.get('expirationType');
await callerConvo?.addSingleIncomingMessage({ await callerConvo?.addSingleIncomingMessage({
callNotificationType: 'answered-a-call',
source: UserUtils.getOurPubKeyStrFromCache(), source: UserUtils.getOurPubKeyStrFromCache(),
sent_at: networkTimestamp, sent_at: networkTimestamp,
received_at: networkTimestamp, received_at: networkTimestamp,
expireTimer: 0,
callNotificationType: 'answered-a-call',
unread: 0, 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); await buildAnswerAndSendIt(fromSender);
@ -1167,13 +1181,21 @@ async function addMissedCallMessage(callerPubkey: string, sentAt: number) {
incomingCallConversation.set('active_at', getNowWithNetworkOffset()); incomingCallConversation.set('active_at', getNowWithNetworkOffset());
} }
const expirationType = incomingCallConversation.get('expirationType');
await incomingCallConversation?.addSingleIncomingMessage({ await incomingCallConversation?.addSingleIncomingMessage({
callNotificationType: 'missed-call',
source: callerPubkey, source: callerPubkey,
sent_at: sentAt, sent_at: sentAt,
received_at: getNowWithNetworkOffset(), received_at: getNowWithNetworkOffset(),
expireTimer: 0,
callNotificationType: 'missed-call',
unread: 1, 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'; } from '../../util/expiringMessages';
export type CallNotificationType = 'missed-call' | 'started-call' | 'answered-a-call'; export type CallNotificationType = 'missed-call' | 'started-call' | 'answered-a-call';
export type PropsForCallNotification = {
export interface PropsForCallNotification extends PropsForExpiringMessage {
notificationType: CallNotificationType; notificationType: CallNotificationType;
messageId: string;
receivedAt: number; receivedAt: number;
isUnread: boolean; isUnread: boolean;
}; }
export type MessageModelPropsWithoutConvoProps = { export type MessageModelPropsWithoutConvoProps = {
propsForMessage: PropsForMessageWithoutConvoProps; propsForMessage: PropsForMessageWithoutConvoProps;
@ -78,6 +78,7 @@ export type FindAndFormatContactType = {
export type PropsForExpiringMessage = { export type PropsForExpiringMessage = {
convoId?: string; convoId?: string;
messageId: string; messageId: string;
direction: MessageModelType;
expirationTimestamp?: number | null; expirationTimestamp?: number | null;
expirationLength?: number | null; expirationLength?: number | null;
isExpired?: boolean; isExpired?: boolean;
@ -96,7 +97,6 @@ export interface PropsForExpirationTimer extends PropsForExpiringMessage {
messageId: string; messageId: string;
isUnread: boolean; isUnread: boolean;
receivedAt: number | undefined; receivedAt: number | undefined;
direction: MessageModelType;
} }
export type PropsForGroupUpdateGeneral = { export type PropsForGroupUpdateGeneral = {
@ -140,7 +140,6 @@ export type PropsForGroupUpdate = {
export interface PropsForGroupInvitation extends PropsForExpiringMessage { export interface PropsForGroupInvitation extends PropsForExpiringMessage {
serverName: string; serverName: string;
url: string; url: string;
direction: MessageModelType;
acceptUrl: string; acceptUrl: string;
messageId: string; messageId: string;
receivedAt?: number; receivedAt?: number;

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

Loading…
Cancel
Save