mirror of
https://github.com/vector-im/element-call.git
synced 2026-08-08 20:09:19 +00:00
fix loudspeaker confusion and icons
This commit is contained in:
@@ -23,6 +23,7 @@ import {
|
|||||||
OverflowHorizontalIcon,
|
OverflowHorizontalIcon,
|
||||||
OverflowVerticalIcon,
|
OverflowVerticalIcon,
|
||||||
VolumeOnSolidIcon,
|
VolumeOnSolidIcon,
|
||||||
|
VolumeOffSolidIcon,
|
||||||
} from "@vector-im/compound-design-tokens/assets/web/icons";
|
} from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||||
|
|
||||||
import styles from "./Button.module.css";
|
import styles from "./Button.module.css";
|
||||||
@@ -134,31 +135,25 @@ export const EndCallButton: FC<EndCallButtonProps> = ({
|
|||||||
|
|
||||||
interface LoudspeakerButtonProps extends ComponentPropsWithoutRef<"button"> {
|
interface LoudspeakerButtonProps extends ComponentPropsWithoutRef<"button"> {
|
||||||
size?: "sm" | "lg";
|
size?: "sm" | "lg";
|
||||||
/** The button will be rendered:
|
loudspeakerModeEnabled: boolean;
|
||||||
* true: currently in loudspeaker mode, pressing will switch to earpiece (rendered as enabled)
|
|
||||||
* false: currently in earpiece mode, pressing will switch to loudspeaker (rendered as disabled)
|
|
||||||
*/
|
|
||||||
isEarpieceTarget: boolean;
|
|
||||||
}
|
}
|
||||||
export const LoudspeakerButton: FC<LoudspeakerButtonProps> = ({
|
export const LoudspeakerButton: FC<LoudspeakerButtonProps> = ({
|
||||||
isEarpieceTarget,
|
loudspeakerModeEnabled,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const label = isEarpieceTarget
|
|
||||||
? t("settings.devices.handset")
|
|
||||||
: t("settings.devices.loudspeaker");
|
|
||||||
// if the target is the earpice, we are currently in loudspeaker mode.
|
// if the target is the earpice, we are currently in loudspeaker mode.
|
||||||
const enabled = isEarpieceTarget;
|
const label = loudspeakerModeEnabled
|
||||||
|
? t("settings.devices.loudspeaker")
|
||||||
|
: t("settings.devices.handset");
|
||||||
return (
|
return (
|
||||||
<Tooltip label={label}>
|
<Tooltip label={label}>
|
||||||
<CpdButton
|
<CpdButton
|
||||||
iconOnly
|
iconOnly
|
||||||
Icon={VolumeOnSolidIcon}
|
Icon={loudspeakerModeEnabled ? VolumeOnSolidIcon : VolumeOffSolidIcon}
|
||||||
{...props}
|
{...props}
|
||||||
kind={enabled ? "primary" : "secondary"}
|
kind={loudspeakerModeEnabled ? "primary" : "secondary"}
|
||||||
role="switch"
|
aria-checked={loudspeakerModeEnabled}
|
||||||
aria-checked={enabled}
|
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ export const Default: Story = {
|
|||||||
args: {
|
args: {
|
||||||
hideLogo: true,
|
hideLogo: true,
|
||||||
layoutMode: "grid",
|
layoutMode: "grid",
|
||||||
|
audioEnabled: true,
|
||||||
|
videoEnabled: true,
|
||||||
setLayoutMode: fn(),
|
setLayoutMode: fn(),
|
||||||
openSettings: fn(),
|
openSettings: fn(),
|
||||||
toggleAudio: fn(),
|
toggleAudio: fn(),
|
||||||
@@ -73,8 +75,8 @@ export const Default: Story = {
|
|||||||
mapping: {
|
mapping: {
|
||||||
NoOutputCallback: undefined,
|
NoOutputCallback: undefined,
|
||||||
// This is inverersed (speaker<->earpice) because the switcher object stores the target output, not the current one.
|
// This is inverersed (speaker<->earpice) because the switcher object stores the target output, not the current one.
|
||||||
speaker: { targetOutput: "speaker", switch: fn() },
|
speaker: { targetOutput: "earpiece", switch: fn() },
|
||||||
earpiece: { targetOutput: "earpiece", switch: fn() },
|
earpiece: { targetOutput: "speaker", switch: fn() },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
toggleScreenSharing: fnArgType,
|
toggleScreenSharing: fnArgType,
|
||||||
@@ -102,7 +104,16 @@ export const AudioVideoEnabled: Story = {
|
|||||||
videoEnabled: true,
|
videoEnabled: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
export const WithAudioOutput: Story = {
|
|
||||||
|
export const WithAudioOutputSpeaker: Story = {
|
||||||
|
...Default,
|
||||||
|
args: {
|
||||||
|
...Default.args,
|
||||||
|
audioOutputSwitcher: { targetOutput: "earpiece", switch: fn() },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WithAudioOutputEarpiece: Story = {
|
||||||
...Default,
|
...Default,
|
||||||
args: {
|
args: {
|
||||||
...Default.args,
|
...Default.args,
|
||||||
|
|||||||
@@ -35,6 +35,14 @@ export interface FooterProps {
|
|||||||
ref?: Ref<HTMLDivElement>;
|
ref?: Ref<HTMLDivElement>;
|
||||||
/** Children will only be visible if the component is wider than 5*/
|
/** Children will only be visible if the component is wider than 5*/
|
||||||
children?: JSX.Element | JSX.Element[] | false;
|
children?: JSX.Element | JSX.Element[] | false;
|
||||||
|
|
||||||
|
audioEnabled: boolean;
|
||||||
|
/** Also controls if the audioMute button is disabled */
|
||||||
|
toggleAudio: (() => void) | undefined;
|
||||||
|
videoEnabled: boolean;
|
||||||
|
/** Also controls if the videoMute button is disabled */
|
||||||
|
toggleVideo: (() => void) | undefined;
|
||||||
|
|
||||||
/* This is needed for WindowMode = "flat" */
|
/* This is needed for WindowMode = "flat" */
|
||||||
hideControls?: boolean;
|
hideControls?: boolean;
|
||||||
/** hide the entire footer*/
|
/** hide the entire footer*/
|
||||||
@@ -49,13 +57,6 @@ export interface FooterProps {
|
|||||||
/** Also controls if the layout button is visible */
|
/** Also controls if the layout button is visible */
|
||||||
setLayoutMode?: (mode: GridMode) => void;
|
setLayoutMode?: (mode: GridMode) => void;
|
||||||
|
|
||||||
audioEnabled?: boolean;
|
|
||||||
/** Also controls if the audioMute button is disabled */
|
|
||||||
toggleAudio?: () => void;
|
|
||||||
videoEnabled?: boolean;
|
|
||||||
/** Also controls if the videoMute button is disabled */
|
|
||||||
toggleVideo?: () => void;
|
|
||||||
|
|
||||||
sharingScreen?: boolean;
|
sharingScreen?: boolean;
|
||||||
toggleScreenSharing?: () => void;
|
toggleScreenSharing?: () => void;
|
||||||
|
|
||||||
@@ -175,7 +176,7 @@ export const CallFooter: FC<FooterProps> = ({
|
|||||||
<LoudspeakerButton
|
<LoudspeakerButton
|
||||||
size={buttonSize}
|
size={buttonSize}
|
||||||
onClick={() => audioOutputSwitcher.switch()}
|
onClick={() => audioOutputSwitcher.switch()}
|
||||||
isEarpieceTarget={audioOutputSwitcher.targetOutput === "earpiece"}
|
loudspeakerModeEnabled={audioOutputSwitcher.targetOutput === "earpiece"}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}, [audioOutputSwitcher, buttonSize]);
|
}, [audioOutputSwitcher, buttonSize]);
|
||||||
|
|||||||
@@ -253,9 +253,10 @@ describe("InCallView", () => {
|
|||||||
["earpiece-id", { type: "earpiece" }],
|
["earpiece-id", { type: "earpiece" }],
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
const selected$ = new BehaviorSubject<
|
const selected$ = new BehaviorSubject({
|
||||||
{ id: string; virtualEarpiece: boolean } | undefined
|
id: "speaker-id",
|
||||||
>({ id: "speaker-id", virtualEarpiece: false });
|
virtualEarpiece: false,
|
||||||
|
});
|
||||||
|
|
||||||
const mediaDevices = mockMediaDevices({
|
const mediaDevices = mockMediaDevices({
|
||||||
audioOutput: {
|
audioOutput: {
|
||||||
@@ -267,8 +268,7 @@ describe("InCallView", () => {
|
|||||||
|
|
||||||
const { getByRole } = createInCallView({ mediaDevices });
|
const { getByRole } = createInCallView({ mediaDevices });
|
||||||
// The button should be visible. When current output is "speaker",
|
// The button should be visible. When current output is "speaker",
|
||||||
// the switcher targets "earpiece", so the tooltip label is "Handset".
|
const audioOutputBtn = getByRole("button", { name: "Loudspeaker" });
|
||||||
const audioOutputBtn = getByRole("switch", { name: "Handset" });
|
|
||||||
expect(audioOutputBtn).toBeVisible();
|
expect(audioOutputBtn).toBeVisible();
|
||||||
|
|
||||||
await user.click(audioOutputBtn);
|
await user.click(audioOutputBtn);
|
||||||
|
|||||||
@@ -222,6 +222,8 @@ export const LobbyView: FC<Props> = ({
|
|||||||
{!recentsButtonInFooter && recentsButton}
|
{!recentsButtonInFooter && recentsButton}
|
||||||
</div>
|
</div>
|
||||||
<CallFooter
|
<CallFooter
|
||||||
|
audioEnabled={audioEnabled}
|
||||||
|
videoEnabled={videoEnabled}
|
||||||
toggleAudio={toggleAudio ?? undefined}
|
toggleAudio={toggleAudio ?? undefined}
|
||||||
toggleVideo={toggleVideo ?? undefined}
|
toggleVideo={toggleVideo ?? undefined}
|
||||||
openSettings={openSettings}
|
openSettings={openSettings}
|
||||||
|
|||||||
Reference in New Issue
Block a user