Merge branch 'status-media' into 'develop'
Status media refactor (display media in QuotedStatus) See merge request soapbox-pub/soapbox-fe!1478
This commit is contained in:
commit
56cbde77f4
4 changed files with 192 additions and 250 deletions
173
app/soapbox/components/status-media.tsx
Normal file
173
app/soapbox/components/status-media.tsx
Normal file
|
@ -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<IStatusMedia> = ({
|
||||||
|
status,
|
||||||
|
muted = false,
|
||||||
|
onClick,
|
||||||
|
showMedia = true,
|
||||||
|
onToggleVisibility = () => {},
|
||||||
|
}) => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const [mediaWrapperWidth, setMediaWrapperWidth] = useState<number | undefined>(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 <div className='media_gallery' style={{ height: '285px' }} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderLoadingVideoPlayer = (): JSX.Element => {
|
||||||
|
return <div className='media-spoiler-video' style={{ height: '285px' }} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderLoadingAudioPlayer = (): JSX.Element => {
|
||||||
|
return <div className='media-spoiler-audio' style={{ height: '285px' }} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const openMedia = (media: ImmutableList<Attachment>, 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 = (
|
||||||
|
<AttachmentThumbs
|
||||||
|
media={status.media_attachments}
|
||||||
|
onClick={onClick}
|
||||||
|
sensitive={status.sensitive}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} 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 = (
|
||||||
|
<div className='status-card horizontal compact interactive status-card--video'>
|
||||||
|
<div
|
||||||
|
ref={setRef}
|
||||||
|
className='status-card__image status-card-video'
|
||||||
|
style={height ? { height } : undefined}
|
||||||
|
dangerouslySetInnerHTML={{ __html: status.card.html }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
media = (
|
||||||
|
<Bundle fetchComponent={Video} loading={renderLoadingVideoPlayer} >
|
||||||
|
{(Component: any) => (
|
||||||
|
<Component
|
||||||
|
preview={video.preview_url}
|
||||||
|
blurhash={video.blurhash}
|
||||||
|
src={video.url}
|
||||||
|
alt={video.description}
|
||||||
|
aspectRatio={video.meta.getIn(['original', 'aspect'])}
|
||||||
|
height={285}
|
||||||
|
inline
|
||||||
|
sensitive={status.sensitive}
|
||||||
|
onOpenVideo={openVideo}
|
||||||
|
visible={showMedia}
|
||||||
|
onToggleVisibility={onToggleVisibility}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Bundle>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (size === 1 && firstAttachment.type === 'audio') {
|
||||||
|
const attachment = firstAttachment;
|
||||||
|
|
||||||
|
media = (
|
||||||
|
<Bundle fetchComponent={Audio} loading={renderLoadingAudioPlayer} >
|
||||||
|
{(Component: any) => (
|
||||||
|
<Component
|
||||||
|
src={attachment.url}
|
||||||
|
alt={attachment.description}
|
||||||
|
poster={attachment.preview_url !== attachment.url ? attachment.preview_url : status.getIn(['account', 'avatar_static'])}
|
||||||
|
backgroundColor={attachment.meta.getIn(['colors', 'background'])}
|
||||||
|
foregroundColor={attachment.meta.getIn(['colors', 'foreground'])}
|
||||||
|
accentColor={attachment.meta.getIn(['colors', 'accent'])}
|
||||||
|
duration={attachment.meta.getIn(['original', 'duration'], 0)}
|
||||||
|
height={263}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Bundle>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
media = (
|
||||||
|
<Bundle fetchComponent={MediaGallery} loading={renderLoadingMediaGallery}>
|
||||||
|
{(Component: any) => (
|
||||||
|
<Component
|
||||||
|
media={status.media_attachments}
|
||||||
|
sensitive={status.sensitive}
|
||||||
|
height={285}
|
||||||
|
onOpenMedia={openMedia}
|
||||||
|
visible={showMedia}
|
||||||
|
onToggleVisibility={onToggleVisibility}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Bundle>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (status.spoiler_text.length === 0 && !status.quote && status.card) {
|
||||||
|
media = (
|
||||||
|
<Card
|
||||||
|
onOpenMedia={openMedia}
|
||||||
|
card={status.card}
|
||||||
|
compact
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (status.expectsCard) {
|
||||||
|
media = (
|
||||||
|
<PlaceholderCard />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return media;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StatusMedia;
|
|
@ -7,13 +7,9 @@ import { NavLink, withRouter, RouteComponentProps } from 'react-router-dom';
|
||||||
|
|
||||||
import Icon from 'soapbox/components/icon';
|
import Icon from 'soapbox/components/icon';
|
||||||
import AccountContainer from 'soapbox/containers/account_container';
|
import AccountContainer from 'soapbox/containers/account_container';
|
||||||
import PlaceholderCard from 'soapbox/features/placeholder/components/placeholder_card';
|
|
||||||
import Card from 'soapbox/features/status/components/card';
|
|
||||||
import QuotedStatus from 'soapbox/features/status/containers/quoted_status_container';
|
import QuotedStatus from 'soapbox/features/status/containers/quoted_status_container';
|
||||||
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 StatusReplyMentions from './status-reply-mentions';
|
||||||
import StatusActionBar from './status_action_bar';
|
import StatusActionBar from './status_action_bar';
|
||||||
import StatusContent from './status_content';
|
import StatusContent from './status_content';
|
||||||
|
@ -109,7 +105,6 @@ interface IStatusState {
|
||||||
showMedia: boolean,
|
showMedia: boolean,
|
||||||
statusId?: string,
|
statusId?: string,
|
||||||
emojiSelectorFocused: boolean,
|
emojiSelectorFocused: boolean,
|
||||||
mediaWrapperWidth?: number,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Status extends ImmutablePureComponent<IStatus, IStatusState> {
|
class Status extends ImmutablePureComponent<IStatus, IStatusState> {
|
||||||
|
@ -222,26 +217,6 @@ class Status extends ImmutablePureComponent<IStatus, IStatusState> {
|
||||||
this.props.onToggleHidden(this._properStatus());
|
this.props.onToggleHidden(this._properStatus());
|
||||||
};
|
};
|
||||||
|
|
||||||
renderLoadingMediaGallery(): JSX.Element {
|
|
||||||
return <div className='media_gallery' style={{ height: '285px' }} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderLoadingVideoPlayer(): JSX.Element {
|
|
||||||
return <div className='media-spoiler-video' style={{ height: '285px' }} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderLoadingAudioPlayer(): JSX.Element {
|
|
||||||
return <div className='media-spoiler-audio' style={{ height: '285px' }} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleOpenVideo = (media: ImmutableMap<string, any>, startTime: number): void => {
|
|
||||||
this.props.onOpenVideo(media, startTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleOpenAudio = (media: ImmutableMap<string, any>, startTime: number): void => {
|
|
||||||
this.props.onOpenAudio(media, startTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleHotkeyOpenMedia = (e?: KeyboardEvent): void => {
|
handleHotkeyOpenMedia = (e?: KeyboardEvent): void => {
|
||||||
const { onOpenMedia, onOpenVideo } = this.props;
|
const { onOpenMedia, onOpenVideo } = this.props;
|
||||||
const status = this._properStatus();
|
const status = this._properStatus();
|
||||||
|
@ -335,14 +310,7 @@ class Status extends ImmutablePureComponent<IStatus, IStatusState> {
|
||||||
this.node = c;
|
this.node = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
setRef = (c: HTMLDivElement): void => {
|
|
||||||
if (c) {
|
|
||||||
this.setState({ mediaWrapperWidth: c.offsetWidth });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let media = null;
|
|
||||||
const poll = null;
|
const poll = null;
|
||||||
let prepend, rebloggedByText, reblogElement, reblogElementMobile;
|
let prepend, rebloggedByText, reblogElement, reblogElementMobile;
|
||||||
|
|
||||||
|
@ -450,120 +418,6 @@ class Status extends ImmutablePureComponent<IStatus, IStatusState> {
|
||||||
status = status.reblog;
|
status = status.reblog;
|
||||||
}
|
}
|
||||||
|
|
||||||
const size = status.media_attachments.size;
|
|
||||||
const firstAttachment = status.media_attachments.first();
|
|
||||||
|
|
||||||
if (size > 0 && firstAttachment) {
|
|
||||||
if (this.props.muted) {
|
|
||||||
media = (
|
|
||||||
<AttachmentThumbs
|
|
||||||
media={status.media_attachments}
|
|
||||||
onClick={this.handleClick}
|
|
||||||
sensitive={status.sensitive}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} 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 = (
|
|
||||||
<div className='status-card horizontal compact interactive status-card--video'>
|
|
||||||
<div
|
|
||||||
ref={this.setRef}
|
|
||||||
className='status-card__image status-card-video'
|
|
||||||
style={height ? { height } : undefined}
|
|
||||||
dangerouslySetInnerHTML={{ __html: status.card.html }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
media = (
|
|
||||||
<Bundle fetchComponent={Video} loading={this.renderLoadingVideoPlayer} >
|
|
||||||
{(Component: any) => (
|
|
||||||
<Component
|
|
||||||
preview={video.preview_url}
|
|
||||||
blurhash={video.blurhash}
|
|
||||||
src={video.url}
|
|
||||||
alt={video.description}
|
|
||||||
aspectRatio={video.meta.getIn(['original', 'aspect'])}
|
|
||||||
width={this.props.cachedMediaWidth}
|
|
||||||
height={285}
|
|
||||||
inline
|
|
||||||
sensitive={status.sensitive}
|
|
||||||
onOpenVideo={this.handleOpenVideo}
|
|
||||||
cacheWidth={this.props.cacheMediaWidth}
|
|
||||||
visible={this.state.showMedia}
|
|
||||||
onToggleVisibility={this.handleToggleMediaVisibility}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Bundle>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (size === 1 && firstAttachment.type === 'audio') {
|
|
||||||
const attachment = firstAttachment;
|
|
||||||
|
|
||||||
media = (
|
|
||||||
<Bundle fetchComponent={Audio} loading={this.renderLoadingAudioPlayer} >
|
|
||||||
{(Component: any) => (
|
|
||||||
<Component
|
|
||||||
src={attachment.url}
|
|
||||||
alt={attachment.description}
|
|
||||||
poster={attachment.preview_url !== attachment.url ? attachment.preview_url : status.getIn(['account', 'avatar_static'])}
|
|
||||||
backgroundColor={attachment.meta.getIn(['colors', 'background'])}
|
|
||||||
foregroundColor={attachment.meta.getIn(['colors', 'foreground'])}
|
|
||||||
accentColor={attachment.meta.getIn(['colors', 'accent'])}
|
|
||||||
duration={attachment.meta.getIn(['original', 'duration'], 0)}
|
|
||||||
width={this.props.cachedMediaWidth}
|
|
||||||
height={263}
|
|
||||||
cacheWidth={this.props.cacheMediaWidth}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Bundle>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
media = (
|
|
||||||
<Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery}>
|
|
||||||
{(Component: any) => (
|
|
||||||
<Component
|
|
||||||
media={status.media_attachments}
|
|
||||||
sensitive={status.sensitive}
|
|
||||||
height={285}
|
|
||||||
onOpenMedia={this.props.onOpenMedia}
|
|
||||||
cacheWidth={this.props.cacheMediaWidth}
|
|
||||||
defaultWidth={this.props.cachedMediaWidth}
|
|
||||||
visible={this.state.showMedia}
|
|
||||||
onToggleVisibility={this.handleToggleMediaVisibility}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Bundle>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (status.spoiler_text.length === 0 && !status.quote && status.card) {
|
|
||||||
media = (
|
|
||||||
<Card
|
|
||||||
onOpenMedia={this.props.onOpenMedia}
|
|
||||||
card={status.card}
|
|
||||||
compact
|
|
||||||
cacheWidth={this.props.cacheMediaWidth}
|
|
||||||
defaultWidth={this.props.cachedMediaWidth}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else if (status.expectsCard) {
|
|
||||||
media = (
|
|
||||||
<PlaceholderCard />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let quote;
|
let quote;
|
||||||
|
|
||||||
if (status.quote) {
|
if (status.quote) {
|
||||||
|
@ -653,7 +507,14 @@ class Status extends ImmutablePureComponent<IStatus, IStatusState> {
|
||||||
collapsable
|
collapsable
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{media}
|
<StatusMedia
|
||||||
|
status={status}
|
||||||
|
muted={this.props.muted}
|
||||||
|
onClick={this.handleClick}
|
||||||
|
showMedia={this.state.showMedia}
|
||||||
|
onToggleVisibility={this.handleToggleMediaVisibility}
|
||||||
|
/>
|
||||||
|
|
||||||
{poll}
|
{poll}
|
||||||
{quote}
|
{quote}
|
||||||
|
|
||||||
|
|
|
@ -5,18 +5,14 @@ import { FormattedMessage, injectIntl, WrappedComponentProps as IntlProps } from
|
||||||
import { FormattedDate } from 'react-intl';
|
import { FormattedDate } from 'react-intl';
|
||||||
|
|
||||||
import Icon from 'soapbox/components/icon';
|
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 StatusReplyMentions from 'soapbox/components/status-reply-mentions';
|
||||||
import StatusContent from 'soapbox/components/status_content';
|
import StatusContent from 'soapbox/components/status_content';
|
||||||
import { HStack, Text } from 'soapbox/components/ui';
|
import { HStack, Text } from 'soapbox/components/ui';
|
||||||
import AccountContainer from 'soapbox/containers/account_container';
|
import AccountContainer from 'soapbox/containers/account_container';
|
||||||
import QuotedStatus from 'soapbox/features/status/containers/quoted_status_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 StatusInteractionBar from './status-interaction-bar';
|
||||||
|
|
||||||
import type { List as ImmutableList } from 'immutable';
|
import type { List as ImmutableList } from 'immutable';
|
||||||
|
@ -38,22 +34,16 @@ interface IDetailedStatus extends IntlProps {
|
||||||
|
|
||||||
interface IDetailedStatusState {
|
interface IDetailedStatusState {
|
||||||
height: number | null,
|
height: number | null,
|
||||||
mediaWrapperWidth: number,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DetailedStatus extends ImmutablePureComponent<IDetailedStatus, IDetailedStatusState> {
|
class DetailedStatus extends ImmutablePureComponent<IDetailedStatus, IDetailedStatusState> {
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
height: null,
|
height: null,
|
||||||
mediaWrapperWidth: NaN,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
node: HTMLDivElement | null = null;
|
node: HTMLDivElement | null = null;
|
||||||
|
|
||||||
handleOpenVideo = (media: ImmutableList<AttachmentEntity>, startTime: number) => {
|
|
||||||
this.props.onOpenVideo(media, startTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleExpandedToggle = () => {
|
handleExpandedToggle = () => {
|
||||||
this.props.onToggleHidden(this.props.status);
|
this.props.onToggleHidden(this.props.status);
|
||||||
}
|
}
|
||||||
|
@ -75,10 +65,6 @@ class DetailedStatus extends ImmutablePureComponent<IDetailedStatus, IDetailedSt
|
||||||
setRef: React.RefCallback<HTMLDivElement> = c => {
|
setRef: React.RefCallback<HTMLDivElement> = c => {
|
||||||
this.node = c;
|
this.node = c;
|
||||||
this._measureHeight();
|
this._measureHeight();
|
||||||
|
|
||||||
if (c) {
|
|
||||||
this.setState({ mediaWrapperWidth: c.offsetWidth });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps: IDetailedStatus, prevState: IDetailedStatusState) {
|
componentDidUpdate(prevProps: IDetailedStatus, prevState: IDetailedStatusState) {
|
||||||
|
@ -114,90 +100,12 @@ class DetailedStatus extends ImmutablePureComponent<IDetailedStatus, IDetailedSt
|
||||||
const outerStyle: React.CSSProperties = { boxSizing: 'border-box' };
|
const outerStyle: React.CSSProperties = { boxSizing: 'border-box' };
|
||||||
const { compact } = this.props;
|
const { compact } = this.props;
|
||||||
|
|
||||||
let media = null;
|
|
||||||
let statusTypeIcon = null;
|
let statusTypeIcon = null;
|
||||||
|
|
||||||
if (this.props.measureHeight) {
|
if (this.props.measureHeight) {
|
||||||
outerStyle.height = `${this.state.height}px`;
|
outerStyle.height = `${this.state.height}px`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const size = status.media_attachments.size;
|
|
||||||
const firstAttachment = status.media_attachments.get(0);
|
|
||||||
|
|
||||||
if (size > 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 = (
|
|
||||||
<div className='status-card horizontal interactive status-card--video'>
|
|
||||||
<div
|
|
||||||
ref={this.setRef}
|
|
||||||
className='status-card-video'
|
|
||||||
style={{ height }}
|
|
||||||
dangerouslySetInnerHTML={{ __html: status.card.html }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
media = (
|
|
||||||
<Video
|
|
||||||
preview={video.preview_url}
|
|
||||||
blurhash={video.blurhash}
|
|
||||||
src={video.url}
|
|
||||||
alt={video.description}
|
|
||||||
aspectRatio={video.meta.getIn(['original', 'aspect'])}
|
|
||||||
width={300}
|
|
||||||
height={150}
|
|
||||||
inline
|
|
||||||
onOpenVideo={this.handleOpenVideo}
|
|
||||||
sensitive={status.sensitive}
|
|
||||||
visible={this.props.showMedia}
|
|
||||||
onToggleVisibility={this.props.onToggleMediaVisibility}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (size === 1 && firstAttachment.type === 'audio') {
|
|
||||||
const attachment = firstAttachment;
|
|
||||||
|
|
||||||
media = (
|
|
||||||
<Audio
|
|
||||||
src={attachment.url}
|
|
||||||
alt={attachment.description}
|
|
||||||
duration={attachment.meta.getIn(['original', 'duration', 0])}
|
|
||||||
poster={attachment.preview_url !== attachment.url ? attachment.preview_url : account.avatar_static}
|
|
||||||
backgroundColor={attachment.meta.getIn(['colors', 'background'])}
|
|
||||||
foregroundColor={attachment.meta.getIn(['colors', 'foreground'])}
|
|
||||||
accentColor={attachment.meta.getIn(['colors', 'accent'])}
|
|
||||||
height={150}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
media = (
|
|
||||||
<MediaGallery
|
|
||||||
standalone
|
|
||||||
sensitive={status.sensitive}
|
|
||||||
media={status.media_attachments}
|
|
||||||
height={300}
|
|
||||||
onOpenMedia={this.props.onOpenMedia}
|
|
||||||
visible={this.props.showMedia}
|
|
||||||
onToggleVisibility={this.props.onToggleMediaVisibility}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (status.spoiler_text.length === 0 && !status.quote && status.card) {
|
|
||||||
media = <Card onOpenMedia={this.props.onOpenMedia} card={status.card} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
let quote;
|
let quote;
|
||||||
|
|
||||||
if (status.quote) {
|
if (status.quote) {
|
||||||
|
@ -245,7 +153,12 @@ class DetailedStatus extends ImmutablePureComponent<IDetailedStatus, IDetailedSt
|
||||||
onExpandedToggle={this.handleExpandedToggle}
|
onExpandedToggle={this.handleExpandedToggle}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{media}
|
<StatusMedia
|
||||||
|
status={status}
|
||||||
|
showMedia={this.props.showMedia}
|
||||||
|
onToggleVisibility={this.props.onToggleMediaVisibility}
|
||||||
|
/>
|
||||||
|
|
||||||
{quote}
|
{quote}
|
||||||
|
|
||||||
<HStack justifyContent='between' alignItems='center' className='py-2'>
|
<HStack justifyContent='between' alignItems='center' className='py-2'>
|
||||||
|
|
|
@ -5,7 +5,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { defineMessages, injectIntl, FormattedMessage, IntlShape, FormattedList } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage, IntlShape, FormattedList } from 'react-intl';
|
||||||
import { withRouter } from 'react-router-dom';
|
import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
import AttachmentThumbs from 'soapbox/components/attachment-thumbs';
|
import StatusMedia from 'soapbox/components/status-media';
|
||||||
import { Stack, Text } from 'soapbox/components/ui';
|
import { Stack, Text } from 'soapbox/components/ui';
|
||||||
import AccountContainer from 'soapbox/containers/account_container';
|
import AccountContainer from 'soapbox/containers/account_container';
|
||||||
|
|
||||||
|
@ -147,12 +147,7 @@ class QuotedStatus extends ImmutablePureComponent<IQuotedStatus> {
|
||||||
dangerouslySetInnerHTML={{ __html: status.contentHtml }}
|
dangerouslySetInnerHTML={{ __html: status.contentHtml }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{status.media_attachments.size > 0 && (
|
<StatusMedia status={status} />
|
||||||
<AttachmentThumbs
|
|
||||||
media={status.media_attachments}
|
|
||||||
sensitive={status.sensitive}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue