Show notification on screenshare start in adhoc call
This commit is contained in:
parent
22192a4037
commit
1a4bc49563
7 changed files with 114 additions and 32 deletions
|
@ -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}</>;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,19 +2066,34 @@ 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 result = await conversation.getAvatarOrIdenticon();
|
||||
url = result.url;
|
||||
absolutePath = result.absolutePath;
|
||||
}
|
||||
|
||||
const conversation = window.ConversationController.get(conversationId);
|
||||
strictAssert(conversation, 'setPresenting: conversation not found');
|
||||
|
||||
const { url, absolutePath } = await conversation.getAvatarOrIdenticon();
|
||||
|
||||
notificationService.notify({
|
||||
conversationId,
|
||||
iconPath: absolutePath,
|
||||
|
|
|
@ -488,3 +488,20 @@ function filterNotificationText(text: string) {
|
|||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue