From 784599d9e965682d84ea6c1fc1608c0459113d84 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 30 Apr 2019 18:09:10 +0100 Subject: [PATCH] Add primary reactions to action bar This adds the primary reactions to the action bar. They act as toggles where you can only select one from each group at a time. Note that currently we aren't actually sending the reaction at all. That's left for a separate task. Fixes https://github.com/vector-im/riot-web/issues/9576 --- res/css/views/messages/_MessageActionBar.scss | 35 ++++-- .../views/messages/MessageActionBar.js | 117 +++++++++++++++++- src/i18n/strings/en_EN.json | 2 + 3 files changed, 140 insertions(+), 14 deletions(-) diff --git a/res/css/views/messages/_MessageActionBar.scss b/res/css/views/messages/_MessageActionBar.scss index f01ef4f04f..877e1916fc 100644 --- a/res/css/views/messages/_MessageActionBar.scss +++ b/res/css/views/messages/_MessageActionBar.scss @@ -20,6 +20,7 @@ limitations under the License. cursor: pointer; display: flex; height: 24px; + line-height: 24px; border-radius: 4px; background: $message-action-bar-bg-color; top: -13px; @@ -49,21 +50,21 @@ limitations under the License. &:only-child { border-radius: 3px; } - - &::after { - content: ''; - position: absolute; - top: 0; - left: 0; - height: 100%; - width: 100%; - mask-repeat: no-repeat; - mask-position: center; - background-color: $message-action-bar-fg-color; - } } } +.mx_MessageActionBar_maskButton::after { + content: ''; + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + mask-repeat: no-repeat; + mask-position: center; + background-color: $message-action-bar-fg-color; +} + .mx_MessageActionBar_replyButton::after { mask-image: url('$(res)/img/reply.svg'); } @@ -71,3 +72,13 @@ limitations under the License. .mx_MessageActionBar_optionsButton::after { mask-image: url('$(res)/img/icon_context.svg'); } + +.mx_MessageActionBar_reactionDimension { + width: 42px; + display: flex; + justify-content: space-evenly; +} + +.mx_MessageActionBar_reactionDisabled { + opacity: 0.4; +} diff --git a/src/components/views/messages/MessageActionBar.js b/src/components/views/messages/MessageActionBar.js index 3fe3f74a9d..276a142ccb 100644 --- a/src/components/views/messages/MessageActionBar.js +++ b/src/components/views/messages/MessageActionBar.js @@ -23,6 +23,8 @@ import sdk from '../../../index'; import dis from '../../../dispatcher'; import Modal from '../../../Modal'; import { createMenu } from '../../structures/ContextualMenu'; +import SettingsStore from '../../../settings/SettingsStore'; +import classNames from 'classnames'; export default class MessageActionBar extends React.PureComponent { static propTypes = { @@ -33,6 +35,15 @@ export default class MessageActionBar extends React.PureComponent { onFocusChange: PropTypes.func, }; + constructor(props) { + super(props); + + this.state = { + agreeDimension: null, + likeDimension: null, + }; + } + onFocusChange = (focused) => { if (!this.props.onFocusChange) { return; @@ -48,6 +59,31 @@ export default class MessageActionBar extends React.PureComponent { ); } + onAgreeClick = (ev) => { + this.toggleDimensionValue("agreeDimension", "agree"); + } + + onDisagreeClick = (ev) => { + this.toggleDimensionValue("agreeDimension", "disagree"); + } + + onLikeClick = (ev) => { + this.toggleDimensionValue("likeDimension", "like"); + } + + onDislikeClick = (ev) => { + this.toggleDimensionValue("likeDimension", "dislike"); + } + + toggleDimensionValue(dimension, value) { + const state = this.state[dimension]; + const newState = state !== value ? value : null; + this.setState({ + [dimension]: newState, + }); + // TODO: Send the reaction event + } + onReplyClick = (ev) => { dis.dispatch({ action: 'reply_to_event', @@ -108,19 +144,96 @@ export default class MessageActionBar extends React.PureComponent { return false; } + isReactionsEnabled() { + return SettingsStore.isFeatureEnabled("feature_reactions"); + } + + renderAgreeDimension() { + if (!this.isReactionsEnabled()) { + return null; + } + + const state = this.state.agreeDimension; + const options = [ + { + key: "agree", + content: "👍", + onClick: this.onAgreeClick, + }, + { + key: "disagree", + content: "👎", + onClick: this.onDisagreeClick, + }, + ]; + + return + {this.renderReactionDimensionItems(state, options)} + ; + } + + renderLikeDimension() { + if (!this.isReactionsEnabled()) { + return null; + } + + const state = this.state.likeDimension; + const options = [ + { + key: "like", + content: "🙂", + onClick: this.onLikeClick, + }, + { + key: "dislike", + content: "😔", + onClick: this.onDislikeClick, + }, + ]; + + return + {this.renderReactionDimensionItems(state, options)} + ; + } + + renderReactionDimensionItems(state, options) { + return options.map(option => { + const disabled = state && state !== option.key; + const classes = classNames({ + mx_MessageActionBar_reactionDisabled: disabled, + }); + return + {option.content} + ; + }); + } + render() { + let agreeDimensionReactionButtons; + let likeDimensionReactionButtons; let replyButton; if (this.isContentActionable()) { - replyButton = ; } return
+ {agreeDimensionReactionButtons} + {likeDimensionReactionButtons} {replyButton} - diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index e18dc2761d..5cfb61d60b 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -890,6 +890,8 @@ "Today": "Today", "Yesterday": "Yesterday", "Error decrypting audio": "Error decrypting audio", + "Agree or Disagree": "Agree or Disagree", + "Like or Dislike": "Like or Dislike", "Reply": "Reply", "Options": "Options", "Attachment": "Attachment",