Add screensharing behind a feature flag
This commit is contained in:
parent
7c7f7ee5a0
commit
ceffc2380c
49 changed files with 2044 additions and 164 deletions
163
ts/components/CallingToastManager.tsx
Normal file
163
ts/components/CallingToastManager.tsx
Normal file
|
@ -0,0 +1,163 @@
|
|||
// Copyright 2020-2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
ActiveCallType,
|
||||
CallMode,
|
||||
GroupCallConnectionState,
|
||||
} from '../types/Calling';
|
||||
import { ConversationType } from '../state/ducks/conversations';
|
||||
import { LocalizerType } from '../types/Util';
|
||||
|
||||
type PropsType = {
|
||||
activeCall: ActiveCallType;
|
||||
i18n: LocalizerType;
|
||||
};
|
||||
|
||||
type ToastType =
|
||||
| {
|
||||
message: string;
|
||||
type: 'dismissable' | 'static';
|
||||
}
|
||||
| undefined;
|
||||
|
||||
function getReconnectingToast({ activeCall, i18n }: PropsType): ToastType {
|
||||
if (
|
||||
activeCall.callMode === CallMode.Group &&
|
||||
activeCall.connectionState === GroupCallConnectionState.Reconnecting
|
||||
) {
|
||||
return {
|
||||
message: i18n('callReconnecting'),
|
||||
type: 'static',
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const ME = Symbol('me');
|
||||
|
||||
function getCurrentPresenter(
|
||||
activeCall: Readonly<ActiveCallType>
|
||||
): ConversationType | typeof ME | undefined {
|
||||
if (activeCall.presentingSource) {
|
||||
return ME;
|
||||
}
|
||||
if (activeCall.callMode === CallMode.Direct) {
|
||||
const isOtherPersonPresenting = activeCall.remoteParticipants.some(
|
||||
participant => participant.presenting
|
||||
);
|
||||
return isOtherPersonPresenting ? activeCall.conversation : undefined;
|
||||
}
|
||||
if (activeCall.callMode === CallMode.Group) {
|
||||
return activeCall.remoteParticipants.find(
|
||||
participant => participant.presenting
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function useScreenSharingToast({ activeCall, i18n }: PropsType): ToastType {
|
||||
const [result, setResult] = useState<undefined | ToastType>(undefined);
|
||||
|
||||
const [previousPresenter, setPreviousPresenter] = useState<
|
||||
undefined | { id: string | typeof ME; title?: string }
|
||||
>(undefined);
|
||||
|
||||
const previousPresenterId = previousPresenter?.id;
|
||||
const previousPresenterTitle = previousPresenter?.title;
|
||||
|
||||
useEffect(() => {
|
||||
const currentPresenter = getCurrentPresenter(activeCall);
|
||||
if (!currentPresenter && previousPresenterId) {
|
||||
if (previousPresenterId === ME) {
|
||||
setResult({
|
||||
type: 'dismissable',
|
||||
message: i18n('calling__presenting--you-stopped'),
|
||||
});
|
||||
} else if (previousPresenterTitle) {
|
||||
setResult({
|
||||
type: 'dismissable',
|
||||
message: i18n('calling__presenting--person-stopped', [
|
||||
previousPresenterTitle,
|
||||
]),
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [activeCall, i18n, previousPresenterId, previousPresenterTitle]);
|
||||
|
||||
useEffect(() => {
|
||||
const currentPresenter = getCurrentPresenter(activeCall);
|
||||
if (currentPresenter === ME) {
|
||||
setPreviousPresenter({
|
||||
id: ME,
|
||||
});
|
||||
} else if (!currentPresenter) {
|
||||
setPreviousPresenter(undefined);
|
||||
} else {
|
||||
const { id, title } = currentPresenter;
|
||||
setPreviousPresenter({ id, title });
|
||||
}
|
||||
}, [activeCall]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const DEFAULT_DELAY = 5000;
|
||||
|
||||
// In the future, this component should show toasts when users join or leave. See
|
||||
// DESKTOP-902.
|
||||
export const CallingToastManager: React.FC<PropsType> = props => {
|
||||
const reconnectingToast = getReconnectingToast(props);
|
||||
const screenSharingToast = useScreenSharingToast(props);
|
||||
|
||||
let toast: ToastType;
|
||||
if (reconnectingToast) {
|
||||
toast = reconnectingToast;
|
||||
} else if (screenSharingToast) {
|
||||
toast = screenSharingToast;
|
||||
}
|
||||
|
||||
const [toastMessage, setToastMessage] = useState('');
|
||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
const dismissToast = useCallback(() => {
|
||||
if (timeoutRef) {
|
||||
setToastMessage('');
|
||||
}
|
||||
}, [setToastMessage, timeoutRef]);
|
||||
|
||||
useEffect(() => {
|
||||
if (toast) {
|
||||
if (toast.type === 'dismissable') {
|
||||
if (timeoutRef && timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
timeoutRef.current = setTimeout(dismissToast, DEFAULT_DELAY);
|
||||
}
|
||||
|
||||
setToastMessage(toast.message);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (timeoutRef && timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, [dismissToast, setToastMessage, timeoutRef, toast]);
|
||||
|
||||
const isVisible = Boolean(toastMessage);
|
||||
|
||||
return (
|
||||
<button
|
||||
className={classNames('module-ongoing-call__toast', {
|
||||
'module-ongoing-call__toast--hidden': !isVisible,
|
||||
})}
|
||||
type="button"
|
||||
onClick={dismissToast}
|
||||
>
|
||||
{toastMessage}
|
||||
</button>
|
||||
);
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue