Skip to content

feat: lyrics tab (#113) - #117

Merged
joelkanyi merged 3 commits into
mainfrom
feature/lyrics
Jun 9, 2026
Merged

feat: lyrics tab (#113)#117
joelkanyi merged 3 commits into
mainfrom
feature/lyrics

Conversation

@joelkanyi

@joelkanyi joelkanyi commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

Closes #113.

Picks up @AntonioSanFer's POC fork (the first commit on this branch, authored by them) and finishes it on top of #106 so it actually runs on current main.

What this adds

A dedicated lyrics screen reachable from the expanded player, with synced highlighting, click-to-seek, and online search fallback.

Where to find it: when the player sheet is expanded, the lyrics icon sits in the bottom control row (next to repeat / queue / shuffle). Tapping it collapses the sheet and opens the lyrics screen, with the mini-player still visible at the bottom for control.

Trigger in expanded player Lyrics screen with active line
Lyrics icon in player control row Lyrics screen showing Bird Set Free with synced highlight

Behavior

  • Synced lyrics: lines highlight in time with the player using the LRC timestamps. The active line auto-scrolls into view at roughly one-third from the top. If you scroll manually, auto-scroll pauses until the playing line drifts out of the visible third again.
  • Click-to-seek: tap any line and the player jumps to that timestamp.
  • Unsynced lyrics: if the LRC isn't synced, lines render as a plain list with an unsynced chip in the header. No auto-scroll, no highlighting.
  • No lyrics on server: shows a "No lyrics available" state with a Search online button that hits the /plugins/lyrics/search plugin endpoint. The error message stays visible for 5 seconds then clears.
  • Auto-search online: if the user has enabled the useLyricsPlugin preference plus lyricsAutoDownload, the screen will automatically hit the plugin search endpoint when local lyrics are missing. If lyricsOverrideUnsynced is on, it'll also override unsynced local lyrics with a synced version from a plugin source.

What's in the diff

From @AntonioSanFer's POC (commit 87591c4):

  • DTOs: LyricsDto, LyricsLineDto, LyricsCheckDto, LyricsRequestDto, PluginLyricsRequestDto, PluginLyricsResultDto
  • Domain: Lyrics, LyricsLine
  • Repository: LyricsRepository interface + DataLyricsRepository implementation (/lyrics, /lyrics/check, /plugins/lyrics/search)
  • Hilt module wiring
  • LyricsScreen composable (header with album art and back nav, synced/unsynced/empty body composables)
  • LyricsViewModel with line index calculation, scheduled advance, online search
  • LyricsUiState, LyricsUiEvent
  • Three lyrics preferences in AppSettings (plugin enabled, auto-download, override-unsynced)
  • Navigation wiring: gotoLyrics() on CommonNavigator / CoreNavigator, LyricsScreenDestination in NavGraphs
  • NetworkApiService endpoints

Follow-up commit (cafe172):

  • Move the lyrics icon into AnimatedPlayerSheet's control row. The POC modified NowPlaying.kt which isn't the active screen post-player: Add Player Animations #106, so the icon was invisible. Tap now collapses the sheet to partial then navigates so the lyrics screen is actually visible.
  • Fix the position-math bug in LyricsScreen: was passing seekPosition * 1000 (a 0..1000 fraction) where milliseconds were expected, so the highlight never moved past line 0. Multiply by track.duration too.
  • Change LyricsLineDto.time from Long to Double. The server returns fractional ms like 128021.99999999999 which Gson refused to parse into Long and killed every fetch. Mapper truncates back to Long for the domain model.
  • Drop the 300ms look-ahead in scheduleNextLine. Lines now advance at the actual line timestamp, which matches the audio for tracks with good LRC data.
  • Add statusBarsPadding() to the lyrics header so the back button and track info aren't covered by the system bar.
  • Replace deprecated Icons.Default.ArrowBack with Icons.AutoMirrored.Filled.ArrowBack.

Testing

Tested on a Pixel 7 Pro running the build from this branch:

  • Loaded synced lyrics across multiple tracks. Highlight advances on the line's timestamp within ~100ms.
  • Click-to-seek: works, player jumps and highlight catches up.
  • Switching tracks while on the lyrics screen: state resets, new lyrics load.
  • Back navigation: returns to the previous screen with the mini-player still visible.
  • Header reads cleanly below the status bar, back button tappable.

One sample track (Short N Sweet by Nyashinski) had LRC timestamps roughly 2 seconds ahead of the actual sung audio. Every other track lined up, which points to bad data in that one LRC file rather than a sync issue in the code. The sync trace logs I ran during dev confirmed advances fire at the exact timestamps the LRC declares.

Known follow-ups (out of scope for this PR)

  • Settings UI for the three lyrics preferences. The preferences exist in AppSettings/AppSettingsRepository but there are no toggles in the settings screen yet, so they default to off.
  • Per-track lyric offset adjustment. For LRC files like the Nyashinski one where the data is offset from the audio, a manual ±n seconds adjustment would let the user fix sync without us changing the data.
  • The "Go to album" / "Go to folder" navigation from the lyrics header onClick-artist is wired but there's no parallel for clicking the title or thumbnail. Minor.

Credit

Lyrics architecture, DTOs, repository, ViewModel sync logic, and the initial LyricsScreen composable are @AntonioSanFer's work from https://github.com/AntonioSanFer/android/tree/feature/lyrics. The follow-up commit on this branch is the integration glue and a handful of bug fixes spotted while testing.

antoniosanchez-es and others added 2 commits June 8, 2026 19:45
- Implemented lyrics navigation in CoreNavigator and NavGraphs.
- Created data transfer objects (DTOs) for lyrics handling including LyricsCheckDto, LyricsDto, LyricsLineDto, LyricsRequestDto, PluginLyricsRequestDto, and PluginLyricsResultDto.
- Developed DataLyricsRepository to manage lyrics fetching and searching online.
- Added Lyrics and LyricsLine domain models to represent lyrics data.
- Introduced LyricsUiState to manage UI state for lyrics display.
- Created LyricsViewModel to handle business logic for lyrics.
- Designed rough LyricsScreen composable for displaying lyrics with synchronization and online search capabilities.
- Updated AppSettings to include preferences for lyrics plugin usage and auto-download settings.
The POC modified NowPlaying.kt which isn't the active screen post-#106. Move
the lyrics icon into AnimatedPlayerSheet's bottom control row and collapse the
sheet on tap so the lyrics screen is actually visible.

Other fixes spotted while testing:

- LyricsScreen was computing positionMs as seekPosition*1000, but seekPosition
  is a 0..1 fraction, so the value passed to PositionChanged maxed at 1000ms
  and the highlight never advanced past line 0. Multiply by track.duration too.
- LyricsLineDto.time is Double. The server returns fractional ms like
  128021.99999999999 which Gson refused to parse into Long, killing every
  lyrics fetch.
- Drop the 300ms look-ahead in scheduleNextLine. Lines now advance at the
  actual line timestamp, which matches the audio for tracks with good LRC data.
- Replace deprecated Icons.Default.ArrowBack with the AutoMirrored variant.
@CLAassistant

CLAassistant commented Jun 8, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@joelkanyi joelkanyi self-assigned this Jun 8, 2026
@joelkanyi
joelkanyi requested a review from Ericgacoki June 9, 2026 02:06

@AntonioSanFer AntonioSanFer 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.

Everything seems great, and working 👍

- Implement smooth scaling and color transitions for lyric lines using `animateFloatAsState` and `animateColorAsState`.
- Add a dynamic scaling effect where the active lyric line is larger than surrounding lines.
- Refine alpha transparency logic to better distinguish between past, active, and upcoming lines.
- Increase font size to 32.sp and adjust line height for improved readability.
- Reduce vertical spacing between lines in the `LazyColumn`.
- Apply `graphicsLayer` with a start-aligned `TransformOrigin` to anchor the scaling effect.
@joelkanyi
joelkanyi merged commit bf062f2 into main Jun 9, 2026
1 check passed
@Ericgacoki

Copy link
Copy Markdown
Member

👁️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature request] Lyrics tab

5 participants