import { useState, useCallback } from 'react'; import classNames from 'classnames'; import HeadphonesIcon from '@/material-icons/400-24px/headphones-fill.svg?react'; import MovieIcon from '@/material-icons/400-24px/movie-fill.svg?react'; import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react'; import { AltTextBadge } from 'mastodon/components/alt_text_badge'; import { Blurhash } from 'mastodon/components/blurhash'; import { Icon } from 'mastodon/components/icon'; import { formatTime } from 'mastodon/features/video'; import { autoPlayGif, displayMedia, useBlurhash } from 'mastodon/initial_state'; import type { Status, MediaAttachment } from 'mastodon/models/status'; export const MediaItem: React.FC<{ attachment: MediaAttachment; onOpenMedia: (arg0: MediaAttachment) => void; }> = ({ attachment, onOpenMedia }) => { const [visible, setVisible] = useState( (displayMedia !== 'hide_all' && !attachment.getIn(['status', 'sensitive'])) || displayMedia === 'show_all', ); const [loaded, setLoaded] = useState(false); const handleImageLoad = useCallback(() => { setLoaded(true); }, [setLoaded]); const handleMouseEnter = useCallback( (e: React.MouseEvent) => { if (e.target instanceof HTMLVideoElement) { void e.target.play(); } }, [], ); const handleMouseLeave = useCallback( (e: React.MouseEvent) => { if (e.target instanceof HTMLVideoElement) { e.target.pause(); e.target.currentTime = 0; } }, [], ); const handleClick = useCallback( (e: React.MouseEvent) => { if (e.button === 0 && !(e.ctrlKey || e.metaKey)) { e.preventDefault(); if (visible) { onOpenMedia(attachment); } else { setVisible(true); } } }, [attachment, visible, onOpenMedia, setVisible], ); const status = attachment.get('status') as Status; const description = (attachment.getIn(['translation', 'description']) || attachment.get('description')) as string | undefined; const previewUrl = attachment.get('preview_url') as string; const fullUrl = attachment.get('url') as string; const avatarUrl = status.getIn(['account', 'avatar_static']) as string; const lang = status.get('language') as string; const blurhash = attachment.get('blurhash') as string; const statusId = status.get('id') as string; const acct = status.getIn(['account', 'acct']) as string; const type = attachment.get('type') as string; let thumbnail; const badges = []; if (description && description.length > 0) { badges.push(); } if (!visible) { thumbnail = (
); } else if (type === 'audio') { thumbnail = ( <> {description}
); } else if (type === 'image') { const focusX = (attachment.getIn(['meta', 'focus', 'x']) || 0) as number; const focusY = (attachment.getIn(['meta', 'focus', 'y']) || 0) as number; const x = (focusX / 2 + 0.5) * 100; const y = (focusY / -2 + 0.5) * 100; thumbnail = ( {description} ); } else if (['video', 'gifv'].includes(type)) { const duration = attachment.getIn([ 'meta', 'original', 'duration', ]) as number; thumbnail = (
); if (type === 'gifv') { badges.push( GIF , ); } else { badges.push( {formatTime(Math.floor(duration))} , ); } } return (
{thumbnail} {badges.length > 0 && (
{badges}
)}
); };