mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-07-08 22:34:04 +01:00
Improve call screen header buttons and context menu
This commit is contained in:
@@ -4161,25 +4161,6 @@ button.module-image__border-overlay:focus {
|
||||
}
|
||||
}
|
||||
|
||||
.module-calling-tools {
|
||||
position: absolute;
|
||||
top: calc(32px + var(--title-bar-drag-area-height));
|
||||
inset-inline-end: 0;
|
||||
display: flex;
|
||||
|
||||
&__button {
|
||||
margin-inline-end: 12px;
|
||||
}
|
||||
|
||||
&__button:last-child {
|
||||
margin-inline-end: 24px;
|
||||
}
|
||||
.ContextMenu__container {
|
||||
background: none;
|
||||
text-wrap: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.module-calling-pip {
|
||||
backface-visibility: hidden;
|
||||
background-color: variables.$color-gray-95;
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
// Copyright 2023 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
@use '../mixins';
|
||||
@use '../variables';
|
||||
|
||||
@mixin CallSettingsButton-icon($path) {
|
||||
@include mixins.color-svg($path, variables.$color-gray-15);
|
||||
}
|
||||
|
||||
.CallSettingsButton__Button {
|
||||
align-items: center;
|
||||
background-color: variables.$color-gray-78;
|
||||
border: none;
|
||||
border-radius: 40px;
|
||||
display: flex;
|
||||
height: 36px;
|
||||
justify-content: center;
|
||||
outline: none;
|
||||
width: 36px;
|
||||
|
||||
@include mixins.keyboard-mode {
|
||||
&:focus {
|
||||
outline-offset: 1px;
|
||||
outline: 2px solid variables.$color-ultramarine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.CallSettingsButton__Icon {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.CallSettingsButton__Icon--Cancel {
|
||||
@include CallSettingsButton-icon('../images/icons/v3/x/x.svg');
|
||||
}
|
||||
|
||||
.CallSettingsButton__Icon--SidebarView {
|
||||
@include CallSettingsButton-icon(
|
||||
'../images/icons/v3/sidebar_view/sidebar_view.svg'
|
||||
);
|
||||
}
|
||||
|
||||
.CallSettingsButton__Icon--PaginatedView {
|
||||
@include CallSettingsButton-icon('../images/icons/v3/grid/grid.svg');
|
||||
}
|
||||
|
||||
.CallSettingsButton__Icon--Pip {
|
||||
@include CallSettingsButton-icon('../images/icons/v3/pip/pip.svg');
|
||||
}
|
||||
|
||||
.CallSettingsButton__Icon--Settings {
|
||||
@include CallSettingsButton-icon('../images/icons/v3/settings/settings.svg');
|
||||
}
|
||||
|
||||
.CallSettingsButton__Icon--SpeakerView {
|
||||
@include CallSettingsButton-icon(
|
||||
'../images/icons/v3/speaker_view/speaker_view.svg'
|
||||
);
|
||||
}
|
||||
@@ -66,13 +66,3 @@
|
||||
transform: translateY(-100%);
|
||||
inset-inline-start: 0;
|
||||
}
|
||||
|
||||
.CallingToast__viewChanged {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
&__icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,6 @@ $is-storybook: false !default;
|
||||
@use 'components/CallingStatusIndicator.scss';
|
||||
@use 'components/CallingButton.scss';
|
||||
@use 'components/CallControls.scss';
|
||||
@use 'components/CallSettingsButton.scss';
|
||||
@use 'components/CallingLobby.scss';
|
||||
@use 'components/CallingPendingParticipants.scss';
|
||||
@use 'components/CallingPreCallInfo.scss';
|
||||
|
||||
@@ -449,14 +449,16 @@ export namespace AxoDropdownMenu {
|
||||
>
|
||||
<AxoBaseMenu.ItemLeadingSlot>
|
||||
<AxoBaseMenu.ItemCheckPlaceholder>
|
||||
<DropdownMenu.ItemIndicator>
|
||||
<DropdownMenu.ItemIndicator
|
||||
className={tw('inline-flex items-center')}
|
||||
>
|
||||
<AxoBaseMenu.ItemCheck />
|
||||
</DropdownMenu.ItemIndicator>
|
||||
</AxoBaseMenu.ItemCheckPlaceholder>
|
||||
</AxoBaseMenu.ItemLeadingSlot>
|
||||
<AxoBaseMenu.ItemContentSlot>
|
||||
{props.symbol && (
|
||||
<span className={tw('me-2')}>
|
||||
<span className={tw('me-2 inline-flex items-center')}>
|
||||
<AxoBaseMenu.ItemSymbol symbol={props.symbol} />
|
||||
</span>
|
||||
)}
|
||||
@@ -518,14 +520,16 @@ export namespace AxoDropdownMenu {
|
||||
>
|
||||
<AxoBaseMenu.ItemLeadingSlot>
|
||||
<AxoBaseMenu.ItemCheckPlaceholder>
|
||||
<DropdownMenu.ItemIndicator>
|
||||
<DropdownMenu.ItemIndicator
|
||||
className={tw('inline-flex items-center')}
|
||||
>
|
||||
<AxoBaseMenu.ItemCheck />
|
||||
</DropdownMenu.ItemIndicator>
|
||||
</AxoBaseMenu.ItemCheckPlaceholder>
|
||||
</AxoBaseMenu.ItemLeadingSlot>
|
||||
<AxoBaseMenu.ItemContentSlot>
|
||||
{props.symbol && (
|
||||
<span className={tw('me-2')}>
|
||||
<span className={tw('me-2 inline-flex items-center')}>
|
||||
<AxoBaseMenu.ItemSymbol symbol={props.symbol} />
|
||||
</span>
|
||||
)}
|
||||
@@ -617,7 +621,7 @@ export namespace AxoDropdownMenu {
|
||||
)}
|
||||
<AxoBaseMenu.ItemContentSlot>
|
||||
<AxoBaseMenu.ItemText>{props.children}</AxoBaseMenu.ItemText>
|
||||
<span className={tw('ms-auto')}>
|
||||
<span className={tw('ms-auto inline-flex items-center')}>
|
||||
<AxoSymbol.Icon size={14} symbol="chevron-[end]" label={null} />
|
||||
</span>
|
||||
</AxoBaseMenu.ItemContentSlot>
|
||||
|
||||
@@ -29,10 +29,7 @@ import type {
|
||||
SetRendererCanvasType,
|
||||
} from '../state/ducks/calling.preload.ts';
|
||||
import { Avatar, AvatarSize } from './Avatar.dom.tsx';
|
||||
import {
|
||||
CallingHeader,
|
||||
getCallViewIconClassname,
|
||||
} from './CallingHeader.dom.tsx';
|
||||
import { CallingHeader, getCallViewModeIcon } from './CallingHeader.dom.tsx';
|
||||
import { CallingPreCallInfo, RingMode } from './CallingPreCallInfo.dom.tsx';
|
||||
import { CallingButton, CallingButtonType } from './CallingButton.dom.tsx';
|
||||
import { Button, ButtonVariant } from './Button.dom.tsx';
|
||||
@@ -1348,13 +1345,12 @@ function useViewModeChangedToast({
|
||||
showToast({
|
||||
key: VIEW_MODE_CHANGED_TOAST_KEY,
|
||||
content: (
|
||||
<div className="CallingToast__viewChanged">
|
||||
<span
|
||||
className={classNames(
|
||||
'CallingToast__viewChanged__icon',
|
||||
getCallViewIconClassname(viewMode)
|
||||
)}
|
||||
<div>
|
||||
<AxoSymbol.InlineGlyph
|
||||
symbol={getCallViewModeIcon(viewMode)}
|
||||
label={null}
|
||||
/>
|
||||
|
||||
{i18n('icu:calling__view_mode--updated')}
|
||||
</div>
|
||||
),
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { JSX } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import type { LocalizerType } from '../types/Util.std.ts';
|
||||
import { CallViewMode } from '../types/Calling.std.ts';
|
||||
import { Tooltip } from './Tooltip.dom.tsx';
|
||||
import { Theme } from '../util/theme.std.ts';
|
||||
import { ContextMenu } from './ContextMenu.dom.tsx';
|
||||
import { AxoDropdownMenu } from '../axo/AxoDropdownMenu.dom.tsx';
|
||||
import { AxoIconButton } from '../axo/AxoIconButton.dom.tsx';
|
||||
import { tw } from '../axo/tw.dom.tsx';
|
||||
import type { AxoSymbolIconName } from '../axo/_internal/AxoSymbolDefs.generated.std.ts';
|
||||
import { missingCaseError } from '../util/missingCaseError.std.ts';
|
||||
|
||||
export type PropsType = {
|
||||
callViewMode?: CallViewMode;
|
||||
@@ -31,127 +33,108 @@ export function CallingHeader({
|
||||
togglePip,
|
||||
toggleSettings,
|
||||
}: PropsType): JSX.Element {
|
||||
const handleViewModeChange = useCallback(
|
||||
(value: string) => {
|
||||
changeCallView?.(value as CallViewMode);
|
||||
},
|
||||
[changeCallView]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="module-calling-tools">
|
||||
<div
|
||||
className={tw(
|
||||
'absolute inset-e-6 top-[calc(32px+var(--title-bar-drag-area-height))] flex gap-3'
|
||||
)}
|
||||
>
|
||||
{isGroupCall &&
|
||||
participantCount > 2 &&
|
||||
callViewMode &&
|
||||
changeCallView && (
|
||||
<div className="module-calling-tools__button">
|
||||
<ContextMenu
|
||||
ariaLabel={i18n('icu:calling__change-view')}
|
||||
i18n={i18n}
|
||||
menuOptions={[
|
||||
{
|
||||
icon: 'CallSettingsButton__Icon--PaginatedView',
|
||||
label: i18n('icu:calling__view_mode--paginated'),
|
||||
onClick: () => changeCallView(CallViewMode.Paginated),
|
||||
value: CallViewMode.Paginated,
|
||||
},
|
||||
{
|
||||
icon: 'CallSettingsButton__Icon--SidebarView',
|
||||
label: i18n('icu:calling__view_mode--overflow'),
|
||||
onClick: () => changeCallView(CallViewMode.Sidebar),
|
||||
value: CallViewMode.Sidebar,
|
||||
},
|
||||
{
|
||||
icon: 'CallSettingsButton__Icon--SpeakerView',
|
||||
label: i18n('icu:calling__view_mode--speaker'),
|
||||
onClick: () => changeCallView(CallViewMode.Speaker),
|
||||
value: CallViewMode.Speaker,
|
||||
},
|
||||
]}
|
||||
theme={Theme.Dark}
|
||||
popperOptions={{
|
||||
placement: 'bottom',
|
||||
strategy: 'absolute',
|
||||
}}
|
||||
value={
|
||||
// If it's Presentation we want to still show Speaker as selected
|
||||
callViewMode === CallViewMode.Presentation
|
||||
? CallViewMode.Speaker
|
||||
: callViewMode
|
||||
}
|
||||
>
|
||||
<Tooltip
|
||||
content={i18n('icu:calling__change-view')}
|
||||
className="CallingButton__tooltip"
|
||||
theme={Theme.Dark}
|
||||
<AxoDropdownMenu.Root>
|
||||
<AxoDropdownMenu.Trigger>
|
||||
<AxoIconButton.Root
|
||||
variant="floating-secondary"
|
||||
size="lg"
|
||||
iconWeight={300}
|
||||
symbol={getCallViewModeIcon(callViewMode)}
|
||||
label={i18n('icu:calling__change-view')}
|
||||
tooltip={false}
|
||||
/>
|
||||
</AxoDropdownMenu.Trigger>
|
||||
<AxoDropdownMenu.Content align="end">
|
||||
<AxoDropdownMenu.RadioGroup
|
||||
value={
|
||||
// If it's Presentation we want to still show Speaker as selected
|
||||
callViewMode === CallViewMode.Presentation
|
||||
? CallViewMode.Speaker
|
||||
: callViewMode
|
||||
}
|
||||
onValueChange={handleViewModeChange}
|
||||
>
|
||||
<div className="CallSettingsButton__Button">
|
||||
<span
|
||||
className={classNames(
|
||||
'CallSettingsButton__Icon',
|
||||
getCallViewIconClassname(callViewMode)
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</ContextMenu>
|
||||
</div>
|
||||
<AxoDropdownMenu.RadioItem
|
||||
value={CallViewMode.Paginated}
|
||||
symbol="grid"
|
||||
>
|
||||
{i18n('icu:calling__view_mode--paginated')}
|
||||
</AxoDropdownMenu.RadioItem>
|
||||
<AxoDropdownMenu.RadioItem
|
||||
value={CallViewMode.Sidebar}
|
||||
symbol="grid-sidebar"
|
||||
>
|
||||
{i18n('icu:calling__view_mode--overflow')}
|
||||
</AxoDropdownMenu.RadioItem>
|
||||
<AxoDropdownMenu.RadioItem
|
||||
value={CallViewMode.Speaker}
|
||||
symbol="sidebar"
|
||||
>
|
||||
{i18n('icu:calling__view_mode--speaker')}
|
||||
</AxoDropdownMenu.RadioItem>
|
||||
</AxoDropdownMenu.RadioGroup>
|
||||
</AxoDropdownMenu.Content>
|
||||
</AxoDropdownMenu.Root>
|
||||
)}
|
||||
<div className="module-calling-tools__button">
|
||||
<Tooltip
|
||||
content={i18n('icu:callingDeviceSelection__settings')}
|
||||
className="CallingButton__tooltip"
|
||||
theme={Theme.Dark}
|
||||
>
|
||||
<button
|
||||
aria-label={i18n('icu:callingDeviceSelection__settings')}
|
||||
className="CallSettingsButton__Button"
|
||||
onClick={toggleSettings}
|
||||
type="button"
|
||||
>
|
||||
<span className="CallSettingsButton__Icon CallSettingsButton__Icon--Settings" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<AxoIconButton.Root
|
||||
variant="floating-secondary"
|
||||
size="lg"
|
||||
iconWeight={300}
|
||||
symbol="settings"
|
||||
label={i18n('icu:callingDeviceSelection__settings')}
|
||||
onClick={toggleSettings}
|
||||
/>
|
||||
{togglePip && (
|
||||
<div className="module-calling-tools__button">
|
||||
<Tooltip
|
||||
content={i18n('icu:calling__pip--on')}
|
||||
className="CallingButton__tooltip"
|
||||
theme={Theme.Dark}
|
||||
>
|
||||
<button
|
||||
aria-label={i18n('icu:calling__pip--on')}
|
||||
className="CallSettingsButton__Button"
|
||||
onClick={togglePip}
|
||||
type="button"
|
||||
>
|
||||
<span className="CallSettingsButton__Icon CallSettingsButton__Icon--Pip" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<AxoIconButton.Root
|
||||
variant="floating-secondary"
|
||||
size="lg"
|
||||
iconWeight={300}
|
||||
symbol="pip"
|
||||
label={i18n('icu:calling__pip--on')}
|
||||
onClick={togglePip}
|
||||
/>
|
||||
)}
|
||||
{onCancel && (
|
||||
<div className="module-calling-tools__button">
|
||||
<Tooltip
|
||||
content={i18n('icu:cancel')}
|
||||
theme={Theme.Dark}
|
||||
className="CallingButton__tooltip"
|
||||
>
|
||||
<button
|
||||
aria-label={i18n('icu:cancel')}
|
||||
className="CallSettingsButton__Button CallSettingsButton__Button--Cancel"
|
||||
onClick={onCancel}
|
||||
type="button"
|
||||
>
|
||||
<span className="CallSettingsButton__Icon CallSettingsButton__Icon--Cancel" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<AxoIconButton.Root
|
||||
variant="floating-secondary"
|
||||
size="lg"
|
||||
iconWeight={300}
|
||||
symbol="x"
|
||||
label={i18n('icu:cancel')}
|
||||
onClick={onCancel}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const CALL_VIEW_MODE_ICON_CLASSNAMES: Record<CallViewMode, string> = {
|
||||
[CallViewMode.Sidebar]: 'CallSettingsButton__Icon--SidebarView',
|
||||
[CallViewMode.Paginated]: 'CallSettingsButton__Icon--PaginatedView',
|
||||
[CallViewMode.Speaker]: 'CallSettingsButton__Icon--SpeakerView',
|
||||
[CallViewMode.Presentation]: 'CallSettingsButton__Icon--SpeakerView',
|
||||
};
|
||||
export function getCallViewIconClassname(viewMode: CallViewMode): string {
|
||||
return CALL_VIEW_MODE_ICON_CLASSNAMES[viewMode];
|
||||
export function getCallViewModeIcon(mode: CallViewMode): AxoSymbolIconName {
|
||||
switch (mode) {
|
||||
case CallViewMode.Paginated:
|
||||
return 'grid';
|
||||
case CallViewMode.Sidebar:
|
||||
return 'grid-sidebar';
|
||||
case CallViewMode.Presentation:
|
||||
case CallViewMode.Speaker:
|
||||
return 'sidebar';
|
||||
default:
|
||||
throw missingCaseError(mode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,10 +193,7 @@ describe('callMessages', function callMessages(this: Mocha.Suite) {
|
||||
|
||||
async function setInputAndOutput(win: Page, input: string, output: string) {
|
||||
debug(`setInputAndOutput input: ${input} output: ${output}`);
|
||||
await win
|
||||
.locator('.CallSettingsButton__Button')
|
||||
.and(win.getByLabel('Settings'))
|
||||
.click();
|
||||
await win.getByLabel('Settings').click();
|
||||
await win.locator('#audio-input').selectOption(input);
|
||||
await win.locator('#audio-output').selectOption(output);
|
||||
await win.locator('.module-calling-device-selection__close-button').click();
|
||||
|
||||
Reference in New Issue
Block a user