Calling: New option to expand your local preview
This commit is contained in:
@@ -3555,6 +3555,10 @@
|
|||||||
"messageformat": "Toggle video on and off",
|
"messageformat": "Toggle video on and off",
|
||||||
"description": "Shown in the shortcuts guide"
|
"description": "Shown in the shortcuts guide"
|
||||||
},
|
},
|
||||||
|
"icu:Keyboard--toggle-preview": {
|
||||||
|
"messageformat": "Toggle expanded preview on and off",
|
||||||
|
"description": "Shown in the shortcuts guide"
|
||||||
|
},
|
||||||
"icu:Keyboard--accept-video-call": {
|
"icu:Keyboard--accept-video-call": {
|
||||||
"messageformat": "Answer call with video (video calls only)",
|
"messageformat": "Answer call with video (video calls only)",
|
||||||
"description": "Shown in the calling keyboard shortcuts guide"
|
"description": "Shown in the calling keyboard shortcuts guide"
|
||||||
@@ -4115,6 +4119,14 @@
|
|||||||
"messageformat": "Fullscreen call",
|
"messageformat": "Fullscreen call",
|
||||||
"description": "Title for picture-in-picture toggle"
|
"description": "Title for picture-in-picture toggle"
|
||||||
},
|
},
|
||||||
|
"icu:calling__preview--maximize": {
|
||||||
|
"messageformat": "Maximize preview",
|
||||||
|
"description": "Title for button to make in-call video preview bigger"
|
||||||
|
},
|
||||||
|
"icu:calling__preview--minimize": {
|
||||||
|
"messageformat": "Minimize preview",
|
||||||
|
"description": "Title for button to make in-call video preview smaller"
|
||||||
|
},
|
||||||
"icu:calling__change-view": {
|
"icu:calling__change-view": {
|
||||||
"messageformat": "Change view",
|
"messageformat": "Change view",
|
||||||
"description": "Tooltip for changing the in-call layout of remote participants in a group call"
|
"description": "Tooltip for changing the in-call layout of remote participants in a group call"
|
||||||
|
1
images/icons/v3/maximize/maximize.svg
Normal file
1
images/icons/v3/maximize/maximize.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="20" height="20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M16.98 3.75a.729.729 0 0 0-.73-.73h-4.583a.73.73 0 1 0 0 1.46h3.032l-1.256 1.046-2.709 2.708a.73.73 0 0 0 1.031 1.032l2.709-2.709 1.047-1.256v3.032a.73.73 0 1 0 1.458 0V3.75ZM3.234 16.766a.73.73 0 0 1-.213-.516v-4.583a.73.73 0 0 1 1.458 0v3.032l1.047-1.256 2.708-2.709a.73.73 0 0 1 1.032 1.032l-2.709 2.708-1.256 1.047h3.032a.73.73 0 1 1 0 1.458H3.75a.729.729 0 0 1-.516-.213Z" fill="#000"/></svg>
|
After Width: | Height: | Size: 481 B |
1
images/icons/v3/minimize/minimize.svg
Normal file
1
images/icons/v3/minimize/minimize.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="20" height="20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9.27 11.458a.73.73 0 0 0-.728-.729H3.958a.73.73 0 1 0 0 1.459h3.033l-1.257 1.046-2.708 2.709a.73.73 0 1 0 1.031 1.03l2.709-2.707 1.046-1.257v3.033a.73.73 0 0 0 1.459 0v-4.584Zm1.673-2.401a.73.73 0 0 1-.214-.515V3.958a.73.73 0 1 1 1.459 0v3.033l1.046-1.257 2.709-2.708a.73.73 0 1 1 1.03 1.031l-2.707 2.709-1.257 1.046h3.033a.73.73 0 0 1 0 1.459h-4.584a.73.73 0 0 1-.515-.214Z" fill="#000"/></svg>
|
After Width: | Height: | Size: 480 B |
@@ -3996,8 +3996,6 @@ button.module-image__border-overlay:focus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.module-ongoing-call {
|
.module-ongoing-call {
|
||||||
$local-preview-height: 80px;
|
|
||||||
|
|
||||||
&__remote-video-enabled {
|
&__remote-video-enabled {
|
||||||
background-color: variables.$color-gray-95;
|
background-color: variables.$color-gray-95;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -4075,6 +4073,13 @@ button.module-image__border-overlay:focus {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
inset-inline-end: 16px;
|
inset-inline-end: 16px;
|
||||||
bottom: 112px;
|
bottom: 112px;
|
||||||
|
transition: bottom 0.3s variables.$ease-out-local-preview;
|
||||||
|
}
|
||||||
|
&__direct-call-speaking-indicator--self-view-expanded {
|
||||||
|
bottom: 330px;
|
||||||
|
}
|
||||||
|
&__direct-call-speaking-indicator--expanded-no-controls {
|
||||||
|
bottom: 232px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__participants {
|
&__participants {
|
||||||
@@ -4523,6 +4528,56 @@ button.module-image__border-overlay:focus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__local-preview {
|
||||||
|
z-index: variables.$z-index-calling-pip;
|
||||||
|
border-radius: 12px;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
height: 80px;
|
||||||
|
width: variables.$calling-local-preview-normal-width;
|
||||||
|
|
||||||
|
inset-inline-end: 16px;
|
||||||
|
bottom: 16px;
|
||||||
|
|
||||||
|
transition: all 0.3s variables.$ease-out-local-preview;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&--active {
|
||||||
|
box-shadow: 0px 4px 14px 0px variables.$color-black-alpha-40;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--expanded {
|
||||||
|
bottom: 112px;
|
||||||
|
height: 200px;
|
||||||
|
width: 312px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--controls-hidden {
|
||||||
|
bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__video {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
video {
|
||||||
|
// The background-color is seen while the video loads.
|
||||||
|
background-color: variables.$color-gray-75;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
transform: rotateY(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--presenting video {
|
||||||
|
transform: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__footer {
|
&__footer {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -4537,40 +4592,6 @@ button.module-image__border-overlay:focus {
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__local-preview {
|
|
||||||
border-radius: 10px;
|
|
||||||
display: flex;
|
|
||||||
flex-shrink: 0;
|
|
||||||
height: $local-preview-height;
|
|
||||||
margin-block-end: 16px;
|
|
||||||
margin-inline: 0 16px;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
width: variables.$calling-local-preview-width;
|
|
||||||
|
|
||||||
&--active {
|
|
||||||
box-shadow: 0px 4px 14px 0px variables.$color-black-alpha-40;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__video {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
video {
|
|
||||||
// The background-color is seen while the video loads.
|
|
||||||
background-color: variables.$color-gray-75;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
transform: rotateY(180deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
&--presenting video {
|
|
||||||
transform: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__controls {
|
&__controls {
|
||||||
|
@@ -272,11 +272,12 @@ $color-selected-message-background-dark: $color-gray-65;
|
|||||||
$header-height: 52px;
|
$header-height: 52px;
|
||||||
|
|
||||||
$ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1);
|
$ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1);
|
||||||
|
$ease-out-local-preview: cubic-bezier(0.17, 0.17, 0, 1);
|
||||||
|
|
||||||
$calling-background-color: $color-gray-90;
|
$calling-background-color: $color-gray-90;
|
||||||
|
|
||||||
// Maintain aspect ratio 960x720 with $local-preview-height
|
// Maintain aspect ratio 960x720 with $local-preview-height
|
||||||
$calling-local-preview-width: 106.67px;
|
$calling-local-preview-normal-width: 106.67px;
|
||||||
|
|
||||||
// General
|
// General
|
||||||
|
|
||||||
|
@@ -118,7 +118,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.CallControls__OuterSpacer {
|
.CallControls__OuterSpacer {
|
||||||
flex-basis: calc(variables.$calling-local-preview-width + 16px);
|
flex-basis: calc(variables.$calling-local-preview-normal-width + 16px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.CallControls__ReactionPickerContainer {
|
.CallControls__ReactionPickerContainer {
|
||||||
|
@@ -38,10 +38,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.module-ongoing-call__footer__local-preview .CallingAudioIndicator {
|
.module-ongoing-call__local-preview .CallingAudioIndicator {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 6px;
|
top: 8px;
|
||||||
inset-inline-end: 6px;
|
inset-inline-end: 8px;
|
||||||
z-index: variables.$z-index-base;
|
z-index: variables.$z-index-base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -160,6 +160,22 @@
|
|||||||
&--more-options {
|
&--more-options {
|
||||||
@include calling-button-icon-regular('../images/icons/v3/more/more.svg');
|
@include calling-button-icon-regular('../images/icons/v3/more/more.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--maximize {
|
||||||
|
@include calling-button-icon(
|
||||||
|
'../images/icons/v3/maximize/maximize.svg',
|
||||||
|
rgba(variables.$color-gray-80, 0.7),
|
||||||
|
variables.$color-white
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--minimize {
|
||||||
|
@include calling-button-icon(
|
||||||
|
'../images/icons/v3/minimize/minimize.svg',
|
||||||
|
rgba(variables.$color-gray-80, 0.7),
|
||||||
|
variables.$color-white
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__button-container {
|
&__button-container {
|
||||||
@@ -228,3 +244,23 @@
|
|||||||
border-top-color: variables.$color-gray-80 !important;
|
border-top-color: variables.$color-gray-80 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.CallingButton__Button--self-view {
|
||||||
|
position: absolute;
|
||||||
|
inset-inline-start: 8px;
|
||||||
|
top: 8px;
|
||||||
|
|
||||||
|
.CallingButton__button-container {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.CallingButton__Button--self-view-normal .CallingButton__icon {
|
||||||
|
height: 28px;
|
||||||
|
width: 28px;
|
||||||
|
|
||||||
|
div {
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -36,27 +36,26 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.CallingStatusIndicator--Video::after {
|
.CallingStatusIndicator--NoVideo::after {
|
||||||
@include mixins.color-svg(
|
@include mixins.color-svg(
|
||||||
'../images/icons/v3/video/video-slash-fill-light.svg',
|
'../images/icons/v3/video/video-slash-fill-light.svg',
|
||||||
variables.$color-white
|
variables.$color-white
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
.module-ongoing-call__footer__local-preview .CallingStatusIndicator {
|
.module-ongoing-call__local-preview .CallingStatusIndicator {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: variables.$z-index-base;
|
z-index: variables.$z-index-base;
|
||||||
}
|
}
|
||||||
|
|
||||||
.module-ongoing-call__footer__local-preview .CallingStatusIndicator--Video {
|
.module-ongoing-call__local-preview .CallingStatusIndicator--NoVideo {
|
||||||
top: 6px;
|
top: 8px;
|
||||||
inset-inline-start: 6px;
|
inset-inline-start: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.module-ongoing-call__footer__local-preview
|
.module-ongoing-call__local-preview .CallingStatusIndicator--HandRaised {
|
||||||
.CallingStatusIndicator--HandRaised {
|
bottom: 8px;
|
||||||
bottom: 6px;
|
inset-inline-start: 8px;
|
||||||
inset-inline-start: 6px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.module-ongoing-call__participants__grid
|
.module-ongoing-call__participants__grid
|
||||||
|
@@ -81,6 +81,7 @@ const getCommonActiveCallData = () => ({
|
|||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
});
|
});
|
||||||
@@ -147,6 +148,7 @@ const createProps = (storyProps: Partial<PropsType> = {}): PropsType => ({
|
|||||||
toggleScreenRecordingPermissionsDialog: action(
|
toggleScreenRecordingPermissionsDialog: action(
|
||||||
'toggle-screen-recording-permissions-dialog'
|
'toggle-screen-recording-permissions-dialog'
|
||||||
),
|
),
|
||||||
|
toggleSelfViewExpanded: action('toggle-self-view-expanded'),
|
||||||
toggleSettings: action('toggle-settings'),
|
toggleSettings: action('toggle-settings'),
|
||||||
pauseVoiceNotePlayer: action('pause-audio-player'),
|
pauseVoiceNotePlayer: action('pause-audio-player'),
|
||||||
});
|
});
|
||||||
@@ -181,6 +183,7 @@ const getActiveCallForCallLink = (
|
|||||||
pendingParticipants: overrideProps.pendingParticipants ?? [],
|
pendingParticipants: overrideProps.pendingParticipants ?? [],
|
||||||
raisedHands: new Set<number>(),
|
raisedHands: new Set<number>(),
|
||||||
remoteAudioLevels: new Map<number, number>(),
|
remoteAudioLevels: new Map<number, number>(),
|
||||||
|
selfViewExpanded: false,
|
||||||
suggestLowerHand: false,
|
suggestLowerHand: false,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -138,6 +138,7 @@ export type PropsType = {
|
|||||||
togglePip: () => void;
|
togglePip: () => void;
|
||||||
toggleCallLinkPendingParticipantModal: (contactId: string) => void;
|
toggleCallLinkPendingParticipantModal: (contactId: string) => void;
|
||||||
toggleScreenRecordingPermissionsDialog: () => unknown;
|
toggleScreenRecordingPermissionsDialog: () => unknown;
|
||||||
|
toggleSelfViewExpanded: () => unknown;
|
||||||
toggleSettings: () => void;
|
toggleSettings: () => void;
|
||||||
pauseVoiceNotePlayer: () => void;
|
pauseVoiceNotePlayer: () => void;
|
||||||
} & Pick<ReactionPickerProps, 'renderEmojiPicker'>;
|
} & Pick<ReactionPickerProps, 'renderEmojiPicker'>;
|
||||||
@@ -200,6 +201,7 @@ function ActiveCallManager({
|
|||||||
toggleParticipants,
|
toggleParticipants,
|
||||||
togglePip,
|
togglePip,
|
||||||
toggleScreenRecordingPermissionsDialog,
|
toggleScreenRecordingPermissionsDialog,
|
||||||
|
toggleSelfViewExpanded,
|
||||||
toggleSettings,
|
toggleSettings,
|
||||||
pauseVoiceNotePlayer,
|
pauseVoiceNotePlayer,
|
||||||
}: ActiveCallManagerPropsType): JSX.Element {
|
}: ActiveCallManagerPropsType): JSX.Element {
|
||||||
@@ -480,6 +482,7 @@ function ActiveCallManager({
|
|||||||
}
|
}
|
||||||
toggleParticipants={toggleParticipants}
|
toggleParticipants={toggleParticipants}
|
||||||
togglePip={togglePip}
|
togglePip={togglePip}
|
||||||
|
toggleSelfViewExpanded={toggleSelfViewExpanded}
|
||||||
toggleSettings={toggleSettings}
|
toggleSettings={toggleSettings}
|
||||||
/>
|
/>
|
||||||
{presentingSourcesAvailable && presentingSourcesAvailable.length ? (
|
{presentingSourcesAvailable && presentingSourcesAvailable.length ? (
|
||||||
@@ -573,6 +576,7 @@ export function CallManager({
|
|||||||
togglePip,
|
togglePip,
|
||||||
toggleCallLinkPendingParticipantModal,
|
toggleCallLinkPendingParticipantModal,
|
||||||
toggleScreenRecordingPermissionsDialog,
|
toggleScreenRecordingPermissionsDialog,
|
||||||
|
toggleSelfViewExpanded,
|
||||||
toggleSettings,
|
toggleSettings,
|
||||||
}: PropsType): JSX.Element | null {
|
}: PropsType): JSX.Element | null {
|
||||||
const isCallActive = Boolean(activeCall);
|
const isCallActive = Boolean(activeCall);
|
||||||
@@ -667,6 +671,7 @@ export function CallManager({
|
|||||||
toggleScreenRecordingPermissionsDialog={
|
toggleScreenRecordingPermissionsDialog={
|
||||||
toggleScreenRecordingPermissionsDialog
|
toggleScreenRecordingPermissionsDialog
|
||||||
}
|
}
|
||||||
|
toggleSelfViewExpanded={toggleSelfViewExpanded}
|
||||||
toggleSettings={toggleSettings}
|
toggleSettings={toggleSettings}
|
||||||
/>
|
/>
|
||||||
</CallingToastProvider>
|
</CallingToastProvider>
|
||||||
|
@@ -56,6 +56,7 @@ type OverridePropsBase = {
|
|||||||
hasLocalVideo?: boolean;
|
hasLocalVideo?: boolean;
|
||||||
localAudioLevel?: number;
|
localAudioLevel?: number;
|
||||||
viewMode?: CallViewMode;
|
viewMode?: CallViewMode;
|
||||||
|
outgoingRing?: boolean;
|
||||||
reactions?: ActiveCallReactionsType;
|
reactions?: ActiveCallReactionsType;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,6 +64,9 @@ type DirectCallOverrideProps = OverridePropsBase & {
|
|||||||
callMode: CallMode.Direct;
|
callMode: CallMode.Direct;
|
||||||
callState?: CallState;
|
callState?: CallState;
|
||||||
hasRemoteVideo?: boolean;
|
hasRemoteVideo?: boolean;
|
||||||
|
outgoingRing?: boolean;
|
||||||
|
selfViewExpanded?: boolean;
|
||||||
|
remoteAudioLevel?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type GroupCallOverrideProps = OverridePropsBase & {
|
type GroupCallOverrideProps = OverridePropsBase & {
|
||||||
@@ -72,9 +76,11 @@ type GroupCallOverrideProps = OverridePropsBase & {
|
|||||||
peekedParticipants?: Array<ConversationType>;
|
peekedParticipants?: Array<ConversationType>;
|
||||||
pendingParticipants?: Array<ConversationType>;
|
pendingParticipants?: Array<ConversationType>;
|
||||||
raisedHands?: Set<number>;
|
raisedHands?: Set<number>;
|
||||||
remoteParticipants?: Array<GroupCallRemoteParticipantType>;
|
|
||||||
remoteAudioLevel?: number;
|
remoteAudioLevel?: number;
|
||||||
|
remoteParticipants?: Array<GroupCallRemoteParticipantType>;
|
||||||
|
selfViewExpanded?: boolean;
|
||||||
suggestLowerHand?: boolean;
|
suggestLowerHand?: boolean;
|
||||||
|
outgoingRing?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createActiveDirectCallProp = (
|
const createActiveDirectCallProp = (
|
||||||
@@ -84,7 +90,7 @@ const createActiveDirectCallProp = (
|
|||||||
conversation,
|
conversation,
|
||||||
callState: overrideProps.callState ?? CallState.Accepted,
|
callState: overrideProps.callState ?? CallState.Accepted,
|
||||||
peekedParticipants: [] as [],
|
peekedParticipants: [] as [],
|
||||||
remoteAudioLevel: 0,
|
remoteAudioLevel: overrideProps.remoteAudioLevel ?? 0,
|
||||||
remoteParticipants: [
|
remoteParticipants: [
|
||||||
{
|
{
|
||||||
hasRemoteVideo: overrideProps.hasRemoteVideo ?? false,
|
hasRemoteVideo: overrideProps.hasRemoteVideo ?? false,
|
||||||
@@ -168,9 +174,10 @@ const createActiveCallProp = (
|
|||||||
hasLocalVideo: overrideProps.hasLocalVideo ?? false,
|
hasLocalVideo: overrideProps.hasLocalVideo ?? false,
|
||||||
localAudioLevel: overrideProps.localAudioLevel ?? 0,
|
localAudioLevel: overrideProps.localAudioLevel ?? 0,
|
||||||
viewMode: overrideProps.viewMode ?? CallViewMode.Sidebar,
|
viewMode: overrideProps.viewMode ?? CallViewMode.Sidebar,
|
||||||
outgoingRing: true,
|
outgoingRing: overrideProps.outgoingRing ?? true,
|
||||||
pip: false,
|
pip: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
|
selfViewExpanded: overrideProps.selfViewExpanded ?? false,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -236,6 +243,7 @@ const createProps = (
|
|||||||
toggleScreenRecordingPermissionsDialog: action(
|
toggleScreenRecordingPermissionsDialog: action(
|
||||||
'toggle-screen-recording-permissions-dialog'
|
'toggle-screen-recording-permissions-dialog'
|
||||||
),
|
),
|
||||||
|
toggleSelfViewExpanded: action('toggle-self-view-expanded'),
|
||||||
toggleSettings: action('toggle-settings'),
|
toggleSettings: action('toggle-settings'),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -269,7 +277,7 @@ export function PreRing(): JSX.Element {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Ringing(): JSX.Element {
|
export function DirectRinging(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<CallScreen
|
<CallScreen
|
||||||
{...createProps({
|
{...createProps({
|
||||||
@@ -335,6 +343,46 @@ export function HasRemoteVideo(): JSX.Element {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function BothSpeaking(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<CallScreen
|
||||||
|
{...createProps({
|
||||||
|
callMode: CallMode.Direct,
|
||||||
|
hasRemoteVideo: true,
|
||||||
|
hasLocalAudio: true,
|
||||||
|
localAudioLevel: 0.75,
|
||||||
|
remoteAudioLevel: 0.75,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SelfViewExpanded(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<CallScreen
|
||||||
|
{...createProps({
|
||||||
|
callMode: CallMode.Direct,
|
||||||
|
selfViewExpanded: true,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SelfViewExpandedBothSpeaking(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<CallScreen
|
||||||
|
{...createProps({
|
||||||
|
callMode: CallMode.Direct,
|
||||||
|
selfViewExpanded: true,
|
||||||
|
hasRemoteVideo: true,
|
||||||
|
hasLocalAudio: true,
|
||||||
|
localAudioLevel: 0.75,
|
||||||
|
remoteAudioLevel: 0.75,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function GroupCall1(): JSX.Element {
|
export function GroupCall1(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<CallScreen
|
<CallScreen
|
||||||
@@ -363,6 +411,16 @@ export function GroupCall1(): JSX.Element {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function GroupCall0(): JSX.Element {
|
||||||
|
const props = createProps({
|
||||||
|
callMode: CallMode.Group,
|
||||||
|
remoteParticipants: [],
|
||||||
|
groupMembers: [],
|
||||||
|
outgoingRing: false,
|
||||||
|
});
|
||||||
|
return <CallScreen {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
export function GroupCallYourHandRaised(): JSX.Element {
|
export function GroupCallYourHandRaised(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<CallScreen
|
<CallScreen
|
||||||
@@ -516,7 +574,7 @@ export function GroupCallReconnecting(): JSX.Element {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GroupCall0(): JSX.Element {
|
export function GroupCallOutgoingRinging(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<CallScreen
|
<CallScreen
|
||||||
{...createProps({
|
{...createProps({
|
||||||
|
@@ -126,6 +126,7 @@ export type PropsType = {
|
|||||||
toggleParticipants: () => void;
|
toggleParticipants: () => void;
|
||||||
togglePip: () => void;
|
togglePip: () => void;
|
||||||
toggleScreenRecordingPermissionsDialog: () => unknown;
|
toggleScreenRecordingPermissionsDialog: () => unknown;
|
||||||
|
toggleSelfViewExpanded: () => void;
|
||||||
toggleSettings: () => void;
|
toggleSettings: () => void;
|
||||||
changeCallView: (mode: CallViewMode) => void;
|
changeCallView: (mode: CallViewMode) => void;
|
||||||
} & Pick<ReactionPickerProps, 'renderEmojiPicker'>;
|
} & Pick<ReactionPickerProps, 'renderEmojiPicker'>;
|
||||||
@@ -215,6 +216,7 @@ export function CallScreen({
|
|||||||
toggleParticipants,
|
toggleParticipants,
|
||||||
togglePip,
|
togglePip,
|
||||||
toggleScreenRecordingPermissionsDialog,
|
toggleScreenRecordingPermissionsDialog,
|
||||||
|
toggleSelfViewExpanded,
|
||||||
toggleSettings,
|
toggleSettings,
|
||||||
}: PropsType): JSX.Element {
|
}: PropsType): JSX.Element {
|
||||||
const {
|
const {
|
||||||
@@ -280,7 +282,6 @@ export function CallScreen({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const [controlsHover, setControlsHover] = useState(false);
|
const [controlsHover, setControlsHover] = useState(false);
|
||||||
|
|
||||||
const onControlsMouseEnter = useCallback(() => {
|
const onControlsMouseEnter = useCallback(() => {
|
||||||
setControlsHover(true);
|
setControlsHover(true);
|
||||||
}, [setControlsHover]);
|
}, [setControlsHover]);
|
||||||
@@ -290,7 +291,6 @@ export function CallScreen({
|
|||||||
}, [setControlsHover]);
|
}, [setControlsHover]);
|
||||||
|
|
||||||
const [showControls, setShowControls] = useState(true);
|
const [showControls, setShowControls] = useState(true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
!showControls ||
|
!showControls ||
|
||||||
@@ -306,6 +306,28 @@ export function CallScreen({
|
|||||||
return clearTimeout.bind(null, timer);
|
return clearTimeout.bind(null, timer);
|
||||||
}, [showControls, showReactionPicker, stickyControls, controlsHover]);
|
}, [showControls, showReactionPicker, stickyControls, controlsHover]);
|
||||||
|
|
||||||
|
const [selfViewHover, setSelfViewHover] = useState(false);
|
||||||
|
const onSelfViewMouseEnter = useCallback(() => {
|
||||||
|
setSelfViewHover(true);
|
||||||
|
}, [setSelfViewHover]);
|
||||||
|
|
||||||
|
const onSelfViewMouseLeave = useCallback(() => {
|
||||||
|
setSelfViewHover(false);
|
||||||
|
}, [setSelfViewHover]);
|
||||||
|
|
||||||
|
const [showSelfViewControls, setShowSelfViewControls] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
if (selfViewHover) {
|
||||||
|
setShowSelfViewControls(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
setShowSelfViewControls(false);
|
||||||
|
}, 2000);
|
||||||
|
return clearTimeout.bind(null, timer);
|
||||||
|
}, [showSelfViewControls, setShowSelfViewControls, selfViewHover]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleKeyDown = (event: KeyboardEvent): void => {
|
const handleKeyDown = (event: KeyboardEvent): void => {
|
||||||
let eventHandled = false;
|
let eventHandled = false;
|
||||||
@@ -314,16 +336,20 @@ export function CallScreen({
|
|||||||
|
|
||||||
if (event.shiftKey && (key === 'V' || key === 'v')) {
|
if (event.shiftKey && (key === 'V' || key === 'v')) {
|
||||||
toggleVideo();
|
toggleVideo();
|
||||||
|
setShowControls(true);
|
||||||
eventHandled = true;
|
eventHandled = true;
|
||||||
} else if (event.shiftKey && (key === 'M' || key === 'm')) {
|
} else if (event.shiftKey && (key === 'M' || key === 'm')) {
|
||||||
toggleAudio();
|
toggleAudio();
|
||||||
|
setShowControls(true);
|
||||||
|
eventHandled = true;
|
||||||
|
} else if (event.shiftKey && (key === 'P' || key === 'p')) {
|
||||||
|
toggleSelfViewExpanded();
|
||||||
eventHandled = true;
|
eventHandled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventHandled) {
|
if (eventHandled) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
setShowControls(true);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -331,7 +357,7 @@ export function CallScreen({
|
|||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('keydown', handleKeyDown);
|
document.removeEventListener('keydown', handleKeyDown);
|
||||||
};
|
};
|
||||||
}, [toggleAudio, toggleVideo]);
|
}, [setShowControls, toggleAudio, toggleSelfViewExpanded, toggleVideo]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!showReactionPicker) {
|
if (!showReactionPicker) {
|
||||||
@@ -411,7 +437,24 @@ export function CallScreen({
|
|||||||
let lonelyInCallNode: ReactNode;
|
let lonelyInCallNode: ReactNode;
|
||||||
let localPreviewNode: ReactNode;
|
let localPreviewNode: ReactNode;
|
||||||
|
|
||||||
|
const raisedHands = isGroupOrAdhocActiveCall(activeCall)
|
||||||
|
? activeCall.raisedHands
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
// This is the value of our hand raised as seen by remote clients. We should prefer
|
||||||
|
// to use it in UI so the user understands what remote clients see.
|
||||||
|
const syncedLocalHandRaised = isHandRaised(raisedHands, localDemuxId);
|
||||||
|
|
||||||
const isLonelyInCall = !activeCall.remoteParticipants.length;
|
const isLonelyInCall = !activeCall.remoteParticipants.length;
|
||||||
|
const handlePreviewClick = useCallback(
|
||||||
|
(event?: React.MouseEvent) => {
|
||||||
|
event?.preventDefault();
|
||||||
|
event?.stopPropagation();
|
||||||
|
|
||||||
|
toggleSelfViewExpanded();
|
||||||
|
},
|
||||||
|
[toggleSelfViewExpanded]
|
||||||
|
);
|
||||||
|
|
||||||
if (isLonelyInCall) {
|
if (isLonelyInCall) {
|
||||||
lonelyInCallNode = (
|
lonelyInCallNode = (
|
||||||
@@ -438,12 +481,12 @@ export function CallScreen({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
localPreviewNode = isSendingVideo ? (
|
const innerPreviewNode = isSendingVideo ? (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'module-ongoing-call__footer__local-preview__video',
|
'module-ongoing-call__local-preview__video',
|
||||||
presentingSource &&
|
presentingSource &&
|
||||||
'module-ongoing-call__footer__local-preview__video--presenting'
|
'module-ongoing-call__local-preview__video--presenting'
|
||||||
)}
|
)}
|
||||||
ref={setLocalPreviewContainer}
|
ref={setLocalPreviewContainer}
|
||||||
/>
|
/>
|
||||||
@@ -467,6 +510,74 @@ export function CallScreen({
|
|||||||
/>
|
/>
|
||||||
</CallBackgroundBlur>
|
</CallBackgroundBlur>
|
||||||
);
|
);
|
||||||
|
localPreviewNode = (
|
||||||
|
// Keyboard shortcuts are available for this gesture, no need for keyboard support
|
||||||
|
/* eslint-disable-next-line max-len */
|
||||||
|
/* eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'module-ongoing-call__local-preview',
|
||||||
|
'module-ongoing-call__local-preview--active',
|
||||||
|
activeCall.selfViewExpanded
|
||||||
|
? 'module-ongoing-call__local-preview--expanded'
|
||||||
|
: undefined,
|
||||||
|
!showControls
|
||||||
|
? 'module-ongoing-call__local-preview--controls-hidden'
|
||||||
|
: undefined
|
||||||
|
)}
|
||||||
|
onMouseEnter={onSelfViewMouseEnter}
|
||||||
|
onMouseLeave={onSelfViewMouseLeave}
|
||||||
|
onClick={handlePreviewClick}
|
||||||
|
>
|
||||||
|
{innerPreviewNode}
|
||||||
|
{!isSendingVideo && (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'CallingStatusIndicator',
|
||||||
|
'CallingStatusIndicator--NoVideo',
|
||||||
|
!showSelfViewControls
|
||||||
|
? 'module-ongoing-call__controls--fadeIn'
|
||||||
|
: undefined,
|
||||||
|
showSelfViewControls
|
||||||
|
? 'module-ongoing-call__controls--fadeOut'
|
||||||
|
: undefined
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<CallingAudioIndicator
|
||||||
|
hasAudio={hasLocalAudio}
|
||||||
|
audioLevel={localAudioLevel}
|
||||||
|
shouldShowSpeaking={isSpeaking}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'CallingButton__Button--self-view',
|
||||||
|
showSelfViewControls
|
||||||
|
? 'module-ongoing-call__controls--fadeIn'
|
||||||
|
: undefined,
|
||||||
|
!showSelfViewControls
|
||||||
|
? 'module-ongoing-call__controls--fadeOut'
|
||||||
|
: undefined,
|
||||||
|
!activeCall.selfViewExpanded
|
||||||
|
? 'CallingButton__Button--self-view-normal'
|
||||||
|
: undefined
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<CallingButton
|
||||||
|
buttonType={
|
||||||
|
activeCall.selfViewExpanded
|
||||||
|
? CallingButtonType.MINIMIZE
|
||||||
|
: CallingButtonType.MAXIMIZE
|
||||||
|
}
|
||||||
|
i18n={i18n}
|
||||||
|
onClick={handlePreviewClick}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{syncedLocalHandRaised && (
|
||||||
|
<div className="CallingStatusIndicator CallingStatusIndicator--HandRaised" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let videoButtonType: CallingButtonType;
|
let videoButtonType: CallingButtonType;
|
||||||
@@ -503,14 +614,6 @@ export function CallScreen({
|
|||||||
presentingButtonType = CallingButtonType.PRESENTING_OFF;
|
presentingButtonType = CallingButtonType.PRESENTING_OFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
const raisedHands = isGroupOrAdhocActiveCall(activeCall)
|
|
||||||
? activeCall.raisedHands
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
// This is the value of our hand raised as seen by remote clients. We should prefer
|
|
||||||
// to use it in UI so the user understands what remote clients see.
|
|
||||||
const syncedLocalHandRaised = isHandRaised(raisedHands, localDemuxId);
|
|
||||||
|
|
||||||
// Don't call setLocalHandRaised because it only sets local state. Instead call
|
// Don't call setLocalHandRaised because it only sets local state. Instead call
|
||||||
// toggleRaiseHand() which will set ringrtc state and call setLocalHandRaised.
|
// toggleRaiseHand() which will set ringrtc state and call setLocalHandRaised.
|
||||||
const [localHandRaised, setLocalHandRaised] = useState<boolean>(
|
const [localHandRaised, setLocalHandRaised] = useState<boolean>(
|
||||||
@@ -877,7 +980,17 @@ export function CallScreen({
|
|||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
{activeCall.callMode === CallMode.Direct && (
|
{activeCall.callMode === CallMode.Direct && (
|
||||||
<div className="module-ongoing-call__direct-call-speaking-indicator">
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'module-ongoing-call__direct-call-speaking-indicator',
|
||||||
|
activeCall.selfViewExpanded
|
||||||
|
? 'module-ongoing-call__direct-call-speaking-indicator--self-view-expanded'
|
||||||
|
: undefined,
|
||||||
|
activeCall.selfViewExpanded && !showControls
|
||||||
|
? 'module-ongoing-call__direct-call-speaking-indicator--expanded-no-controls'
|
||||||
|
: undefined
|
||||||
|
)}
|
||||||
|
>
|
||||||
<CallingAudioIndicator
|
<CallingAudioIndicator
|
||||||
hasAudio
|
hasAudio
|
||||||
audioLevel={activeCall.remoteAudioLevel}
|
audioLevel={activeCall.remoteAudioLevel}
|
||||||
@@ -885,27 +998,10 @@ export function CallScreen({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{/* We render the local preview first and set the footer flex direction to row-reverse
|
{localPreviewNode}
|
||||||
to ensure the preview is visible at low viewport widths. */}
|
{/* We set flex direction to row-reverse to render outward from local preview */}
|
||||||
<div className="module-ongoing-call__footer">
|
<div className="module-ongoing-call__footer">
|
||||||
{localPreviewNode ? (
|
<div className="module-calling__spacer CallControls__OuterSpacer" />
|
||||||
<div className="module-ongoing-call__footer__local-preview module-ongoing-call__footer__local-preview--active">
|
|
||||||
{localPreviewNode}
|
|
||||||
{!isSendingVideo && (
|
|
||||||
<div className="CallingStatusIndicator CallingStatusIndicator--Video" />
|
|
||||||
)}
|
|
||||||
<CallingAudioIndicator
|
|
||||||
hasAudio={hasLocalAudio}
|
|
||||||
audioLevel={localAudioLevel}
|
|
||||||
shouldShowSpeaking={isSpeaking}
|
|
||||||
/>
|
|
||||||
{syncedLocalHandRaised && (
|
|
||||||
<div className="CallingStatusIndicator CallingStatusIndicator--HandRaised" />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="module-ongoing-call__footer__local-preview" />
|
|
||||||
)}
|
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'CallControls',
|
'CallControls',
|
||||||
|
@@ -13,6 +13,9 @@ export enum CallingButtonType {
|
|||||||
AUDIO_DISABLED = 'AUDIO_DISABLED',
|
AUDIO_DISABLED = 'AUDIO_DISABLED',
|
||||||
AUDIO_OFF = 'AUDIO_OFF',
|
AUDIO_OFF = 'AUDIO_OFF',
|
||||||
AUDIO_ON = 'AUDIO_ON',
|
AUDIO_ON = 'AUDIO_ON',
|
||||||
|
MAXIMIZE = 'MAXIMIZE',
|
||||||
|
MINIMIZE = 'MINIMIZE',
|
||||||
|
MORE_OPTIONS = 'MORE_OPTIONS',
|
||||||
PRESENTING_DISABLED = 'PRESENTING_DISABLED',
|
PRESENTING_DISABLED = 'PRESENTING_DISABLED',
|
||||||
PRESENTING_OFF = 'PRESENTING_OFF',
|
PRESENTING_OFF = 'PRESENTING_OFF',
|
||||||
PRESENTING_ON = 'PRESENTING_ON',
|
PRESENTING_ON = 'PRESENTING_ON',
|
||||||
@@ -26,7 +29,6 @@ export enum CallingButtonType {
|
|||||||
VIDEO_DISABLED = 'VIDEO_DISABLED',
|
VIDEO_DISABLED = 'VIDEO_DISABLED',
|
||||||
VIDEO_OFF = 'VIDEO_OFF',
|
VIDEO_OFF = 'VIDEO_OFF',
|
||||||
VIDEO_ON = 'VIDEO_ON',
|
VIDEO_ON = 'VIDEO_ON',
|
||||||
MORE_OPTIONS = 'MORE_OPTIONS',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PropsType = {
|
export type PropsType = {
|
||||||
@@ -109,8 +111,23 @@ export function CallingButton({
|
|||||||
} else if (buttonType === CallingButtonType.MORE_OPTIONS) {
|
} else if (buttonType === CallingButtonType.MORE_OPTIONS) {
|
||||||
classNameSuffix = 'more-options';
|
classNameSuffix = 'more-options';
|
||||||
tooltipContent = i18n('icu:CallingButton--more-options');
|
tooltipContent = i18n('icu:CallingButton--more-options');
|
||||||
|
} else if (buttonType === CallingButtonType.MAXIMIZE) {
|
||||||
|
classNameSuffix = 'maximize';
|
||||||
|
tooltipContent = i18n('icu:calling__preview--maximize');
|
||||||
|
} else if (buttonType === CallingButtonType.MINIMIZE) {
|
||||||
|
classNameSuffix = 'minimize';
|
||||||
|
tooltipContent = i18n('icu:calling__preview--minimize');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleClick = React.useCallback(
|
||||||
|
(event: React.MouseEvent) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
onClick();
|
||||||
|
},
|
||||||
|
[onClick]
|
||||||
|
);
|
||||||
const buttonContent = (
|
const buttonContent = (
|
||||||
<button
|
<button
|
||||||
aria-label={tooltipContent}
|
aria-label={tooltipContent}
|
||||||
@@ -120,7 +137,7 @@ export function CallingButton({
|
|||||||
)}
|
)}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
id={uniqueButtonId}
|
id={uniqueButtonId}
|
||||||
onClick={onClick}
|
onClick={handleClick}
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
onMouseLeave={onMouseLeave}
|
onMouseLeave={onMouseLeave}
|
||||||
type="button"
|
type="button"
|
||||||
|
@@ -51,6 +51,7 @@ const getCommonActiveCallData = (overrides: Overrides) => ({
|
|||||||
joinedAt: Date.now() - MINUTE,
|
joinedAt: Date.now() - MINUTE,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
pip: true,
|
pip: true,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
});
|
});
|
||||||
|
@@ -317,12 +317,17 @@ function getCallingShortcuts(i18n: LocalizerType): Array<ShortcutType> {
|
|||||||
keys: [['shift', 'V']],
|
keys: [['shift', 'V']],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'icu:Keyboard--accept-video-call',
|
id: 'Keyboard--toggle-preview',
|
||||||
|
description: i18n('icu:Keyboard--toggle-preview'),
|
||||||
|
keys: [['shift', 'P']],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'Keyboard--accept-video-call',
|
||||||
description: i18n('icu:Keyboard--accept-video-call'),
|
description: i18n('icu:Keyboard--accept-video-call'),
|
||||||
keys: [['ctrlOrAlt', 'shift', 'V']],
|
keys: [['ctrlOrAlt', 'shift', 'V']],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'icu:Keyboard--accept-call-without-video',
|
id: 'Keyboard--accept-call-without-video',
|
||||||
description: i18n('icu:Keyboard--accept-call-without-video'),
|
description: i18n('icu:Keyboard--accept-call-without-video'),
|
||||||
keys: [['ctrlOrAlt', 'shift', 'A']],
|
keys: [['ctrlOrAlt', 'shift', 'A']],
|
||||||
},
|
},
|
||||||
|
@@ -190,6 +190,7 @@ export type ActiveCallStateType = {
|
|||||||
pip: boolean;
|
pip: boolean;
|
||||||
presentingSource?: PresentedSource;
|
presentingSource?: PresentedSource;
|
||||||
presentingSourcesAvailable?: ReadonlyArray<PresentableSource>;
|
presentingSourcesAvailable?: ReadonlyArray<PresentableSource>;
|
||||||
|
selfViewExpanded: boolean;
|
||||||
settingsDialogOpen: boolean;
|
settingsDialogOpen: boolean;
|
||||||
showNeedsScreenRecordingPermissionsWarning?: boolean;
|
showNeedsScreenRecordingPermissionsWarning?: boolean;
|
||||||
showParticipantsList: boolean;
|
showParticipantsList: boolean;
|
||||||
@@ -659,6 +660,7 @@ const TOGGLE_NEEDS_SCREEN_RECORDING_PERMISSIONS =
|
|||||||
const START_DIRECT_CALL = 'calling/START_DIRECT_CALL';
|
const START_DIRECT_CALL = 'calling/START_DIRECT_CALL';
|
||||||
const TOGGLE_PARTICIPANTS = 'calling/TOGGLE_PARTICIPANTS';
|
const TOGGLE_PARTICIPANTS = 'calling/TOGGLE_PARTICIPANTS';
|
||||||
const TOGGLE_PIP = 'calling/TOGGLE_PIP';
|
const TOGGLE_PIP = 'calling/TOGGLE_PIP';
|
||||||
|
const TOGGLE_SELF_VIEW_EXPANDED = 'calling/TOGGLE_SELF_VIEW_EXPANDED';
|
||||||
const TOGGLE_SETTINGS = 'calling/TOGGLE_SETTINGS';
|
const TOGGLE_SETTINGS = 'calling/TOGGLE_SETTINGS';
|
||||||
const SWITCH_TO_PRESENTATION_VIEW = 'calling/SWITCH_TO_PRESENTATION_VIEW';
|
const SWITCH_TO_PRESENTATION_VIEW = 'calling/SWITCH_TO_PRESENTATION_VIEW';
|
||||||
const SWITCH_FROM_PRESENTATION_VIEW = 'calling/SWITCH_FROM_PRESENTATION_VIEW';
|
const SWITCH_FROM_PRESENTATION_VIEW = 'calling/SWITCH_FROM_PRESENTATION_VIEW';
|
||||||
@@ -941,9 +943,11 @@ type ToggleParticipantsActionType = ReadonlyDeep<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
type TogglePipActionType = ReadonlyDeep<{
|
type TogglePipActionType = ReadonlyDeep<{
|
||||||
type: 'calling/TOGGLE_PIP';
|
type: typeof TOGGLE_PIP;
|
||||||
|
}>;
|
||||||
|
type ToggleSelfViewExpandedActionType = ReadonlyDeep<{
|
||||||
|
type: typeof TOGGLE_SELF_VIEW_EXPANDED;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
type ToggleSettingsActionType = ReadonlyDeep<{
|
type ToggleSettingsActionType = ReadonlyDeep<{
|
||||||
type: 'calling/TOGGLE_SETTINGS';
|
type: 'calling/TOGGLE_SETTINGS';
|
||||||
}>;
|
}>;
|
||||||
@@ -1008,6 +1012,7 @@ export type CallingActionType =
|
|||||||
| ToggleNeedsScreenRecordingPermissionsActionType
|
| ToggleNeedsScreenRecordingPermissionsActionType
|
||||||
| ToggleParticipantsActionType
|
| ToggleParticipantsActionType
|
||||||
| TogglePipActionType
|
| TogglePipActionType
|
||||||
|
| ToggleSelfViewExpandedActionType
|
||||||
| SetPresentingFulfilledActionType
|
| SetPresentingFulfilledActionType
|
||||||
| ToggleSettingsActionType
|
| ToggleSettingsActionType
|
||||||
| SuggestLowerHandActionType
|
| SuggestLowerHandActionType
|
||||||
@@ -2665,6 +2670,12 @@ function togglePip(): TogglePipActionType {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleSelfViewExpanded(): ToggleSelfViewExpandedActionType {
|
||||||
|
return {
|
||||||
|
type: TOGGLE_SELF_VIEW_EXPANDED,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function toggleScreenRecordingPermissionsDialog(): ToggleNeedsScreenRecordingPermissionsActionType {
|
function toggleScreenRecordingPermissionsDialog(): ToggleNeedsScreenRecordingPermissionsActionType {
|
||||||
return {
|
return {
|
||||||
type: TOGGLE_NEEDS_SCREEN_RECORDING_PERMISSIONS,
|
type: TOGGLE_NEEDS_SCREEN_RECORDING_PERMISSIONS,
|
||||||
@@ -2757,6 +2768,7 @@ export const actions = {
|
|||||||
toggleParticipants,
|
toggleParticipants,
|
||||||
togglePip,
|
togglePip,
|
||||||
toggleScreenRecordingPermissionsDialog,
|
toggleScreenRecordingPermissionsDialog,
|
||||||
|
toggleSelfViewExpanded,
|
||||||
toggleSettings,
|
toggleSettings,
|
||||||
updateCallLinkName,
|
updateCallLinkName,
|
||||||
updateCallLinkRestrictions,
|
updateCallLinkRestrictions,
|
||||||
@@ -3052,6 +3064,7 @@ export function reducer(
|
|||||||
localAudioLevel: 0,
|
localAudioLevel: 0,
|
||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
outgoingRing,
|
outgoingRing,
|
||||||
@@ -3098,6 +3111,7 @@ export function reducer(
|
|||||||
localAudioLevel: 0,
|
localAudioLevel: 0,
|
||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
@@ -3130,6 +3144,7 @@ export function reducer(
|
|||||||
localAudioLevel: 0,
|
localAudioLevel: 0,
|
||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
outgoingRing: false,
|
outgoingRing: false,
|
||||||
@@ -3342,6 +3357,7 @@ export function reducer(
|
|||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
pip: false,
|
pip: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
joinedAt: null,
|
joinedAt: null,
|
||||||
@@ -4038,6 +4054,21 @@ export function reducer(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (action.type === TOGGLE_SELF_VIEW_EXPANDED) {
|
||||||
|
const { activeCallState } = state;
|
||||||
|
if (activeCallState?.state !== 'Active') {
|
||||||
|
log.warn('Cannot toggle PiP when there is no active call');
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
activeCallState: {
|
||||||
|
...activeCallState,
|
||||||
|
selfViewExpanded: !activeCallState.selfViewExpanded,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (action.type === SET_PRESENTING) {
|
if (action.type === SET_PRESENTING) {
|
||||||
const { activeCallState } = state;
|
const { activeCallState } = state;
|
||||||
|
@@ -181,6 +181,7 @@ const mapStateToActiveCallProp = (
|
|||||||
presentingSource: activeCallState.presentingSource,
|
presentingSource: activeCallState.presentingSource,
|
||||||
presentingSourcesAvailable: activeCallState.presentingSourcesAvailable,
|
presentingSourcesAvailable: activeCallState.presentingSourcesAvailable,
|
||||||
settingsDialogOpen: activeCallState.settingsDialogOpen,
|
settingsDialogOpen: activeCallState.settingsDialogOpen,
|
||||||
|
selfViewExpanded: activeCallState.selfViewExpanded,
|
||||||
showNeedsScreenRecordingPermissionsWarning: Boolean(
|
showNeedsScreenRecordingPermissionsWarning: Boolean(
|
||||||
activeCallState.showNeedsScreenRecordingPermissionsWarning
|
activeCallState.showNeedsScreenRecordingPermissionsWarning
|
||||||
),
|
),
|
||||||
@@ -465,6 +466,7 @@ export const SmartCallManager = memo(function SmartCallManager() {
|
|||||||
hangUpActiveCall,
|
hangUpActiveCall,
|
||||||
togglePip,
|
togglePip,
|
||||||
toggleScreenRecordingPermissionsDialog,
|
toggleScreenRecordingPermissionsDialog,
|
||||||
|
toggleSelfViewExpanded,
|
||||||
toggleSettings,
|
toggleSettings,
|
||||||
} = useCallingActions();
|
} = useCallingActions();
|
||||||
const { pauseVoiceNotePlayer } = useAudioPlayerActions();
|
const { pauseVoiceNotePlayer } = useAudioPlayerActions();
|
||||||
@@ -533,6 +535,7 @@ export const SmartCallManager = memo(function SmartCallManager() {
|
|||||||
toggleScreenRecordingPermissionsDialog={
|
toggleScreenRecordingPermissionsDialog={
|
||||||
toggleScreenRecordingPermissionsDialog
|
toggleScreenRecordingPermissionsDialog
|
||||||
}
|
}
|
||||||
|
toggleSelfViewExpanded={toggleSelfViewExpanded}
|
||||||
toggleSettings={toggleSettings}
|
toggleSettings={toggleSettings}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@@ -88,6 +88,7 @@ describe('calling duck', () => {
|
|||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
joinedAt: null,
|
joinedAt: null,
|
||||||
},
|
},
|
||||||
@@ -193,6 +194,7 @@ describe('calling duck', () => {
|
|||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
outgoingRing: false,
|
outgoingRing: false,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
joinedAt: null,
|
joinedAt: null,
|
||||||
};
|
};
|
||||||
@@ -495,6 +497,7 @@ describe('calling duck', () => {
|
|||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
outgoingRing: false,
|
outgoingRing: false,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
joinedAt: null,
|
joinedAt: null,
|
||||||
} satisfies ActiveCallStateType);
|
} satisfies ActiveCallStateType);
|
||||||
@@ -590,6 +593,7 @@ describe('calling duck', () => {
|
|||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
outgoingRing: false,
|
outgoingRing: false,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
joinedAt: null,
|
joinedAt: null,
|
||||||
} satisfies ActiveCallStateType);
|
} satisfies ActiveCallStateType);
|
||||||
@@ -1223,6 +1227,7 @@ describe('calling duck', () => {
|
|||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
outgoingRing: false,
|
outgoingRing: false,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
joinedAt: null,
|
joinedAt: null,
|
||||||
} satisfies ActiveCallStateType);
|
} satisfies ActiveCallStateType);
|
||||||
@@ -2310,6 +2315,7 @@ describe('calling duck', () => {
|
|||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
joinedAt: null,
|
joinedAt: null,
|
||||||
@@ -2588,6 +2594,7 @@ describe('calling duck', () => {
|
|||||||
joinedAt: null,
|
joinedAt: null,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
},
|
},
|
||||||
@@ -2631,6 +2638,7 @@ describe('calling duck', () => {
|
|||||||
joinedAt: null,
|
joinedAt: null,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
},
|
},
|
||||||
@@ -2675,6 +2683,7 @@ describe('calling duck', () => {
|
|||||||
joinedAt: null,
|
joinedAt: null,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
},
|
},
|
||||||
@@ -2709,6 +2718,7 @@ describe('calling duck', () => {
|
|||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
joinedAt: null,
|
joinedAt: null,
|
||||||
@@ -2735,6 +2745,7 @@ describe('calling duck', () => {
|
|||||||
joinedAt: null,
|
joinedAt: null,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
},
|
},
|
||||||
|
@@ -78,6 +78,7 @@ describe('state/selectors/calling', () => {
|
|||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
pip: false,
|
pip: false,
|
||||||
|
selfViewExpanded: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
joinedAt: null,
|
joinedAt: null,
|
||||||
},
|
},
|
||||||
|
@@ -57,6 +57,7 @@ export type ActiveCallBaseType = {
|
|||||||
presentingSource?: PresentedSource;
|
presentingSource?: PresentedSource;
|
||||||
presentingSourcesAvailable?: ReadonlyArray<PresentableSource>;
|
presentingSourcesAvailable?: ReadonlyArray<PresentableSource>;
|
||||||
settingsDialogOpen: boolean;
|
settingsDialogOpen: boolean;
|
||||||
|
selfViewExpanded: boolean;
|
||||||
showNeedsScreenRecordingPermissionsWarning?: boolean;
|
showNeedsScreenRecordingPermissionsWarning?: boolean;
|
||||||
showParticipantsList: boolean;
|
showParticipantsList: boolean;
|
||||||
reactions?: ActiveCallReactionsType;
|
reactions?: ActiveCallReactionsType;
|
||||||
|
Reference in New Issue
Block a user