Fix/ux round 2 - #3
Merged
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR refines UX and correctness around library/stats by (a) making “unknown” artist/album metadata consistently representable and localizable without persisting translated phantom rows, (b) extracting listen-cycle bookkeeping into a unit-tested helper to address repeat-one/restart edge cases, and (c) adding targeted performance instrumentation and defensive tab-level error boundaries.
Changes:
- Group missing artist/album under a reserved rollup/entity id (0) and propagate “Unknown artist/album” labels through stats + library UI.
- Introduce
ListenCycle(with tests) and integrate it intoAudioEngineto make listen banking/restarts testable and less stateful. - Reduce library row-press latency by precomputing the playable queue + id→index map; add perf timing hooks and tab error boundaries.
Reviewed changes
Copilot reviewed 45 out of 46 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/services/stats/rollups.ts | Introduces UNKNOWN_ENTITY_ID and assigns null artist/album to the reserved rollup id. |
| src/services/stats/rollups.test.ts | Updates rollup-delta expectations to cover unknown artist/album grouping. |
| src/services/stats/listenCycle.ts | Adds a unit-testable listen lifecycle accumulator/banker. |
| src/services/stats/listenCycle.test.ts | Tests pause/playing accumulation and repeat-one restart semantics. |
| src/services/scanner/trackMapping.ts | Ensures enriched tag fields include nullable artist/album/albumArtist consistently. |
| src/services/scanner/trackMapping.test.ts | Verifies missing collection tags remain null for fallback grouping. |
| src/services/perf/index.ts | Uses a monotonic clock when available; improves measurement precision formatting. |
| src/services/audio/AudioEngine.ts | Replaces ad-hoc listen timing with ListenCycle integration. |
| src/i18n/locales/tr.json | Adds common strings for unknown artist/album and generic error/retry labels. |
| src/i18n/locales/en.json | Adds common strings for unknown artist/album and generic error/retry labels. |
| src/features/stats/StatsScreen.tsx | Passes unknown labels into stats UI components for reserved rows. |
| src/features/stats/components/Wrapped.tsx | Displays unknown fallback text when top entries have no title. |
| src/features/stats/components/TopList.tsx | Supports per-list unknown-title fallback for reserved rows. |
| src/features/playlists/components/PlaylistEntryRow.tsx | Uses localized unknown artist/album fallbacks in subtitles. |
| src/features/playlists/components/AddTracksSheet.tsx | Memoizes pick rows; removes inline handlers; uses unknown fallbacks. |
| src/features/player/PlayerScreen.tsx | Switches to common unknown-artist i18n key. |
| src/features/player/components/QueueRow.tsx | Uses localized unknown artist/album fallbacks in subtitles. |
| src/features/player/components/MiniPlayer.tsx | Adds perf measure hook; tweaks pan activation; adds Android ripples; shows unknown artist. |
| src/features/library/LibraryTracks.tsx | Precomputes playable queue + id→index map; adds perf marks/measures for row press. |
| src/features/library/LibraryScreen.tsx | Fixes displayed count for artist/album views; threads kind to grids. |
| src/features/library/components/TrackRow.tsx | Uses unknown fallbacks and adds Android ripple. |
| src/features/library/components/TrackInfoSheet.tsx | Displays localized unknown artist/album rather than a dash for nulls. |
| src/features/library/components/TrackActionSheet.tsx | Shows localized unknown artist/album in sheet subtitle. |
| src/features/library/components/LibraryHeader.tsx | Adds Android ripple feedback to header actions. |
| src/features/library/components/CollectionHeader.tsx | Renders unknown artist/album titles/subtitles based on flags; stabilizes recyclingKey. |
| src/features/library/components/CollectionGrid.tsx | Threads kind so cards can label unknown rows correctly. |
| src/features/library/components/CollectionCard.tsx | Renders localized unknown names/subtitles; adds Android ripple; updates memo comparator. |
| src/features/library/CollectionDetailScreen.tsx | Passes unknown flags through to the collection header. |
| src/db/seed.ts | Clears dependent tables transactionally so seeded tracks can be removed safely. |
| src/db/queries/tracks.ts | Groups null artist/album into id 0 cards; supports browsing unknown collections via isNull. |
| src/db/queries/stats.ts | Left-joins artists/albums so reserved entityId=0 (and missing refs) can render with fallbacks. |
| src/components/ui/TabErrorBoundary.tsx | Adds a tab-scoped error boundary with retry UI. |
| src/components/ui/SegmentedControl.tsx | Adds Android ripple feedback for segmented options. |
| docs/stats.md | Documents reserved rollup id 0 and left-join rendering strategy. |
| docs/scanner.md | Documents how ARTIST/ALBUM/ALBUMARTIST resolve normalized foreign keys. |
| docs/performance.md | Documents measured row-press latency improvements and updated test counts. |
| docs/components.md | Documents TabErrorBoundary and updates MiniPlayer behavior notes. |
| docs/adr/013-unknown-metadata.md | Adds ADR describing “unknown metadata stays null” + reserved rollup id approach. |
| docs/adr/012-artist-and-album-shelves.md | Updates ADR to reflect track-first grouping and unknown-card behavior. |
| app/(tabs)/stats.tsx | Wraps stats tab route with TabErrorBoundary. |
| app/(tabs)/settings.tsx | Wraps settings tab route with TabErrorBoundary. |
| app/(tabs)/playlists.tsx | Wraps playlists tab route with TabErrorBoundary. |
| app/(tabs)/index.tsx | Wraps library tab route with TabErrorBoundary. |
| app/(tabs)/_layout.tsx | Adds perf timing hooks for tab press→focus. |
| .gitattributes | Marks a historical diff-repair path as reviewable. |
Suppressed comments (1)
src/services/audio/AudioEngine.ts:438
repeat === 'one'can finish a track without callingloadIndex(it seeks to 0). In that pathdidJustFinishcloses the listen viaflushListen(true)but never opens the next cycle, so subsequent loops won’t be banked (the regression described inListenCycle). Open the next cycle whendidJustFinishfires in repeat-one mode.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+16
to
+18
| /** Keeps a render failure inside one tab instead of taking down the whole app. */ | ||
| // React render error boundaries require a class component. | ||
| export class TabErrorBoundary extends Component<TabErrorBoundaryProps, TabErrorBoundaryState> { |
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.
No description provided.