Changes to View Once
This commit is contained in:
parent
9d88abdb90
commit
d42eb2126e
14 changed files with 152 additions and 167 deletions
|
@ -1698,13 +1698,12 @@
|
|||
}
|
||||
|
||||
async function onViewSync(ev) {
|
||||
const { viewedAt, source, timestamp } = ev;
|
||||
window.log.info(`view sync ${source} ${timestamp}, viewed at ${viewedAt}`);
|
||||
const { source, timestamp } = ev;
|
||||
window.log.info(`view sync ${source} ${timestamp}`);
|
||||
|
||||
const sync = Whisper.ViewSyncs.add({
|
||||
source,
|
||||
timestamp,
|
||||
viewedAt,
|
||||
});
|
||||
|
||||
sync.on('remove', ev.confirm);
|
||||
|
|
|
@ -52,22 +52,12 @@
|
|||
const toAgeOut = await window.Signal.Data.getNextTapToViewMessageToAgeOut({
|
||||
Message: Whisper.Message,
|
||||
});
|
||||
const toExpire = await window.Signal.Data.getNextTapToViewMessageToExpire({
|
||||
Message: Whisper.Message,
|
||||
});
|
||||
|
||||
if (!toAgeOut && !toExpire) {
|
||||
if (!toAgeOut) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ageOutAt = toAgeOut
|
||||
? toAgeOut.get('received_at') + THIRTY_DAYS
|
||||
: Number.MAX_VALUE;
|
||||
const expireAt = toExpire
|
||||
? toExpire.get('messageTimerExpiresAt')
|
||||
: Number.MAX_VALUE;
|
||||
|
||||
const nextCheck = Math.min(ageOutAt, expireAt);
|
||||
const nextCheck = toAgeOut.get('received_at') + THIRTY_DAYS;
|
||||
|
||||
Whisper.TapToViewMessagesListener.nextCheck = nextCheck;
|
||||
window.log.info(
|
||||
|
|
|
@ -495,8 +495,7 @@
|
|||
expirationTimestamp,
|
||||
|
||||
isTapToView,
|
||||
isTapToViewExpired:
|
||||
isTapToView && (this.get('isErased') || this.isTapToViewExpired()),
|
||||
isTapToViewExpired: isTapToView && this.get('isErased'),
|
||||
isTapToViewError:
|
||||
isTapToView && this.isIncoming() && this.get('isTapToViewInvalid'),
|
||||
|
||||
|
@ -870,7 +869,7 @@
|
|||
}
|
||||
},
|
||||
isTapToView() {
|
||||
return Boolean(this.get('messageTimer'));
|
||||
return Boolean(this.get('isViewOnce') || this.get('messageTimer'));
|
||||
},
|
||||
isValidTapToView() {
|
||||
const body = this.get('body');
|
||||
|
@ -908,66 +907,27 @@
|
|||
|
||||
return true;
|
||||
},
|
||||
isTapToViewExpired() {
|
||||
const THIRTY_DAYS = 30 * 24 * 60 * 60 * 1000;
|
||||
const now = Date.now();
|
||||
|
||||
const receivedAt = this.get('received_at');
|
||||
if (now >= receivedAt + THIRTY_DAYS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const messageTimer = this.get('messageTimer');
|
||||
const messageTimerStart = this.get('messageTimerStart');
|
||||
if (!messageTimerStart) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const expiresAt = messageTimerStart + messageTimer * 1000;
|
||||
if (now >= expiresAt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
async startTapToViewTimer(viewedAt, options) {
|
||||
async markViewed(options) {
|
||||
const { fromSync } = options || {};
|
||||
|
||||
if (!this.isValidTapToView()) {
|
||||
window.log.warn(
|
||||
`markViewed: Message ${this.idForLogging()} is not a valid tap to view message!`
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (this.isErased()) {
|
||||
window.log.warn(
|
||||
`markViewed: Message ${this.idForLogging()} is already erased!`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.get('unread')) {
|
||||
await this.markRead();
|
||||
}
|
||||
|
||||
const messageTimer = this.get('messageTimer');
|
||||
if (!messageTimer) {
|
||||
window.log.warn(
|
||||
`startTapToViewTimer: Message ${this.idForLogging()} has no messageTimer!`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const existingTimerStart = this.get('messageTimerStart');
|
||||
const messageTimerStart = Math.min(
|
||||
Date.now(),
|
||||
viewedAt || Date.now(),
|
||||
existingTimerStart || Date.now()
|
||||
);
|
||||
const messageTimerExpiresAt = messageTimerStart + messageTimer * 1000;
|
||||
|
||||
// Because we're not using Backbone-integrated saves, we need to manually
|
||||
// clear the changed fields here so our hasChanged() check below is useful.
|
||||
this.changed = {};
|
||||
this.set({
|
||||
messageTimerStart,
|
||||
messageTimerExpiresAt,
|
||||
});
|
||||
|
||||
if (!this.hasChanged()) {
|
||||
return;
|
||||
}
|
||||
|
||||
await window.Signal.Data.saveMessage(this.attributes, {
|
||||
Message: Whisper.Message,
|
||||
});
|
||||
await this.eraseContents();
|
||||
|
||||
if (!fromSync) {
|
||||
const sender = this.getSource();
|
||||
|
@ -979,14 +939,13 @@
|
|||
);
|
||||
|
||||
await wrap(
|
||||
textsecure.messaging.syncMessageTimerRead(
|
||||
sender,
|
||||
timestamp,
|
||||
sendOptions
|
||||
)
|
||||
textsecure.messaging.syncViewOnceOpen(sender, timestamp, sendOptions)
|
||||
);
|
||||
}
|
||||
},
|
||||
isErased() {
|
||||
return Boolean(this.get('isErased'));
|
||||
},
|
||||
async eraseContents() {
|
||||
if (this.get('isErased')) {
|
||||
return;
|
||||
|
@ -1940,7 +1899,7 @@
|
|||
hasAttachments: dataMessage.hasAttachments,
|
||||
hasFileAttachments: dataMessage.hasFileAttachments,
|
||||
hasVisualMediaAttachments: dataMessage.hasVisualMediaAttachments,
|
||||
messageTimer: dataMessage.messageTimer,
|
||||
isViewOnce: Boolean(dataMessage.isViewOnce),
|
||||
preview,
|
||||
requiredProtocolVersion:
|
||||
dataMessage.requiredProtocolVersion ||
|
||||
|
|
|
@ -715,7 +715,7 @@ async function exportConversation(conversation, options = {}) {
|
|||
count += 1;
|
||||
|
||||
// skip message if it is disappearing, no matter the amount of time left
|
||||
if (message.expireTimer || message.messageTimer) {
|
||||
if (message.expireTimer || message.messageTimer || message.isViewOnce) {
|
||||
// eslint-disable-next-line no-continue
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -122,7 +122,6 @@ module.exports = {
|
|||
getOutgoingWithoutExpiresAt,
|
||||
getNextExpiringMessage,
|
||||
getMessagesByConversation,
|
||||
getNextTapToViewMessageToExpire,
|
||||
getNextTapToViewMessageToAgeOut,
|
||||
getTapToViewMessagesNeedingErase,
|
||||
|
||||
|
@ -842,14 +841,6 @@ async function getNextExpiringMessage({ MessageCollection }) {
|
|||
return new MessageCollection(messages);
|
||||
}
|
||||
|
||||
async function getNextTapToViewMessageToExpire({ Message }) {
|
||||
const message = await channels.getNextTapToViewMessageToExpire();
|
||||
if (!message) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Message(message);
|
||||
}
|
||||
async function getNextTapToViewMessageToAgeOut({ Message }) {
|
||||
const message = await channels.getNextTapToViewMessageToAgeOut();
|
||||
if (!message) {
|
||||
|
|
|
@ -169,10 +169,14 @@ function initializeMigrations({
|
|||
const writeNewTempData = createWriterForNew(tempPath);
|
||||
const deleteTempFile = Attachments.createDeleter(tempPath);
|
||||
const readTempData = createReader(tempPath);
|
||||
const copyIntoTempDirectory = Attachments.copyIntoAttachmentsDirectory(
|
||||
tempPath
|
||||
);
|
||||
|
||||
return {
|
||||
attachmentsPath,
|
||||
copyIntoAttachmentsDirectory,
|
||||
copyIntoTempDirectory,
|
||||
deleteAttachmentData: deleteOnDisk,
|
||||
deleteExternalMessageFiles: MessageType.deleteAllExternalFiles({
|
||||
deleteAttachmentData: Type.deleteData(deleteOnDisk),
|
||||
|
@ -182,6 +186,7 @@ function initializeMigrations({
|
|||
deleteTempFile,
|
||||
getAbsoluteAttachmentPath,
|
||||
getAbsoluteStickerPath,
|
||||
getAbsoluteTempPath,
|
||||
getPlaceholderMigrations,
|
||||
getCurrentVersion,
|
||||
loadAttachmentData,
|
||||
|
|
|
@ -51,9 +51,7 @@
|
|||
}
|
||||
|
||||
const message = MessageController.register(found.id, found);
|
||||
|
||||
const viewedAt = sync.get('viewedAt');
|
||||
await message.startTapToViewTimer(viewedAt, { fromSync: true });
|
||||
await message.markViewed({ fromSync: true });
|
||||
|
||||
this.remove(sync);
|
||||
} catch (error) {
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
const {
|
||||
upgradeMessageSchema,
|
||||
getAbsoluteAttachmentPath,
|
||||
copyIntoTempDirectory,
|
||||
getAbsoluteTempPath,
|
||||
deleteTempFile,
|
||||
} = window.Signal.Migrations;
|
||||
|
||||
Whisper.ExpiredToast = Whisper.ToastView.extend({
|
||||
|
@ -1324,17 +1327,33 @@
|
|||
|
||||
if (!message.isTapToView()) {
|
||||
throw new Error(
|
||||
`displayTapToViewMessage: Message ${message.idForLogging()} is not tap to view`
|
||||
`displayTapToViewMessage: Message ${message.idForLogging()} is not a tap to view message`
|
||||
);
|
||||
}
|
||||
|
||||
if (message.isTapToViewExpired()) {
|
||||
return;
|
||||
if (message.isErased()) {
|
||||
throw new Error(
|
||||
`displayTapToViewMessage: Message ${message.idForLogging()} is already erased`
|
||||
);
|
||||
}
|
||||
|
||||
await message.startTapToViewTimer();
|
||||
const firstAttachment = message.get('attachments')[0];
|
||||
if (!firstAttachment || !firstAttachment.path) {
|
||||
throw new Error(
|
||||
`displayTapToViewMessage: Message ${message.idForLogging()} had no first attachment with path`
|
||||
);
|
||||
}
|
||||
|
||||
const closeLightbox = () => {
|
||||
const absolutePath = getAbsoluteAttachmentPath(firstAttachment.path);
|
||||
const tempPath = await copyIntoTempDirectory(absolutePath);
|
||||
const tempAttachment = {
|
||||
...firstAttachment,
|
||||
path: tempPath,
|
||||
};
|
||||
|
||||
await message.markViewed();
|
||||
|
||||
const closeLightbox = async () => {
|
||||
if (!this.lightboxView) {
|
||||
return;
|
||||
}
|
||||
|
@ -1345,6 +1364,8 @@
|
|||
this.stopListening(message);
|
||||
Signal.Backbone.Views.Lightbox.hide();
|
||||
lightboxView.remove();
|
||||
|
||||
await deleteTempFile(tempPath);
|
||||
};
|
||||
this.listenTo(message, 'expired', closeLightbox);
|
||||
this.listenTo(message, 'change', () => {
|
||||
|
@ -1354,14 +1375,11 @@
|
|||
});
|
||||
|
||||
const getProps = () => {
|
||||
const firstAttachment = message.get('attachments')[0];
|
||||
const { path, contentType } = firstAttachment;
|
||||
const { path, contentType } = tempAttachment;
|
||||
|
||||
return {
|
||||
objectURL: getAbsoluteAttachmentPath(path),
|
||||
objectURL: getAbsoluteTempPath(path),
|
||||
contentType,
|
||||
timerExpiresAt: message.get('messageTimerExpiresAt'),
|
||||
timerDuration: message.get('messageTimer') * 1000,
|
||||
};
|
||||
};
|
||||
this.lightboxView = new Whisper.ReactWrapperView({
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue