Add warning for sensitive audio posts (#17885)
This commit is contained in:
		
							parent
							
								
									03f19b8cd3
								
							
						
					
					
						commit
						e6979aa6d4
					
				@ -409,6 +409,10 @@ class Status extends ImmutablePureComponent {
 | 
				
			|||||||
                height={110}
 | 
					                height={110}
 | 
				
			||||||
                cacheWidth={this.props.cacheMediaWidth}
 | 
					                cacheWidth={this.props.cacheMediaWidth}
 | 
				
			||||||
                deployPictureInPicture={pictureInPicture.get('available') ? this.handleDeployPictureInPicture : undefined}
 | 
					                deployPictureInPicture={pictureInPicture.get('available') ? this.handleDeployPictureInPicture : undefined}
 | 
				
			||||||
 | 
					                sensitive={status.get('sensitive')}
 | 
				
			||||||
 | 
					                blurhash={attachment.get('blurhash')}
 | 
				
			||||||
 | 
					                visible={this.state.showMedia}
 | 
				
			||||||
 | 
					                onToggleVisibility={this.handleToggleMediaVisibility}
 | 
				
			||||||
              />
 | 
					              />
 | 
				
			||||||
            )}
 | 
					            )}
 | 
				
			||||||
          </Bundle>
 | 
					          </Bundle>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import { defineMessages, injectIntl } from 'react-intl';
 | 
					import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
 | 
				
			||||||
import { formatTime } from 'mastodon/features/video';
 | 
					import { formatTime } from 'mastodon/features/video';
 | 
				
			||||||
import Icon from 'mastodon/components/icon';
 | 
					import Icon from 'mastodon/components/icon';
 | 
				
			||||||
import classNames from 'classnames';
 | 
					import classNames from 'classnames';
 | 
				
			||||||
@ -8,6 +8,9 @@ import { throttle } from 'lodash';
 | 
				
			|||||||
import { getPointerPosition, fileNameFromURL } from 'mastodon/features/video';
 | 
					import { getPointerPosition, fileNameFromURL } from 'mastodon/features/video';
 | 
				
			||||||
import { debounce } from 'lodash';
 | 
					import { debounce } from 'lodash';
 | 
				
			||||||
import Visualizer from './visualizer';
 | 
					import Visualizer from './visualizer';
 | 
				
			||||||
 | 
					import { displayMedia, useBlurhash } from '../../initial_state';
 | 
				
			||||||
 | 
					import Blurhash from '../../components/blurhash';
 | 
				
			||||||
 | 
					import { is } from 'immutable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const messages = defineMessages({
 | 
					const messages = defineMessages({
 | 
				
			||||||
  play: { id: 'video.play', defaultMessage: 'Play' },
 | 
					  play: { id: 'video.play', defaultMessage: 'Play' },
 | 
				
			||||||
@ -15,6 +18,7 @@ const messages = defineMessages({
 | 
				
			|||||||
  mute: { id: 'video.mute', defaultMessage: 'Mute sound' },
 | 
					  mute: { id: 'video.mute', defaultMessage: 'Mute sound' },
 | 
				
			||||||
  unmute: { id: 'video.unmute', defaultMessage: 'Unmute sound' },
 | 
					  unmute: { id: 'video.unmute', defaultMessage: 'Unmute sound' },
 | 
				
			||||||
  download: { id: 'video.download', defaultMessage: 'Download file' },
 | 
					  download: { id: 'video.download', defaultMessage: 'Download file' },
 | 
				
			||||||
 | 
					  hide: { id: 'audio.hide', defaultMessage: 'Hide audio' },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const TICK_SIZE = 10;
 | 
					const TICK_SIZE = 10;
 | 
				
			||||||
@ -30,10 +34,14 @@ class Audio extends React.PureComponent {
 | 
				
			|||||||
    duration: PropTypes.number,
 | 
					    duration: PropTypes.number,
 | 
				
			||||||
    width: PropTypes.number,
 | 
					    width: PropTypes.number,
 | 
				
			||||||
    height: PropTypes.number,
 | 
					    height: PropTypes.number,
 | 
				
			||||||
 | 
					    sensitive: PropTypes.bool,
 | 
				
			||||||
    editable: PropTypes.bool,
 | 
					    editable: PropTypes.bool,
 | 
				
			||||||
    fullscreen: PropTypes.bool,
 | 
					    fullscreen: PropTypes.bool,
 | 
				
			||||||
    intl: PropTypes.object.isRequired,
 | 
					    intl: PropTypes.object.isRequired,
 | 
				
			||||||
 | 
					    blurhash: PropTypes.string,
 | 
				
			||||||
    cacheWidth: PropTypes.func,
 | 
					    cacheWidth: PropTypes.func,
 | 
				
			||||||
 | 
					    visible: PropTypes.bool,
 | 
				
			||||||
 | 
					    onToggleVisibility: PropTypes.func,
 | 
				
			||||||
    backgroundColor: PropTypes.string,
 | 
					    backgroundColor: PropTypes.string,
 | 
				
			||||||
    foregroundColor: PropTypes.string,
 | 
					    foregroundColor: PropTypes.string,
 | 
				
			||||||
    accentColor: PropTypes.string,
 | 
					    accentColor: PropTypes.string,
 | 
				
			||||||
@ -53,6 +61,7 @@ class Audio extends React.PureComponent {
 | 
				
			|||||||
    muted: false,
 | 
					    muted: false,
 | 
				
			||||||
    volume: 0.5,
 | 
					    volume: 0.5,
 | 
				
			||||||
    dragging: false,
 | 
					    dragging: false,
 | 
				
			||||||
 | 
					    revealed: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor (props) {
 | 
					  constructor (props) {
 | 
				
			||||||
@ -78,6 +87,8 @@ class Audio extends React.PureComponent {
 | 
				
			|||||||
      backgroundColor: this.props.backgroundColor,
 | 
					      backgroundColor: this.props.backgroundColor,
 | 
				
			||||||
      foregroundColor: this.props.foregroundColor,
 | 
					      foregroundColor: this.props.foregroundColor,
 | 
				
			||||||
      accentColor: this.props.accentColor,
 | 
					      accentColor: this.props.accentColor,
 | 
				
			||||||
 | 
					      sensitive: this.props.sensitive,
 | 
				
			||||||
 | 
					      visible: this.props.visible,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -126,6 +137,12 @@ class Audio extends React.PureComponent {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  componentWillReceiveProps (nextProps) {
 | 
				
			||||||
 | 
					    if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {
 | 
				
			||||||
 | 
					      this.setState({ revealed: nextProps.visible });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  componentWillUnmount () {
 | 
					  componentWillUnmount () {
 | 
				
			||||||
    window.removeEventListener('scroll', this.handleScroll);
 | 
					    window.removeEventListener('scroll', this.handleScroll);
 | 
				
			||||||
    window.removeEventListener('resize', this.handleResize);
 | 
					    window.removeEventListener('resize', this.handleResize);
 | 
				
			||||||
@ -189,6 +206,14 @@ class Audio extends React.PureComponent {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  toggleReveal = () => {
 | 
				
			||||||
 | 
					    if (this.props.onToggleVisibility) {
 | 
				
			||||||
 | 
					      this.props.onToggleVisibility();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.setState({ revealed: !this.state.revealed });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  handleVolumeMouseDown = e => {
 | 
					  handleVolumeMouseDown = e => {
 | 
				
			||||||
    document.addEventListener('mousemove', this.handleMouseVolSlide, true);
 | 
					    document.addEventListener('mousemove', this.handleMouseVolSlide, true);
 | 
				
			||||||
    document.addEventListener('mouseup', this.handleVolumeMouseUp, true);
 | 
					    document.addEventListener('mouseup', this.handleVolumeMouseUp, true);
 | 
				
			||||||
@ -433,13 +458,29 @@ class Audio extends React.PureComponent {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const { src, intl, alt, editable, autoPlay } = this.props;
 | 
					    const { src, intl, alt, editable, autoPlay, sensitive, blurhash } = this.props;
 | 
				
			||||||
    const { paused, muted, volume, currentTime, duration, buffer, dragging } = this.state;
 | 
					    const { paused, muted, volume, currentTime, duration, buffer, dragging, revealed } = this.state;
 | 
				
			||||||
    const progress = Math.min((currentTime / duration) * 100, 100);
 | 
					    const progress = Math.min((currentTime / duration) * 100, 100);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let warning;
 | 
				
			||||||
 | 
					    if (sensitive) {
 | 
				
			||||||
 | 
					      warning = <FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' />;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      warning = <FormattedMessage id='status.media_hidden' defaultMessage='Media hidden' />;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className={classNames('audio-player', { editable })} ref={this.setPlayerRef} style={{ backgroundColor: this._getBackgroundColor(), color: this._getForegroundColor(), width: '100%', height: this.props.fullscreen ? '100%' : (this.state.height || this.props.height) }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} tabIndex='0' onKeyDown={this.handleKeyDown}>
 | 
					      <div className={classNames('audio-player', { editable, inactive: !revealed })} ref={this.setPlayerRef} style={{ backgroundColor: this._getBackgroundColor(), color: this._getForegroundColor(), width: '100%', height: this.props.fullscreen ? '100%' : (this.state.height || this.props.height) }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} tabIndex='0' onKeyDown={this.handleKeyDown}>
 | 
				
			||||||
        <audio
 | 
					
 | 
				
			||||||
 | 
					        <Blurhash
 | 
				
			||||||
 | 
					          hash={blurhash}
 | 
				
			||||||
 | 
					          className={classNames('media-gallery__preview', {
 | 
				
			||||||
 | 
					            'media-gallery__preview--hidden': revealed,
 | 
				
			||||||
 | 
					          })}
 | 
				
			||||||
 | 
					          dummy={!useBlurhash}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        {(revealed || editable) && <audio
 | 
				
			||||||
          src={src}
 | 
					          src={src}
 | 
				
			||||||
          ref={this.setAudioRef}
 | 
					          ref={this.setAudioRef}
 | 
				
			||||||
          preload={autoPlay ? 'auto' : 'none'}
 | 
					          preload={autoPlay ? 'auto' : 'none'}
 | 
				
			||||||
@ -448,7 +489,7 @@ class Audio extends React.PureComponent {
 | 
				
			|||||||
          onProgress={this.handleProgress}
 | 
					          onProgress={this.handleProgress}
 | 
				
			||||||
          onLoadedData={this.handleLoadedData}
 | 
					          onLoadedData={this.handleLoadedData}
 | 
				
			||||||
          crossOrigin='anonymous'
 | 
					          crossOrigin='anonymous'
 | 
				
			||||||
        />
 | 
					        />}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <canvas
 | 
					        <canvas
 | 
				
			||||||
          role='button'
 | 
					          role='button'
 | 
				
			||||||
@ -464,13 +505,19 @@ class Audio extends React.PureComponent {
 | 
				
			|||||||
          aria-label={alt}
 | 
					          aria-label={alt}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <img
 | 
					        <div className={classNames('spoiler-button', { 'spoiler-button--hidden': revealed || editable })}>
 | 
				
			||||||
 | 
					          <button type='button' className='spoiler-button__overlay' onClick={this.toggleReveal}>
 | 
				
			||||||
 | 
					            <span className='spoiler-button__overlay__label'>{warning}</span>
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        {(revealed || editable) && <img
 | 
				
			||||||
          src={this.props.poster}
 | 
					          src={this.props.poster}
 | 
				
			||||||
          alt=''
 | 
					          alt=''
 | 
				
			||||||
          width={(this._getRadius() - TICK_SIZE) * 2}
 | 
					          width={(this._getRadius() - TICK_SIZE) * 2}
 | 
				
			||||||
          height={(this._getRadius() - TICK_SIZE) * 2}
 | 
					          height={(this._getRadius() - TICK_SIZE) * 2}
 | 
				
			||||||
          style={{ position: 'absolute', left: this._getCX(), top: this._getCY(), transform: 'translate(-50%, -50%)', borderRadius: '50%', pointerEvents: 'none' }}
 | 
					          style={{ position: 'absolute', left: this._getCX(), top: this._getCY(), transform: 'translate(-50%, -50%)', borderRadius: '50%', pointerEvents: 'none' }}
 | 
				
			||||||
        />
 | 
					        />}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className='video-player__seek' onMouseDown={this.handleMouseDown} ref={this.setSeekRef}>
 | 
					        <div className='video-player__seek' onMouseDown={this.handleMouseDown} ref={this.setSeekRef}>
 | 
				
			||||||
          <div className='video-player__seek__buffer' style={{ width: `${buffer}%` }} />
 | 
					          <div className='video-player__seek__buffer' style={{ width: `${buffer}%` }} />
 | 
				
			||||||
@ -508,6 +555,7 @@ class Audio extends React.PureComponent {
 | 
				
			|||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <div className='video-player__buttons right'>
 | 
					            <div className='video-player__buttons right'>
 | 
				
			||||||
 | 
					              {!editable && <button type='button' title={intl.formatMessage(messages.hide)} aria-label={intl.formatMessage(messages.hide)} className='player-button' onClick={this.toggleReveal}><Icon id='eye-slash' fixedWidth /></button>}
 | 
				
			||||||
              <a title={intl.formatMessage(messages.download)} aria-label={intl.formatMessage(messages.download)} className='video-player__download__icon player-button' href={this.props.src} download>
 | 
					              <a title={intl.formatMessage(messages.download)} aria-label={intl.formatMessage(messages.download)} className='video-player__download__icon player-button' href={this.props.src} download>
 | 
				
			||||||
                <Icon id={'download'} fixedWidth />
 | 
					                <Icon id={'download'} fixedWidth />
 | 
				
			||||||
              </a>
 | 
					              </a>
 | 
				
			||||||
 | 
				
			|||||||
@ -138,7 +138,11 @@ class DetailedStatus extends ImmutablePureComponent {
 | 
				
			|||||||
            backgroundColor={attachment.getIn(['meta', 'colors', 'background'])}
 | 
					            backgroundColor={attachment.getIn(['meta', 'colors', 'background'])}
 | 
				
			||||||
            foregroundColor={attachment.getIn(['meta', 'colors', 'foreground'])}
 | 
					            foregroundColor={attachment.getIn(['meta', 'colors', 'foreground'])}
 | 
				
			||||||
            accentColor={attachment.getIn(['meta', 'colors', 'accent'])}
 | 
					            accentColor={attachment.getIn(['meta', 'colors', 'accent'])}
 | 
				
			||||||
 | 
					            sensitive={status.get('sensitive')}
 | 
				
			||||||
 | 
					            visible={this.props.showMedia}
 | 
				
			||||||
 | 
					            blurhash={attachment.get('blurhash')}
 | 
				
			||||||
            height={150}
 | 
					            height={150}
 | 
				
			||||||
 | 
					            onToggleVisibility={this.props.onToggleMediaVisibility}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      } else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
 | 
					      } else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
 | 
				
			||||||
 | 
				
			|||||||
@ -5939,6 +5939,13 @@ a.status-card.compact:hover {
 | 
				
			|||||||
    height: 100%;
 | 
					    height: 100%;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.inactive {
 | 
				
			||||||
 | 
					    audio,
 | 
				
			||||||
 | 
					    .video-player__controls {
 | 
				
			||||||
 | 
					      visibility: hidden;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .video-player__volume::before,
 | 
					  .video-player__volume::before,
 | 
				
			||||||
  .video-player__seek::before {
 | 
					  .video-player__seek::before {
 | 
				
			||||||
    background: currentColor;
 | 
					    background: currentColor;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user