diff options
author | Chocobozzz <me@florianbigard.com> | 2022-01-11 11:26:35 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2022-01-11 11:26:35 +0100 |
commit | f1a0555a88db9ade2b073a2e4dc73c4a6176c8a0 (patch) | |
tree | e1f73376527152fb9ac92447a826bccc9e8f0dd5 | |
parent | ba9eef5f628764aed6183135e669b17741d24d7a (diff) | |
download | PeerTube-f1a0555a88db9ade2b073a2e4dc73c4a6176c8a0.tar.gz PeerTube-f1a0555a88db9ade2b073a2e4dc73c4a6176c8a0.tar.zst PeerTube-f1a0555a88db9ade2b073a2e4dc73c4a6176c8a0.zip |
Add player controls on mobile
11 files changed, 153 insertions, 4 deletions
diff --git a/client/src/assets/player/bezels/pause-bezel.ts b/client/src/assets/player/bezels/pause-bezel.ts index 886574380..315964311 100644 --- a/client/src/assets/player/bezels/pause-bezel.ts +++ b/client/src/assets/player/bezels/pause-bezel.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import videojs from 'video.js' | 1 | import videojs from 'video.js' |
2 | import { isMobile } from '../utils' | ||
2 | 3 | ||
3 | function getPauseBezel () { | 4 | function getPauseBezel () { |
4 | return ` | 5 | return ` |
@@ -37,6 +38,9 @@ class PauseBezel extends Component { | |||
37 | constructor (player: videojs.Player, options?: videojs.ComponentOptions) { | 38 | constructor (player: videojs.Player, options?: videojs.ComponentOptions) { |
38 | super(player, options) | 39 | super(player, options) |
39 | 40 | ||
41 | // Hide bezels on mobile since we already have our mobile overlay | ||
42 | if (isMobile()) return | ||
43 | |||
40 | player.on('pause', (_: any) => { | 44 | player.on('pause', (_: any) => { |
41 | if (player.seeking() || player.ended()) return | 45 | if (player.seeking() || player.ended()) return |
42 | this.container.innerHTML = getPauseBezel() | 46 | this.container.innerHTML = getPauseBezel() |
diff --git a/client/src/assets/player/mobile/peertube-mobile-buttons.ts b/client/src/assets/player/mobile/peertube-mobile-buttons.ts new file mode 100644 index 000000000..d6f8f35e3 --- /dev/null +++ b/client/src/assets/player/mobile/peertube-mobile-buttons.ts | |||
@@ -0,0 +1,42 @@ | |||
1 | import videojs from 'video.js' | ||
2 | |||
3 | import debug from 'debug' | ||
4 | |||
5 | const logger = debug('peertube:player:mobile') | ||
6 | |||
7 | const Component = videojs.getComponent('Component') | ||
8 | class PeerTubeMobileButtons extends Component { | ||
9 | |||
10 | createEl () { | ||
11 | const container = super.createEl('div', { | ||
12 | className: 'vjs-mobile-buttons-overlay' | ||
13 | }) as HTMLDivElement | ||
14 | |||
15 | container.addEventListener('click', () => { | ||
16 | logger('Set user as inactive') | ||
17 | |||
18 | this.player_.userActive(false) | ||
19 | }) | ||
20 | |||
21 | const mainButton = super.createEl('div', { | ||
22 | className: 'main-button' | ||
23 | }) as HTMLDivElement | ||
24 | |||
25 | mainButton.addEventListener('click', e => { | ||
26 | e.stopPropagation() | ||
27 | |||
28 | if (this.player_.paused() || this.player_.ended()) { | ||
29 | this.player_.play() | ||
30 | return | ||
31 | } | ||
32 | |||
33 | this.player_.pause() | ||
34 | }) | ||
35 | |||
36 | container.appendChild(mainButton) | ||
37 | |||
38 | return container | ||
39 | } | ||
40 | } | ||
41 | |||
42 | videojs.registerComponent('PeerTubeMobileButtons', PeerTubeMobileButtons) | ||
diff --git a/client/src/assets/player/mobile/peertube-mobile-plugin.ts b/client/src/assets/player/mobile/peertube-mobile-plugin.ts new file mode 100644 index 000000000..b3834e20d --- /dev/null +++ b/client/src/assets/player/mobile/peertube-mobile-plugin.ts | |||
@@ -0,0 +1,16 @@ | |||
1 | import videojs from 'video.js' | ||
2 | import './peertube-mobile-buttons' | ||
3 | |||
4 | const Plugin = videojs.getPlugin('plugin') | ||
5 | |||
6 | class PeerTubeMobilePlugin extends Plugin { | ||
7 | |||
8 | constructor (player: videojs.Player, options: videojs.PlayerOptions) { | ||
9 | super(player, options) | ||
10 | |||
11 | player.addChild('PeerTubeMobileButtons') | ||
12 | } | ||
13 | } | ||
14 | |||
15 | videojs.registerPlugin('peertubeMobile', PeerTubeMobilePlugin) | ||
16 | export { PeerTubeMobilePlugin } | ||
diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index ac8134fa8..6b6c1e581 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts | |||
@@ -21,6 +21,7 @@ import './videojs-components/settings-panel' | |||
21 | import './videojs-components/settings-panel-child' | 21 | import './videojs-components/settings-panel-child' |
22 | import './videojs-components/theater-button' | 22 | import './videojs-components/theater-button' |
23 | import './playlist/playlist-plugin' | 23 | import './playlist/playlist-plugin' |
24 | import './mobile/peertube-mobile-plugin' | ||
24 | import videojs from 'video.js' | 25 | import videojs from 'video.js' |
25 | import { HlsJsEngineSettings } from '@peertube/p2p-media-loader-hlsjs' | 26 | import { HlsJsEngineSettings } from '@peertube/p2p-media-loader-hlsjs' |
26 | import { PluginsManager } from '@root-helpers/plugins-manager' | 27 | import { PluginsManager } from '@root-helpers/plugins-manager' |
@@ -43,7 +44,7 @@ import { | |||
43 | VideoJSPluginOptions | 44 | VideoJSPluginOptions |
44 | } from './peertube-videojs-typings' | 45 | } from './peertube-videojs-typings' |
45 | import { TranslationsManager } from './translations-manager' | 46 | import { TranslationsManager } from './translations-manager' |
46 | import { buildVideoOrPlaylistEmbed, getRtcConfig, isIOS, isSafari } from './utils' | 47 | import { buildVideoOrPlaylistEmbed, getRtcConfig, isIOS, isMobile, isSafari } from './utils' |
47 | 48 | ||
48 | // Change 'Playback Rate' to 'Speed' (smaller for our settings menu) | 49 | // Change 'Playback Rate' to 'Speed' (smaller for our settings menu) |
49 | (videojs.getComponent('PlaybackRateMenuButton') as any).prototype.controlText_ = 'Speed' | 50 | (videojs.getComponent('PlaybackRateMenuButton') as any).prototype.controlText_ = 'Speed' |
@@ -189,7 +190,10 @@ export class PeertubePlayerManager { | |||
189 | videoEmbedTitle: options.common.embedTitle | 190 | videoEmbedTitle: options.common.embedTitle |
190 | }) | 191 | }) |
191 | 192 | ||
193 | if (isMobile()) player.peertubeMobile() | ||
194 | |||
192 | player.bezels() | 195 | player.bezels() |
196 | |||
193 | player.stats({ | 197 | player.stats({ |
194 | videoUUID: options.common.videoUUID, | 198 | videoUUID: options.common.videoUUID, |
195 | videoIsLive: options.common.isLive, | 199 | videoIsLive: options.common.isLive, |
diff --git a/client/src/assets/player/peertube-plugin.ts b/client/src/assets/player/peertube-plugin.ts index 451b4a161..272f5353d 100644 --- a/client/src/assets/player/peertube-plugin.ts +++ b/client/src/assets/player/peertube-plugin.ts | |||
@@ -12,6 +12,9 @@ import { | |||
12 | import { PeerTubePluginOptions, UserWatching, VideoJSCaption } from './peertube-videojs-typings' | 12 | import { PeerTubePluginOptions, UserWatching, VideoJSCaption } from './peertube-videojs-typings' |
13 | import { isMobile } from './utils' | 13 | import { isMobile } from './utils' |
14 | import { SettingsButton } from './videojs-components/settings-menu-button' | 14 | import { SettingsButton } from './videojs-components/settings-menu-button' |
15 | import debug from 'debug' | ||
16 | |||
17 | const logger = debug('peertube:player:peertube') | ||
15 | 18 | ||
16 | const Plugin = videojs.getPlugin('plugin') | 19 | const Plugin = videojs.getPlugin('plugin') |
17 | 20 | ||
@@ -233,7 +236,7 @@ class PeerTubePlugin extends Plugin { | |||
233 | } | 236 | } |
234 | 237 | ||
235 | private alterInactivity () { | 238 | private alterInactivity () { |
236 | if (this.menuOpened || this.mouseInSettings || this.mouseInControlBar || this.isTouchEnabled()) { | 239 | if (this.menuOpened || this.mouseInSettings || this.mouseInControlBar) { |
237 | this.setInactivityTimeout(0) | 240 | this.setInactivityTimeout(0) |
238 | return | 241 | return |
239 | } | 242 | } |
@@ -245,6 +248,8 @@ class PeerTubePlugin extends Plugin { | |||
245 | private setInactivityTimeout (timeout: number) { | 248 | private setInactivityTimeout (timeout: number) { |
246 | (this.player as any).cache_.inactivityTimeout = timeout | 249 | (this.player as any).cache_.inactivityTimeout = timeout |
247 | this.player.options_.inactivityTimeout = timeout | 250 | this.player.options_.inactivityTimeout = timeout |
251 | |||
252 | logger('Set player inactivity to ' + timeout) | ||
248 | } | 253 | } |
249 | 254 | ||
250 | private isTouchEnabled () { | 255 | private isTouchEnabled () { |
diff --git a/client/src/assets/player/peertube-videojs-typings.ts b/client/src/assets/player/peertube-videojs-typings.ts index f97d7a208..e4013d815 100644 --- a/client/src/assets/player/peertube-videojs-typings.ts +++ b/client/src/assets/player/peertube-videojs-typings.ts | |||
@@ -42,6 +42,8 @@ declare module 'video.js' { | |||
42 | 42 | ||
43 | bezels (): void | 43 | bezels (): void |
44 | 44 | ||
45 | peertubeMobile (): void | ||
46 | |||
45 | stats (options?: StatsCardOptions): StatsForNerdsPlugin | 47 | stats (options?: StatsCardOptions): StatsForNerdsPlugin |
46 | 48 | ||
47 | textTracks (): TextTrackList & { | 49 | textTracks (): TextTrackList & { |
diff --git a/client/src/assets/player/videojs-components/next-previous-video-button.ts b/client/src/assets/player/videojs-components/next-previous-video-button.ts index 228231a22..fe17ce2ce 100644 --- a/client/src/assets/player/videojs-components/next-previous-video-button.ts +++ b/client/src/assets/player/videojs-components/next-previous-video-button.ts | |||
@@ -40,7 +40,6 @@ class NextPreviousVideoButton extends Button { | |||
40 | 40 | ||
41 | update () { | 41 | update () { |
42 | const disabled = this.nextPreviousVideoButtonOptions.isDisabled() | 42 | const disabled = this.nextPreviousVideoButtonOptions.isDisabled() |
43 | console.log(disabled) | ||
44 | 43 | ||
45 | if (disabled) this.addClass('vjs-disabled') | 44 | if (disabled) this.addClass('vjs-disabled') |
46 | else this.removeClass('vjs-disabled') | 45 | else this.removeClass('vjs-disabled') |
diff --git a/client/src/sass/player/_player-variables.scss b/client/src/sass/player/_player-variables.scss index 2625576d4..dec3fe911 100644 --- a/client/src/sass/player/_player-variables.scss +++ b/client/src/sass/player/_player-variables.scss | |||
@@ -8,11 +8,14 @@ $font-size: 13px; | |||
8 | $control-bar-height: 38px; | 8 | $control-bar-height: 38px; |
9 | $control-bar-icon-size: 26px; | 9 | $control-bar-icon-size: 26px; |
10 | $control-bar-volume-slider-height: 14px; | 10 | $control-bar-volume-slider-height: 14px; |
11 | $control-bar-slider-top: -10px; | ||
11 | $control-bar-font-size: 14px; | 12 | $control-bar-font-size: 14px; |
12 | $control-bar-play-font-size: 34px; | 13 | $control-bar-play-font-size: 34px; |
13 | $control-bar-next-previous-play-font-size: 14px; | 14 | $control-bar-next-previous-play-font-size: 14px; |
14 | $control-bar-button-width: 38px; | 15 | $control-bar-button-width: 38px; |
15 | 16 | ||
17 | $control-bar-total-height: $control-bar-height - $control-bar-slider-top; | ||
18 | |||
16 | $slider-bg-color: lighten($primary-background-color, 33%); | 19 | $slider-bg-color: lighten($primary-background-color, 33%); |
17 | 20 | ||
18 | $progress-margin: 10px; | 21 | $progress-margin: 10px; |
diff --git a/client/src/sass/player/control-bar.scss b/client/src/sass/player/control-bar.scss index b3a96510a..c4e1283f8 100644 --- a/client/src/sass/player/control-bar.scss +++ b/client/src/sass/player/control-bar.scss | |||
@@ -4,6 +4,8 @@ | |||
4 | @use './_player-variables' as *; | 4 | @use './_player-variables' as *; |
5 | 5 | ||
6 | .video-js.vjs-peertube-skin .vjs-control-bar { | 6 | .video-js.vjs-peertube-skin .vjs-control-bar { |
7 | z-index: 100; | ||
8 | |||
7 | height: $control-bar-height; | 9 | height: $control-bar-height; |
8 | background: linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.6)); | 10 | background: linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.6)); |
9 | box-shadow: 0 -15px 40px 10px rgba(0, 0, 0, 0.2); | 11 | box-shadow: 0 -15px 40px 10px rgba(0, 0, 0, 0.2); |
@@ -49,7 +51,7 @@ | |||
49 | @include margin-left($progress-margin); | 51 | @include margin-left($progress-margin); |
50 | 52 | ||
51 | position: absolute; | 53 | position: absolute; |
52 | top: -10px; | 54 | top: $control-bar-slider-top; |
53 | z-index: 100; // On top of the progress bar | 55 | z-index: 100; // On top of the progress bar |
54 | width: calc(100% - (2 * #{$progress-margin})); | 56 | width: calc(100% - (2 * #{$progress-margin})); |
55 | height: 14px; | 57 | height: 14px; |
diff --git a/client/src/sass/player/mobile.scss b/client/src/sass/player/mobile.scss index 86c090200..d72dc41df 100644 --- a/client/src/sass/player/mobile.scss +++ b/client/src/sass/player/mobile.scss | |||
@@ -1,5 +1,7 @@ | |||
1 | @use 'sass:math'; | ||
1 | @use '_variables' as *; | 2 | @use '_variables' as *; |
2 | @use '_mixins' as *; | 3 | @use '_mixins' as *; |
4 | @use './_player-variables' as *; | ||
3 | 5 | ||
4 | /* Special mobile style */ | 6 | /* Special mobile style */ |
5 | 7 | ||
@@ -14,3 +16,72 @@ | |||
14 | } | 16 | } |
15 | } | 17 | } |
16 | } | 18 | } |
19 | |||
20 | .vjs-mobile-buttons-overlay { | ||
21 | display: none; | ||
22 | |||
23 | position: absolute; | ||
24 | background-color: rgba(0, 0, 0, 0.4); | ||
25 | width: 100%; | ||
26 | height: 100%; | ||
27 | top: 0; | ||
28 | |||
29 | .vjs-user-active, | ||
30 | .vjs-paused { | ||
31 | display: block; | ||
32 | } | ||
33 | |||
34 | .main-button { | ||
35 | font-family: VideoJS; | ||
36 | font-weight: normal; | ||
37 | font-style: normal; | ||
38 | font-size: 5em; | ||
39 | width: fit-content; | ||
40 | margin: auto; | ||
41 | position: relative; | ||
42 | top: calc(50% - 10px); | ||
43 | transform: translateY(-50%); | ||
44 | } | ||
45 | } | ||
46 | |||
47 | .vjs-paused { | ||
48 | .main-button { | ||
49 | &:before { | ||
50 | content: '\f101'; | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | |||
55 | .vjs-playing { | ||
56 | .main-button { | ||
57 | &:before { | ||
58 | content: '\f103'; | ||
59 | } | ||
60 | } | ||
61 | } | ||
62 | |||
63 | .vjs-ended { | ||
64 | .main-button { | ||
65 | &:before { | ||
66 | content: '\f116'; | ||
67 | } | ||
68 | } | ||
69 | } | ||
70 | |||
71 | .vjs-has-started { | ||
72 | |||
73 | &.vjs-user-active, | ||
74 | &.vjs-paused { | ||
75 | .vjs-mobile-buttons-overlay { | ||
76 | display: block; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | &.vjs-seeking, | ||
81 | &.vjs-scrubbing, | ||
82 | &.vjs-waiting { | ||
83 | .vjs-mobile-buttons-overlay { | ||
84 | display: none; | ||
85 | } | ||
86 | } | ||
87 | } | ||
diff --git a/client/src/sass/player/settings-menu.scss b/client/src/sass/player/settings-menu.scss index 5a476259e..8aa2c2ac3 100644 --- a/client/src/sass/player/settings-menu.scss +++ b/client/src/sass/player/settings-menu.scss | |||
@@ -22,6 +22,7 @@ $setting-transition-easing: ease-out; | |||
22 | opacity: $primary-foreground-opacity; | 22 | opacity: $primary-foreground-opacity; |
23 | margin: 0 auto; | 23 | margin: 0 auto; |
24 | font-size: $font-size !important; | 24 | font-size: $font-size !important; |
25 | z-index: 100; | ||
25 | 26 | ||
26 | width: auto; | 27 | width: auto; |
27 | overflow: hidden; | 28 | overflow: hidden; |