166 lines
4.7 KiB
JavaScript
166 lines
4.7 KiB
JavaScript
import React, { Fragment } from 'react';
|
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
import PropTypes from 'prop-types';
|
|
import { is } from 'immutable';
|
|
import classNames from 'classnames';
|
|
import { displayMedia, useBlurhash } from '../initial_state';
|
|
import Blurhash from 'mastodon/components/blurhash';
|
|
import { FormattedMessage } from 'react-intl';
|
|
|
|
class Item extends React.PureComponent {
|
|
|
|
static propTypes = {
|
|
attachment: ImmutablePropTypes.map.isRequired,
|
|
visible: PropTypes.bool.isRequired,
|
|
autoplay: PropTypes.bool,
|
|
};
|
|
|
|
state = {
|
|
loaded: false,
|
|
};
|
|
|
|
handleImageLoad = () => {
|
|
this.setState({ loaded: true });
|
|
}
|
|
|
|
render () {
|
|
const { attachment, visible } = this.props;
|
|
|
|
let thumbnail = '';
|
|
let typeLabel = '';
|
|
|
|
const id = attachment.get('id');
|
|
const type = attachment.get('type');
|
|
const hash = attachment.get('blurhash');
|
|
const preview = attachment.get('preview_url');
|
|
const description = attachment.get('description');
|
|
|
|
switch(type) {
|
|
case 'image':
|
|
const focusX = attachment.getIn(['meta', 'focus', 'x']) || 0;
|
|
const focusY = attachment.getIn(['meta', 'focus', 'y']) || 0;
|
|
const x = ((focusX / 2) + .5) * 100;
|
|
const y = ((focusY / -2) + .5) * 100;
|
|
|
|
thumbnail = (
|
|
<img
|
|
className='thumbnail-gallery__item-thumbnail'
|
|
src={preview}
|
|
alt={description}
|
|
title={description}
|
|
style={{ objectPosition: `${x}% ${y}%` }}
|
|
onLoad={this.handleImageLoad}
|
|
/>
|
|
);
|
|
break;
|
|
|
|
case 'gifv':
|
|
thumbnail = (
|
|
<div className='thumbnail-gallery__gifv'>
|
|
<video
|
|
className='thumbnail-gallery__item-gifv-thumbnail'
|
|
aria-label={description}
|
|
title={description}
|
|
role='application'
|
|
src={attachment.get('url')}
|
|
autoPlay={false}
|
|
muted
|
|
/>
|
|
</div>
|
|
);
|
|
typeLabel = <FormattedMessage id='thumbnail.type.gif' defaultMessage='(GIF)' />;
|
|
break;
|
|
|
|
case 'audio':
|
|
thumbnail = preview ? (
|
|
<img
|
|
className='thumbnail-gallery__item-thumbnail'
|
|
src={preview}
|
|
alt={description}
|
|
title={description}
|
|
onLoad={this.handleImageLoad}
|
|
/>
|
|
) : null;
|
|
typeLabel = <FormattedMessage id='thumbnail.type.audio' defaultMessage='(Audio)' />;
|
|
break;
|
|
|
|
case 'video':
|
|
thumbnail = (
|
|
<img
|
|
className='thumbnail-gallery__item-thumbnail'
|
|
src={preview}
|
|
alt={description}
|
|
title={description}
|
|
onLoad={this.handleImageLoad}
|
|
/>
|
|
);
|
|
typeLabel = <FormattedMessage id='thumbnail.type.video' defaultMessage='(Video)' />;
|
|
break;
|
|
|
|
default:
|
|
return hash ? (
|
|
<div className='thumbnail-gallery__item' key={id}>
|
|
<Blurhash
|
|
hash={hash}
|
|
className='thumbnail-gallery__preview'
|
|
dummy={!useBlurhash}
|
|
/>
|
|
</div>
|
|
) : null;
|
|
}
|
|
|
|
return (
|
|
<Fragment>
|
|
<div className='thumbnail-gallery__item' key={id}>
|
|
{hash && <Blurhash
|
|
hash={hash}
|
|
dummy={!useBlurhash}
|
|
className={classNames('thumbnail-gallery__preview', {
|
|
'thumbnail-gallery__preview--hidden': visible && this.state.loaded,
|
|
})}
|
|
/>}
|
|
{visible && thumbnail}
|
|
</div>
|
|
{typeLabel && <div className='thumbnail-gallery__type' key='type'>{typeLabel}</div>}
|
|
</Fragment>
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
export default
|
|
class ThumbnailGallery extends React.PureComponent {
|
|
|
|
static propTypes = {
|
|
sensitive: PropTypes.bool,
|
|
media: ImmutablePropTypes.list.isRequired,
|
|
visible: PropTypes.bool,
|
|
};
|
|
|
|
state = {
|
|
visible: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),
|
|
};
|
|
|
|
componentWillReceiveProps (nextProps) {
|
|
if (!is(nextProps.media, this.props.media) && nextProps.visible === undefined) {
|
|
this.setState({ visible: displayMedia !== 'hide_all' && !nextProps.sensitive || displayMedia === 'show_all' });
|
|
} else if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {
|
|
this.setState({ visible: nextProps.visible });
|
|
}
|
|
}
|
|
|
|
render () {
|
|
const { media } = this.props;
|
|
const { visible } = this.state;
|
|
|
|
const uncached = media.every(attachment => attachment.get('type') === 'unknown');
|
|
const children = media.take(4).map((attachment) => <Item key={attachment.get('id')} attachment={attachment} visible={visible || uncached} />);
|
|
|
|
return (
|
|
<div className='thumbnail-gallery' ref={this.handleRef}>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
}
|