Skip to content

Portrait fullscreen rebuild, Material 3 Expressive on-video controls, and a run of playback fixes - #1067

Merged
A-EDev merged 18 commits into
mainfrom
polish/player-overlay-portrait-fullscreen
Sep 16, 2026
Merged

A-EDev merged 18 commits into
mainfrom
polish/player-overlay-portrait-fullscreen

Conversation

@A-EDev

@A-EDev A-EDev commented Sep 15, 2026

Copy link
Copy Markdown
Owner

Summary

Polishes the layer drawn on top of the video — the layer the adaptive and InnerTube work left untouched — and fixes a run of playback and layout bugs found alongside it.

Portrait fullscreen is rebuilt around the video with the title and channel above it, and is now reached the same way whether you swipe into it or press the button. The on-video controls move to Material 3 Expressive with haptics throughout, the volume and brightness read-outs gain four styles, and volume boost above 100% works for the first time.

Related issue

Closes #867
Closes #977
Closes #978
Closes #991
Closes #1029
Closes #1051
Closes #1062
Closes #1066

Partially addresses #1022 — the player items only. Related videos off no longer leaves the side pane empty, and the fullscreen title opens the description so landscape has a route to it. The search-result suggestions are out of scope here; they were designed differently during the search refactor. The two remaining gesture items (swipe-down-to-close only reacting in the middle of the player, and the landscape body scroll competing with swipe-up) are gesture-budget trade-offs that need a product decision rather than a fix.

Partially addresses #1065 — the seek bar no longer jumps to the edge during the transition. The broader "glitchy" feel of entering fullscreen is not addressed; it needs a more specific description of what looks wrong.

Likely fixes #967 and #1064 but neither is confirmed, so neither is closed here. #967 describes empty space on an upright HyperOS tablet, which is exactly what the two-pane split produced before this branch, but the evidence is a video I could not review. #1064 shares its root cause with the resume freeze fixed here — a surface re-attach that never flushed the codec — but it is random and I could not reproduce it.

Change type

  • Bug fix
  • Feature
  • Refactor or maintenance
  • Build, packaging, or CI
  • Documentation

Validation

  • ./gradlew :app:assembleGithubDebug
  • ./gradlew :app:testGithubDebugUnitTest — 1,907 tests, 0 failures
  • ./gradlew :app:compileFossDebugKotlin and ./gradlew spotlessCheck
  • I manually tested the affected behavior on an Android device or emulator.

Test device and Android version: Xiaomi POCO X6 Pro, Android 16

Verified on the device by driving it over adb and reading the logs, not by eye alone:

  • Resume freeze. Played, paused, backgrounded 70 s, returned, resumed. surfaceReattachResync pos=373498 target=373497 and the reported position actually moved, which it never did before. Video resumed at pts 373.54 s against a playhead of 373.497 s, with following frames at timediff: 9 and 24 ms. Previously video sat 13 s ahead of audio and the picture held for 14.5 s.
  • Volume boost. Volume set to: 2.0 (player=1.0, boost=602mB) with the effect at 1202mB — the boost summed with stable volume's 600 rather than overwriting it.
  • Fullscreen transitions. Three rotate-in/rotate-out cycles with playback continuing and no Padding must be non-negative.
  • Portrait fullscreen, the gesture overlay styles setting, the speed pill beside the quality badge, the channel line in landscape fullscreen, and the seek-zone chevrons were each confirmed on screen.

Not verified on hardware, and stated as such: the mini player size cap (#991) only applies to large windows and could not be exercised on a phone, and #1064 is not reproducible on demand.

Screenshots or recordings

Not included.

Risk and compatibility

Player-path changes. attachVideoSurface now seeks one millisecond short of the current position instead of to it. A seek resolving to the millisecond the player already reports returns from ExoPlayerImplInternal.seekToInternal before the renderers are disabled — and the resync's own guard required exactly the state that triggers that early return, so the workaround had never flushed anything. Exact seek parameters keep the one-millisecond step from snapping to a sync frame, and SABR sessions are excluded because a SABR seek rebuilds the whole session. A watchdog forces the same flush if a re-attached surface has drawn nothing after 1.2 s, guarded on READY and playing so a slow first load cannot trip it; measured first-frame latency on a real load is about 120 ms, and an 8.4 s extraction load left it correctly untouched.

Preference removed. show_fullscreen_title is gone and the title always shows in fullscreen — it is now the control that opens the description, so it is no longer optional. The stored key is simply left unread. player_show_title_title/_subtitle were removed from the default locale; the translations still carry them until Weblate's next sync, which lint reports without failing (abortOnError = false).

Preferences added: gesture overlay style (default Circular, the existing look) and player vibration (default on). Both are additive with existing behaviour as the default.

Volume boost now applies real gain. Above unity it drives LoudnessEnhancer rather than ExoPlayer.volume, which is documented 0..1 and was silently constraining it. Gain is capped at 2000 mB and shares one effect with stable volume rather than the two overwriting each other.

  • Blocked channels are filtered where related videos are derived, so they leave the cards, the autoplay candidates and the queue together. Items arriving without a channel id still pass, the same gap the search PR recorded.

  • Fullscreen picks its layout from the orientation it is about to request rather than the one the window currently has, so entering fullscreen on a landscape video no longer renders a portrait frame first.

  • The mini player size preference now applies on tablets, bounded by an absolute width instead of a fraction of the screen. On phones the result is unchanged.

  • No dependency, Room schema, or permission changes.

  • The change does not introduce secrets, private data, or unexpected telemetry.

  • New user-facing text uses Android string resources.

  • Dependency and lockfile changes are intentional and limited to this PR — none.

  • Room schema changes include the required version bump and migration, or this PR does not change the Room schema.

  • Breaking changes and upgrade steps are clearly documented — none.

…it, and give the portrait layout YouTube's title and channel line
…he player tokens and give its buttons haptics
…, toggle buttons and an animated play-pause swap
…d pill beside the quality badge, and add gesture overlay styles
…or, place them clear of the thumb and the cutout, and accumulate each drag locally
…de pane only to windows wider than they are tall
… size on tablets, highlight a tapped chapter at once, and make the surface resync actually flush the codec
…e animation cannot produce a negative padding
…t and the speed pill see it, and drop the side pane when it would be empty
… the side pane useful when related videos are off
Copilot AI lite review requested due to automatic review settings September 15, 2026 21:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added player Video and audio playback ui Compose UI, theming, or Material 3 surfaces labels Sep 15, 2026
@A-EDev
A-EDev merged commit 58b36d7 into main Sep 16, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

player Video and audio playback ui Compose UI, theming, or Material 3 surfaces

Projects

None yet

2 participants