From a472190729782f31731674c626c07af483fe9c7f Mon Sep 17 00:00:00 2001 From: ThibG Date: Sat, 25 May 2019 23:20:51 +0200 Subject: [PATCH] Add a keyboard shortcut to hide/show media (#10647) * Move control of media visibility to parent component * Add keyboard shortcut to toggle media visibility --- .../mastodon/components/media_gallery.js | 16 +++++++++--- app/javascript/mastodon/components/status.js | 18 +++++++++++++ .../features/keyboard_shortcuts/index.js | 4 +++ .../status/components/detailed_status.js | 6 +++++ .../mastodon/features/status/index.js | 17 ++++++++++++- app/javascript/mastodon/features/ui/index.js | 1 + .../mastodon/features/video/index.js | 25 +++++++++++++------ 7 files changed, 75 insertions(+), 12 deletions(-) diff --git a/app/javascript/mastodon/components/media_gallery.js b/app/javascript/mastodon/components/media_gallery.js index abd17647e..56618462b 100644 --- a/app/javascript/mastodon/components/media_gallery.js +++ b/app/javascript/mastodon/components/media_gallery.js @@ -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,18 +253,24 @@ 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 = () => { - this.setState({ visible: !this.state.visible }); + if (this.props.onToggleVisibility) { + this.props.onToggleVisibility(); + } else { + this.setState({ visible: !this.state.visible }); + } } handleClick = (index) => { diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js index 6f66a4260..5722d3778 100644 --- a/app/javascript/mastodon/components/status.js +++ b/app/javascript/mastodon/components/status.js @@ -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} /> )} @@ -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} /> )} @@ -348,6 +365,7 @@ class Status extends ImmutablePureComponent { moveUp: this.handleHotkeyMoveUp, moveDown: this.handleHotkeyMoveDown, toggleHidden: this.handleHotkeyToggleHidden, + toggleSensitive: this.handleHotkeyToggleSensitive, }; return ( diff --git a/app/javascript/mastodon/features/keyboard_shortcuts/index.js b/app/javascript/mastodon/features/keyboard_shortcuts/index.js index ab1ac511e..01b45652c 100644 --- a/app/javascript/mastodon/features/keyboard_shortcuts/index.js +++ b/app/javascript/mastodon/features/keyboard_shortcuts/index.js @@ -60,6 +60,10 @@ class KeyboardShortcuts extends ImmutablePureComponent { x + + h + + up, k diff --git a/app/javascript/mastodon/features/status/components/detailed_status.js b/app/javascript/mastodon/features/status/components/detailed_status.js index 059ecd979..22821af0c 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.js +++ b/app/javascript/mastodon/features/status/components/detailed_status.js @@ -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} /> ); } diff --git a/app/javascript/mastodon/features/status/index.js b/app/javascript/mastodon/features/status/index.js index 6279bb468..499afe6f7 100644 --- a/app/javascript/mastodon/features/status/index.js +++ b/app/javascript/mastodon/features/status/index.js @@ -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} /> { - 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 = () => {