Improve VoIP UI/UX (#7048)

* Remove speaking indicator

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Remove mic icon for primary feed

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Remove caching as it doesn't seem to be neccessary

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Add call view buttons colors

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Refactor button code

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Update call view button icons

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* i18n

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Add dialpad icon

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Fix button sizing in PiP

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Fix secondary voice video feed color

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
This commit is contained in:
Šimon Brandner 2021-11-15 18:24:11 +01:00 committed by GitHub
parent 431098b56b
commit bafeb38472
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 247 additions and 383 deletions

View file

@ -39,6 +39,31 @@ const TOOLTIP_Y_OFFSET = -24;
const CONTROLS_HIDE_DELAY = 2000;
interface IButtonProps {
state: boolean;
className: string;
onLabel: string;
offLabel: string;
onClick: () => void;
}
const CallViewToggleButton: React.FC<IButtonProps> = ({ state: isOn, className, onLabel, offLabel, onClick }) => {
const classes = classNames("mx_CallViewButtons_button", className, {
mx_CallViewButtons_button_on: isOn,
mx_CallViewButtons_button_off: !isOn,
});
return (
<AccessibleTooltipButton
className={classes}
onClick={onClick}
title={isOn ? onLabel : offLabel}
alignment={Alignment.Top}
yOffset={TOOLTIP_Y_OFFSET}
/>
);
};
interface IProps {
call: MatrixCall;
pipMode: boolean;
@ -142,113 +167,10 @@ export default class CallViewButtons extends React.Component<IProps, IState> {
};
public render(): JSX.Element {
const micClasses = classNames("mx_CallViewButtons_button", {
mx_CallViewButtons_button_micOn: !this.props.buttonsState.micMuted,
mx_CallViewButtons_button_micOff: this.props.buttonsState.micMuted,
});
const vidClasses = classNames("mx_CallViewButtons_button", {
mx_CallViewButtons_button_vidOn: !this.props.buttonsState.vidMuted,
mx_CallViewButtons_button_vidOff: this.props.buttonsState.vidMuted,
});
const screensharingClasses = classNames("mx_CallViewButtons_button", {
mx_CallViewButtons_button_screensharingOn: this.props.buttonsState.screensharing,
mx_CallViewButtons_button_screensharingOff: !this.props.buttonsState.screensharing,
});
const sidebarButtonClasses = classNames("mx_CallViewButtons_button", {
mx_CallViewButtons_button_sidebarOn: this.props.buttonsState.sidebarShown,
mx_CallViewButtons_button_sidebarOff: !this.props.buttonsState.sidebarShown,
});
// Put the other states of the mic/video icons in the document to make sure they're cached
// (otherwise the icon disappears briefly when toggled)
const micCacheClasses = classNames("mx_CallViewButtons_button", "mx_CallViewButtons_button_invisible", {
mx_CallViewButtons_button_micOn: this.props.buttonsState.micMuted,
mx_CallViewButtons_button_micOff: !this.props.buttonsState.micMuted,
});
const vidCacheClasses = classNames("mx_CallViewButtons_button", "mx_CallViewButtons_button_invisible", {
mx_CallViewButtons_button_vidOn: this.props.buttonsState.micMuted,
mx_CallViewButtons_button_vidOff: !this.props.buttonsState.micMuted,
});
const callControlsClasses = classNames("mx_CallViewButtons", {
mx_CallViewButtons_hidden: !this.state.visible,
});
let vidMuteButton;
if (this.props.buttonsVisibility.vidMute) {
vidMuteButton = (
<AccessibleTooltipButton
className={vidClasses}
onClick={this.props.handlers.onVidMuteClick}
title={this.props.buttonsState.vidMuted ? _t("Start the camera") : _t("Stop the camera")}
alignment={Alignment.Top}
yOffset={TOOLTIP_Y_OFFSET}
/>
);
}
let screensharingButton;
if (this.props.buttonsVisibility.screensharing) {
screensharingButton = (
<AccessibleTooltipButton
className={screensharingClasses}
onClick={this.props.handlers.onScreenshareClick}
title={this.props.buttonsState.screensharing
? _t("Stop sharing your screen")
: _t("Start sharing your screen")
}
alignment={Alignment.Top}
yOffset={TOOLTIP_Y_OFFSET}
/>
);
}
let sidebarButton;
if (this.props.buttonsVisibility.sidebar) {
sidebarButton = (
<AccessibleTooltipButton
className={sidebarButtonClasses}
onClick={this.props.handlers.onToggleSidebarClick}
title={this.props.buttonsState.sidebarShown ? _t("Hide sidebar") : _t("Show sidebar")}
alignment={Alignment.Top}
yOffset={TOOLTIP_Y_OFFSET}
/>
);
}
let contextMenuButton;
if (this.props.buttonsVisibility.contextMenu) {
contextMenuButton = (
<ContextMenuTooltipButton
className="mx_CallViewButtons_button mx_CallViewButtons_button_more"
onClick={this.onMoreClick}
inputRef={this.contextMenuButton}
isExpanded={this.state.showMoreMenu}
title={_t("More")}
alignment={Alignment.Top}
yOffset={TOOLTIP_Y_OFFSET}
/>
);
}
let dialpadButton;
if (this.props.buttonsVisibility.dialpad) {
dialpadButton = (
<ContextMenuTooltipButton
className="mx_CallViewButtons_button mx_CallViewButtons_dialpad"
inputRef={this.dialpadButton}
onClick={this.onDialpadClick}
isExpanded={this.state.showDialpad}
title={_t("Dialpad")}
alignment={Alignment.Top}
yOffset={TOOLTIP_Y_OFFSET}
/>
);
}
let dialPad;
if (this.state.showDialpad) {
dialPad = <DialpadContextMenu
@ -289,20 +211,53 @@ export default class CallViewButtons extends React.Component<IProps, IState> {
>
{ dialPad }
{ contextMenu }
{ dialpadButton }
<AccessibleTooltipButton
className={micClasses}
onClick={this.props.handlers.onMicMuteClick}
title={this.props.buttonsState.micMuted ? _t("Unmute the microphone") : _t("Mute the microphone")}
{ this.props.buttonsVisibility.dialpad && <ContextMenuTooltipButton
className="mx_CallViewButtons_button mx_CallViewButtons_dialpad"
inputRef={this.dialpadButton}
onClick={this.onDialpadClick}
isExpanded={this.state.showDialpad}
title={_t("Dialpad")}
alignment={Alignment.Top}
yOffset={TOOLTIP_Y_OFFSET}
/> }
<CallViewToggleButton
state={!this.props.buttonsState.micMuted}
className="mx_CallViewButtons_button_mic"
onLabel={_t("Mute the microphone")}
offLabel={_t("Unmute the microphone")}
onClick={this.props.handlers.onMicMuteClick}
/>
{ vidMuteButton }
<div className={micCacheClasses} />
<div className={vidCacheClasses} />
{ screensharingButton }
{ sidebarButton }
{ contextMenuButton }
{ this.props.buttonsVisibility.vidMute && <CallViewToggleButton
state={!this.props.buttonsState.vidMuted}
className="mx_CallViewButtons_button_vid"
onLabel={_t("Stop the camera")}
offLabel={_t("Start the camera")}
onClick={this.props.handlers.onVidMuteClick}
/> }
{ this.props.buttonsVisibility.screensharing && <CallViewToggleButton
state={this.props.buttonsState.screensharing}
className="mx_CallViewButtons_button_screensharing"
onLabel={_t("Stop sharing your screen")}
offLabel={_t("Start sharing your screen")}
onClick={this.props.handlers.onScreenshareClick}
/> }
{ this.props.buttonsVisibility.sidebar && <CallViewToggleButton
state={this.props.buttonsState.sidebarShown}
className="mx_CallViewButtons_button_sidebar"
onLabel={_t("Hide sidebar")}
offLabel={_t("Show sidebar")}
onClick={this.props.handlers.onToggleSidebarClick}
/> }
{ this.props.buttonsVisibility.contextMenu && <ContextMenuTooltipButton
className="mx_CallViewButtons_button mx_CallViewButtons_button_more"
onClick={this.onMoreClick}
inputRef={this.contextMenuButton}
isExpanded={this.state.showMoreMenu}
title={_t("More")}
alignment={Alignment.Top}
yOffset={TOOLTIP_Y_OFFSET}
/> }
<AccessibleTooltipButton
className="mx_CallViewButtons_button mx_CallViewButtons_button_hangup"
onClick={this.props.handlers.onHangupClick}

View file

@ -45,7 +45,6 @@ interface IProps {
interface IState {
audioMuted: boolean;
videoMuted: boolean;
speaking: boolean;
}
@replaceableComponent("views.voip.VideoFeed")
@ -58,7 +57,6 @@ export default class VideoFeed extends React.PureComponent<IProps, IState> {
this.state = {
audioMuted: this.props.feed.isAudioMuted(),
videoMuted: this.props.feed.isVideoMuted(),
speaking: false,
};
}
@ -106,7 +104,6 @@ export default class VideoFeed extends React.PureComponent<IProps, IState> {
this.props.feed.removeListener(CallFeedEvent.NewStream, this.onNewStream);
this.props.feed.removeListener(CallFeedEvent.MuteStateChanged, this.onMuteStateChanged);
if (this.props.feed.purpose === SDPStreamMetadataPurpose.Usermedia) {
this.props.feed.removeListener(CallFeedEvent.Speaking, this.onSpeaking);
this.props.feed.measureVolumeActivity(false);
}
this.stopMedia();
@ -115,7 +112,6 @@ export default class VideoFeed extends React.PureComponent<IProps, IState> {
this.props.feed.addListener(CallFeedEvent.NewStream, this.onNewStream);
this.props.feed.addListener(CallFeedEvent.MuteStateChanged, this.onMuteStateChanged);
if (this.props.feed.purpose === SDPStreamMetadataPurpose.Usermedia) {
this.props.feed.addListener(CallFeedEvent.Speaking, this.onSpeaking);
this.props.feed.measureVolumeActivity(true);
}
this.playMedia();
@ -172,10 +168,6 @@ export default class VideoFeed extends React.PureComponent<IProps, IState> {
});
};
private onSpeaking = (speaking: boolean): void => {
this.setState({ speaking });
};
private onResize = (e) => {
if (this.props.onResize && !this.props.feed.isLocal()) {
this.props.onResize(e);
@ -187,7 +179,6 @@ export default class VideoFeed extends React.PureComponent<IProps, IState> {
const wrapperClasses = classnames("mx_VideoFeed", {
mx_VideoFeed_voice: this.state.videoMuted,
mx_VideoFeed_speaking: this.state.speaking,
});
const micIconClasses = classnames("mx_VideoFeed_mic", {
mx_VideoFeed_mic_muted: this.state.audioMuted,
@ -195,7 +186,11 @@ export default class VideoFeed extends React.PureComponent<IProps, IState> {
});
let micIcon;
if (feed.purpose !== SDPStreamMetadataPurpose.Screenshare && !pipMode) {
if (
feed.purpose !== SDPStreamMetadataPurpose.Screenshare &&
!primary &&
!pipMode
) {
micIcon = (
<div className={micIconClasses} />
);

View file

@ -929,16 +929,16 @@
"%(sharerName)s is presenting": "%(sharerName)s is presenting",
"Your camera is turned off": "Your camera is turned off",
"Your camera is still enabled": "Your camera is still enabled",
"Start the camera": "Start the camera",
"Dialpad": "Dialpad",
"Mute the microphone": "Mute the microphone",
"Unmute the microphone": "Unmute the microphone",
"Stop the camera": "Stop the camera",
"Start the camera": "Start the camera",
"Stop sharing your screen": "Stop sharing your screen",
"Start sharing your screen": "Start sharing your screen",
"Hide sidebar": "Hide sidebar",
"Show sidebar": "Show sidebar",
"More": "More",
"Dialpad": "Dialpad",
"Unmute the microphone": "Unmute the microphone",
"Mute the microphone": "Mute the microphone",
"Hangup": "Hangup",
"Video Call": "Video Call",
"Voice Call": "Voice Call",