Single playback controller for audio & round video
This commit is contained in:
parent
6fd10adaef
commit
9339260fde
@ -1,149 +0,0 @@
|
|||||||
import { MTDocument } from "../types";
|
|
||||||
import { $rootScope } from "../lib/utils";
|
|
||||||
import appMessagesManager from "../lib/appManagers/appMessagesManager";
|
|
||||||
import appDocsManager from "../lib/appManagers/appDocsManager";
|
|
||||||
import opusDecodeController from "../lib/opusDecodeController";
|
|
||||||
|
|
||||||
// TODO: если удалить сообщение, и при этом аудио будет играть - оно не остановится, и можно будет по нему перейти вникуда
|
|
||||||
|
|
||||||
class AppAudio {
|
|
||||||
private container: HTMLElement;
|
|
||||||
private audios: {[mid: string]: HTMLAudioElement} = {};
|
|
||||||
private playingAudio: HTMLAudioElement;
|
|
||||||
|
|
||||||
public willBePlayedAudio: HTMLAudioElement;
|
|
||||||
|
|
||||||
private prevMid: number;
|
|
||||||
private nextMid: number;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.container = document.createElement('div');
|
|
||||||
//this.container.style.cssText = 'position: absolute; top: -10000px; left: -10000px;';
|
|
||||||
this.container.style.cssText = 'display: none;';
|
|
||||||
document.body.append(this.container);
|
|
||||||
}
|
|
||||||
|
|
||||||
public addAudio(doc: MTDocument, mid: number) {
|
|
||||||
if(this.audios[mid]) return this.audios[mid];
|
|
||||||
|
|
||||||
const audio = document.createElement('audio');
|
|
||||||
const source = document.createElement('source');
|
|
||||||
source.type = doc.type == 'voice' && !opusDecodeController.isPlaySupported() ? 'audio/wav' : doc.mime_type;
|
|
||||||
|
|
||||||
audio.autoplay = false;
|
|
||||||
audio.volume = 1;
|
|
||||||
audio.append(source);
|
|
||||||
|
|
||||||
audio.addEventListener('playing', (e) => {
|
|
||||||
if(this.playingAudio != audio) {
|
|
||||||
if(this.playingAudio && !this.playingAudio.paused) {
|
|
||||||
this.playingAudio.pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.playingAudio = audio;
|
|
||||||
this.loadSiblingsAudio(doc.type as 'voice' | 'audio', mid);
|
|
||||||
}
|
|
||||||
|
|
||||||
// audio_pause не успеет сработать без таймаута
|
|
||||||
setTimeout(() => {
|
|
||||||
$rootScope.$broadcast('audio_play', {doc, mid});
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
audio.addEventListener('pause', this.onPause);
|
|
||||||
audio.addEventListener('ended', this.onEnded);
|
|
||||||
|
|
||||||
const onError = (e: Event) => {
|
|
||||||
if(this.nextMid == mid) {
|
|
||||||
this.loadSiblingsAudio(doc.type as 'voice' | 'audio', mid).then(() => {
|
|
||||||
if(this.nextMid && this.audios[this.nextMid]) {
|
|
||||||
this.audios[this.nextMid].play();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
audio.addEventListener('error', onError);
|
|
||||||
|
|
||||||
const downloadPromise: Promise<any> = !doc.supportsStreaming ? appDocsManager.downloadDocNew(doc.id) : Promise.resolve();
|
|
||||||
|
|
||||||
downloadPromise.then(() => {
|
|
||||||
this.container.append(audio);
|
|
||||||
source.src = doc.url;
|
|
||||||
}, onError);
|
|
||||||
|
|
||||||
return this.audios[mid] = audio;
|
|
||||||
}
|
|
||||||
|
|
||||||
onPause = (e: Event) => {
|
|
||||||
$rootScope.$broadcast('audio_pause');
|
|
||||||
};
|
|
||||||
|
|
||||||
onEnded = (e: Event) => {
|
|
||||||
this.onPause(e);
|
|
||||||
|
|
||||||
if(this.nextMid) {
|
|
||||||
this.audios[this.nextMid].play();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private loadSiblingsAudio(type: 'voice' | 'audio', mid: number) {
|
|
||||||
const audio = this.playingAudio;
|
|
||||||
const message = appMessagesManager.getMessage(mid);
|
|
||||||
this.prevMid = this.nextMid = 0;
|
|
||||||
|
|
||||||
return appMessagesManager.getSearch(message.peerID, '', {
|
|
||||||
_: type == 'audio' ? 'inputMessagesFilterMusic' : 'inputMessagesFilterVoice'
|
|
||||||
}, mid, 3, 0, 2).then(value => {
|
|
||||||
if(this.playingAudio != audio) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(let m of value.history) {
|
|
||||||
if(m > mid) {
|
|
||||||
this.nextMid = m;
|
|
||||||
} else if(m < mid) {
|
|
||||||
this.prevMid = m;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[this.prevMid, this.nextMid].filter(Boolean).forEach(mid => {
|
|
||||||
const message = appMessagesManager.getMessage(mid);
|
|
||||||
this.addAudio(message.media.document, mid);
|
|
||||||
});
|
|
||||||
|
|
||||||
//console.log('loadSiblingsAudio', audio, type, mid, value, this.prevMid, this.nextMid);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public toggle() {
|
|
||||||
if(!this.playingAudio) return;
|
|
||||||
|
|
||||||
if(this.playingAudio.paused) {
|
|
||||||
this.playingAudio.play();
|
|
||||||
} else {
|
|
||||||
this.playingAudio.pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public pause() {
|
|
||||||
if(!this.playingAudio || this.playingAudio.paused) return;
|
|
||||||
this.playingAudio.pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
public willBePlayed(audio: HTMLAudioElement) {
|
|
||||||
this.willBePlayedAudio = audio;
|
|
||||||
}
|
|
||||||
|
|
||||||
public audioExists(mid: number) {
|
|
||||||
return !!this.audios[mid];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const appAudio = new AppAudio();
|
|
||||||
// @ts-ignore
|
|
||||||
if(process.env.NODE_ENV != 'production') {
|
|
||||||
(window as any).appAudio = appAudio;
|
|
||||||
}
|
|
||||||
export default appAudio;
|
|
157
src/components/appMediaPlaybackController.ts
Normal file
157
src/components/appMediaPlaybackController.ts
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
import { MTDocument } from "../types";
|
||||||
|
import { $rootScope } from "../lib/utils";
|
||||||
|
import appMessagesManager from "../lib/appManagers/appMessagesManager";
|
||||||
|
import appDocsManager from "../lib/appManagers/appDocsManager";
|
||||||
|
|
||||||
|
// TODO: если удалить сообщение, и при этом аудио будет играть - оно не остановится, и можно будет по нему перейти вникуда
|
||||||
|
|
||||||
|
type HTMLMediaElement = HTMLAudioElement | HTMLVideoElement;
|
||||||
|
|
||||||
|
type MediaType = 'voice' | 'audio' | 'round';
|
||||||
|
|
||||||
|
class AppMediaPlaybackController {
|
||||||
|
private container: HTMLElement;
|
||||||
|
private media: {[mid: string]: HTMLMediaElement} = {};
|
||||||
|
private playingMedia: HTMLMediaElement;
|
||||||
|
|
||||||
|
public willBePlayedMedia: HTMLMediaElement;
|
||||||
|
|
||||||
|
private prevMid: number;
|
||||||
|
private nextMid: number;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.container = document.createElement('div');
|
||||||
|
//this.container.style.cssText = 'position: absolute; top: -10000px; left: -10000px;';
|
||||||
|
this.container.style.cssText = 'display: none;';
|
||||||
|
document.body.append(this.container);
|
||||||
|
}
|
||||||
|
|
||||||
|
public addMedia(doc: MTDocument, mid: number): HTMLMediaElement {
|
||||||
|
if(this.media[mid]) return this.media[mid];
|
||||||
|
|
||||||
|
const media = document.createElement(doc.type == 'round' ? 'video' : 'audio');
|
||||||
|
//const source = document.createElement('source');
|
||||||
|
//source.type = doc.type == 'voice' && !opusDecodeController.isPlaySupported() ? 'audio/wav' : doc.mime_type;
|
||||||
|
|
||||||
|
media.autoplay = false;
|
||||||
|
media.volume = 1;
|
||||||
|
//media.append(source);
|
||||||
|
|
||||||
|
media.addEventListener('playing', () => {
|
||||||
|
if(this.playingMedia != media) {
|
||||||
|
if(this.playingMedia && !this.playingMedia.paused) {
|
||||||
|
this.playingMedia.pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.playingMedia = media;
|
||||||
|
this.loadSiblingsMedia(doc.type as MediaType, mid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// audio_pause не успеет сработать без таймаута
|
||||||
|
setTimeout(() => {
|
||||||
|
$rootScope.$broadcast('audio_play', {doc, mid});
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
media.addEventListener('pause', this.onPause);
|
||||||
|
media.addEventListener('ended', this.onEnded);
|
||||||
|
|
||||||
|
const onError = (e: Event) => {
|
||||||
|
if(this.nextMid == mid) {
|
||||||
|
this.loadSiblingsMedia(doc.type as MediaType, mid).then(() => {
|
||||||
|
if(this.nextMid && this.media[this.nextMid]) {
|
||||||
|
this.media[this.nextMid].play();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
media.addEventListener('error', onError);
|
||||||
|
|
||||||
|
const downloadPromise: Promise<any> = !doc.supportsStreaming ? appDocsManager.downloadDocNew(doc.id) : Promise.resolve();
|
||||||
|
|
||||||
|
downloadPromise.then(() => {
|
||||||
|
//if(doc.type != 'round') {
|
||||||
|
this.container.append(media);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//source.src = doc.url;
|
||||||
|
media.src = doc.url;
|
||||||
|
}, onError);
|
||||||
|
|
||||||
|
return this.media[mid] = media;
|
||||||
|
}
|
||||||
|
|
||||||
|
onPause = (e: Event) => {
|
||||||
|
$rootScope.$broadcast('audio_pause');
|
||||||
|
};
|
||||||
|
|
||||||
|
onEnded = (e: Event) => {
|
||||||
|
this.onPause(e);
|
||||||
|
|
||||||
|
if(this.nextMid) {
|
||||||
|
this.media[this.nextMid].play();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private loadSiblingsMedia(type: MediaType, mid: number) {
|
||||||
|
const media = this.playingMedia;
|
||||||
|
const message = appMessagesManager.getMessage(mid);
|
||||||
|
this.prevMid = this.nextMid = 0;
|
||||||
|
|
||||||
|
return appMessagesManager.getSearch(message.peerID, '', {
|
||||||
|
//_: type == 'audio' ? 'inputMessagesFilterMusic' : (type == 'round' ? 'inputMessagesFilterRoundVideo' : 'inputMessagesFilterVoice')
|
||||||
|
_: type == 'audio' ? 'inputMessagesFilterMusic' : 'inputMessagesFilterRoundVoice'
|
||||||
|
}, mid, 3, 0, 2).then(value => {
|
||||||
|
if(this.playingMedia != media) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let m of value.history) {
|
||||||
|
if(m > mid) {
|
||||||
|
this.nextMid = m;
|
||||||
|
} else if(m < mid) {
|
||||||
|
this.prevMid = m;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[this.prevMid, this.nextMid].filter(Boolean).forEach(mid => {
|
||||||
|
const message = appMessagesManager.getMessage(mid);
|
||||||
|
this.addMedia(message.media.document, mid);
|
||||||
|
});
|
||||||
|
|
||||||
|
//console.log('loadSiblingsAudio', audio, type, mid, value, this.prevMid, this.nextMid);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public toggle() {
|
||||||
|
if(!this.playingMedia) return;
|
||||||
|
|
||||||
|
if(this.playingMedia.paused) {
|
||||||
|
this.playingMedia.play();
|
||||||
|
} else {
|
||||||
|
this.playingMedia.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public pause() {
|
||||||
|
if(!this.playingMedia || this.playingMedia.paused) return;
|
||||||
|
this.playingMedia.pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
public willBePlayed(media: HTMLMediaElement) {
|
||||||
|
this.willBePlayedMedia = media;
|
||||||
|
}
|
||||||
|
|
||||||
|
public mediaExists(mid: number) {
|
||||||
|
return !!this.media[mid];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const appMediaPlaybackController = new AppMediaPlaybackController();
|
||||||
|
// @ts-ignore
|
||||||
|
if(process.env.NODE_ENV != 'production') {
|
||||||
|
(window as any).appMediaPlaybackController = appMediaPlaybackController;
|
||||||
|
}
|
||||||
|
export default appMediaPlaybackController;
|
@ -3,7 +3,7 @@ import { RichTextProcessor } from "../lib/richtextprocessor";
|
|||||||
import { formatDate } from "./wrappers";
|
import { formatDate } from "./wrappers";
|
||||||
import ProgressivePreloader from "./preloader";
|
import ProgressivePreloader from "./preloader";
|
||||||
import { MediaProgressLine } from "../lib/mediaPlayer";
|
import { MediaProgressLine } from "../lib/mediaPlayer";
|
||||||
import appAudio from "./appAudio";
|
import appMediaPlaybackController from "./appMediaPlaybackController";
|
||||||
import { MTDocument } from "../types";
|
import { MTDocument } from "../types";
|
||||||
import { mediaSizes } from "../lib/config";
|
import { mediaSizes } from "../lib/config";
|
||||||
import { Download } from "../lib/appManagers/appDownloadManager";
|
import { Download } from "../lib/appManagers/appDownloadManager";
|
||||||
@ -313,7 +313,7 @@ export default class AudioElement extends HTMLElement {
|
|||||||
audioTimeDiv.innerHTML = durationStr;
|
audioTimeDiv.innerHTML = durationStr;
|
||||||
|
|
||||||
const onLoad = () => {
|
const onLoad = () => {
|
||||||
const audio = this.audio = appAudio.addAudio(doc, mid);
|
const audio = this.audio = appMediaPlaybackController.addMedia(doc, mid);
|
||||||
|
|
||||||
this.onTypeDisconnect = onTypeLoad();
|
this.onTypeDisconnect = onTypeLoad();
|
||||||
|
|
||||||
@ -390,13 +390,13 @@ export default class AudioElement extends HTMLElement {
|
|||||||
this.addEventListener('click', onClick);
|
this.addEventListener('click', onClick);
|
||||||
this.click();
|
this.click();
|
||||||
} else {
|
} else {
|
||||||
if(appAudio.audioExists(mid)) { // чтобы показать прогресс, если аудио уже было скачано
|
if(appMediaPlaybackController.mediaExists(mid)) { // чтобы показать прогресс, если аудио уже было скачано
|
||||||
onLoad();
|
onLoad();
|
||||||
} else {
|
} else {
|
||||||
const r = () => {
|
const r = () => {
|
||||||
onLoad();
|
onLoad();
|
||||||
|
|
||||||
appAudio.willBePlayed(this.audio); // prepare for loading audio
|
appMediaPlaybackController.willBePlayed(this.audio); // prepare for loading audio
|
||||||
|
|
||||||
if(!preloader) {
|
if(!preloader) {
|
||||||
preloader = new ProgressivePreloader(null, false);
|
preloader = new ProgressivePreloader(null, false);
|
||||||
@ -413,9 +413,9 @@ export default class AudioElement extends HTMLElement {
|
|||||||
|
|
||||||
//setTimeout(() => {
|
//setTimeout(() => {
|
||||||
// release loaded audio
|
// release loaded audio
|
||||||
if(appAudio.willBePlayedAudio == this.audio) {
|
if(appMediaPlaybackController.willBePlayedMedia == this.audio) {
|
||||||
this.audio.play();
|
this.audio.play();
|
||||||
appAudio.willBePlayedAudio = null;
|
appMediaPlaybackController.willBePlayedMedia = null;
|
||||||
}
|
}
|
||||||
//}, 10e3);
|
//}, 10e3);
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import appPhotosManager, { MTPhoto } from '../lib/appManagers/appPhotosManager';
|
import appPhotosManager, { MTPhoto } from '../lib/appManagers/appPhotosManager';
|
||||||
import LottieLoader from '../lib/lottieLoader';
|
import LottieLoader from '../lib/lottieLoader';
|
||||||
import appDocsManager from "../lib/appManagers/appDocsManager";
|
import appDocsManager from "../lib/appManagers/appDocsManager";
|
||||||
import { formatBytes, getEmojiToneIndex } from "../lib/utils";
|
import { formatBytes, getEmojiToneIndex, isInDOM } from "../lib/utils";
|
||||||
import ProgressivePreloader from './preloader';
|
import ProgressivePreloader from './preloader';
|
||||||
import LazyLoadQueue from './lazyLoadQueue';
|
import LazyLoadQueue from './lazyLoadQueue';
|
||||||
import VideoPlayer from '../lib/mediaPlayer';
|
import VideoPlayer from '../lib/mediaPlayer';
|
||||||
@ -17,6 +17,7 @@ import AudioElement from './audio';
|
|||||||
import { DownloadBlob } from '../lib/appManagers/appDownloadManager';
|
import { DownloadBlob } from '../lib/appManagers/appDownloadManager';
|
||||||
import webpWorkerController from '../lib/webp/webpWorkerController';
|
import webpWorkerController from '../lib/webp/webpWorkerController';
|
||||||
import { readBlobAsText } from '../helpers/blob';
|
import { readBlobAsText } from '../helpers/blob';
|
||||||
|
import appMediaPlaybackController from './appMediaPlaybackController';
|
||||||
|
|
||||||
export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue, noInfo, group}: {
|
export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue, noInfo, group}: {
|
||||||
doc: MTDocument,
|
doc: MTDocument,
|
||||||
@ -55,7 +56,72 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
|||||||
return wrapPhoto(doc, message, container, boxWidth, boxHeight, withTail, isOut, lazyLoadQueue, middleware);
|
return wrapPhoto(doc, message, container, boxWidth, boxHeight, withTail, isOut, lazyLoadQueue, middleware);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* const video = doc.type == 'round' ? appMediaPlaybackController.addMedia(doc, message.mid) as HTMLVideoElement : document.createElement('video');
|
||||||
|
if(video.parentElement) {
|
||||||
|
video.remove();
|
||||||
|
} */
|
||||||
|
|
||||||
const video = document.createElement('video');
|
const video = document.createElement('video');
|
||||||
|
if(doc.type == 'round') {
|
||||||
|
video.muted = true;
|
||||||
|
const globalVideo = appMediaPlaybackController.addMedia(doc, message.mid);
|
||||||
|
|
||||||
|
video.addEventListener('canplay', () => {
|
||||||
|
if(globalVideo.currentTime > 0) {
|
||||||
|
video.currentTime = globalVideo.currentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!globalVideo.paused) {
|
||||||
|
// с закоментированными настройками - хром выключал видео при скролле, для этого нужно было включить видео - выйти из диалога, зайти заново и проскроллить вверх
|
||||||
|
/* video.autoplay = true;
|
||||||
|
video.loop = false; */
|
||||||
|
video.play();
|
||||||
|
}
|
||||||
|
}, {once: true});
|
||||||
|
|
||||||
|
const clear = () => {
|
||||||
|
//console.log('clearing video');
|
||||||
|
|
||||||
|
globalVideo.removeEventListener('timeupdate', onTimeUpdate);
|
||||||
|
globalVideo.removeEventListener('play', onGlobalPlay);
|
||||||
|
globalVideo.removeEventListener('pause', onGlobalPause);
|
||||||
|
video.removeEventListener('play', onVideoPlay);
|
||||||
|
video.removeEventListener('pause', onVideoPause);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTimeUpdate = () => {
|
||||||
|
if(!isInDOM(video)) {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onGlobalPlay = () => {
|
||||||
|
video.play();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onGlobalPause = () => {
|
||||||
|
video.pause();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onVideoPlay = () => {
|
||||||
|
globalVideo.play();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onVideoPause = () => {
|
||||||
|
//console.log('video pause event');
|
||||||
|
if(isInDOM(video)) {
|
||||||
|
globalVideo.pause();
|
||||||
|
} else {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
globalVideo.addEventListener('timeupdate', onTimeUpdate);
|
||||||
|
globalVideo.addEventListener('play', onGlobalPlay);
|
||||||
|
globalVideo.addEventListener('pause', onGlobalPause);
|
||||||
|
video.addEventListener('play', onVideoPlay);
|
||||||
|
video.addEventListener('pause', onVideoPause);
|
||||||
|
}
|
||||||
|
|
||||||
let img: HTMLImageElement;
|
let img: HTMLImageElement;
|
||||||
if(message) {
|
if(message) {
|
||||||
@ -154,7 +220,10 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
|||||||
}, {once: true});
|
}, {once: true});
|
||||||
//}
|
//}
|
||||||
|
|
||||||
renderImageFromUrl(video, doc.url);
|
//if(doc.type != 'round') {
|
||||||
|
renderImageFromUrl(video, doc.url);
|
||||||
|
//}
|
||||||
|
|
||||||
video.setAttribute('playsinline', '');
|
video.setAttribute('playsinline', '');
|
||||||
|
|
||||||
/* if(!container.parentElement) {
|
/* if(!container.parentElement) {
|
||||||
|
@ -35,7 +35,7 @@ import PopupStickers from '../../components/popupStickers';
|
|||||||
import SearchInput from '../../components/searchInput';
|
import SearchInput from '../../components/searchInput';
|
||||||
import AppSearch, { SearchGroup } from '../../components/appSearch';
|
import AppSearch, { SearchGroup } from '../../components/appSearch';
|
||||||
import PopupDatePicker from '../../components/popupDatepicker';
|
import PopupDatePicker from '../../components/popupDatepicker';
|
||||||
import appAudio from '../../components/appAudio';
|
import appMediaPlaybackController from '../../components/appMediaPlaybackController';
|
||||||
import appPollsManager from './appPollsManager';
|
import appPollsManager from './appPollsManager';
|
||||||
import { ripple } from '../../components/ripple';
|
import { ripple } from '../../components/ripple';
|
||||||
import { horizontalMenu } from '../../components/horizontalMenu';
|
import { horizontalMenu } from '../../components/horizontalMenu';
|
||||||
@ -420,20 +420,20 @@ class ChatAudio {
|
|||||||
this.container.style.display = 'none';
|
this.container.style.display = 'none';
|
||||||
this.container.parentElement.classList.remove('is-audio-shown');
|
this.container.parentElement.classList.remove('is-audio-shown');
|
||||||
if(this.toggle.classList.contains('flip-icon')) {
|
if(this.toggle.classList.contains('flip-icon')) {
|
||||||
appAudio.toggle();
|
appMediaPlaybackController.toggle();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.toggle.addEventListener('click', (e) => {
|
this.toggle.addEventListener('click', (e) => {
|
||||||
cancelEvent(e);
|
cancelEvent(e);
|
||||||
appAudio.toggle();
|
appMediaPlaybackController.toggle();
|
||||||
});
|
});
|
||||||
|
|
||||||
$rootScope.$on('audio_play', (e: CustomEvent) => {
|
$rootScope.$on('audio_play', (e: CustomEvent) => {
|
||||||
const {doc, mid} = e.detail;
|
const {doc, mid} = e.detail;
|
||||||
|
|
||||||
let title: string, subtitle: string;
|
let title: string, subtitle: string;
|
||||||
if(doc.type == 'voice') {
|
if(doc.type == 'voice' || doc.type == 'round') {
|
||||||
const message = appMessagesManager.getMessage(mid);
|
const message = appMessagesManager.getMessage(mid);
|
||||||
title = appPeersManager.getPeerTitle(message.fromID, false, true);
|
title = appPeersManager.getPeerTitle(message.fromID, false, true);
|
||||||
//subtitle = 'Voice message';
|
//subtitle = 'Voice message';
|
||||||
|
@ -12,10 +12,9 @@ import AvatarElement from "../../components/avatar";
|
|||||||
import LazyLoadQueue from "../../components/lazyLoadQueue";
|
import LazyLoadQueue from "../../components/lazyLoadQueue";
|
||||||
import appForward from "../../components/appForward";
|
import appForward from "../../components/appForward";
|
||||||
import { isSafari, mediaSizes, touchSupport } from "../config";
|
import { isSafari, mediaSizes, touchSupport } from "../config";
|
||||||
import appAudio from "../../components/appAudio";
|
|
||||||
import { deferredPromise } from "../polyfill";
|
import { deferredPromise } from "../polyfill";
|
||||||
import { MTDocument } from "../../types";
|
import { MTDocument } from "../../types";
|
||||||
import idbFileStorage from "../idb";
|
import appMediaPlaybackController from "../../components/appMediaPlaybackController";
|
||||||
|
|
||||||
// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию
|
// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию
|
||||||
// TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)
|
// TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)
|
||||||
@ -954,8 +953,8 @@ export class AppMediaViewer {
|
|||||||
video.dataset.overlay = '1';
|
video.dataset.overlay = '1';
|
||||||
|
|
||||||
// fix for simultaneous play
|
// fix for simultaneous play
|
||||||
appAudio.pause();
|
appMediaPlaybackController.pause();
|
||||||
appAudio.willBePlayedAudio = null;
|
appMediaPlaybackController.willBePlayedMedia = null;
|
||||||
|
|
||||||
Promise.all([canPlayThrough, onAnimationEnd]).then(() => {
|
Promise.all([canPlayThrough, onAnimationEnd]).then(() => {
|
||||||
const player = new VideoPlayer(video, true, media.supportsStreaming);
|
const player = new VideoPlayer(video, true, media.supportsStreaming);
|
||||||
|
@ -2896,7 +2896,7 @@ export class AppMessagesManager {
|
|||||||
var neededContents: {
|
var neededContents: {
|
||||||
[type: string]: boolean
|
[type: string]: boolean
|
||||||
} = {},
|
} = {},
|
||||||
neededDocType: string | boolean;
|
neededDocTypes: string[] = [];
|
||||||
var neededLimit = limit || 20;
|
var neededLimit = limit || 20;
|
||||||
var message;
|
var message;
|
||||||
|
|
||||||
@ -2908,32 +2908,36 @@ export class AppMessagesManager {
|
|||||||
case 'inputMessagesFilterPhotoVideo':
|
case 'inputMessagesFilterPhotoVideo':
|
||||||
neededContents['messageMediaPhoto'] = true;
|
neededContents['messageMediaPhoto'] = true;
|
||||||
neededContents['messageMediaDocument'] = true;
|
neededContents['messageMediaDocument'] = true;
|
||||||
neededDocType = 'video';
|
neededDocTypes.push('video');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'inputMessagesFilterVideo':
|
case 'inputMessagesFilterVideo':
|
||||||
neededContents['messageMediaDocument'] = true;
|
neededContents['messageMediaDocument'] = true;
|
||||||
neededDocType = 'video';
|
neededDocTypes.push('video');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'inputMessagesFilterDocument':
|
case 'inputMessagesFilterDocument':
|
||||||
neededContents['messageMediaDocument'] = true;
|
neededContents['messageMediaDocument'] = true;
|
||||||
neededDocType = false;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'inputMessagesFilterVoice':
|
case 'inputMessagesFilterVoice':
|
||||||
neededContents['messageMediaDocument'] = true;
|
neededContents['messageMediaDocument'] = true;
|
||||||
neededDocType = 'voice';
|
neededDocTypes.push('voice');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'inputMessagesFilterRoundVoice':
|
||||||
|
neededContents['messageMediaDocument'] = true;
|
||||||
|
neededDocTypes.push('round', 'voice');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'inputMessagesFilterRoundVideo':
|
case 'inputMessagesFilterRoundVideo':
|
||||||
neededContents['messageMediaDocument'] = true;
|
neededContents['messageMediaDocument'] = true;
|
||||||
neededDocType = 'round';
|
neededDocTypes.push('round');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'inputMessagesFilterMusic':
|
case 'inputMessagesFilterMusic':
|
||||||
neededContents['messageMediaDocument'] = true;
|
neededContents['messageMediaDocument'] = true;
|
||||||
neededDocType = 'audio';
|
neededDocTypes.push('audio');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'inputMessagesFilterUrl':
|
case 'inputMessagesFilterUrl':
|
||||||
@ -2955,9 +2959,9 @@ export class AppMessagesManager {
|
|||||||
for(let i = 0; i < historyStorage.history.length; i++) {
|
for(let i = 0; i < historyStorage.history.length; i++) {
|
||||||
message = this.messagesStorage[historyStorage.history[i]];
|
message = this.messagesStorage[historyStorage.history[i]];
|
||||||
if(message.media && neededContents[message.media._]) {
|
if(message.media && neededContents[message.media._]) {
|
||||||
if(neededDocType !== undefined &&
|
if(neededDocTypes.length &&
|
||||||
message.media._ == 'messageMediaDocument' &&
|
message.media._ == 'messageMediaDocument' &&
|
||||||
message.media.document.type != neededDocType) {
|
!neededDocTypes.includes(message.media.document.type)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { cancelEvent, whichChild } from "./utils";
|
import { cancelEvent } from "./utils";
|
||||||
import { touchSupport } from "./config";
|
import { touchSupport } from "./config";
|
||||||
|
|
||||||
export class ProgressLine {
|
export class ProgressLine {
|
||||||
@ -7,7 +7,7 @@ export class ProgressLine {
|
|||||||
protected seek: HTMLInputElement;
|
protected seek: HTMLInputElement;
|
||||||
|
|
||||||
protected duration = 1;
|
protected duration = 1;
|
||||||
protected mousedown = false;
|
public mousedown = false;
|
||||||
|
|
||||||
private events: Partial<{
|
private events: Partial<{
|
||||||
//onMouseMove: ProgressLine['onMouseMove'],
|
//onMouseMove: ProgressLine['onMouseMove'],
|
||||||
@ -343,7 +343,9 @@ export default class VideoPlayer {
|
|||||||
volumeSvg.innerHTML = `<path d="${d}"></path>`;
|
volumeSvg.innerHTML = `<path d="${d}"></path>`;
|
||||||
} catch(err) {}
|
} catch(err) {}
|
||||||
|
|
||||||
volumeProgress.setProgress(video.muted ? 0 : volume);
|
if(!volumeProgress.mousedown) {
|
||||||
|
volumeProgress.setProgress(video.muted ? 0 : volume);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// не вызовется повторно если на 1 установить 1
|
// не вызовется повторно если на 1 установить 1
|
||||||
@ -439,6 +441,14 @@ export default class VideoPlayer {
|
|||||||
iconVolume.style.display = '';
|
iconVolume.style.display = '';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
video.addEventListener('play', () => {
|
||||||
|
this.wrapper.classList.add('is-playing');
|
||||||
|
});
|
||||||
|
|
||||||
|
video.addEventListener('pause', () => {
|
||||||
|
this.wrapper.classList.remove('is-playing');
|
||||||
|
});
|
||||||
|
|
||||||
if(video.duration > 0) {
|
if(video.duration > 0) {
|
||||||
timeDuration.innerHTML = String(Math.round(video.duration)).toHHMMSS();
|
timeDuration.innerHTML = String(Math.round(video.duration)).toHHMMSS();
|
||||||
@ -469,7 +479,7 @@ export default class VideoPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.video[this.video.paused ? 'play' : 'pause']();
|
this.video[this.video.paused ? 'play' : 'pause']();
|
||||||
this.video.paused ? this.wrapper.classList.remove('is-playing') : this.wrapper.classList.add('is-playing');
|
//this.wrapper.classList.toggle('is-playing', !this.video.paused);
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleProgress(timeDuration: HTMLElement, circumference: number, circle: SVGCircleElement, updateInterval: number) {
|
private handleProgress(timeDuration: HTMLElement, circumference: number, circle: SVGCircleElement, updateInterval: number) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user