)}
- {/* We render the local preview first and set the footer flex direction to row-reverse
- to ensure the preview is visible at low viewport widths. */}
+ {localPreviewNode}
+ {/* We set flex direction to row-reverse to render outward from local preview */}
- {localPreviewNode ? (
-
- {localPreviewNode}
- {!isSendingVideo && (
-
- )}
-
- {syncedLocalHandRaised && (
-
- )}
-
- ) : (
-
- )}
+
{
+ event.preventDefault();
+ event.stopPropagation();
+
+ onClick();
+ },
+ [onClick]
+ );
const buttonContent = (
({
joinedAt: Date.now() - MINUTE,
outgoingRing: true,
pip: true,
+ selfViewExpanded: false,
settingsDialogOpen: false,
showParticipantsList: false,
});
diff --git a/ts/components/ShortcutGuide.tsx b/ts/components/ShortcutGuide.tsx
index 76cfee542..c5dd52811 100644
--- a/ts/components/ShortcutGuide.tsx
+++ b/ts/components/ShortcutGuide.tsx
@@ -317,12 +317,17 @@ function getCallingShortcuts(i18n: LocalizerType): Array {
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'),
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'),
keys: [['ctrlOrAlt', 'shift', 'A']],
},
diff --git a/ts/state/ducks/calling.ts b/ts/state/ducks/calling.ts
index 0e755ca35..55edb952f 100644
--- a/ts/state/ducks/calling.ts
+++ b/ts/state/ducks/calling.ts
@@ -190,6 +190,7 @@ export type ActiveCallStateType = {
pip: boolean;
presentingSource?: PresentedSource;
presentingSourcesAvailable?: ReadonlyArray;
+ selfViewExpanded: boolean;
settingsDialogOpen: boolean;
showNeedsScreenRecordingPermissionsWarning?: boolean;
showParticipantsList: boolean;
@@ -659,6 +660,7 @@ const TOGGLE_NEEDS_SCREEN_RECORDING_PERMISSIONS =
const START_DIRECT_CALL = 'calling/START_DIRECT_CALL';
const TOGGLE_PARTICIPANTS = 'calling/TOGGLE_PARTICIPANTS';
const TOGGLE_PIP = 'calling/TOGGLE_PIP';
+const TOGGLE_SELF_VIEW_EXPANDED = 'calling/TOGGLE_SELF_VIEW_EXPANDED';
const TOGGLE_SETTINGS = 'calling/TOGGLE_SETTINGS';
const SWITCH_TO_PRESENTATION_VIEW = 'calling/SWITCH_TO_PRESENTATION_VIEW';
const SWITCH_FROM_PRESENTATION_VIEW = 'calling/SWITCH_FROM_PRESENTATION_VIEW';
@@ -941,9 +943,11 @@ type ToggleParticipantsActionType = 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: 'calling/TOGGLE_SETTINGS';
}>;
@@ -1008,6 +1012,7 @@ export type CallingActionType =
| ToggleNeedsScreenRecordingPermissionsActionType
| ToggleParticipantsActionType
| TogglePipActionType
+ | ToggleSelfViewExpandedActionType
| SetPresentingFulfilledActionType
| ToggleSettingsActionType
| SuggestLowerHandActionType
@@ -2665,6 +2670,12 @@ function togglePip(): TogglePipActionType {
};
}
+function toggleSelfViewExpanded(): ToggleSelfViewExpandedActionType {
+ return {
+ type: TOGGLE_SELF_VIEW_EXPANDED,
+ };
+}
+
function toggleScreenRecordingPermissionsDialog(): ToggleNeedsScreenRecordingPermissionsActionType {
return {
type: TOGGLE_NEEDS_SCREEN_RECORDING_PERMISSIONS,
@@ -2757,6 +2768,7 @@ export const actions = {
toggleParticipants,
togglePip,
toggleScreenRecordingPermissionsDialog,
+ toggleSelfViewExpanded,
toggleSettings,
updateCallLinkName,
updateCallLinkRestrictions,
@@ -3052,6 +3064,7 @@ export function reducer(
localAudioLevel: 0,
viewMode: CallViewMode.Paginated,
pip: false,
+ selfViewExpanded: false,
settingsDialogOpen: false,
showParticipantsList: false,
outgoingRing,
@@ -3098,6 +3111,7 @@ export function reducer(
localAudioLevel: 0,
viewMode: CallViewMode.Paginated,
pip: false,
+ selfViewExpanded: false,
settingsDialogOpen: false,
showParticipantsList: false,
outgoingRing: true,
@@ -3130,6 +3144,7 @@ export function reducer(
localAudioLevel: 0,
viewMode: CallViewMode.Paginated,
pip: false,
+ selfViewExpanded: false,
settingsDialogOpen: false,
showParticipantsList: false,
outgoingRing: false,
@@ -3342,6 +3357,7 @@ export function reducer(
viewMode: CallViewMode.Paginated,
pip: false,
settingsDialogOpen: false,
+ selfViewExpanded: false,
showParticipantsList: false,
outgoingRing: true,
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) {
const { activeCallState } = state;
diff --git a/ts/state/smart/CallManager.tsx b/ts/state/smart/CallManager.tsx
index c7160c138..7e7e442d8 100644
--- a/ts/state/smart/CallManager.tsx
+++ b/ts/state/smart/CallManager.tsx
@@ -181,6 +181,7 @@ const mapStateToActiveCallProp = (
presentingSource: activeCallState.presentingSource,
presentingSourcesAvailable: activeCallState.presentingSourcesAvailable,
settingsDialogOpen: activeCallState.settingsDialogOpen,
+ selfViewExpanded: activeCallState.selfViewExpanded,
showNeedsScreenRecordingPermissionsWarning: Boolean(
activeCallState.showNeedsScreenRecordingPermissionsWarning
),
@@ -465,6 +466,7 @@ export const SmartCallManager = memo(function SmartCallManager() {
hangUpActiveCall,
togglePip,
toggleScreenRecordingPermissionsDialog,
+ toggleSelfViewExpanded,
toggleSettings,
} = useCallingActions();
const { pauseVoiceNotePlayer } = useAudioPlayerActions();
@@ -533,6 +535,7 @@ export const SmartCallManager = memo(function SmartCallManager() {
toggleScreenRecordingPermissionsDialog={
toggleScreenRecordingPermissionsDialog
}
+ toggleSelfViewExpanded={toggleSelfViewExpanded}
toggleSettings={toggleSettings}
/>
);
diff --git a/ts/test-electron/state/ducks/calling_test.ts b/ts/test-electron/state/ducks/calling_test.ts
index 4b37cbad0..92cacc239 100644
--- a/ts/test-electron/state/ducks/calling_test.ts
+++ b/ts/test-electron/state/ducks/calling_test.ts
@@ -88,6 +88,7 @@ describe('calling duck', () => {
showParticipantsList: false,
outgoingRing: true,
pip: false,
+ selfViewExpanded: false,
settingsDialogOpen: false,
joinedAt: null,
},
@@ -193,6 +194,7 @@ describe('calling duck', () => {
showParticipantsList: false,
outgoingRing: false,
pip: false,
+ selfViewExpanded: false,
settingsDialogOpen: false,
joinedAt: null,
};
@@ -495,6 +497,7 @@ describe('calling duck', () => {
showParticipantsList: false,
outgoingRing: false,
pip: false,
+ selfViewExpanded: false,
settingsDialogOpen: false,
joinedAt: null,
} satisfies ActiveCallStateType);
@@ -590,6 +593,7 @@ describe('calling duck', () => {
showParticipantsList: false,
outgoingRing: false,
pip: false,
+ selfViewExpanded: false,
settingsDialogOpen: false,
joinedAt: null,
} satisfies ActiveCallStateType);
@@ -1223,6 +1227,7 @@ describe('calling duck', () => {
showParticipantsList: false,
outgoingRing: false,
pip: false,
+ selfViewExpanded: false,
settingsDialogOpen: false,
joinedAt: null,
} satisfies ActiveCallStateType);
@@ -2310,6 +2315,7 @@ describe('calling duck', () => {
viewMode: CallViewMode.Paginated,
showParticipantsList: false,
pip: false,
+ selfViewExpanded: false,
settingsDialogOpen: false,
outgoingRing: true,
joinedAt: null,
@@ -2588,6 +2594,7 @@ describe('calling duck', () => {
joinedAt: null,
outgoingRing: true,
pip: false,
+ selfViewExpanded: false,
settingsDialogOpen: false,
showParticipantsList: false,
},
@@ -2631,6 +2638,7 @@ describe('calling duck', () => {
joinedAt: null,
outgoingRing: true,
pip: false,
+ selfViewExpanded: false,
settingsDialogOpen: false,
showParticipantsList: false,
},
@@ -2675,6 +2683,7 @@ describe('calling duck', () => {
joinedAt: null,
outgoingRing: true,
pip: false,
+ selfViewExpanded: false,
settingsDialogOpen: false,
showParticipantsList: false,
},
@@ -2709,6 +2718,7 @@ describe('calling duck', () => {
viewMode: CallViewMode.Paginated,
showParticipantsList: false,
pip: false,
+ selfViewExpanded: false,
settingsDialogOpen: false,
outgoingRing: true,
joinedAt: null,
@@ -2735,6 +2745,7 @@ describe('calling duck', () => {
joinedAt: null,
outgoingRing: true,
pip: false,
+ selfViewExpanded: false,
settingsDialogOpen: false,
showParticipantsList: false,
},
diff --git a/ts/test-electron/state/selectors/calling_test.ts b/ts/test-electron/state/selectors/calling_test.ts
index a649445e7..5be2e5731 100644
--- a/ts/test-electron/state/selectors/calling_test.ts
+++ b/ts/test-electron/state/selectors/calling_test.ts
@@ -78,6 +78,7 @@ describe('state/selectors/calling', () => {
showParticipantsList: false,
outgoingRing: true,
pip: false,
+ selfViewExpanded: false,
settingsDialogOpen: false,
joinedAt: null,
},
diff --git a/ts/types/Calling.ts b/ts/types/Calling.ts
index f979e84d1..bcfee3276 100644
--- a/ts/types/Calling.ts
+++ b/ts/types/Calling.ts
@@ -57,6 +57,7 @@ export type ActiveCallBaseType = {
presentingSource?: PresentedSource;
presentingSourcesAvailable?: ReadonlyArray;
settingsDialogOpen: boolean;
+ selfViewExpanded: boolean;
showNeedsScreenRecordingPermissionsWarning?: boolean;
showParticipantsList: boolean;
reactions?: ActiveCallReactionsType;