Show notification on screenshare start in adhoc call

This commit is contained in:
Scott Nonnenberg 2024-08-02 10:01:40 -07:00 committed by GitHub
parent 22192a4037
commit 1a4bc49563
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 114 additions and 32 deletions

View file

@ -3,7 +3,11 @@
import React from 'react';
import type { Meta } from '@storybook/react';
import { IdenticonSVGForContact, IdenticonSVGForGroup } from './IdenticonSVG';
import {
IdenticonSVGForCallLink,
IdenticonSVGForContact,
IdenticonSVGForGroup,
} from './IdenticonSVG';
import { AvatarColorMap } from '../types/Colors';
export default {
@ -40,3 +44,18 @@ export function AllColorsForGroup(): JSX.Element {
return <>{stories}</>;
}
export function AllColorsForCallLink(): JSX.Element {
const stories: Array<JSX.Element> = [];
AvatarColorMap.forEach(value =>
stories.push(
<IdenticonSVGForCallLink
backgroundColor={value.bg}
foregroundColor={value.fg}
/>
)
);
return <>{stories}</>;
}

View file

@ -67,3 +67,25 @@ export function IdenticonSVGForGroup({
</svg>
);
}
export function IdenticonSVGForCallLink({
backgroundColor,
foregroundColor,
}: PropsTypeForGroup): JSX.Element {
// Note: the inner SVG below is taken from images/icons/v3/video/video-display-bold.svg,
// viewBox added to match the original SVG, new dimensions to create match Avatar.tsx.
return (
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<circle cx="50" cy="50" r="40" fill={backgroundColor} />
<svg viewBox="0 0 36 36" height="50" width="50" y="26" x="25">
<path
fill={foregroundColor}
fillRule="evenodd"
// eslint-disable-next-line max-len
d="M10.302 5.625c-1.22 0-2.203 0-3 .065-.82.067-1.54.209-2.206.548a5.625 5.625 0 0 0-2.458 2.458c-.34.667-.481 1.387-.548 2.207-.065.796-.065 1.78-.065 2.999v8.196c0 1.22 0 2.203.065 3 .067.82.208 1.54.548 2.206a5.625 5.625 0 0 0 2.458 2.458c.667.34 1.387.481 2.207.548.796.065 1.78.065 2.999.065h7.296c1.22 0 2.203 0 3-.065.82-.067 1.54-.209 2.206-.548a5.625 5.625 0 0 0 2.458-2.458c.34-.667.48-1.387.548-2.207.065-.796.065-1.78.065-2.999v-.032l4.775 4.775c1.559 1.56 4.225.455 4.225-1.75V10.909c0-2.205-2.666-3.31-4.225-1.75l-4.775 4.775v-.032c0-1.22 0-2.203-.065-3-.067-.82-.209-1.54-.548-2.206a5.625 5.625 0 0 0-2.458-2.458c-.667-.34-1.387-.481-2.207-.548-.796-.065-1.78-.065-2.999-.065h-7.296Zm13.323 8.325c0-1.279-.001-2.17-.058-2.864-.055-.68-.159-1.072-.31-1.368a3.374 3.374 0 0 0-1.475-1.475c-.296-.151-.687-.255-1.368-.31-.694-.057-1.585-.058-2.864-.058h-7.2c-1.279 0-2.17 0-2.864.058-.68.055-1.072.159-1.368.31a3.375 3.375 0 0 0-1.475 1.475c-.151.296-.255.687-.31 1.368-.057.694-.058 1.585-.058 2.864v8.1c0 1.279 0 2.17.057 2.864.056.68.16 1.072.31 1.368.324.635.84 1.152 1.476 1.475.296.151.687.255 1.368.31.694.057 1.585.058 2.864.058h7.2c1.279 0 2.17 0 2.864-.058.68-.055 1.072-.159 1.368-.31a3.374 3.374 0 0 0 1.475-1.475c.151-.296.255-.687.31-1.368.057-.694.058-1.585.058-2.864v-8.1Zm2.25 4.05c0 .566.225 1.109.625 1.51l5.74 5.74a.21.21 0 0 0 .116.066.24.24 0 0 0 .13-.017.239.239 0 0 0 .104-.08.21.21 0 0 0 .035-.128V10.909a.21.21 0 0 0-.035-.128.238.238 0 0 0-.104-.08.24.24 0 0 0-.13-.017.21.21 0 0 0-.115.066L26.5 16.49c-.4.401-.625.944-.625 1.51Z"
clipRule="evenodd"
/>
</svg>
</svg>
);
}

View file

@ -37,7 +37,6 @@ import {
} from '../util/avatarUtils';
import { getDraftPreview } from '../util/getDraftPreview';
import { hasDraft } from '../util/hasDraft';
import { missingCaseError } from '../util/missingCaseError';
import { hydrateStoryContext } from '../util/hydrateStoryContext';
import * as Conversation from '../types/Conversation';
import type { StickerType, StickerWithHydratedData } from '../types/Stickers';
@ -94,8 +93,8 @@ import { migrateColor } from '../util/migrateColor';
import { isNotNil } from '../util/isNotNil';
import {
NotificationType,
NotificationSetting,
notificationService,
shouldSaveNotificationAvatarToDisk,
} from '../services/notifications';
import { storageServiceUploadJob } from '../services/storage';
import { getSendOptions } from '../util/getSendOptions';
@ -172,7 +171,6 @@ import { ReceiptType } from '../types/Receipt';
import { getQuoteAttachment } from '../util/makeQuote';
import { deriveProfileKeyVersion } from '../util/zkgroup';
import { incrementMessageCounter } from '../util/incrementMessageCounter';
import OS from '../util/os/osMain';
import { getMessageAuthorText } from '../util/getMessageAuthorText';
import { downscaleOutgoingAttachment } from '../util/attachments';
import { MessageRequestResponseEvent } from '../types/MessageRequestResponseEvent';
@ -5292,24 +5290,7 @@ export class ConversationModel extends window.Backbone
url: string;
absolutePath?: string;
}> {
let saveToDisk: boolean;
const notificationSetting = notificationService.getNotificationSetting();
switch (notificationSetting) {
case NotificationSetting.NameOnly:
case NotificationSetting.NameAndMessage:
// According to the MSDN, avatars can only be loaded from disk or an
// http server:
// https://learn.microsoft.com/en-us/uwp/schemas/tiles/toastschema/element-image?redirectedfrom=MSDN
saveToDisk = OS.isWindows();
break;
case NotificationSetting.Off:
case NotificationSetting.NoNameOrMessage:
saveToDisk = false;
break;
default:
throw missingCaseError(notificationSetting);
}
const saveToDisk = shouldSaveNotificationAvatarToDisk();
const avatarUrl = getLocalAvatarUrl(this.attributes);
if (avatarUrl) {
return {

View file

@ -110,6 +110,7 @@ import {
NotificationSetting,
FALLBACK_NOTIFICATION_TITLE,
NotificationType,
shouldSaveNotificationAvatarToDisk,
} from './notifications';
import * as log from '../logging/log';
import { assertDev, strictAssert } from '../util/assert';
@ -154,6 +155,8 @@ import type { CallLinkType, CallLinkStateType } from '../types/CallLink';
import { CallLinkRestrictions } from '../types/CallLink';
import { getConversationIdForLogging } from '../util/idForLogging';
import { sendCallLinkUpdateSync } from '../util/sendCallLinkUpdateSync';
import { createIdenticon } from '../util/createIdenticon';
import { getColorForCallLink } from '../util/getColorForCallLink';
const { wasGroupCallRingPreviouslyCanceled } = DataReader;
const {
@ -2027,7 +2030,8 @@ export class CallingClass {
async setPresenting(
conversationId: string,
hasLocalVideo: boolean,
source?: PresentedSource
source?: PresentedSource,
callLinkRootKey?: string
): Promise<void> {
const call = getOwn(this.callsLookup, conversationId);
if (!call) {
@ -2062,18 +2066,33 @@ export class CallingClass {
if (source) {
ipcRenderer.send('show-screen-share', source.name);
// TODO: DESKTOP-7068
let url: string;
let absolutePath: string | undefined;
if (
call instanceof GroupCall &&
call.getKind() === GroupCallKind.CallLink
) {
return;
}
strictAssert(callLinkRootKey, 'If call is adhoc, we need rootKey');
const color = getColorForCallLink(callLinkRootKey);
const saveToDisk = shouldSaveNotificationAvatarToDisk();
const result = await createIdenticon(
color,
{ type: 'call-link' },
{ saveToDisk }
);
url = result.url;
absolutePath = result.path
? window.Signal.Migrations.getAbsoluteTempPath(result.path)
: undefined;
} else {
const conversation = window.ConversationController.get(conversationId);
strictAssert(conversation, 'setPresenting: conversation not found');
const { url, absolutePath } = await conversation.getAvatarOrIdenticon();
const result = await conversation.getAvatarOrIdenticon();
url = result.url;
absolutePath = result.absolutePath;
}
notificationService.notify({
conversationId,

View file

@ -488,3 +488,20 @@ function filterNotificationText(text: string) {
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
}
export function shouldSaveNotificationAvatarToDisk(): boolean {
const notificationSetting = notificationService.getNotificationSetting();
switch (notificationSetting) {
case NotificationSetting.NameOnly:
case NotificationSetting.NameAndMessage:
// According to the MSDN, avatars can only be loaded from disk or an
// http server:
// https://learn.microsoft.com/en-us/uwp/schemas/tiles/toastschema/element-image?redirectedfrom=MSDN
return OS.isWindows();
case NotificationSetting.Off:
case NotificationSetting.NoNameOrMessage:
return false;
default:
throw missingCaseError(notificationSetting);
}
}

View file

@ -96,6 +96,7 @@ import { addCallHistory } from './callHistory';
import { saveDraftRecordingIfNeeded } from './composer';
import type { CallHistoryDetails } from '../../types/CallDisposition';
import type { StartCallData } from '../../components/ConfirmLeaveCallModal';
import { getCallLinksByRoomId } from '../selectors/calling';
// State
@ -1794,7 +1795,9 @@ function setPresenting(
sourceToPresent?: PresentedSource
): ThunkAction<void, RootStateType, unknown, SetPresentingFulfilledActionType> {
return async (dispatch, getState) => {
const callingState = getState().calling;
const state = getState();
const callingState = state.calling;
const { activeCallState } = callingState;
const activeCall = getActiveCall(callingState);
if (!activeCall || !activeCallState) {
@ -1802,10 +1805,20 @@ function setPresenting(
return;
}
let rootKey: string | undefined;
if (activeCall.callMode === CallMode.Adhoc) {
const callLink = getOwn(
getCallLinksByRoomId(state),
activeCall.conversationId
);
rootKey = callLink?.rootKey;
}
await calling.setPresenting(
activeCall.conversationId,
activeCallState.hasLocalVideo,
sourceToPresent
sourceToPresent,
rootKey
);
dispatch({

View file

@ -7,6 +7,7 @@ import { renderToString } from 'react-dom/server';
import type { AvatarColorType } from '../types/Colors';
import { AvatarColorMap } from '../types/Colors';
import {
IdenticonSVGForCallLink,
IdenticonSVGForContact,
IdenticonSVGForGroup,
} from '../components/IdenticonSVG';
@ -21,6 +22,9 @@ type IdenticonDetailsType =
}
| {
type: 'group';
}
| {
type: 'call-link';
};
export function createIdenticon(
@ -47,6 +51,13 @@ export function createIdenticon(
foregroundColor={avatarColor?.fg || defaultColorValue.fg}
/>
);
} else if (details.type === 'call-link') {
html = renderToString(
<IdenticonSVGForCallLink
backgroundColor={avatarColor?.bg || defaultColorValue.bg}
foregroundColor={avatarColor?.fg || defaultColorValue.fg}
/>
);
} else {
throw missingCaseError(details);
}