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

Tooltip: improve accessibility for call and voice messages #12489

Merged
merged 5 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions src/components/views/audio_messages/PlayPauseButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,11 @@ limitations under the License.
import React, { ComponentProps, ReactNode } from "react";
import classNames from "classnames";

import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
import { _t } from "../../../languageHandler";
import { Playback, PlaybackState } from "../../../audio/Playback";
import AccessibleButton from "../elements/AccessibleButton";

type Props = Omit<
ComponentProps<typeof AccessibleTooltipButton>,
"title" | "onClick" | "disabled" | "element" | "ref"
> & {
type Props = Omit<ComponentProps<typeof AccessibleButton>, "title" | "onClick" | "disabled" | "element" | "ref"> & {
// Playback instance to manipulate. Cannot change during the component lifecycle.
playback: Playback;

Expand Down Expand Up @@ -61,7 +58,7 @@ export default class PlayPauseButton extends React.PureComponent<Props> {
});

return (
<AccessibleTooltipButton
<AccessibleButton
data-testid="play-pause-button"
className={classes}
title={isPlaying ? _t("action|pause") : _t("action|play")}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ import React, { ComponentProps, createRef, useState, forwardRef } from "react";
import classNames from "classnames";
import { MatrixCall } from "matrix-js-sdk/src/webrtc/call";

import AccessibleTooltipButton from "../../elements/AccessibleTooltipButton";
import LegacyCallContextMenu from "../../context_menus/LegacyCallContextMenu";
import DialpadContextMenu from "../../context_menus/DialpadContextMenu";
import { Alignment } from "../../elements/Tooltip";
import {
alwaysMenuProps,
alwaysAboveRightOf,
Expand All @@ -34,37 +32,42 @@ import {
import { _t } from "../../../../languageHandler";
import DeviceContextMenu from "../../context_menus/DeviceContextMenu";
import { MediaDeviceKindEnum } from "../../../../MediaDeviceHandler";
import { ButtonEvent } from "../../elements/AccessibleButton";
import AccessibleButton, { ButtonEvent } from "../../elements/AccessibleButton";

// Height of the header duplicated from CSS because we need to subtract it from our max
// height to get the max height of the video
const CONTEXT_MENU_VPADDING = 8; // How far the context menu sits above the button (px)

const CONTROLS_HIDE_DELAY = 2000;

type ButtonProps = Omit<ComponentProps<typeof AccessibleTooltipButton>, "title" | "element"> & {
type ButtonProps = Omit<ComponentProps<typeof AccessibleButton>, "title" | "element"> & {
state: boolean;
onLabel?: string;
offLabel?: string;
forceHide?: boolean;
onHover?: (hovering: boolean) => void;
};

const LegacyCallViewToggleButton = forwardRef<HTMLElement, ButtonProps>(
({ children, state: isOn, className, onLabel, offLabel, ...props }, ref) => {
({ children, state: isOn, className, onLabel, offLabel, forceHide, onHover, ...props }, ref) => {
const classes = classNames("mx_LegacyCallViewButtons_button", className, {
mx_LegacyCallViewButtons_button_on: isOn,
mx_LegacyCallViewButtons_button_off: !isOn,
});

const title = forceHide ? undefined : isOn ? onLabel : offLabel;

return (
<AccessibleTooltipButton
<AccessibleButton
ref={ref}
className={classes}
title={isOn ? onLabel : offLabel}
alignment={Alignment.Top}
title={title}
placement="top"
onTooltipOpenChange={onHover}
{...props}
>
{children}
</AccessibleTooltipButton>
</AccessibleButton>
);
},
);
Expand Down Expand Up @@ -265,7 +268,7 @@ export default class LegacyCallViewButtons extends React.Component<IProps, IStat
onClick={this.onDialpadClick}
isExpanded={this.state.showDialpad}
title={_t("voip|dialpad")}
alignment={Alignment.Top}
placement="top"
/>
)}
<LegacyCallViewDropdownButton
Expand Down Expand Up @@ -311,14 +314,14 @@ export default class LegacyCallViewButtons extends React.Component<IProps, IStat
ref={this.contextMenuButton}
isExpanded={this.state.showMoreMenu}
title={_t("voip|more_button")}
alignment={Alignment.Top}
placement="top"
/>
)}
<AccessibleTooltipButton
<AccessibleButton
className="mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button_hangup"
onClick={this.props.handlers.onHangupClick}
title={_t("voip|hangup")}
alignment={Alignment.Top}
placement="top"
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import React from "react";

import { _t } from "../../../../languageHandler";
import RoomAvatar from "../../avatars/RoomAvatar";
import AccessibleTooltipButton from "../../elements/AccessibleTooltipButton";
import AccessibleButton from "../../elements/AccessibleButton";

interface LegacyCallControlsProps {
onExpand?: () => void;
Expand All @@ -31,21 +31,21 @@ const LegacyCallViewHeaderControls: React.FC<LegacyCallControlsProps> = ({ onExp
return (
<div className="mx_LegacyCallViewHeader_controls">
{onMaximize && (
<AccessibleTooltipButton
<AccessibleButton
className="mx_LegacyCallViewHeader_button mx_LegacyCallViewHeader_button_fullscreen"
onClick={onMaximize}
title={_t("voip|maximise")}
/>
)}
{onPin && (
<AccessibleTooltipButton
<AccessibleButton
className="mx_LegacyCallViewHeader_button mx_LegacyCallViewHeader_button_pin"
onClick={onPin}
title={_t("action|pin")}
/>
)}
{onExpand && (
<AccessibleTooltipButton
<AccessibleButton
className="mx_LegacyCallViewHeader_button mx_LegacyCallViewHeader_button_expand"
onClick={onExpand}
title={_t("voip|expand")}
Expand Down
5 changes: 2 additions & 3 deletions src/toasts/IncomingCallToast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,12 @@ import {
LiveContentType,
} from "../components/views/rooms/LiveContentSummary";
import { useCall, useJoinCallButtonDisabledTooltip } from "../hooks/useCall";
import { ButtonEvent } from "../components/views/elements/AccessibleButton";
import AccessibleButton, { ButtonEvent } from "../components/views/elements/AccessibleButton";
import { useDispatcher } from "../hooks/useDispatcher";
import { ActionPayload } from "../dispatcher/payloads";
import { Call } from "../models/Call";
import { AudioID } from "../LegacyCallHandler";
import { useEventEmitter, useTypedEventEmitter } from "../hooks/useEventEmitter";
import AccessibleTooltipButton from "../components/views/elements/AccessibleTooltipButton";
import { CallStore, CallStoreEvent } from "../stores/CallStore";

export const getIncomingCallToastKey = (callId: string, roomId: string): string => `call_${callId}_${roomId}`;
Expand Down Expand Up @@ -195,7 +194,7 @@ export function IncomingCallToast({ notifyEvent }: Props): JSX.Element {
disabledTooltip={otherCallIsOngoing ? "Ongoing call" : undefined}
/>
</div>
<AccessibleTooltipButton
<AccessibleButton
className="mx_IncomingCallToast_closeButton"
onClick={onCloseClick}
title={_t("action|close")}
Expand Down
3 changes: 1 addition & 2 deletions src/toasts/IncomingLegacyCallToast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import LegacyCallHandler, { LegacyCallHandlerEvent } from "../LegacyCallHandler"
import { MatrixClientPeg } from "../MatrixClientPeg";
import { _t } from "../languageHandler";
import RoomAvatar from "../components/views/avatars/RoomAvatar";
import AccessibleTooltipButton from "../components/views/elements/AccessibleTooltipButton";
import AccessibleButton, { ButtonEvent } from "../components/views/elements/AccessibleButton";

export const getIncomingLegacyCallToastKey = (callId: string): string => `call_${callId}`;
Expand Down Expand Up @@ -136,7 +135,7 @@ export default class IncomingLegacyCallToast extends React.Component<IProps, ISt
</AccessibleButton>
</div>
</div>
<AccessibleTooltipButton
<AccessibleButton
className={silenceClass}
disabled={callForcedSilent}
onClick={this.onSilenceClick}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import Spinner from "../../../components/views/elements/Spinner";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import { Action } from "../../../dispatcher/actions";
import dis from "../../../dispatcher/dispatcher";
import AccessibleTooltipButton from "../../../components/views/elements/AccessibleTooltipButton";

interface VoiceBroadcastHeaderProps {
linkToRoom?: boolean;
Expand Down Expand Up @@ -95,14 +94,14 @@ export const VoiceBroadcastHeader: React.FC<VoiceBroadcastHeaderProps> = ({
});

const microphoneLine = microphoneLabel && (
<AccessibleTooltipButton
<AccessibleButton
className={microphoneLineClasses}
onClick={onMicrophoneLineClick}
title={_t("voip|change_input_device")}
>
<MicrophoneIcon className="mx_Icon mx_Icon_16" />
<span>{microphoneLabel}</span>
</AccessibleTooltipButton>
</AccessibleButton>
);

const onRoomAvatarOrNameClick = (): void => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { Icon as MicrophoneIcon } from "../../../../res/img/compound/mic-16px.sv
import { _t } from "../../../languageHandler";
import { useAudioDeviceSelection } from "../../../hooks/useAudioDeviceSelection";
import { DevicesContextMenu } from "../../../components/views/audio_messages/DevicesContextMenu";
import AccessibleTooltipButton from "../../../components/views/elements/AccessibleTooltipButton";
import AccessibleButton from "../../../components/views/elements/AccessibleButton";

interface VoiceBroadcastRecordingPipProps {
recording: VoiceBroadcastRecording;
Expand Down Expand Up @@ -92,12 +92,12 @@ export const VoiceBroadcastRecordingPip: React.FC<VoiceBroadcastRecordingPipProp
) : (
<div className="mx_VoiceBroadcastBody_controls">
{toggleControl}
<AccessibleTooltipButton
<AccessibleButton
onClick={(): void => setShowDeviceSelect(true)}
title={_t("voip|change_input_device")}
>
<MicrophoneIcon className="mx_Icon mx_Icon_16 mx_Icon_alert" />
</AccessibleTooltipButton>
</AccessibleButton>
<VoiceBroadcastControl
icon={<StopIcon className="mx_Icon mx_Icon_16" />}
label="Stop Recording"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
*
* Copyright 2024 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 { render } from "@testing-library/react";
import { MatrixCall } from "matrix-js-sdk/src/webrtc/call";

import LegacyCallViewButtons from "../../../../../src/components/views/voip/LegacyCallView/LegacyCallViewButtons";
import { createTestClient } from "../../../../test-utils";

describe("LegacyCallViewButtons", () => {
const matrixClient = createTestClient();
const roomId = "test-room-id";

const renderButtons = () => {
const call = new MatrixCall({
client: matrixClient,
roomId,
});

return render(
<LegacyCallViewButtons
call={call}
handlers={{
onScreenshareClick: jest.fn(),
onToggleSidebarClick: jest.fn(),
onHangupClick: jest.fn(),
onMicMuteClick: jest.fn(),
onVidMuteClick: jest.fn(),
}}
buttonsVisibility={{
vidMute: true,
screensharing: true,
sidebar: true,
contextMenu: true,
dialpad: true,
}}
buttonsState={{
micMuted: false,
vidMuted: false,
sidebarShown: false,
screensharing: false,
}}
/>,
);
};

it("should render the buttons", () => {
const { container } = renderButtons();
expect(container).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`LegacyCallViewButtons should render the buttons 1`] = `
<div>
<div
class="mx_LegacyCallViewButtons"
>
<div
aria-expanded="false"
aria-haspopup="true"
aria-label="Dialpad"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_dialpad"
role="button"
tabindex="0"
/>
<div
aria-label="Mute microphone"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button_mic mx_LegacyCallViewButtons_button_on"
role="button"
tabindex="0"
>
<div
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_dropdownButton mx_LegacyCallViewButtons_dropdownButton_collapsed mx_LegacyCallViewButtons_button_on"
role="button"
tabindex="0"
/>
</div>
<div
aria-label="Turn off camera"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button_vid mx_LegacyCallViewButtons_button_on"
role="button"
tabindex="0"
>
<div
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_dropdownButton mx_LegacyCallViewButtons_dropdownButton_collapsed mx_LegacyCallViewButtons_button_on"
role="button"
tabindex="0"
/>
</div>
<div
aria-label="Start sharing your screen"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button_screensharing mx_LegacyCallViewButtons_button_off"
role="button"
tabindex="0"
/>
<div
aria-label="Show sidebar"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button_sidebar mx_LegacyCallViewButtons_button_off"
role="button"
tabindex="0"
/>
<div
aria-expanded="false"
aria-haspopup="true"
aria-label="More"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button_more"
role="button"
tabindex="0"
/>
<div
aria-label="Hangup"
class="mx_AccessibleButton mx_LegacyCallViewButtons_button mx_LegacyCallViewButtons_button_hangup"
role="button"
tabindex="0"
/>
</div>
</div>
`;
1 change: 1 addition & 0 deletions test/test-utils/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ export function createTestClient(): MatrixClient {
getMediaConfig: jest.fn(),
baseUrl: "https://matrix-client.matrix.org",
matrixRTC: createStubMatrixRTC(),
isFallbackICEServerAllowed: jest.fn().mockReturnValue(false),
} as unknown as MatrixClient;

client.reEmitter = new ReEmitter(client);
Expand Down
Loading