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

Commit e83a685

Browse files
committed
Add interactive radio component to the left panel
Signed-off-by: Robin Townsend <[email protected]>
1 parent cf2d05a commit e83a685

File tree

6 files changed

+226
-2
lines changed

6 files changed

+226
-2
lines changed

res/css/_components.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,3 +324,4 @@
324324
@import "./views/voip/_DialPadModal.scss";
325325
@import "./views/voip/_PiPContainer.scss";
326326
@import "./views/voip/_VideoFeed.scss";
327+
@import "./views/voip/_VoiceChannelRadio.scss";
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
Copyright 2022 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_VoiceChannelRadio {
18+
background-color: $system;
19+
20+
> .mx_VoiceChannelRadio_statusBar {
21+
display: flex;
22+
padding: 12px 16px;
23+
align-items: center;
24+
gap: 12px;
25+
26+
> .mx_VoiceChannelRadio_titleContainer {
27+
flex-grow: 1;
28+
29+
> .mx_VoiceChannelRadio_status {
30+
font-size: $font-15px;
31+
color: $accent;
32+
33+
&::before {
34+
content: '';
35+
display: inline-block;
36+
margin-right: 4px;
37+
width: 11px;
38+
height: 11px;
39+
background-color: $accent;
40+
mask-image: url('$(res)/img/voip/signal-bars.svg');
41+
mask-position: center;
42+
mask-size: contain;
43+
mask-repeat: no-repeat;
44+
}
45+
}
46+
47+
> .mx_VoiceChannelRadio_name {
48+
font-size: $font-13px;
49+
color: $secondary-content;
50+
}
51+
}
52+
53+
> .mx_VoiceChannelRadio_disconnectButton::before {
54+
content: '';
55+
display: block;
56+
width: 36px;
57+
height: 36px;
58+
background-color: $tertiary-content;
59+
mask-image: url('$(res)/img/element-icons/call/hangup.svg');
60+
mask-position: center;
61+
mask-size: 24px;
62+
mask-repeat: no-repeat;
63+
}
64+
}
65+
66+
> .mx_VoiceChannelRadio_controlBar {
67+
display: flex;
68+
border-top: 1px solid $quinary-content;
69+
padding: 12px 16px;
70+
align-items: center;
71+
justify-content: space-between;
72+
73+
> .mx_AccessibleButton {
74+
font-size: $font-15px;
75+
padding: 6px 0;
76+
77+
&.mx_VoiceChannelRadio_button_active {
78+
padding: 6px 12px;
79+
background-color: $quinary-content;
80+
border-radius: 8px;
81+
font-weight: 600;
82+
}
83+
}
84+
85+
> .mx_VoiceChannelRadio_videoButton::before {
86+
content: '';
87+
display: inline-block;
88+
margin-right: 8px;
89+
width: 16px;
90+
height: 16px;
91+
background-color: $primary-content;
92+
vertical-align: sub;
93+
mask-image: url('$(res)/img/voip/call-view/cam-off.svg');
94+
mask-position: center;
95+
mask-size: contain;
96+
mask-repeat: no-repeat;
97+
}
98+
99+
> .mx_VoiceChannelRadio_videoButton.mx_VoiceChannelRadio_button_active::before {
100+
mask-image: url('$(res)/img/voip/call-view/cam-on.svg');
101+
}
102+
103+
> .mx_VoiceChannelRadio_audioButton::before {
104+
content: '';
105+
display: inline-block;
106+
margin-right: 4px;
107+
width: 16px;
108+
height: 16px;
109+
background-color: $primary-content;
110+
vertical-align: sub;
111+
mask-image: url('$(res)/img/voip/call-view/mic-off.svg');
112+
mask-position: center;
113+
mask-size: contain;
114+
mask-repeat: no-repeat;
115+
}
116+
117+
> .mx_VoiceChannelRadio_audioButton.mx_VoiceChannelRadio_button_active::before {
118+
mask-image: url('$(res)/img/voip/call-view/mic-on.svg');
119+
}
120+
}
121+
}

res/img/voip/signal-bars.svg

Lines changed: 5 additions & 0 deletions
Loading

src/components/structures/LeftPanel.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import { UPDATE_EVENT } from "../../stores/AsyncStore";
4141
import IndicatorScrollbar from "./IndicatorScrollbar";
4242
import RoomBreadcrumbs from "../views/rooms/RoomBreadcrumbs";
4343
import SettingsStore from "../../settings/SettingsStore";
44+
import VoiceChannelRadio from "../views/voip/VoiceChannelRadio";
4445
import UserMenu from "./UserMenu";
4546
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
4647
import { shouldShowComponent } from "../../customisations/helpers/UIComponents";
@@ -443,6 +444,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
443444
{ roomList }
444445
</div>
445446
</div>
447+
{ SettingsStore.getValue("feature_voice_rooms") && <VoiceChannelRadio /> }
446448
</aside>
447449
</div>
448450
);
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
Copyright 2022 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, { FC, useState, useContext } from "react";
18+
import classNames from "classnames";
19+
20+
import { _t } from "../../../languageHandler";
21+
import { useEventEmitter } from "../../../hooks/useEventEmitter";
22+
import MatrixClientContext from "../../../contexts/MatrixClientContext";
23+
import VoiceChannelStore, { VoiceChannelEvent } from "../../../stores/VoiceChannelStore";
24+
import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
25+
import AccessibleButton from "../elements/AccessibleButton";
26+
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
27+
28+
const _VoiceChannelRadio: FC<{ roomId: string }> = ({ roomId }) => {
29+
const cli = useContext(MatrixClientContext);
30+
const room = cli.getRoom(roomId);
31+
const store = VoiceChannelStore.instance;
32+
33+
const [audioMuted, setAudioMuted] = useState<boolean>(store.audioMuted);
34+
const [videoMuted, setVideoMuted] = useState<boolean>(store.videoMuted);
35+
36+
useEventEmitter(store, VoiceChannelEvent.MuteAudio, () => setAudioMuted(true));
37+
useEventEmitter(store, VoiceChannelEvent.UnmuteAudio, () => setAudioMuted(false));
38+
useEventEmitter(store, VoiceChannelEvent.MuteVideo, () => setVideoMuted(true));
39+
useEventEmitter(store, VoiceChannelEvent.UnmuteVideo, () => setVideoMuted(false));
40+
41+
return <div className="mx_VoiceChannelRadio">
42+
<div className="mx_VoiceChannelRadio_statusBar">
43+
<DecoratedRoomAvatar room={room} avatarSize={36} />
44+
<div className="mx_VoiceChannelRadio_titleContainer">
45+
<div className="mx_VoiceChannelRadio_status">{ _t("Connected") }</div>
46+
<div className="mx_VoiceChannelRadio_name">{ room.name }</div>
47+
</div>
48+
<AccessibleTooltipButton
49+
className="mx_VoiceChannelRadio_disconnectButton"
50+
title={_t("Disconnect")}
51+
onClick={() => store.disconnect()}
52+
/>
53+
</div>
54+
<div className="mx_VoiceChannelRadio_controlBar">
55+
<AccessibleButton
56+
className={classNames({
57+
"mx_VoiceChannelRadio_videoButton": true,
58+
"mx_VoiceChannelRadio_button_active": !videoMuted,
59+
})}
60+
onClick={() => videoMuted ? store.unmuteVideo() : store.muteVideo()}
61+
>
62+
{ videoMuted ? _t("Video off") : _t("Video") }
63+
</AccessibleButton>
64+
<AccessibleButton
65+
className={classNames({
66+
"mx_VoiceChannelRadio_audioButton": true,
67+
"mx_VoiceChannelRadio_button_active": !audioMuted,
68+
})}
69+
onClick={() => audioMuted ? store.unmuteAudio() : store.muteAudio()}
70+
>
71+
{ audioMuted ? _t("Mic off") : _t("Mic") }
72+
</AccessibleButton>
73+
</div>
74+
</div>;
75+
};
76+
77+
const VoiceChannelRadio: FC<{}> = () => {
78+
const store = VoiceChannelStore.instance;
79+
80+
const [activeChannel, setActiveChannel] = useState<string>(VoiceChannelStore.instance.roomId);
81+
useEventEmitter(store, VoiceChannelEvent.Connect, () =>
82+
setActiveChannel(VoiceChannelStore.instance.roomId),
83+
);
84+
useEventEmitter(store, VoiceChannelEvent.Disconnect, () =>
85+
setActiveChannel(null),
86+
);
87+
88+
return activeChannel ? <_VoiceChannelRadio roomId={activeChannel} /> : null;
89+
};
90+
91+
export default VoiceChannelRadio;

src/i18n/strings/en_EN.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,12 @@
10161016
"Your camera is turned off": "Your camera is turned off",
10171017
"Your camera is still enabled": "Your camera is still enabled",
10181018
"Dial": "Dial",
1019+
"Connected": "Connected",
1020+
"Disconnect": "Disconnect",
1021+
"Video off": "Video off",
1022+
"Video": "Video",
1023+
"Mic off": "Mic off",
1024+
"Mic": "Mic",
10191025
"Dialpad": "Dialpad",
10201026
"Mute the microphone": "Mute the microphone",
10211027
"Unmute the microphone": "Unmute the microphone",
@@ -1367,7 +1373,6 @@
13671373
"The identity server you have chosen does not have any terms of service.": "The identity server you have chosen does not have any terms of service.",
13681374
"Disconnect identity server": "Disconnect identity server",
13691375
"Disconnect from the identity server <idserver />?": "Disconnect from the identity server <idserver />?",
1370-
"Disconnect": "Disconnect",
13711376
"You should <b>remove your personal data</b> from identity server <idserver /> before disconnecting. Unfortunately, identity server <idserver /> is currently offline or cannot be reached.": "You should <b>remove your personal data</b> from identity server <idserver /> before disconnecting. Unfortunately, identity server <idserver /> is currently offline or cannot be reached.",
13721377
"You should:": "You should:",
13731378
"check your browser plugins for anything that might block the identity server (such as Privacy Badger)": "check your browser plugins for anything that might block the identity server (such as Privacy Badger)",
@@ -1866,7 +1871,6 @@
18661871
"Join": "Join",
18671872
"Voice room": "Voice room",
18681873
"Connecting…": "Connecting…",
1869-
"Connected": "Connected",
18701874
"%(count)s unread messages including mentions.|other": "%(count)s unread messages including mentions.",
18711875
"%(count)s unread messages including mentions.|one": "1 unread mention.",
18721876
"%(count)s unread messages.|other": "%(count)s unread messages.",

0 commit comments

Comments
 (0)