Handles safety number changes while in a call
This commit is contained in:
parent
561baf6309
commit
318013e83d
26 changed files with 387 additions and 162 deletions
|
@ -425,6 +425,10 @@
|
|||
"message": "Call Anyway",
|
||||
"description": "Used on a warning dialog to make it clear that it might be risky to call the conversation."
|
||||
},
|
||||
"continueCall": {
|
||||
"message": "Continue Call",
|
||||
"description": "Used on a warning dialog to make it clear that it might be risky to continue the group call."
|
||||
},
|
||||
"noLongerVerified": {
|
||||
"message": "Your safety number with $name$ has changed and is no longer verified. Click to show.",
|
||||
"description": "Shown in conversation banner when user's safety number has changed, but they were previously verified.",
|
||||
|
|
|
@ -904,7 +904,7 @@
|
|||
// state we had before.
|
||||
return false;
|
||||
},
|
||||
async isUntrusted(identifier) {
|
||||
isUntrusted(identifier) {
|
||||
if (identifier === null || identifier === undefined) {
|
||||
throw new Error('Tried to set verified for undefined/null key');
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@ import {
|
|||
} from '../types/Calling';
|
||||
import { ConversationTypeType } from '../state/ducks/conversations';
|
||||
import { Colors, ColorType } from '../types/Colors';
|
||||
import { getDefaultConversation } from '../util/getDefaultConversation';
|
||||
import { setup as setupI18n } from '../../js/modules/i18n';
|
||||
import { Props as SafetyNumberViewerProps } from '../state/smart/SafetyNumberViewer';
|
||||
import enMessages from '../../_locales/en/messages.json';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
@ -68,12 +70,16 @@ const createProps = (storyProps: Partial<PropsType> = {}): PropsType => ({
|
|||
getGroupCallVideoFrameSource: noop as any,
|
||||
hangUp: action('hang-up'),
|
||||
i18n,
|
||||
keyChangeOk: action('key-change-ok'),
|
||||
me: {
|
||||
...getDefaultConversation({
|
||||
color: select('Caller color', Colors, 'ultramarine' as ColorType),
|
||||
title: text('Caller Title', 'Morty Smith'),
|
||||
}),
|
||||
uuid: 'cb0dd0c8-7393-41e9-a0aa-d631c4109541',
|
||||
color: select('Caller color', Colors, 'ultramarine' as ColorType),
|
||||
title: text('Caller Title', 'Morty Smith'),
|
||||
},
|
||||
renderDeviceSelection: () => <div />,
|
||||
renderSafetyNumberViewer: (_: SafetyNumberViewerProps) => <div />,
|
||||
setGroupCallVideoRequest: action('set-group-call-video-request'),
|
||||
setLocalAudio: action('set-local-audio'),
|
||||
setLocalPreview: action('set-local-preview'),
|
||||
|
@ -110,6 +116,7 @@ story.add('Ongoing Group Call', () => (
|
|||
...getCommonActiveCallData(),
|
||||
callMode: CallMode.Group,
|
||||
connectionState: GroupCallConnectionState.Connected,
|
||||
conversationsWithSafetyNumberChanges: [],
|
||||
deviceCount: 0,
|
||||
joinState: GroupCallJoinState.Joined,
|
||||
maxDevices: 5,
|
||||
|
@ -145,3 +152,27 @@ story.add('Call Request Needed', () => (
|
|||
})}
|
||||
/>
|
||||
));
|
||||
|
||||
story.add('Group call - Safety Number Changed', () => (
|
||||
<CallManager
|
||||
{...createProps({
|
||||
activeCall: {
|
||||
...getCommonActiveCallData(),
|
||||
callMode: CallMode.Group,
|
||||
connectionState: GroupCallConnectionState.Connected,
|
||||
conversationsWithSafetyNumberChanges: [
|
||||
{
|
||||
...getDefaultConversation({
|
||||
title: 'Aaron',
|
||||
}),
|
||||
},
|
||||
],
|
||||
deviceCount: 0,
|
||||
joinState: GroupCallJoinState.Joined,
|
||||
maxDevices: 5,
|
||||
peekedParticipants: [],
|
||||
remoteParticipants: [],
|
||||
},
|
||||
})}
|
||||
/>
|
||||
));
|
||||
|
|
|
@ -8,6 +8,10 @@ import { CallingLobby } from './CallingLobby';
|
|||
import { CallingParticipantsList } from './CallingParticipantsList';
|
||||
import { CallingPip } from './CallingPip';
|
||||
import { IncomingCallBar } from './IncomingCallBar';
|
||||
import {
|
||||
SafetyNumberChangeDialog,
|
||||
SafetyNumberProps,
|
||||
} from './SafetyNumberChangeDialog';
|
||||
import {
|
||||
ActiveCallType,
|
||||
CallEndedReason,
|
||||
|
@ -24,6 +28,7 @@ import {
|
|||
DeclineCallType,
|
||||
DirectCallStateType,
|
||||
HangUpType,
|
||||
KeyChangeOkType,
|
||||
SetGroupCallVideoRequestType,
|
||||
SetLocalAudioType,
|
||||
SetLocalPreviewType,
|
||||
|
@ -32,9 +37,12 @@ import {
|
|||
StartCallType,
|
||||
} from '../state/ducks/calling';
|
||||
import { LocalizerType } from '../types/Util';
|
||||
import { ColorType } from '../types/Colors';
|
||||
import { missingCaseError } from '../util/missingCaseError';
|
||||
|
||||
interface MeType extends ConversationType {
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export interface PropsType {
|
||||
activeCall?: ActiveCallType;
|
||||
availableCameras: Array<MediaDeviceInfo>;
|
||||
|
@ -48,21 +56,15 @@ export interface PropsType {
|
|||
call: DirectCallStateType;
|
||||
conversation: ConversationType;
|
||||
};
|
||||
keyChangeOk: (_: KeyChangeOkType) => void;
|
||||
renderDeviceSelection: () => JSX.Element;
|
||||
renderSafetyNumberViewer: (props: SafetyNumberProps) => JSX.Element;
|
||||
startCall: (payload: StartCallType) => void;
|
||||
toggleParticipants: () => void;
|
||||
acceptCall: (_: AcceptCallType) => void;
|
||||
declineCall: (_: DeclineCallType) => void;
|
||||
i18n: LocalizerType;
|
||||
me: {
|
||||
avatarPath?: string;
|
||||
color?: ColorType;
|
||||
name?: string;
|
||||
phoneNumber?: string;
|
||||
profileName?: string;
|
||||
title: string;
|
||||
uuid: string;
|
||||
};
|
||||
me: MeType;
|
||||
setGroupCallVideoRequest: (_: SetGroupCallVideoRequestType) => void;
|
||||
setLocalAudio: (_: SetLocalAudioType) => void;
|
||||
setLocalVideo: (_: SetLocalVideoType) => void;
|
||||
|
@ -84,9 +86,11 @@ const ActiveCallManager: React.FC<ActiveCallManagerPropsType> = ({
|
|||
closeNeedPermissionScreen,
|
||||
hangUp,
|
||||
i18n,
|
||||
keyChangeOk,
|
||||
getGroupCallVideoFrameSource,
|
||||
me,
|
||||
renderDeviceSelection,
|
||||
renderSafetyNumberViewer,
|
||||
setGroupCallVideoRequest,
|
||||
setLocalAudio,
|
||||
setLocalPreview,
|
||||
|
@ -203,6 +207,7 @@ const ActiveCallManager: React.FC<ActiveCallManagerPropsType> = ({
|
|||
<CallingParticipantsList
|
||||
i18n={i18n}
|
||||
onClose={toggleParticipants}
|
||||
ourUuid={me.uuid}
|
||||
participants={peekedParticipants}
|
||||
/>
|
||||
) : null}
|
||||
|
@ -233,13 +238,11 @@ const ActiveCallManager: React.FC<ActiveCallManagerPropsType> = ({
|
|||
...participant,
|
||||
hasAudio: participant.hasRemoteAudio,
|
||||
hasVideo: participant.hasRemoteVideo,
|
||||
isSelf: false,
|
||||
})),
|
||||
{
|
||||
...me,
|
||||
hasAudio: hasLocalAudio,
|
||||
hasVideo: hasLocalVideo,
|
||||
isSelf: true,
|
||||
},
|
||||
]
|
||||
: [];
|
||||
|
@ -268,9 +271,25 @@ const ActiveCallManager: React.FC<ActiveCallManagerPropsType> = ({
|
|||
<CallingParticipantsList
|
||||
i18n={i18n}
|
||||
onClose={toggleParticipants}
|
||||
ourUuid={me.uuid}
|
||||
participants={groupCallParticipantsForParticipantsList}
|
||||
/>
|
||||
) : null}
|
||||
{activeCall.callMode === CallMode.Group &&
|
||||
activeCall.conversationsWithSafetyNumberChanges.length ? (
|
||||
<SafetyNumberChangeDialog
|
||||
confirmText={i18n('continueCall')}
|
||||
contacts={activeCall.conversationsWithSafetyNumberChanges}
|
||||
i18n={i18n}
|
||||
onCancel={() => {
|
||||
hangUp({ conversationId: activeCall.conversation.id });
|
||||
}}
|
||||
onConfirm={() => {
|
||||
keyChangeOk({ conversationId: activeCall.conversation.id });
|
||||
}}
|
||||
renderSafetyNumber={renderSafetyNumberViewer}
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -12,13 +12,14 @@ import {
|
|||
CallState,
|
||||
GroupCallConnectionState,
|
||||
GroupCallJoinState,
|
||||
GroupCallPeekedParticipantType,
|
||||
GroupCallRemoteParticipantType,
|
||||
} from '../types/Calling';
|
||||
import { ConversationType } from '../state/ducks/conversations';
|
||||
import { Colors } from '../types/Colors';
|
||||
import { CallScreen, PropsType } from './CallScreen';
|
||||
import { setup as setupI18n } from '../../js/modules/i18n';
|
||||
import { missingCaseError } from '../util/missingCaseError';
|
||||
import { getDefaultConversation } from '../util/getDefaultConversation';
|
||||
import enMessages from '../../_locales/en/messages.json';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
@ -50,7 +51,7 @@ interface DirectCallOverrideProps extends OverridePropsBase {
|
|||
interface GroupCallOverrideProps extends OverridePropsBase {
|
||||
callMode: CallMode.Group;
|
||||
connectionState?: GroupCallConnectionState;
|
||||
peekedParticipants?: Array<GroupCallPeekedParticipantType>;
|
||||
peekedParticipants?: Array<ConversationType>;
|
||||
remoteParticipants?: Array<GroupCallRemoteParticipantType>;
|
||||
}
|
||||
|
||||
|
@ -83,6 +84,7 @@ const createActiveGroupCallProp = (overrideProps: GroupCallOverrideProps) => ({
|
|||
callMode: CallMode.Group as CallMode.Group,
|
||||
connectionState:
|
||||
overrideProps.connectionState || GroupCallConnectionState.Connected,
|
||||
conversationsWithSafetyNumberChanges: [],
|
||||
joinState: GroupCallJoinState.Joined,
|
||||
maxDevices: 5,
|
||||
deviceCount: (overrideProps.remoteParticipants || []).length,
|
||||
|
@ -240,14 +242,15 @@ story.add('Group call - 1', () => (
|
|||
callMode: CallMode.Group,
|
||||
remoteParticipants: [
|
||||
{
|
||||
uuid: '72fa60e5-25fb-472d-8a56-e56867c57dda',
|
||||
demuxId: 0,
|
||||
hasRemoteAudio: true,
|
||||
hasRemoteVideo: true,
|
||||
isBlocked: false,
|
||||
isSelf: false,
|
||||
title: 'Tyler',
|
||||
videoAspectRatio: 1.3,
|
||||
...getDefaultConversation({
|
||||
isBlocked: false,
|
||||
uuid: '72fa60e5-25fb-472d-8a56-e56867c57dda',
|
||||
title: 'Tyler',
|
||||
}),
|
||||
},
|
||||
],
|
||||
})}
|
||||
|
@ -260,34 +263,37 @@ story.add('Group call - Many', () => (
|
|||
callMode: CallMode.Group,
|
||||
remoteParticipants: [
|
||||
{
|
||||
uuid: '094586f5-8fc2-4ce2-a152-2dfcc99f4630',
|
||||
demuxId: 0,
|
||||
hasRemoteAudio: true,
|
||||
hasRemoteVideo: true,
|
||||
isBlocked: false,
|
||||
isSelf: false,
|
||||
title: 'Amy',
|
||||
videoAspectRatio: 1.3,
|
||||
...getDefaultConversation({
|
||||
isBlocked: false,
|
||||
title: 'Amy',
|
||||
uuid: '094586f5-8fc2-4ce2-a152-2dfcc99f4630',
|
||||
}),
|
||||
},
|
||||
{
|
||||
uuid: 'cb5bdb24-4cbb-4650-8a7a-1a2807051e74',
|
||||
demuxId: 1,
|
||||
hasRemoteAudio: true,
|
||||
hasRemoteVideo: true,
|
||||
isBlocked: false,
|
||||
isSelf: true,
|
||||
title: 'Bob',
|
||||
videoAspectRatio: 1.3,
|
||||
...getDefaultConversation({
|
||||
isBlocked: false,
|
||||
title: 'Bob',
|
||||
uuid: 'cb5bdb24-4cbb-4650-8a7a-1a2807051e74',
|
||||
}),
|
||||
},
|
||||
{
|
||||
uuid: '2d7d13ae-53dc-4a51-8dc7-976cd85e0b57',
|
||||
demuxId: 2,
|
||||
hasRemoteAudio: true,
|
||||
hasRemoteVideo: true,
|
||||
isBlocked: true,
|
||||
isSelf: false,
|
||||
title: 'Alice',
|
||||
videoAspectRatio: 1.3,
|
||||
...getDefaultConversation({
|
||||
isBlocked: true,
|
||||
title: 'Alice',
|
||||
uuid: '2d7d13ae-53dc-4a51-8dc7-976cd85e0b57',
|
||||
}),
|
||||
},
|
||||
],
|
||||
})}
|
||||
|
@ -301,14 +307,15 @@ story.add('Group call - reconnecting', () => (
|
|||
connectionState: GroupCallConnectionState.Reconnecting,
|
||||
remoteParticipants: [
|
||||
{
|
||||
uuid: '33871c64-0c22-45ce-8aa4-0ec237ac4a31',
|
||||
demuxId: 0,
|
||||
hasRemoteAudio: true,
|
||||
hasRemoteVideo: true,
|
||||
isBlocked: false,
|
||||
isSelf: false,
|
||||
title: 'Tyler',
|
||||
videoAspectRatio: 1.3,
|
||||
...getDefaultConversation({
|
||||
isBlocked: false,
|
||||
title: 'Tyler',
|
||||
uuid: '33871c64-0c22-45ce-8aa4-0ec237ac4a31',
|
||||
}),
|
||||
},
|
||||
],
|
||||
})}
|
||||
|
|
|
@ -11,6 +11,7 @@ import { ColorType } from '../types/Colors';
|
|||
import { CallingLobby, PropsType } from './CallingLobby';
|
||||
import { setup as setupI18n } from '../../js/modules/i18n';
|
||||
import enMessages from '../../_locales/en/messages.json';
|
||||
import { getDefaultConversation } from '../util/getDefaultConversation';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
|
@ -33,7 +34,10 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
|||
hasLocalVideo: boolean('hasLocalVideo', overrideProps.hasLocalVideo || false),
|
||||
i18n,
|
||||
isGroupCall: boolean('isGroupCall', overrideProps.isGroupCall || false),
|
||||
me: overrideProps.me || { color: 'ultramarine' as ColorType },
|
||||
me: overrideProps.me || {
|
||||
color: 'ultramarine' as ColorType,
|
||||
uuid: generateUuid(),
|
||||
},
|
||||
onCallCanceled: action('on-call-canceled'),
|
||||
onJoinCall: action('on-join-call'),
|
||||
peekedParticipants: overrideProps.peekedParticipants || [],
|
||||
|
@ -48,11 +52,11 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
|||
toggleSettings: action('toggle-settings'),
|
||||
});
|
||||
|
||||
const fakePeekedParticipant = (title: string) => ({
|
||||
isSelf: false,
|
||||
title,
|
||||
uuid: generateUuid(),
|
||||
});
|
||||
const fakePeekedParticipant = (title: string) =>
|
||||
getDefaultConversation({
|
||||
title,
|
||||
uuid: generateUuid(),
|
||||
});
|
||||
|
||||
const story = storiesOf('Components/CallingLobby', module);
|
||||
|
||||
|
@ -72,8 +76,9 @@ story.add('No Camera, local avatar', () => {
|
|||
const props = createProps({
|
||||
availableCameras: [],
|
||||
me: {
|
||||
color: 'ultramarine' as ColorType,
|
||||
avatarPath: '/fixtures/kitten-4-112-112.jpg',
|
||||
color: 'ultramarine' as ColorType,
|
||||
uuid: generateUuid(),
|
||||
},
|
||||
});
|
||||
return <CallingLobby {...props} />;
|
||||
|
|
|
@ -14,6 +14,7 @@ import { CallingHeader } from './CallingHeader';
|
|||
import { Spinner } from './Spinner';
|
||||
import { ColorType } from '../types/Colors';
|
||||
import { LocalizerType } from '../types/Util';
|
||||
import { ConversationType } from '../state/ducks/conversations';
|
||||
|
||||
export type PropsType = {
|
||||
availableCameras: Array<MediaDeviceInfo>;
|
||||
|
@ -28,15 +29,11 @@ export type PropsType = {
|
|||
me: {
|
||||
avatarPath?: string;
|
||||
color?: ColorType;
|
||||
uuid: string;
|
||||
};
|
||||
onCallCanceled: () => void;
|
||||
onJoinCall: () => void;
|
||||
peekedParticipants: Array<{
|
||||
firstName?: string;
|
||||
isSelf: boolean;
|
||||
title: string;
|
||||
uuid: string;
|
||||
}>;
|
||||
peekedParticipants: Array<ConversationType>;
|
||||
setLocalAudio: (_: SetLocalAudioType) => void;
|
||||
setLocalVideo: (_: SetLocalVideoType) => void;
|
||||
setLocalPreview: (_: SetLocalPreviewType) => void;
|
||||
|
@ -124,7 +121,7 @@ export const CallingLobby = ({
|
|||
// device.
|
||||
// TODO: Improve the "it's you" case; see DESKTOP-926.
|
||||
const participantNames = peekedParticipants.map(participant =>
|
||||
participant.isSelf
|
||||
participant.uuid === me.uuid
|
||||
? i18n('you')
|
||||
: participant.firstName || participant.title
|
||||
);
|
||||
|
|
|
@ -9,6 +9,7 @@ import { v4 as generateUuid } from 'uuid';
|
|||
import { CallingParticipantsList, PropsType } from './CallingParticipantsList';
|
||||
import { Colors } from '../types/Colors';
|
||||
import { GroupCallRemoteParticipantType } from '../types/Calling';
|
||||
import { getDefaultConversation } from '../util/getDefaultConversation';
|
||||
import { setup as setupI18n } from '../../js/modules/i18n';
|
||||
import enMessages from '../../_locales/en/messages.json';
|
||||
|
||||
|
@ -19,24 +20,26 @@ function createParticipant(
|
|||
): GroupCallRemoteParticipantType {
|
||||
const randomColor = Math.floor(Math.random() * Colors.length - 1);
|
||||
return {
|
||||
avatarPath: participantProps.avatarPath,
|
||||
color: Colors[randomColor],
|
||||
demuxId: 2,
|
||||
hasRemoteAudio: Boolean(participantProps.hasRemoteAudio),
|
||||
hasRemoteVideo: Boolean(participantProps.hasRemoteVideo),
|
||||
isBlocked: Boolean(participantProps.isBlocked),
|
||||
isSelf: Boolean(participantProps.isSelf),
|
||||
name: participantProps.name,
|
||||
profileName: participantProps.title,
|
||||
title: String(participantProps.title),
|
||||
videoAspectRatio: 1.3,
|
||||
uuid: generateUuid(),
|
||||
...getDefaultConversation({
|
||||
avatarPath: participantProps.avatarPath,
|
||||
color: Colors[randomColor],
|
||||
isBlocked: Boolean(participantProps.isBlocked),
|
||||
name: participantProps.name,
|
||||
profileName: participantProps.title,
|
||||
title: String(participantProps.title),
|
||||
uuid: generateUuid(),
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
||||
i18n,
|
||||
onClose: action('on-close'),
|
||||
ourUuid: 'cf085e6a-e70b-41ec-a310-c198248af13f',
|
||||
participants: overrideProps.participants || [],
|
||||
});
|
||||
|
||||
|
@ -62,7 +65,6 @@ story.add('Many Participants', () => {
|
|||
const props = createProps({
|
||||
participants: [
|
||||
createParticipant({
|
||||
isSelf: true,
|
||||
title: 'Son Goku',
|
||||
}),
|
||||
createParticipant({
|
||||
|
|
|
@ -9,10 +9,10 @@ import { Avatar } from './Avatar';
|
|||
import { ContactName } from './conversation/ContactName';
|
||||
import { InContactsIcon } from './InContactsIcon';
|
||||
import { LocalizerType } from '../types/Util';
|
||||
import { GroupCallPeekedParticipantType } from '../types/Calling';
|
||||
import { sortByTitle } from '../util/sortByTitle';
|
||||
import { ConversationType } from '../state/ducks/conversations';
|
||||
|
||||
interface ParticipantType extends GroupCallPeekedParticipantType {
|
||||
interface ParticipantType extends ConversationType {
|
||||
hasAudio?: boolean;
|
||||
hasVideo?: boolean;
|
||||
}
|
||||
|
@ -20,11 +20,12 @@ interface ParticipantType extends GroupCallPeekedParticipantType {
|
|||
export type PropsType = {
|
||||
readonly i18n: LocalizerType;
|
||||
readonly onClose: () => void;
|
||||
readonly ourUuid: string;
|
||||
readonly participants: Array<ParticipantType>;
|
||||
};
|
||||
|
||||
export const CallingParticipantsList = React.memo(
|
||||
({ i18n, onClose, participants }: PropsType) => {
|
||||
({ i18n, onClose, ourUuid, participants }: PropsType) => {
|
||||
const [root, setRoot] = React.useState<HTMLElement | null>(null);
|
||||
|
||||
const sortedParticipants = React.useMemo<Array<ParticipantType>>(
|
||||
|
@ -100,7 +101,7 @@ export const CallingParticipantsList = React.memo(
|
|||
title={participant.title}
|
||||
size={32}
|
||||
/>
|
||||
{participant.isSelf ? (
|
||||
{participant.uuid === ourUuid ? (
|
||||
<span className="module-calling-participants-list__name">
|
||||
{i18n('you')}
|
||||
</span>
|
||||
|
|
|
@ -105,6 +105,7 @@ story.add('Group Call', () => {
|
|||
...getCommonActiveCallData(),
|
||||
callMode: CallMode.Group as CallMode.Group,
|
||||
connectionState: GroupCallConnectionState.Connected,
|
||||
conversationsWithSafetyNumberChanges: [],
|
||||
joinState: GroupCallJoinState.Joined,
|
||||
maxDevices: 5,
|
||||
deviceCount: 0,
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
GroupCallRemoteParticipant,
|
||||
PropsType,
|
||||
} from './GroupCallRemoteParticipant';
|
||||
import { getDefaultConversation } from '../util/getDefaultConversation';
|
||||
import { setup as setupI18n } from '../../js/modules/i18n';
|
||||
import enMessages from '../../_locales/en/messages.json';
|
||||
|
||||
|
@ -37,12 +38,13 @@ const createProps = (
|
|||
demuxId: 123,
|
||||
hasRemoteAudio: false,
|
||||
hasRemoteVideo: true,
|
||||
isBlocked: Boolean(isBlocked),
|
||||
isSelf: false,
|
||||
title:
|
||||
'Pablo Diego José Francisco de Paula Juan Nepomuceno María de los Remedios Cipriano de la Santísima Trinidad Ruiz y Picasso',
|
||||
videoAspectRatio: 1.3,
|
||||
uuid: '992ed3b9-fc9b-47a9-bdb4-e0c7cbb0fda5',
|
||||
...getDefaultConversation({
|
||||
isBlocked: Boolean(isBlocked),
|
||||
title:
|
||||
'Pablo Diego José Francisco de Paula Juan Nepomuceno María de los Remedios Cipriano de la Santísima Trinidad Ruiz y Picasso',
|
||||
uuid: '992ed3b9-fc9b-47a9-bdb4-e0c7cbb0fda5',
|
||||
}),
|
||||
},
|
||||
...overrideProps,
|
||||
});
|
||||
|
|
|
@ -10,7 +10,7 @@ import { InContactsIcon } from './InContactsIcon';
|
|||
import { ConversationType } from '../state/ducks/conversations';
|
||||
import { LocalizerType } from '../types/Util';
|
||||
|
||||
type SafetyNumberProps = {
|
||||
export type SafetyNumberProps = {
|
||||
contactID: string;
|
||||
onClose?: () => void;
|
||||
};
|
||||
|
|
|
@ -1194,6 +1194,7 @@ export class ConversationModel extends window.Backbone.Model<
|
|||
isGroupV1AndDisabled: this.isGroupV1AndDisabled(),
|
||||
isPinned: this.get('isPinned'),
|
||||
isMissingMandatoryProfileSharing: this.isMissingRequiredProfileSharing(),
|
||||
isUntrusted: this.isUntrusted(),
|
||||
isVerified: this.isVerified(),
|
||||
lastMessage: {
|
||||
status: this.get('lastMessageStatus')!,
|
||||
|
@ -1809,64 +1810,50 @@ export class ConversationModel extends window.Backbone.Model<
|
|||
return window.textsecure.storage.protocol.setApproval(this.id, true);
|
||||
}
|
||||
|
||||
async safeIsUntrusted(): Promise<boolean> {
|
||||
return window.textsecure.storage.protocol
|
||||
.isUntrusted(this.id)
|
||||
.catch(() => false);
|
||||
safeIsUntrusted(): boolean {
|
||||
try {
|
||||
return window.textsecure.storage.protocol.isUntrusted(this.id);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async isUntrusted(): Promise<boolean> {
|
||||
isUntrusted(): boolean {
|
||||
if (this.isPrivate()) {
|
||||
return this.safeIsUntrusted();
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
if (!this.contactCollection!.length) {
|
||||
return Promise.resolve(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
return Promise.all(
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
this.contactCollection!.map(contact => {
|
||||
if (contact.isMe()) {
|
||||
return false;
|
||||
}
|
||||
return contact.safeIsUntrusted();
|
||||
})
|
||||
).then(results => window._.any(results, result => result));
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return this.contactCollection!.any(contact => {
|
||||
if (contact.isMe()) {
|
||||
return false;
|
||||
}
|
||||
return contact.safeIsUntrusted();
|
||||
});
|
||||
}
|
||||
|
||||
async getUntrusted(): Promise<Backbone.Collection> {
|
||||
// This is a bit ugly because isUntrusted() is async. Could do the work to cache
|
||||
// it locally, but we really only need it for this call.
|
||||
getUntrusted(): Backbone.Collection {
|
||||
if (this.isPrivate()) {
|
||||
return this.isUntrusted().then(untrusted => {
|
||||
if (untrusted) {
|
||||
return new window.Backbone.Collection([this]);
|
||||
}
|
||||
|
||||
return new window.Backbone.Collection();
|
||||
});
|
||||
if (this.isUntrusted()) {
|
||||
return new window.Backbone.Collection([this]);
|
||||
}
|
||||
return new window.Backbone.Collection();
|
||||
}
|
||||
return Promise.all(
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
this.contactCollection!.map(contact => {
|
||||
if (contact.isMe()) {
|
||||
return [false, contact];
|
||||
}
|
||||
return Promise.all([contact.isUntrusted(), contact]);
|
||||
})
|
||||
).then(results => {
|
||||
const filtered = window._.filter(results, result => {
|
||||
const untrusted = result[0];
|
||||
return untrusted;
|
||||
});
|
||||
return new window.Backbone.Collection(
|
||||
window._.map(filtered, result => {
|
||||
const contact = result[1];
|
||||
return contact;
|
||||
})
|
||||
);
|
||||
|
||||
const results = this.contactCollection!.map(contact => {
|
||||
if (contact.isMe()) {
|
||||
return [false, contact];
|
||||
}
|
||||
return [contact.isUntrusted(), contact];
|
||||
});
|
||||
|
||||
return new window.Backbone.Collection(
|
||||
results.filter(result => result[0]).map(result => result[1])
|
||||
);
|
||||
}
|
||||
|
||||
getSentMessageCount(): number {
|
||||
|
@ -1983,7 +1970,15 @@ export class ConversationModel extends window.Backbone.Model<
|
|||
})
|
||||
);
|
||||
|
||||
const isUntrusted = await this.isUntrusted();
|
||||
|
||||
this.trigger('newmessage', model);
|
||||
|
||||
const uuid = this.get('uuid');
|
||||
// Group calls are always with folks that have a UUID
|
||||
if (isUntrusted && uuid) {
|
||||
window.reduxActions.calling.keyChanged({ uuid });
|
||||
}
|
||||
}
|
||||
|
||||
async addVerifiedChange(
|
||||
|
|
|
@ -667,6 +667,14 @@ export class CallingClass {
|
|||
return groupCall.getVideoSource(demuxId);
|
||||
}
|
||||
|
||||
public resendGroupCallMediaKeys(conversationId: string): void {
|
||||
const groupCall = this.getGroupCall(conversationId);
|
||||
if (!groupCall) {
|
||||
throw new Error('Could not find matching call');
|
||||
}
|
||||
groupCall.resendMediaKeys();
|
||||
}
|
||||
|
||||
private syncGroupCallToRedux(
|
||||
conversationId: string,
|
||||
groupCall: GroupCall
|
||||
|
|
|
@ -71,9 +71,10 @@ export interface ActiveCallStateType {
|
|||
joinedAt?: number;
|
||||
hasLocalAudio: boolean;
|
||||
hasLocalVideo: boolean;
|
||||
showParticipantsList: boolean;
|
||||
pip: boolean;
|
||||
settingsDialogOpen: boolean;
|
||||
safetyNumberChangedUuids: Array<string>;
|
||||
showParticipantsList: boolean;
|
||||
}
|
||||
|
||||
export interface CallsByConversationType {
|
||||
|
@ -126,6 +127,14 @@ export type HangUpType = {
|
|||
conversationId: string;
|
||||
};
|
||||
|
||||
type KeyChangedType = {
|
||||
uuid: string;
|
||||
};
|
||||
|
||||
export type KeyChangeOkType = {
|
||||
conversationId: string;
|
||||
};
|
||||
|
||||
export type IncomingCallType = {
|
||||
conversationId: string;
|
||||
isVideoCall: boolean;
|
||||
|
@ -220,6 +229,8 @@ const DECLINE_CALL = 'calling/DECLINE_CALL';
|
|||
const GROUP_CALL_STATE_CHANGE = 'calling/GROUP_CALL_STATE_CHANGE';
|
||||
const HANG_UP = 'calling/HANG_UP';
|
||||
const INCOMING_CALL = 'calling/INCOMING_CALL';
|
||||
const MARK_CALL_TRUSTED = 'calling/MARK_CALL_TRUSTED';
|
||||
const MARK_CALL_UNTRUSTED = 'calling/MARK_CALL_UNTRUSTED';
|
||||
const OUTGOING_CALL = 'calling/OUTGOING_CALL';
|
||||
const PEEK_NOT_CONNECTED_GROUP_CALL_FULFILLED =
|
||||
'calling/PEEK_NOT_CONNECTED_GROUP_CALL_FULFILLED';
|
||||
|
@ -282,6 +293,18 @@ type IncomingCallActionType = {
|
|||
payload: IncomingCallType;
|
||||
};
|
||||
|
||||
type KeyChangedActionType = {
|
||||
type: 'calling/MARK_CALL_UNTRUSTED';
|
||||
payload: {
|
||||
safetyNumberChangedUuids: Array<string>;
|
||||
};
|
||||
};
|
||||
|
||||
type KeyChangeOkActionType = {
|
||||
type: 'calling/MARK_CALL_TRUSTED';
|
||||
payload: null;
|
||||
};
|
||||
|
||||
type OutgoingCallActionType = {
|
||||
type: 'calling/OUTGOING_CALL';
|
||||
payload: StartDirectCallType;
|
||||
|
@ -353,6 +376,8 @@ export type CallingActionType =
|
|||
| GroupCallStateChangeActionType
|
||||
| HangUpActionType
|
||||
| IncomingCallActionType
|
||||
| KeyChangedActionType
|
||||
| KeyChangeOkActionType
|
||||
| OutgoingCallActionType
|
||||
| PeekNotConnectedGroupCallFulfilledActionType
|
||||
| RefreshIODevicesActionType
|
||||
|
@ -509,6 +534,56 @@ function hangUp(payload: HangUpType): HangUpActionType {
|
|||
};
|
||||
}
|
||||
|
||||
function keyChanged(
|
||||
payload: KeyChangedType
|
||||
): ThunkAction<void, RootStateType, unknown, KeyChangedActionType> {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const { activeCallState } = state.calling;
|
||||
|
||||
const activeCall = getActiveCall(state.calling);
|
||||
if (!activeCall || !activeCallState) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeCall.callMode === CallMode.Group) {
|
||||
const uuidsChanged = new Set(activeCallState.safetyNumberChangedUuids);
|
||||
|
||||
// Iterate over each participant to ensure that the uuid passed in
|
||||
// matches one of the participants in the group call.
|
||||
activeCall.remoteParticipants.forEach(participant => {
|
||||
if (participant.uuid === payload.uuid) {
|
||||
uuidsChanged.add(participant.uuid);
|
||||
}
|
||||
});
|
||||
|
||||
const safetyNumberChangedUuids = Array.from(uuidsChanged);
|
||||
|
||||
if (safetyNumberChangedUuids.length) {
|
||||
dispatch({
|
||||
type: MARK_CALL_UNTRUSTED,
|
||||
payload: {
|
||||
safetyNumberChangedUuids,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function keyChangeOk(
|
||||
payload: KeyChangeOkType
|
||||
): ThunkAction<void, RootStateType, unknown, KeyChangeOkActionType> {
|
||||
return dispatch => {
|
||||
calling.resendGroupCallMediaKeys(payload.conversationId);
|
||||
|
||||
dispatch({
|
||||
type: MARK_CALL_TRUSTED,
|
||||
payload: null,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function receiveIncomingCall(
|
||||
payload: IncomingCallType
|
||||
): IncomingCallActionType {
|
||||
|
@ -789,6 +864,8 @@ export const actions = {
|
|||
declineCall,
|
||||
groupCallStateChange,
|
||||
hangUp,
|
||||
keyChanged,
|
||||
keyChangeOk,
|
||||
receiveIncomingCall,
|
||||
outgoingCall,
|
||||
peekNotConnectedGroupCall,
|
||||
|
@ -896,9 +973,10 @@ export function reducer(
|
|||
conversationId: action.payload.conversationId,
|
||||
hasLocalAudio: action.payload.hasLocalAudio,
|
||||
hasLocalVideo: action.payload.hasLocalVideo,
|
||||
showParticipantsList: false,
|
||||
pip: false,
|
||||
safetyNumberChangedUuids: [],
|
||||
settingsDialogOpen: false,
|
||||
showParticipantsList: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -920,9 +998,10 @@ export function reducer(
|
|||
conversationId: action.payload.conversationId,
|
||||
hasLocalAudio: action.payload.hasLocalAudio,
|
||||
hasLocalVideo: action.payload.hasLocalVideo,
|
||||
showParticipantsList: false,
|
||||
pip: false,
|
||||
safetyNumberChangedUuids: [],
|
||||
settingsDialogOpen: false,
|
||||
showParticipantsList: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -939,9 +1018,10 @@ export function reducer(
|
|||
conversationId: action.payload.conversationId,
|
||||
hasLocalAudio: true,
|
||||
hasLocalVideo: action.payload.asVideoCall,
|
||||
showParticipantsList: false,
|
||||
pip: false,
|
||||
safetyNumberChangedUuids: [],
|
||||
settingsDialogOpen: false,
|
||||
showParticipantsList: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -1003,9 +1083,10 @@ export function reducer(
|
|||
conversationId: action.payload.conversationId,
|
||||
hasLocalAudio: action.payload.hasLocalAudio,
|
||||
hasLocalVideo: action.payload.hasLocalVideo,
|
||||
showParticipantsList: false,
|
||||
pip: false,
|
||||
safetyNumberChangedUuids: [],
|
||||
settingsDialogOpen: false,
|
||||
showParticipantsList: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -1327,5 +1408,46 @@ export function reducer(
|
|||
};
|
||||
}
|
||||
|
||||
if (action.type === MARK_CALL_UNTRUSTED) {
|
||||
const { activeCallState } = state;
|
||||
if (!activeCallState) {
|
||||
window.log.warn(
|
||||
'Cannot mark call as untrusted when there is no active call'
|
||||
);
|
||||
return state;
|
||||
}
|
||||
|
||||
const { safetyNumberChangedUuids } = action.payload;
|
||||
|
||||
return {
|
||||
...state,
|
||||
activeCallState: {
|
||||
...activeCallState,
|
||||
pip: false,
|
||||
safetyNumberChangedUuids,
|
||||
settingsDialogOpen: false,
|
||||
showParticipantsList: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (action.type === MARK_CALL_TRUSTED) {
|
||||
const { activeCallState } = state;
|
||||
if (!activeCallState) {
|
||||
window.log.warn(
|
||||
'Cannot mark call as trusted when there is no active call'
|
||||
);
|
||||
return state;
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
activeCallState: {
|
||||
...activeCallState,
|
||||
safetyNumberChangedUuids: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ export type ConversationType = {
|
|||
isBlocked?: boolean;
|
||||
isGroupV1AndDisabled?: boolean;
|
||||
isPinned?: boolean;
|
||||
isUntrusted?: boolean;
|
||||
isVerified?: boolean;
|
||||
activeAt?: number;
|
||||
timestamp?: number;
|
||||
|
|
|
@ -15,17 +15,24 @@ import { getIncomingCall } from '../selectors/calling';
|
|||
import {
|
||||
ActiveCallType,
|
||||
CallMode,
|
||||
GroupCallPeekedParticipantType,
|
||||
GroupCallRemoteParticipantType,
|
||||
} from '../../types/Calling';
|
||||
import { StateType } from '../reducer';
|
||||
import { missingCaseError } from '../../util/missingCaseError';
|
||||
import { SmartCallingDeviceSelection } from './CallingDeviceSelection';
|
||||
import {
|
||||
SmartSafetyNumberViewer,
|
||||
Props as SafetyNumberViewerProps,
|
||||
} from './SafetyNumberViewer';
|
||||
|
||||
function renderDeviceSelection(): JSX.Element {
|
||||
return <SmartCallingDeviceSelection />;
|
||||
}
|
||||
|
||||
function renderSafetyNumberViewer(props: SafetyNumberViewerProps): JSX.Element {
|
||||
return <SmartSafetyNumberViewer {...props} />;
|
||||
}
|
||||
|
||||
const getGroupCallVideoFrameSource = callingService.getGroupCallVideoFrameSource.bind(
|
||||
callingService
|
||||
);
|
||||
|
@ -89,10 +96,9 @@ const mapStateToActiveCallProp = (
|
|||
],
|
||||
};
|
||||
case CallMode.Group: {
|
||||
const ourUuid = getUserUuid(state);
|
||||
|
||||
const conversationsWithSafetyNumberChanges: Array<ConversationType> = [];
|
||||
const remoteParticipants: Array<GroupCallRemoteParticipantType> = [];
|
||||
const peekedParticipants: Array<GroupCallPeekedParticipantType> = [];
|
||||
const peekedParticipants: Array<ConversationType> = [];
|
||||
|
||||
for (let i = 0; i < call.remoteParticipants.length; i += 1) {
|
||||
const remoteParticipant = call.remoteParticipants[i];
|
||||
|
@ -108,23 +114,33 @@ const mapStateToActiveCallProp = (
|
|||
}
|
||||
|
||||
remoteParticipants.push({
|
||||
avatarPath: remoteConversation.avatarPath,
|
||||
color: remoteConversation.color,
|
||||
...remoteConversation,
|
||||
demuxId: remoteParticipant.demuxId,
|
||||
firstName: remoteConversation.firstName,
|
||||
hasRemoteAudio: remoteParticipant.hasRemoteAudio,
|
||||
hasRemoteVideo: remoteParticipant.hasRemoteVideo,
|
||||
isBlocked: Boolean(remoteConversation.isBlocked),
|
||||
isSelf: remoteParticipant.uuid === ourUuid,
|
||||
name: remoteConversation.name,
|
||||
profileName: remoteConversation.profileName,
|
||||
speakerTime: remoteParticipant.speakerTime,
|
||||
title: remoteConversation.title,
|
||||
uuid: remoteParticipant.uuid,
|
||||
videoAspectRatio: remoteParticipant.videoAspectRatio,
|
||||
});
|
||||
}
|
||||
|
||||
for (
|
||||
let i = 0;
|
||||
i < activeCallState.safetyNumberChangedUuids.length;
|
||||
i += 1
|
||||
) {
|
||||
const uuid = activeCallState.safetyNumberChangedUuids[i];
|
||||
|
||||
const remoteConversation = conversationSelectorByUuid(uuid);
|
||||
if (!remoteConversation) {
|
||||
window.log.error(
|
||||
'Remote participant has no corresponding conversation'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
conversationsWithSafetyNumberChanges.push(remoteConversation);
|
||||
}
|
||||
|
||||
for (let i = 0; i < call.peekInfo.uuids.length; i += 1) {
|
||||
const peekedParticipantUuid = call.peekInfo.uuids[i];
|
||||
|
||||
|
@ -138,22 +154,14 @@ const mapStateToActiveCallProp = (
|
|||
continue;
|
||||
}
|
||||
|
||||
peekedParticipants.push({
|
||||
avatarPath: peekedConversation.avatarPath,
|
||||
color: peekedConversation.color,
|
||||
firstName: peekedConversation.firstName,
|
||||
isSelf: peekedParticipantUuid === ourUuid,
|
||||
name: peekedConversation.name,
|
||||
profileName: peekedConversation.profileName,
|
||||
title: peekedConversation.title,
|
||||
uuid: peekedParticipantUuid,
|
||||
});
|
||||
peekedParticipants.push(peekedConversation);
|
||||
}
|
||||
|
||||
return {
|
||||
...baseResult,
|
||||
callMode: CallMode.Group,
|
||||
connectionState: call.connectionState,
|
||||
conversationsWithSafetyNumberChanges,
|
||||
deviceCount: call.peekInfo.deviceCount,
|
||||
joinState: call.joinState,
|
||||
maxDevices: call.peekInfo.maxDevices,
|
||||
|
@ -197,6 +205,7 @@ const mapStateToProps = (state: StateType) => ({
|
|||
uuid: getUserUuid(state),
|
||||
},
|
||||
renderDeviceSelection,
|
||||
renderSafetyNumberViewer,
|
||||
});
|
||||
|
||||
const smart = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
|
|
@ -9,7 +9,7 @@ import { getContactSafetyNumber } from '../selectors/safetyNumber';
|
|||
import { getConversationSelector } from '../selectors/conversations';
|
||||
import { getIntl } from '../selectors/user';
|
||||
|
||||
type Props = {
|
||||
export type Props = {
|
||||
contactID: string;
|
||||
onClose?: () => void;
|
||||
};
|
||||
|
|
|
@ -44,6 +44,7 @@ describe('calling duck', () => {
|
|||
hasLocalAudio: true,
|
||||
hasLocalVideo: false,
|
||||
showParticipantsList: false,
|
||||
safetyNumberChangedUuids: [],
|
||||
pip: false,
|
||||
settingsDialogOpen: false,
|
||||
},
|
||||
|
@ -98,6 +99,7 @@ describe('calling duck', () => {
|
|||
hasLocalAudio: true,
|
||||
hasLocalVideo: false,
|
||||
showParticipantsList: false,
|
||||
safetyNumberChangedUuids: [],
|
||||
pip: false,
|
||||
settingsDialogOpen: false,
|
||||
},
|
||||
|
@ -201,6 +203,7 @@ describe('calling duck', () => {
|
|||
hasLocalAudio: true,
|
||||
hasLocalVideo: true,
|
||||
showParticipantsList: false,
|
||||
safetyNumberChangedUuids: [],
|
||||
pip: false,
|
||||
settingsDialogOpen: false,
|
||||
});
|
||||
|
@ -576,6 +579,7 @@ describe('calling duck', () => {
|
|||
hasLocalAudio: true,
|
||||
hasLocalVideo: false,
|
||||
showParticipantsList: false,
|
||||
safetyNumberChangedUuids: [],
|
||||
pip: false,
|
||||
settingsDialogOpen: false,
|
||||
});
|
||||
|
@ -812,6 +816,7 @@ describe('calling duck', () => {
|
|||
hasLocalAudio: true,
|
||||
hasLocalVideo: true,
|
||||
showParticipantsList: false,
|
||||
safetyNumberChangedUuids: [],
|
||||
pip: false,
|
||||
settingsDialogOpen: false,
|
||||
});
|
||||
|
@ -1046,6 +1051,7 @@ describe('calling duck', () => {
|
|||
hasLocalAudio: true,
|
||||
hasLocalVideo: false,
|
||||
showParticipantsList: false,
|
||||
safetyNumberChangedUuids: [],
|
||||
pip: false,
|
||||
settingsDialogOpen: false,
|
||||
});
|
||||
|
|
|
@ -41,6 +41,7 @@ describe('state/selectors/calling', () => {
|
|||
hasLocalAudio: true,
|
||||
hasLocalVideo: false,
|
||||
showParticipantsList: false,
|
||||
safetyNumberChangedUuids: [],
|
||||
pip: false,
|
||||
settingsDialogOpen: false,
|
||||
},
|
||||
|
|
2
ts/textsecure.d.ts
vendored
2
ts/textsecure.d.ts
vendored
|
@ -123,7 +123,7 @@ export type StorageProtocolType = StorageType & {
|
|||
clearSignedPreKeysStore: () => Promise<void>;
|
||||
clearSessionStore: () => Promise<void>;
|
||||
isTrustedIdentity: () => void;
|
||||
isUntrusted: (id: string) => Promise<boolean>;
|
||||
isUntrusted: (id: string) => boolean;
|
||||
storePreKey: (keyId: number, keyPair: KeyPairType) => Promise<void>;
|
||||
storeSignedPreKey: (
|
||||
keyId: number,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright 2020 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { ColorType } from './Colors';
|
||||
import { ConversationType } from '../state/ducks/conversations';
|
||||
|
||||
// These are strings (1) for the database (2) for Storybook.
|
||||
|
@ -19,6 +18,7 @@ interface ActiveCallBaseType {
|
|||
pip: boolean;
|
||||
settingsDialogOpen: boolean;
|
||||
showParticipantsList: boolean;
|
||||
showSafetyNumberDialog?: boolean;
|
||||
}
|
||||
|
||||
interface ActiveDirectCallType extends ActiveCallBaseType {
|
||||
|
@ -36,10 +36,11 @@ interface ActiveDirectCallType extends ActiveCallBaseType {
|
|||
interface ActiveGroupCallType extends ActiveCallBaseType {
|
||||
callMode: CallMode.Group;
|
||||
connectionState: GroupCallConnectionState;
|
||||
conversationsWithSafetyNumberChanges: Array<ConversationType>;
|
||||
joinState: GroupCallJoinState;
|
||||
maxDevices: number;
|
||||
deviceCount: number;
|
||||
peekedParticipants: Array<GroupCallPeekedParticipantType>;
|
||||
peekedParticipants: Array<ConversationType>;
|
||||
remoteParticipants: Array<GroupCallRemoteParticipantType>;
|
||||
}
|
||||
|
||||
|
@ -94,23 +95,10 @@ export enum GroupCallJoinState {
|
|||
Joined = 2,
|
||||
}
|
||||
|
||||
export interface GroupCallPeekedParticipantType {
|
||||
avatarPath?: string;
|
||||
color?: ColorType;
|
||||
firstName?: string;
|
||||
isSelf: boolean;
|
||||
name?: string;
|
||||
profileName?: string;
|
||||
title: string;
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export interface GroupCallRemoteParticipantType
|
||||
extends GroupCallPeekedParticipantType {
|
||||
export interface GroupCallRemoteParticipantType extends ConversationType {
|
||||
demuxId: number;
|
||||
hasRemoteAudio: boolean;
|
||||
hasRemoteVideo: boolean;
|
||||
isBlocked: boolean;
|
||||
speakerTime?: number;
|
||||
videoAspectRatio: number;
|
||||
}
|
||||
|
|
24
ts/util/getDefaultConversation.ts
Normal file
24
ts/util/getDefaultConversation.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2020 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import { v4 as generateUuid } from 'uuid';
|
||||
import { ConversationType } from '../state/ducks/conversations';
|
||||
|
||||
export function getDefaultConversation(
|
||||
overrideProps: Partial<ConversationType>
|
||||
): ConversationType {
|
||||
if (window.STORYBOOK_ENV !== 'react') {
|
||||
throw new Error('getDefaultConversation is for storybook only');
|
||||
}
|
||||
|
||||
return {
|
||||
id: 'guid-1',
|
||||
lastUpdated: Date.now(),
|
||||
markedUnread: Boolean(overrideProps.markedUnread),
|
||||
e164: '+1300555000',
|
||||
title: 'Alice',
|
||||
type: 'direct' as const,
|
||||
uuid: generateUuid(),
|
||||
...overrideProps,
|
||||
};
|
||||
}
|
|
@ -14400,7 +14400,7 @@
|
|||
"rule": "React-useRef",
|
||||
"path": "ts/components/CallingLobby.tsx",
|
||||
"line": " const localVideoRef = React.useRef(null);",
|
||||
"lineNumber": 67,
|
||||
"lineNumber": 64,
|
||||
"reasonCategory": "usageTrusted",
|
||||
"updated": "2020-10-26T19:12:24.410Z",
|
||||
"reasonDetail": "Used to get the local video element for rendering."
|
||||
|
|
|
@ -2992,7 +2992,7 @@ Whisper.ConversationView = Whisper.View.extend({
|
|||
return unverifiedContacts;
|
||||
}
|
||||
|
||||
const untrustedContacts = await this.model.getUntrusted();
|
||||
const untrustedContacts = this.model.getUntrusted();
|
||||
|
||||
if (options.force) {
|
||||
if (untrustedContacts.length) {
|
||||
|
|
2
ts/window.d.ts
vendored
2
ts/window.d.ts
vendored
|
@ -479,6 +479,8 @@ declare global {
|
|||
getServerTrustRoot: () => WhatIsThis;
|
||||
readyForUpdates: () => void;
|
||||
|
||||
STORYBOOK_ENV?: string;
|
||||
|
||||
// Flags
|
||||
isGroupCallingEnabled: () => boolean;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue