refactor(player): centralize format helpers + unify title/artist tap handling#820
Merged
rukamori merged 5 commits intoJun 18, 2026
Conversation
… labeling Move codecLabel(), containerLabel(), formattedBitrate(), formattedSampleRate(), and formattedFileSize() into FormatEntity.kt as public extensions, replacing ~70 lines of duplicated inline parsing scattered across 6 queue composables and the private codecLabel() in PlayerComponents.kt. The inline parsing in QueueComponents named its variable 'codec' while actually extracting the container from mimeType (e.g. 'WEBM' instead of 'opus'). Variable is now honestly named 'container'. User-facing display is unchanged. Bonus: bitrate formatting now returns 'Unknown' instead of '0 kbps' for local files where bitrate is not available.
Extract the duplicated title/artist tap behavior into a single rememberPlayerTitleActions() helper, and add a reusable ClickableArtists primitive that makes each artist name individually tappable. Classic, V7, V8 and V9 now share this behavior instead of each hand-rolling its own lambdas, removing prior feature drift (per-artist navigation previously existed only in the classic style). Visual rendering stays per-style: adding a new player style no longer requires touching shared title/artist code.
Tapping the song title navigated to the album but used snapTo to move the sheet, which jumps without animation and — crucially — does not update the sheet's internal anchor. The anchor could then go stale (e.g. still EXPANDED), so on the next recomposition the sheet snapped back open, making "tap title to collapse" appear broken on the home screen while it worked elsewhere. Use collapseSoft() instead, which animates and updates the anchor, matching the artist-tap behavior.
- Remove unused PlayerTitleActions.onFirstArtistClick (dead code) - ClickableArtists: use detectTapGestures instead of a standing awaitPointerEventScope loop; memoize the AnnotatedString; restore per-artist annotation tags; document the marquee hit-test caveat - Drop the now-unused clipboardManager/context params threaded through PlayerTitleSection / PlayerControlsContent (and remove dead imports)
Refactor/player title artist
rukamori
approved these changes
Jun 18, 2026
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.
Pull Request
Summary
This PR bundles two related player-UI refactors.
(1) FormatEntity display helpers: extracts 5 reusable extension functions (
containerLabel,codecLabel,formattedBitrate,formattedSampleRate,formattedFileSize) intoFormatEntity.kt, replacing ~70 lines of duplicated inline parsing across 6 queue composables and aprivateduplicate inPlayerComponents.kt; the inline logic named its variablecodecwhile actually extracting the container, now honestly namedcontainer.(2) Title/artist tap handling: centralizes the duplicated title/artist tap behavior into a single
rememberPlayerTitleActions()helper and adds a reusableClickableArtistsprimitive so each artist name is individually tappable, with Classic, V7, V8 and V9 now sharing one implementation instead of hand-rolling their own lambdas. It also fixes a real bug where tapping the song title usedstate.snapTo(...)— which jumped without animation and left the bottom-sheet anchor stale — so the player now collapses reliably viacollapseSoft(). No format display changes; per-style visual rendering is preserved.Linked Work
Change Type
Affected Surfaces
:app:innertube:betterlyrics:kugou:lrclib:lastfm:simpmusic:paxsenix:unison:canvas:shazamkit:spotifycoreserverfastlane.githubScreenshots / Recordings
Format row is unchanged. Title-tap now animates the player closed; artist tap targets a specific artist.
WEBM • 141 kbps • 3 MBWEBM • 141 kbps • 3 MBBehavior Notes
val codec = mimeType.substringAfter("/")was extracting the container, not the codec; nowval container = currentFormat.containerLabel().formattedBitrate()returns"Unknown"or not showed at all whenbitrate == 0(local files), instead of the previous"0 kbps".snapTojumped with no animation and left the anchor stale, so the player failed to collapse reliably from the home screen).Architecture Checklist
Loading,Success,Empty, andErrorwhere this PR introduces or changes screen state. (N/A — no screen-state changes.)FormatEntityare pure;PlayerTitleActionsis@Immutable.)runBlockingis introduced in app execution paths.Compose / Material Checklist
collectAsStateWithLifecycle(). (N/A — no new state collection.)@Immutableor@Stable. (PlayerTitleActionsis@Immutable.)keyvalues and explicitcontentType. (N/A — no lazy-layout changes.)rememberPlayerTitleActionsand theClickableArtistsannotated string are remembered.)derivedStateOfwhere appropriate. (N/A.)stringResource()and duplicated visible strings on the same screen are avoided. (No new user-facing strings added.)WindowInsetscorrectly when this PR changes screen layout. (N/A — no layout/inset changes.)Concurrency / Performance Checklist
viewModelScopeor an existing lifecycle-owned application/service scope. (N/A.)Dispatchers.IOorDispatchers.Default. (N/A — lightweight string ops.)Data / Persistence Checklist
app/schemas. (N/A — only pure extension functions added to existingFormatEntity; no schema change.)Playback / Integration Checklist
Localization / Assets Checklist
Privacy / Security Checklist
Verification
Reviewer Focus
FormatEntity.kt— the 5 new extension functions and thecodec→containernaming correction.PlayerTitleActions.kt— single source of truth for title/artist tap + clipboard behavior; notecollapseSoft()vs the oldsnapTo().PlayerArtistText.kt—ClickableArtistshit-tests taps to the correct artist span via the static text layout (see the in-file note on marquee).PlayerComponents.kt— Classic/V8/V9 now delegate to the shared helper/primitive;Stringartist params becameList<MediaMetadata.Artist>through the V8/V9 pipeline.V8PlayerControlsContentinPlayer.kt.Release Notes
Tapping a song's title now smoothly collapses the player, and tapping an artist opens that specific artist's page across all player styles.