From 137badb6dbc80742046ffbb273428d842df78311 Mon Sep 17 00:00:00 2001
From: Chocobozzz <me@florianbigard.com>
Date: Mon, 16 Sep 2024 10:52:45 +0200
Subject: [PATCH] Improve mobile double tap

---
 .../shared/mobile/peertube-mobile-plugin.ts   | 31 +++++++++++++------
 client/src/sass/player/mobile.scss            | 10 ++++--
 2 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/client/src/assets/player/shared/mobile/peertube-mobile-plugin.ts b/client/src/assets/player/shared/mobile/peertube-mobile-plugin.ts
index 1154fe5cc..47d6dc0ad 100644
--- a/client/src/assets/player/shared/mobile/peertube-mobile-plugin.ts
+++ b/client/src/assets/player/shared/mobile/peertube-mobile-plugin.ts
@@ -9,11 +9,12 @@ const Plugin = videojs.getPlugin('plugin')
 
 class PeerTubeMobilePlugin extends Plugin {
   private static readonly DOUBLE_TAP_DELAY_MS = 250
-  private static readonly SET_CURRENT_TIME_DELAY = 1000
+  private static readonly SET_CURRENT_TIME_DELAY = 750
 
   declare private peerTubeMobileButtons: PeerTubeMobileButtons
 
   declare private seekAmount: number
+  declare private doubleTapping: boolean
 
   declare private lastTapEvent: TouchEvent
   declare private tapTimeout: ReturnType<typeof setTimeout>
@@ -88,24 +89,35 @@ class PeerTubeMobilePlugin extends Plugin {
 
   private initTouchStartEvents () {
     const handleTouchStart = (event: TouchEvent) => {
+      debugLogger('Handle touch start')
+
       if (this.tapTimeout) {
         clearTimeout(this.tapTimeout)
         this.tapTimeout = undefined
       }
 
-      if (this.lastTapEvent && event.timeStamp - this.lastTapEvent.timeStamp < PeerTubeMobilePlugin.DOUBLE_TAP_DELAY_MS) {
+      if (
+        this.doubleTapping ||
+        (this.lastTapEvent && event.timeStamp - this.lastTapEvent.timeStamp < PeerTubeMobilePlugin.DOUBLE_TAP_DELAY_MS)
+      ) {
         debugLogger('Detected double tap')
 
-        this.lastTapEvent = undefined
+        this.lastTapEvent = event
         this.onDoubleTap(event)
         return
       }
 
       this.newActiveState = !this.player.userActive()
 
-      this.tapTimeout = setTimeout(() => {
-        debugLogger('No double tap detected, set user active state to %s.', this.newActiveState)
+      // video.js forces userActive on tap so we prevent this behaviour with a custom class
+      if (this.newActiveState === true) {
+        this.player.addClass('vjs-force-inactive')
+      }
 
+      this.tapTimeout = setTimeout(() => {
+        debugLogger('No double tap detected, set user active state to ' + this.newActiveState)
+
+        this.player.removeClass('vjs-force-inactive')
         this.player.userActive(this.newActiveState)
       }, PeerTubeMobilePlugin.DOUBLE_TAP_DELAY_MS)
 
@@ -113,16 +125,14 @@ class PeerTubeMobilePlugin extends Plugin {
     }
 
     this.onTouchStartHandler = event => {
-      // Only enable user active on player touch, we listen event on peertube mobile buttons to disable it
-      if (this.player.userActive()) return
-
       handleTouchStart(event)
     }
     this.player.on('touchstart', this.onTouchStartHandler)
 
     this.onMobileButtonTouchStartHandler = event => {
-      // Prevent mousemove/click events firing on the player, that conflict with our user active logic
+      // Prevent mousemove/click/tap events firing on the player, that conflict with our user active logic
       event.preventDefault()
+      event.stopPropagation()
 
       handleTouchStart(event)
     }
@@ -165,6 +175,7 @@ class PeerTubeMobilePlugin extends Plugin {
   private scheduleSetCurrentTime () {
     this.player.pause()
     this.player.addClass('vjs-fast-seeking')
+    this.doubleTapping = true
 
     if (this.setCurrentTimeTimeout) clearTimeout(this.setCurrentTimeTimeout)
 
@@ -180,7 +191,9 @@ class PeerTubeMobilePlugin extends Plugin {
       this.peerTubeMobileButtons.displayFastSeek(0)
 
       this.player.removeClass('vjs-fast-seeking')
+      this.player.removeClass('vjs-force-inactive')
       this.player.userActive(false)
+      this.doubleTapping = false
 
       this.player.play()
     }, PeerTubeMobilePlugin.SET_CURRENT_TIME_DELAY)
diff --git a/client/src/sass/player/mobile.scss b/client/src/sass/player/mobile.scss
index 103909d14..517c96020 100644
--- a/client/src/sass/player/mobile.scss
+++ b/client/src/sass/player/mobile.scss
@@ -51,7 +51,7 @@
   height: 100%;
   top: 0;
 
-  .vjs-user-active,
+  .vjs-user-active:not(.vjs-force-inactive),
   .vjs-paused {
     display: block;
   }
@@ -88,7 +88,7 @@
 
     .icon {
       opacity: 0;
-      animation: fadeInAndOut 1s linear infinite;
+      animation: fadeInAndOut 750ms linear infinite;
 
       &::before {
         font-size: 20px;
@@ -163,7 +163,7 @@
 
 .vjs-can-play.vjs-has-started {
 
-  &.vjs-user-active,
+  &.vjs-user-active:not(.vjs-force-inactive),
   &.vjs-paused {
     .vjs-mobile-buttons-overlay {
       display: block;
@@ -186,6 +186,10 @@
   }
 }
 
+.vjs-force-inactive .vjs-control-bar {
+  display: none;
+}
+
 @keyframes fadeInAndOut {
   0%,
   20% {