Skip to content

fix: incorrect sorting in recently added list#125

Open
gmcf111 wants to merge 3 commits intodddevid:masterfrom
gmcf111:fix/recently-added-sort
Open

fix: incorrect sorting in recently added list#125
gmcf111 wants to merge 3 commits intodddevid:masterfrom
gmcf111:fix/recently-added-sort

Conversation

@gmcf111
Copy link
Copy Markdown

@gmcf111 gmcf111 commented Apr 13, 2026

This PR fixes an issue with the sorting of the "recently added" list.

Changes
Corrected the sorting logic for recently added items
Ensured items are ordered properly by time
Improved accuracy and user experience when browsing recent additions
Background

Previously, the list could be incorrectly ordered in certain cases, causing newly added items to not appear in the expected position.

Also, a small request:
In a previous PR, the squash merge caused the contribution attribution to be lost.
If possible, could you please preserve the original commit authorship (e.g., using merge or rebase),
or include Co-authored-by when squashing, so the contribution can be properly credited?

Thanks a lot!

Summary by CodeRabbit

  • New Features

    • Songs now include creation date information for tracking when items were added to your library.
  • Improvements

    • "Recently Added" sorting now uses actual creation timestamps for more accurate ordering; items without a creation date are treated as older.
    • Library refresh process improved with safer error handling: partial failures during album loading preserve previous cache and avoid corrupt updates.
  • Tests

    • Added/updated tests to cover parsing and absence of song creation dates.

gmcf111 added 2 commits April 13, 2026 14:21
- Add DateTime? created field to Song model
- Parse 'created' from JSON response (Navidrome/Subsonic)
- Sort by created date (newest first) in Recently Added option
- Handle null created by placing at end of list
- Add unit test for created field parsing

This fixes the issue where 'Recently Added' was just reversing the
current list order instead of sorting by actual server-added date.
… list

- In _refreshAllDataInBackground(), now fetches all album songs and populates _cachedAllSongs
- Uses a Map to deduplicate songs by ID
- This fixes the 'No songs found' issue in AllSongsScreen
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 13, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 82360862-d7b5-47b4-a9bc-4dc88862631a

📥 Commits

Reviewing files that changed from the base of the PR and between beee0b1 and c59eb8f.

📒 Files selected for processing (1)
  • lib/providers/library_provider.dart

📝 Walkthrough

Walkthrough

Added a nullable created DateTime to Song with JSON (de)serialization and copyWith support; library refresh now aggregates and de-duplicates songs from per-album fetches and restores prior caches on failures; songs UI sorts by created with null-safe descending order; tests added for parsing and null handling.

Changes

Cohort / File(s) Summary
Song Model
lib/models/song.dart
Added final DateTime? created with constructor param, fromJson using DateTime.tryParse(...), toJson serializing created?.toIso8601String(), and copyWith propagation.
Library Caching
lib/providers/library_provider.dart
Refresh logic now builds a songById map from per-album song fetches to deduplicate songs, logs per-album fetch failures, and restores previous caches + notifies/returns early if any album fetch fails.
Song Sorting (UI)
lib/screens/all_songs_screen.dart
Replaced reverse-based ordering for recentlyAdded with explicit sort using created timestamps; treats null created as newer/after non-null appropriately.
Tests
test/models/song_test.dart
Extended tests: assert created is null when missing and added test parsing ISO8601 created string into DateTime (checks year/month/day).

Sequence Diagram(s)

mermaid
sequenceDiagram
participant UI as "AllSongsScreen (UI)"
participant Provider as "LibraryProvider"
participant AlbumAPI as "Album Service"
participant SongAPI as "Song Service"
participant Cache as "Local Cache"
UI->>Provider: request refresh
Provider->>AlbumAPI: fetch list of albums
AlbumAPI-->>Provider: return albums
loop for each album
Provider->>SongAPI: fetch songs for album
alt success
SongAPI-->>Provider: return songs
Provider->>Provider: add songs to songById map (dedupe)
else failure
SongAPI-->>Provider: error
Provider->>Provider: log failure, increment failure count
end
end
alt failures == 0
Provider->>Cache: save updated albums and songs
Provider->>UI: notifyListeners (updated data)
else failures > 0
Provider->>Cache: restore previous caches
Provider->>UI: notifyListeners (restored data)
end

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through code with gentle cheer,

Tucked timestamps where the songs appear,
Deduped the hops across each album bed,
Sorted newest notes above my head 🎵
Cache restored — I wink and steer.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing incorrect sorting in the recently added list by implementing proper timestamp-based sorting instead of list reversal.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Caution

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

⚠️ Outside diff range comments (1)
lib/providers/library_provider.dart (1)

305-320: ⚠️ Potential issue | 🟠 Major

Do not mark cache as fresh when album-song fetches partially fail.

When any album request fails (Line 311), the flow still sets _lastCacheUpdate (Line 317) and persists cache (Line 319). That can lock in a partial _cachedAllSongs snapshot and suppress refresh retries for ~6 hours.

🔧 Proposed fix
       _cachedAllAlbums = allAlbums;
       final Map<String, Song> songById = {};
+      int failedAlbumLoads = 0;
       for (final album in allAlbums) {
         try {
           final albumSongs = await _subsonicService.getAlbumSongs(album.id);
           for (final song in albumSongs) {
             songById[song.id] = song;
           }
         } catch (e) {
+          failedAlbumLoads++;
           debugPrint('Error loading album ${album.id}: $e');
         }
       }

       _cachedAllSongs = songById.values.toList();
-      _lastCacheUpdate = DateTime.now();
-
-      await _saveCachedData();
+      if (failedAlbumLoads == 0) {
+        _lastCacheUpdate = DateTime.now();
+        await _saveCachedData();
+      } else {
+        debugPrint(
+          'Background refresh incomplete: $failedAlbumLoads album(s) failed; skipping cache freshness update.',
+        );
+      }
       notifyListeners();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/providers/library_provider.dart` around lines 305 - 320, The current loop
over allAlbums swallows errors from _subsonicService.getAlbumSongs (inside the
try/catch) but still sets _cachedAllSongs, _lastCacheUpdate and calls
_saveCachedData, which can mark a partial snapshot as fresh; change the logic in
the for (final album in allAlbums) block (and its catch) to record when any
album fetch fails (e.g., a boolean partialFailure flag or collect failed IDs)
and only assign _cachedAllSongs, set _lastCacheUpdate, call _saveCachedData(),
and notifyListeners() if no failures occurred; if any failure happened, do not
persist or update the cache (instead log and optionally rethrow or return early)
so the cache isn’t marked fresh on partial data.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@lib/providers/library_provider.dart`:
- Around line 305-320: The current loop over allAlbums swallows errors from
_subsonicService.getAlbumSongs (inside the try/catch) but still sets
_cachedAllSongs, _lastCacheUpdate and calls _saveCachedData, which can mark a
partial snapshot as fresh; change the logic in the for (final album in
allAlbums) block (and its catch) to record when any album fetch fails (e.g., a
boolean partialFailure flag or collect failed IDs) and only assign
_cachedAllSongs, set _lastCacheUpdate, call _saveCachedData(), and
notifyListeners() if no failures occurred; if any failure happened, do not
persist or update the cache (instead log and optionally rethrow or return early)
so the cache isn’t marked fresh on partial data.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c9a73685-5d68-4ebb-be5b-f1c3c8a38132

📥 Commits

Reviewing files that changed from the base of the PR and between c5ba9af and beee0b1.

📒 Files selected for processing (4)
  • lib/models/song.dart
  • lib/providers/library_provider.dart
  • lib/screens/all_songs_screen.dart
  • test/models/song_test.dart

Keep the previous cached albums and songs when any album song fetch fails during background refresh. This prevents incomplete libraries from being marked fresh and suppressing retries for several hours.
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.

1 participant