Implement video support in lightbox
This commit is contained in:
parent
ac04f0648a
commit
45d6c7a5a8
5 changed files with 61 additions and 24 deletions
|
@ -109,7 +109,8 @@
|
|||
}
|
||||
|
||||
const props = {
|
||||
imageURL: this.objectUrl,
|
||||
objectURL: this.objectUrl,
|
||||
contentType: this.model.contentType,
|
||||
onSave: () => this.saveFile(),
|
||||
// implicit: `close`
|
||||
};
|
||||
|
|
|
@ -600,25 +600,28 @@
|
|||
const media = await loadMessages(rawMedia);
|
||||
|
||||
const saveAttachment = async ({ message } = {}) => {
|
||||
const loadedMessage = await Signal.Migrations.loadMessage(message);
|
||||
const attachment = loadedMessage.attachments[0];
|
||||
const timestamp = loadedMessage.received_at;
|
||||
const attachment = message.attachments[0];
|
||||
const timestamp = message.received_at;
|
||||
Signal.Types.AttachmentTS.save({ attachment, timestamp });
|
||||
};
|
||||
|
||||
const onItemClick = async ({ message, type }) => {
|
||||
const loadedMessage = Signal.Components.Types.Message
|
||||
.withObjectURL(await Signal.Migrations.loadMessage(message));
|
||||
switch (type) {
|
||||
case 'documents': {
|
||||
saveAttachment({ message });
|
||||
saveAttachment({ message: loadedMessage });
|
||||
break;
|
||||
}
|
||||
|
||||
case 'media': {
|
||||
const attachment = loadedMessage.attachments[0];
|
||||
this.lightboxView = new Whisper.ReactWrapperView({
|
||||
Component: Signal.Components.Lightbox,
|
||||
props: {
|
||||
imageURL: message.objectURL,
|
||||
onSave: () => saveAttachment({ message }),
|
||||
objectURL: loadedMessage.objectURL,
|
||||
contentType: attachment.contentType,
|
||||
onSave: () => saveAttachment({ message: loadedMessage }),
|
||||
},
|
||||
onClose: () => Signal.Backbone.Views.Lightbox.hide(),
|
||||
});
|
||||
|
|
|
@ -3,7 +3,8 @@ const noop = () => {};
|
|||
|
||||
<div style={{position: 'relative', width: '100%', height: 500}}>
|
||||
<Lightbox
|
||||
imageURL="https://placekitten.com/800/600"
|
||||
objectURL="https://placekitten.com/800/600"
|
||||
contentType="image/jpeg"
|
||||
onNext={noop}
|
||||
onPrevious={noop}
|
||||
onSave={noop}
|
||||
|
|
|
@ -4,13 +4,18 @@
|
|||
import React from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import is from '@sindresorhus/is';
|
||||
|
||||
import * as GoogleChrome from '../util/GoogleChrome';
|
||||
import * as MIME from '../types/MIME';
|
||||
|
||||
interface Props {
|
||||
close: () => void;
|
||||
imageURL?: string;
|
||||
objectURL: string;
|
||||
contentType: MIME.MIMEType | undefined;
|
||||
onNext?: () => void;
|
||||
onPrevious?: () => void;
|
||||
onSave: () => void;
|
||||
onSave?: () => void;
|
||||
}
|
||||
|
||||
const styles = {
|
||||
|
@ -67,7 +72,7 @@ export class Lightbox extends React.Component<Props, {}> {
|
|||
}
|
||||
|
||||
public render() {
|
||||
const { imageURL } = this.props;
|
||||
const { contentType, objectURL } = this.props;
|
||||
return (
|
||||
<div
|
||||
style={styles.container}
|
||||
|
@ -75,11 +80,9 @@ export class Lightbox extends React.Component<Props, {}> {
|
|||
ref={this.setContainerRef}
|
||||
>
|
||||
<div style={styles.objectContainer}>
|
||||
<img
|
||||
style={styles.image}
|
||||
src={imageURL}
|
||||
onClick={this.onImageClick}
|
||||
/>
|
||||
{!is.undefined(contentType)
|
||||
? this.renderObject({ objectURL, contentType })
|
||||
: null}
|
||||
</div>
|
||||
<div style={styles.controls}>
|
||||
<IconButton type="close" onClick={this.onClose} />
|
||||
|
@ -97,6 +100,38 @@ export class Lightbox extends React.Component<Props, {}> {
|
|||
);
|
||||
}
|
||||
|
||||
private renderObject = ({
|
||||
objectURL,
|
||||
contentType,
|
||||
}: {
|
||||
objectURL: string;
|
||||
contentType: MIME.MIMEType;
|
||||
}) => {
|
||||
const isImage = GoogleChrome.isImageTypeSupported(contentType);
|
||||
if (isImage) {
|
||||
return (
|
||||
<img
|
||||
style={styles.image}
|
||||
src={objectURL}
|
||||
onClick={this.onObjectClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const isVideo = GoogleChrome.isVideoTypeSupported(contentType);
|
||||
if (isVideo) {
|
||||
return (
|
||||
<video controls>
|
||||
<source src={objectURL} />
|
||||
</video>
|
||||
);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-console
|
||||
console.log('Lightbox: Unexpected content type', { contentType });
|
||||
return null;
|
||||
};
|
||||
|
||||
private setContainerRef = (value: HTMLDivElement) => {
|
||||
this.containerRef = value;
|
||||
};
|
||||
|
@ -125,7 +160,7 @@ export class Lightbox extends React.Component<Props, {}> {
|
|||
this.onClose();
|
||||
};
|
||||
|
||||
private onImageClick = (event: React.MouseEvent<HTMLImageElement>) => {
|
||||
private onObjectClick = (event: React.MouseEvent<HTMLImageElement>) => {
|
||||
event.stopPropagation();
|
||||
this.onClose();
|
||||
};
|
||||
|
|
|
@ -8,7 +8,6 @@ import * as MIME from '../../../../types/MIME';
|
|||
import { arrayBufferToObjectURL } from '../../../../util/arrayBufferToObjectURL';
|
||||
import { Attachment } from '../../../../types/Attachment';
|
||||
import { MapAsync } from '../../../../types/MapAsync';
|
||||
import { MIMEType } from '../../../../types/MIME';
|
||||
|
||||
export type Message = {
|
||||
id: string;
|
||||
|
@ -16,8 +15,6 @@ export type Message = {
|
|||
received_at: number;
|
||||
} & { objectURL?: string };
|
||||
|
||||
const DEFAULT_CONTENT_TYPE: MIMEType = 'application/octet-stream' as MIMEType;
|
||||
|
||||
export const loadWithObjectURL = (loadMessage: MapAsync<Message>) => async (
|
||||
messages: Array<Message>
|
||||
): Promise<Array<Message>> => {
|
||||
|
@ -51,17 +48,17 @@ const hasVideoAttachment = (message: Message): boolean =>
|
|||
MIME.isVideo(attachment.contentType)
|
||||
);
|
||||
|
||||
const withObjectURL = (message: Message): Message => {
|
||||
export const withObjectURL = (message: Message): Message => {
|
||||
if (message.attachments.length === 0) {
|
||||
throw new TypeError('`message.attachments` cannot be empty');
|
||||
}
|
||||
|
||||
const attachment = message.attachments[0];
|
||||
if (typeof attachment.contentType === 'undefined') {
|
||||
if (is.undefined(attachment.contentType)) {
|
||||
throw new TypeError('`attachment.contentType` is required');
|
||||
}
|
||||
|
||||
if (MIME.isVideo(attachment.contentType)) {
|
||||
if (is.undefined(attachment.data) && MIME.isVideo(attachment.contentType)) {
|
||||
return {
|
||||
...message,
|
||||
objectURL: 'images/video.svg',
|
||||
|
@ -70,7 +67,7 @@ const withObjectURL = (message: Message): Message => {
|
|||
|
||||
const objectURL = arrayBufferToObjectURL({
|
||||
data: attachment.data,
|
||||
type: attachment.contentType || DEFAULT_CONTENT_TYPE,
|
||||
type: attachment.contentType,
|
||||
});
|
||||
return {
|
||||
...message,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue