Skip to content

Commit

Permalink
Add a keyboard shortcut to hide/show media (mastodon#10647)
Browse files Browse the repository at this point in the history
* Move control of media visibility to parent component

* Add keyboard shortcut to toggle media visibility
  • Loading branch information
ClearlyClaire authored and hiyuki2578 committed Oct 2, 2019
1 parent 6544c32 commit 36dac67
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 12 deletions.
16 changes: 12 additions & 4 deletions app/javascript/mastodon/components/media_gallery.js
Original file line number Diff line number Diff line change
Expand Up @@ -244,25 +244,33 @@ class MediaGallery extends React.PureComponent {
intl: PropTypes.object.isRequired,
defaultWidth: PropTypes.number,
cacheWidth: PropTypes.func,
visible: PropTypes.bool,
onToggleVisibility: PropTypes.func,
};

static defaultProps = {
standalone: false,
};

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 = () => {
this.setState({ visible: !this.state.visible });
if (this.props.onToggleVisibility) {
this.props.onToggleVisibility();
} else {
this.setState({ visible: !this.state.visible });
}
}

handleClick = (index) => {
Expand Down
18 changes: 18 additions & 0 deletions app/javascript/mastodon/components/status.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -122,6 +127,10 @@ class Status extends ImmutablePureComponent {
}
}

handleToggleMediaVisibility = () => {
this.setState({ showMedia: !this.state.showMedia });
}

handleClick = () => {
if (this.props.onClick) {
this.props.onClick();
Expand Down Expand Up @@ -198,6 +207,10 @@ class Status extends ImmutablePureComponent {
this.props.onToggleHidden(this._properStatus());
}

handleHotkeyToggleSensitive = () => {
this.handleToggleMediaVisibility();
}

_properStatus () {
const { status } = this.props;

Expand Down Expand Up @@ -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>
Expand All @@ -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>
Expand Down Expand Up @@ -348,6 +365,7 @@ class Status extends ImmutablePureComponent {
moveUp: this.handleHotkeyMoveUp,
moveDown: this.handleHotkeyMoveDown,
toggleHidden: this.handleHotkeyToggleHidden,
toggleSensitive: this.handleHotkeyToggleSensitive,
};

return (
Expand Down
4 changes: 4 additions & 0 deletions app/javascript/mastodon/features/keyboard_shortcuts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 {
Expand All @@ -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}
/>
);
}
Expand Down
17 changes: 16 additions & 1 deletion app/javascript/mastodon/features/status/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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 () {
Expand All @@ -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) => {
Expand Down Expand Up @@ -312,6 +320,10 @@ class Status extends ImmutablePureComponent {
this.handleToggleHidden(this.props.status);
}

handleHotkeyToggleSensitive = () => {
this.handleToggleMediaVisibility();
}

handleMoveUp = id => {
const { status, ancestorsIds, descendantsIds } = this.props;

Expand Down Expand Up @@ -432,6 +444,7 @@ class Status extends ImmutablePureComponent {
mention: this.handleHotkeyMention,
openProfile: this.handleHotkeyOpenProfile,
toggleHidden: this.handleHotkeyToggleHidden,
toggleSensitive: this.handleHotkeyToggleSensitive,
};

return (
Expand All @@ -455,6 +468,8 @@ class Status extends ImmutablePureComponent {
onOpenMedia={this.handleOpenMedia}
onToggleHidden={this.handleToggleHidden}
domain={domain}
showMedia={this.state.showMedia}
onToggleMediaVisibility={this.handleToggleMediaVisibility}
/>

<ActionBar
Expand Down
1 change: 1 addition & 0 deletions app/javascript/mastodon/features/ui/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ const keyMap = {
goToMuted: 'g m',
goToRequests: 'g r',
toggleHidden: 'x',
toggleSensitive: 'h',
};

class SwitchingColumnsArea extends React.PureComponent {
Expand Down
25 changes: 18 additions & 7 deletions app/javascript/mastodon/features/video/index.js
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -316,11 +327,11 @@ 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 });
}

this.setState({ revealed: !this.state.revealed });
}

handleLoadedData = () => {
Expand Down

0 comments on commit 36dac67

Please sign in to comment.