Display attachments from disk

This commit is contained in:
Daniel Gasienica 2018-04-26 16:48:08 -04:00
parent 407c77395b
commit e1b620602d
6 changed files with 70 additions and 35 deletions

View file

@ -180,6 +180,7 @@
Signal.Types.AttachmentTS.save({
attachment: this.model,
document,
getAbsolutePath: Signal.Migrations.getAbsoluteAttachmentPath,
timestamp: this.timestamp,
});
},

View file

@ -282,8 +282,8 @@
if (this.quoteView) {
this.quoteView.remove();
}
if (this.lightboxView) {
this.lightboxView.remove();
if (this.lightboxGalleryView) {
this.lightboxGalleryView.remove();
}
if (this.panels && this.panels.length) {
for (let i = 0, max = this.panels.length; i < max; i += 1) {
@ -598,6 +598,7 @@
WhisperMessageCollection,
});
// NOTE: Could we show grid previews from disk as well?
const loadMessages = Signal.Components.Types.Message
.loadWithObjectURL(Signal.Migrations.loadMessage);
const media = await loadMessages(rawMedia);
@ -605,30 +606,36 @@
const saveAttachment = async ({ message } = {}) => {
const attachment = message.attachments[0];
const timestamp = message.received_at;
Signal.Types.AttachmentTS.save({ attachment, timestamp });
Signal.Types.AttachmentTS.save({
attachment,
document,
getAbsolutePath: Signal.Migrations.getAbsoluteAttachmentPath,
timestamp,
});
};
const onItemClick = async ({ message, type }) => {
const loadedMessage = Signal.Components.Types.Message
.withObjectURL(await Signal.Migrations.loadMessage(message));
switch (type) {
case 'documents': {
saveAttachment({ message: loadedMessage });
saveAttachment({ message });
break;
}
case 'media': {
const attachment = loadedMessage.attachments[0];
this.lightboxView = new Whisper.ReactWrapperView({
Component: Signal.Components.Lightbox,
const selectedIndex = media.findIndex(mediaMessage =>
mediaMessage.id === message.id);
const { getAbsoluteAttachmentPath } = Signal.Migrations;
this.lightboxGalleryView = new Whisper.ReactWrapperView({
Component: Signal.Components.LightboxGallery,
props: {
objectURL: loadedMessage.objectURL,
contentType: attachment.contentType,
onSave: () => saveAttachment({ message: loadedMessage }),
getAbsoluteAttachmentPath,
messages: media,
onSave: () => saveAttachment({ message }),
selectedIndex,
},
onClose: () => Signal.Backbone.Views.Lightbox.hide(),
});
Signal.Backbone.Views.Lightbox.show(this.lightboxView.el);
Signal.Backbone.Views.Lightbox.show(this.lightboxGalleryView.el);
break;
}

View file

@ -166,6 +166,7 @@ window.Signal.Logs = require('./js/modules/logs');
// React components
const { Lightbox } = require('./ts/components/Lightbox');
const { LightboxGallery } = require('./ts/components/LightboxGallery');
const { MediaGallery } =
require('./ts/components/conversation/media-gallery/MediaGallery');
const { Quote } = require('./ts/components/conversation/Quote');
@ -175,6 +176,7 @@ const MediaGalleryMessage =
window.Signal.Components = {
Lightbox,
LightboxGallery,
MediaGallery,
Types: {
Message: MediaGalleryMessage,

View file

@ -117,7 +117,7 @@ export class Lightbox extends React.Component<Props, {}> {
}
public render() {
const { contentType, objectURL } = this.props;
const { contentType, objectURL, onNext, onPrevious, onSave } = this.props;
return (
<div
style={styles.container}
@ -132,23 +132,23 @@ export class Lightbox extends React.Component<Props, {}> {
</div>
<div style={styles.controls}>
<IconButton type="close" onClick={this.onClose} />
{this.props.onSave ? (
{onSave ? (
<IconButton
type="save"
onClick={this.props.onSave}
onClick={onSave}
style={styles.saveButton}
/>
) : null}
</div>
</div>
<div style={styles.navigationContainer}>
{this.props.onPrevious ? (
<IconButton type="previous" onClick={this.props.onPrevious} />
{onPrevious ? (
<IconButton type="previous" onClick={onPrevious} />
) : (
<IconButtonPlaceholder />
)}
{this.props.onNext ? (
<IconButton type="next" onClick={this.props.onNext} />
{onNext ? (
<IconButton type="next" onClick={onNext} />
) : (
<IconButtonPlaceholder />
)}

View file

@ -5,18 +5,18 @@ import React from 'react';
import * as MIME from '../types/MIME';
import { Lightbox } from './Lightbox';
import { Message } from './conversation/media-gallery/types/Message';
interface Item {
objectURL: string;
objectURL?: string;
contentType: MIME.MIMEType | undefined;
}
interface Props {
close: () => void;
items: Array<Item>;
// onNext?: () => void;
// onPrevious?: () => void;
onSave?: () => void;
getAbsoluteAttachmentPath: (relativePath: string) => string;
messages: Array<Message>;
onSave?: ({ message }: { message: Message }) => void;
selectedIndex: number;
}
@ -24,6 +24,11 @@ interface State {
selectedIndex: number;
}
const messageToItem = (message: Message): Item => ({
objectURL: message.attachments[0].path,
contentType: message.attachments[0].contentType,
});
export class LightboxGallery extends React.Component<Props, State> {
public static defaultProps: Partial<Props> = {
selectedIndex: 0,
@ -38,25 +43,30 @@ export class LightboxGallery extends React.Component<Props, State> {
}
public render() {
const { close, items, onSave } = this.props;
const { close, getAbsoluteAttachmentPath, messages, onSave } = this.props;
const { selectedIndex } = this.state;
const selectedItem: Item = items[selectedIndex];
const selectedMessage: Message = messages[selectedIndex];
const selectedItem = messageToItem(selectedMessage);
const firstIndex = 0;
const onPrevious =
selectedIndex > firstIndex ? this.handlePrevious : undefined;
const lastIndex = items.length - 1;
const lastIndex = messages.length - 1;
const onNext = selectedIndex < lastIndex ? this.handleNext : undefined;
const objectURL = selectedItem.objectURL
? getAbsoluteAttachmentPath(selectedItem.objectURL)
: 'images/video.svg';
return (
<Lightbox
close={close}
onPrevious={onPrevious}
onNext={onNext}
onSave={onSave}
objectURL={selectedItem.objectURL}
onSave={onSave ? this.handleSave : undefined}
objectURL={objectURL}
contentType={selectedItem.contentType}
/>
);
@ -72,8 +82,19 @@ export class LightboxGallery extends React.Component<Props, State> {
this.setState((prevState, props) => ({
selectedIndex: Math.min(
prevState.selectedIndex + 1,
props.items.length - 1
props.messages.length - 1
),
}));
};
private handleSave = () => {
const { messages, onSave } = this.props;
if (!onSave) {
return;
}
const { selectedIndex } = this.state;
const message = messages[selectedIndex];
onSave({ message });
};
}

View file

@ -47,16 +47,20 @@ export const isVisualMedia = (attachment: Attachment): boolean => {
export const save = ({
attachment,
document,
getAbsolutePath,
timestamp,
}: {
attachment: Attachment;
document: Document;
getAbsolutePath: (relativePath: string) => string;
timestamp?: number;
}): void => {
const url = arrayBufferToObjectURL({
data: attachment.data,
type: SAVE_CONTENT_TYPE,
});
const url = !is.undefined(attachment.path)
? getAbsolutePath(attachment.path)
: arrayBufferToObjectURL({
data: attachment.data,
type: SAVE_CONTENT_TYPE,
});
const filename = getSuggestedFilename({ attachment, timestamp });
saveURLAsFile({ url, filename, document });
URL.revokeObjectURL(url);