View All Media: Listen for updates to conversation, re-render

This commit is contained in:
Scott Nonnenberg 2019-02-19 15:17:52 -08:00
parent d4eacda649
commit 9afea3ae2b

View file

@ -767,125 +767,141 @@
const DEFAULT_DOCUMENTS_FETCH_COUNT = 150; const DEFAULT_DOCUMENTS_FETCH_COUNT = 150;
const conversationId = this.model.get('id'); const conversationId = this.model.get('id');
const rawMedia = await Signal.Data.getMessagesWithVisualMediaAttachments(
conversationId,
{
limit: DEFAULT_MEDIA_FETCH_COUNT,
MessageCollection: Whisper.MessageCollection,
}
);
const rawDocuments = await Signal.Data.getMessagesWithFileAttachments(
conversationId,
{
limit: DEFAULT_DOCUMENTS_FETCH_COUNT,
MessageCollection: Whisper.MessageCollection,
}
);
// First we upgrade these messages to ensure that they have thumbnails const getProps = async () => {
for (let max = rawMedia.length, i = 0; i < max; i += 1) { const rawMedia = await Signal.Data.getMessagesWithVisualMediaAttachments(
const message = rawMedia[i]; conversationId,
const { schemaVersion } = message; {
limit: DEFAULT_MEDIA_FETCH_COUNT,
MessageCollection: Whisper.MessageCollection,
}
);
const rawDocuments = await Signal.Data.getMessagesWithFileAttachments(
conversationId,
{
limit: DEFAULT_DOCUMENTS_FETCH_COUNT,
MessageCollection: Whisper.MessageCollection,
}
);
if (schemaVersion < Message.VERSION_NEEDED_FOR_DISPLAY) { // First we upgrade these messages to ensure that they have thumbnails
// Yep, we really do want to wait for each of these for (let max = rawMedia.length, i = 0; i < max; i += 1) {
// eslint-disable-next-line no-await-in-loop const message = rawMedia[i];
rawMedia[i] = await upgradeMessageSchema(message); const { schemaVersion } = message;
// eslint-disable-next-line no-await-in-loop
await window.Signal.Data.saveMessage(rawMedia[i], {
Message: Whisper.Message,
});
}
}
const media = _.flatten( if (schemaVersion < Message.VERSION_NEEDED_FOR_DISPLAY) {
rawMedia.map(message => { // Yep, we really do want to wait for each of these
const { attachments } = message; // eslint-disable-next-line no-await-in-loop
return (attachments || []) rawMedia[i] = await upgradeMessageSchema(message);
.filter( // eslint-disable-next-line no-await-in-loop
attachment => await window.Signal.Data.saveMessage(rawMedia[i], {
attachment.thumbnail && !attachment.pending && !attachment.error Message: Whisper.Message,
)
.map((attachment, index) => {
const { thumbnail } = attachment;
return {
objectURL: getAbsoluteAttachmentPath(attachment.path),
thumbnailObjectUrl: thumbnail
? getAbsoluteAttachmentPath(thumbnail.path)
: null,
contentType: attachment.contentType,
index,
attachment,
message,
};
}); });
}) }
); }
// Unlike visual media, only one non-image attachment is supported const media = _.flatten(
const documents = rawDocuments.map(message => { rawMedia.map(message => {
const attachments = message.attachments || []; const { attachments } = message;
const attachment = attachments[0]; return (attachments || [])
return { .filter(
contentType: attachment.contentType, attachment =>
index: 0, attachment.thumbnail &&
attachment, !attachment.pending &&
message, !attachment.error
}; )
}); .map((attachment, index) => {
const { thumbnail } = attachment;
const saveAttachment = async ({ attachment, message } = {}) => { return {
const timestamp = message.received_at; objectURL: getAbsoluteAttachmentPath(attachment.path),
Signal.Types.Attachment.save({ thumbnailObjectUrl: thumbnail
attachment, ? getAbsoluteAttachmentPath(thumbnail.path)
document, : null,
getAbsolutePath: getAbsoluteAttachmentPath, contentType: attachment.contentType,
timestamp, index,
attachment,
message,
};
});
})
);
// Unlike visual media, only one non-image attachment is supported
const documents = rawDocuments.map(message => {
const attachments = message.attachments || [];
const attachment = attachments[0];
return {
contentType: attachment.contentType,
index: 0,
attachment,
message,
};
}); });
};
const onItemClick = async ({ message, attachment, type }) => { const saveAttachment = async ({ attachment, message } = {}) => {
switch (type) { const timestamp = message.received_at;
case 'documents': { Signal.Types.Attachment.save({
saveAttachment({ message, attachment }); attachment,
break; document,
getAbsolutePath: getAbsoluteAttachmentPath,
timestamp,
});
};
const onItemClick = async ({ message, attachment, type }) => {
switch (type) {
case 'documents': {
saveAttachment({ message, attachment });
break;
}
case 'media': {
const selectedIndex = media.findIndex(
mediaMessage => mediaMessage.attachment.path === attachment.path
);
this.lightboxGalleryView = new Whisper.ReactWrapperView({
className: 'lightbox-wrapper',
Component: Signal.Components.LightboxGallery,
props: {
media,
onSave: saveAttachment,
selectedIndex,
},
onClose: () => Signal.Backbone.Views.Lightbox.hide(),
});
Signal.Backbone.Views.Lightbox.show(this.lightboxGalleryView.el);
break;
}
default:
throw new TypeError(`Unknown attachment type: '${type}'`);
} }
};
case 'media': { return {
const selectedIndex = media.findIndex( documents,
mediaMessage => mediaMessage.attachment.path === attachment.path media,
); onItemClick,
this.lightboxGalleryView = new Whisper.ReactWrapperView({ };
className: 'lightbox-wrapper',
Component: Signal.Components.LightboxGallery,
props: {
media,
onSave: saveAttachment,
selectedIndex,
},
onClose: () => Signal.Backbone.Views.Lightbox.hide(),
});
Signal.Backbone.Views.Lightbox.show(this.lightboxGalleryView.el);
break;
}
default:
throw new TypeError(`Unknown attachment type: '${type}'`);
}
}; };
const view = new Whisper.ReactWrapperView({ const view = new Whisper.ReactWrapperView({
className: 'panel-wrapper', className: 'panel-wrapper',
Component: Signal.Components.MediaGallery, Component: Signal.Components.MediaGallery,
props: { props: await getProps(),
documents, onClose: () => {
media, this.stopListening(this.model.messageCollection, 'remove', update);
onItemClick, this.resetPanel();
}, },
onClose: () => this.resetPanel(),
}); });
const update = async () => {
view.update(await getProps());
};
this.listenTo(this.model.messageCollection, 'remove', update);
this.listenBack(view); this.listenBack(view);
}, },
@ -1294,20 +1310,23 @@
}, },
showMessageDetail(message) { showMessageDetail(message) {
const onClose = () => {
this.stopListening(message, 'change', update);
this.resetPanel();
this.updateHeader();
};
const props = message.getPropsForMessageDetail(); const props = message.getPropsForMessageDetail();
const view = new Whisper.ReactWrapperView({ const view = new Whisper.ReactWrapperView({
className: 'message-detail-wrapper', className: 'message-detail-wrapper',
Component: Signal.Components.MessageDetail, Component: Signal.Components.MessageDetail,
props, props,
onClose: () => { onClose,
this.stopListening(message, 'change', update);
this.resetPanel();
this.updateHeader();
},
}); });
const update = () => view.update(message.getPropsForMessageDetail()); const update = () => view.update(message.getPropsForMessageDetail());
this.listenTo(message, 'change', update); this.listenTo(message, 'change', update);
this.listenTo(message, 'expired', onClose);
// We could listen to all involved contacts, but we'll call that overkill // We could listen to all involved contacts, but we'll call that overkill
this.listenBack(view); this.listenBack(view);