gab-social/app/javascript/gabsocial/components/media_item.js
mgabdev 6fbea0a59e Progress on little important things
removing .mov for now until we can figure out solution with videojs, added model to track username changes, got chat creation flow down, progress on bookmark collections, albums, filtering blocks/mutes from group, explore, collection timelines
2020-12-22 01:36:38 -05:00

237 lines
6.8 KiB
JavaScript

import React from 'react'
import PropTypes from 'prop-types'
import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component'
import { NavLink } from 'react-router-dom'
import { decode } from 'blurhash'
import { autoPlayGif, displayMedia } from '../initial_state'
import { CX } from '../constants'
import Icon from './icon'
import Image from './image'
import Text from './text'
class MediaItem extends ImmutablePureComponent {
state = {
loaded: false,
visible: true,
}
componentDidMount() {
const { attachment } = this.props
if (!attachment) return
if (attachment.get('blurhash')) {
this._decode()
}
this.setState({
visible: displayMedia !== 'hide_all' && !this.props.attachment.getIn(['status', 'sensitive']) || displayMedia === 'show_all',
})
}
componentDidUpdate(prevProps) {
const { attachment } = this.props
const { prevAttachment } = prevProps
if (prevAttachment !== attachment) {
this._decode()
return
}
if (prevAttachment.get('blurhash') !== attachment.get('blurhash') && attachment.get('blurhash')) {
this._decode()
}
}
_decode = () => {
const { attachment } = this.props
if (!attachment) return
const hash = attachment.get('blurhash')
if (!hash) return
const pixels = decode(hash, 160, 160)
if (pixels && this.canvas) {
const ctx = this.canvas.getContext('2d')
const imageData = new ImageData(pixels, 160, 160)
ctx.putImageData(imageData, 0, 0)
}
}
setCanvasRef = (c) => {
this.canvas = c
}
handleImageLoad = () => {
this.setState({ loaded: true })
}
hoverToPlay() {
const { attachment } = this.props
if (!attachment) return
return !autoPlayGif && ['gifv', 'video'].indexOf(attachment.get('type')) !== -1
}
render() {
const {
account,
attachment,
isSmall,
} = this.props
const { visible, loaded } = this.state
if (!attachment || !account) return null
const status = attachment.get('status')
const title = status.get('spoiler_text') || attachment.get('description')
const attachmentType = attachment.get('type')
const aspectRatio = attachment.getIn(['meta', 'aspect'])
const isVideo = attachmentType === 'video'
let badge = null
if (isVideo) {
const duration = attachment.getIn(['meta', 'duration'])
badge = (duration / 60).toFixed(2)
} else if (attachmentType === 'gifv') {
badge = 'GIF'
}
const statusUrl = `/${account.getIn(['acct'])}/posts/${status.get('id')}`
const isSmallRatio = aspectRatio < 1
const isSquare = aspectRatio === 1 || isSmall
const containerClasses = CX({
d: 1,
px5: 1,
flex1: !isSmallRatio && !isSquare,
minW198PX: !isVideo && !isSmallRatio && !isSquare,
minW232PX: isVideo && !isSmallRatio && !isSquare,
minW120PX: isSmallRatio,
minW162PX: isSquare,
})
const paddedContainerClasses = CX({
d: 1,
h100PC: isSmallRatio || isSquare,
pt100PC: isSmallRatio || isSquare || !isVideo,
pt5625PC: isVideo && !isSmallRatio && !isSquare,
})
return (
<div className={containerClasses}>
<NavLink
className={[_s.d, _s.noUnderline, _s.outlineNone, _s.bgTransparent, _s.flexGrow1].join(' ')}
to={statusUrl}
title={title}
>
<div className={[_s.d, _s.mt5, _s.mb10, _s.flexGrow1].join(' ')}>
<div className={paddedContainerClasses}>
<div className={[_s.d, _s.posAbs, _s.top0, _s.right0, _s.left0, _s.bottom0].join(' ')}>
<div className={[_s.d, _s.h100PC, _s.aiCenter, _s.jcCenter, _s.radiusSmall, _s.overflowHidden].join(' ')}>
{
(!loaded || !visible) &&
<canvas
height='100%'
width='100%'
ref={this.setCanvasRef}
className={[_s.d, _s.w100PC, _s.h100PC, _s.z2].join(' ')}
/>
}
{
visible &&
<Image
height='100%'
width=''
src={attachment.get('preview_url')}
alt={attachment.get('description')}
title={attachment.get('description')}
onLoad={this.handleImageLoad}
className={_s.z1}
/>
}
{
(!visible || !!badge) &&
<div className={[_s.d, _s.aiCenter, _s.jcCenter, _s.h100PC, _s.w100PC, _s.z3, _s.posAbs].join(' ')}>
{
!visible &&
<Icon
id='hidden'
size='22px'
className={[_s.cWhite].join('')}
/>
}
{
!!badge &&
<div className={[_s.d, _s.posAbs, _s.radiusSmall, _s.bgBlackOpaque, _s.px5, _s.py5, _s.mr5, _s.mt5, _s.mb5, _s.bottom0, _s.right0].join(' ')}>
<Text size='extraSmall' color='white'>
{badge}
</Text>
</div>
}
</div>
}
</div>
</div>
</div>
</div>
</NavLink>
</div>
)
// return (
// <div className={[_s.d, _s.pt25PC].join(' ')}>
// <div className={containerClasses}>
// <NavLink
// to={statusUrl}
// title={title}
// className={linkClasses}
// >
// {
// (!loaded || !visible) &&
// <canvas
// height='100%'
// width='100%'
// ref={this.setCanvasRef}
// className={[_s.d, _s.w100PC, _s.h100PC, _s.z2].join(' ')}
// />
// }
// {
// visible &&
// <Image
// height='100%'
// width=''
// src={attachment.get('preview_url')}
// alt={attachment.get('description')}
// title={attachment.get('description')}
// onLoad={this.handleImageLoad}
// className={_s.z1}
// />
// }
// </NavLink>
// </div>
// </div>
// )
}
}
MediaItem.propTypes = {
isDummy: PropTypes.bool.isRequired,
account: ImmutablePropTypes.map.isRequired,
attachment: ImmutablePropTypes.map.isRequired,
isSmall: PropTypes.bool,
}
export default MediaItem