Volume controls for video

This commit is contained in:
morethanwords 2020-08-26 22:25:43 +03:00
parent a0c2004c6d
commit f87cfba0dc
13 changed files with 229 additions and 125 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -36,7 +36,7 @@
@media only screen and (max-width: 720px){.bubble .message.audio-message .audio{height:59px;padding-left:47px}}
@media only screen and (max-width: 720px){.bubble .message.audio-message .audio-details{margin-top:-1px}}
@media only screen and (max-width: 720px){.bubble .message.audio-message .audio-ico{margin-top:1px;margin-left:2px}}
@media only screen and (max-width: 720px){.bubble .message.audio-message .media-progress{width:unset}}
@media only screen and (max-width: 720px){.bubble .message.audio-message .progress-line{width:unset}}
@media only screen and (max-width: 720px){.bubble .message.document-message .document{padding-left:44px}}
@media only screen and (max-width: 720px){.bubble.is-in.is-reply.emoji-big .reply,.bubble.is-in.is-reply.sticker .reply{left:calc(100% + 1px)}}
@media only screen and (max-width: 720px){.bubble.is-in{margin-right:auto}.bubble.is-out{margin-left:auto}}

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -16,7 +16,7 @@ export function logger(prefix: string, level = LogLevels.log | LogLevels.warn |
level = LogLevels.error;
}
level = LogLevels.log | LogLevels.warn | LogLevels.error | LogLevels.debug
//level = LogLevels.log | LogLevels.warn | LogLevels.error | LogLevels.debug
function Log(...args: any[]) {
return level & LogLevels.log && console.log(dT(), '[' + prefix + ']:', ...args);
@ -38,13 +38,13 @@ export function logger(prefix: string, level = LogLevels.log | LogLevels.warn |
return level & LogLevels.log && console.trace(dT(), '[' + prefix + ']:', ...args);
};
Log.debug = function(...args: any[]) {
return level & LogLevels.debug && console.log(dT(), '[' + prefix + ']:', ...args);
};
/* Log.debug = function(...args: any[]) {
return level & LogLevels.debug && console.debug(dT(), '[' + prefix + ']:', ...args);
return level & LogLevels.debug && console.log(dT(), '[' + prefix + ']:', ...args);
}; */
Log.debug = function(...args: any[]) {
return level & LogLevels.debug && console.debug(dT(), '[' + prefix + ']:', ...args);
};
return Log;
};

View File

@ -1,9 +1,11 @@
import { cancelEvent } from "./utils";
export class ProgressLine {
public container: HTMLDivElement;
protected filled: HTMLDivElement;
protected seek: HTMLInputElement;
protected duration = 100;
protected duration = 1;
protected mousedown = false;
private events: Partial<{
@ -13,22 +15,26 @@ export class ProgressLine {
onScrub: (scrubTime: number) => void
}> = {};
constructor() {
constructor(initialValue = 0) {
this.container = document.createElement('div');
this.container.classList.add('media-progress');
this.container.classList.add('progress-line');
this.filled = document.createElement('div');
this.filled.classList.add('media-progress__filled');
this.filled.classList.add('progress-line__filled');
const seek = this.seek = document.createElement('input');
seek.classList.add('media-progress__seek');
seek.value = '0';
seek.classList.add('progress-line__seek');
seek.value = '' + initialValue;
seek.setAttribute('min', '0');
seek.setAttribute('max', '0');
//seek.setAttribute('max', '0');
seek.type = 'range';
seek.step = '0.1';
seek.max = '' + (this.duration * 1000);
if(initialValue > 0) {
this.setProgress(initialValue);
}
//this.setListeners();
this.container.append(this.filled, seek);
@ -45,28 +51,37 @@ export class ProgressLine {
onMouseDown = (e: MouseEvent) => {
this.scrub(e);
this.mousedown = true;
this.events?.onMouseDown(e);
this.events?.onMouseDown && this.events.onMouseDown(e);
};
onMouseUp = (e: MouseEvent) => {
this.mousedown = false;
this.events?.onMouseUp(e);
this.events?.onMouseUp && this.events.onMouseUp(e);
};
protected setListeners() {
public setListeners() {
this.container.addEventListener('mousemove', this.onMouseMove);
this.container.addEventListener('mousedown', this.onMouseDown);
this.container.addEventListener('mouseup', this.onMouseUp);
}
protected scrub(e: MouseEvent) {
const scrubTime = e.offsetX / this.container.offsetWidth * this.duration;
public setProgress(scrubTime: number) {
this.setFilled(scrubTime);
this.seek.value = '' + (scrubTime * 1000);
}
public setFilled(scrubTime: number) {
let scaleX = scrubTime / this.duration;
scaleX = Math.max(0, Math.min(1, scaleX));
this.filled.style.transform = 'scaleX(' + scaleX + ')';
}
//this.events?.onScrub(scrubTime);
protected scrub(e: MouseEvent) {
const scrubTime = e.offsetX / this.container.offsetWidth * this.duration;
this.setFilled(scrubTime);
this.events?.onScrub && this.events.onScrub(scrubTime);
return scrubTime;
}
@ -90,7 +105,7 @@ export class MediaProgressLine extends ProgressLine {
if(streamable) {
this.filledLoad = document.createElement('div');
this.filledLoad.classList.add('media-progress__filled', 'media-progress__loaded');
this.filledLoad.classList.add('progress-line__filled', 'progress-line__loaded');
this.container.prepend(this.filledLoad);
//this.setLoadProgress();
}
@ -197,15 +212,13 @@ export class MediaProgressLine extends ProgressLine {
}
}
protected setProgress() {
public setProgress() {
const currentTime = this.media.currentTime;
const scaleX = (currentTime / this.duration);
this.filled.style.transform = 'scaleX(' + scaleX + ')';
this.seek.value = '' + currentTime * 1000;
super.setProgress(currentTime);
}
protected setListeners() {
public setListeners() {
super.setListeners();
this.media.addEventListener('ended', this.onEnded);
this.media.addEventListener('play', this.onPlay);
@ -230,6 +243,7 @@ export class MediaProgressLine extends ProgressLine {
}
}
let lastVolume = 1, muted = !lastVolume;
export default class VideoPlayer {
public wrapper: HTMLDivElement;
public progress: MediaProgressLine;
@ -274,7 +288,66 @@ export default class VideoPlayer {
var timeElapsed = player.querySelector('#time-elapsed');
var timeDuration = player.querySelector('#time-duration') as HTMLElement;
timeDuration.innerHTML = String(video.duration | 0).toHHMMSS();
const volumeDiv = document.createElement('div');
volumeDiv.classList.add('player-volume');
volumeDiv.innerHTML = `
<svg class="player-volume__icon" focusable="false" viewBox="0 0 24 24" aria-hidden="true"></svg>
`;
const volumeSvg = volumeDiv.firstElementChild as SVGSVGElement;
volumeSvg.addEventListener('click', (e) => {
cancelEvent(e);
if(!lastVolume) {
muted = true;
lastVolume = 1;
}
const realVolume = !muted ? 0 : lastVolume;
setVolume(realVolume);
volumeProgress.setProgress(realVolume);
muted = !muted;
});
const setVolume = (volume: number) => {
let d: string;
if(volume > .5) {
d = `M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z`;
} else if(!volume) {
d = `M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z`;
} else if(volume > 0 && volume < .25) {
d = `M7 9v6h4l5 5V4l-5 5H7z`;
} else {
d = `M18.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z`;
}
try {
volumeSvg.innerHTML = `<path d="${d}"></path>`;
} catch(err) {}
video.volume = volume;
};
const fakeVolume = muted ? 0 : lastVolume;
video.volume = fakeVolume;
setVolume(fakeVolume);
const volumeProgress = new ProgressLine(muted ? 0 : fakeVolume);
volumeProgress.setListeners();
volumeProgress.setHandlers({
onScrub: currentTime => {
const value = Math.max(Math.min(currentTime, 1), 0);
console.log('scrub', currentTime, value);
setVolume(lastVolume = value);
}
});
volumeDiv.append(volumeProgress.container);
const leftControls = player.querySelector('.left-controls');
leftControls.insertBefore(volumeDiv, timeElapsed.parentElement);
Array.from(toggle).forEach((button) => {
return button.addEventListener('click', () => {
this.togglePlay();
@ -402,9 +475,8 @@ export default class VideoPlayer {
private buildControls() {
const skin = this.skin;
const html: string[] = [];
if(skin === 'default') {
html.push(`
return `
<button class="${skin}__button--big toggle tgico-largeplay" title="Toggle Play"></button>
<div class="${skin}__gradient-bottom ckin__controls"></div>
<div class="${skin}__controls ckin__controls">
@ -421,14 +493,14 @@ export default class VideoPlayer {
<button class="${skin}__button fullscreen tgico-fullscreen" title="Full Screen"></button>
</div>
</div>
</div>`);
</div>`;
} else if(skin === 'circle') {
html.push('<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>');
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>
`;
}
return html.join('');
}
public updateButton(toggle: NodeListOf<HTMLElement>) {

View File

@ -754,7 +754,7 @@ $bubble-margin: .25rem;
}
}
.media-progress {
.progress-line {
/* width: calc(100% + 50px); */
width: 191px;
margin: 9px 0 9px;
@ -1202,7 +1202,7 @@ $bubble-margin: .25rem;
}
.message.audio-message {
.media-progress {
.progress-line {
&__seek {
background: rgba(193, 207, 220, 0.39);
}

View File

@ -1,6 +1,27 @@
.ckin {
&__player {
letter-spacing: 0.02em;
&.ckin__fullscreen {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 100%;
width: 100%;
z-index: 10000000;
background: #000;
border-radius: 0 !important;
display: -ms-flexbox;
display: flex;
video {
max-height: none;
max-width: none;
object-fit: contain;
}
}
}
&__overlay {
@ -16,27 +37,6 @@
}
}
.ckin__player.ckin__fullscreen {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 100%;
width: 100%;
z-index: 10000000;
background: #000;
border-radius: 0 !important;
display: -ms-flexbox;
display: flex;
video {
max-height: none;
max-width: none;
object-fit: contain;
}
}
.default {
border: 0 solid rgba(0, 0, 0, 0.2);
box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
@ -120,73 +120,105 @@
direction: ltr;
border-radius: 0 0 5px 5px;
z-index: 6;
}
}
.default__gradient-bottom {
height: 49px;
// padding-top: 49px;
padding-top: 93px;
bottom: 0;
z-index: 2;
background-position: bottom;
width: 100%;
position: absolute;
background-repeat: repeat-x;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAADGCAYAAAAT+OqFAAAAdklEQVQoz42QQQ7AIAgEF/T/D+kbq/RWAlnQyyazA4aoAB4FsBSA/bFjuF1EOL7VbrIrBuusmrt4ZZORfb6ehbWdnRHEIiITaEUKa5EJqUakRSaEYBJSCY2dEstQY7AuxahwXFrvZmWl2rh4JZ07z9dLtesfNj5q0FU3A5ObbwAAAABJRU5ErkJggg==);
transition: all .3s;
pointer-events: none;
}
.default.is-playing .default__gradient-bottom {
transform: translateY(50px);
}
html.no-touch .default.is-playing:hover .default__gradient-bottom {
transform: translateY(0px);
}
.default.is-playing:before {
opacity: 0;
visibility: hidden;
transform: translate(-50%, -50%) scale(1.3);
}
.default.is-playing .default__button--big {
opacity: 0;
visibility: hidden;
}
.default.is-playing .default__controls {
transform: translateY(52px);
}
html.no-touch .default.is-playing:hover .default__controls {
transform: translateY(0);
}
.default {
.media-progress {
margin: 0 16px;
height: 5px;
transition: height 0.3s;
background: rgba(255, 255, 255, 0.38);
border-radius: 4px;
overflow: visible;
&__filled {
background: #63a2e3;
transform-origin: left;
border-radius: 4px;
.progress-line {
margin: 0 16px;
height: 5px;
transform: scaleX(0);
background: rgba(255, 255, 255, 0.38);
border-radius: 4px;
overflow: visible;
&__filled {
background: #63a2e3;
transform-origin: left;
border-radius: 4px;
height: 5px;
transform: scaleX(0);
}
&__loaded {
background: rgba(255, 255, 255, 0.38);
left: 11px;
width: calc(100% - 11px);
}
}
}
&__gradient-bottom {
height: 49px;
// padding-top: 49px;
padding-top: 93px;
bottom: 0;
z-index: 2;
background-position: bottom;
width: 100%;
position: absolute;
background-repeat: repeat-x;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAADGCAYAAAAT+OqFAAAAdklEQVQoz42QQQ7AIAgEF/T/D+kbq/RWAlnQyyazA4aoAB4FsBSA/bFjuF1EOL7VbrIrBuusmrt4ZZORfb6ehbWdnRHEIiITaEUKa5EJqUakRSaEYBJSCY2dEstQY7AuxahwXFrvZmWl2rh4JZ07z9dLtesfNj5q0FU3A5ObbwAAAABJRU5ErkJggg==);
transition: all .3s;
pointer-events: none;
}
&.is-playing {
.default__gradient-bottom {
transform: translateY(50px);
}
&__loaded {
background: rgba(255, 255, 255, 0.38);
left: 11px;
width: calc(100% - 11px);
html.no-touch &:hover {
.default__gradient-bottom {
transform: translateY(0px);
}
.default__controls {
transform: translateY(0);
}
}
&:before {
opacity: 0;
visibility: hidden;
transform: translate(-50%, -50%) scale(1.3);
}
.default__button--big {
opacity: 0;
visibility: hidden;
}
.default__controls {
transform: translateY(52px);
}
}
.player-volume {
margin: -3px 12px 0 16px;
display: flex;
align-items: center;
&__icon {
fill: #fff;
width: 24px;
height: 24px;
margin-right: 8px;
cursor: pointer;
}
.progress-line {
margin: 0;
width: 50px;
&__filled {
background: #fff;
}
input[type=range]::-webkit-slider-thumb {
height: 15px;
width: 15px;
border-radius: 16px;
background: #fff;
}
}
}
}
@ -200,7 +232,7 @@ video::-webkit-media-controls-enclosure {
display: none !important;
}
.media-progress {
.progress-line {
position: relative;
cursor: pointer;

View File

@ -466,7 +466,7 @@
}
}
.media-progress {
.progress-line {
margin: 11px 0 8px;
&__filled {