Calls improvements
This commit is contained in:
parent
5f78b9e4cb
commit
c4827d50f6
@ -119,10 +119,11 @@ const seen: Set<PeerId> = new Set();
|
|||||||
|
|
||||||
export default class AvatarElement extends HTMLElement {
|
export default class AvatarElement extends HTMLElement {
|
||||||
private peerId: PeerId;
|
private peerId: PeerId;
|
||||||
private isDialog = false;
|
private isDialog: boolean;
|
||||||
private peerTitle: string;
|
private peerTitle: string;
|
||||||
public loadPromises: Promise<any>[];
|
public loadPromises: Promise<any>[];
|
||||||
public lazyLoadQueue: LazyLoadQueueIntersector;
|
public lazyLoadQueue: LazyLoadQueueIntersector;
|
||||||
|
public isBig: boolean;
|
||||||
private addedToQueue = false;
|
private addedToQueue = false;
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
@ -196,7 +197,7 @@ export default class AvatarElement extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private r(onlyThumb = false) {
|
private r(onlyThumb = false) {
|
||||||
const res = appAvatarsManager.putPhoto(this, this.peerId, this.isDialog, this.peerTitle, onlyThumb);
|
const res = appAvatarsManager.putPhoto(this, this.peerId, this.isDialog, this.peerTitle, onlyThumb, this.isBig);
|
||||||
const promise = res ? res.loadPromise : Promise.resolve();
|
const promise = res ? res.loadPromise : Promise.resolve();
|
||||||
if(this.loadPromises) {
|
if(this.loadPromises) {
|
||||||
if(res && res.cached) {
|
if(res && res.cached) {
|
||||||
|
@ -75,6 +75,7 @@ export default class CallDescriptionElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.container.classList.toggle('has-duration', connectionState === CALL_STATE.CONNECTED);
|
||||||
replaceContent(this.container, element);
|
replaceContent(this.container, element);
|
||||||
|
|
||||||
if(!this.container.parentElement) {
|
if(!this.container.parentElement) {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import IS_SCREEN_SHARING_SUPPORTED from "../../environment/screenSharingSupport";
|
import IS_SCREEN_SHARING_SUPPORTED from "../../environment/screenSharingSupport";
|
||||||
|
import { IS_MOBILE } from "../../environment/userAgent";
|
||||||
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
||||||
import ControlsHover from "../../helpers/dom/controlsHover";
|
import ControlsHover from "../../helpers/dom/controlsHover";
|
||||||
import findUpClassName from "../../helpers/dom/findUpClassName";
|
import findUpClassName from "../../helpers/dom/findUpClassName";
|
||||||
@ -14,6 +15,7 @@ import MovablePanel from "../../helpers/movablePanel";
|
|||||||
import safeAssign from "../../helpers/object/safeAssign";
|
import safeAssign from "../../helpers/object/safeAssign";
|
||||||
import toggleClassName from "../../helpers/toggleClassName";
|
import toggleClassName from "../../helpers/toggleClassName";
|
||||||
import type { AppAvatarsManager } from "../../lib/appManagers/appAvatarsManager";
|
import type { AppAvatarsManager } from "../../lib/appManagers/appAvatarsManager";
|
||||||
|
import type { AppCallsManager } from "../../lib/appManagers/appCallsManager";
|
||||||
import type { AppPeersManager } from "../../lib/appManagers/appPeersManager";
|
import type { AppPeersManager } from "../../lib/appManagers/appPeersManager";
|
||||||
import CallInstance from "../../lib/calls/callInstance";
|
import CallInstance from "../../lib/calls/callInstance";
|
||||||
import CALL_STATE from "../../lib/calls/callState";
|
import CALL_STATE from "../../lib/calls/callState";
|
||||||
@ -21,6 +23,7 @@ import I18n, { i18n } from "../../lib/langPack";
|
|||||||
import RichTextProcessor from "../../lib/richtextprocessor";
|
import RichTextProcessor from "../../lib/richtextprocessor";
|
||||||
import rootScope from "../../lib/rootScope";
|
import rootScope from "../../lib/rootScope";
|
||||||
import animationIntersector from "../animationIntersector";
|
import animationIntersector from "../animationIntersector";
|
||||||
|
import AvatarElement from "../avatar";
|
||||||
import ButtonIcon from "../buttonIcon";
|
import ButtonIcon from "../buttonIcon";
|
||||||
import GroupCallMicrophoneIconMini from "../groupCall/microphoneIconMini";
|
import GroupCallMicrophoneIconMini from "../groupCall/microphoneIconMini";
|
||||||
import { MovableState } from "../movableElement";
|
import { MovableState } from "../movableElement";
|
||||||
@ -40,6 +43,7 @@ let previousState: MovableState = {
|
|||||||
|
|
||||||
export default class PopupCall extends PopupElement {
|
export default class PopupCall extends PopupElement {
|
||||||
private instance: CallInstance;
|
private instance: CallInstance;
|
||||||
|
private appCallsManager: AppCallsManager;
|
||||||
private appAvatarsManager: AppAvatarsManager;
|
private appAvatarsManager: AppAvatarsManager;
|
||||||
private appPeersManager: AppPeersManager;
|
private appPeersManager: AppPeersManager;
|
||||||
private peerId: PeerId;
|
private peerId: PeerId;
|
||||||
@ -76,6 +80,7 @@ export default class PopupCall extends PopupElement {
|
|||||||
private controlsHover: ControlsHover;
|
private controlsHover: ControlsHover;
|
||||||
|
|
||||||
constructor(options: {
|
constructor(options: {
|
||||||
|
appCallsManager: AppCallsManager,
|
||||||
appAvatarsManager: AppAvatarsManager,
|
appAvatarsManager: AppAvatarsManager,
|
||||||
appPeersManager: AppPeersManager,
|
appPeersManager: AppPeersManager,
|
||||||
instance: CallInstance
|
instance: CallInstance
|
||||||
@ -96,8 +101,11 @@ export default class PopupCall extends PopupElement {
|
|||||||
avatarContainer.classList.add(className + '-avatar');
|
avatarContainer.classList.add(className + '-avatar');
|
||||||
|
|
||||||
const peerId = this.peerId = this.instance.interlocutorUserId.toPeerId();
|
const peerId = this.peerId = this.instance.interlocutorUserId.toPeerId();
|
||||||
const photo = this.appPeersManager.getPeerPhoto(peerId);
|
const avatar = new AvatarElement();
|
||||||
this.appAvatarsManager.putAvatar(avatarContainer, peerId, photo, 'photo_big');
|
avatar.isBig = true;
|
||||||
|
avatar.setAttribute('peer', '' + peerId);
|
||||||
|
avatar.classList.add('avatar-full');
|
||||||
|
avatarContainer.append(avatar);
|
||||||
|
|
||||||
const title = new PeerTitle({
|
const title = new PeerTitle({
|
||||||
peerId
|
peerId
|
||||||
@ -113,22 +121,28 @@ export default class PopupCall extends PopupElement {
|
|||||||
const emojisSubtitle = this.emojisSubtitle = document.createElement('div');
|
const emojisSubtitle = this.emojisSubtitle = document.createElement('div');
|
||||||
emojisSubtitle.classList.add(className + '-emojis');
|
emojisSubtitle.classList.add(className + '-emojis');
|
||||||
|
|
||||||
container.append(avatarContainer, title, subtitle, emojisSubtitle);
|
container.append(avatarContainer, title, subtitle);
|
||||||
|
|
||||||
this.btnFullScreen = ButtonIcon('fullscreen');
|
if(!IS_MOBILE) {
|
||||||
this.btnExitFullScreen = ButtonIcon('smallscreen hide');
|
this.btnFullScreen = ButtonIcon('fullscreen');
|
||||||
attachClickEvent(this.btnFullScreen, this.onFullScreenClick, {listenerSetter});
|
this.btnExitFullScreen = ButtonIcon('smallscreen hide');
|
||||||
attachClickEvent(this.btnExitFullScreen, () => cancelFullScreen(), {listenerSetter});
|
attachClickEvent(this.btnFullScreen, this.onFullScreenClick, {listenerSetter});
|
||||||
addFullScreenListener(this.container, this.onFullScreenChange, listenerSetter);
|
attachClickEvent(this.btnExitFullScreen, () => cancelFullScreen(), {listenerSetter});
|
||||||
this.header.prepend(this.btnExitFullScreen);
|
addFullScreenListener(this.container, this.onFullScreenChange, listenerSetter);
|
||||||
this.header.append(this.btnFullScreen);
|
this.header.prepend(this.btnExitFullScreen);
|
||||||
|
this.header.append(this.btnFullScreen);
|
||||||
|
|
||||||
|
container.append(emojisSubtitle);
|
||||||
|
} else {
|
||||||
|
this.header.append(emojisSubtitle);
|
||||||
|
}
|
||||||
|
|
||||||
this.partyStates = document.createElement('div');
|
this.partyStates = document.createElement('div');
|
||||||
this.partyStates.classList.add(className + '-party-states');
|
this.partyStates.classList.add(className + '-party-states');
|
||||||
|
|
||||||
this.partyMutedState = document.createElement('div');
|
this.partyMutedState = document.createElement('div');
|
||||||
this.partyMutedState.classList.add(className + '-party-state');
|
this.partyMutedState.classList.add(className + '-party-state');
|
||||||
const stateText = i18n('VoipUserMicrophoneIsOff', [new PeerTitle({peerId, onlyFirstName: true}).element]);
|
const stateText = i18n('VoipUserMicrophoneIsOff', [new PeerTitle({peerId, onlyFirstName: true, limitSymbols: 18}).element]);
|
||||||
stateText.classList.add(className + '-party-state-text');
|
stateText.classList.add(className + '-party-state-text');
|
||||||
const mutedIcon = new GroupCallMicrophoneIconMini(false, true);
|
const mutedIcon = new GroupCallMicrophoneIconMini(false, true);
|
||||||
mutedIcon.setState(false, false);
|
mutedIcon.setState(false, false);
|
||||||
@ -193,6 +207,10 @@ export default class PopupCall extends PopupElement {
|
|||||||
this.updateInstance();
|
this.updateInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getCallInstance() {
|
||||||
|
return this.instance;
|
||||||
|
}
|
||||||
|
|
||||||
private constructFirstButtons() {
|
private constructFirstButtons() {
|
||||||
const buttons = this.firstButtonsRow = document.createElement('div');
|
const buttons = this.firstButtonsRow = document.createElement('div');
|
||||||
buttons.classList.add(className + '-buttons', 'is-first');
|
buttons.classList.add(className + '-buttons', 'is-first');
|
||||||
@ -260,7 +278,7 @@ export default class PopupCall extends PopupElement {
|
|||||||
|
|
||||||
const btnAccept = this.btnAccept = this.makeButton({
|
const btnAccept = this.btnAccept = this.makeButton({
|
||||||
text: 'Call.Accept',
|
text: 'Call.Accept',
|
||||||
icon: 'phone',
|
icon: 'phone_filled',
|
||||||
callback: () => {
|
callback: () => {
|
||||||
this.instance.acceptCall();
|
this.instance.acceptCall();
|
||||||
},
|
},
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { IS_SAFARI } from "../../environment/userAgent";
|
import { IS_SAFARI } from "../../environment/userAgent";
|
||||||
import { indexOfAndSplice } from "../../helpers/array";
|
import indexOfAndSplice from "../../helpers/array/indexOfAndSplice";
|
||||||
import { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl";
|
import { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl";
|
||||||
import { deepEqual } from "../../helpers/object";
|
import deepEqual from "../../helpers/object/deepEqual";
|
||||||
|
|
||||||
type ChatBackgroundPatternRendererInitOptions = {
|
type ChatBackgroundPatternRendererInitOptions = {
|
||||||
url: string,
|
url: string,
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { forEachReverse } from "../../helpers/array";
|
import forEachReverse from "../../helpers/array/forEachReverse";
|
||||||
import positionElementByIndex from "../../helpers/dom/positionElementByIndex";
|
import positionElementByIndex from "../../helpers/dom/positionElementByIndex";
|
||||||
import { Message, ReactionCount } from "../../layer";
|
import { Message, ReactionCount } from "../../layer";
|
||||||
import appReactionsManager from "../../lib/appManagers/appReactionsManager";
|
import appReactionsManager from "../../lib/appManagers/appReactionsManager";
|
||||||
|
@ -12,13 +12,15 @@ import replaceContent from "../helpers/dom/replaceContent";
|
|||||||
import appUsersManager from "../lib/appManagers/appUsersManager";
|
import appUsersManager from "../lib/appManagers/appUsersManager";
|
||||||
import RichTextProcessor from "../lib/richtextprocessor";
|
import RichTextProcessor from "../lib/richtextprocessor";
|
||||||
import { NULL_PEER_ID } from "../lib/mtproto/mtproto_config";
|
import { NULL_PEER_ID } from "../lib/mtproto/mtproto_config";
|
||||||
|
import { limitSymbols } from "../helpers/string";
|
||||||
|
|
||||||
export type PeerTitleOptions = {
|
export type PeerTitleOptions = {
|
||||||
peerId?: PeerId,
|
peerId?: PeerId,
|
||||||
fromName?: string,
|
fromName?: string,
|
||||||
plainText?: boolean,
|
plainText?: boolean,
|
||||||
onlyFirstName?: boolean,
|
onlyFirstName?: boolean,
|
||||||
dialog?: boolean
|
dialog?: boolean,
|
||||||
|
limitSymbols?: number
|
||||||
};
|
};
|
||||||
|
|
||||||
const weakMap: WeakMap<HTMLElement, PeerTitle> = new WeakMap();
|
const weakMap: WeakMap<HTMLElement, PeerTitle> = new WeakMap();
|
||||||
@ -44,6 +46,7 @@ export default class PeerTitle {
|
|||||||
public plainText = false;
|
public plainText = false;
|
||||||
public onlyFirstName = false;
|
public onlyFirstName = false;
|
||||||
public dialog = false;
|
public dialog = false;
|
||||||
|
public limitSymbols: number;
|
||||||
|
|
||||||
constructor(options: PeerTitleOptions) {
|
constructor(options: PeerTitleOptions) {
|
||||||
this.element = document.createElement('span');
|
this.element = document.createElement('span');
|
||||||
@ -64,8 +67,13 @@ export default class PeerTitle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.fromName !== undefined) {
|
let fromName = this.fromName;
|
||||||
this.element.innerHTML = RichTextProcessor.wrapEmojiText(this.fromName);
|
if(fromName !== undefined) {
|
||||||
|
if(this.limitSymbols !== undefined) {
|
||||||
|
fromName = limitSymbols(fromName, this.limitSymbols, this.limitSymbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element.innerHTML = RichTextProcessor.wrapEmojiText(fromName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +85,7 @@ export default class PeerTitle {
|
|||||||
if(this.peerId.isUser() && appUsersManager.getUser(this.peerId).pFlags.deleted) {
|
if(this.peerId.isUser() && appUsersManager.getUser(this.peerId).pFlags.deleted) {
|
||||||
replaceContent(this.element, i18n(this.onlyFirstName ? 'Deleted' : 'HiddenName'));
|
replaceContent(this.element, i18n(this.onlyFirstName ? 'Deleted' : 'HiddenName'));
|
||||||
} else {
|
} else {
|
||||||
this.element.innerHTML = appPeersManager.getPeerTitle(this.peerId, this.plainText, this.onlyFirstName);
|
this.element.innerHTML = appPeersManager.getPeerTitle(this.peerId, this.plainText, this.onlyFirstName, this.limitSymbols);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
replaceContent(this.element, i18n(this.onlyFirstName ? 'Saved' : 'SavedMessages'));
|
replaceContent(this.element, i18n(this.onlyFirstName ? 'Saved' : 'SavedMessages'));
|
||||||
|
@ -15,7 +15,7 @@ import ListenerSetter from "../../helpers/listenerSetter";
|
|||||||
import { attachClickEvent, simulateClickEvent } from "../../helpers/dom/clickEvent";
|
import { attachClickEvent, simulateClickEvent } from "../../helpers/dom/clickEvent";
|
||||||
import isSendShortcutPressed from "../../helpers/dom/isSendShortcutPressed";
|
import isSendShortcutPressed from "../../helpers/dom/isSendShortcutPressed";
|
||||||
import { cancelEvent } from "../../helpers/dom/cancelEvent";
|
import { cancelEvent } from "../../helpers/dom/cancelEvent";
|
||||||
import EventListenerBase from "../../helpers/eventListenerBase";
|
import EventListenerBase, { EventListenerListeners } from "../../helpers/eventListenerBase";
|
||||||
import { addFullScreenListener, getFullScreenElement } from "../../helpers/dom/fullScreen";
|
import { addFullScreenListener, getFullScreenElement } from "../../helpers/dom/fullScreen";
|
||||||
import indexOfAndSplice from "../../helpers/array/indexOfAndSplice";
|
import indexOfAndSplice from "../../helpers/array/indexOfAndSplice";
|
||||||
|
|
||||||
@ -52,11 +52,13 @@ const onFullScreenChange = () => {
|
|||||||
|
|
||||||
addFullScreenListener(DEFAULT_APPEND_TO, onFullScreenChange);
|
addFullScreenListener(DEFAULT_APPEND_TO, onFullScreenChange);
|
||||||
|
|
||||||
export default class PopupElement extends EventListenerBase<{
|
type PopupListeners = {
|
||||||
close: () => void,
|
close: () => void,
|
||||||
closeAfterTimeout: () => void
|
closeAfterTimeout: () => void
|
||||||
}> {
|
};
|
||||||
private static POPUPS: PopupElement[] = [];
|
|
||||||
|
export default class PopupElement<T extends EventListenerListeners = {}> extends EventListenerBase<PopupListeners & T> {
|
||||||
|
private static POPUPS: PopupElement<any>[] = [];
|
||||||
protected element = document.createElement('div');
|
protected element = document.createElement('div');
|
||||||
protected container = document.createElement('div');
|
protected container = document.createElement('div');
|
||||||
protected header = document.createElement('div');
|
protected header = document.createElement('div');
|
||||||
@ -181,7 +183,7 @@ export default class PopupElement extends EventListenerBase<{
|
|||||||
public show() {
|
public show() {
|
||||||
this.navigationItem = {
|
this.navigationItem = {
|
||||||
type: 'popup',
|
type: 'popup',
|
||||||
onPop: this.destroy,
|
onPop: () => this.destroy(),
|
||||||
onEscape: this.onEscape
|
onEscape: this.onEscape
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -214,8 +216,8 @@ export default class PopupElement extends EventListenerBase<{
|
|||||||
appNavigationController.backByItem(this.navigationItem);
|
appNavigationController.backByItem(this.navigationItem);
|
||||||
};
|
};
|
||||||
|
|
||||||
private destroy = () => {
|
protected destroy() {
|
||||||
this.dispatchEvent('close');
|
this.dispatchEvent<PopupListeners>('close');
|
||||||
this.element.classList.add('hiding');
|
this.element.classList.add('hiding');
|
||||||
this.element.classList.remove('active');
|
this.element.classList.remove('active');
|
||||||
this.listenerSetter.removeAll();
|
this.listenerSetter.removeAll();
|
||||||
@ -234,14 +236,14 @@ export default class PopupElement extends EventListenerBase<{
|
|||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.element.remove();
|
this.element.remove();
|
||||||
this.dispatchEvent('closeAfterTimeout');
|
this.dispatchEvent<PopupListeners>('closeAfterTimeout');
|
||||||
this.cleanup();
|
this.cleanup();
|
||||||
|
|
||||||
if(!this.withoutOverlay) {
|
if(!this.withoutOverlay) {
|
||||||
animationIntersector.checkAnimations(false);
|
animationIntersector.checkAnimations(false);
|
||||||
}
|
}
|
||||||
}, 150);
|
}, 150);
|
||||||
};
|
}
|
||||||
|
|
||||||
public static reAppend() {
|
public static reAppend() {
|
||||||
this.POPUPS.forEach(popup => {
|
this.POPUPS.forEach(popup => {
|
||||||
|
@ -9,7 +9,8 @@ import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
|||||||
import replaceContent from "../../../helpers/dom/replaceContent";
|
import replaceContent from "../../../helpers/dom/replaceContent";
|
||||||
import toggleDisability from "../../../helpers/dom/toggleDisability";
|
import toggleDisability from "../../../helpers/dom/toggleDisability";
|
||||||
import formatBytes from "../../../helpers/formatBytes";
|
import formatBytes from "../../../helpers/formatBytes";
|
||||||
import { copy, deepEqual } from "../../../helpers/object";
|
import copy from "../../../helpers/object/copy";
|
||||||
|
import deepEqual from "../../../helpers/object/deepEqual";
|
||||||
import appStateManager, { AutoDownloadPeerTypeSettings, STATE_INIT } from "../../../lib/appManagers/appStateManager";
|
import appStateManager, { AutoDownloadPeerTypeSettings, STATE_INIT } from "../../../lib/appManagers/appStateManager";
|
||||||
import { FormatterArguments, i18n, join, LangPackKey } from "../../../lib/langPack";
|
import { FormatterArguments, i18n, join, LangPackKey } from "../../../lib/langPack";
|
||||||
import rootScope from "../../../lib/rootScope";
|
import rootScope from "../../../lib/rootScope";
|
||||||
|
@ -29,6 +29,7 @@ import PopupCall from "./call";
|
|||||||
import type { AppAvatarsManager } from "../lib/appManagers/appAvatarsManager";
|
import type { AppAvatarsManager } from "../lib/appManagers/appAvatarsManager";
|
||||||
import GroupCallMicrophoneIconMini from "./groupCall/microphoneIconMini";
|
import GroupCallMicrophoneIconMini from "./groupCall/microphoneIconMini";
|
||||||
import CallInstance from "../lib/calls/callInstance";
|
import CallInstance from "../lib/calls/callInstance";
|
||||||
|
import type { AppCallsManager } from "../lib/appManagers/appCallsManager";
|
||||||
|
|
||||||
function convertCallStateToGroupState(state: CALL_STATE, isMuted: boolean) {
|
function convertCallStateToGroupState(state: CALL_STATE, isMuted: boolean) {
|
||||||
switch(state) {
|
switch(state) {
|
||||||
@ -64,11 +65,18 @@ export default class TopbarCall {
|
|||||||
private appPeersManager: AppPeersManager,
|
private appPeersManager: AppPeersManager,
|
||||||
private appChatsManager: AppChatsManager,
|
private appChatsManager: AppChatsManager,
|
||||||
private appAvatarsManager: AppAvatarsManager,
|
private appAvatarsManager: AppAvatarsManager,
|
||||||
|
private appCallsManager: AppCallsManager
|
||||||
) {
|
) {
|
||||||
const listenerSetter = this.listenerSetter = new ListenerSetter();
|
const listenerSetter = this.listenerSetter = new ListenerSetter();
|
||||||
|
|
||||||
listenerSetter.add(rootScope)('call_instance', ({instance, hasCurrent}) => {
|
listenerSetter.add(rootScope)('call_instance', ({instance}) => {
|
||||||
if(!hasCurrent) {
|
if(!this.instance) {
|
||||||
|
this.updateInstance(instance);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
listenerSetter.add(rootScope)('call_accepting', (instance) => {
|
||||||
|
if(this.instance !== instance) {
|
||||||
this.updateInstance(instance);
|
this.updateInstance(instance);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -121,7 +129,8 @@ export default class TopbarCall {
|
|||||||
this.construct = undefined;
|
this.construct = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.instance !== instance) {
|
const isChangingInstance = this.instance !== instance;
|
||||||
|
if(isChangingInstance) {
|
||||||
this.clearCurrentInstance();
|
this.clearCurrentInstance();
|
||||||
|
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
@ -135,6 +144,8 @@ export default class TopbarCall {
|
|||||||
this.currentDescription = this.callDescription;
|
this.currentDescription = this.callDescription;
|
||||||
this.instanceListenerSetter.add(instance)('muted', this.onState);
|
this.instanceListenerSetter.add(instance)('muted', this.onState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.container.classList.toggle('is-call', !(instance instanceof GroupCallInstance));
|
||||||
}
|
}
|
||||||
|
|
||||||
const isMuted = this.instance.isMuted;
|
const isMuted = this.instance.isMuted;
|
||||||
@ -145,7 +156,7 @@ export default class TopbarCall {
|
|||||||
weave.componentDidMount();
|
weave.componentDidMount();
|
||||||
|
|
||||||
const isClosed = state === GROUP_CALL_STATE.CLOSED;
|
const isClosed = state === GROUP_CALL_STATE.CLOSED;
|
||||||
if(!document.body.classList.contains('is-calling') || isClosed) {
|
if((!document.body.classList.contains('is-calling') || isChangingInstance) || isClosed) {
|
||||||
if(isClosed) {
|
if(isClosed) {
|
||||||
weave.setAmplitude(0);
|
weave.setAmplitude(0);
|
||||||
}
|
}
|
||||||
@ -257,7 +268,13 @@ export default class TopbarCall {
|
|||||||
appChatsManager: this.appChatsManager
|
appChatsManager: this.appChatsManager
|
||||||
}).show();
|
}).show();
|
||||||
} else if(this.instance instanceof CallInstance) {
|
} else if(this.instance instanceof CallInstance) {
|
||||||
|
const hasPopup = PopupElement.getPopup(PopupCall) as PopupCall;
|
||||||
|
if(hasPopup && hasPopup.getCallInstance() === this.instance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
new PopupCall({
|
new PopupCall({
|
||||||
|
appCallsManager: this.appCallsManager,
|
||||||
appAvatarsManager: this.appAvatarsManager,
|
appAvatarsManager: this.appAvatarsManager,
|
||||||
appPeersManager: this.appPeersManager,
|
appPeersManager: this.appPeersManager,
|
||||||
instance: this.instance
|
instance: this.instance
|
||||||
|
@ -50,6 +50,8 @@ import type { ArgumentTypes, SuperReturnType } from "../types";
|
|||||||
// MOUNT_CLASS_TO.e = e;
|
// MOUNT_CLASS_TO.e = e;
|
||||||
|
|
||||||
export type EventListenerListeners = Record<string, Function>;
|
export type EventListenerListeners = Record<string, Function>;
|
||||||
|
// export type EventListenerListeners = Record<string, (...args: any[]) => any>;
|
||||||
|
// export type EventListenerListeners = {[name in string]: Function};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Better not to remove listeners during setting
|
* Better not to remove listeners during setting
|
||||||
@ -151,7 +153,8 @@ export default class EventListenerBase<Listeners extends EventListenerListeners>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// * must be protected, but who cares
|
// * must be protected, but who cares
|
||||||
public dispatchEvent<T extends keyof Listeners>(name: T, ...args: ArgumentTypes<Listeners[T]>) {
|
public dispatchEvent<L extends EventListenerListeners = Listeners, T extends keyof L = keyof L>(name: T, ...args: ArgumentTypes<L[T]>) {
|
||||||
|
// @ts-ignore
|
||||||
this._dispatchEvent(name, false, ...args);
|
this._dispatchEvent(name, false, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,6 +170,10 @@ console.timeEnd('get storage1'); */
|
|||||||
document.documentElement.classList.add('is-firefox');
|
document.documentElement.classList.add('is-firefox');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(userAgent.IS_MOBILE) {
|
||||||
|
document.documentElement.classList.add('is-mobile');
|
||||||
|
}
|
||||||
|
|
||||||
if(userAgent.IS_APPLE) {
|
if(userAgent.IS_APPLE) {
|
||||||
if(userAgent.IS_SAFARI) {
|
if(userAgent.IS_SAFARI) {
|
||||||
document.documentElement.classList.add('is-safari');
|
document.documentElement.classList.add('is-safari');
|
||||||
|
@ -169,7 +169,7 @@ export class AppAvatarsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// peerId === peerId || title
|
// peerId === peerId || title
|
||||||
public putPhoto(div: HTMLElement, peerId: PeerId, isDialog = false, title = '', onlyThumb = false) {
|
public putPhoto(div: HTMLElement, peerId: PeerId, isDialog = false, title = '', onlyThumb = false, isBig?: boolean) {
|
||||||
const myId = rootScope.myId;
|
const myId = rootScope.myId;
|
||||||
|
|
||||||
//console.log('loadDialogPhoto location:', location, inputPeer);
|
//console.log('loadDialogPhoto location:', location, inputPeer);
|
||||||
@ -213,7 +213,7 @@ export class AppAvatarsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(avatarAvailable/* && false */) {
|
if(avatarAvailable/* && false */) {
|
||||||
const size: PeerPhotoSize = 'photo_small';
|
const size: PeerPhotoSize = isBig ? 'photo_big' : 'photo_small';
|
||||||
return this.putAvatar(div, peerId, photo, size, undefined, onlyThumb);
|
return this.putAvatar(div, peerId, photo, size, undefined, onlyThumb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
import { MOUNT_CLASS_TO } from "../../config/debug";
|
import { MOUNT_CLASS_TO } from "../../config/debug";
|
||||||
import IS_CALL_SUPPORTED from "../../environment/callSupport";
|
import IS_CALL_SUPPORTED from "../../environment/callSupport";
|
||||||
|
import indexOfAndSplice from "../../helpers/array/indexOfAndSplice";
|
||||||
|
import insertInDescendSortedArray from "../../helpers/array/insertInDescendSortedArray";
|
||||||
import AudioAssetPlayer from "../../helpers/audioAssetPlayer";
|
import AudioAssetPlayer from "../../helpers/audioAssetPlayer";
|
||||||
import bytesCmp from "../../helpers/bytes/bytesCmp";
|
import bytesCmp from "../../helpers/bytes/bytesCmp";
|
||||||
import safeReplaceObject from "../../helpers/object/safeReplaceObject";
|
import safeReplaceObject from "../../helpers/object/safeReplaceObject";
|
||||||
@ -39,6 +41,7 @@ export class AppCallsManager {
|
|||||||
private log: ReturnType<typeof logger>;
|
private log: ReturnType<typeof logger>;
|
||||||
private calls: Map<CallId, MyPhoneCall>;
|
private calls: Map<CallId, MyPhoneCall>;
|
||||||
private instances: Map<CallId, CallInstance>;
|
private instances: Map<CallId, CallInstance>;
|
||||||
|
private sortedInstances: Array<CallInstance>;
|
||||||
private tempId: number;
|
private tempId: number;
|
||||||
private audioAsset: AudioAssetPlayer<CallAudioAssetName>;
|
private audioAsset: AudioAssetPlayer<CallAudioAssetName>;
|
||||||
|
|
||||||
@ -48,6 +51,7 @@ export class AppCallsManager {
|
|||||||
this.tempId = 0;
|
this.tempId = 0;
|
||||||
this.calls = new Map();
|
this.calls = new Map();
|
||||||
this.instances = new Map();
|
this.instances = new Map();
|
||||||
|
this.sortedInstances = [];
|
||||||
|
|
||||||
if(!IS_CALL_SUPPORTED) {
|
if(!IS_CALL_SUPPORTED) {
|
||||||
return;
|
return;
|
||||||
@ -139,15 +143,7 @@ export class AppCallsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get currentCall() {
|
public get currentCall() {
|
||||||
let lastInstance: CallInstance;
|
return this.sortedInstances[0];
|
||||||
for(const [callId, instance] of this.instances) {
|
|
||||||
lastInstance = instance;
|
|
||||||
if(instance.connectionState !== CALL_STATE.PENDING) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return lastInstance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCallByUserId(userId: UserId) {
|
public getCallByUserId(userId: UserId) {
|
||||||
@ -207,15 +203,17 @@ export class AppCallsManager {
|
|||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
|
|
||||||
let wasTryingToJoin = false;
|
|
||||||
call.addEventListener('state', (state) => {
|
call.addEventListener('state', (state) => {
|
||||||
const currentCall = this.currentCall;
|
const currentCall = this.currentCall;
|
||||||
if(state === CALL_STATE.CLOSED) {
|
if(state === CALL_STATE.CLOSED) {
|
||||||
this.instances.delete(call.id);
|
this.instances.delete(call.id);
|
||||||
|
indexOfAndSplice(this.sortedInstances, call);
|
||||||
|
} else {
|
||||||
|
insertInDescendSortedArray(this.sortedInstances, call, 'sortIndex');
|
||||||
}
|
}
|
||||||
|
|
||||||
if(state === CALL_STATE.EXCHANGING_KEYS) {
|
if(state === CALL_STATE.EXCHANGING_KEYS) {
|
||||||
wasTryingToJoin = true;
|
call.wasTryingToJoin = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasConnected = call.connectedAt !== undefined;
|
const hasConnected = call.connectedAt !== undefined;
|
||||||
@ -227,9 +225,9 @@ export class AppCallsManager {
|
|||||||
|
|
||||||
if(currentCall === call || !currentCall) {
|
if(currentCall === call || !currentCall) {
|
||||||
if(state === CALL_STATE.CLOSED) {
|
if(state === CALL_STATE.CLOSED) {
|
||||||
if(!call.isOutgoing && !wasTryingToJoin) { // incoming call has been accepted on other device or ended
|
if(!call.isOutgoing && !call.wasTryingToJoin) { // incoming call has been accepted on other device or ended
|
||||||
this.audioAsset.stopSound();
|
this.audioAsset.stopSound();
|
||||||
} else if(wasTryingToJoin && !hasConnected) { // something has happened during the key exchanging
|
} else if(call.wasTryingToJoin && !hasConnected) { // something has happened during the key exchanging
|
||||||
this.audioAsset.playSound('voip_failed.mp3');
|
this.audioAsset.playSound('voip_failed.mp3');
|
||||||
} else {
|
} else {
|
||||||
this.audioAsset.playSound(call.discardReason === 'phoneCallDiscardReasonBusy' ? 'call_busy.mp3' : 'call_end.mp3');
|
this.audioAsset.playSound(call.discardReason === 'phoneCallDiscardReasonBusy' ? 'call_busy.mp3' : 'call_end.mp3');
|
||||||
|
@ -87,6 +87,8 @@ import appReactionsManager from './appReactionsManager';
|
|||||||
import PopupCall from '../../components/call';
|
import PopupCall from '../../components/call';
|
||||||
import copy from '../../helpers/object/copy';
|
import copy from '../../helpers/object/copy';
|
||||||
import getObjectKeysAndSort from '../../helpers/object/getObjectKeysAndSort';
|
import getObjectKeysAndSort from '../../helpers/object/getObjectKeysAndSort';
|
||||||
|
import type GroupCallInstance from '../calls/groupCallInstance';
|
||||||
|
import type CallInstance from '../calls/callInstance';
|
||||||
|
|
||||||
//console.log('appImManager included33!');
|
//console.log('appImManager included33!');
|
||||||
|
|
||||||
@ -341,20 +343,39 @@ export class AppImManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if(IS_CALL_SUPPORTED || IS_GROUP_CALL_SUPPORTED) {
|
if(IS_CALL_SUPPORTED || IS_GROUP_CALL_SUPPORTED) {
|
||||||
this.topbarCall = new TopbarCall(appGroupCallsManager, appPeersManager, appChatsManager, appAvatarsManager);
|
this.topbarCall = new TopbarCall(appGroupCallsManager, appPeersManager, appChatsManager, appAvatarsManager, appCallsManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IS_CALL_SUPPORTED) {
|
if(IS_CALL_SUPPORTED) {
|
||||||
rootScope.addEventListener('call_instance', ({instance, hasCurrent}) => {
|
rootScope.addEventListener('call_instance', ({instance/* , hasCurrent */}) => {
|
||||||
if(hasCurrent) {
|
// if(hasCurrent) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
new PopupCall({
|
const popup = new PopupCall({
|
||||||
|
appCallsManager,
|
||||||
appAvatarsManager,
|
appAvatarsManager,
|
||||||
appPeersManager,
|
appPeersManager,
|
||||||
instance
|
instance
|
||||||
}).show();
|
});
|
||||||
|
|
||||||
|
instance.addEventListener('acceptCallOverride', () => {
|
||||||
|
return this.discardCurrentCall(instance.interlocutorUserId.toPeerId(), undefined, instance)
|
||||||
|
.then(() => {
|
||||||
|
rootScope.dispatchEvent('call_accepting', instance);
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.catch(() => false);
|
||||||
|
});
|
||||||
|
|
||||||
|
popup.addEventListener('close', () => {
|
||||||
|
const currentCall = appCallsManager.currentCall;
|
||||||
|
if(currentCall && currentCall !== instance && !instance.wasTryingToJoin) {
|
||||||
|
instance.hangUp('phoneCallDiscardReasonBusy');
|
||||||
|
}
|
||||||
|
}, {once: true});
|
||||||
|
|
||||||
|
popup.show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -944,9 +965,9 @@ export class AppImManager {
|
|||||||
appCallsManager.startCallInternal(userId, type === 'video');
|
appCallsManager.startCallInternal(userId, type === 'video');
|
||||||
}
|
}
|
||||||
|
|
||||||
private discardCurrentCall(toPeerId: PeerId) {
|
private discardCurrentCall(toPeerId: PeerId, ignoreGroupCall?: GroupCallInstance, ignoreCall?: CallInstance) {
|
||||||
if(appCallsManager.currentCall) return this.discardCallConfirmation(toPeerId);
|
if(appGroupCallsManager.groupCall && appGroupCallsManager.groupCall !== ignoreGroupCall) return this.discardGroupCallConfirmation(toPeerId);
|
||||||
else if(appGroupCallsManager.groupCall) return this.discardGroupCallConfirmation(toPeerId);
|
else if(appCallsManager.currentCall && appCallsManager.currentCall !== ignoreCall) return this.discardCallConfirmation(toPeerId);
|
||||||
else return Promise.resolve();
|
else return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -965,8 +986,8 @@ export class AppImManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if(appCallsManager.currentCall === currentCall) {
|
if(!currentCall.isClosing) {
|
||||||
await currentCall.hangUp();
|
await currentCall.hangUp('phoneCallDiscardReasonDisconnect');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import I18n from '../langPack';
|
|||||||
import { NULL_PEER_ID } from "../mtproto/mtproto_config";
|
import { NULL_PEER_ID } from "../mtproto/mtproto_config";
|
||||||
import { getRestrictionReason } from "../../helpers/restrictions";
|
import { getRestrictionReason } from "../../helpers/restrictions";
|
||||||
import isObject from "../../helpers/object/isObject";
|
import isObject from "../../helpers/object/isObject";
|
||||||
|
import { limitSymbols } from "../../helpers/string";
|
||||||
|
|
||||||
// https://github.com/eelcohn/Telegram-API/wiki/Calculating-color-for-a-Telegram-user-on-IRC
|
// https://github.com/eelcohn/Telegram-API/wiki/Calculating-color-for-a-Telegram-user-on-IRC
|
||||||
/*
|
/*
|
||||||
@ -73,7 +74,7 @@ export class AppPeersManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPeerTitle(peerId: PeerId, plainText = false, onlyFirstName = false) {
|
public getPeerTitle(peerId: PeerId, plainText = false, onlyFirstName = false, _limitSymbols?: number) {
|
||||||
if(!peerId) {
|
if(!peerId) {
|
||||||
peerId = rootScope.myId;
|
peerId = rootScope.myId;
|
||||||
}
|
}
|
||||||
@ -94,6 +95,10 @@ export class AppPeersManager {
|
|||||||
title = title.split(' ')[0];
|
title = title.split(' ')[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(_limitSymbols !== undefined) {
|
||||||
|
title = limitSymbols(title, _limitSymbols, _limitSymbols);
|
||||||
|
}
|
||||||
|
|
||||||
return plainText ? title : RichTextProcessor.wrapEmojiText(title);
|
return plainText ? title : RichTextProcessor.wrapEmojiText(title);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import { MOUNT_CLASS_TO } from "../../config/debug";
|
|||||||
import assumeType from "../../helpers/assumeType";
|
import assumeType from "../../helpers/assumeType";
|
||||||
import callbackify from "../../helpers/callbackify";
|
import callbackify from "../../helpers/callbackify";
|
||||||
import callbackifyAll from "../../helpers/callbackifyAll";
|
import callbackifyAll from "../../helpers/callbackifyAll";
|
||||||
import { copy } from "../../helpers/object";
|
import copy from "../../helpers/object/copy";
|
||||||
import { AvailableReaction, Message, MessagePeerReaction, MessagesAvailableReactions, Update, Updates } from "../../layer";
|
import { AvailableReaction, Message, MessagePeerReaction, MessagesAvailableReactions, Update, Updates } from "../../layer";
|
||||||
import apiManager from "../mtproto/mtprotoworker";
|
import apiManager from "../mtproto/mtprotoworker";
|
||||||
import { ReferenceContext } from "../mtproto/referenceDatabase";
|
import { ReferenceContext } from "../mtproto/referenceDatabase";
|
||||||
|
@ -34,7 +34,8 @@ export default class CallInstance extends CallInstanceBase<{
|
|||||||
state: (state: CALL_STATE) => void,
|
state: (state: CALL_STATE) => void,
|
||||||
id: (id: CallId, prevId: CallId) => void,
|
id: (id: CallId, prevId: CallId) => void,
|
||||||
muted: (muted: boolean) => void,
|
muted: (muted: boolean) => void,
|
||||||
mediaState: (mediaState: CallMediaState) => void
|
mediaState: (mediaState: CallMediaState) => void,
|
||||||
|
acceptCallOverride: () => Promise<boolean>,
|
||||||
}> {
|
}> {
|
||||||
public dh: Partial<DiffieHellmanInfo.a & DiffieHellmanInfo.b>;
|
public dh: Partial<DiffieHellmanInfo.a & DiffieHellmanInfo.b>;
|
||||||
public id: CallId;
|
public id: CallId;
|
||||||
@ -55,6 +56,7 @@ export default class CallInstance extends CallInstanceBase<{
|
|||||||
public release: () => Promise<void>;
|
public release: () => Promise<void>;
|
||||||
public _connectionState: CALL_STATE;
|
public _connectionState: CALL_STATE;
|
||||||
|
|
||||||
|
public createdAt: number;
|
||||||
public connectedAt: number;
|
public connectedAt: number;
|
||||||
public discardReason: string;
|
public discardReason: string;
|
||||||
|
|
||||||
@ -78,6 +80,9 @@ export default class CallInstance extends CallInstanceBase<{
|
|||||||
|
|
||||||
private wasStartingScreen: boolean;
|
private wasStartingScreen: boolean;
|
||||||
private wasStartingVideo: boolean;
|
private wasStartingVideo: boolean;
|
||||||
|
public wasTryingToJoin: boolean;
|
||||||
|
|
||||||
|
public streamManager: StreamManager;
|
||||||
|
|
||||||
constructor(options: {
|
constructor(options: {
|
||||||
isOutgoing: boolean,
|
isOutgoing: boolean,
|
||||||
@ -97,6 +102,7 @@ export default class CallInstance extends CallInstanceBase<{
|
|||||||
|
|
||||||
safeAssign(this, options);
|
safeAssign(this, options);
|
||||||
|
|
||||||
|
this.createdAt = Date.now();
|
||||||
this.offerReceived = false;
|
this.offerReceived = false;
|
||||||
this.offerSent = false;
|
this.offerSent = false;
|
||||||
this.decryptQueue = [];
|
this.decryptQueue = [];
|
||||||
@ -110,7 +116,7 @@ export default class CallInstance extends CallInstanceBase<{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const streamManager = new StreamManager(GROUP_CALL_AMPLITUDE_ANALYSE_INTERVAL_MS);
|
const streamManager = this.streamManager = new StreamManager(GROUP_CALL_AMPLITUDE_ANALYSE_INTERVAL_MS);
|
||||||
streamManager.direction = 'sendrecv';
|
streamManager.direction = 'sendrecv';
|
||||||
streamManager.types.push('screencast');
|
streamManager.types.push('screencast');
|
||||||
if(!this.isOutgoing) {
|
if(!this.isOutgoing) {
|
||||||
@ -164,6 +170,14 @@ export default class CallInstance extends CallInstanceBase<{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get sortIndex() {
|
||||||
|
const connectionState = this.connectionState;
|
||||||
|
const state = CALL_STATE.CLOSED - connectionState + 1;
|
||||||
|
let index = state * 10000000000000;
|
||||||
|
index += 2147483647000 - (connectionState === CALL_STATE.PENDING && this.isOutgoing ? 0 : this.createdAt);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
public getVideoElement(type: CallMediaState['type']) {
|
public getVideoElement(type: CallMediaState['type']) {
|
||||||
if(type === 'input') return this.elements.get('main');
|
if(type === 'input') return this.elements.get('main');
|
||||||
else {
|
else {
|
||||||
@ -283,10 +297,6 @@ export default class CallInstance extends CallInstanceBase<{
|
|||||||
return connectionState === CALL_STATE.CLOSING || connectionState === CALL_STATE.CLOSED;
|
return connectionState === CALL_STATE.CLOSING || connectionState === CALL_STATE.CLOSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get streamManager(): StreamManager {
|
|
||||||
return this.connectionInstance?.streamManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get description(): localConferenceDescription {
|
public get description(): localConferenceDescription {
|
||||||
return this.connectionInstance?.description;
|
return this.connectionInstance?.description;
|
||||||
}
|
}
|
||||||
@ -318,6 +328,11 @@ export default class CallInstance extends CallInstanceBase<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async acceptCall() {
|
public async acceptCall() {
|
||||||
|
const canAccept = (await Promise.all(this.dispatchResultableEvent('acceptCallOverride')))[0] ?? true;
|
||||||
|
if(this.isClosing || !canAccept) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// this.clearHangUpTimeout();
|
// this.clearHangUpTimeout();
|
||||||
this.overrideConnectionState(CALL_STATE.EXCHANGING_KEYS);
|
this.overrideConnectionState(CALL_STATE.EXCHANGING_KEYS);
|
||||||
|
|
||||||
@ -619,7 +634,7 @@ export default class CallInstance extends CallInstanceBase<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async hangUp(discardReason?: PhoneCallDiscardReason['_'], discardedByOtherParty?: boolean) {
|
public async hangUp(discardReason?: PhoneCallDiscardReason['_'], discardedByOtherParty?: boolean) {
|
||||||
if(this.connectionState === CALL_STATE.CLOSED) {
|
if(this.isClosing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import getAudioConstraints from "./helpers/getAudioConstraints";
|
|||||||
import getScreenConstraints from "./helpers/getScreenConstraints";
|
import getScreenConstraints from "./helpers/getScreenConstraints";
|
||||||
import getStreamCached from "./helpers/getStreamCached";
|
import getStreamCached from "./helpers/getStreamCached";
|
||||||
import getVideoConstraints from "./helpers/getVideoConstraints";
|
import getVideoConstraints from "./helpers/getVideoConstraints";
|
||||||
|
import stopTrack from "./helpers/stopTrack";
|
||||||
import LocalConferenceDescription from "./localConferenceDescription";
|
import LocalConferenceDescription from "./localConferenceDescription";
|
||||||
import StreamManager, { StreamItem } from "./streamManager";
|
import StreamManager, { StreamItem } from "./streamManager";
|
||||||
|
|
||||||
@ -190,6 +191,9 @@ export default abstract class CallInstanceBase<E extends EventListenerListeners>
|
|||||||
|
|
||||||
if(!isVideo) {
|
if(!isVideo) {
|
||||||
player.appendChild(element);
|
player.appendChild(element);
|
||||||
|
} else {
|
||||||
|
element.setAttribute('playsinline', 'true');
|
||||||
|
element.muted = true;
|
||||||
}
|
}
|
||||||
// audio.play();
|
// audio.play();
|
||||||
|
|
||||||
@ -229,6 +233,10 @@ export default abstract class CallInstanceBase<E extends EventListenerListeners>
|
|||||||
if(description) {
|
if(description) {
|
||||||
streamManager.appendToConference(description);
|
streamManager.appendToConference(description);
|
||||||
}
|
}
|
||||||
|
} else { // if call is declined earlier than stream appears
|
||||||
|
stream.getTracks().forEach(track => {
|
||||||
|
stopTrack(track);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,8 +183,6 @@ export default class GroupCallInstance extends CallInstanceBase<{
|
|||||||
|
|
||||||
const clone = element.cloneNode() as typeof element;
|
const clone = element.cloneNode() as typeof element;
|
||||||
clone.srcObject = element.srcObject;
|
clone.srcObject = element.srcObject;
|
||||||
clone.setAttribute('playsinline', 'true');
|
|
||||||
clone.muted = true;
|
|
||||||
return {video: clone, source};
|
return {video: clone, source};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ import { encodeEntities } from '../helpers/string';
|
|||||||
import { IS_SAFARI } from '../environment/userAgent';
|
import { IS_SAFARI } from '../environment/userAgent';
|
||||||
import { MOUNT_CLASS_TO } from '../config/debug';
|
import { MOUNT_CLASS_TO } from '../config/debug';
|
||||||
import IS_EMOJI_SUPPORTED from '../environment/emojiSupport';
|
import IS_EMOJI_SUPPORTED from '../environment/emojiSupport';
|
||||||
import { copy } from '../helpers/object';
|
import copy from '../helpers/object/copy';
|
||||||
|
|
||||||
const EmojiHelper = {
|
const EmojiHelper = {
|
||||||
emojiMap: (code: string) => { return code; },
|
emojiMap: (code: string) => { return code; },
|
||||||
|
@ -17,7 +17,7 @@ import type { PushNotificationObject } from "./serviceWorker/push";
|
|||||||
import type { ConnectionStatusChange } from "./mtproto/connectionStatus";
|
import type { ConnectionStatusChange } from "./mtproto/connectionStatus";
|
||||||
import type { GroupCallId } from "./appManagers/appGroupCallsManager";
|
import type { GroupCallId } from "./appManagers/appGroupCallsManager";
|
||||||
import type GroupCallInstance from "./calls/groupCallInstance";
|
import type GroupCallInstance from "./calls/groupCallInstance";
|
||||||
// import type CallInstance from "./calls/callInstance";
|
import type CallInstance from "./calls/callInstance";
|
||||||
import type { StreamAmplitude } from "./calls/streamManager";
|
import type { StreamAmplitude } from "./calls/streamManager";
|
||||||
import type Chat from "../components/chat/chat";
|
import type Chat from "../components/chat/chat";
|
||||||
import { NULL_PEER_ID, UserAuth } from "./mtproto/mtproto_config";
|
import { NULL_PEER_ID, UserAuth } from "./mtproto/mtproto_config";
|
||||||
@ -158,7 +158,8 @@ export type BroadcastEvents = {
|
|||||||
'group_call_participant': {groupCallId: GroupCallId, participant: GroupCallParticipant},
|
'group_call_participant': {groupCallId: GroupCallId, participant: GroupCallParticipant},
|
||||||
// 'group_call_video_track_added': {instance: GroupCallInstance}
|
// 'group_call_video_track_added': {instance: GroupCallInstance}
|
||||||
|
|
||||||
'call_instance': {hasCurrent: boolean, instance: any/* CallInstance */},
|
'call_instance': {hasCurrent: boolean, instance: CallInstance},
|
||||||
|
'call_accepting': CallInstance, // это костыль. используется при параллельном вызове, чтобы заменить звонок в topbarCall
|
||||||
|
|
||||||
'quick_reaction': string,
|
'quick_reaction': string,
|
||||||
|
|
||||||
|
@ -232,3 +232,19 @@ avatar-element {
|
|||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.avatar-full {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: inherit;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.avatar-photo {
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1383,12 +1383,13 @@ $bubble-beside-button-width: 38px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
&-subtitle {
|
&-subtitle {
|
||||||
font-size: .875rem;
|
font-size: var(--messages-secondary-text-size);
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-top: .0625rem;
|
margin-top: .0625rem;
|
||||||
margin-left: -.1875rem;
|
margin-left: -.1875rem;
|
||||||
|
line-height: var(--messages-secondary-line-height);
|
||||||
|
|
||||||
&.is-reason:before {
|
&.is-reason:before {
|
||||||
margin-right: .0625rem;
|
margin-right: .0625rem;
|
||||||
|
@ -239,6 +239,7 @@ body.is-right-column-shown {
|
|||||||
height: 3.5rem;
|
height: 3.5rem;
|
||||||
max-height: 3.5rem;
|
max-height: 3.5rem;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,15 +361,29 @@ body.is-right-column-shown {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 480px) {
|
&:not(.is-call) {
|
||||||
.topbar-call-left,
|
@media only screen and (max-width: 480px) {
|
||||||
.topbar-call-right {
|
.topbar-call-left,
|
||||||
width: auto;
|
.topbar-call-right {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-call-description {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.group-call-description,
|
&.is-call {
|
||||||
.call-description {
|
@media only screen and (max-width: 480px) {
|
||||||
display: none;
|
.topbar-call-left,
|
||||||
|
.topbar-call-right {
|
||||||
|
width: 6.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.call-description:not(.has-duration) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -399,6 +414,13 @@ body.is-right-column-shown {
|
|||||||
&-center {
|
&-center {
|
||||||
@include sidebar-transform(true);
|
@include sidebar-transform(true);
|
||||||
@include text-overflow();
|
@include text-overflow();
|
||||||
|
|
||||||
|
@include respond-to(medium-screens) {
|
||||||
|
// ! it flicks over the left side :(
|
||||||
|
// body.is-right-column-shown & {
|
||||||
|
padding: 0 calc(var(--right-column-width) / 2);
|
||||||
|
// }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-right {
|
&-right {
|
||||||
|
@ -37,6 +37,13 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tgico-phone_filled {
|
||||||
|
&:before {
|
||||||
|
content: $tgico-endcall_filled;
|
||||||
|
transform: rotate(-135deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.tgico-check {
|
.tgico-check {
|
||||||
&:before {
|
&:before {
|
||||||
content: $tgico-check;
|
content: $tgico-check;
|
||||||
|
@ -24,10 +24,15 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&.is-full-screen {
|
&.is-full-screen,
|
||||||
|
html.is-mobile & {
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.is-full-screen:not(.show-controls) {
|
||||||
|
cursor: none;
|
||||||
|
}
|
||||||
|
|
||||||
&.show-controls,
|
&.show-controls,
|
||||||
&.no-video {
|
&.no-video {
|
||||||
.call-title,
|
.call-title,
|
||||||
@ -41,10 +46,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.show-controls {
|
||||||
|
.call-video {
|
||||||
|
opacity: .8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.call-video-blur {
|
||||||
|
opacity: .56;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.popup-header {
|
.popup-header {
|
||||||
.btn-icon {
|
.btn-icon {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.call-emojis {
|
||||||
|
transform: scale(1.3125);
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-avatar {
|
&-avatar {
|
||||||
@ -55,11 +75,10 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
opacity: .7;
|
opacity: .7;
|
||||||
|
border-radius: inherit;
|
||||||
|
|
||||||
.avatar-photo {
|
.avatar-full {
|
||||||
width: 100%;
|
font-size: 6rem;
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,6 +201,7 @@
|
|||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border-radius: inherit;
|
border-radius: inherit;
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
&-container {
|
&-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -212,6 +232,13 @@
|
|||||||
opacity: .7;
|
opacity: .7;
|
||||||
border-radius: inherit;
|
border-radius: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&,
|
||||||
|
&-blur {
|
||||||
|
@include animation-level(2) {
|
||||||
|
transition: opacity var(--transition-standard-in);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// html.emoji-supported & {
|
// html.emoji-supported & {
|
||||||
@ -234,6 +261,7 @@
|
|||||||
z-index: 2;
|
z-index: 2;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding: 0 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-party-state {
|
&-party-state {
|
||||||
@ -252,7 +280,6 @@
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: scale(0) translateY(0);
|
transform: scale(0) translateY(0);
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
padding: 0 1rem;
|
|
||||||
|
|
||||||
@include animation-level(2) {
|
@include animation-level(2) {
|
||||||
transition: opacity var(--transition-standard-in), transform var(--transition-standard-in);
|
transition: opacity var(--transition-standard-in), transform var(--transition-standard-in);
|
||||||
@ -262,7 +289,7 @@
|
|||||||
width: 1.875rem !important;
|
width: 1.875rem !important;
|
||||||
height: 1.875rem !important;
|
height: 1.875rem !important;
|
||||||
margin-right: .25rem;
|
margin-right: .25rem;
|
||||||
margin-left: -.625rem;
|
margin-left: -.25rem;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,11 +302,12 @@
|
|||||||
// opacity: 0 !important;
|
// opacity: 0 !important;
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&-text {
|
&-party-state-text,
|
||||||
max-width: 100%;
|
&-title {
|
||||||
@include text-overflow();
|
max-width: 100%;
|
||||||
}
|
@include text-overflow();
|
||||||
}
|
}
|
||||||
|
|
||||||
&.two-button-rows {
|
&.two-button-rows {
|
||||||
|
Loading…
Reference in New Issue
Block a user