diff options
Diffstat (limited to 'client/src/assets/player/mobile/peertube-mobile-plugin.ts')
-rw-r--r-- | client/src/assets/player/mobile/peertube-mobile-plugin.ts | 115 |
1 files changed, 113 insertions, 2 deletions
diff --git a/client/src/assets/player/mobile/peertube-mobile-plugin.ts b/client/src/assets/player/mobile/peertube-mobile-plugin.ts index 2ce6b4b33..3c0365e5b 100644 --- a/client/src/assets/player/mobile/peertube-mobile-plugin.ts +++ b/client/src/assets/player/mobile/peertube-mobile-plugin.ts | |||
@@ -1,18 +1,43 @@ | |||
1 | import './peertube-mobile-buttons' | 1 | import { PeerTubeMobileButtons } from './peertube-mobile-buttons' |
2 | import videojs from 'video.js' | 2 | import videojs from 'video.js' |
3 | import debug from 'debug' | ||
4 | |||
5 | const logger = debug('peertube:player:mobile') | ||
3 | 6 | ||
4 | const Plugin = videojs.getPlugin('plugin') | 7 | const Plugin = videojs.getPlugin('plugin') |
5 | 8 | ||
6 | class PeerTubeMobilePlugin extends Plugin { | 9 | class PeerTubeMobilePlugin extends Plugin { |
10 | private static readonly DOUBLE_TAP_DELAY_MS = 250 | ||
11 | private static readonly SET_CURRENT_TIME_DELAY = 1000 | ||
12 | |||
13 | private peerTubeMobileButtons: PeerTubeMobileButtons | ||
14 | |||
15 | private seekAmount = 0 | ||
16 | |||
17 | private lastTapEvent: TouchEvent | ||
18 | private tapTimeout: NodeJS.Timeout | ||
19 | private newActiveState: boolean | ||
20 | |||
21 | private setCurrentTimeTimeout: NodeJS.Timeout | ||
7 | 22 | ||
8 | constructor (player: videojs.Player, options: videojs.PlayerOptions) { | 23 | constructor (player: videojs.Player, options: videojs.PlayerOptions) { |
9 | super(player, options) | 24 | super(player, options) |
10 | 25 | ||
11 | player.addChild('PeerTubeMobileButtons') | 26 | this.peerTubeMobileButtons = player.addChild('PeerTubeMobileButtons') as PeerTubeMobileButtons |
12 | 27 | ||
13 | if (videojs.browser.IS_ANDROID && screen.orientation) { | 28 | if (videojs.browser.IS_ANDROID && screen.orientation) { |
14 | this.handleFullscreenRotation() | 29 | this.handleFullscreenRotation() |
15 | } | 30 | } |
31 | |||
32 | if (!this.player.options_.userActions) this.player.options_.userActions = {}; | ||
33 | |||
34 | // FIXME: typings | ||
35 | (this.player.options_.userActions as any).click = false | ||
36 | this.player.options_.userActions.doubleClick = false | ||
37 | |||
38 | this.player.one('play', () => { | ||
39 | this.initTouchStartEvents() | ||
40 | }) | ||
16 | } | 41 | } |
17 | 42 | ||
18 | private handleFullscreenRotation () { | 43 | private handleFullscreenRotation () { |
@@ -27,6 +52,92 @@ class PeerTubeMobilePlugin extends Plugin { | |||
27 | private isPortraitVideo () { | 52 | private isPortraitVideo () { |
28 | return this.player.videoWidth() < this.player.videoHeight() | 53 | return this.player.videoWidth() < this.player.videoHeight() |
29 | } | 54 | } |
55 | |||
56 | private initTouchStartEvents () { | ||
57 | this.player.on('touchstart', (event: TouchEvent) => { | ||
58 | event.stopPropagation() | ||
59 | |||
60 | if (this.tapTimeout) { | ||
61 | clearTimeout(this.tapTimeout) | ||
62 | this.tapTimeout = undefined | ||
63 | } | ||
64 | |||
65 | if (this.lastTapEvent && event.timeStamp - this.lastTapEvent.timeStamp < PeerTubeMobilePlugin.DOUBLE_TAP_DELAY_MS) { | ||
66 | logger('Detected double tap') | ||
67 | |||
68 | this.lastTapEvent = undefined | ||
69 | this.onDoubleTap(event) | ||
70 | return | ||
71 | } | ||
72 | |||
73 | this.newActiveState = !this.player.userActive() | ||
74 | |||
75 | this.tapTimeout = setTimeout(() => { | ||
76 | logger('No double tap detected, set user active state to %s.', this.newActiveState) | ||
77 | |||
78 | this.player.userActive(this.newActiveState) | ||
79 | }, PeerTubeMobilePlugin.DOUBLE_TAP_DELAY_MS) | ||
80 | |||
81 | this.lastTapEvent = event | ||
82 | }) | ||
83 | } | ||
84 | |||
85 | private onDoubleTap (event: TouchEvent) { | ||
86 | const playerWidth = this.player.currentWidth() | ||
87 | |||
88 | const rect = this.findPlayerTarget((event.target as HTMLElement)).getBoundingClientRect() | ||
89 | const offsetX = event.targetTouches[0].pageX - rect.left | ||
90 | |||
91 | logger('Calculating double tap zone (player width: %d, offset X: %d)', playerWidth, offsetX) | ||
92 | |||
93 | if (offsetX > 0.66 * playerWidth) { | ||
94 | if (this.seekAmount < 0) this.seekAmount = 0 | ||
95 | |||
96 | this.seekAmount += 10 | ||
97 | |||
98 | logger('Will forward %d seconds', this.seekAmount) | ||
99 | } else if (offsetX < 0.33 * playerWidth) { | ||
100 | if (this.seekAmount > 0) this.seekAmount = 0 | ||
101 | |||
102 | this.seekAmount -= 10 | ||
103 | logger('Will rewind %d seconds', this.seekAmount) | ||
104 | } | ||
105 | |||
106 | this.peerTubeMobileButtons.displayFastSeek(this.seekAmount) | ||
107 | |||
108 | this.scheduleSetCurrentTime() | ||
109 | |||
110 | } | ||
111 | |||
112 | private findPlayerTarget (target: HTMLElement): HTMLElement { | ||
113 | if (target.classList.contains('video-js')) return target | ||
114 | |||
115 | return this.findPlayerTarget(target.parentElement) | ||
116 | } | ||
117 | |||
118 | private scheduleSetCurrentTime () { | ||
119 | this.player.pause() | ||
120 | this.player.addClass('vjs-fast-seeking') | ||
121 | |||
122 | if (this.setCurrentTimeTimeout) clearTimeout(this.setCurrentTimeTimeout) | ||
123 | |||
124 | this.setCurrentTimeTimeout = setTimeout(() => { | ||
125 | let newTime = this.player.currentTime() + this.seekAmount | ||
126 | this.seekAmount = 0 | ||
127 | |||
128 | newTime = Math.max(0, newTime) | ||
129 | newTime = Math.min(this.player.duration(), newTime) | ||
130 | |||
131 | this.player.currentTime(newTime) | ||
132 | this.seekAmount = 0 | ||
133 | this.peerTubeMobileButtons.displayFastSeek(0) | ||
134 | |||
135 | this.player.removeClass('vjs-fast-seeking') | ||
136 | this.player.userActive(false) | ||
137 | |||
138 | this.player.play() | ||
139 | }, PeerTubeMobilePlugin.SET_CURRENT_TIME_DELAY) | ||
140 | } | ||
30 | } | 141 | } |
31 | 142 | ||
32 | videojs.registerPlugin('peertubeMobile', PeerTubeMobilePlugin) | 143 | videojs.registerPlugin('peertubeMobile', PeerTubeMobilePlugin) |