Add a keyboard shortcut to hide/show media (#10647)
* Move control of media visibility to parent component * Add keyboard shortcut to toggle media visibility
This commit is contained in:
		
							parent
							
								
									c90f3b9865
								
							
						
					
					
						commit
						a472190729
					
				@ -244,6 +244,8 @@ class MediaGallery extends React.PureComponent {
 | 
			
		||||
    intl: PropTypes.object.isRequired,
 | 
			
		||||
    defaultWidth: PropTypes.number,
 | 
			
		||||
    cacheWidth: PropTypes.func,
 | 
			
		||||
    visible: PropTypes.bool,
 | 
			
		||||
    onToggleVisibility: PropTypes.func,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  static defaultProps = {
 | 
			
		||||
@ -251,19 +253,25 @@ class MediaGallery extends React.PureComponent {
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  state = {
 | 
			
		||||
    visible: displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all',
 | 
			
		||||
    visible: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),
 | 
			
		||||
    width: this.props.defaultWidth,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  componentWillReceiveProps (nextProps) {
 | 
			
		||||
    if (!is(nextProps.media, this.props.media)) {
 | 
			
		||||
      this.setState({ visible: !nextProps.sensitive });
 | 
			
		||||
    if (!is(nextProps.media, this.props.media) && nextProps.visible === undefined) {
 | 
			
		||||
      this.setState({ visible: displayMedia !== 'hide_all' && !nextProps.sensitive || displayMedia === 'show_all' });
 | 
			
		||||
    } else if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {
 | 
			
		||||
      this.setState({ visible: nextProps.visible });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleOpen = () => {
 | 
			
		||||
    if (this.props.onToggleVisibility) {
 | 
			
		||||
      this.props.onToggleVisibility();
 | 
			
		||||
    } else {
 | 
			
		||||
      this.setState({ visible: !this.state.visible });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleClick = (index) => {
 | 
			
		||||
    this.props.onOpenMedia(this.props.media, index);
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,7 @@ import { HotKeys } from 'react-hotkeys';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import Icon from 'mastodon/components/icon';
 | 
			
		||||
import PollContainer from 'mastodon/containers/poll_container';
 | 
			
		||||
import { displayMedia } from '../initial_state';
 | 
			
		||||
 | 
			
		||||
// We use the component (and not the container) since we do not want
 | 
			
		||||
// to use the progress bar to show download progress
 | 
			
		||||
@ -85,6 +86,10 @@ class Status extends ImmutablePureComponent {
 | 
			
		||||
    'hidden',
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  state = {
 | 
			
		||||
    showMedia: displayMedia !== 'hide_all' && !this.props.status.get('sensitive') || displayMedia === 'show_all',
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // Track height changes we know about to compensate scrolling
 | 
			
		||||
  componentDidMount () {
 | 
			
		||||
    this.didShowCard = !this.props.muted && !this.props.hidden && this.props.status && this.props.status.get('card');
 | 
			
		||||
@ -122,6 +127,10 @@ class Status extends ImmutablePureComponent {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleToggleMediaVisibility = () => {
 | 
			
		||||
    this.setState({ showMedia: !this.state.showMedia });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleClick = () => {
 | 
			
		||||
    if (this.props.onClick) {
 | 
			
		||||
      this.props.onClick();
 | 
			
		||||
@ -198,6 +207,10 @@ class Status extends ImmutablePureComponent {
 | 
			
		||||
    this.props.onToggleHidden(this._properStatus());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleHotkeyToggleSensitive = () => {
 | 
			
		||||
    this.handleToggleMediaVisibility();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _properStatus () {
 | 
			
		||||
    const { status } = this.props;
 | 
			
		||||
 | 
			
		||||
@ -298,6 +311,8 @@ class Status extends ImmutablePureComponent {
 | 
			
		||||
                sensitive={status.get('sensitive')}
 | 
			
		||||
                onOpenVideo={this.handleOpenVideo}
 | 
			
		||||
                cacheWidth={this.props.cacheMediaWidth}
 | 
			
		||||
                visible={this.state.showMedia}
 | 
			
		||||
                onToggleVisibility={this.handleToggleMediaVisibility}
 | 
			
		||||
              />
 | 
			
		||||
            )}
 | 
			
		||||
          </Bundle>
 | 
			
		||||
@ -313,6 +328,8 @@ class Status extends ImmutablePureComponent {
 | 
			
		||||
                onOpenMedia={this.props.onOpenMedia}
 | 
			
		||||
                cacheWidth={this.props.cacheMediaWidth}
 | 
			
		||||
                defaultWidth={this.props.cachedMediaWidth}
 | 
			
		||||
                visible={this.state.showMedia}
 | 
			
		||||
                onToggleVisibility={this.handleToggleMediaVisibility}
 | 
			
		||||
              />
 | 
			
		||||
            )}
 | 
			
		||||
          </Bundle>
 | 
			
		||||
@ -348,6 +365,7 @@ class Status extends ImmutablePureComponent {
 | 
			
		||||
      moveUp: this.handleHotkeyMoveUp,
 | 
			
		||||
      moveDown: this.handleHotkeyMoveDown,
 | 
			
		||||
      toggleHidden: this.handleHotkeyToggleHidden,
 | 
			
		||||
      toggleSensitive: this.handleHotkeyToggleSensitive,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
 | 
			
		||||
@ -60,6 +60,10 @@ class KeyboardShortcuts extends ImmutablePureComponent {
 | 
			
		||||
                <td><kbd>x</kbd></td>
 | 
			
		||||
                <td><FormattedMessage id='keyboard_shortcuts.toggle_hidden' defaultMessage='to show/hide text behind CW' /></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td><kbd>h</kbd></td>
 | 
			
		||||
                <td><FormattedMessage id='keyboard_shortcuts.toggle_sensitivity' defaultMessage='to show/hide media' /></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td><kbd>up</kbd>, <kbd>k</kbd></td>
 | 
			
		||||
                <td><FormattedMessage id='keyboard_shortcuts.up' defaultMessage='to move up in the list' /></td>
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,8 @@ export default class DetailedStatus extends ImmutablePureComponent {
 | 
			
		||||
    onHeightChange: PropTypes.func,
 | 
			
		||||
    domain: PropTypes.string.isRequired,
 | 
			
		||||
    compact: PropTypes.bool,
 | 
			
		||||
    showMedia: PropTypes.bool,
 | 
			
		||||
    onToggleMediaVisibility: PropTypes.func,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  state = {
 | 
			
		||||
@ -122,6 +124,8 @@ export default class DetailedStatus extends ImmutablePureComponent {
 | 
			
		||||
            inline
 | 
			
		||||
            onOpenVideo={this.handleOpenVideo}
 | 
			
		||||
            sensitive={status.get('sensitive')}
 | 
			
		||||
            visible={this.props.showMedia}
 | 
			
		||||
            onToggleVisibility={this.props.onToggleMediaVisibility}
 | 
			
		||||
          />
 | 
			
		||||
        );
 | 
			
		||||
      } else {
 | 
			
		||||
@ -132,6 +136,8 @@ export default class DetailedStatus extends ImmutablePureComponent {
 | 
			
		||||
            media={status.get('media_attachments')}
 | 
			
		||||
            height={300}
 | 
			
		||||
            onOpenMedia={this.props.onOpenMedia}
 | 
			
		||||
            visible={this.props.showMedia}
 | 
			
		||||
            onToggleVisibility={this.props.onToggleMediaVisibility}
 | 
			
		||||
          />
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,7 @@ import { openModal } from '../../actions/modal';
 | 
			
		||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
			
		||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
			
		||||
import { HotKeys } from 'react-hotkeys';
 | 
			
		||||
import { boostModal, deleteModal } from '../../initial_state';
 | 
			
		||||
import { boostModal, deleteModal, displayMedia } from '../../initial_state';
 | 
			
		||||
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen';
 | 
			
		||||
import { textForScreenReader } from '../../components/status';
 | 
			
		||||
import Icon from 'mastodon/components/icon';
 | 
			
		||||
@ -131,6 +131,7 @@ class Status extends ImmutablePureComponent {
 | 
			
		||||
 | 
			
		||||
  state = {
 | 
			
		||||
    fullscreen: false,
 | 
			
		||||
    showMedia: !this.props.status ? undefined : (displayMedia !== 'hide_all' && !this.props.status.get('sensitive') || displayMedia === 'show_all'),
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  componentWillMount () {
 | 
			
		||||
@ -146,6 +147,13 @@ class Status extends ImmutablePureComponent {
 | 
			
		||||
      this._scrolledIntoView = false;
 | 
			
		||||
      this.props.dispatch(fetchStatus(nextProps.params.statusId));
 | 
			
		||||
    }
 | 
			
		||||
    if (!Immutable.is(nextProps.status, this.props.status) && nextProps.status) {
 | 
			
		||||
      this.setState({ showMedia: displayMedia !== 'hide_all' && !nextProps.status.get('sensitive') || displayMedia === 'show_all' });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleToggleMediaVisibility = () => {
 | 
			
		||||
    this.setState({ showMedia: !this.state.showMedia });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleFavouriteClick = (status) => {
 | 
			
		||||
@ -312,6 +320,10 @@ class Status extends ImmutablePureComponent {
 | 
			
		||||
    this.handleToggleHidden(this.props.status);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleHotkeyToggleSensitive = () => {
 | 
			
		||||
    this.handleToggleMediaVisibility();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleMoveUp = id => {
 | 
			
		||||
    const { status, ancestorsIds, descendantsIds } = this.props;
 | 
			
		||||
 | 
			
		||||
@ -432,6 +444,7 @@ class Status extends ImmutablePureComponent {
 | 
			
		||||
      mention: this.handleHotkeyMention,
 | 
			
		||||
      openProfile: this.handleHotkeyOpenProfile,
 | 
			
		||||
      toggleHidden: this.handleHotkeyToggleHidden,
 | 
			
		||||
      toggleSensitive: this.handleHotkeyToggleSensitive,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
@ -455,6 +468,8 @@ class Status extends ImmutablePureComponent {
 | 
			
		||||
                  onOpenMedia={this.handleOpenMedia}
 | 
			
		||||
                  onToggleHidden={this.handleToggleHidden}
 | 
			
		||||
                  domain={domain}
 | 
			
		||||
                  showMedia={this.state.showMedia}
 | 
			
		||||
                  onToggleMediaVisibility={this.handleToggleMediaVisibility}
 | 
			
		||||
                />
 | 
			
		||||
 | 
			
		||||
                <ActionBar
 | 
			
		||||
 | 
			
		||||
@ -93,6 +93,7 @@ const keyMap = {
 | 
			
		||||
  goToMuted: 'g m',
 | 
			
		||||
  goToRequests: 'g r',
 | 
			
		||||
  toggleHidden: 'x',
 | 
			
		||||
  toggleSensitive: 'h',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SwitchingColumnsArea extends React.PureComponent {
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import PropTypes from 'prop-types';
 | 
			
		||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
			
		||||
import { fromJS } from 'immutable';
 | 
			
		||||
import { fromJS, is } from 'immutable';
 | 
			
		||||
import { throttle } from 'lodash';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import { isFullscreen, requestFullscreen, exitFullscreen } from '../ui/util/fullscreen';
 | 
			
		||||
@ -102,6 +102,8 @@ class Video extends React.PureComponent {
 | 
			
		||||
    detailed: PropTypes.bool,
 | 
			
		||||
    inline: PropTypes.bool,
 | 
			
		||||
    cacheWidth: PropTypes.func,
 | 
			
		||||
    visible: PropTypes.bool,
 | 
			
		||||
    onToggleVisibility: PropTypes.func,
 | 
			
		||||
    intl: PropTypes.object.isRequired,
 | 
			
		||||
    blurhash: PropTypes.string,
 | 
			
		||||
    link: PropTypes.node,
 | 
			
		||||
@ -117,7 +119,7 @@ class Video extends React.PureComponent {
 | 
			
		||||
    fullscreen: false,
 | 
			
		||||
    hovered: false,
 | 
			
		||||
    muted: false,
 | 
			
		||||
    revealed: displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all',
 | 
			
		||||
    revealed: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // hard coded in components.scss
 | 
			
		||||
@ -280,7 +282,16 @@ class Video extends React.PureComponent {
 | 
			
		||||
    document.removeEventListener('MSFullscreenChange', this.handleFullscreenChange, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  componentDidUpdate (prevProps) {
 | 
			
		||||
  componentWillReceiveProps (nextProps) {
 | 
			
		||||
    if (!is(nextProps.visible, this.props.visible) && nextProps.visible !== undefined) {
 | 
			
		||||
      this.setState({ revealed: nextProps.visible });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  componentDidUpdate (prevProps, prevState) {
 | 
			
		||||
    if (prevState.revealed && !this.state.revealed && this.video) {
 | 
			
		||||
      this.video.pause();
 | 
			
		||||
    }
 | 
			
		||||
    if (prevProps.blurhash !== this.props.blurhash && this.props.blurhash) {
 | 
			
		||||
      this._decode();
 | 
			
		||||
    }
 | 
			
		||||
@ -316,12 +327,12 @@ class Video extends React.PureComponent {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  toggleReveal = () => {
 | 
			
		||||
    if (this.state.revealed) {
 | 
			
		||||
      this.video.pause();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this.props.onToggleVisibility) {
 | 
			
		||||
      this.props.onToggleVisibility();
 | 
			
		||||
    } else {
 | 
			
		||||
      this.setState({ revealed: !this.state.revealed });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  handleLoadedData = () => {
 | 
			
		||||
    if (this.props.startTime) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user