fix(player): stabilize iOS Safari controls toggle on tap#632
Merged
Conversation
Ignore touch-synthesized mouse move/leave events that were racing the video click toggle, keep showControls in a ref for consistent toggles, and disable pointer events on hidden overlays so taps reach the video. Co-authored-by: Stackie Jia <jsq2627@gmail.com>
Contributor
Documentation previewThe documentation preview has been deployed for this pull request. |
Stop hiding player controls on mouse leave; auto-hide is driven solely by the idle timer. Drop the redundant controls mouseenter handler. Co-authored-by: Stackie Jia <jsq2627@gmail.com>
Drop video click toggle and touch-mousemove suppression. Showing controls relies on mouseenter/mousemove (including iOS tap-synthesized move); hiding stays timer-only plus Escape. Co-authored-by: Stackie Jia <jsq2627@gmail.com>
Co-authored-by: Stackie Jia <jsq2627@gmail.com>
stackia
added a commit
that referenced
this pull request
Jul 9, 2026
…ols (#634) ## Summary Reworks player controls visibility so it matches expected behavior on both desktop and mobile, while keeping the iOS tap stability from #632. #632 fixed flaky iOS show/hide by dropping **click-toggle** and **leave-to-hide** entirely, leaving only `mousemove` + a 3s timer. That regressed those interactions on every platform. This PR brings them back with a cleaner model. ### Root cause of the original iOS flicker A single tap on iOS makes WebKit synthesize *compatibility mouse events* — `mousemove`, `mouseleave`, **and** `click` all fire from one tap. The old `onMouseMove`=show + `onMouseLeave`=hide + `onClick`=toggle raced through all three, so a tap showed then immediately hid controls. ### The fix Drive hover through **Pointer Events gated on `pointerType`**. iOS compatibility mouse events are legacy `MouseEvent`s and never re-dispatch as `PointerEvent`s, so ignoring `pointerType === "touch"` in the hover handlers removes the race with no timing heuristics or conflict detection. ## Behavior | Action | Desktop (mouse/pen) | Mobile (touch) | |---|---|---| | Pointer enters player | show | — (no hover) | | Move inside | reset 3s timer | — | | Leave player | hide | — | | Click / tap on video | toggle | toggle | | Idle 3s | auto-hide | auto-hide | On mobile there is no hover state, so tap-to-toggle is the natural equivalent and the standard mobile video pattern. ## Notes - Click handler stays on the `<video>` element so clicks on toolbar/overlay buttons don't bubble into a toggle. - `tsc --noEmit` and `biome check` both pass. - `src/embedded_web_data.h` is intentionally not included; rebuild the Web UI to regenerate it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Simplify player controls visibility to fix flaky show/hide on iOS Safari.
Previously, video click toggle raced with touch-synthesized
mousemove/mouseleave, so a single tap could show then immediately hide controls. The new model drops click toggle and leave-based hide entirely.Controls visibility
Show / keep alive (resets 3s timer):
mouseenter/mousemoveon the player surface (includes iOS tap-synthesized mouse events)mouseenteron the controls toolbarHide:
Test results (local)
Verified on Chromium against
devlab+rtp2httpd(http://127.0.0.1:5140/player, channelHLS-TS (h264-mp2)), with strict timing (~0.4s after each action):mousemoveover video → showNot retested on a physical iOS Safari device in this run; touch wake relies on WebKit synthesizing
mousemovefrom taps, which is the same path exercised above for show/keep-alive.