Skip to content

feat: performance improve#69

Merged
roitium merged 5 commits into
devfrom
fix/many-things
Nov 2, 2025
Merged

feat: performance improve#69
roitium merged 5 commits into
devfrom
fix/many-things

Conversation

@roitium
Copy link
Copy Markdown
Collaborator

@roitium roitium commented Nov 2, 2025

Summary by CodeRabbit

  • Performance

    • Reduced unnecessary rerenders across lists and screens for smoother UI.
  • Bug Fixes

    • Restored menu interaction/animation behavior.
    • Centralized error handling and improved consistency of user-facing error toasts.
  • Documentation

    • Added UI development guidelines for rendering patterns and FlashList usage.

@roitium roitium added this to the v1.4.0 milestone Nov 2, 2025
@roitium roitium added the enhancement New feature or request label Nov 2, 2025
@roitium roitium added this to BBPlayer 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

Package Details
Package Malware Vulnerability Risky License Report
icon react-native-paper @ 5.14.5
pnpm-lock.yaml
ok icon
ok icon
ok icon
🔗

This report is generated by SafeDep Github App

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Nov 2, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This PR refactors error handling and player state management across the codebase by extracting toastAndLogError into a dedicated module, consolidating player hooks, converting current-track detection to use a haveTrack boolean flag from the player store, and standardizing FlashList renderItem functions to module-level scope with memoized extraData patterns.

Changes

Cohort / File(s) Summary
Error handling module extraction
src/utils/error-handling.ts, src/utils/log.ts
Creates new @/utils/error-handling.ts with toastAndLogError function; removes function from src/utils/log.ts.
Import updates: error handling module
src/app/(tabs)/index.tsx, src/app/(tabs)/settings.tsx, src/app/_layout.tsx, src/app/playlist/local/[id].tsx, src/components/modals/login/CookieLoginModal.tsx, src/components/modals/lyrics/EditLyrics.tsx, src/components/modals/edit-metadata/editPlaylistMetadataModal.tsx, src/features/playlist/local/hooks/useLocalPlaylistMenu.ts, src/features/playlist/local/hooks/useLocalPlaylistPlayer.ts, src/features/playlist/remote/hooks/useCheckLinkedToLocalPlaylist.ts, src/hooks/mutations/bilibili/..., src/hooks/stores/usePlayerStore.ts, src/lib/..., src/utils/lyrics.ts, src/utils/search.ts
Updates imports of toastAndLogError from @/utils/log to @/utils/error-handling across 19 files.
Player hook path consolidation
src/app/player.tsx, src/components/NowPlayingBar.tsx, src/features/player/components/PlayerFunctionalMenu.tsx, src/features/player/components/PlayerHeader.tsx, src/features/player/components/PlayerTrackInfo.tsx
Updates import path for useCurrentTrack from @/hooks/stores/playerHooks/useCurrentTrack to @/hooks/player/useCurrentTrack.
Current track detection pattern refactor
src/app/(tabs)/settings.tsx, src/app/download.tsx, src/app/test.tsx, src/features/library/collection/CollectionList.tsx, src/features/library/favorite/FavoriteFolderList.tsx, src/features/library/local/LocalPlaylistList.tsx, src/features/library/multipage/MultiPageVideosList.tsx, src/features/playlist/local/components/LocalTrackList.tsx, src/features/playlist/remote/components/RemoteTrackList.tsx
Replaces useCurrentTrack() with usePlayerStore() to derive haveTrack boolean from state.currentTrackUniqueKey; updates layout padding logic accordingly.
FlashList renderItem extraction to module scope
src/app/download.tsx, src/app/leaderboard.tsx, src/features/library/collection/CollectionList.tsx, src/features/library/favorite/FavoriteFolderList.tsx, src/features/library/local/LocalPlaylistList.tsx, src/features/library/multipage/MultiPageVideosList.tsx
Moves inline useCallback-based renderItem to top-level constant function; removes associated memoization wrapper for simpler, stable function references.
FlashList with extraData pattern implementation
src/components/modals/lyrics/ManualSearchLyrics.tsx, src/components/modals/playlist/BatchAddTracksToLocalPlaylist.tsx, src/components/modals/playlist/UpdateTrackLocalPlaylistsModal.tsx, src/features/player/components/PlayerLyrics.tsx, src/features/playlist/local/components/LocalTrackList.tsx, src/features/playlist/remote/components/RemoteTrackList.tsx
Introduces module-level renderItem function, creates memoized extraData object via useMemo containing callbacks/state, passes extraData to FlashList, adds ListRenderItemInfoWithExtraData type usage, and includes runtime guards for missing extraData.
Type definition & documentation
src/types/flashlist.ts, docs/principles.md
Adds new generic type ListRenderItemInfoWithExtraData<TItem, TExtraData> for typed FlashList rendering with optional extraData; creates documentation file with UI development guidelines for renderItem functions and memoization patterns.
Menu component patch removal and configuration
patches/react-native-paper.patch, pnpm-workspace.yaml, src/components/common/FunctionalMenu.tsx
Removes react-native-paper Menu patch file and corresponding patchedDependencies entry from workspace config; adds key={String(visible)} prop to Menu component to trigger reconciliation on visibility changes.
CHANGELOG & Player initialization
CHANGELOG.md, src/lib/player/playerLogic.ts
Documents rerender optimization and Menu component approach change; removes playerIsReady idempotence guard from initPlayer function, introducing listenersAttached flag for event listener binding protection.

Sequence Diagram(s)

sequenceDiagram
    participant OldPattern as Old Pattern<br/>(useCallback)
    participant NewPattern as New Pattern<br/>(Module-level +<br/>extraData)
    participant Component
    participant FlashList

    rect rgb(240, 248, 255)
    Note over OldPattern: Previous approach
    OldPattern->>Component: Component renders
    Component->>OldPattern: useCallback evaluates<br/>with deps array
    OldPattern->>FlashList: Pass renderItem
    FlashList->>FlashList: Re-render may trigger<br/>callback re-evaluation
    end

    rect rgb(245, 255, 250)
    Note over NewPattern: New approach
    NewPattern->>NewPattern: Define top-level<br/>renderItem (stable)
    Component->>Component: useMemo creates<br/>extraData with deps
    Component->>FlashList: Pass stable renderItem<br/>+ memoized extraData
    FlashList->>FlashList: Item render uses<br/>stable function &<br/>extraData reference
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Large scope: 50+ files affected with coordinated changes across multiple interconnected systems (error handling, player state management, component rendering patterns).
  • Recurring patterns: While many changes follow consistent patterns (import consolidation, renderItem extraction, extraData adoption), each implementation requires individual verification for correctness.
  • Heterogeneous logic: Mix of straightforward mechanical import rewiring alongside substantive behavioral changes (idempotence guard removal, Menu key prop, renderItem memoization strategy).
  • Specific areas requiring extra attention:
    • src/lib/player/playerLogic.ts — Removal of global.playerIsReady idempotence guard in initPlayer and introduction of listenersAttached flag; verify no duplicate initialization side effects or listener binding issues occur on re-initialization.
    • src/features/playlist/remote/components/RemoteTrackList.tsx — Most complex renderItem refactor with multiple handlers, state, and selection logic integrated via extraData; verify structure, typing, error handling, and haptic feedback behavior.
    • src/components/common/FunctionalMenu.tsx — Key prop addition (key={String(visible)}) changes reconciliation behavior; ensure Menu animations, state transitions, and visual interactions remain correct.
    • Files using haveTrack pattern — Verify state.currentTrackUniqueKey semantic equivalence to previous currentTrack presence check across nine modified component files.
    • Type safety across ListRenderItemInfoWithExtraData usages — Confirm all extraData structures are properly typed and guards are consistently placed.
    • Patch removal impact — Verify react-native-paper Menu component works correctly without the patch after the key prop addition.

Possibly related PRs

  • PR#69: Contains overlapping code-level changes (toastAndLogError extraction, ListRenderItemInfoWithExtraData type addition, react-native-paper patch removal, and FlashList renderItem/extraData refactoring patterns).
  • PR#56: Modifies leaderboard page UI with similar renderItem extraction and usePlayerStore/haveTrack pattern changes, indicating sequential or parallel refactoring work.
  • PR#63: Refactors LocalTrackList component with similar renderItem and usePlayerStore changes, suggesting related component modernization effort.

Poem

🐰 Refactoring through the warren deep,
Error handlers bundled, safe to keep,
FlashList items now arranged with care,
ExtraData memoized everywhere,
Player state consolidates its might—
The codebase hops toward cleaner light!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The title "feat: performance improve" is vague and overly generic. While the changeset does include performance optimizations (primarily around moving renderItem functions to top-level scope for FlashList per the new UI principles, and reorganizing player state), the PR encompasses substantially more: code module reorganization (moving toastAndLogError to a dedicated error-handling module), hook path reorganization, removal of react-native-paper patches, new documentation, and new type definitions. The phrase "performance improve" is too broad and grammatically awkward to clearly convey what the primary change is, leaving a reviewer scanning history without a clear understanding of the changeset's scope and intent. Consider retitling to be more specific and descriptive. For example, if the main focus is the FlashList and rendering optimization, a title like "refactor: optimize FlashList renderItem functions and consolidate error handling" would better capture the primary changes. If refactoring is the primary goal, reflect that in the title. Ensure the title is grammatically correct and specific enough that a teammate scanning commit history understands the changeset's main purpose without opening the PR.
✅ 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 c7e8d3e and d4e6494.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • src/app/leaderboard.tsx (3 hunks)
  • src/lib/player/playerLogic.ts (4 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.

@roitium roitium moved this to In review in BBPlayer Nov 2, 2025
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: 1

Caution

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

⚠️ Outside diff range comments (2)
src/app/leaderboard.tsx (1)

60-60: Replace useCurrentTrack() with haveTrack from usePlayerStore to align with codebase pattern.

This file is the only one using currentTrack for the padding calculation. All other files (LocalTrackList, RemoteTrackList, download, settings, and others) use:

const haveTrack = usePlayerStore((state) => !!state.currentTrackUniqueKey)

Then reference it as: paddingBottom: haveTrack ? 70 + insets.bottom : insets.bottom

At line 60, replace the useCurrentTrack() import and hook usage with the usePlayerStore pattern used elsewhere.

src/lib/player/playerLogic.ts (1)

16-24: Verify idempotence: risk of duplicate event listener registration.

The initPlayer function no longer guards against re-initialization. While the caller in src/app/_layout.tsx (line 97) checks global.playerIsReady, removing the guard from initPlayer itself makes it fragile:

  • Line 19: setupEventListeners() registers event handlers via TrackPlayer.addEventListener
  • TrackPlayer does not automatically deduplicate listeners
  • If initPlayer is called multiple times (e.g., during hot reload, or from another call site without a guard), duplicate listeners will accumulate

This can cause memory leaks and duplicate event handling (e.g., multiple play records for a single track, multiple pause calls on sleep timer).

Consider restoring the idempotence guard:

 const initPlayer = async () => {
+  if (global.playerIsReady) {
+    logger.debug('播放器已初始化,跳过')
+    return
+  }
   logger.info('开始初始化播放器')
   await PlayerLogic.preparePlayer()
   PlayerLogic.setupEventListeners()
🧹 Nitpick comments (1)
docs/principles.md (1)

1-5: Good practice documented.

This principle aligns well with React performance best practices by preventing unnecessary function recreations and ensuring FlashList can properly detect changes.

Consider adding a code example to illustrate the pattern:

// ❌ 不好的做法
function MyList() {
  const data = useData()
  const currentUser = useCurrentUser()
  
  return (
    <FlashList
      data={data}
      renderItem={({ item }) => <Item item={item} user={currentUser} />}
    />
  )
}

// ✅ 推荐的做法
const renderItem = ({ item, extraData }: { item: DataType; extraData?: ExtraDataType }) => {
  if (!extraData) return null
  return <Item item={item} user={extraData.user} />
}

function MyList() {
  const data = useData()
  const currentUser = useCurrentUser()
  const extraData = useMemo(() => ({ user: currentUser }), [currentUser])
  
  return (
    <FlashList
      data={data}
      renderItem={renderItem}
      extraData={extraData}
    />
  )
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6255fad and c7e8d3e.

📒 Files selected for processing (46)
  • CHANGELOG.md (1 hunks)
  • docs/principles.md (1 hunks)
  • patches/react-native-paper.patch (0 hunks)
  • pnpm-workspace.yaml (0 hunks)
  • src/app/(tabs)/index.tsx (1 hunks)
  • src/app/(tabs)/settings.tsx (3 hunks)
  • src/app/_layout.tsx (1 hunks)
  • src/app/download.tsx (4 hunks)
  • src/app/leaderboard.tsx (2 hunks)
  • src/app/player.tsx (1 hunks)
  • src/app/playlist/local/[id].tsx (1 hunks)
  • src/app/test.tsx (3 hunks)
  • src/components/NowPlayingBar.tsx (1 hunks)
  • src/components/common/FunctionalMenu.tsx (1 hunks)
  • src/components/modals/PlayerQueueModal.tsx (1 hunks)
  • src/components/modals/edit-metadata/editPlaylistMetadataModal.tsx (1 hunks)
  • src/components/modals/login/CookieLoginModal.tsx (1 hunks)
  • src/components/modals/lyrics/EditLyrics.tsx (1 hunks)
  • src/components/modals/lyrics/ManualSearchLyrics.tsx (4 hunks)
  • src/components/modals/playlist/BatchAddTracksToLocalPlaylist.tsx (3 hunks)
  • src/components/modals/playlist/UpdateTrackLocalPlaylistsModal.tsx (3 hunks)
  • src/features/library/collection/CollectionList.tsx (2 hunks)
  • src/features/library/favorite/FavoriteFolderList.tsx (3 hunks)
  • src/features/library/local/LocalPlaylistList.tsx (2 hunks)
  • src/features/library/multipage/MultiPageVideosList.tsx (2 hunks)
  • src/features/player/components/PlayerFunctionalMenu.tsx (1 hunks)
  • src/features/player/components/PlayerHeader.tsx (1 hunks)
  • src/features/player/components/PlayerLyrics.tsx (4 hunks)
  • src/features/player/components/PlayerTrackInfo.tsx (1 hunks)
  • src/features/playlist/local/components/LocalTrackList.tsx (4 hunks)
  • src/features/playlist/local/hooks/useLocalPlaylistMenu.ts (1 hunks)
  • src/features/playlist/local/hooks/useLocalPlaylistPlayer.ts (1 hunks)
  • src/features/playlist/remote/components/RemoteTrackList.tsx (5 hunks)
  • src/features/playlist/remote/hooks/useCheckLinkedToLocalPlaylist.ts (1 hunks)
  • src/hooks/mutations/bilibili/favorite.ts (1 hunks)
  • src/hooks/mutations/bilibili/video.ts (1 hunks)
  • src/hooks/mutations/db/playlist.ts (1 hunks)
  • src/hooks/stores/usePlayerStore.ts (1 hunks)
  • src/lib/config/queryClient.ts (1 hunks)
  • src/lib/player/playerLogic.ts (1 hunks)
  • src/lib/services/lyricService.ts (1 hunks)
  • src/types/flashlist.ts (1 hunks)
  • src/utils/error-handling.ts (1 hunks)
  • src/utils/log.ts (0 hunks)
  • src/utils/lyrics.ts (1 hunks)
  • src/utils/search.ts (1 hunks)
💤 Files with no reviewable changes (3)
  • src/utils/log.ts
  • pnpm-workspace.yaml
  • patches/react-native-paper.patch
🧰 Additional context used
🧬 Code graph analysis (15)
src/app/(tabs)/settings.tsx (1)
src/hooks/stores/usePlayerStore.ts (1)
  • usePlayerStore (45-728)
src/features/library/local/LocalPlaylistList.tsx (2)
src/types/core/media.ts (1)
  • Playlist (65-78)
src/hooks/stores/usePlayerStore.ts (1)
  • usePlayerStore (45-728)
src/app/test.tsx (1)
src/hooks/stores/usePlayerStore.ts (1)
  • usePlayerStore (45-728)
src/app/leaderboard.tsx (1)
src/features/leaderboard/LeaderBoardItem.tsx (1)
  • LeaderBoardListItem (18-135)
src/components/modals/playlist/BatchAddTracksToLocalPlaylist.tsx (2)
src/types/flashlist.ts (1)
  • ListRenderItemInfoWithExtraData (3-8)
src/types/core/media.ts (1)
  • Playlist (65-78)
src/features/playlist/local/components/LocalTrackList.tsx (4)
src/types/flashlist.ts (1)
  • ListRenderItemInfoWithExtraData (3-8)
src/types/core/media.ts (2)
  • Track (63-63)
  • Playlist (65-78)
src/features/playlist/local/components/LocalPlaylistItem.tsx (1)
  • TrackListItem (35-236)
src/hooks/stores/usePlayerStore.ts (1)
  • usePlayerStore (45-728)
src/features/player/components/PlayerLyrics.tsx (2)
src/types/flashlist.ts (1)
  • ListRenderItemInfoWithExtraData (3-8)
src/types/player/lyrics.ts (1)
  • LyricLine (3-16)
src/components/modals/playlist/UpdateTrackLocalPlaylistsModal.tsx (2)
src/types/flashlist.ts (1)
  • ListRenderItemInfoWithExtraData (3-8)
src/types/core/media.ts (1)
  • Playlist (65-78)
src/components/modals/lyrics/ManualSearchLyrics.tsx (2)
src/types/flashlist.ts (1)
  • ListRenderItemInfoWithExtraData (3-8)
src/types/player/lyrics.ts (1)
  • LyricSearchResult (26-32)
src/features/library/multipage/MultiPageVideosList.tsx (2)
src/types/apis/bilibili.ts (1)
  • BilibiliFavoriteListContent (363-363)
src/hooks/stores/usePlayerStore.ts (1)
  • usePlayerStore (45-728)
src/features/library/favorite/FavoriteFolderList.tsx (1)
src/hooks/stores/usePlayerStore.ts (1)
  • usePlayerStore (45-728)
src/utils/error-handling.ts (2)
src/lib/errors/index.ts (1)
  • CustomError (1-13)
src/utils/log.ts (1)
  • flatErrorMessage (111-129)
src/features/library/collection/CollectionList.tsx (1)
src/hooks/stores/usePlayerStore.ts (1)
  • usePlayerStore (45-728)
src/app/download.tsx (2)
src/types/core/downloadManagerStore.ts (1)
  • DownloadTask (1-7)
src/hooks/stores/usePlayerStore.ts (1)
  • usePlayerStore (45-728)
src/features/playlist/remote/components/RemoteTrackList.tsx (2)
src/types/flashlist.ts (1)
  • ListRenderItemInfoWithExtraData (3-8)
src/hooks/stores/usePlayerStore.ts (1)
  • usePlayerStore (45-728)
🔇 Additional comments (51)
src/app/player.tsx (1)

8-8: Import path update verified as complete.

The migration from @/hooks/stores/playerHooks/useCurrentTrack to @/hooks/player/useCurrentTrack is fully complete across the codebase. All 7 imports in the codebase have been updated to use the new path, the old hook file has been removed, and the new hook maintains API compatibility (returns Track | null). The change on line 8 is correct with no outstanding concerns.

src/app/leaderboard.tsx (2)

43-54: Good performance optimization with module-scoped renderItem.

Moving renderItem to module scope is an excellent performance optimization. The function is now created once rather than on every component render. Since LeaderBoardListItem uses Zustand store subscriptions internally (accessing usePlayerStore for isCurrentTrack), it will automatically re-render when needed without requiring extraData on the FlashList.


3-3: Import path and hook are valid; no issues found.

The new import path @/hooks/player/useCurrentTrack is correct. The hook exists at src/hooks/player/useCurrentTrack.ts, is properly exported as a default export, and returns Track | null as expected. The hook's usage in the file (line 60 for the call, line 129 for the ternary check on padding) is semantically correct and handles the null case properly.

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

2-2: LGTM - Clean refactor.

The import path consolidation improves code organization by moving player hooks to a dedicated directory.

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

1-1: LGTM - Consistent with hook consolidation.

Import path update aligns with the broader refactor to consolidate player hooks.

CHANGELOG.md (1)

16-20: LGTM - Clear changelog entries.

The changelog appropriately documents the performance optimizations and Menu component fix with a reference to the upstream issue.

src/components/modals/PlayerQueueModal.tsx (1)

1-2: LGTM - Hook consolidation refactor.

Import paths updated consistently with the broader effort to organize player hooks under a dedicated directory.

src/features/library/multipage/MultiPageVideosList.tsx (3)

18-22: LGTM - Follows documented principles.

The module-scope renderPlaylistItem function correctly follows the principle documented in docs/principles.md. Since MultiPageVideosItem only depends on the item prop, no extraData object is needed, which is the appropriate simplification of the pattern.


26-26: Good optimization - using haveTrack for boolean check.

Switching from useCurrentTrack() to deriving haveTrack from usePlayerStore((state) => !!state.currentTrackUniqueKey) is more efficient for the boolean check use case. This avoids subscribing to the entire currentTrack object when only track presence is needed.


112-112: Consistent with haveTrack refactor.

The padding calculation correctly uses the new haveTrack boolean flag, maintaining the same conditional logic (70px when track exists for NowPlayingBar, 10px otherwise).

src/hooks/mutations/bilibili/video.ts (1)

4-4: LGTM - Error handling consolidation.

Moving toastAndLogError to a dedicated error-handling module improves code organization and separation of concerns.

src/lib/config/queryClient.ts (1)

4-4: LGTM! Clean import path refactor.

The import path change aligns with the centralized error-handling module structure.

src/utils/lyrics.ts (1)

2-3: LGTM! Clean separation of concerns.

Splitting error handling and logging imports makes the module boundaries clearer.

src/components/modals/login/CookieLoginModal.tsx (1)

5-5: LGTM! Consistent with the error-handling refactor.

src/features/playlist/remote/hooks/useCheckLinkedToLocalPlaylist.ts (1)

3-3: LGTM! Aligns with the centralized error-handling pattern.

src/components/modals/lyrics/EditLyrics.tsx (1)

6-6: LGTM! Consistent with the error-handling module migration.

src/hooks/mutations/db/playlist.ts (1)

10-10: LGTM! Clean migration to the centralized error-handling module.

src/app/(tabs)/index.tsx (1)

7-7: LGTM! Follows the error-handling refactor pattern.

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

2-2: Hook path migration verified as complete.

Migration to the new player hooks structure is successful. Verification confirms:

  • No stale @/hooks/stores/playerHooks imports remain
  • New modules exist at consolidated locations (src/utils/error-handling.ts, src/hooks/player/useCurrentTrack.ts)
  • Codebase is consistent with the refactored import paths
src/utils/search.ts (1)

4-5: LGTM! Clean separation of concerns.

The refactoring correctly moves toastAndLogError to a dedicated error-handling module while maintaining the log import from the logging module. This improves code organization and maintainability.

src/components/NowPlayingBar.tsx (1)

2-2: LGTM! Import path consolidation.

The updated import path for useCurrentTrack aligns with the broader player hook consolidation mentioned in the PR objectives.

src/features/playlist/local/hooks/useLocalPlaylistMenu.ts (1)

9-9: LGTM! Consistent error-handling module usage.

The import update correctly references the new dedicated error-handling module.

src/app/playlist/local/[id].tsx (1)

26-26: LGTM! Aligned with error-handling refactor.

The import correctly uses the new error-handling module.

src/components/modals/edit-metadata/editPlaylistMetadataModal.tsx (1)

5-6: LGTM! Proper import separation.

The split imports correctly separate error handling from logging utilities while maintaining all necessary functionality.

src/lib/services/lyricService.ts (1)

7-8: LGTM! Consistent module separation.

The import reorganization properly separates error handling from logging utilities.

src/features/playlist/local/hooks/useLocalPlaylistPlayer.ts (1)

4-4: LGTM! Error-handling module usage.

The import correctly references the dedicated error-handling module.

src/hooks/mutations/bilibili/favorite.ts (1)

4-5: LGTM! Import refactoring complete.

The import split correctly separates error-handling utilities from logging, completing the consistent refactoring pattern across the codebase.

src/app/(tabs)/settings.tsx (1)

4-6: LGTM! Clean refactor to centralized error handling and player state.

The migration from useCurrentTrack to deriving haveTrack directly from usePlayerStore(state => !!state.currentTrackUniqueKey) is more efficient and aligns with the PR's consolidation objectives. The error handling import path change to @/utils/error-handling is consistent with the codebase-wide refactor.

Also applies to: 27-27, 41-41

src/app/test.tsx (1)

7-8: LGTM! Consistent with codebase-wide refactor.

The separation of error handling utilities to @/utils/error-handling while keeping logging functions in @/utils/log improves module organization. The haveTrack pattern adoption aligns with changes across other files.

Also applies to: 24-24, 152-152

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

15-16: LGTM! Import path consolidation.

The refactor moves toastAndLogError to a dedicated error-handling module while preserving other log utilities in their original location. No runtime behavior changes.

src/app/_layout.tsx (1)

11-12: LGTM! Import reorganization aligns with centralized error handling.

src/types/flashlist.ts (1)

1-8: LGTM! Well-defined generic type for FlashList extraData pattern.

The ListRenderItemInfoWithExtraData type correctly extends ListRenderItemInfo to support typed extraData, enabling type-safe module-level renderItem functions used throughout the PR.

src/features/library/local/LocalPlaylistList.tsx (1)

5-5: LGTM! Efficient refactor with module-level renderItem.

Moving renderPlaylistItem to module scope (lines 13-15) is appropriate since it has no component-specific dependencies, improving render stability. The haveTrack pattern (line 19) and padding calculation (line 80) are consistent with the codebase-wide refactor.

Also applies to: 13-15, 19-19, 80-80

src/app/download.tsx (1)

5-5: LGTM! Clean refactor aligning with codebase patterns.

The module-level renderItem (lines 15-17) and haveTrack pattern (line 30) are consistent with changes across the PR. The padding calculation correctly accounts for the NowPlayingBar height when a track is active.

Also applies to: 15-17, 30-30, 53-53

src/features/library/collection/CollectionList.tsx (2)

15-17: LGTM! Module-level renderItem improves performance.

Moving renderCollectionItem to module scope prevents function recreation on every render, which is a good performance optimization. Since CollectionListItem only depends on the item prop, no extraData is needed here.


21-21: LGTM! Using haveTrack flag avoids unnecessary re-renders.

Deriving haveTrack from currentTrackUniqueKey is a good optimization. This boolean flag will only trigger re-renders when track presence changes, not when track content changes.

src/features/library/favorite/FavoriteFolderList.tsx (2)

16-18: LGTM! Consistent with the module-level renderItem pattern.

This follows the same performance optimization pattern as other list components in this PR.


23-23: LGTM! Consistent haveTrack usage.

The haveTrack flag is consistently derived from usePlayerStore across all list components in this PR.

src/components/modals/lyrics/ManualSearchLyrics.tsx (2)

23-41: LGTM! extraData pattern correctly implemented.

The module-level renderItem with extraData is properly implemented:

  • Throws an error if extraData is missing (defensive programming)
  • Extracts required handlers from extraData
  • Passes them to SearchItem

This pattern ensures that renderItem doesn't get recreated on every render while still having access to the latest handlers.


94-97: LGTM! extraData properly memoized.

The extraData object is correctly memoized with all necessary dependencies (handlePressItem, isFetchingLyrics). This ensures FlashList only re-renders when these values actually change.

src/components/modals/playlist/BatchAddTracksToLocalPlaylist.tsx (2)

14-35: LGTM! extraData pattern correctly implemented for playlist selection.

The module-level renderPlaylistItem properly uses extraData to access selectedPlaylistId and setSelectedPlaylistId. The error guard ensures the function fails fast if extraData is missing.


97-103: LGTM! extraData properly memoized with stable dependencies.

The extraData object is memoized with the correct dependencies. Note that setSelectedPlaylistId is a stable function reference from useState, so it won't cause unnecessary re-renders.

src/components/modals/playlist/UpdateTrackLocalPlaylistsModal.tsx (2)

17-41: LGTM! extraData pattern for checkbox state management.

The module-level renderPlaylistItem correctly uses extraData to pass checkedPlaylistIds and handleCheckboxPress to the rendered item. The implementation is consistent with other modal components in this PR.


166-172: LGTM! extraData memoization is correct.

All dependencies are properly included: checkedPlaylistIds (state), handleCheckboxPress (memoized callback).

src/utils/error-handling.ts (1)

1-41: LGTM! Centralizing error handling improves maintainability.

The toastAndLogError function properly handles different error types and provides consistent error reporting. The implementation correctly:

  • Distinguishes between CustomError, standard Error, undefined, and unknown types
  • Flattens nested error messages using flatErrorMessage
  • Logs to the appropriate scope
  • Displays user-friendly toasts

However, verify that duration: Number.POSITIVE_INFINITY is intentional. This means error toasts will never auto-dismiss and require manual user action. This might be the desired behavior for errors, but consider whether some error types should auto-dismiss after a longer timeout.

src/features/player/components/PlayerLyrics.tsx (3)

169-190: LGTM! extraData pattern for lyric synchronization.

The module-level renderItem correctly uses extraData to pass currentLyricIndex and handleJumpToLyric to LyricLineItem. This ensures:

  • The renderItem function is not recreated on every render (performance win)
  • Lyric highlighting updates correctly when currentLyricIndex changes
  • Jump-to-lyric functionality remains accessible

10-10: LGTM! Error handling import updated to centralized module.

This aligns with the broader refactoring to consolidate error handling in a dedicated module, improving maintainability.


273-279: LGTM! extraData properly memoized for lyric rendering.

The extraData is memoized with the correct dependencies (currentLyricIndex, handleJumpToLyric), ensuring FlashList re-renders only when necessary.

src/features/playlist/local/components/LocalTrackList.tsx (3)

34-78: LGTM! Complex extraData correctly manages track list interactions.

The module-level renderItem properly uses extraData to pass all necessary handlers and state for track list functionality:

  • Selection mode state (selectMode, selected)
  • Event handlers (handleTrackPress, handleMenuPress, toggle, enterSelectMode)
  • Context data (playlist)

While the extraData object is large (7 properties), this is necessary for the rich interaction model of the track list. The implementation is correct.


121-140: LGTM! All dependencies properly included in extraData memoization.

The useMemo dependency array correctly includes all properties that make up the extraData object:

  • State: selectMode, selected
  • Callbacks: handleTrackPress, handleMenuPress, toggle, enterSelectMode
  • Data: playlist

This ensures the extraData object is only recreated when necessary, optimizing FlashList performance.


94-94: LGTM! Consistent haveTrack pattern for layout adjustments.

The haveTrack flag is used to adjust bottom padding (line 153), ensuring the track list doesn't get obscured by the mini player when a track is playing. This is consistent with other list components in this PR.

Comment thread src/components/common/FunctionalMenu.tsx
@roitium roitium merged commit fb9daaf into dev Nov 2, 2025
3 of 4 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 fix/many-things branch November 2, 2025 00:51
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