From ae8f0755b7aa9389b95068e8c71fe765cd134fd8 Mon Sep 17 00:00:00 2001 From: morethanwords Date: Wed, 26 Aug 2020 22:25:43 +0300 Subject: [PATCH] Volume controls for video --- src/lib/logger.ts | 10 +- src/lib/mediaPlayer.ts | 128 ++++++++++++++---- src/scss/partials/_chatBubble.scss | 4 +- src/scss/partials/_ckin.scss | 186 ++++++++++++++++----------- src/scss/partials/_rightSidebar.scss | 2 +- 5 files changed, 217 insertions(+), 113 deletions(-) diff --git a/src/lib/logger.ts b/src/lib/logger.ts index 7be11e03..8221a4d8 100644 --- a/src/lib/logger.ts +++ b/src/lib/logger.ts @@ -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[]) { + /* Log.debug = function(...args: any[]) { return level & LogLevels.debug && console.log(dT(), '[' + prefix + ']:', ...args); - }; + }; */ - /* Log.debug = function(...args: any[]) { + Log.debug = function(...args: any[]) { return level & LogLevels.debug && console.debug(dT(), '[' + prefix + ']:', ...args); - }; */ + }; return Log; }; \ No newline at end of file diff --git a/src/lib/mediaPlayer.ts b/src/lib/mediaPlayer.ts index d8864db2..49f7c50f 100644 --- a/src/lib/mediaPlayer.ts +++ b/src/lib/mediaPlayer.ts @@ -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 + ')'; + } + + protected scrub(e: MouseEvent) { + const scrubTime = e.offsetX / this.container.offsetWidth * this.duration; - //this.events?.onScrub(scrubTime); + 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 = ` + + `; + 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 = ``; + } 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 `
@@ -421,14 +493,14 @@ export default class VideoPlayer {
- `); + `; } else if(skin === 'circle') { - html.push('', - '', - ''); + return ` + + + + `; } - - return html.join(''); } public updateButton(toggle: NodeListOf) { diff --git a/src/scss/partials/_chatBubble.scss b/src/scss/partials/_chatBubble.scss index 6e488ec1..52164eb9 100644 --- a/src/scss/partials/_chatBubble.scss +++ b/src/scss/partials/_chatBubble.scss @@ -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); } diff --git a/src/scss/partials/_ckin.scss b/src/scss/partials/_ckin.scss index d8c7cc06..22b8599b 100644 --- a/src/scss/partials/_ckin.scss +++ b/src/scss/partials/_ckin.scss @@ -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; + + .progress-line { + margin: 0 16px; + height: 5px; + 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); + } + } } -} -.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; -} + &__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); -} + &.is-playing { + .default__gradient-bottom { + transform: translateY(50px); + } -html.no-touch .default.is-playing:hover .default__gradient-bottom { - transform: translateY(0px); -} + html.no-touch &:hover { + .default__gradient-bottom { + transform: translateY(0px); + } -.default.is-playing:before { - opacity: 0; - visibility: hidden; - transform: translate(-50%, -50%) scale(1.3); -} + .default__controls { + transform: translateY(0); + } + } -.default.is-playing .default__button--big { - opacity: 0; - visibility: hidden; -} + &:before { + opacity: 0; + visibility: hidden; + transform: translate(-50%, -50%) scale(1.3); + } -.default.is-playing .default__controls { - transform: translateY(52px); -} + .default__button--big { + opacity: 0; + visibility: hidden; + } -html.no-touch .default.is-playing:hover .default__controls { - transform: translateY(0); -} + .default__controls { + transform: translateY(52px); + } + } -.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; - height: 5px; - transform: scaleX(0); + .player-volume { + margin: -3px 12px 0 16px; + display: flex; + align-items: center; + + &__icon { + fill: #fff; + width: 24px; + height: 24px; + margin-right: 8px; + cursor: pointer; } - &__loaded { - background: rgba(255, 255, 255, 0.38); - left: 11px; - width: calc(100% - 11px); + .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; diff --git a/src/scss/partials/_rightSidebar.scss b/src/scss/partials/_rightSidebar.scss index b87cb139..7d83234b 100644 --- a/src/scss/partials/_rightSidebar.scss +++ b/src/scss/partials/_rightSidebar.scss @@ -466,7 +466,7 @@ } } - .media-progress { + .progress-line { margin: 11px 0 8px; &__filled {