From b4af0140d425c03ffe2e8044edf30f1fe8326d7a Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 16 Sep 2020 12:38:47 -0600 Subject: [PATCH] Render Jitsi widget state events in a more obvious way A clear improvement to this would be to include join/leave buttons in the tiles, however this is currently deferred. --- res/css/_components.scss | 1 + .../views/messages/_MJitsiWidgetEvent.scss | 55 ++++++++++++++ src/TextForEvent.js | 4 - .../views/messages/MJitsiWidgetEvent.tsx | 74 +++++++++++++++++++ src/components/views/rooms/EventTile.js | 20 ++++- src/i18n/strings/en_EN.json | 4 + 6 files changed, 152 insertions(+), 6 deletions(-) create mode 100644 res/css/views/messages/_MJitsiWidgetEvent.scss create mode 100644 src/components/views/messages/MJitsiWidgetEvent.tsx diff --git a/res/css/_components.scss b/res/css/_components.scss index 54e7436886..26ad802955 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -139,6 +139,7 @@ @import "./views/messages/_MEmoteBody.scss"; @import "./views/messages/_MFileBody.scss"; @import "./views/messages/_MImageBody.scss"; +@import "./views/messages/_MJitsiWidgetEvent.scss"; @import "./views/messages/_MNoticeBody.scss"; @import "./views/messages/_MStickerBody.scss"; @import "./views/messages/_MTextBody.scss"; diff --git a/res/css/views/messages/_MJitsiWidgetEvent.scss b/res/css/views/messages/_MJitsiWidgetEvent.scss new file mode 100644 index 0000000000..3e51e89744 --- /dev/null +++ b/res/css/views/messages/_MJitsiWidgetEvent.scss @@ -0,0 +1,55 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +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_MJitsiWidgetEvent { + display: grid; + grid-template-columns: 24px minmax(0, 1fr) min-content; + + &::before { + grid-column: 1; + grid-row: 1 / 3; + width: 16px; + height: 16px; + content: ""; + top: 0; + bottom: 0; + left: 0; + right: 0; + mask-repeat: no-repeat; + mask-position: center; + mask-size: contain; + background-color: $composer-e2e-icon-color; // XXX: Variable abuse + margin-top: 4px; + mask-image: url('$(res)/img/element-icons/call/video-call.svg'); + } + + .mx_MJitsiWidgetEvent_title { + font-weight: 600; + font-size: $font-15px; + grid-column: 2; + grid-row: 1; + } + + .mx_MJitsiWidgetEvent_subtitle { + grid-column: 2; + grid-row: 2; + } + + .mx_MJitsiWidgetEvent_title, + .mx_MJitsiWidgetEvent_subtitle { + overflow-wrap: break-word; + } +} diff --git a/src/TextForEvent.js b/src/TextForEvent.js index a76c1f59e6..46e1878d5f 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.js @@ -476,10 +476,6 @@ function textForWidgetEvent(event) { const {name: prevName, type: prevType, url: prevUrl} = event.getPrevContent(); const {name, type, url} = event.getContent() || {}; - if (WidgetType.JITSI.matches(type) || WidgetType.JITSI.matches(prevType)) { - return textForJitsiWidgetEvent(event, senderName, url, prevUrl); - } - let widgetName = name || prevName || type || prevType || ''; // Apply sentence case to widget name if (widgetName && widgetName.length > 0) { diff --git a/src/components/views/messages/MJitsiWidgetEvent.tsx b/src/components/views/messages/MJitsiWidgetEvent.tsx new file mode 100644 index 0000000000..1bfefbff6a --- /dev/null +++ b/src/components/views/messages/MJitsiWidgetEvent.tsx @@ -0,0 +1,74 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +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 { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { _t } from "../../../languageHandler"; + +interface IProps { + mxEvent: MatrixEvent; +} + +interface IState { +} + +export default class MJitsiWidgetEvent extends React.PureComponent { + constructor(props) { + super(props); + this.state = {}; + } + + render() { + const url = this.props.mxEvent.getContent()['url']; + const prevUrl = this.props.mxEvent.getPrevContent()['url']; + const senderName = this.props.mxEvent.sender?.name || this.props.mxEvent.getSender(); + + if (!url) { + // removed + return ( +
+
+ {_t("Video conference ended by %(senderName)s", {senderName})} +
+
+ ); + } else if (prevUrl) { + // modified + return ( +
+
+ {_t("Video conference updated by %(senderName)s", {senderName})} +
+
+ {_t("Join the conference at the top of this room.")} +
+
+ ); + } else { + // assume added + return ( +
+
+ {_t("Video conference started by %(senderName)s", {senderName})} +
+
+ {_t("Join the conference at the top of this room.")} +
+
+ ); + } + } +} diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index ab9f240f2d..ef9317704d 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -34,6 +34,7 @@ import * as ObjectUtils from "../../../ObjectUtils"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import {E2E_STATE} from "./E2EIcon"; import {toRem} from "../../../utils/units"; +import {WidgetType} from "../../../widgets/WidgetType"; const eventTileTypes = { 'm.room.message': 'messages.MessageEvent', @@ -110,6 +111,19 @@ export function getHandlerTile(ev) { } } + // TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111) + if (type === "im.vector.modular.widgets") { + let type = ev.getContent()['type']; + if (!type) { + // deleted/invalid widget - try the past widget type + type = ev.getPrevContent()['type']; + } + + if (WidgetType.JITSI.matches(type)) { + return "messages.MJitsiWidgetEvent"; + } + } + return ev.isState() ? stateEventTileTypes[type] : eventTileTypes[type]; } @@ -619,16 +633,18 @@ export default class EventTile extends React.Component { const msgtype = content.msgtype; const eventType = this.props.mxEvent.getType(); + let tileHandler = getHandlerTile(this.props.mxEvent); + // Info messages are basically information about commands processed on a room const isBubbleMessage = eventType.startsWith("m.key.verification") || (eventType === "m.room.message" && msgtype && msgtype.startsWith("m.key.verification")) || - (eventType === "m.room.encryption"); + (eventType === "m.room.encryption") || + (tileHandler === "messages.MJitsiWidgetEvent"); let isInfoMessage = ( !isBubbleMessage && eventType !== 'm.room.message' && eventType !== 'm.sticker' && eventType !== 'm.room.create' ); - let tileHandler = getHandlerTile(this.props.mxEvent); // If we're showing hidden events in the timeline, we should use the // source tile when there's no regular tile for an event and also for // replace relations (which otherwise would display as a confusing diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index b2b4e01202..9d1d39477c 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1405,6 +1405,10 @@ "Invalid file%(extra)s": "Invalid file%(extra)s", "Error decrypting image": "Error decrypting image", "Show image": "Show image", + "Video conference ended by %(senderName)s": "Video conference ended by %(senderName)s", + "Video conference updated by %(senderName)s": "Video conference updated by %(senderName)s", + "Join the conference at the top of this room.": "Join the conference at the top of this room.", + "Video conference started by %(senderName)s": "Video conference started by %(senderName)s", "You have ignored this user, so their message is hidden. Show anyways.": "You have ignored this user, so their message is hidden. Show anyways.", "You verified %(name)s": "You verified %(name)s", "You cancelled verifying %(name)s": "You cancelled verifying %(name)s",