Reimplemented round videos
This commit is contained in:
parent
444ea1f446
commit
8fe6968c35
@ -19,6 +19,7 @@ export class AnimationIntersector {
|
||||
private onlyOnePlayableGroup: string = '';
|
||||
|
||||
private intersectionLockedGroups: {[group: string]: true} = {};
|
||||
private videosLocked = false;
|
||||
|
||||
constructor() {
|
||||
this.observer = new IntersectionObserver((entries) => {
|
||||
@ -52,6 +53,20 @@ export class AnimationIntersector {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
rootScope.on('audio_play', ({doc}) => {
|
||||
if(doc.type === 'round') {
|
||||
this.videosLocked = true;
|
||||
this.checkAnimations();
|
||||
}
|
||||
});
|
||||
|
||||
rootScope.on('audio_pause', () => {
|
||||
if(this.videosLocked) {
|
||||
this.videosLocked = false;
|
||||
this.checkAnimations();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public getAnimations(element: HTMLElement) {
|
||||
@ -132,7 +147,7 @@ export class AnimationIntersector {
|
||||
return;
|
||||
}
|
||||
|
||||
if(blurred || (this.onlyOnePlayableGroup && this.onlyOnePlayableGroup !== group)) {
|
||||
if(blurred || (this.onlyOnePlayableGroup && this.onlyOnePlayableGroup !== group) || (animation instanceof HTMLVideoElement && this.videosLocked)) {
|
||||
if(!animation.paused) {
|
||||
//console.warn('pause animation:', animation);
|
||||
animation.pause();
|
||||
|
@ -177,7 +177,7 @@ class AppMediaPlaybackController {
|
||||
media.safariBuffering = value;
|
||||
}
|
||||
|
||||
onPause = (e: Event) => {
|
||||
onPause = (e?: Event) => {
|
||||
/* const target = e.target as HTMLMediaElement;
|
||||
if(!isInDOM(target)) {
|
||||
this.container.append(target);
|
||||
@ -188,7 +188,7 @@ class AppMediaPlaybackController {
|
||||
rootScope.broadcast('audio_pause');
|
||||
};
|
||||
|
||||
onEnded = (e: Event) => {
|
||||
onEnded = (e?: Event) => {
|
||||
this.onPause(e);
|
||||
|
||||
//console.log('on media end');
|
||||
|
@ -30,6 +30,7 @@ import appImManager from '../lib/appManagers/appImManager';
|
||||
import { SearchSuperContext } from './appSearchSuper.';
|
||||
import rootScope from '../lib/rootScope';
|
||||
import { onVideoLoad } from '../helpers/files';
|
||||
import { animateSingle } from '../helpers/animation';
|
||||
|
||||
const MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB
|
||||
|
||||
@ -55,26 +56,24 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
||||
let spanTime: HTMLElement;
|
||||
|
||||
if(!noInfo) {
|
||||
if(doc.type !== 'round') {
|
||||
spanTime = document.createElement('span');
|
||||
spanTime.classList.add('video-time');
|
||||
container.append(spanTime);
|
||||
spanTime = document.createElement('span');
|
||||
spanTime.classList.add('video-time');
|
||||
container.append(spanTime);
|
||||
|
||||
if(doc.type !== 'gif') {
|
||||
spanTime.innerText = (doc.duration + '').toHHMMSS(false);
|
||||
if(doc.type !== 'gif') {
|
||||
spanTime.innerText = (doc.duration + '').toHHMMSS(false);
|
||||
|
||||
if(!noPlayButton) {
|
||||
if(canAutoplay) {
|
||||
spanTime.classList.add('tgico', 'can-autoplay');
|
||||
} else {
|
||||
const spanPlay = document.createElement('span');
|
||||
spanPlay.classList.add('video-play', 'tgico-largeplay', 'btn-circle', 'position-center');
|
||||
container.append(spanPlay);
|
||||
}
|
||||
if(!noPlayButton && doc.type !== 'round') {
|
||||
if(canAutoplay) {
|
||||
spanTime.classList.add('tgico', 'can-autoplay');
|
||||
} else {
|
||||
const spanPlay = document.createElement('span');
|
||||
spanPlay.classList.add('video-play', 'tgico-largeplay', 'btn-circle', 'position-center');
|
||||
container.append(spanPlay);
|
||||
}
|
||||
} else {
|
||||
spanTime.innerText = 'GIF';
|
||||
}
|
||||
} else {
|
||||
spanTime.innerText = 'GIF';
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,80 +107,110 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
||||
video.remove();
|
||||
} */
|
||||
|
||||
const video = /* doc.type === 'round' ? appMediaPlaybackController.addMedia(message.peerId, doc, message.mid) as HTMLVideoElement : */document.createElement('video');
|
||||
const video = document.createElement('video');
|
||||
video.classList.add('media-video');
|
||||
video.muted = true;
|
||||
video.setAttribute('playsinline', 'true');
|
||||
video.muted = true;
|
||||
if(doc.type === 'round') {
|
||||
//video.classList.add('z-depth-1');
|
||||
const globalVideo = appMediaPlaybackController.addMedia(message.peerId, doc, message.mid);
|
||||
const globalVideo = appMediaPlaybackController.addMedia(message.peerId, doc, message.mid) as HTMLVideoElement;
|
||||
|
||||
video.classList.add('z-depth-1');
|
||||
const divRound = document.createElement('div');
|
||||
divRound.classList.add('media-round', 'z-depth-1');
|
||||
|
||||
onVideoLoad(video).then(() => {
|
||||
if(globalVideo.currentTime !== globalVideo.duration) {
|
||||
video.currentTime = globalVideo.currentTime;
|
||||
divRound.innerHTML = `<svg class="progress-ring" width="200px" height="200px">
|
||||
<circle class="progress-ring__circle" stroke="white" stroke-opacity="0.3" stroke-width="3.5" cx="100" cy="100" r="93" fill="transparent" transform="rotate(-90, 100, 100)"/>
|
||||
</svg>`;
|
||||
|
||||
const circle = divRound.querySelector('.progress-ring__circle') as SVGCircleElement;
|
||||
const radius = circle.r.baseVal.value;
|
||||
const circumference = 2 * Math.PI * radius;
|
||||
circle.style.strokeDasharray = circumference + ' ' + circumference;
|
||||
circle.style.strokeDashoffset = '' + circumference;
|
||||
|
||||
spanTime.classList.add('tgico');
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = canvas.height = doc.w/* * window.devicePixelRatio */;
|
||||
|
||||
divRound.prepend(canvas, spanTime);
|
||||
container.append(divRound);
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
/* ctx.beginPath();
|
||||
ctx.arc(canvas.width / 2, canvas.height / 2, canvas.width / 2, 0, Math.PI * 2);
|
||||
ctx.clip(); */
|
||||
|
||||
const clear = () => {
|
||||
(appImManager.chat.setPeerPromise || Promise.resolve()).finally(() => {
|
||||
if(isInDOM(globalVideo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
globalVideo.removeEventListener('play', onPlay);
|
||||
globalVideo.removeEventListener('timeupdate', onTimeUpdate);
|
||||
globalVideo.removeEventListener('pause', onPaused);
|
||||
});
|
||||
};
|
||||
|
||||
const onFrame = () => {
|
||||
ctx.drawImage(globalVideo, 0, 0);
|
||||
|
||||
const offset = circumference - globalVideo.currentTime / globalVideo.duration * circumference;
|
||||
circle.style.strokeDashoffset = '' + offset;
|
||||
|
||||
return !globalVideo.paused;
|
||||
};
|
||||
|
||||
const onTimeUpdate = () => {
|
||||
if(!globalVideo.duration) return;
|
||||
|
||||
if(!isInDOM(globalVideo)) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!globalVideo.paused) {
|
||||
// с закоментированными настройками - хром выключал видео при скролле, для этого нужно было включить видео - выйти из диалога, зайти заново и проскроллить вверх
|
||||
//video.autoplay = true;
|
||||
//video.loop = false;
|
||||
video.play();
|
||||
spanTime.innerText = (globalVideo.duration - globalVideo.currentTime + '').toHHMMSS(false);
|
||||
};
|
||||
|
||||
const onPlay = () => {
|
||||
video.remove();
|
||||
divRound.classList.remove('is-paused');
|
||||
animateSingle(onFrame, canvas);
|
||||
};
|
||||
|
||||
const onPaused = () => {
|
||||
if(!isInDOM(globalVideo)) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
|
||||
divRound.classList.add('is-paused');
|
||||
};
|
||||
|
||||
globalVideo.addEventListener('play', onPlay);
|
||||
globalVideo.addEventListener('timeupdate', onTimeUpdate);
|
||||
globalVideo.addEventListener('pause', onPaused);
|
||||
|
||||
attachClickEvent(canvas, (e) => {
|
||||
cancelEvent(e);
|
||||
|
||||
if(globalVideo.paused) {
|
||||
globalVideo.play();
|
||||
} else {
|
||||
globalVideo.pause();
|
||||
}
|
||||
});
|
||||
|
||||
const clear = () => {
|
||||
//console.log('clearing video');
|
||||
|
||||
globalVideo.removeEventListener('timeupdate', onGlobalTimeUpdate);
|
||||
globalVideo.removeEventListener('play', onGlobalPlay);
|
||||
globalVideo.removeEventListener('pause', onGlobalPause);
|
||||
video.removeEventListener('play', onVideoPlay);
|
||||
video.removeEventListener('pause', onVideoPause);
|
||||
};
|
||||
|
||||
const onGlobalTimeUpdate = (e: Event) => {
|
||||
//console.log('video global timeupdate event', e, globalVideo.currentTime, globalVideo.duration);
|
||||
if(!isInDOM(video)) {
|
||||
clear();
|
||||
}
|
||||
};
|
||||
|
||||
const onGlobalPlay = (e: Event) => {
|
||||
//console.log('video global play event', e);
|
||||
video.play();
|
||||
};
|
||||
|
||||
const onGlobalPause = (e: Event) => {
|
||||
//console.trace('video global pause event', e, globalVideo.paused, e.eventPhase);
|
||||
video.pause();
|
||||
};
|
||||
|
||||
const onVideoPlay = (e: Event) => {
|
||||
//console.log('video play event', e);
|
||||
if(globalVideo.paused) {
|
||||
globalVideo.currentTime = video.currentTime;
|
||||
globalVideo.play();
|
||||
}
|
||||
};
|
||||
|
||||
// * this will fire when video unmounts
|
||||
const onVideoPause = (e: Event) => {
|
||||
//console.trace('video pause event', e);
|
||||
if(isInDOM(video)) {
|
||||
globalVideo.pause();
|
||||
globalVideo.currentTime = video.currentTime;
|
||||
if(globalVideo.paused) {
|
||||
if(globalVideo.duration && globalVideo.currentTime !== globalVideo.duration) {
|
||||
onFrame();
|
||||
onTimeUpdate();
|
||||
} else {
|
||||
clear();
|
||||
onPaused();
|
||||
}
|
||||
};
|
||||
|
||||
globalVideo.addEventListener('timeupdate', onGlobalTimeUpdate);
|
||||
globalVideo.addEventListener('play', onGlobalPlay);
|
||||
globalVideo.addEventListener('pause', onGlobalPause);
|
||||
video.addEventListener('play', onVideoPlay);
|
||||
video.addEventListener('pause', onVideoPause);
|
||||
} else {
|
||||
onPlay();
|
||||
}
|
||||
} else {
|
||||
video.autoplay = true; // для safari
|
||||
}
|
||||
@ -276,7 +305,7 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
||||
/* if(!video.paused) {
|
||||
video.pause();
|
||||
} */
|
||||
if(doc.type !== 'round' && group) {
|
||||
if(group) {
|
||||
animationIntersector.addAnimation(video, group);
|
||||
}
|
||||
|
||||
@ -297,24 +326,16 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
if(doc.type !== 'round') {
|
||||
video.muted = true;
|
||||
video.loop = true;
|
||||
//video.play();
|
||||
video.autoplay = true;
|
||||
}
|
||||
video.muted = true;
|
||||
video.loop = true;
|
||||
//video.play();
|
||||
video.autoplay = true;
|
||||
|
||||
renderImageFromUrl(video, doc.url);
|
||||
|
||||
return Promise.all([loadPromise, deferred]);
|
||||
};
|
||||
|
||||
if(doc.type === 'round') {
|
||||
video.dataset.ckin = 'circle';
|
||||
video.dataset.overlay = '1';
|
||||
new VideoPlayer(video, undefined, undefined, doc.duration);
|
||||
}
|
||||
|
||||
/* if(doc.size >= 20e6 && !doc.downloaded) {
|
||||
let downloadDiv = document.createElement('div');
|
||||
downloadDiv.classList.add('download');
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { attachClickEvent, cancelEvent } from "../helpers/dom";
|
||||
import { cancelEvent } from "../helpers/dom";
|
||||
import appMediaPlaybackController from "../components/appMediaPlaybackController";
|
||||
import { isAppleMobile } from "../helpers/userAgent";
|
||||
import { isTouchSupported } from "../helpers/touchSupport";
|
||||
import RangeSelector from "../components/rangeSelector";
|
||||
import { animateSingle } from "../helpers/animation";
|
||||
import { onVideoLoad } from "../helpers/files";
|
||||
|
||||
type SUPEREVENT = MouseEvent | TouchEvent;
|
||||
@ -358,56 +357,6 @@ export default class VideoPlayer {
|
||||
video.addEventListener('timeupdate', () => {
|
||||
timeElapsed.innerHTML = String(video.currentTime | 0).toHHMMSS();
|
||||
});
|
||||
} else if(skin === 'circle') {
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.classList.add('circle-time-left');
|
||||
video.parentNode.insertBefore(wrapper, video);
|
||||
wrapper.innerHTML = '<div class="circle-time"></div><div class="iconVolume tgico-nosound"></div>';
|
||||
|
||||
const circle = player.querySelector('.progress-ring__circle') as SVGCircleElement;
|
||||
const radius = circle.r.baseVal.value;
|
||||
const circumference = 2 * Math.PI * radius;
|
||||
timeDuration = wrapper.firstElementChild as HTMLElement;
|
||||
const iconVolume = wrapper.lastElementChild as HTMLElement;
|
||||
circle.style.strokeDasharray = circumference + ' ' + circumference;
|
||||
circle.style.strokeDashoffset = '' + circumference;
|
||||
attachClickEvent(circle as any, (e) => {
|
||||
cancelEvent(e);
|
||||
this.togglePlay();
|
||||
});
|
||||
|
||||
const update = () => {
|
||||
const offset = circumference - video.currentTime / video.duration * circumference;
|
||||
circle.style.strokeDashoffset = '' + offset;
|
||||
|
||||
return !video.paused;
|
||||
};
|
||||
|
||||
const timeUpdate = () => {
|
||||
const timeLeft = String((video.duration - video.currentTime) | 0).toHHMMSS();
|
||||
if(timeLeft != '0') timeDuration.innerHTML = timeLeft;
|
||||
};
|
||||
|
||||
video.addEventListener('play', () => {
|
||||
iconVolume.style.display = 'none';
|
||||
|
||||
animateSingle(update, circle);
|
||||
update();
|
||||
});
|
||||
|
||||
video.addEventListener('pause', () => {
|
||||
iconVolume.style.display = '';
|
||||
});
|
||||
|
||||
video.addEventListener('timeupdate', () => {
|
||||
timeUpdate();
|
||||
});
|
||||
|
||||
onVideoLoad(video).then(() => {
|
||||
if(!video.currentTime || video.currentTime === video.duration) return;
|
||||
update();
|
||||
timeUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
video.addEventListener('play', () => {
|
||||
@ -465,12 +414,6 @@ export default class VideoPlayer {
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
} else if(skin === 'circle') {
|
||||
return `
|
||||
<svg class="progress-ring" width="200px" height="200px">
|
||||
<circle class="progress-ring__circle" stroke="white" stroke-opacity="0.3" stroke-width="3.5" cx="100" cy="100" r="93" fill="transparent" transform="rotate(-90, 100, 100)"/>
|
||||
</svg>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -520,8 +520,9 @@ $bubble-margin: .25rem;
|
||||
max-width: 200px !important;
|
||||
max-height: 200px !important;
|
||||
|
||||
img {
|
||||
.media-photo, .media-video {
|
||||
border-radius: 50%;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1239,6 +1240,7 @@ $bubble-margin: .25rem;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
height: 1.125rem;
|
||||
|
||||
&.can-autoplay:after {
|
||||
content: $tgico-nosound;
|
||||
|
@ -402,52 +402,3 @@ input[type=range] {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
video[data-ckin="circle"] {
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
z-index: -1;
|
||||
}
|
||||
.progress-ring {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
cursor: pointer;
|
||||
|
||||
&__circle {
|
||||
transition: stroke-dashoffset;
|
||||
}
|
||||
}
|
||||
|
||||
.ckin__player.circle {
|
||||
position: relative;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
|
||||
.circle-time-left {
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
top: .1875rem;
|
||||
left: .1875rem;
|
||||
border-radius: 12px;
|
||||
background-color: rgba(0, 0, 0, .23);
|
||||
padding: 1px 6px 2px 7px;
|
||||
height: 1.125rem;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.circle-time {
|
||||
font-size: .75rem;
|
||||
//margin-top: 1px;
|
||||
}
|
||||
|
||||
.iconVolume {
|
||||
padding-left: .25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
}
|
||||
|
@ -1142,7 +1142,7 @@ middle-ellipsis-element {
|
||||
fill: rgba(0, 0, 0, .08);
|
||||
}
|
||||
|
||||
.media-photo, .media-video, .media-sticker {
|
||||
.media-photo, .media-video, .media-sticker, .media-round {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
@ -1165,3 +1165,43 @@ middle-ellipsis-element {
|
||||
.media-sticker {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.media-round {
|
||||
max-width: 200px;
|
||||
max-height: 200px;
|
||||
z-index: 1;
|
||||
|
||||
canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.progress-ring {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
|
||||
&__circle {
|
||||
transition: stroke-dashoffset;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
}
|
||||
|
||||
.video-time {
|
||||
padding: 1px 6px 2px 7px;
|
||||
background-color: rgba(0, 0, 0, .23) !important;
|
||||
}
|
||||
|
||||
&.is-paused .video-time {
|
||||
&:after {
|
||||
content: $tgico-nosound;
|
||||
padding-left: .25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user