From 7f8cd203a8407e074f945fc890645c3f13485650 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 21 Aug 2018 15:56:56 +0100 Subject: [PATCH 1/3] Support m.room.tombstone events For https://github.com/vector-im/riot-web/issues/7164 --- res/css/views/rooms/_MessageComposer.scss | 22 ++++++++ src/components/views/rooms/MessageComposer.js | 51 ++++++++++++++++++- src/i18n/strings/en_EN.json | 2 + 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index e84240a705..ab7d4d7b34 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright 2018 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. @@ -22,6 +23,27 @@ limitations under the License. position: relative; } +.mx_MessageComposer_replaced_wrapper { + margin-left: auto; + margin-right: auto; +} + +.mx_MessageComposer_replaced_valign { + height: 60px; + display: table-cell; + vertical-align: middle; +} + +.mx_MessageComposer_roomReplaced_icon { + float: left; + margin-right: 20px; + margin-top: 5px; +} + +.mx_MessageComposer_roomReplaced_header { + font-weight: bold; +} + .mx_MessageComposer_autocomplete_wrapper { position: relative; height: 0; diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index a7e02d16ae..cbce4cec81 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -1,6 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd -Copyright 2017 New Vector Ltd +Copyright 2017, 2018 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. @@ -25,6 +25,7 @@ import dis from '../../../dispatcher'; import RoomViewStore from '../../../stores/RoomViewStore'; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import Stickerpicker from './Stickerpicker'; +import { makeRoomPermalink } from '../../../matrix-to'; const formatButtonList = [ _td("bold"), @@ -51,7 +52,9 @@ export default class MessageComposer extends React.Component { this.onToggleMarkdownClicked = this.onToggleMarkdownClicked.bind(this); this.onInputStateChanged = this.onInputStateChanged.bind(this); this.onEvent = this.onEvent.bind(this); + this._onRoomStateEvents = this._onRoomStateEvents.bind(this); this._onRoomViewStoreUpdate = this._onRoomViewStoreUpdate.bind(this); + this._onTombstoneClick = this._onTombstoneClick.bind(this); this.state = { inputState: { @@ -61,6 +64,7 @@ export default class MessageComposer extends React.Component { }, showFormatting: SettingsStore.getValue('MessageComposer.showFormatting'), isQuoting: Boolean(RoomViewStore.getQuotingEvent()), + tombstone: this._getRoomTombstone(), }; } @@ -70,12 +74,14 @@ export default class MessageComposer extends React.Component { // marked as encrypted. // XXX: fragile as all hell - fixme somehow, perhaps with a dedicated Room.encryption event or something. MatrixClientPeg.get().on("event", this.onEvent); + MatrixClientPeg.get().on("RoomState.events", this._onRoomStateEvents); this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate); } componentWillUnmount() { if (MatrixClientPeg.get()) { MatrixClientPeg.get().removeListener("event", this.onEvent); + MatrixClientPeg.get().removeListener("RoomState.events", this._onRoomStateEvents); } if (this._roomStoreToken) { this._roomStoreToken.remove(); @@ -88,6 +94,18 @@ export default class MessageComposer extends React.Component { this.forceUpdate(); } + _onRoomStateEvents(ev, state) { + if (ev.getRoomId() !== this.props.room.roomId) return; + + if (ev.getType() === 'm.room.tombstone') { + this.setState({tombstone: this._getRoomTombstone()}); + } + } + + _getRoomTombstone() { + return this.props.room.currentState.getStateEvents('m.room.tombstone', ''); + } + _onRoomViewStoreUpdate() { const isQuoting = Boolean(RoomViewStore.getQuotingEvent()); if (this.state.isQuoting === isQuoting) return; @@ -207,6 +225,17 @@ export default class MessageComposer extends React.Component { this.messageComposerInput.enableRichtext(!this.state.inputState.isRichTextEnabled); } + _onTombstoneClick(ev) { + ev.preventDefault(); + + const replacementRoomId = this.state.tombstone.getContent()['replacement_room']; + dis.dispatch({ + action: 'view_room', + highlighted: true, + room_id: replacementRoomId, + }); + } + render() { const me = this.props.room.getMember(MatrixClientPeg.get().credentials.userId); const uploadInputStyle = {display: 'none'}; @@ -262,7 +291,7 @@ export default class MessageComposer extends React.Component { ; } - const canSendMessages = this.props.room.currentState.maySendMessage( + const canSendMessages = !this.state.tombstone && this.props.room.currentState.maySendMessage( MatrixClientPeg.get().credentials.userId); if (canSendMessages) { @@ -322,6 +351,24 @@ export default class MessageComposer extends React.Component { callButton, videoCallButton, ); + } else if (this.state.tombstone) { + const replacementRoomId = this.state.tombstone.getContent()['replacement_room']; + + const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); + controls.push(
+
+ + + {_t("This room has been replaced and is no longer active.")} +
+ + {_t("The conversation continues here.")} + +
+
); } else { controls.push(
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index fcc9bcc8be..0cf48e242e 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -393,6 +393,8 @@ "At this time it is not possible to reply with a file so this will be sent without being a reply.": "At this time it is not possible to reply with a file so this will be sent without being a reply.", "Upload Files": "Upload Files", "Are you sure you want to upload the following files?": "Are you sure you want to upload the following files?", + "This room has been replaced and is no longer active.": "This room has been replaced and is no longer active.", + "The conversation continues here.": "The conversation continues here.", "Encrypted room": "Encrypted room", "Unencrypted room": "Unencrypted room", "Hangup": "Hangup", From c54578d529fb68401395316b69f227a7e387893f Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 21 Aug 2018 17:56:28 +0100 Subject: [PATCH 2/3] Forgot the image file --- res/img/room_replaced.svg | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 res/img/room_replaced.svg diff --git a/res/img/room_replaced.svg b/res/img/room_replaced.svg new file mode 100644 index 0000000000..fa5abd1c9f --- /dev/null +++ b/res/img/room_replaced.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + From 42bb8e4ebd47e98172506e82d6954a6e1878f7a0 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 21 Aug 2018 17:57:15 +0100 Subject: [PATCH 3/3] Add image dimensions --- res/css/views/rooms/_MessageComposer.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index ab7d4d7b34..e6a532d072 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -38,6 +38,8 @@ limitations under the License. float: left; margin-right: 20px; margin-top: 5px; + width: 31px; + height: 31px; } .mx_MessageComposer_roomReplaced_header {