Skip to content

feat: lyrics style#70

Merged
roitium merged 5 commits into
devfrom
feat/improve-lyrics-style
Nov 2, 2025
Merged

feat: lyrics style#70
roitium merged 5 commits into
devfrom
feat/improve-lyrics-style

Conversation

@roitium
Copy link
Copy Markdown
Collaborator

@roitium roitium commented Nov 2, 2025

Summary by CodeRabbit

  • New Features

    • Redesigned player with tab-based Main and Lyrics views
    • Enhanced lyrics: animated line highlighting, offset editing UI, and a new "Old School Lyrics" toggle in Settings
    • Improved seek/lyrics synchronization for smoother jumps between playback and lyrics
  • Style

    • UI polish for player header, track/cover presentation, and lyrics layout
  • Chores

    • App version bumped to 72
  • Documentation

    • Added acknowledgments section to README

@roitium roitium added this to the v1.4.0 milestone Nov 2, 2025
@roitium roitium added this to BBPlayer Nov 2, 2025
@roitium roitium added the enhancement New feature or request label Nov 2, 2025
@safedep
Copy link
Copy Markdown

safedep Bot commented Nov 2, 2025

SafeDep Report Summary

Green Malicious Packages Badge Green Vulnerable Packages Badge Green Risky License Badge

No dependency changes detected. Nothing to scan.

This report is generated by SafeDep Github App

@roitium roitium moved this to In review in BBPlayer Nov 2, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Nov 2, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Refactors player into a tabbed "Main"/"Lyrics" UI, replaces TrackPlayer progress listeners with a sticky progress emitter, adds animated lyric rendering and async seek/coalescing, adjusts several component props/signatures, introduces new progress emitter and sticky-mitt subscribe API, bumps versionCode to 72 and updates docs.

Changes

Cohort / File(s) Change Summary
Version & Docs
CHANGELOG.md, README.md, package.json
Added UNRELEASED changelog entry and acknowledgements; README "感谢" section added; versionCode bumped 71 → 72 in package.json.
Player Page & Tabs
src/app/player.tsx, src/features/player/components/PlayerMainTab.tsx
Reworked player into TabView with "Main" and "Lyrics" routes; extracted PlayerMainTab for cover, track info, slider and controls; simplified header/index state and navigation usage; removed several previous toggles and navigation logic.
Lyrics & Lyric UI
src/features/player/components/PlayerLyrics.tsx
Converted Lyrics to memoized, prop-less component that reads current track internally; added Animated.Text per-line animations, Modern/OldSchool lyric variants, offset editing UI, measureInWindow usage, and async-safe guards for missing track.
Header & Functional Menu
src/features/player/components/PlayerHeader.tsx, src/features/player/components/PlayerFunctionalMenu.tsx
PlayerHeader signature changed to accept index (replacing viewMode/trackTitle); PlayerFunctionalMenu removed screenWidth/uploaderMid/track props and computes values internally, uses Dimensions, and added defensive download-guard behavior.
Track Info Styling
src/features/player/components/PlayerTrackInfo.tsx
Moved borderRadius: 16 from outer touchable to LinearGradient and Image styles.
Progress Emitter & Utils
src/lib/player/progressListener.ts, src/utils/sticky-mitt.ts
New sticky progress emitter playerProgressEmitter relays PlaybackProgressUpdated events; createStickyEmitter loosened generic constraint and now exposes subscribe() which returns an unsubscribe function.
Hooks — Progress & Slider
src/features/player/hooks/useLyricSync.ts, src/features/player/hooks/usePlayerSlider.ts, src/hooks/player/useAnimatedTrackProgress.ts, src/hooks/player/useTrackProgress.ts
Replaced TrackPlayer.addEventListener wiring with playerProgressEmitter.subscribe('progress', ...); updated seek flows to async Promise<void> and awaited seeks, coalesced jump requests to avoid races; timer types adjusted from NodeJS.Timeout to number.
Player Store
src/hooks/stores/usePlayerStore.ts
seekTo now emits a sticky progress event after seeking (position, duration, buffered) to improve update consistency during seeks.
App Settings & Store
src/app/(tabs)/settings.tsx, src/hooks/stores/useAppStore.ts, src/types/core/appStore.ts, src/types/storage.ts
Added enableOldSchoolStyleLyric flag to storage, types, and app store; exposed setEnableOldSchoolStyleLyric; added settings UI toggle; persisted new key enable_old_school_style_lyric.
Native Intent Handling
src/app/+native-intent.ts
Added hostname handling for bbplayer.roitium.com to extract /link-to/ segment as redirect path.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant PlayerPage
    participant TabView
    participant PlayerMainTab
    participant PlayerLyrics

    User->>PlayerPage: Open player
    PlayerPage->>TabView: Render tabs (index state)
    TabView->>PlayerMainTab: Render when index=0
    PlayerMainTab->>PlayerMainTab: Load cover, controls, slider
    PlayerMainTab->>User: Display main playback UI

    User->>TabView: Switch to Lyrics tab (index=1)
    TabView->>PlayerLyrics: Render lyrics
    PlayerLyrics->>PlayerLyrics: Fetch track & lyrics, animate lines
    PlayerLyrics->>User: Display animated lyrics and offset UI
Loading
sequenceDiagram
    participant TrackPlayer as TrackPlayer (native)
    participant Emitter as playerProgressEmitter
    participant Hook as Hook (useLyricSync / usePlayerSlider / etc.)

    TrackPlayer->>TrackPlayer: PlaybackProgressUpdated fires
    TrackPlayer->>Emitter: Listener maps payload -> progress shape
    Emitter->>Emitter: emitSticky('progress', data)

    Hook->>Emitter: subscribe('progress', handler)
    Emitter->>Hook: deliver latest or future progress
    Hook->>Hook: update local state (position, lyric index, UI)
    Hook->>Emitter: unsubscribe via returned function on cleanup
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas needing extra attention:

  • src/app/player.tsx — tab state, renderScene memoization, refs for menu/queue.
  • src/features/player/hooks/useLyricSync.ts — async seek/coalescing and latestJumpRequestRef correctness.
  • src/lib/player/progressListener.ts & src/utils/sticky-mitt.ts — sticky behavior and subscribe/unsubscribe correctness.
  • Hooks using the emitter (usePlayerSlider, useAnimatedTrackProgress, useTrackProgress) — ensure cleanup/unsubscribe paths execute.
  • PlayerFunctionalMenu internal uploaderMid/download guard logic.

Possibly related PRs

Poem

🐰
Tabs now hop where single views lay,
Progress sticks and finds its way,
Lyrics glow in timed design,
Seeks await — then lines align,
I twitch my whiskers, sip thyme tea. 🎶

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The title "feat: lyrics style" does refer to real changes in the pull request, specifically the additions of lyrics animation enhancements and a new settings toggle for lyrics style preference. However, the changeset encompasses a much broader refactoring that includes a significant architectural change: the entire player interface has been refactored from a single-view layout to a tab-based layout with separate "Main" and "Lyrics" tabs. This tab-based refactor appears to be the primary structural change, with the lyrics style improvements being a feature that leverages this new architecture. The title captures only the narrower aspect of lyrics styling improvements while omitting the main architectural transformation.
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cca5aa8 and 12ebcd7.

📒 Files selected for processing (1)
  • src/app/+native-intent.ts (1 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/features/player/hooks/useLyricSync.ts (1)

17-77: Prevent stale lyric highlight after overlapping seeks.

When the user taps multiple lines quickly, each handleJumpToLyric call kicks off a seekTo. Those promises can resolve out of order, so an older request may finish last and revert currentLyricIndex to an obsolete value, making the highlight jump back even though playback has already moved on. Please guard the state update so only the latest jump wins (e.g., track a monotonically increasing request id or move the state update ahead of the await).

diff
@@
-	const manualScrollTimeoutRef = useRef<number | null>(null)
+	const manualScrollTimeoutRef = useRef<number | null>(null)
+	const latestJumpRequestRef = useRef(0)
@@
-		async (index: number) => {
+		async (index: number) => {
 			if (lyrics.length === 0) return
 			if (!lyrics[index]) return
-			await seekTo(lyrics[index].timestamp)
+			const requestId = ++latestJumpRequestRef.current
+			await seekTo(lyrics[index].timestamp)
+			if (latestJumpRequestRef.current !== requestId) return
 			setCurrentLyricIndex(index)
 			if (manualScrollTimeoutRef.current) {
 				clearTimeout(manualScrollTimeoutRef.current)
 				manualScrollTimeoutRef.current = null
 			}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fb9daaf and 21aa0d9.

📒 Files selected for processing (15)
  • CHANGELOG.md (1 hunks)
  • package.json (1 hunks)
  • src/app/player.tsx (2 hunks)
  • src/features/player/components/PlayerFunctionalMenu.tsx (2 hunks)
  • src/features/player/components/PlayerHeader.tsx (2 hunks)
  • src/features/player/components/PlayerLyrics.tsx (16 hunks)
  • src/features/player/components/PlayerMainTab.tsx (1 hunks)
  • src/features/player/components/PlayerTrackInfo.tsx (2 hunks)
  • src/features/player/hooks/useLyricSync.ts (3 hunks)
  • src/features/player/hooks/usePlayerSlider.ts (3 hunks)
  • src/hooks/player/useAnimatedTrackProgress.ts (2 hunks)
  • src/hooks/player/useTrackProgress.ts (3 hunks)
  • src/hooks/stores/usePlayerStore.ts (2 hunks)
  • src/lib/player/progressListener.ts (1 hunks)
  • src/utils/sticky-mitt.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
src/features/player/components/PlayerFunctionalMenu.tsx (1)
src/hooks/stores/useModalStore.ts (2)
  • openModal (74-74)
  • useModalStore (29-72)
src/features/player/components/PlayerMainTab.tsx (3)
src/features/player/components/PlayerTrackInfo.tsx (1)
  • TrackInfo (17-154)
src/features/player/components/PlayerSlider.tsx (1)
  • PlayerSlider (71-115)
src/features/player/components/PlayerControls.tsx (1)
  • PlayerControls (7-122)
src/features/player/components/PlayerLyrics.tsx (2)
src/hooks/queries/lyrics/index.ts (1)
  • useSmartFetchLyrics (14-36)
src/hooks/stores/useModalStore.ts (1)
  • useModalStore (29-72)
src/features/player/hooks/useLyricSync.ts (1)
src/types/player/lyrics.ts (1)
  • LyricLine (3-16)
src/features/player/hooks/usePlayerSlider.ts (1)
src/hooks/stores/usePlayerStore.ts (1)
  • usePlayerStore (46-735)
src/app/player.tsx (1)
src/features/player/components/PlayerHeader.tsx (1)
  • PlayerHeader (6-52)
🔇 Additional comments (8)
package.json (1)

5-5: LGTM!

Version code increment aligns with the PR's feature additions.

src/features/player/components/PlayerTrackInfo.tsx (1)

83-83: LGTM!

Consistent border radius applied to both the gradient placeholder and cover image improves visual polish.

Also applies to: 104-104

src/hooks/stores/usePlayerStore.ts (1)

504-513: Verify progress fetch timing for accuracy.

The current implementation fetches progress before seeking, then emits the new position with the old duration and buffered values. This provides immediate feedback but might be briefly inaccurate if these values change during the seek operation.

Consider whether fetching progress after TrackPlayer.seekTo(position) would better reflect the actual player state, or confirm that immediate emission with pre-seek values is intentional for responsiveness.

src/hooks/player/useAnimatedTrackProgress.ts (1)

1-1: LGTM!

Clean migration from TrackPlayer events to the centralized progress emitter. The unsubscribe pattern is correctly implemented.

Also applies to: 26-34

src/features/player/components/PlayerHeader.tsx (1)

6-12: LGTM!

The refactor from viewMode/trackTitle props to a single index prop simplifies the component API while maintaining clear rendering logic for different tab states.

Also applies to: 39-43

src/utils/sticky-mitt.ts (1)

90-103: LGTM!

The subscribe method provides a clean convenience API that correctly inherits sticky behavior from the underlying on() method and returns an unsubscribe function for easy cleanup.

src/features/player/hooks/usePlayerSlider.ts (2)

12-12: Good type correction.

Changing from NodeJS.Timeout to number correctly reflects that React Native's setTimeout returns a number rather than a NodeJS Timeout object.


26-31: LGTM!

The migration to the progress emitter and centralizing seek through usePlayerStore aligns with the PR's architectural improvements, enabling consistent progress updates across the application.

Also applies to: 33-33, 63-63

Comment thread src/features/player/components/PlayerMainTab.tsx
Comment thread src/utils/sticky-mitt.ts
@roitium roitium merged commit fbb8975 into dev Nov 2, 2025
3 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in BBPlayer Nov 2, 2025
@roitium roitium deleted the feat/improve-lyrics-style branch November 2, 2025 09:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant