diff --git a/app/soapbox/features/account_gallery/components/media_item.js b/app/soapbox/features/account_gallery/components/media_item.js deleted file mode 100644 index fe8c6cc85..000000000 --- a/app/soapbox/features/account_gallery/components/media_item.js +++ /dev/null @@ -1,158 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React from 'react'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { connect } from 'react-redux'; - -import { getSettings } from 'soapbox/actions/settings'; -import Blurhash from 'soapbox/components/blurhash'; -import Icon from 'soapbox/components/icon'; -import StillImage from 'soapbox/components/still_image'; -import { isIOS } from 'soapbox/is_mobile'; - -const mapStateToProps = state => ({ - autoPlayGif: getSettings(state).get('autoPlayGif'), - displayMedia: getSettings(state).get('displayMedia'), -}); - -export default @connect(mapStateToProps) -class MediaItem extends ImmutablePureComponent { - - static propTypes = { - attachment: ImmutablePropTypes.map.isRequired, - displayWidth: PropTypes.number.isRequired, - onOpenMedia: PropTypes.func.isRequired, - autoPlayGif: PropTypes.bool, - displayMedia: PropTypes.string, - }; - - state = { - visible: this.props.displayMedia !== 'hide_all' && !this.props.attachment.getIn(['status', 'sensitive']) || this.props.displayMedia === 'show_all', - loaded: false, - }; - - handleImageLoad = () => { - this.setState({ loaded: true }); - } - - handleMouseEnter = e => { - if (this.hoverToPlay()) { - e.target.play(); - } - } - - handleMouseLeave = e => { - if (this.hoverToPlay()) { - e.target.pause(); - e.target.currentTime = 0; - } - } - - hoverToPlay = () => { - const { autoPlayGif } = this.props; - return !autoPlayGif && ['gifv', 'video'].indexOf(this.props.attachment.get('type')) !== -1; - } - - handleClick = e => { - if (e.button === 0 && !(e.ctrlKey || e.metaKey)) { - e.preventDefault(); - - if (this.state.visible) { - this.props.onOpenMedia(this.props.attachment); - } else { - this.setState({ visible: true }); - } - } - } - - render() { - const { attachment, displayWidth, autoPlayGif } = this.props; - const { visible, loaded } = this.state; - - const width = `${Math.floor((displayWidth - 4) / 3) - 4}px`; - const height = width; - const status = attachment.get('status'); - const title = status.get('spoiler_text') || attachment.get('description'); - - let thumbnail = ''; - let icon; - - if (attachment.get('type') === 'unknown') { - // Skip - } else if (attachment.get('type') === '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 = ( - - ); - } else if (['gifv', 'video'].indexOf(attachment.get('type')) !== -1) { - const conditionalAttributes = {}; - if (isIOS()) { - conditionalAttributes.playsInline = '1'; - } - if (autoPlayGif) { - conditionalAttributes.autoPlay = '1'; - } - thumbnail = ( -
-
- ); - } else if (attachment.get('type') === 'audio') { - const remoteURL = attachment.get('remote_url') || ''; - const fileExtensionLastIndex = remoteURL.lastIndexOf('.'); - const fileExtension = remoteURL.substr(fileExtensionLastIndex + 1).toUpperCase(); - thumbnail = ( -
- - {fileExtension} -
- ); - } - - if (!visible) { - icon = ( - - - - ); - } - - return ( -
- - - {visible && thumbnail} - {!visible && icon} - -
- ); - } - -} diff --git a/app/soapbox/features/account_gallery/components/media_item.tsx b/app/soapbox/features/account_gallery/components/media_item.tsx new file mode 100644 index 000000000..c113ac5e6 --- /dev/null +++ b/app/soapbox/features/account_gallery/components/media_item.tsx @@ -0,0 +1,141 @@ +import classNames from 'classnames'; +import React, { useState } from 'react'; + +import Blurhash from 'soapbox/components/blurhash'; +import Icon from 'soapbox/components/icon'; +import StillImage from 'soapbox/components/still_image'; +import { useSettings } from 'soapbox/hooks'; +import { isIOS } from 'soapbox/is_mobile'; + +import type { Attachment } from 'soapbox/types/entities'; + +interface IMediaItem { + attachment: Attachment, + displayWidth: number, + onOpenMedia: (attachment: Attachment) => void, +} + +const MediaItem: React.FC = ({ attachment, displayWidth, onOpenMedia }) => { + const settings = useSettings(); + const autoPlayGif = settings.get('autoPlayGif'); + const displayMedia = settings.get('displayMedia'); + + const [visible, setVisible] = useState(displayMedia !== 'hide_all' && !attachment.status?.sensitive || displayMedia === 'show_all'); + + const handleMouseEnter: React.MouseEventHandler = e => { + const video = e.target as HTMLVideoElement; + if (hoverToPlay()) { + video.play(); + } + }; + + const handleMouseLeave: React.MouseEventHandler = e => { + const video = e.target as HTMLVideoElement; + if (hoverToPlay()) { + video.pause(); + video.currentTime = 0; + } + }; + + const hoverToPlay = () => { + return !autoPlayGif && ['gifv', 'video'].indexOf(attachment.type) !== -1; + }; + + const handleClick: React.MouseEventHandler = e => { + if (e.button === 0 && !(e.ctrlKey || e.metaKey)) { + e.preventDefault(); + + if (visible) { + onOpenMedia(attachment); + } else { + setVisible(true); + } + } + }; + + const width = `${Math.floor((displayWidth - 4) / 3) - 4}px`; + const height = width; + const status = attachment.get('status'); + const title = status.get('spoiler_text') || attachment.get('description'); + + let thumbnail: React.ReactNode = ''; + let icon; + + if (attachment.type === 'unknown') { + // Skip + } else if (attachment.type === 'image') { + const focusX = Number(attachment.getIn(['meta', 'focus', 'x'])) || 0; + const focusY = Number(attachment.getIn(['meta', 'focus', 'y'])) || 0; + const x = ((focusX / 2) + .5) * 100; + const y = ((focusY / -2) + .5) * 100; + + thumbnail = ( + + ); + } else if (['gifv', 'video'].indexOf(attachment.type) !== -1) { + const conditionalAttributes: React.VideoHTMLAttributes = {}; + if (isIOS()) { + conditionalAttributes.playsInline = true; + } + if (autoPlayGif) { + conditionalAttributes.autoPlay = true; + } + thumbnail = ( +
+
+ ); + } else if (attachment.type === 'audio') { + const remoteURL = attachment.remote_url || ''; + const fileExtensionLastIndex = remoteURL.lastIndexOf('.'); + const fileExtension = remoteURL.substr(fileExtensionLastIndex + 1).toUpperCase(); + thumbnail = ( +
+ + {fileExtension} +
+ ); + } + + if (!visible) { + icon = ( + + + + ); + } + + return ( + + ); +}; + +export default MediaItem;