Hide composer and call buttons when the room is tombstoned (#7975)

This commit is contained in:
Michael Telatynski 2022-03-04 15:53:22 +00:00 committed by GitHub
parent 675b4271e9
commit 0e60ad98c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 196 additions and 93 deletions

View file

@ -187,7 +187,8 @@ export interface IRoomState {
upgradeRecommendation?: IRecommendedVersion;
canReact: boolean;
canReply: boolean;
canSendMessages: boolean;
tombstone?: MatrixEvent;
layout: Layout;
lowBandwidth: boolean;
alwaysShowTimestamps: boolean;
@ -259,7 +260,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
showTopUnreadMessagesBar: false,
statusBarVisible: false,
canReact: false,
canReply: false,
canSendMessages: false,
layout: SettingsStore.getValue("layout"),
lowBandwidth: SettingsStore.getValue("lowBandwidth"),
alwaysShowTimestamps: SettingsStore.getValue("alwaysShowTimestamps"),
@ -371,12 +372,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
: MainSplitContentType.Timeline;
};
private onReadReceiptsChange = () => {
this.setState({
showReadReceipts: SettingsStore.getValue("showReadReceipts", this.state.roomId),
});
};
private onRoomViewStoreUpdate = async (initial?: boolean): Promise<void> => {
if (this.unmounted) {
return;
@ -1033,10 +1028,15 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
this.checkWidgets(room);
this.setState({
tombstone: this.getRoomTombstone(),
liveTimeline: room.getLiveTimeline(),
});
};
private getRoomTombstone() {
return this.state.room?.currentState.getStateEvents(EventType.RoomTombstone, "");
}
private async calculateRecommendedVersion(room: Room) {
const upgradeRecommendation = await room.getRecommendedVersion();
if (this.unmounted) return;
@ -1167,17 +1167,23 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
// ignore if we don't have a room yet
if (!this.state.room || this.state.room.roomId !== state.roomId) return;
if (ev.getType() === EventType.RoomCanonicalAlias) {
// re-view the room so MatrixChat can manage the alias in the URL properly
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: this.state.room.roomId,
metricsTrigger: undefined, // room doesn't change
});
return; // this event cannot affect permissions so bail
}
switch (ev.getType()) {
case EventType.RoomCanonicalAlias:
// re-view the room so MatrixChat can manage the alias in the URL properly
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: this.state.room.roomId,
metricsTrigger: undefined, // room doesn't change
});
break;
this.updatePermissions(this.state.room);
case EventType.RoomTombstone:
this.setState({ tombstone: this.getRoomTombstone() });
break;
default:
this.updatePermissions(this.state.room);
}
};
private onRoomStateUpdate = (state: RoomState) => {
@ -1201,9 +1207,9 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
if (room) {
const me = this.context.getUserId();
const canReact = room.getMyMembership() === "join" && room.currentState.maySendEvent("m.reaction", me);
const canReply = room.maySendMessage();
const canSendMessages = room.maySendMessage();
this.setState({ canReact, canReply });
this.setState({ canReact, canSendMessages });
}
}

View file

@ -334,7 +334,7 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
// Like the resend button, the react and reply buttons need to appear before the edit.
// The only catch is we do the reply button first so that we can make sure the react
// button is the very first button without having to do length checks for `splice()`.
if (this.context.canReply) {
if (this.context.canSendMessages) {
if (this.showReplyInThreadAction) {
toolbarOpts.splice(0, 0, threadTooltipButton);
}

View file

@ -20,7 +20,6 @@ import { IEventRelation, MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Room } from "matrix-js-sdk/src/models/room";
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { EventType, RelationType } from 'matrix-js-sdk/src/@types/event';
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { Optional } from "matrix-events-sdk";
import { _t } from '../../../languageHandler';
@ -81,8 +80,6 @@ interface IProps {
}
interface IState {
tombstone: MatrixEvent;
canSendMessages: boolean;
isComposerEmpty: boolean;
haveRecording: boolean;
recordingTimeLeftSeconds?: number;
@ -114,8 +111,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
VoiceRecordingStore.instance.on(UPDATE_EVENT, this.onVoiceStoreUpdate);
this.state = {
tombstone: this.getRoomTombstone(),
canSendMessages: this.props.room.maySendMessage(),
isComposerEmpty: true,
haveRecording: false,
recordingTimeLeftSeconds: null, // when set to a number, shows a toast
@ -154,7 +149,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
public componentDidMount() {
this.dispatcherRef = dis.register(this.onAction);
MatrixClientPeg.get().on(RoomStateEvent.Events, this.onRoomStateEvents);
this.waitForOwnMember();
UIStore.instance.trackElementDimensions(`MessageComposer${this.instanceId}`, this.ref.current);
UIStore.instance.on(`MessageComposer${this.instanceId}`, this.onResize);
@ -217,9 +211,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
}
public componentWillUnmount() {
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
}
VoiceRecordingStore.instance.off(UPDATE_EVENT, this.onVoiceStoreUpdate);
dis.unregister(this.dispatcherRef);
UIStore.instance.stopTrackingElementDimensions(`MessageComposer${this.instanceId}`);
@ -229,25 +220,10 @@ export default class MessageComposer extends React.Component<IProps, IState> {
this.voiceRecording = null;
}
private onRoomStateEvents = (ev: MatrixEvent) => {
if (ev.getRoomId() !== this.props.room.roomId) return;
if (ev.getType() === EventType.RoomTombstone) {
this.setState({ tombstone: this.getRoomTombstone() });
}
if (ev.getType() === EventType.RoomPowerLevels) {
this.setState({ canSendMessages: this.props.room.maySendMessage() });
}
};
private getRoomTombstone() {
return this.props.room.currentState.getStateEvents(EventType.RoomTombstone, '');
}
private onTombstoneClick = (ev) => {
ev.preventDefault();
const replacementRoomId = this.state.tombstone.getContent()['replacement_room'];
const replacementRoomId = this.context.tombstone.getContent()['replacement_room'];
const replacementRoom = MatrixClientPeg.get().getRoom(replacementRoomId);
let createEventId = null;
if (replacementRoom) {
@ -255,7 +231,7 @@ export default class MessageComposer extends React.Component<IProps, IState> {
if (createEvent && createEvent.getId()) createEventId = createEvent.getId();
}
const viaServers = [this.state.tombstone.getSender().split(':').slice(1).join(':')];
const viaServers = [this.context.tombstone.getSender().split(':').slice(1).join(':')];
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
highlighted: true,
@ -374,7 +350,8 @@ export default class MessageComposer extends React.Component<IProps, IState> {
menuPosition = aboveLeftOf(contentRect);
}
if (!this.state.tombstone && this.state.canSendMessages) {
const canSendMessages = this.context.canSendMessages && !this.context.tombstone;
if (canSendMessages) {
controls.push(
<SendMessageComposer
ref={this.messageComposerInput}
@ -393,8 +370,8 @@ export default class MessageComposer extends React.Component<IProps, IState> {
key="controls_voice_record"
ref={this.voiceRecordingButton}
room={this.props.room} />);
} else if (this.state.tombstone) {
const replacementRoomId = this.state.tombstone.getContent()['replacement_room'];
} else if (this.context.tombstone) {
const replacementRoomId = this.context.tombstone.getContent()['replacement_room'];
const continuesLink = replacementRoomId ? (
<a href={makeRoomPermalink(replacementRoomId)}
@ -467,7 +444,7 @@ export default class MessageComposer extends React.Component<IProps, IState> {
permalinkCreator={this.props.permalinkCreator} />
<div className="mx_MessageComposer_row">
{ controls }
{ this.state.canSendMessages && <MessageComposerButtons
{ canSendMessages && <MessageComposerButtons
addEmoji={this.addEmoji}
haveRecording={this.state.haveRecording}
isMenuOpen={this.state.isMenuOpen}

View file

@ -40,6 +40,7 @@ import { contextMenuBelow } from './RoomTile';
import { RoomNotificationStateStore } from '../../../stores/notifications/RoomNotificationStateStore';
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
import { NotificationStateEvents } from '../../../stores/notifications/NotificationState';
import RoomContext from "../../../contexts/RoomContext";
export interface ISearchInfo {
searchTerm: string;
@ -73,6 +74,9 @@ export default class RoomHeader extends React.Component<IProps, IState> {
excludedRightPanelPhaseButtons: [],
};
static contextType = RoomContext;
public context!: React.ContextType<typeof RoomContext>;
constructor(props, context) {
super(props, context);
const notiStore = RoomNotificationStateStore.instance.getRoomState(props.room);
@ -200,7 +204,10 @@ export default class RoomHeader extends React.Component<IProps, IState> {
const buttons: JSX.Element[] = [];
if (this.props.inRoom && SettingsStore.getValue("showCallButtonsInComposer")) {
if (this.props.inRoom &&
!this.context.tombstone &&
SettingsStore.getValue("showCallButtonsInComposer")
) {
const voiceCallButton = <AccessibleTooltipButton
className="mx_RoomHeader_button mx_RoomHeader_voiceCallButton"
onClick={() => this.props.onCallPlaced(CallType.Voice)}