signal-desktop/ts/components/CallingPip.stories.tsx

449 lines
13 KiB
TypeScript
Raw Normal View History

2023-01-03 11:55:46 -08:00
// Copyright 2020 Signal Messenger, LLC
2020-10-30 15:34:04 -05:00
// SPDX-License-Identifier: AGPL-3.0-only
2020-09-30 20:43:05 -04:00
import * as React from 'react';
import { times } from 'lodash';
2020-09-30 20:43:05 -04:00
import { action } from '@storybook/addon-actions';
import type { Meta } from '@storybook/react';
2021-05-28 12:15:17 -04:00
import { AvatarColors } from '../types/Colors';
import type { ConversationType } from '../state/ducks/conversations';
import type { PropsType } from './CallingPip';
import { CallingPip } from './CallingPip';
2022-11-17 16:45:19 -08:00
import type { ActiveDirectCallType } from '../types/Calling';
2020-11-17 10:07:53 -05:00
import {
CallViewMode,
2020-11-17 10:07:53 -05:00
CallState,
GroupCallConnectionState,
GroupCallJoinState,
} from '../types/Calling';
import { CallMode } from '../types/CallDisposition';
2021-05-07 17:21:10 -05:00
import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation';
2021-01-08 12:58:28 -06:00
import { fakeGetGroupCallVideoFrameSource } from '../test-both/helpers/fakeGetGroupCallVideoFrameSource';
import { MINUTE } from '../util/durations';
import type { SetRendererCanvasType } from '../state/ducks/calling';
import { createCallParticipant } from '../test-both/helpers/createCallParticipant';
2020-09-30 20:43:05 -04:00
2025-03-13 12:52:08 -07:00
const { i18n } = window.SignalContext;
2020-09-30 20:43:05 -04:00
const videoScreenshot = new Image(300, 400);
videoScreenshot.src = '../../fixtures/cat-screenshot-3x4.png';
const localPreviewVideo = document.createElement('video');
localPreviewVideo.autoplay = true;
localPreviewVideo.loop = true;
localPreviewVideo.src = '../../fixtures/pixabay-Soap-Bubble-7141.mp4';
2021-05-07 17:21:10 -05:00
const conversation: ConversationType = getDefaultConversation({
2020-10-07 21:25:33 -04:00
id: '3051234567',
2024-07-11 12:44:09 -07:00
avatarUrl: undefined,
2021-05-28 12:15:17 -04:00
color: AvatarColors[0],
2020-09-30 20:43:05 -04:00
title: 'Rick Sanchez',
name: 'Rick Sanchez',
phoneNumber: '3051234567',
profileName: 'Rick Sanchez',
2021-05-07 17:21:10 -05:00
});
2020-11-17 10:07:53 -05:00
type Overrides = {
hasLocalAudio?: boolean;
hasLocalVideo?: boolean;
localAudioLevel?: number;
viewMode?: CallViewMode;
};
const getCommonActiveCallData = (overrides: Overrides) => ({
2020-12-02 12:14:03 -06:00
conversation,
hasLocalAudio: overrides.hasLocalAudio ?? true,
hasLocalVideo: overrides.hasLocalVideo ?? true,
localAudioLevel: overrides.localAudioLevel ?? 0,
viewMode: overrides.viewMode ?? CallViewMode.Paginated,
joinedAt: Date.now() - MINUTE,
outgoingRing: true,
2020-12-02 12:14:03 -06:00
pip: true,
selfViewExpanded: false,
2020-12-02 12:14:03 -06:00
settingsDialogOpen: false,
showParticipantsList: false,
});
const getDefaultCall = (overrides: Overrides): ActiveDirectCallType => {
return {
...getCommonActiveCallData(overrides),
callMode: CallMode.Direct as CallMode.Direct,
callState: CallState.Accepted,
peekedParticipants: [],
hasRemoteAudio: true,
hasRemoteVideo: true,
2025-03-01 05:42:08 +10:00
remoteAudioLevel: 0,
remoteParticipants: [
{ hasRemoteVideo: true, presenting: false, title: 'Arsene' },
],
};
2020-09-30 20:43:05 -04:00
};
2022-06-06 20:48:02 -04:00
export default {
title: 'Components/CallingPip',
args: {
activeCall: getDefaultCall({}),
getGroupCallVideoFrameSource: fakeGetGroupCallVideoFrameSource,
hangUpActiveCall: action('hang-up-active-call'),
i18n,
me: getDefaultConversation({
name: 'Lonely InGroup',
title: 'Lonely InGroup',
}),
setGroupCallVideoRequest: action('set-group-call-video-request'),
setLocalPreviewContainer: (container: HTMLDivElement | null) => {
container?.appendChild(localPreviewVideo);
},
setRendererCanvas: ({ element }: SetRendererCanvasType) => {
element?.current?.getContext('2d')?.drawImage(videoScreenshot, 0, 0);
},
switchFromPresentationView: action('switch-to-presentation-view'),
switchToPresentationView: action('switch-to-presentation-view'),
toggleAudio: action('toggle-audio'),
togglePip: action('toggle-pip'),
toggleVideo: action('toggle-video'),
},
} satisfies Meta<PropsType>;
2020-09-30 20:43:05 -04:00
export function Default(args: PropsType): JSX.Element {
return <CallingPip {...args} />;
2022-11-17 16:45:19 -08:00
}
2020-10-07 21:25:33 -04:00
// Note: should NOT show speaking indicators
export function DefaultBothSpeaking(args: PropsType): JSX.Element {
return (
<CallingPip
{...args}
activeCall={{
...getDefaultCall({}),
remoteAudioLevel: 0.75,
localAudioLevel: 0.75,
}}
/>
);
}
// Note: should NOT show mute indicator for remote party
export function RemoteMuted(args: PropsType): JSX.Element {
return (
<CallingPip
{...args}
activeCall={{
...getDefaultCall({}),
hasRemoteAudio: false,
}}
/>
);
}
// Note: should NOT show show mute indicator in self preview
export function NoLocalAudio(args: PropsType): JSX.Element {
return (
<CallingPip
{...args}
activeCall={{
...getDefaultCall({
hasLocalAudio: false,
}),
}}
/>
);
}
export function NoLocalVideo(args: PropsType): JSX.Element {
return (
<CallingPip
{...args}
activeCall={{
...getDefaultCall({
hasLocalVideo: false,
}),
}}
/>
);
}
export function ContactWithAvatarAndNoVideo(args: PropsType): JSX.Element {
return (
<CallingPip
{...args}
activeCall={{
...getDefaultCall({}),
conversation: {
...conversation,
2024-07-11 12:44:09 -07:00
avatarUrl: 'https://www.fillmurray.com/64/64',
},
remoteParticipants: [
{ hasRemoteVideo: false, presenting: false, title: 'Julian' },
],
}}
/>
);
2022-11-17 16:45:19 -08:00
}
2022-06-06 20:48:02 -04:00
export function ContactNoColor(args: PropsType): JSX.Element {
return (
<CallingPip
{...args}
activeCall={{
...getDefaultCall({}),
conversation: {
...conversation,
color: undefined,
},
}}
/>
);
2022-11-17 16:45:19 -08:00
}
2022-06-06 20:48:02 -04:00
export function LonelyInGroupCall(args: PropsType): JSX.Element {
return (
<CallingPip
{...args}
activeCall={{
...getCommonActiveCallData({}),
callMode: CallMode.Group as CallMode.Group,
connectionState: GroupCallConnectionState.Connected,
2023-11-16 11:55:35 -08:00
conversationsByDemuxId: new Map<number, ConversationType>(),
groupMembers: times(3, () => getDefaultConversation()),
isConversationTooBigToRing: false,
joinState: GroupCallJoinState.Joined,
2023-11-16 11:55:35 -08:00
localDemuxId: 1,
maxDevices: 5,
deviceCount: 0,
peekedParticipants: [],
pendingParticipants: [],
2023-12-06 13:52:29 -08:00
raisedHands: new Set<number>(),
remoteParticipants: [],
remoteAudioLevels: new Map<number, number>(),
suggestLowerHand: false,
}}
/>
);
2022-11-17 16:45:19 -08:00
}
export function LonelyInGroupCallVideoDisabled(args: PropsType): JSX.Element {
return (
<CallingPip
{...args}
activeCall={{
...getCommonActiveCallData({
hasLocalVideo: false,
}),
callMode: CallMode.Group as CallMode.Group,
connectionState: GroupCallConnectionState.Connected,
conversationsByDemuxId: new Map<number, ConversationType>(),
groupMembers: times(3, () => getDefaultConversation()),
isConversationTooBigToRing: false,
joinState: GroupCallJoinState.Joined,
localDemuxId: 1,
maxDevices: 5,
deviceCount: 0,
peekedParticipants: [],
pendingParticipants: [],
raisedHands: new Set<number>(),
remoteParticipants: [],
remoteAudioLevels: new Map<number, number>(),
suggestLowerHand: false,
}}
/>
);
}
export function GroupCall(args: PropsType): JSX.Element {
return (
<CallingPip
{...args}
activeCall={{
...getCommonActiveCallData({}),
callMode: CallMode.Group as CallMode.Group,
connectionState: GroupCallConnectionState.Connected,
conversationsByDemuxId: new Map<number, ConversationType>(),
groupMembers: times(3, () => getDefaultConversation()),
isConversationTooBigToRing: false,
joinState: GroupCallJoinState.Joined,
localDemuxId: 1,
maxDevices: 5,
deviceCount: 0,
peekedParticipants: [],
pendingParticipants: [],
raisedHands: new Set<number>(),
remoteParticipants: [
createCallParticipant({}),
createCallParticipant({}),
],
remoteAudioLevels: new Map<number, number>(),
suggestLowerHand: false,
}}
/>
);
}
export function GroupCallWithRaisedHands(args: PropsType): JSX.Element {
return (
<CallingPip
{...args}
activeCall={{
...getCommonActiveCallData({}),
callMode: CallMode.Group as CallMode.Group,
connectionState: GroupCallConnectionState.Connected,
conversationsByDemuxId: new Map<number, ConversationType>(),
groupMembers: times(3, () => getDefaultConversation()),
isConversationTooBigToRing: false,
joinState: GroupCallJoinState.Joined,
localDemuxId: 1,
maxDevices: 5,
deviceCount: 0,
peekedParticipants: [],
pendingParticipants: [],
raisedHands: new Set<number>([1, 2, 3]),
remoteParticipants: [
createCallParticipant({}),
createCallParticipant({}),
],
remoteAudioLevels: new Map<number, number>(),
suggestLowerHand: false,
}}
/>
);
}
export function GroupCallWithPendingParticipants(args: PropsType): JSX.Element {
return (
<CallingPip
{...args}
activeCall={{
...getCommonActiveCallData({}),
callMode: CallMode.Group as CallMode.Group,
connectionState: GroupCallConnectionState.Connected,
conversationsByDemuxId: new Map<number, ConversationType>(),
groupMembers: times(3, () => getDefaultConversation()),
isConversationTooBigToRing: false,
joinState: GroupCallJoinState.Joined,
localDemuxId: 1,
maxDevices: 5,
deviceCount: 0,
peekedParticipants: [],
pendingParticipants: [
getDefaultConversation(),
getDefaultConversation(),
],
raisedHands: new Set<number>(),
remoteParticipants: [
createCallParticipant({}),
createCallParticipant({}),
],
remoteAudioLevels: new Map<number, number>(),
suggestLowerHand: false,
}}
/>
);
}
export function GroupCallWithPendingAndRaised(args: PropsType): JSX.Element {
return (
<CallingPip
{...args}
activeCall={{
...getCommonActiveCallData({}),
callMode: CallMode.Group as CallMode.Group,
connectionState: GroupCallConnectionState.Connected,
conversationsByDemuxId: new Map<number, ConversationType>(),
groupMembers: times(3, () => getDefaultConversation()),
isConversationTooBigToRing: false,
joinState: GroupCallJoinState.Joined,
localDemuxId: 1,
maxDevices: 5,
deviceCount: 0,
peekedParticipants: [],
pendingParticipants: [
getDefaultConversation(),
getDefaultConversation(),
],
raisedHands: new Set<number>([1, 2, 3]),
remoteParticipants: [
createCallParticipant({}),
createCallParticipant({}),
],
remoteAudioLevels: new Map<number, number>(),
suggestLowerHand: false,
}}
/>
);
}
// Note: should NOT show muted indicator for remote party
export function GroupCallRemoteMuted(args: PropsType): JSX.Element {
return (
<CallingPip
{...args}
activeCall={{
...getCommonActiveCallData({}),
callMode: CallMode.Group as CallMode.Group,
connectionState: GroupCallConnectionState.Connected,
conversationsByDemuxId: new Map<number, ConversationType>(),
groupMembers: times(3, () => getDefaultConversation()),
isConversationTooBigToRing: false,
joinState: GroupCallJoinState.Joined,
localDemuxId: 1,
maxDevices: 5,
deviceCount: 0,
peekedParticipants: [],
pendingParticipants: [
getDefaultConversation(),
getDefaultConversation(),
],
raisedHands: new Set<number>([1, 2, 3]),
remoteParticipants: [
{
...createCallParticipant({}),
demuxId: 1,
hasRemoteAudio: false,
hasRemoteVideo: true,
mediaKeysReceived: true,
},
],
remoteAudioLevels: new Map<number, number>(),
suggestLowerHand: false,
}}
/>
);
}
// Note: should NOT show speaking indicator
export function GroupCallRemoteSpeaking(args: PropsType): JSX.Element {
return (
<CallingPip
{...args}
activeCall={{
...getCommonActiveCallData({}),
callMode: CallMode.Group as CallMode.Group,
connectionState: GroupCallConnectionState.Connected,
conversationsByDemuxId: new Map<number, ConversationType>(),
groupMembers: times(3, () => getDefaultConversation()),
isConversationTooBigToRing: false,
joinState: GroupCallJoinState.Joined,
localDemuxId: 1,
maxDevices: 5,
deviceCount: 0,
peekedParticipants: [],
pendingParticipants: [
getDefaultConversation(),
getDefaultConversation(),
],
raisedHands: new Set<number>([1, 2, 3]),
remoteParticipants: [
{
...createCallParticipant({}),
demuxId: 1,
hasRemoteAudio: true,
hasRemoteVideo: true,
mediaKeysReceived: true,
},
],
remoteAudioLevels: new Map<number, number>([[1, 0.75]]),
suggestLowerHand: false,
}}
/>
);
}