From ba8379c753380c398e96f8d88281d71b34a15d01 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 31 May 2022 12:31:08 -0500 Subject: [PATCH 1/7] Break out StatusMedia into a separate component --- app/soapbox/components/status-media.tsx | 173 ++++++++++++++++++++++++ app/soapbox/components/status.tsx | 125 ++--------------- 2 files changed, 182 insertions(+), 116 deletions(-) create mode 100644 app/soapbox/components/status-media.tsx diff --git a/app/soapbox/components/status-media.tsx b/app/soapbox/components/status-media.tsx new file mode 100644 index 000000000..391d2c865 --- /dev/null +++ b/app/soapbox/components/status-media.tsx @@ -0,0 +1,173 @@ +import React, { useState } from 'react'; + +import { openModal } from 'soapbox/actions/modals'; +import AttachmentThumbs from 'soapbox/components/attachment-thumbs'; +import PlaceholderCard from 'soapbox/features/placeholder/components/placeholder_card'; +import Card from 'soapbox/features/status/components/card'; +import Bundle from 'soapbox/features/ui/components/bundle'; +import { MediaGallery, Video, Audio } from 'soapbox/features/ui/util/async-components'; +import { useAppDispatch } from 'soapbox/hooks'; + +import type { List as ImmutableList } from 'immutable'; +import type { Status, Attachment } from 'soapbox/types/entities'; + +interface IStatusMedia { + /** Status entity to render media for. */ + status: Status, + /** Whether to display compact media. */ + muted?: boolean, + /** Callback when compact media is clicked. */ + onClick?: () => void, + /** Whether or not the media is concealed behind a NSFW banner. */ + showMedia?: boolean, + /** Callback when visibility is toggled (eg clicked through NSFW). */ + onToggleVisibility: () => void, +} + +/** Render media attachments for a status. */ +const StatusMedia: React.FC = ({ + status, + muted = false, + onClick, + showMedia = true, + onToggleVisibility, +}) => { + const dispatch = useAppDispatch(); + const [mediaWrapperWidth, setMediaWrapperWidth] = useState(undefined); + + const size = status.media_attachments.size; + const firstAttachment = status.media_attachments.first(); + + let media = null; + + const setRef = (c: HTMLDivElement): void => { + if (c) { + setMediaWrapperWidth(c.offsetWidth); + } + }; + + const renderLoadingMediaGallery = (): JSX.Element => { + return
; + }; + + const renderLoadingVideoPlayer = (): JSX.Element => { + return
; + }; + + const renderLoadingAudioPlayer = (): JSX.Element => { + return
; + }; + + const openMedia = (media: ImmutableList, index: number) => { + dispatch(openModal('MEDIA', { media, index })); + }; + + const openVideo = (media: Attachment, time: number): void => { + dispatch(openModal('VIDEO', { media, time })); + }; + + if (size > 0 && firstAttachment) { + if (muted) { + media = ( + + ); + } else if (size === 1 && firstAttachment.type === 'video') { + const video = firstAttachment; + + if (video.external_video_id && status.card) { + const getHeight = (): number => { + const width = Number(video.meta.getIn(['original', 'width'])); + const height = Number(video.meta.getIn(['original', 'height'])); + return Number(mediaWrapperWidth) / (width / height); + }; + + const height = getHeight(); + + media = ( +
+
+
+ ); + } else { + media = ( + + {(Component: any) => ( + + )} + + ); + } + } else if (size === 1 && firstAttachment.type === 'audio') { + const attachment = firstAttachment; + + media = ( + + {(Component: any) => ( + + )} + + ); + } else { + media = ( + + {(Component: any) => ( + + )} + + ); + } + } else if (status.spoiler_text.length === 0 && !status.quote && status.card) { + media = ( + + ); + } else if (status.expectsCard) { + media = ( + + ); + } + + return media; +}; + +export default StatusMedia; diff --git a/app/soapbox/components/status.tsx b/app/soapbox/components/status.tsx index 3cea7c280..5a42fdea5 100644 --- a/app/soapbox/components/status.tsx +++ b/app/soapbox/components/status.tsx @@ -14,6 +14,7 @@ import Bundle from 'soapbox/features/ui/components/bundle'; import { MediaGallery, Video, Audio } from 'soapbox/features/ui/util/async-components'; import AttachmentThumbs from './attachment-thumbs'; +import StatusMedia from './status-media'; import StatusReplyMentions from './status-reply-mentions'; import StatusActionBar from './status_action_bar'; import StatusContent from './status_content'; @@ -342,7 +343,6 @@ class Status extends ImmutablePureComponent { } render() { - let media = null; const poll = null; let prepend, rebloggedByText, reblogElement, reblogElementMobile; @@ -450,120 +450,6 @@ class Status extends ImmutablePureComponent { status = status.reblog; } - const size = status.media_attachments.size; - const firstAttachment = status.media_attachments.first(); - - if (size > 0 && firstAttachment) { - if (this.props.muted) { - media = ( - - ); - } else if (size === 1 && firstAttachment.type === 'video') { - const video = firstAttachment; - - if (video.external_video_id && status.card) { - const { mediaWrapperWidth } = this.state; - - const getHeight = (): number => { - const width = Number(video.meta.getIn(['original', 'width'])); - const height = Number(video.meta.getIn(['original', 'height'])); - return Number(mediaWrapperWidth) / (width / height); - }; - - const height = getHeight(); - - media = ( -
-
-
- ); - } else { - media = ( - - {(Component: any) => ( - - )} - - ); - } - } else if (size === 1 && firstAttachment.type === 'audio') { - const attachment = firstAttachment; - - media = ( - - {(Component: any) => ( - - )} - - ); - } else { - media = ( - - {(Component: any) => ( - - )} - - ); - } - } else if (status.spoiler_text.length === 0 && !status.quote && status.card) { - media = ( - - ); - } else if (status.expectsCard) { - media = ( - - ); - } - let quote; if (status.quote) { @@ -653,7 +539,14 @@ class Status extends ImmutablePureComponent { collapsable /> - {media} + + {poll} {quote} From 62d432a65da6dc6a4327e9cd4f7d3abb465938c7 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 31 May 2022 12:32:59 -0500 Subject: [PATCH 2/7] Status: clean up now unused media methods, etc --- app/soapbox/components/status.tsx | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/app/soapbox/components/status.tsx b/app/soapbox/components/status.tsx index 5a42fdea5..4d9b4eb59 100644 --- a/app/soapbox/components/status.tsx +++ b/app/soapbox/components/status.tsx @@ -110,7 +110,6 @@ interface IStatusState { showMedia: boolean, statusId?: string, emojiSelectorFocused: boolean, - mediaWrapperWidth?: number, } class Status extends ImmutablePureComponent { @@ -223,26 +222,6 @@ class Status extends ImmutablePureComponent { this.props.onToggleHidden(this._properStatus()); }; - renderLoadingMediaGallery(): JSX.Element { - return
; - } - - renderLoadingVideoPlayer(): JSX.Element { - return
; - } - - renderLoadingAudioPlayer(): JSX.Element { - return
; - } - - handleOpenVideo = (media: ImmutableMap, startTime: number): void => { - this.props.onOpenVideo(media, startTime); - } - - handleOpenAudio = (media: ImmutableMap, startTime: number): void => { - this.props.onOpenAudio(media, startTime); - } - handleHotkeyOpenMedia = (e?: KeyboardEvent): void => { const { onOpenMedia, onOpenVideo } = this.props; const status = this._properStatus(); @@ -336,12 +315,6 @@ class Status extends ImmutablePureComponent { this.node = c; } - setRef = (c: HTMLDivElement): void => { - if (c) { - this.setState({ mediaWrapperWidth: c.offsetWidth }); - } - } - render() { const poll = null; let prepend, rebloggedByText, reblogElement, reblogElementMobile; From d6a7e38e565b2b8146637d68b17221e2ae893cec Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 31 May 2022 12:49:24 -0500 Subject: [PATCH 3/7] DetailedStatus: use StatusMedia component --- .../status/components/detailed-status.tsx | 93 ++----------------- 1 file changed, 8 insertions(+), 85 deletions(-) diff --git a/app/soapbox/features/status/components/detailed-status.tsx b/app/soapbox/features/status/components/detailed-status.tsx index 093e0a896..f0b34ea4a 100644 --- a/app/soapbox/features/status/components/detailed-status.tsx +++ b/app/soapbox/features/status/components/detailed-status.tsx @@ -5,18 +5,14 @@ import { FormattedMessage, injectIntl, WrappedComponentProps as IntlProps } from import { FormattedDate } from 'react-intl'; import Icon from 'soapbox/components/icon'; -import MediaGallery from 'soapbox/components/media_gallery'; +import StatusMedia from 'soapbox/components/status-media'; import StatusReplyMentions from 'soapbox/components/status-reply-mentions'; import StatusContent from 'soapbox/components/status_content'; import { HStack, Text } from 'soapbox/components/ui'; import AccountContainer from 'soapbox/containers/account_container'; import QuotedStatus from 'soapbox/features/status/containers/quoted_status_container'; +import scheduleIdleTask from 'soapbox/features/ui/util/schedule_idle_task'; -import Audio from '../../audio'; -import scheduleIdleTask from '../../ui/util/schedule_idle_task'; -import Video from '../../video'; - -import Card from './card'; import StatusInteractionBar from './status-interaction-bar'; import type { List as ImmutableList } from 'immutable'; @@ -114,90 +110,12 @@ class DetailedStatus extends ImmutablePureComponent 0 && firstAttachment) { - if (size === 1 && firstAttachment.type === 'video') { - const video = firstAttachment; - if (video.external_video_id && status.card?.html) { - const { mediaWrapperWidth } = this.state; - - const getHeight = (): number => { - const width = Number(video.meta.getIn(['original', 'width'])); - const height = Number(video.meta.getIn(['original', 'height'])); - return Number(mediaWrapperWidth) / (width / height); - }; - - const height = getHeight(); - - media = ( -
-
-
- ); - } else { - media = ( -