Merge branch 'sensitive-video-fix' into 'develop'
Sensitive video refactor Closes #1190 See merge request soapbox-pub/soapbox!1917
This commit is contained in:
commit
afaf8b10c2
9 changed files with 30 additions and 197 deletions
|
@ -10,6 +10,7 @@ import { useAppDispatch, useSettings } from 'soapbox/hooks';
|
|||
import { addAutoPlay } from 'soapbox/utils/media';
|
||||
|
||||
import type { List as ImmutableList } from 'immutable';
|
||||
import type VideoType from 'soapbox/features/video';
|
||||
import type { Status, Attachment } from 'soapbox/types/entities';
|
||||
|
||||
interface IStatusMedia {
|
||||
|
@ -66,10 +67,6 @@ const StatusMedia: React.FC<IStatusMedia> = ({
|
|||
dispatch(openModal('MEDIA', { media, status, index }));
|
||||
};
|
||||
|
||||
const openVideo = (media: Attachment, time: number): void => {
|
||||
dispatch(openModal('VIDEO', { media, time }));
|
||||
};
|
||||
|
||||
if (size > 0 && firstAttachment) {
|
||||
if (muted) {
|
||||
media = (
|
||||
|
@ -105,20 +102,17 @@ const StatusMedia: React.FC<IStatusMedia> = ({
|
|||
);
|
||||
} else {
|
||||
media = (
|
||||
<Bundle fetchComponent={Video} loading={renderLoadingVideoPlayer} >
|
||||
{(Component: any) => (
|
||||
<Bundle fetchComponent={Video} loading={renderLoadingVideoPlayer}>
|
||||
{(Component: typeof VideoType) => (
|
||||
<Component
|
||||
preview={video.preview_url}
|
||||
blurhash={video.blurhash}
|
||||
src={video.url}
|
||||
alt={video.description}
|
||||
aspectRatio={video.meta.getIn(['original', 'aspect'])}
|
||||
aspectRatio={Number(video.meta.getIn(['original', 'aspect']))}
|
||||
height={285}
|
||||
inline
|
||||
sensitive={status.sensitive}
|
||||
onOpenVideo={openVideo}
|
||||
visible={showMedia}
|
||||
onToggleVisibility={onToggleVisibility}
|
||||
inline
|
||||
/>
|
||||
)}
|
||||
</Bundle>
|
||||
|
|
|
@ -197,7 +197,6 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
|
|||
width={width}
|
||||
height={height}
|
||||
startTime={time}
|
||||
onCloseVideo={onClose}
|
||||
detailed
|
||||
link={link}
|
||||
alt={attachment.description}
|
||||
|
|
|
@ -37,7 +37,6 @@ const VideoModal: React.FC<IVideoModal> = ({ status, account, media, time, onClo
|
|||
blurhash={media.blurhash}
|
||||
src={media.url}
|
||||
startTime={time}
|
||||
onCloseVideo={onClose}
|
||||
link={link}
|
||||
detailed
|
||||
alt={media.description}
|
||||
|
|
|
@ -2,17 +2,14 @@ import classNames from 'clsx';
|
|||
import debounce from 'lodash/debounce';
|
||||
import throttle from 'lodash/throttle';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import Blurhash from 'soapbox/components/blurhash';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
import { useSettings } from 'soapbox/hooks';
|
||||
import { isPanoramic, isPortrait, minimumAspectRatio, maximumAspectRatio } from 'soapbox/utils/media-aspect-ratio';
|
||||
|
||||
import { isFullscreen, requestFullscreen, exitFullscreen } from '../ui/util/fullscreen';
|
||||
|
||||
import type { Attachment } from 'soapbox/types/entities';
|
||||
|
||||
const DEFAULT_HEIGHT = 300;
|
||||
|
||||
type Position = { x: number, y: number };
|
||||
|
@ -107,15 +104,11 @@ interface IVideo {
|
|||
alt?: string,
|
||||
width?: number,
|
||||
height?: number,
|
||||
sensitive?: boolean,
|
||||
startTime?: number,
|
||||
onOpenVideo?: (attachment: Attachment, time: number) => void,
|
||||
onCloseVideo?: () => void,
|
||||
detailed?: boolean,
|
||||
inline?: boolean,
|
||||
cacheWidth?: (width: number) => void,
|
||||
visible?: boolean,
|
||||
onToggleVisibility?: () => void,
|
||||
blurhash?: string,
|
||||
link?: React.ReactNode,
|
||||
aspectRatio?: number,
|
||||
|
@ -125,23 +118,18 @@ interface IVideo {
|
|||
const Video: React.FC<IVideo> = ({
|
||||
width,
|
||||
visible = false,
|
||||
sensitive = false,
|
||||
detailed = false,
|
||||
cacheWidth,
|
||||
onToggleVisibility,
|
||||
startTime,
|
||||
src,
|
||||
height,
|
||||
alt,
|
||||
onCloseVideo,
|
||||
inline,
|
||||
aspectRatio = 16 / 9,
|
||||
link,
|
||||
blurhash,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const settings = useSettings();
|
||||
const displayMedia = settings.get('displayMedia') as string | undefined;
|
||||
|
||||
const player = useRef<HTMLDivElement>(null);
|
||||
const video = useRef<HTMLVideoElement>(null);
|
||||
|
@ -157,7 +145,6 @@ const Video: React.FC<IVideo> = ({
|
|||
const [fullscreen, setFullscreen] = useState(false);
|
||||
const [hovered, setHovered] = useState(false);
|
||||
const [muted, setMuted] = useState(false);
|
||||
const [revealed, setRevealed] = useState<boolean>(visible !== undefined ? visible : (displayMedia !== 'hide_all' && !sensitive || displayMedia === 'show_all'));
|
||||
const [buffer, setBuffer] = useState(0);
|
||||
|
||||
const setDimensions = () => {
|
||||
|
@ -342,7 +329,6 @@ const Video: React.FC<IVideo> = ({
|
|||
|
||||
// If we are in fullscreen mode, we don't want any hotkeys
|
||||
// interacting with the UI that's not visible
|
||||
|
||||
if (fullscreen) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
@ -411,16 +397,6 @@ const Video: React.FC<IVideo> = ({
|
|||
}
|
||||
};
|
||||
|
||||
const toggleReveal: React.MouseEventHandler = (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (onToggleVisibility) {
|
||||
onToggleVisibility();
|
||||
} else {
|
||||
setRevealed(!revealed);
|
||||
}
|
||||
};
|
||||
|
||||
const handleLoadedData = () => {
|
||||
if (video.current && startTime) {
|
||||
video.current.currentTime = startTime;
|
||||
|
@ -459,14 +435,6 @@ const Video: React.FC<IVideo> = ({
|
|||
playerStyle.height = height || DEFAULT_HEIGHT;
|
||||
}
|
||||
|
||||
let warning;
|
||||
|
||||
if (sensitive) {
|
||||
warning = <FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' />;
|
||||
} else {
|
||||
warning = <FormattedMessage id='status.media_hidden' defaultMessage='Media hidden' />;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('fullscreenchange', handleFullscreenChange, true);
|
||||
document.addEventListener('webkitfullscreenchange', handleFullscreenChange, true);
|
||||
|
@ -488,21 +456,15 @@ const Video: React.FC<IVideo> = ({
|
|||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
setRevealed(true);
|
||||
}
|
||||
}, [visible]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!revealed) {
|
||||
if (!visible) {
|
||||
video.current?.pause();
|
||||
}
|
||||
}, [revealed]);
|
||||
}, [visible]);
|
||||
|
||||
return (
|
||||
<div
|
||||
role='menuitem'
|
||||
className={classNames('video-player', { 'video-player--inactive': !revealed, detailed, 'video-player--inline': inline && !fullscreen, fullscreen })}
|
||||
className={classNames('video-player', { detailed, 'video-player--inline': inline && !fullscreen, fullscreen })}
|
||||
style={playerStyle}
|
||||
ref={player}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
|
@ -511,40 +473,29 @@ const Video: React.FC<IVideo> = ({
|
|||
onKeyDown={handleKeyDown}
|
||||
tabIndex={0}
|
||||
>
|
||||
<Blurhash
|
||||
hash={blurhash}
|
||||
className={classNames('media-gallery__preview', {
|
||||
'media-gallery__preview--hidden': revealed,
|
||||
})}
|
||||
/>
|
||||
|
||||
{revealed && (
|
||||
<video
|
||||
ref={video}
|
||||
src={src}
|
||||
loop
|
||||
role='button'
|
||||
tabIndex={0}
|
||||
aria-label={alt}
|
||||
title={alt}
|
||||
width={width}
|
||||
height={height || DEFAULT_HEIGHT}
|
||||
onClick={togglePlay}
|
||||
onKeyDown={handleVideoKeyDown}
|
||||
onPlay={handlePlay}
|
||||
onPause={handlePause}
|
||||
onTimeUpdate={handleTimeUpdate}
|
||||
onLoadedData={handleLoadedData}
|
||||
onProgress={handleProgress}
|
||||
onVolumeChange={handleVolumeChange}
|
||||
/>
|
||||
{!fullscreen && (
|
||||
<Blurhash hash={blurhash} className='media-gallery__preview' />
|
||||
)}
|
||||
|
||||
<div className={classNames('spoiler-button', { 'spoiler-button--hidden': !sensitive || revealed })}>
|
||||
<button type='button' className='spoiler-button__overlay' onClick={toggleReveal}>
|
||||
<span className='spoiler-button__overlay__label'>{warning}</span>
|
||||
</button>
|
||||
</div>
|
||||
<video
|
||||
ref={video}
|
||||
src={src}
|
||||
loop
|
||||
role='button'
|
||||
tabIndex={0}
|
||||
aria-label={alt}
|
||||
title={alt}
|
||||
width={width}
|
||||
height={height || DEFAULT_HEIGHT}
|
||||
onClick={togglePlay}
|
||||
onKeyDown={handleVideoKeyDown}
|
||||
onPlay={handlePlay}
|
||||
onPause={handlePause}
|
||||
onTimeUpdate={handleTimeUpdate}
|
||||
onLoadedData={handleLoadedData}
|
||||
onProgress={handleProgress}
|
||||
onVolumeChange={handleVolumeChange}
|
||||
/>
|
||||
|
||||
<div className={classNames('video-player__controls', { active: paused || hovered })}>
|
||||
<div className='video-player__seek' onMouseDown={handleMouseDown} ref={seek}>
|
||||
|
@ -605,18 +556,6 @@ const Video: React.FC<IVideo> = ({
|
|||
</div>
|
||||
|
||||
<div className='video-player__buttons right'>
|
||||
{(sensitive && !onCloseVideo) && (
|
||||
<button
|
||||
type='button'
|
||||
title={intl.formatMessage(messages.hide)}
|
||||
aria-label={intl.formatMessage(messages.hide)}
|
||||
className='player-button'
|
||||
onClick={toggleReveal}
|
||||
>
|
||||
<Icon src={require('@tabler/icons/eye-off.svg')} />
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
type='button'
|
||||
title={intl.formatMessage(fullscreen ? messages.exit_fullscreen : messages.fullscreen)}
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
@import 'components/columns';
|
||||
@import 'components/search';
|
||||
@import 'components/react-toggle';
|
||||
@import 'components/spoiler-button';
|
||||
@import 'components/video-player';
|
||||
@import 'components/audio-player';
|
||||
@import 'components/profile-hover-card';
|
||||
|
|
|
@ -343,10 +343,6 @@
|
|||
height: 100% !important;
|
||||
margin: 4px 0 8px;
|
||||
|
||||
.spoiler-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.media-gallery__item:not(.media-gallery__item--image) {
|
||||
max-width: 100%;
|
||||
width: 120px !important;
|
||||
|
|
|
@ -141,10 +141,6 @@ $media-compact-size: 50px;
|
|||
height: $media-compact-size !important;
|
||||
background: transparent;
|
||||
|
||||
.spoiler-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.media-gallery__item {
|
||||
width: $media-compact-size !important;
|
||||
height: $media-compact-size !important;
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
.spoiler-button {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
z-index: 40;
|
||||
|
||||
&--hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
&__overlay {
|
||||
display: block;
|
||||
background: transparent;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
|
||||
&__label {
|
||||
display: inline-block;
|
||||
background: var(--accent-color--faint);
|
||||
border-radius: 8px;
|
||||
padding: 8px 12px;
|
||||
color: var(--primary-text-color);
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
.spoiler-button__overlay__label {
|
||||
background: var(--accent-color--med);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -73,52 +73,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
&--inactive {
|
||||
min-height: 300px;
|
||||
|
||||
video,
|
||||
.video-player__controls {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&__spoiler {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 4;
|
||||
border: 0;
|
||||
background: var(--background-color);
|
||||
color: var(--primary-text-color--faint);
|
||||
transition: none;
|
||||
pointer-events: none;
|
||||
|
||||
&.active {
|
||||
display: block;
|
||||
pointer-events: auto;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
display: block;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
&__buttons-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
|
Loading…
Reference in a new issue