Telegram Web K with changes to work inside I2P
https://web.telegram.i2p/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
286 lines
8.8 KiB
286 lines
8.8 KiB
/* |
|
* https://github.com/morethanwords/tweb |
|
* Copyright (C) 2019-2021 Eduard Kuzmenko |
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE |
|
*/ |
|
|
|
import cancelEvent from '../helpers/dom/cancelEvent'; |
|
import {attachClickEvent} from '../helpers/dom/clickEvent'; |
|
import ListenerSetter from '../helpers/listenerSetter'; |
|
import GROUP_CALL_STATE from '../lib/calls/groupCallState'; |
|
import rootScope from '../lib/rootScope'; |
|
import ButtonIcon from './buttonIcon'; |
|
import TopbarWeave from './topbarWeave'; |
|
import SetTransition from './singleTransition'; |
|
import PopupGroupCall from './groupCall'; |
|
import GroupCallDescriptionElement from './groupCall/description'; |
|
import GroupCallTitleElement from './groupCall/title'; |
|
import PopupElement from './popups'; |
|
import throttle from '../helpers/schedulers/throttle'; |
|
import GroupCallInstance from '../lib/calls/groupCallInstance'; |
|
import CALL_STATE from '../lib/calls/callState'; |
|
import replaceContent from '../helpers/dom/replaceContent'; |
|
import PeerTitle from './peerTitle'; |
|
import CallDescriptionElement from './call/description'; |
|
import PopupCall from './call'; |
|
import GroupCallMicrophoneIconMini from './groupCall/microphoneIconMini'; |
|
import CallInstance from '../lib/calls/callInstance'; |
|
import {AppManagers} from '../lib/appManagers/managers'; |
|
import groupCallsController from '../lib/calls/groupCallsController'; |
|
import StreamManager from '../lib/calls/streamManager'; |
|
import callsController from '../lib/calls/callsController'; |
|
|
|
function convertCallStateToGroupState(state: CALL_STATE, isMuted: boolean) { |
|
switch(state) { |
|
case CALL_STATE.CLOSING: |
|
case CALL_STATE.CLOSED: |
|
return GROUP_CALL_STATE.CLOSED; |
|
case CALL_STATE.CONNECTED: |
|
return isMuted ? GROUP_CALL_STATE.MUTED : GROUP_CALL_STATE.UNMUTED; |
|
default: |
|
return GROUP_CALL_STATE.CONNECTING; |
|
} |
|
} |
|
|
|
const CLASS_NAME = 'topbar-call'; |
|
|
|
export default class TopbarCall { |
|
public container: HTMLElement; |
|
private listenerSetter: ListenerSetter; |
|
private weave: TopbarWeave; |
|
private center: HTMLDivElement; |
|
private groupCallTitle: GroupCallTitleElement; |
|
private groupCallDescription: GroupCallDescriptionElement; |
|
private groupCallMicrophoneIconMini: GroupCallMicrophoneIconMini; |
|
private callDescription: CallDescriptionElement; |
|
|
|
private currentDescription: GroupCallDescriptionElement | CallDescriptionElement; |
|
|
|
private instance: GroupCallInstance | any/* CallInstance */; |
|
private instanceListenerSetter: ListenerSetter; |
|
|
|
constructor( |
|
private managers: AppManagers |
|
) { |
|
const listenerSetter = this.listenerSetter = new ListenerSetter(); |
|
|
|
listenerSetter.add(callsController)('instance', ({instance}) => { |
|
if(!this.instance) { |
|
this.updateInstance(instance); |
|
} |
|
}); |
|
|
|
listenerSetter.add(callsController)('accepting', (instance) => { |
|
if(this.instance !== instance) { |
|
this.updateInstance(instance); |
|
} |
|
}); |
|
|
|
listenerSetter.add(groupCallsController)('instance', (instance) => { |
|
this.updateInstance(instance); |
|
}); |
|
|
|
listenerSetter.add(rootScope)('group_call_update', (groupCall) => { |
|
const instance = groupCallsController.groupCall; |
|
if(instance?.id === groupCall.id) { |
|
this.updateInstance(instance); |
|
} |
|
}); |
|
|
|
listenerSetter.add(StreamManager.ANALYSER_LISTENER)('amplitude', ({amplitudes, type}) => { |
|
const {weave} = this; |
|
if(!amplitudes.length || !weave/* || type !== 'input' */) return; |
|
|
|
let max = 0; |
|
for(let i = 0; i < amplitudes.length; ++i) { |
|
const {type, value} = amplitudes[i]; |
|
max = value > max ? value : max; |
|
} |
|
|
|
weave.setAmplitude(max); |
|
}); |
|
} |
|
|
|
private onState = () => { |
|
this.updateInstance(this.instance); |
|
}; |
|
|
|
private clearCurrentInstance() { |
|
if(!this.instance) return; |
|
this.center.textContent = ''; |
|
|
|
if(this.currentDescription) { |
|
this.currentDescription.detach(); |
|
this.currentDescription = undefined; |
|
} |
|
|
|
this.instance = undefined; |
|
this.instanceListenerSetter.removeAll(); |
|
} |
|
|
|
private updateInstance(instance: TopbarCall['instance']) { |
|
if(this.construct) { |
|
this.construct(); |
|
this.construct = undefined; |
|
} |
|
|
|
const isChangingInstance = this.instance !== instance; |
|
if(isChangingInstance) { |
|
this.clearCurrentInstance(); |
|
|
|
this.instance = instance; |
|
this.instanceListenerSetter = new ListenerSetter(); |
|
|
|
this.instanceListenerSetter.add(instance as GroupCallInstance)('state', this.onState); |
|
|
|
if(instance instanceof GroupCallInstance) { |
|
this.currentDescription = this.groupCallDescription; |
|
} else { |
|
this.currentDescription = this.callDescription; |
|
this.instanceListenerSetter.add(instance)('muted', this.onState); |
|
} |
|
|
|
this.container.classList.toggle('is-call', !(instance instanceof GroupCallInstance)); |
|
} |
|
|
|
const isMuted = this.instance.isMuted; |
|
const state = instance instanceof GroupCallInstance ? instance.state : convertCallStateToGroupState(instance.connectionState, isMuted); |
|
|
|
const {weave} = this; |
|
|
|
weave.componentDidMount(); |
|
|
|
const isClosed = state === GROUP_CALL_STATE.CLOSED; |
|
if((!document.body.classList.contains('is-calling') || isChangingInstance) || isClosed) { |
|
if(isClosed) { |
|
weave.setAmplitude(0); |
|
} |
|
|
|
SetTransition({ |
|
element: document.body, |
|
className: 'is-calling', |
|
forwards: !isClosed, |
|
duration: 250, |
|
onTransitionEnd: isClosed ? () => { |
|
weave.componentWillUnmount(); |
|
|
|
this.clearCurrentInstance(); |
|
} : undefined |
|
}); |
|
} |
|
|
|
if(isClosed) { |
|
return; |
|
} |
|
|
|
weave.setCurrentState(state, true); |
|
// if(state === GROUP_CALL_STATE.CONNECTING) { |
|
// weave.setCurrentState(state, true); |
|
// } else { |
|
// /* var a = 0; |
|
// animate(() => { |
|
// a += 0.1; |
|
// if(a > 1) a = 0; |
|
// weave.setAmplitude(a); |
|
// return true; |
|
// }); |
|
// weave.setAmplitude(1); */ |
|
// weave.setCurrentState(state, true); |
|
// } |
|
|
|
this.setTitle(instance); |
|
this.setDescription(instance); |
|
this.groupCallMicrophoneIconMini.setState(!isMuted); |
|
} |
|
|
|
private setDescription(instance: TopbarCall['instance']) { |
|
return this.currentDescription.update(instance as any); |
|
} |
|
|
|
private setTitle(instance: TopbarCall['instance']) { |
|
if(instance instanceof GroupCallInstance) { |
|
return this.groupCallTitle.update(instance); |
|
} else { |
|
replaceContent(this.center, new PeerTitle({peerId: instance.interlocutorUserId.toPeerId()}).element); |
|
} |
|
} |
|
|
|
private construct() { |
|
const {listenerSetter} = this; |
|
const container = this.container = document.createElement('div'); |
|
container.classList.add('sidebar-header', CLASS_NAME + '-container'); |
|
|
|
const left = document.createElement('div'); |
|
left.classList.add(CLASS_NAME + '-left'); |
|
|
|
const groupCallMicrophoneIconMini = this.groupCallMicrophoneIconMini = new GroupCallMicrophoneIconMini(); |
|
|
|
const mute = ButtonIcon(); |
|
mute.append(groupCallMicrophoneIconMini.container); |
|
left.append(mute); |
|
|
|
const throttledMuteClick = throttle(() => { |
|
this.instance.toggleMuted(); |
|
}, 600, true); |
|
|
|
attachClickEvent(mute, (e) => { |
|
cancelEvent(e); |
|
throttledMuteClick(); |
|
}, {listenerSetter}); |
|
|
|
const center = this.center = document.createElement('div'); |
|
center.classList.add(CLASS_NAME + '-center'); |
|
|
|
this.groupCallTitle = new GroupCallTitleElement(center); |
|
this.groupCallDescription = new GroupCallDescriptionElement(left); |
|
|
|
this.callDescription = new CallDescriptionElement(left); |
|
|
|
const right = document.createElement('div'); |
|
right.classList.add(CLASS_NAME + '-right'); |
|
|
|
const end = ButtonIcon('endcall_filled'); |
|
right.append(end); |
|
|
|
attachClickEvent(end, (e) => { |
|
cancelEvent(e); |
|
|
|
const {instance} = this; |
|
if(!instance) { |
|
return; |
|
} |
|
|
|
if(instance instanceof GroupCallInstance) { |
|
instance.hangUp(); |
|
} else { |
|
instance.hangUp('phoneCallDiscardReasonHangup'); |
|
} |
|
}, {listenerSetter}); |
|
|
|
attachClickEvent(container, () => { |
|
if(this.instance instanceof GroupCallInstance) { |
|
if(PopupElement.getPopups(PopupGroupCall).length) { |
|
return; |
|
} |
|
|
|
PopupElement.createPopup(PopupGroupCall).show(); |
|
} else if(this.instance instanceof CallInstance) { |
|
const popups = PopupElement.getPopups(PopupCall); |
|
if(popups.find((popup) => popup.getCallInstance() === this.instance)) { |
|
return; |
|
} |
|
|
|
PopupElement.createPopup(PopupCall, this.instance).show(); |
|
} |
|
}, {listenerSetter}); |
|
|
|
container.append(left, center, right); |
|
|
|
const weave = this.weave = new TopbarWeave(); |
|
const weaveContainer = weave.render(CLASS_NAME + '-weave'); |
|
container.prepend(weaveContainer); |
|
|
|
document.getElementById('column-center').prepend(container); |
|
weave.componentDidMount(); |
|
} |
|
}
|
|
|