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

Commit 4e27b00

Browse files
committed
Move call buttons to the room header
This is to make some room in the composer for voice messages. The hangup behaviour is intentionally lost by this change as the VOIP UX is intended to rely on dedicated hangup buttons instead.
1 parent f1330b7 commit 4e27b00

File tree

6 files changed

+45
-134
lines changed

6 files changed

+45
-134
lines changed

res/css/views/rooms/_MessageComposer.scss

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -227,18 +227,6 @@ limitations under the License.
227227
mask-image: url('$(res)/img/element-icons/room/composer/attach.svg');
228228
}
229229

230-
.mx_MessageComposer_hangup::before {
231-
mask-image: url('$(res)/img/element-icons/call/hangup.svg');
232-
}
233-
234-
.mx_MessageComposer_voicecall::before {
235-
mask-image: url('$(res)/img/element-icons/call/voice-call.svg');
236-
}
237-
238-
.mx_MessageComposer_videocall::before {
239-
mask-image: url('$(res)/img/element-icons/call/video-call.svg');
240-
}
241-
242230
.mx_MessageComposer_emoji::before {
243231
mask-image: url('$(res)/img/element-icons/room/composer/emoji.svg');
244232
}

res/css/views/rooms/_RoomHeader.scss

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,19 @@ limitations under the License.
252252
mask-image: url('$(res)/img/element-icons/room/search-inset.svg');
253253
}
254254

255+
.mx_RoomHeader_voiceCallButton::before {
256+
mask-image: url('$(res)/img/element-icons/call/voice-call.svg');
257+
258+
// The call button SVG is padded slightly differently, so match it up to the size
259+
// of the other icons
260+
mask-size: 20px;
261+
mask-position: center;
262+
}
263+
264+
.mx_RoomHeader_videoCallButton::before {
265+
mask-image: url('$(res)/img/element-icons/call/video-call.svg');
266+
}
267+
255268
.mx_RoomHeader_showPanel {
256269
height: 16px;
257270
}

src/components/structures/RoomView.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import ResizeNotifier from '../../utils/ResizeNotifier';
3434
import ContentMessages from '../../ContentMessages';
3535
import Modal from '../../Modal';
3636
import * as sdk from '../../index';
37-
import CallHandler from '../../CallHandler';
37+
import CallHandler, { PlaceCallType } from '../../CallHandler';
3838
import dis from '../../dispatcher/dispatcher';
3939
import Tinter from '../../Tinter';
4040
import rateLimitedFunc from '../../ratelimitedfunc';
@@ -1352,6 +1352,14 @@ export default class RoomView extends React.Component<IProps, IState> {
13521352
SettingsStore.setValue("PinnedEvents.isOpen", roomId, SettingLevel.ROOM_DEVICE, nowShowingPinned);
13531353
};
13541354

1355+
private onCallPlaced = (type: PlaceCallType) => {
1356+
dis.dispatch({
1357+
action: 'place_call',
1358+
type: type,
1359+
room_id: this.state.room.roomId,
1360+
});
1361+
};
1362+
13551363
private onSettingsClick = () => {
13561364
dis.dispatch({ action: "open_room_settings" });
13571365
};
@@ -2031,6 +2039,7 @@ export default class RoomView extends React.Component<IProps, IState> {
20312039
e2eStatus={this.state.e2eStatus}
20322040
onAppsClick={this.state.hasPinnedWidgets ? this.onAppsClick : null}
20332041
appsShown={this.state.showApps}
2042+
onCallPlaced={this.onCallPlaced}
20342043
/>
20352044
<MainSplit panel={rightPanel} resizeNotifier={this.props.resizeNotifier}>
20362045
<div className="mx_RoomView_body">

src/components/views/rooms/MessageComposer.js

Lines changed: 0 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -50,97 +50,6 @@ ComposerAvatar.propTypes = {
5050
me: PropTypes.object.isRequired,
5151
};
5252

53-
function CallButton(props) {
54-
const onVoiceCallClick = (ev) => {
55-
dis.dispatch({
56-
action: 'place_call',
57-
type: PlaceCallType.Voice,
58-
room_id: props.roomId,
59-
});
60-
};
61-
62-
return (<AccessibleTooltipButton
63-
className="mx_MessageComposer_button mx_MessageComposer_voicecall"
64-
onClick={onVoiceCallClick}
65-
title={_t('Voice call')}
66-
/>);
67-
}
68-
69-
CallButton.propTypes = {
70-
roomId: PropTypes.string.isRequired,
71-
};
72-
73-
function VideoCallButton(props) {
74-
const onCallClick = (ev) => {
75-
dis.dispatch({
76-
action: 'place_call',
77-
type: ev.shiftKey ? PlaceCallType.ScreenSharing : PlaceCallType.Video,
78-
room_id: props.roomId,
79-
});
80-
};
81-
82-
return <AccessibleTooltipButton
83-
className="mx_MessageComposer_button mx_MessageComposer_videocall"
84-
onClick={onCallClick}
85-
title={_t('Video call')}
86-
/>;
87-
}
88-
89-
VideoCallButton.propTypes = {
90-
roomId: PropTypes.string.isRequired,
91-
};
92-
93-
function HangupButton(props) {
94-
const onHangupClick = () => {
95-
if (props.isConference) {
96-
dis.dispatch({
97-
action: props.canEndConference ? 'end_conference' : 'hangup_conference',
98-
room_id: props.roomId,
99-
});
100-
return;
101-
}
102-
103-
const call = CallHandler.sharedInstance().getCallForRoom(props.roomId);
104-
if (!call) {
105-
return;
106-
}
107-
108-
const action = call.state === CallState.Ringing ? 'reject' : 'hangup';
109-
110-
dis.dispatch({
111-
action,
112-
// hangup the call for this room. NB. We use the room in props as the room ID
113-
// as call.roomId may be the 'virtual room', and the dispatch actions always
114-
// use the user-facing room (there was a time when we deliberately used
115-
// call.roomId and *not* props.roomId, but that was for the old
116-
// style Freeswitch conference calls and those times are gone.)
117-
room_id: props.roomId,
118-
});
119-
};
120-
121-
let tooltip = _t("Hangup");
122-
if (props.isConference && props.canEndConference) {
123-
tooltip = _t("End conference");
124-
}
125-
126-
const canLeaveConference = !props.isConference ? true : props.isInConference;
127-
return (
128-
<AccessibleTooltipButton
129-
className="mx_MessageComposer_button mx_MessageComposer_hangup"
130-
onClick={onHangupClick}
131-
title={tooltip}
132-
disabled={!canLeaveConference}
133-
/>
134-
);
135-
}
136-
137-
HangupButton.propTypes = {
138-
roomId: PropTypes.string.isRequired,
139-
isConference: PropTypes.bool.isRequired,
140-
canEndConference: PropTypes.bool,
141-
isInConference: PropTypes.bool,
142-
};
143-
14453
const EmojiButton = ({addEmoji}) => {
14554
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu();
14655

@@ -265,7 +174,6 @@ export default class MessageComposer extends React.Component {
265174
this.state = {
266175
tombstone: this._getRoomTombstone(),
267176
canSendMessages: this.props.room.maySendMessage(),
268-
showCallButtons: SettingsStore.getValue("showCallButtonsInComposer"),
269177
hasConference: WidgetStore.instance.doesRoomHaveConference(this.props.room),
270178
joinedConference: WidgetStore.instance.isJoinedToConferenceIn(this.props.room),
271179
};
@@ -405,12 +313,7 @@ export default class MessageComposer extends React.Component {
405313
];
406314

407315
if (!this.state.tombstone && this.state.canSendMessages) {
408-
// This also currently includes the call buttons. Really we should
409-
// check separately for whether we can call, but this is slightly
410-
// complex because of conference calls.
411-
412316
const SendMessageComposer = sdk.getComponent("rooms.SendMessageComposer");
413-
const callInProgress = this.props.callState && this.props.callState !== 'ended';
414317

415318
controls.push(
416319
<SendMessageComposer
@@ -430,30 +333,6 @@ export default class MessageComposer extends React.Component {
430333
SettingsStore.getValue("MessageComposerInput.showStickersButton")) {
431334
controls.push(<Stickerpicker key="stickerpicker_controls_button" room={this.props.room} />);
432335
}
433-
434-
if (this.state.showCallButtons) {
435-
if (this.state.hasConference) {
436-
const canEndConf = WidgetUtils.canUserModifyWidgets(this.props.room.roomId);
437-
controls.push(
438-
<HangupButton
439-
key="controls_hangup"
440-
roomId={this.props.room.roomId}
441-
isConference={true}
442-
canEndConference={canEndConf}
443-
isInConference={this.state.joinedConference}
444-
/>,
445-
);
446-
} else if (callInProgress) {
447-
controls.push(
448-
<HangupButton key="controls_hangup" roomId={this.props.room.roomId} isConference={false} />,
449-
);
450-
} else {
451-
controls.push(
452-
<CallButton key="controls_call" roomId={this.props.room.roomId} />,
453-
<VideoCallButton key="controls_videocall" roomId={this.props.room.roomId} />,
454-
);
455-
}
456-
}
457336
} else if (this.state.tombstone) {
458337
const replacementRoomId = this.state.tombstone.getContent()['replacement_room'];
459338

src/components/views/rooms/RoomHeader.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {DefaultTagID} from "../../../stores/room-list/models";
3131
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
3232
import RoomTopic from "../elements/RoomTopic";
3333
import RoomName from "../elements/RoomName";
34+
import {PlaceCallType} from "../../../CallHandler";
3435

3536
export default class RoomHeader extends React.Component {
3637
static propTypes = {
@@ -45,6 +46,7 @@ export default class RoomHeader extends React.Component {
4546
e2eStatus: PropTypes.string,
4647
onAppsClick: PropTypes.func,
4748
appsShown: PropTypes.bool,
49+
onCallPlaced: PropTypes.func, // (PlaceCallType) => void;
4850
};
4951

5052
static defaultProps = {
@@ -226,8 +228,26 @@ export default class RoomHeader extends React.Component {
226228
title={_t("Search")} />;
227229
}
228230

231+
let voiceCallButton;
232+
let videoCallButton;
233+
if (this.props.inRoom && SettingsStore.getValue("showCallButtonsInComposer")) {
234+
voiceCallButton =
235+
<AccessibleTooltipButton
236+
className="mx_RoomHeader_button mx_RoomHeader_voiceCallButton"
237+
onClick={() => this.props.onCallPlaced(PlaceCallType.Voice)}
238+
title={_t("Voice call")} />;
239+
videoCallButton =
240+
<AccessibleTooltipButton
241+
className="mx_RoomHeader_button mx_RoomHeader_videoCallButton"
242+
onClick={(ev) => this.props.onCallPlaced(
243+
ev.shiftKey ? PlaceCallType.ScreenSharing : PlaceCallType.Video)}
244+
title={_t("Video call")} />;
245+
}
246+
229247
const rightRow =
230248
<div className="mx_RoomHeader_buttons">
249+
{ videoCallButton }
250+
{ voiceCallButton }
231251
{ pinnedEventsButton }
232252
{ forgetButton }
233253
{ appsButton }

src/settings/Settings.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,8 @@ export const SETTINGS: {[setting: string]: ISetting} = {
632632
default: 3000,
633633
},
634634
"showCallButtonsInComposer": {
635+
// Dev note: This is no longer "in composer" but is instead "in room header".
636+
// TODO: Rename with settings v3
635637
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
636638
default: true,
637639
controller: new UIFeatureController(UIFeature.Voip),

0 commit comments

Comments
 (0)