Add player controls on mobile
This commit is contained in:
parent
ba9eef5f62
commit
f1a0555a88
|
@ -1,4 +1,5 @@
|
||||||
import videojs from 'video.js'
|
import videojs from 'video.js'
|
||||||
|
import { isMobile } from '../utils'
|
||||||
|
|
||||||
function getPauseBezel () {
|
function getPauseBezel () {
|
||||||
return `
|
return `
|
||||||
|
@ -37,6 +38,9 @@ class PauseBezel extends Component {
|
||||||
constructor (player: videojs.Player, options?: videojs.ComponentOptions) {
|
constructor (player: videojs.Player, options?: videojs.ComponentOptions) {
|
||||||
super(player, options)
|
super(player, options)
|
||||||
|
|
||||||
|
// Hide bezels on mobile since we already have our mobile overlay
|
||||||
|
if (isMobile()) return
|
||||||
|
|
||||||
player.on('pause', (_: any) => {
|
player.on('pause', (_: any) => {
|
||||||
if (player.seeking() || player.ended()) return
|
if (player.seeking() || player.ended()) return
|
||||||
this.container.innerHTML = getPauseBezel()
|
this.container.innerHTML = getPauseBezel()
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import videojs from 'video.js'
|
||||||
|
|
||||||
|
import debug from 'debug'
|
||||||
|
|
||||||
|
const logger = debug('peertube:player:mobile')
|
||||||
|
|
||||||
|
const Component = videojs.getComponent('Component')
|
||||||
|
class PeerTubeMobileButtons extends Component {
|
||||||
|
|
||||||
|
createEl () {
|
||||||
|
const container = super.createEl('div', {
|
||||||
|
className: 'vjs-mobile-buttons-overlay'
|
||||||
|
}) as HTMLDivElement
|
||||||
|
|
||||||
|
container.addEventListener('click', () => {
|
||||||
|
logger('Set user as inactive')
|
||||||
|
|
||||||
|
this.player_.userActive(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
const mainButton = super.createEl('div', {
|
||||||
|
className: 'main-button'
|
||||||
|
}) as HTMLDivElement
|
||||||
|
|
||||||
|
mainButton.addEventListener('click', e => {
|
||||||
|
e.stopPropagation()
|
||||||
|
|
||||||
|
if (this.player_.paused() || this.player_.ended()) {
|
||||||
|
this.player_.play()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.player_.pause()
|
||||||
|
})
|
||||||
|
|
||||||
|
container.appendChild(mainButton)
|
||||||
|
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
videojs.registerComponent('PeerTubeMobileButtons', PeerTubeMobileButtons)
|
|
@ -0,0 +1,16 @@
|
||||||
|
import videojs from 'video.js'
|
||||||
|
import './peertube-mobile-buttons'
|
||||||
|
|
||||||
|
const Plugin = videojs.getPlugin('plugin')
|
||||||
|
|
||||||
|
class PeerTubeMobilePlugin extends Plugin {
|
||||||
|
|
||||||
|
constructor (player: videojs.Player, options: videojs.PlayerOptions) {
|
||||||
|
super(player, options)
|
||||||
|
|
||||||
|
player.addChild('PeerTubeMobileButtons')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
videojs.registerPlugin('peertubeMobile', PeerTubeMobilePlugin)
|
||||||
|
export { PeerTubeMobilePlugin }
|
|
@ -21,6 +21,7 @@ import './videojs-components/settings-panel'
|
||||||
import './videojs-components/settings-panel-child'
|
import './videojs-components/settings-panel-child'
|
||||||
import './videojs-components/theater-button'
|
import './videojs-components/theater-button'
|
||||||
import './playlist/playlist-plugin'
|
import './playlist/playlist-plugin'
|
||||||
|
import './mobile/peertube-mobile-plugin'
|
||||||
import videojs from 'video.js'
|
import videojs from 'video.js'
|
||||||
import { HlsJsEngineSettings } from '@peertube/p2p-media-loader-hlsjs'
|
import { HlsJsEngineSettings } from '@peertube/p2p-media-loader-hlsjs'
|
||||||
import { PluginsManager } from '@root-helpers/plugins-manager'
|
import { PluginsManager } from '@root-helpers/plugins-manager'
|
||||||
|
@ -43,7 +44,7 @@ import {
|
||||||
VideoJSPluginOptions
|
VideoJSPluginOptions
|
||||||
} from './peertube-videojs-typings'
|
} from './peertube-videojs-typings'
|
||||||
import { TranslationsManager } from './translations-manager'
|
import { TranslationsManager } from './translations-manager'
|
||||||
import { buildVideoOrPlaylistEmbed, getRtcConfig, isIOS, isSafari } from './utils'
|
import { buildVideoOrPlaylistEmbed, getRtcConfig, isIOS, isMobile, isSafari } from './utils'
|
||||||
|
|
||||||
// Change 'Playback Rate' to 'Speed' (smaller for our settings menu)
|
// Change 'Playback Rate' to 'Speed' (smaller for our settings menu)
|
||||||
(videojs.getComponent('PlaybackRateMenuButton') as any).prototype.controlText_ = 'Speed'
|
(videojs.getComponent('PlaybackRateMenuButton') as any).prototype.controlText_ = 'Speed'
|
||||||
|
@ -189,7 +190,10 @@ export class PeertubePlayerManager {
|
||||||
videoEmbedTitle: options.common.embedTitle
|
videoEmbedTitle: options.common.embedTitle
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (isMobile()) player.peertubeMobile()
|
||||||
|
|
||||||
player.bezels()
|
player.bezels()
|
||||||
|
|
||||||
player.stats({
|
player.stats({
|
||||||
videoUUID: options.common.videoUUID,
|
videoUUID: options.common.videoUUID,
|
||||||
videoIsLive: options.common.isLive,
|
videoIsLive: options.common.isLive,
|
||||||
|
|
|
@ -12,6 +12,9 @@ import {
|
||||||
import { PeerTubePluginOptions, UserWatching, VideoJSCaption } from './peertube-videojs-typings'
|
import { PeerTubePluginOptions, UserWatching, VideoJSCaption } from './peertube-videojs-typings'
|
||||||
import { isMobile } from './utils'
|
import { isMobile } from './utils'
|
||||||
import { SettingsButton } from './videojs-components/settings-menu-button'
|
import { SettingsButton } from './videojs-components/settings-menu-button'
|
||||||
|
import debug from 'debug'
|
||||||
|
|
||||||
|
const logger = debug('peertube:player:peertube')
|
||||||
|
|
||||||
const Plugin = videojs.getPlugin('plugin')
|
const Plugin = videojs.getPlugin('plugin')
|
||||||
|
|
||||||
|
@ -233,7 +236,7 @@ class PeerTubePlugin extends Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
private alterInactivity () {
|
private alterInactivity () {
|
||||||
if (this.menuOpened || this.mouseInSettings || this.mouseInControlBar || this.isTouchEnabled()) {
|
if (this.menuOpened || this.mouseInSettings || this.mouseInControlBar) {
|
||||||
this.setInactivityTimeout(0)
|
this.setInactivityTimeout(0)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -245,6 +248,8 @@ class PeerTubePlugin extends Plugin {
|
||||||
private setInactivityTimeout (timeout: number) {
|
private setInactivityTimeout (timeout: number) {
|
||||||
(this.player as any).cache_.inactivityTimeout = timeout
|
(this.player as any).cache_.inactivityTimeout = timeout
|
||||||
this.player.options_.inactivityTimeout = timeout
|
this.player.options_.inactivityTimeout = timeout
|
||||||
|
|
||||||
|
logger('Set player inactivity to ' + timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
private isTouchEnabled () {
|
private isTouchEnabled () {
|
||||||
|
|
|
@ -42,6 +42,8 @@ declare module 'video.js' {
|
||||||
|
|
||||||
bezels (): void
|
bezels (): void
|
||||||
|
|
||||||
|
peertubeMobile (): void
|
||||||
|
|
||||||
stats (options?: StatsCardOptions): StatsForNerdsPlugin
|
stats (options?: StatsCardOptions): StatsForNerdsPlugin
|
||||||
|
|
||||||
textTracks (): TextTrackList & {
|
textTracks (): TextTrackList & {
|
||||||
|
|
|
@ -40,7 +40,6 @@ class NextPreviousVideoButton extends Button {
|
||||||
|
|
||||||
update () {
|
update () {
|
||||||
const disabled = this.nextPreviousVideoButtonOptions.isDisabled()
|
const disabled = this.nextPreviousVideoButtonOptions.isDisabled()
|
||||||
console.log(disabled)
|
|
||||||
|
|
||||||
if (disabled) this.addClass('vjs-disabled')
|
if (disabled) this.addClass('vjs-disabled')
|
||||||
else this.removeClass('vjs-disabled')
|
else this.removeClass('vjs-disabled')
|
||||||
|
|
|
@ -8,11 +8,14 @@ $font-size: 13px;
|
||||||
$control-bar-height: 38px;
|
$control-bar-height: 38px;
|
||||||
$control-bar-icon-size: 26px;
|
$control-bar-icon-size: 26px;
|
||||||
$control-bar-volume-slider-height: 14px;
|
$control-bar-volume-slider-height: 14px;
|
||||||
|
$control-bar-slider-top: -10px;
|
||||||
$control-bar-font-size: 14px;
|
$control-bar-font-size: 14px;
|
||||||
$control-bar-play-font-size: 34px;
|
$control-bar-play-font-size: 34px;
|
||||||
$control-bar-next-previous-play-font-size: 14px;
|
$control-bar-next-previous-play-font-size: 14px;
|
||||||
$control-bar-button-width: 38px;
|
$control-bar-button-width: 38px;
|
||||||
|
|
||||||
|
$control-bar-total-height: $control-bar-height - $control-bar-slider-top;
|
||||||
|
|
||||||
$slider-bg-color: lighten($primary-background-color, 33%);
|
$slider-bg-color: lighten($primary-background-color, 33%);
|
||||||
|
|
||||||
$progress-margin: 10px;
|
$progress-margin: 10px;
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
@use './_player-variables' as *;
|
@use './_player-variables' as *;
|
||||||
|
|
||||||
.video-js.vjs-peertube-skin .vjs-control-bar {
|
.video-js.vjs-peertube-skin .vjs-control-bar {
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
height: $control-bar-height;
|
height: $control-bar-height;
|
||||||
background: linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.6));
|
background: linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.6));
|
||||||
box-shadow: 0 -15px 40px 10px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 -15px 40px 10px rgba(0, 0, 0, 0.2);
|
||||||
|
@ -49,7 +51,7 @@
|
||||||
@include margin-left($progress-margin);
|
@include margin-left($progress-margin);
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -10px;
|
top: $control-bar-slider-top;
|
||||||
z-index: 100; // On top of the progress bar
|
z-index: 100; // On top of the progress bar
|
||||||
width: calc(100% - (2 * #{$progress-margin}));
|
width: calc(100% - (2 * #{$progress-margin}));
|
||||||
height: 14px;
|
height: 14px;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
@use 'sass:math';
|
||||||
@use '_variables' as *;
|
@use '_variables' as *;
|
||||||
@use '_mixins' as *;
|
@use '_mixins' as *;
|
||||||
|
@use './_player-variables' as *;
|
||||||
|
|
||||||
/* Special mobile style */
|
/* Special mobile style */
|
||||||
|
|
||||||
|
@ -14,3 +16,72 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vjs-mobile-buttons-overlay {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
|
||||||
|
.vjs-user-active,
|
||||||
|
.vjs-paused {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-button {
|
||||||
|
font-family: VideoJS;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 5em;
|
||||||
|
width: fit-content;
|
||||||
|
margin: auto;
|
||||||
|
position: relative;
|
||||||
|
top: calc(50% - 10px);
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-paused {
|
||||||
|
.main-button {
|
||||||
|
&:before {
|
||||||
|
content: '\f101';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-playing {
|
||||||
|
.main-button {
|
||||||
|
&:before {
|
||||||
|
content: '\f103';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-ended {
|
||||||
|
.main-button {
|
||||||
|
&:before {
|
||||||
|
content: '\f116';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-has-started {
|
||||||
|
|
||||||
|
&.vjs-user-active,
|
||||||
|
&.vjs-paused {
|
||||||
|
.vjs-mobile-buttons-overlay {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.vjs-seeking,
|
||||||
|
&.vjs-scrubbing,
|
||||||
|
&.vjs-waiting {
|
||||||
|
.vjs-mobile-buttons-overlay {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ $setting-transition-easing: ease-out;
|
||||||
opacity: $primary-foreground-opacity;
|
opacity: $primary-foreground-opacity;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
font-size: $font-size !important;
|
font-size: $font-size !important;
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
width: auto;
|
width: auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
Loading…
Reference in New Issue