tweb/src/components/chat/audio.ts

185 lines
7.2 KiB
TypeScript
Raw Normal View History

2021-04-08 15:52:31 +02:00
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
2022-08-04 08:49:54 +02:00
import type {AppMessagesManager} from '../../lib/appManagers/appMessagesManager';
import type ChatTopbar from './topbar';
import rootScope from '../../lib/rootScope';
import appMediaPlaybackController, {AppMediaPlaybackController} from '../appMediaPlaybackController';
import DivAndCaption from '../divAndCaption';
import PinnedContainer from './pinnedContainer';
import Chat from './chat';
import cancelEvent from '../../helpers/dom/cancelEvent';
import {attachClickEvent} from '../../helpers/dom/clickEvent';
import replaceContent from '../../helpers/dom/replaceContent';
import PeerTitle from '../peerTitle';
import {i18n} from '../../lib/langPack';
import {formatFullSentTime} from '../../helpers/date';
import ButtonIcon from '../buttonIcon';
import {DocumentAttribute} from '../../layer';
import MediaProgressLine from '../mediaProgressLine';
import VolumeSelector from '../volumeSelector';
import wrapEmojiText from '../../lib/richTextProcessor/wrapEmojiText';
import {AppManagers} from '../../lib/appManagers/managers';
export default class ChatAudio extends PinnedContainer {
private toggleEl: HTMLElement;
2021-10-05 22:40:07 +02:00
private progressLine: MediaProgressLine;
private volumeSelector: VolumeSelector;
2022-02-11 15:56:28 +01:00
private fasterEl: HTMLElement;
private repeatEl: HTMLButtonElement;
constructor(protected topbar: ChatTopbar, protected chat: Chat, protected managers: AppManagers) {
2021-10-05 22:40:07 +02:00
super({
2022-08-04 08:49:54 +02:00
topbar,
chat,
listenerSetter: topbar.listenerSetter,
className: 'audio',
2021-10-05 22:40:07 +02:00
divAndCaption: new DivAndCaption(
2022-08-04 08:49:54 +02:00
'pinned-audio',
(title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment) => {
replaceContent(this.divAndCaption.title, title);
replaceContent(this.divAndCaption.subtitle, subtitle);
}
2022-08-04 08:49:54 +02:00
),
2021-10-05 22:40:07 +02:00
onClose: () => {
appMediaPlaybackController.stop(undefined, true);
2021-10-05 22:40:07 +02:00
},
floating: true
});
this.divAndCaption.border.remove();
2022-02-04 19:26:45 +01:00
const prevEl = ButtonIcon('fast_rewind active', {noRipple: true});
const nextEl = ButtonIcon('fast_forward active', {noRipple: true});
2021-10-05 22:40:07 +02:00
const attachClick = (elem: HTMLElement, callback: () => void) => {
attachClickEvent(elem, (e) => {
cancelEvent(e);
callback();
}, {listenerSetter: this.topbar.listenerSetter});
};
attachClick(prevEl, () => {
appMediaPlaybackController.previous();
});
attachClick(nextEl, () => {
appMediaPlaybackController.next();
});
this.toggleEl = ButtonIcon('', {noRipple: true});
this.toggleEl.classList.add('active', 'pinned-audio-ico', 'tgico');
attachClick(this.toggleEl, () => {
appMediaPlaybackController.toggle();
2021-10-05 22:40:07 +02:00
});
this.wrapper.prepend(this.wrapper.firstElementChild, prevEl, this.toggleEl, nextEl);
this.volumeSelector = new VolumeSelector(this.listenerSetter, true);
const volumeProgressLineContainer = document.createElement('div');
volumeProgressLineContainer.classList.add('progress-line-container');
volumeProgressLineContainer.append(this.volumeSelector.container);
const tunnel = document.createElement('div');
tunnel.classList.add('pinned-audio-volume-tunnel');
this.volumeSelector.btn.classList.add('pinned-audio-volume', 'active');
this.volumeSelector.btn.prepend(tunnel);
this.volumeSelector.btn.append(volumeProgressLineContainer);
this.repeatEl = ButtonIcon('audio_repeat', {noRipple: true});
attachClick(this.repeatEl, () => {
const params = appMediaPlaybackController.getPlaybackParams();
if(!params.round) {
appMediaPlaybackController.round = true;
} else if(params.loop) {
appMediaPlaybackController.round = false;
appMediaPlaybackController.loop = false;
} else {
appMediaPlaybackController.loop = !appMediaPlaybackController.loop;
}
});
2022-02-11 15:56:28 +01:00
const fasterEl = this.fasterEl = ButtonIcon('playback_2x', {noRipple: true});
attachClick(fasterEl, () => {
appMediaPlaybackController.playbackRate = fasterEl.classList.contains('active') ? 1 : 1.75;
});
this.wrapperUtils.prepend(this.volumeSelector.btn, fasterEl, this.repeatEl);
2021-10-05 22:40:07 +02:00
const progressWrapper = document.createElement('div');
progressWrapper.classList.add('pinned-audio-progress-wrapper');
this.progressLine = new MediaProgressLine({
media: undefined,
streamable: undefined,
withTransition: true,
useTransform: true
});
2021-10-05 22:40:07 +02:00
this.progressLine.container.classList.add('pinned-audio-progress');
progressWrapper.append(this.progressLine.container);
this.wrapper.insertBefore(progressWrapper, this.wrapperUtils);
this.topbar.listenerSetter.add(appMediaPlaybackController)('play', this.onMediaPlay);
this.topbar.listenerSetter.add(appMediaPlaybackController)('pause', this.onPause);
this.topbar.listenerSetter.add(appMediaPlaybackController)('stop', this.onStop);
this.topbar.listenerSetter.add(appMediaPlaybackController)('playbackParams', this.onPlaybackParams);
2022-02-11 15:56:28 +01:00
const playingDetails = appMediaPlaybackController.getPlayingDetails();
if(playingDetails) {
this.onMediaPlay(playingDetails);
this.onPlaybackParams(playingDetails.playbackParams);
2022-02-11 15:56:28 +01:00
}
}
2022-02-11 15:56:28 +01:00
public destroy() {
if(this.progressLine) {
this.progressLine.removeListeners();
}
}
2022-02-11 15:56:28 +01:00
private onPlaybackParams = (playbackParams: ReturnType<AppMediaPlaybackController['getPlaybackParams']>) => {
this.fasterEl.classList.toggle('active', playbackParams.playbackRate > 1);
this.repeatEl.classList.remove('tgico-audio_repeat', 'tgico-audio_repeat_single');
this.repeatEl.classList.add(playbackParams.loop ? 'tgico-audio_repeat_single' : 'tgico-audio_repeat');
this.repeatEl.classList.toggle('active', playbackParams.loop || playbackParams.round);
2022-02-11 15:56:28 +01:00
};
private onPause = () => {
this.toggleEl.classList.remove('flip-icon');
};
private onStop = () => {
this.toggle(true);
};
2022-08-04 08:49:54 +02:00
2022-04-16 12:07:17 +02:00
private onMediaPlay = ({doc, message, media, playbackParams}: ReturnType<AppMediaPlaybackController['getPlayingDetails']>) => {
2022-04-19 21:33:56 +02:00
let title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment;
const isMusic = doc.type !== 'voice' && doc.type !== 'round';
if(!isMusic) {
2022-04-04 17:09:32 +02:00
title = new PeerTitle({peerId: message.fromId, fromName: message.fwd_from?.from_name}).element;
2022-02-11 15:56:28 +01:00
2022-08-04 08:49:54 +02:00
// subtitle = 'Voice message';
2022-02-11 15:56:28 +01:00
subtitle = formatFullSentTime(message.date);
} else {
2022-04-19 21:33:56 +02:00
const audioAttribute = doc.attributes.find((attr) => attr._ === 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio;
2022-04-25 16:54:30 +02:00
title = wrapEmojiText(audioAttribute?.title ?? doc.file_name);
subtitle = audioAttribute?.performer ? wrapEmojiText(audioAttribute.performer) : i18n('AudioUnknownArtist');
2022-02-11 15:56:28 +01:00
}
this.fasterEl.classList.toggle('hide', isMusic);
this.repeatEl.classList.toggle('hide', !isMusic);
2022-04-16 12:07:17 +02:00
this.onPlaybackParams(playbackParams);
this.volumeSelector.setVolume();
2022-02-11 15:56:28 +01:00
this.progressLine.setMedia(media);
this.fill(title, subtitle, message);
// this.toggleEl.classList.add('flip-icon');
this.toggleEl.classList.toggle('flip-icon', !media.paused);
this.toggle(false);
};
2021-06-11 13:52:04 +02:00
}