This commit is contained in:
Timo K
2026-05-15 18:37:25 +02:00
parent e10bc6c7cf
commit 88f660e43f
12 changed files with 192 additions and 118 deletions

View File

@@ -200,7 +200,7 @@ describe("InCallView", () => {
it("mobile landscape, is accessible when showHeader is false", () => {
// windowSize with height <= 600 results in "flat" windowMode,
// which means showHeader$ emits false.
const { getAllByRole, queryAllByRole, vm } = createInCallView({
const { getAllByRole, getByRole, getByTestId, vm } = createInCallView({
withAppBar: true,
callViewModelOptions: {
// Set windowMode$ to "flat" (height <= 600)
@@ -210,7 +210,12 @@ describe("InCallView", () => {
// In flat (landscape) mode the footer starts hidden until the user
// taps the screen, so no settings button should be accessible yet.
expect(queryAllByRole("button", { name: "Settings" })).toHaveLength(0);
expect(getByTestId("footer-container")).not.toBeVisible();
const buttons = getAllByRole("button", { name: "Settings" });
for (const b of buttons) {
expect(b).not.toBeVisible();
}
// Simulate a touch tap on the call view to reveal the footer.
// (PointerEvent is not available in JSDOM, so we call tapScreen() directly,
@@ -219,17 +224,15 @@ describe("InCallView", () => {
// When showHeader is false, hideSettingsButton is false,
// so the settings button is visible in the footer.
const settingsBtn = getAllByRole("button", { name: "Settings" });
// here we check for two settings buttons because there are two buttons in the bottom bar. One for the
const settingsBtn = getByRole("button", { name: "Settings" });
// There are two buttons in the bottom bar. One for the
// the narrow layout and another one for the wide layout.
// Their visibility uses @media css queries, which cannot be tested in JSDOM,
// but we can at least check that both buttons are rendered and have the correct classes.
expect(settingsBtn.length).toBe(2);
expect(settingsBtn[0]).toHaveAttribute(
// Their visibility uses @media css queries, which we can test JSDOM (see `test.css.include` vitest config).
expect(settingsBtn).toHaveAttribute(
"data-testid",
"settings-bottom-left",
);
expect(settingsBtn[0]).toBeVisible();
expect(settingsBtn).toBeVisible();
});
it("mobile portrait, is accessible when showHeader is true", () => {

View File

@@ -237,7 +237,8 @@ export const InCallView: FC<InCallViewProps> = ({
const windowMode = useBehavior(vm.windowMode$);
const layout = useBehavior(vm.layout$);
const showHeader = useBehavior(vm.showHeader$);
const showFooter = useBehavior(vm.showFooter$);
const settingsOpen = useBehavior(vm.settingsOpen$);
const setSettingsOpen = useBehavior(vm.setSettingsOpen$);
const earpieceMode = useBehavior(vm.earpieceMode$);
const audioOutputSwitcher = useBehavior(vm.audioOutputSwitcher$);
@@ -284,28 +285,18 @@ export const InCallView: FC<InCallViewProps> = ({
);
const onPointerOut = useCallback(() => vm.unhoverScreen(), [vm]);
const [settingsModalOpen, setSettingsModalOpen] = useState(false);
const [settingsTab, setSettingsTab] = useState(defaultSettingsTab);
const openSettings = useCallback(
() => setSettingsModalOpen(true),
[setSettingsModalOpen],
);
const closeSettings = useCallback(
() => setSettingsModalOpen(false),
[setSettingsModalOpen],
);
const openProfile = useMemo(
() =>
// Profile settings are unavailable in widget mode
widget === null
? (): void => {
setSettingsTab("profile");
setSettingsModalOpen(true);
setSettingsOpen(true);
}
: null,
[setSettingsTab, setSettingsModalOpen],
[setSettingsTab, setSettingsOpen],
);
const [headerRef, headerBounds] = useMeasure();
@@ -555,7 +546,6 @@ export const InCallView: FC<InCallViewProps> = ({
vm,
muteStates,
mediaDevices,
openSettings,
supportsReactions
? `${client.getUserId()}:${client.getDeviceId()}`
: undefined,
@@ -564,19 +554,19 @@ export const InCallView: FC<InCallViewProps> = ({
return (): void => {
footerScope.end();
};
}, [client, mediaDevices, muteStates, openSettings, supportsReactions, vm]);
}, [client, mediaDevices, muteStates, supportsReactions, vm]);
useAppBarSecondaryButton(
<SettingsIconButton
key="settings"
onClick={openSettings}
onClick={() => setSettingsOpen(true)}
data-testid="settings-app-bar"
/>,
);
// Only hide the settings button if we have an AppBar header and we are showing the header
const footer = footerVm !== null && (
<>{showFooter && <CallFooter ref={footerRef} vm={footerVm} />}</>
<CallFooter ref={footerRef} vm={footerVm} />
);
const allConnections = useBehavior(vm.allConnections$);
@@ -614,8 +604,8 @@ export const InCallView: FC<InCallViewProps> = ({
<SettingsModal
client={client}
roomId={matrixRoom.roomId}
open={settingsModalOpen}
onDismiss={closeSettings}
open={settingsOpen}
onDismiss={(): void => setSettingsOpen(false)}
tab={settingsTab}
onTabChange={setSettingsTab}
livekitRooms={allConnections