forked from cybrespace/mastodon
		
	Add warning for sensitive audio posts (#17885)
This commit is contained in:
		
							parent
							
								
									03f19b8cd3
								
							
						
					
					
						commit
						e6979aa6d4
					
				
					 4 changed files with 71 additions and 8 deletions
				
			
		| 
						 | 
				
			
			@ -409,6 +409,10 @@ class Status extends ImmutablePureComponent {
 | 
			
		|||
                height={110}
 | 
			
		||||
                cacheWidth={this.props.cacheMediaWidth}
 | 
			
		||||
                deployPictureInPicture={pictureInPicture.get('available') ? this.handleDeployPictureInPicture : undefined}
 | 
			
		||||
                sensitive={status.get('sensitive')}
 | 
			
		||||
                blurhash={attachment.get('blurhash')}
 | 
			
		||||
                visible={this.state.showMedia}
 | 
			
		||||
                onToggleVisibility={this.handleToggleMediaVisibility}
 | 
			
		||||
              />
 | 
			
		||||
            )}
 | 
			
		||||
          </Bundle>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
import React from 'react';
 | 
			
		||||
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 Icon from 'mastodon/components/icon';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
| 
						 | 
				
			
			@ -8,6 +8,9 @@ import { throttle } from 'lodash';
 | 
			
		|||
import { getPointerPosition, fileNameFromURL } from 'mastodon/features/video';
 | 
			
		||||
import { debounce } from 'lodash';
 | 
			
		||||
import Visualizer from './visualizer';
 | 
			
		||||
import { displayMedia, useBlurhash } from '../../initial_state';
 | 
			
		||||
import Blurhash from '../../components/blurhash';
 | 
			
		||||
import { is } from 'immutable';
 | 
			
		||||
 | 
			
		||||
const messages = defineMessages({
 | 
			
		||||
  play: { id: 'video.play', defaultMessage: 'Play' },
 | 
			
		||||
| 
						 | 
				
			
			@ -15,6 +18,7 @@ const messages = defineMessages({
 | 
			
		|||
  mute: { id: 'video.mute', defaultMessage: 'Mute sound' },
 | 
			
		||||
  unmute: { id: 'video.unmute', defaultMessage: 'Unmute sound' },
 | 
			
		||||
  download: { id: 'video.download', defaultMessage: 'Download file' },
 | 
			
		||||
  hide: { id: 'audio.hide', defaultMessage: 'Hide audio' },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const TICK_SIZE = 10;
 | 
			
		||||
| 
						 | 
				
			
			@ -30,10 +34,14 @@ class Audio extends React.PureComponent {
 | 
			
		|||
    duration: PropTypes.number,
 | 
			
		||||
    width: PropTypes.number,
 | 
			
		||||
    height: PropTypes.number,
 | 
			
		||||
    sensitive: PropTypes.bool,
 | 
			
		||||
    editable: PropTypes.bool,
 | 
			
		||||
    fullscreen: PropTypes.bool,
 | 
			
		||||
    intl: PropTypes.object.isRequired,
 | 
			
		||||
    blurhash: PropTypes.string,
 | 
			
		||||
    cacheWidth: PropTypes.func,
 | 
			
		||||
    visible: PropTypes.bool,
 | 
			
		||||
    onToggleVisibility: PropTypes.func,
 | 
			
		||||
    backgroundColor: PropTypes.string,
 | 
			
		||||
    foregroundColor: PropTypes.string,
 | 
			
		||||
    accentColor: PropTypes.string,
 | 
			
		||||
| 
						 | 
				
			
			@ -53,6 +61,7 @@ class Audio extends React.PureComponent {
 | 
			
		|||
    muted: false,
 | 
			
		||||
    volume: 0.5,
 | 
			
		||||
    dragging: false,
 | 
			
		||||
    revealed: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  constructor (props) {
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +87,8 @@ class Audio extends React.PureComponent {
 | 
			
		|||
      backgroundColor: this.props.backgroundColor,
 | 
			
		||||
      foregroundColor: this.props.foregroundColor,
 | 
			
		||||
      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 () {
 | 
			
		||||
    window.removeEventListener('scroll', this.handleScroll);
 | 
			
		||||
    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 => {
 | 
			
		||||
    document.addEventListener('mousemove', this.handleMouseVolSlide, true);
 | 
			
		||||
    document.addEventListener('mouseup', this.handleVolumeMouseUp, true);
 | 
			
		||||
| 
						 | 
				
			
			@ -433,13 +458,29 @@ class Audio extends React.PureComponent {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  render () {
 | 
			
		||||
    const { src, intl, alt, editable, autoPlay } = this.props;
 | 
			
		||||
    const { paused, muted, volume, currentTime, duration, buffer, dragging } = this.state;
 | 
			
		||||
    const { src, intl, alt, editable, autoPlay, sensitive, blurhash } = this.props;
 | 
			
		||||
    const { paused, muted, volume, currentTime, duration, buffer, dragging, revealed } = this.state;
 | 
			
		||||
    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 (
 | 
			
		||||
      <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}>
 | 
			
		||||
        <audio
 | 
			
		||||
      <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}>
 | 
			
		||||
 | 
			
		||||
        <Blurhash
 | 
			
		||||
          hash={blurhash}
 | 
			
		||||
          className={classNames('media-gallery__preview', {
 | 
			
		||||
            'media-gallery__preview--hidden': revealed,
 | 
			
		||||
          })}
 | 
			
		||||
          dummy={!useBlurhash}
 | 
			
		||||
        />
 | 
			
		||||
 | 
			
		||||
        {(revealed || editable) && <audio
 | 
			
		||||
          src={src}
 | 
			
		||||
          ref={this.setAudioRef}
 | 
			
		||||
          preload={autoPlay ? 'auto' : 'none'}
 | 
			
		||||
| 
						 | 
				
			
			@ -448,7 +489,7 @@ class Audio extends React.PureComponent {
 | 
			
		|||
          onProgress={this.handleProgress}
 | 
			
		||||
          onLoadedData={this.handleLoadedData}
 | 
			
		||||
          crossOrigin='anonymous'
 | 
			
		||||
        />
 | 
			
		||||
        />}
 | 
			
		||||
 | 
			
		||||
        <canvas
 | 
			
		||||
          role='button'
 | 
			
		||||
| 
						 | 
				
			
			@ -464,13 +505,19 @@ class Audio extends React.PureComponent {
 | 
			
		|||
          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}
 | 
			
		||||
          alt=''
 | 
			
		||||
          width={(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' }}
 | 
			
		||||
        />
 | 
			
		||||
        />}
 | 
			
		||||
 | 
			
		||||
        <div className='video-player__seek' onMouseDown={this.handleMouseDown} ref={this.setSeekRef}>
 | 
			
		||||
          <div className='video-player__seek__buffer' style={{ width: `${buffer}%` }} />
 | 
			
		||||
| 
						 | 
				
			
			@ -508,6 +555,7 @@ class Audio extends React.PureComponent {
 | 
			
		|||
            </div>
 | 
			
		||||
 | 
			
		||||
            <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>
 | 
			
		||||
                <Icon id={'download'} fixedWidth />
 | 
			
		||||
              </a>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -138,7 +138,11 @@ class DetailedStatus extends ImmutablePureComponent {
 | 
			
		|||
            backgroundColor={attachment.getIn(['meta', 'colors', 'background'])}
 | 
			
		||||
            foregroundColor={attachment.getIn(['meta', 'colors', 'foreground'])}
 | 
			
		||||
            accentColor={attachment.getIn(['meta', 'colors', 'accent'])}
 | 
			
		||||
            sensitive={status.get('sensitive')}
 | 
			
		||||
            visible={this.props.showMedia}
 | 
			
		||||
            blurhash={attachment.get('blurhash')}
 | 
			
		||||
            height={150}
 | 
			
		||||
            onToggleVisibility={this.props.onToggleMediaVisibility}
 | 
			
		||||
          />
 | 
			
		||||
        );
 | 
			
		||||
      } else if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5939,6 +5939,13 @@ a.status-card.compact:hover {
 | 
			
		|||
    height: 100%;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &.inactive {
 | 
			
		||||
    audio,
 | 
			
		||||
    .video-player__controls {
 | 
			
		||||
      visibility: hidden;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .video-player__volume::before,
 | 
			
		||||
  .video-player__seek::before {
 | 
			
		||||
    background: currentColor;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue