Remove toggling reaction dimensions
This removes the v1 Reactions UX which only allowed you to choose only one emoji out of each pair. It is replaced by a different UX inside a tooltip and without these constraints. Part of https://github.com/vector-im/riot-web/issues/9753
This commit is contained in:
parent
088bbbfb91
commit
c1821fabd3
5 changed files with 0 additions and 238 deletions
|
@ -117,7 +117,6 @@
|
||||||
@import "./views/messages/_MTextBody.scss";
|
@import "./views/messages/_MTextBody.scss";
|
||||||
@import "./views/messages/_MessageActionBar.scss";
|
@import "./views/messages/_MessageActionBar.scss";
|
||||||
@import "./views/messages/_MessageTimestamp.scss";
|
@import "./views/messages/_MessageTimestamp.scss";
|
||||||
@import "./views/messages/_ReactionDimension.scss";
|
|
||||||
@import "./views/messages/_ReactionQuickTooltip.scss";
|
@import "./views/messages/_ReactionQuickTooltip.scss";
|
||||||
@import "./views/messages/_ReactionTooltipButton.scss";
|
@import "./views/messages/_ReactionTooltipButton.scss";
|
||||||
@import "./views/messages/_ReactionsRow.scss";
|
@import "./views/messages/_ReactionsRow.scss";
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2019 New Vector Ltd
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.mx_ReactionDimension {
|
|
||||||
width: 42px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-evenly;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ReactionDimension_disabled {
|
|
||||||
opacity: 0.4;
|
|
||||||
}
|
|
|
@ -146,45 +146,13 @@ export default class MessageActionBar extends React.PureComponent {
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAgreeDimension() {
|
|
||||||
if (!this.isReactionsEnabled()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ReactionDimension = sdk.getComponent('messages.ReactionDimension');
|
|
||||||
return <ReactionDimension
|
|
||||||
title={_t("Agree or Disagree")}
|
|
||||||
options={["👍", "👎"]}
|
|
||||||
reactions={this.props.reactions}
|
|
||||||
mxEvent={this.props.mxEvent}
|
|
||||||
/>;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderLikeDimension() {
|
|
||||||
if (!this.isReactionsEnabled()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ReactionDimension = sdk.getComponent('messages.ReactionDimension');
|
|
||||||
return <ReactionDimension
|
|
||||||
title={_t("Like or Dislike")}
|
|
||||||
options={["🙂", "😔"]}
|
|
||||||
reactions={this.props.reactions}
|
|
||||||
mxEvent={this.props.mxEvent}
|
|
||||||
/>;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let reactButton;
|
let reactButton;
|
||||||
let agreeDimensionReactionButtons;
|
|
||||||
let likeDimensionReactionButtons;
|
|
||||||
let replyButton;
|
let replyButton;
|
||||||
let editButton;
|
let editButton;
|
||||||
|
|
||||||
if (isContentActionable(this.props.mxEvent)) {
|
if (isContentActionable(this.props.mxEvent)) {
|
||||||
reactButton = this.renderReactButton();
|
reactButton = this.renderReactButton();
|
||||||
agreeDimensionReactionButtons = this.renderAgreeDimension();
|
|
||||||
likeDimensionReactionButtons = this.renderLikeDimension();
|
|
||||||
replyButton = <span className="mx_MessageActionBar_maskButton mx_MessageActionBar_replyButton"
|
replyButton = <span className="mx_MessageActionBar_maskButton mx_MessageActionBar_replyButton"
|
||||||
title={_t("Reply")}
|
title={_t("Reply")}
|
||||||
onClick={this.onReplyClick}
|
onClick={this.onReplyClick}
|
||||||
|
@ -199,8 +167,6 @@ export default class MessageActionBar extends React.PureComponent {
|
||||||
|
|
||||||
return <div className="mx_MessageActionBar">
|
return <div className="mx_MessageActionBar">
|
||||||
{reactButton}
|
{reactButton}
|
||||||
{agreeDimensionReactionButtons}
|
|
||||||
{likeDimensionReactionButtons}
|
|
||||||
{replyButton}
|
{replyButton}
|
||||||
{editButton}
|
{editButton}
|
||||||
<span className="mx_MessageActionBar_maskButton mx_MessageActionBar_optionsButton"
|
<span className="mx_MessageActionBar_maskButton mx_MessageActionBar_optionsButton"
|
||||||
|
|
|
@ -1,176 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2019 New Vector Ltd
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
|
||||||
|
|
||||||
export default class ReactionDimension extends React.PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
mxEvent: PropTypes.object.isRequired,
|
|
||||||
// Array of strings containing the emoji for each option
|
|
||||||
options: PropTypes.array.isRequired,
|
|
||||||
title: PropTypes.string,
|
|
||||||
// The Relations model from the JS SDK for reactions
|
|
||||||
reactions: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = this.getSelection();
|
|
||||||
|
|
||||||
if (props.reactions) {
|
|
||||||
props.reactions.on("Relations.add", this.onReactionsChange);
|
|
||||||
props.reactions.on("Relations.remove", this.onReactionsChange);
|
|
||||||
props.reactions.on("Relations.redaction", this.onReactionsChange);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
if (prevProps.reactions !== this.props.reactions) {
|
|
||||||
this.props.reactions.on("Relations.add", this.onReactionsChange);
|
|
||||||
this.props.reactions.on("Relations.remove", this.onReactionsChange);
|
|
||||||
this.props.reactions.on("Relations.redaction", this.onReactionsChange);
|
|
||||||
this.onReactionsChange();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
if (this.props.reactions) {
|
|
||||||
this.props.reactions.removeListener(
|
|
||||||
"Relations.add",
|
|
||||||
this.onReactionsChange,
|
|
||||||
);
|
|
||||||
this.props.reactions.removeListener(
|
|
||||||
"Relations.remove",
|
|
||||||
this.onReactionsChange,
|
|
||||||
);
|
|
||||||
this.props.reactions.removeListener(
|
|
||||||
"Relations.redaction",
|
|
||||||
this.onReactionsChange,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onReactionsChange = () => {
|
|
||||||
this.setState(this.getSelection());
|
|
||||||
}
|
|
||||||
|
|
||||||
getSelection() {
|
|
||||||
const myReactions = this.getMyReactions();
|
|
||||||
if (!myReactions) {
|
|
||||||
return {
|
|
||||||
selectedOption: null,
|
|
||||||
selectedReactionEvent: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const { options } = this.props;
|
|
||||||
let selectedOption = null;
|
|
||||||
let selectedReactionEvent = null;
|
|
||||||
for (const option of options) {
|
|
||||||
const reactionForOption = myReactions.find(mxEvent => {
|
|
||||||
if (mxEvent.isRedacted()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return mxEvent.getRelation().key === option;
|
|
||||||
});
|
|
||||||
if (!reactionForOption) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (selectedOption) {
|
|
||||||
// If there are multiple selected values (only expected to occur via
|
|
||||||
// non-Riot clients), then act as if none are selected.
|
|
||||||
return {
|
|
||||||
selectedOption: null,
|
|
||||||
selectedReactionEvent: null,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
selectedOption = option;
|
|
||||||
selectedReactionEvent = reactionForOption;
|
|
||||||
}
|
|
||||||
return { selectedOption, selectedReactionEvent };
|
|
||||||
}
|
|
||||||
|
|
||||||
getMyReactions() {
|
|
||||||
const reactions = this.props.reactions;
|
|
||||||
if (!reactions) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const userId = MatrixClientPeg.get().getUserId();
|
|
||||||
const myReactions = reactions.getAnnotationsBySender()[userId];
|
|
||||||
if (!myReactions) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return [...myReactions.values()];
|
|
||||||
}
|
|
||||||
|
|
||||||
onOptionClick = (ev) => {
|
|
||||||
const { key } = ev.target.dataset;
|
|
||||||
this.toggleDimension(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleDimension(key) {
|
|
||||||
const { selectedOption, selectedReactionEvent } = this.state;
|
|
||||||
const newSelectedOption = selectedOption !== key ? key : null;
|
|
||||||
this.setState({
|
|
||||||
selectedOption: newSelectedOption,
|
|
||||||
});
|
|
||||||
if (selectedReactionEvent) {
|
|
||||||
MatrixClientPeg.get().redactEvent(
|
|
||||||
this.props.mxEvent.getRoomId(),
|
|
||||||
selectedReactionEvent.getId(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (newSelectedOption) {
|
|
||||||
MatrixClientPeg.get().sendEvent(this.props.mxEvent.getRoomId(), "m.reaction", {
|
|
||||||
"m.relates_to": {
|
|
||||||
"rel_type": "m.annotation",
|
|
||||||
"event_id": this.props.mxEvent.getId(),
|
|
||||||
"key": newSelectedOption,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { selectedOption } = this.state;
|
|
||||||
const { options } = this.props;
|
|
||||||
|
|
||||||
const items = options.map(option => {
|
|
||||||
const disabled = selectedOption && selectedOption !== option;
|
|
||||||
const classes = classNames({
|
|
||||||
mx_ReactionDimension_disabled: disabled,
|
|
||||||
});
|
|
||||||
return <span key={option}
|
|
||||||
data-key={option}
|
|
||||||
className={classes}
|
|
||||||
onClick={this.onOptionClick}
|
|
||||||
>
|
|
||||||
{option}
|
|
||||||
</span>;
|
|
||||||
});
|
|
||||||
|
|
||||||
return <span className="mx_ReactionDimension"
|
|
||||||
title={this.props.title}
|
|
||||||
aria-hidden={true}
|
|
||||||
>
|
|
||||||
{items}
|
|
||||||
</span>;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -928,8 +928,6 @@
|
||||||
"Today": "Today",
|
"Today": "Today",
|
||||||
"Yesterday": "Yesterday",
|
"Yesterday": "Yesterday",
|
||||||
"Error decrypting audio": "Error decrypting audio",
|
"Error decrypting audio": "Error decrypting audio",
|
||||||
"Agree or Disagree": "Agree or Disagree",
|
|
||||||
"Like or Dislike": "Like or Dislike",
|
|
||||||
"Reply": "Reply",
|
"Reply": "Reply",
|
||||||
"Edit": "Edit",
|
"Edit": "Edit",
|
||||||
"Options": "Options",
|
"Options": "Options",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue