Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 36882b8

Browse files
authored
Merge pull request #5222 from matrix-org/travis/ft-sep1620/03-jitsi-obvious
Render Jitsi widget state events in a more obvious way
2 parents c756288 + 4295585 commit 36882b8

File tree

7 files changed

+157
-29
lines changed

7 files changed

+157
-29
lines changed

res/css/_components.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@
141141
@import "./views/messages/_MEmoteBody.scss";
142142
@import "./views/messages/_MFileBody.scss";
143143
@import "./views/messages/_MImageBody.scss";
144+
@import "./views/messages/_MJitsiWidgetEvent.scss";
144145
@import "./views/messages/_MNoticeBody.scss";
145146
@import "./views/messages/_MStickerBody.scss";
146147
@import "./views/messages/_MTextBody.scss";
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
Copyright 2020 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
.mx_MJitsiWidgetEvent {
18+
display: grid;
19+
grid-template-columns: 24px minmax(0, 1fr) min-content;
20+
21+
&::before {
22+
grid-column: 1;
23+
grid-row: 1 / 3;
24+
width: 16px;
25+
height: 16px;
26+
content: "";
27+
top: 0;
28+
bottom: 0;
29+
left: 0;
30+
right: 0;
31+
mask-repeat: no-repeat;
32+
mask-position: center;
33+
mask-size: contain;
34+
background-color: $composer-e2e-icon-color; // XXX: Variable abuse
35+
margin-top: 4px;
36+
mask-image: url('$(res)/img/element-icons/call/video-call.svg');
37+
}
38+
39+
.mx_MJitsiWidgetEvent_title {
40+
font-weight: 600;
41+
font-size: $font-15px;
42+
grid-column: 2;
43+
grid-row: 1;
44+
}
45+
46+
.mx_MJitsiWidgetEvent_subtitle {
47+
grid-column: 2;
48+
grid-row: 2;
49+
}
50+
51+
.mx_MJitsiWidgetEvent_title,
52+
.mx_MJitsiWidgetEvent_subtitle {
53+
overflow-wrap: break-word;
54+
}
55+
}

src/TextForEvent.js

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import { _t } from './languageHandler';
1818
import * as Roles from './Roles';
1919
import {isValid3pidInvite} from "./RoomInvite";
2020
import SettingsStore from "./settings/SettingsStore";
21-
import {WidgetType} from "./widgets/WidgetType";
2221
import {ALL_RULE_TYPES, ROOM_RULE_TYPES, SERVER_RULE_TYPES, USER_RULE_TYPES} from "./mjolnir/BanList";
2322

2423
function textForMemberEvent(ev) {
@@ -464,10 +463,6 @@ function textForWidgetEvent(event) {
464463
const {name: prevName, type: prevType, url: prevUrl} = event.getPrevContent();
465464
const {name, type, url} = event.getContent() || {};
466465

467-
if (WidgetType.JITSI.matches(type) || WidgetType.JITSI.matches(prevType)) {
468-
return textForJitsiWidgetEvent(event, senderName, url, prevUrl);
469-
}
470-
471466
let widgetName = name || prevName || type || prevType || '';
472467
// Apply sentence case to widget name
473468
if (widgetName && widgetName.length > 0) {
@@ -493,24 +488,6 @@ function textForWidgetEvent(event) {
493488
}
494489
}
495490

496-
function textForJitsiWidgetEvent(event, senderName, url, prevUrl) {
497-
if (url) {
498-
if (prevUrl) {
499-
return _t('Group call modified by %(senderName)s', {
500-
senderName,
501-
});
502-
} else {
503-
return _t('Group call started by %(senderName)s', {
504-
senderName,
505-
});
506-
}
507-
} else {
508-
return _t('Group call ended by %(senderName)s', {
509-
senderName,
510-
});
511-
}
512-
}
513-
514491
function textForMjolnirEvent(event) {
515492
const senderName = event.getSender();
516493
const {entity: prevEntity} = event.getPrevContent();
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
Copyright 2020 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import React from 'react';
18+
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
19+
import { _t } from "../../../languageHandler";
20+
import WidgetStore from "../../../stores/WidgetStore";
21+
22+
interface IProps {
23+
mxEvent: MatrixEvent;
24+
}
25+
26+
export default class MJitsiWidgetEvent extends React.PureComponent<IProps> {
27+
constructor(props) {
28+
super(props);
29+
}
30+
31+
render() {
32+
const url = this.props.mxEvent.getContent()['url'];
33+
const prevUrl = this.props.mxEvent.getPrevContent()['url'];
34+
const senderName = this.props.mxEvent.sender?.name || this.props.mxEvent.getSender();
35+
36+
let joinCopy = _t('Join the conference at the top of this room');
37+
if (!WidgetStore.instance.isPinned(this.props.mxEvent.getStateKey())) {
38+
joinCopy = _t('Join the conference from the room information card on the right');
39+
}
40+
41+
if (!url) {
42+
// removed
43+
return (
44+
<div className='mx_EventTile_bubble mx_MJitsiWidgetEvent'>
45+
<div className='mx_MJitsiWidgetEvent_title'>
46+
{_t('Video conference ended by %(senderName)s', {senderName})}
47+
</div>
48+
</div>
49+
);
50+
} else if (prevUrl) {
51+
// modified
52+
return (
53+
<div className='mx_EventTile_bubble mx_MJitsiWidgetEvent'>
54+
<div className='mx_MJitsiWidgetEvent_title'>
55+
{_t('Video conference updated by %(senderName)s', {senderName})}
56+
</div>
57+
<div className='mx_MJitsiWidgetEvent_subtitle'>
58+
{joinCopy}
59+
</div>
60+
</div>
61+
);
62+
} else {
63+
// assume added
64+
return (
65+
<div className='mx_EventTile_bubble mx_MJitsiWidgetEvent'>
66+
<div className='mx_MJitsiWidgetEvent_title'>
67+
{_t("Video conference started by %(senderName)s", {senderName})}
68+
</div>
69+
<div className='mx_MJitsiWidgetEvent_subtitle'>
70+
{joinCopy}
71+
</div>
72+
</div>
73+
);
74+
}
75+
}
76+
}

src/components/views/rooms/EventTile.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import * as ObjectUtils from "../../../ObjectUtils";
3434
import MatrixClientContext from "../../../contexts/MatrixClientContext";
3535
import {E2E_STATE} from "./E2EIcon";
3636
import {toRem} from "../../../utils/units";
37+
import {WidgetType} from "../../../widgets/WidgetType";
3738
import RoomAvatar from "../avatars/RoomAvatar";
3839

3940
const eventTileTypes = {
@@ -111,6 +112,19 @@ export function getHandlerTile(ev) {
111112
}
112113
}
113114

115+
// TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
116+
if (type === "im.vector.modular.widgets") {
117+
let type = ev.getContent()['type'];
118+
if (!type) {
119+
// deleted/invalid widget - try the past widget type
120+
type = ev.getPrevContent()['type'];
121+
}
122+
123+
if (WidgetType.JITSI.matches(type)) {
124+
return "messages.MJitsiWidgetEvent";
125+
}
126+
}
127+
114128
return ev.isState() ? stateEventTileTypes[type] : eventTileTypes[type];
115129
}
116130

@@ -627,16 +641,18 @@ export default class EventTile extends React.Component {
627641
const msgtype = content.msgtype;
628642
const eventType = this.props.mxEvent.getType();
629643

644+
let tileHandler = getHandlerTile(this.props.mxEvent);
645+
630646
// Info messages are basically information about commands processed on a room
631647
const isBubbleMessage = eventType.startsWith("m.key.verification") ||
632648
(eventType === "m.room.message" && msgtype && msgtype.startsWith("m.key.verification")) ||
633-
(eventType === "m.room.encryption");
649+
(eventType === "m.room.encryption") ||
650+
(tileHandler === "messages.MJitsiWidgetEvent");
634651
let isInfoMessage = (
635652
!isBubbleMessage && eventType !== 'm.room.message' &&
636653
eventType !== 'm.sticker' && eventType !== 'm.room.create'
637654
);
638655

639-
let tileHandler = getHandlerTile(this.props.mxEvent);
640656
// If we're showing hidden events in the timeline, we should use the
641657
// source tile when there's no regular tile for an event and also for
642658
// replace relations (which otherwise would display as a confusing

src/i18n/strings/en_EN.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,9 +277,6 @@
277277
"%(widgetName)s widget modified by %(senderName)s": "%(widgetName)s widget modified by %(senderName)s",
278278
"%(widgetName)s widget added by %(senderName)s": "%(widgetName)s widget added by %(senderName)s",
279279
"%(widgetName)s widget removed by %(senderName)s": "%(widgetName)s widget removed by %(senderName)s",
280-
"Group call modified by %(senderName)s": "Group call modified by %(senderName)s",
281-
"Group call started by %(senderName)s": "Group call started by %(senderName)s",
282-
"Group call ended by %(senderName)s": "Group call ended by %(senderName)s",
283280
"%(senderName)s removed the rule banning users matching %(glob)s": "%(senderName)s removed the rule banning users matching %(glob)s",
284281
"%(senderName)s removed the rule banning rooms matching %(glob)s": "%(senderName)s removed the rule banning rooms matching %(glob)s",
285282
"%(senderName)s removed the rule banning servers matching %(glob)s": "%(senderName)s removed the rule banning servers matching %(glob)s",
@@ -1393,6 +1390,11 @@
13931390
"Invalid file%(extra)s": "Invalid file%(extra)s",
13941391
"Error decrypting image": "Error decrypting image",
13951392
"Show image": "Show image",
1393+
"Join the conference at the top of this room": "Join the conference at the top of this room",
1394+
"Join the conference from the room information card on the right": "Join the conference from the room information card on the right",
1395+
"Video conference ended by %(senderName)s": "Video conference ended by %(senderName)s",
1396+
"Video conference updated by %(senderName)s": "Video conference updated by %(senderName)s",
1397+
"Video conference started by %(senderName)s": "Video conference started by %(senderName)s",
13961398
"You have ignored this user, so their message is hidden. <a>Show anyways.</a>": "You have ignored this user, so their message is hidden. <a>Show anyways.</a>",
13971399
"You verified %(name)s": "You verified %(name)s",
13981400
"You cancelled verifying %(name)s": "You cancelled verifying %(name)s",

src/stores/WidgetStore.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ export default class WidgetStore extends AsyncStoreWithClient<IState> {
158158

159159
let pinned = roomInfo && roomInfo.pinned[widgetId];
160160
// Jitsi widgets should be pinned by default
161-
if (pinned === undefined && WidgetType.JITSI.matches(this.widgetMap.get(widgetId).type)) pinned = true;
161+
const widget = this.widgetMap.get(widgetId);
162+
if (pinned === undefined && WidgetType.JITSI.matches(widget?.type)) pinned = true;
162163
return pinned;
163164
}
164165

0 commit comments

Comments
 (0)