Fixes for quotes/schema upgrade, optimize media gallery load
Also: Fix for contact detail page; didn't show back button
This commit is contained in:
parent
95976b10e7
commit
db91560990
6 changed files with 109 additions and 138 deletions
|
@ -25,10 +25,13 @@
|
||||||
Contact,
|
Contact,
|
||||||
Errors,
|
Errors,
|
||||||
Message,
|
Message,
|
||||||
VisualAttachment,
|
|
||||||
PhoneNumber,
|
PhoneNumber,
|
||||||
} = window.Signal.Types;
|
} = window.Signal.Types;
|
||||||
const { upgradeMessageSchema, loadAttachmentData } = window.Signal.Migrations;
|
const {
|
||||||
|
upgradeMessageSchema,
|
||||||
|
loadAttachmentData,
|
||||||
|
getAbsoluteAttachmentPath,
|
||||||
|
} = window.Signal.Migrations;
|
||||||
|
|
||||||
// TODO: Factor out private and group subclasses of Conversation
|
// TODO: Factor out private and group subclasses of Conversation
|
||||||
|
|
||||||
|
@ -771,47 +774,6 @@
|
||||||
return _.without(this.get('members'), me);
|
return _.without(this.get('members'), me);
|
||||||
},
|
},
|
||||||
|
|
||||||
blobToArrayBuffer(blob) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const fileReader = new FileReader();
|
|
||||||
|
|
||||||
fileReader.onload = e => resolve(e.target.result);
|
|
||||||
fileReader.onerror = reject;
|
|
||||||
fileReader.onabort = reject;
|
|
||||||
|
|
||||||
fileReader.readAsArrayBuffer(blob);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
async makeThumbnailAttachment(attachment) {
|
|
||||||
const { arrayBufferToObjectURL } = Util;
|
|
||||||
const attachmentWithData = await loadAttachmentData(attachment);
|
|
||||||
const { data, contentType } = attachmentWithData;
|
|
||||||
const objectUrl = arrayBufferToObjectURL({
|
|
||||||
data,
|
|
||||||
type: contentType,
|
|
||||||
});
|
|
||||||
|
|
||||||
const thumbnail = GoogleChrome.isImageTypeSupported(contentType)
|
|
||||||
? await VisualAttachment.makeImageThumbnail(128, objectUrl)
|
|
||||||
: await VisualAttachment.makeVideoThumbnail(128, objectUrl);
|
|
||||||
|
|
||||||
URL.revokeObjectURL(objectUrl);
|
|
||||||
|
|
||||||
const arrayBuffer = await this.blobToArrayBuffer(thumbnail);
|
|
||||||
const finalContentType = 'image/png';
|
|
||||||
const finalObjectUrl = arrayBufferToObjectURL({
|
|
||||||
data: arrayBuffer,
|
|
||||||
type: finalContentType,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: arrayBuffer,
|
|
||||||
objectUrl: finalObjectUrl,
|
|
||||||
contentType: finalContentType,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
async makeQuote(quotedMessage) {
|
async makeQuote(quotedMessage) {
|
||||||
const { getName } = Contact;
|
const { getName } = Contact;
|
||||||
const contact = quotedMessage.getContact();
|
const contact = quotedMessage.getContact();
|
||||||
|
@ -830,29 +792,17 @@
|
||||||
text: body || embeddedContactName,
|
text: body || embeddedContactName,
|
||||||
attachments: await Promise.all(
|
attachments: await Promise.all(
|
||||||
(attachments || []).map(async attachment => {
|
(attachments || []).map(async attachment => {
|
||||||
const { contentType } = attachment;
|
const { contentType, fileName, thumbnail } = attachment;
|
||||||
const willMakeThumbnail =
|
|
||||||
GoogleChrome.isImageTypeSupported(contentType) ||
|
|
||||||
GoogleChrome.isVideoTypeSupported(contentType);
|
|
||||||
const makeThumbnail = async () => {
|
|
||||||
try {
|
|
||||||
if (willMakeThumbnail) {
|
|
||||||
return await this.makeThumbnailAttachment(attachment);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log(
|
|
||||||
'Failed to create quote thumbnail',
|
|
||||||
error && error.stack ? error.stack : error
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
contentType,
|
contentType,
|
||||||
fileName: attachment.fileName,
|
fileName,
|
||||||
thumbnail: await makeThumbnail(),
|
thumbnail: thumbnail
|
||||||
|
? {
|
||||||
|
...(await loadAttachmentData(thumbnail)),
|
||||||
|
path: getAbsoluteAttachmentPath(thumbnail.path),
|
||||||
|
}
|
||||||
|
: null,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
@ -1409,25 +1359,41 @@
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (
|
||||||
|
queryMessage.get('schemaVersion') < Message.CURRENT_SCHEMA_VERSION
|
||||||
|
) {
|
||||||
|
const upgradedMessage = await upgradeMessageSchema(
|
||||||
|
queryMessage.attributes
|
||||||
|
);
|
||||||
|
queryMessage.set(upgradedMessage);
|
||||||
|
await wrapDeferred(message.save());
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(
|
||||||
|
'Problem upgrading message quoted message from database',
|
||||||
|
Errors.toLogFormat(error)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const queryAttachments = queryMessage.attachments || [];
|
const queryAttachments = queryMessage.attachments || [];
|
||||||
if (queryAttachments.length === 0) {
|
if (queryAttachments.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const queryFirst = queryAttachments[0];
|
const queryFirst = queryAttachments[0];
|
||||||
try {
|
const { thumbnail } = queryFirst;
|
||||||
// eslint-disable-next-line no-param-reassign
|
|
||||||
message.quoteThumbnail = await this.makeThumbnailAttachment(queryFirst);
|
// eslint-disable-next-line no-param-reassign
|
||||||
return true;
|
message.quoteThumbnail = {
|
||||||
} catch (error) {
|
...thumbnail,
|
||||||
console.log(
|
objectUrl: getAbsoluteAttachmentPath(thumbnail.path),
|
||||||
'Problem loading attachment data for quoted message from database',
|
};
|
||||||
Errors.toLogFormat(error)
|
|
||||||
);
|
return true;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
async loadQuotedMessage(message, quotedMessage) {
|
loadQuotedMessage(message, quotedMessage) {
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
message.quotedMessage = quotedMessage;
|
message.quotedMessage = quotedMessage;
|
||||||
|
|
||||||
|
@ -1451,19 +1417,20 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
const queryFirst = quotedAttachments[0];
|
||||||
const queryFirst = quotedAttachments[0];
|
const { thumbnail } = queryFirst;
|
||||||
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
if (!thumbnail) {
|
||||||
message.quoteThumbnail = await this.makeThumbnailAttachment(queryFirst);
|
return;
|
||||||
} catch (error) {
|
|
||||||
console.log(
|
|
||||||
'Problem loading attachment data for quoted message',
|
|
||||||
error && error.stack ? error.stack : error
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
message.quoteThumbnail = {
|
||||||
|
...thumbnail,
|
||||||
|
objectUrl: getAbsoluteAttachmentPath(thumbnail.path),
|
||||||
|
};
|
||||||
},
|
},
|
||||||
async loadQuoteThumbnail(message) {
|
loadQuoteThumbnail(message) {
|
||||||
const { quote } = message.attributes;
|
const { quote } = message.attributes;
|
||||||
const { attachments } = quote;
|
const { attachments } = quote;
|
||||||
const first = attachments[0];
|
const first = attachments[0];
|
||||||
|
@ -1477,27 +1444,15 @@
|
||||||
if (!thumbnail) {
|
if (!thumbnail) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
// If we update this data in place, there's the risk that this data could be
|
||||||
const thumbnailWithData = await loadAttachmentData(thumbnail);
|
// saved back to the database
|
||||||
const { data, contentType } = thumbnailWithData;
|
// eslint-disable-next-line no-param-reassign
|
||||||
thumbnailWithData.objectUrl = Util.arrayBufferToObjectURL({
|
message.quoteThumbnail = {
|
||||||
data,
|
...thumbnail,
|
||||||
type: contentType,
|
objectUrl: getAbsoluteAttachmentPath(thumbnail.path),
|
||||||
});
|
};
|
||||||
|
|
||||||
// If we update this data in place, there's the risk that this data could be
|
return true;
|
||||||
// saved back to the database
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
|
||||||
message.quoteThumbnail = thumbnailWithData;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
console.log(
|
|
||||||
'loadQuoteThumbnail: had trouble loading thumbnail data from disk',
|
|
||||||
error && error.stack ? error.stack : error
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
async processQuotes(messages) {
|
async processQuotes(messages) {
|
||||||
const lookup = this.makeMessagesLookup(messages);
|
const lookup = this.makeMessagesLookup(messages);
|
||||||
|
@ -1516,7 +1471,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Load provided thumbnail
|
// 1. Load provided thumbnail
|
||||||
const gotThumbnail = await this.loadQuoteThumbnail(message, quote);
|
if (this.loadQuoteThumbnail(message, quote)) {
|
||||||
|
this.forceRender(message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Check to see if we've already loaded the target message into memory
|
// 2. Check to see if we've already loaded the target message into memory
|
||||||
const { author, id } = quote;
|
const { author, id } = quote;
|
||||||
|
@ -1524,13 +1482,7 @@
|
||||||
const quotedMessage = lookup[key];
|
const quotedMessage = lookup[key];
|
||||||
|
|
||||||
if (quotedMessage) {
|
if (quotedMessage) {
|
||||||
await this.loadQuotedMessage(message, quotedMessage);
|
this.loadQuotedMessage(message, quotedMessage);
|
||||||
this.forceRender(message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No need to go further if we already have a thumbnail
|
|
||||||
if (gotThumbnail) {
|
|
||||||
this.forceRender(message);
|
this.forceRender(message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1566,10 +1518,11 @@
|
||||||
const { schemaVersion } = attributes;
|
const { schemaVersion } = attributes;
|
||||||
|
|
||||||
if (schemaVersion < Message.CURRENT_SCHEMA_VERSION) {
|
if (schemaVersion < Message.CURRENT_SCHEMA_VERSION) {
|
||||||
const upgradedMessage = upgradeMessageSchema(attributes);
|
|
||||||
message.set(upgradedMessage);
|
|
||||||
// Yep, we really do want to wait for each of these
|
// Yep, we really do want to wait for each of these
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
const upgradedMessage = await upgradeMessageSchema(attributes);
|
||||||
|
message.set(upgradedMessage);
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
await wrapDeferred(message.save());
|
await wrapDeferred(message.save());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -283,12 +283,14 @@
|
||||||
processAttachment(attachment, externalObjectUrl) {
|
processAttachment(attachment, externalObjectUrl) {
|
||||||
const { thumbnail } = attachment;
|
const { thumbnail } = attachment;
|
||||||
const objectUrl = (thumbnail && thumbnail.objectUrl) || externalObjectUrl;
|
const objectUrl = (thumbnail && thumbnail.objectUrl) || externalObjectUrl;
|
||||||
|
const path = thumbnail && thumbnail.path;
|
||||||
|
|
||||||
const thumbnailWithObjectUrl = !objectUrl
|
const thumbnailWithObjectUrl =
|
||||||
? null
|
!objectUrl && !path
|
||||||
: Object.assign({}, attachment.thumbnail || {}, {
|
? null
|
||||||
objectUrl,
|
: Object.assign({}, attachment.thumbnail || {}, {
|
||||||
});
|
objectUrl: objectUrl || path,
|
||||||
|
});
|
||||||
|
|
||||||
return Object.assign({}, attachment, {
|
return Object.assign({}, attachment, {
|
||||||
isVoiceMessage: Signal.Types.Attachment.isVoiceMessage(attachment),
|
isVoiceMessage: Signal.Types.Attachment.isVoiceMessage(attachment),
|
||||||
|
|
|
@ -167,7 +167,7 @@
|
||||||
openConversation(conversation) {
|
openConversation(conversation) {
|
||||||
if (conversation) {
|
if (conversation) {
|
||||||
this.openInbox().then(() => {
|
this.openInbox().then(() => {
|
||||||
this.inboxView.openConversation(null, conversation);
|
this.inboxView.openConversation(conversation);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
/* global Signal: false */
|
/* global Signal: false */
|
||||||
/* global storage: false */
|
/* global storage: false */
|
||||||
/* global Whisper: false */
|
/* global Whisper: false */
|
||||||
|
/* global wrapDeferred: false */
|
||||||
|
|
||||||
// eslint-disable-next-line func-names
|
// eslint-disable-next-line func-names
|
||||||
(function() {
|
(function() {
|
||||||
|
@ -14,6 +15,11 @@
|
||||||
|
|
||||||
window.Whisper = window.Whisper || {};
|
window.Whisper = window.Whisper || {};
|
||||||
const { Migrations } = Signal;
|
const { Migrations } = Signal;
|
||||||
|
const { Message } = window.Signal.Types;
|
||||||
|
const {
|
||||||
|
upgradeMessageSchema,
|
||||||
|
getAbsoluteAttachmentPath,
|
||||||
|
} = window.Signal.Migrations;
|
||||||
|
|
||||||
Whisper.ExpiredToast = Whisper.ToastView.extend({
|
Whisper.ExpiredToast = Whisper.ToastView.extend({
|
||||||
render_attributes() {
|
render_attributes() {
|
||||||
|
@ -603,13 +609,29 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// NOTE: Could we show grid previews from disk as well?
|
// First we upgrade these messages to ensure that they have thumbnails
|
||||||
const loadMessages = Signal.Components.Types.Message.loadWithObjectURL(
|
for (let max = rawMedia.length, i = 0; i < max; i += 1) {
|
||||||
Migrations.loadMessage
|
const message = rawMedia[i];
|
||||||
);
|
const { schemaVersion } = message;
|
||||||
const media = await loadMessages(rawMedia);
|
|
||||||
|
if (schemaVersion < Message.CURRENT_SCHEMA_VERSION) {
|
||||||
|
// Yep, we really do want to wait for each of these
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
rawMedia[i] = await upgradeMessageSchema(message);
|
||||||
|
const model = new Whisper.Message(rawMedia[i]);
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
await wrapDeferred(model.save());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const media = rawMedia.map(mediaMessage =>
|
||||||
|
Object.assign({}, mediaMessage, {
|
||||||
|
objectURL: getAbsoluteAttachmentPath(
|
||||||
|
mediaMessage.attachments[0].path
|
||||||
|
),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const { getAbsoluteAttachmentPath } = Signal.Migrations;
|
|
||||||
const saveAttachment = async ({ message } = {}) => {
|
const saveAttachment = async ({ message } = {}) => {
|
||||||
const attachment = message.attachments[0];
|
const attachment = message.attachments[0];
|
||||||
const timestamp = message.received_at;
|
const timestamp = message.received_at;
|
||||||
|
@ -629,13 +651,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'media': {
|
case 'media': {
|
||||||
const mediaWithObjectURL = media.map(mediaMessage =>
|
|
||||||
Object.assign({}, mediaMessage, {
|
|
||||||
objectURL: getAbsoluteAttachmentPath(
|
|
||||||
mediaMessage.attachments[0].path
|
|
||||||
),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
const selectedIndex = media.findIndex(
|
const selectedIndex = media.findIndex(
|
||||||
mediaMessage => mediaMessage.id === message.id
|
mediaMessage => mediaMessage.id === message.id
|
||||||
);
|
);
|
||||||
|
@ -643,7 +658,7 @@
|
||||||
className: 'lightbox-wrapper',
|
className: 'lightbox-wrapper',
|
||||||
Component: Signal.Components.LightboxGallery,
|
Component: Signal.Components.LightboxGallery,
|
||||||
props: {
|
props: {
|
||||||
messages: mediaWithObjectURL,
|
messages: media,
|
||||||
onSave: () => saveAttachment({ message }),
|
onSave: () => saveAttachment({ message }),
|
||||||
selectedIndex,
|
selectedIndex,
|
||||||
},
|
},
|
||||||
|
@ -1055,6 +1070,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
this.listenBack(view);
|
this.listenBack(view);
|
||||||
|
this.updateHeader();
|
||||||
},
|
},
|
||||||
|
|
||||||
async openConversation(number) {
|
async openConversation(number) {
|
||||||
|
|
|
@ -247,10 +247,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
openConversation(conversation) {
|
openConversation(conversation) {
|
||||||
ConversationController.markAsSelected(conversation);
|
|
||||||
|
|
||||||
this.searchView.hideHints();
|
this.searchView.hideHints();
|
||||||
if (conversation) {
|
if (conversation) {
|
||||||
|
ConversationController.markAsSelected(conversation);
|
||||||
this.conversation_stack.open(
|
this.conversation_stack.open(
|
||||||
ConversationController.get(conversation.id)
|
ConversationController.get(conversation.id)
|
||||||
);
|
);
|
||||||
|
|
|
@ -179,7 +179,8 @@
|
||||||
// height calculation.
|
// height calculation.
|
||||||
.bottom-bar .quote-wrapper {
|
.bottom-bar .quote-wrapper {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 6px;
|
||||||
|
margin-top: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.send .quote-wrapper {
|
.send .quote-wrapper {
|
||||||
|
|
Loading…
Add table
Reference in a new issue