diff --git a/lib/services/plex_client.dart b/lib/services/plex_client.dart index 675ae0a6..358160ff 100644 --- a/lib/services/plex_client.dart +++ b/lib/services/plex_client.dart @@ -1791,16 +1791,18 @@ class PlexClient /// Append sort options that Plex honors via the `sort=` parameter but does not /// advertise in `/library/sections/{id}/sorts`. /// - /// Plays (`viewCount`) and the signed-in user's rating (`userRating`) both - /// sort correctly on movie/show libraries, so we surface them client-side - /// (mirroring how the Jellyfin sort list is built). De-duped by key so we - /// never double up if a future Plex version starts advertising them. + /// Date Added (`addedAt`), plays (`viewCount`), and the signed-in user's + /// rating (`userRating`) sort correctly on movie/show libraries, so we + /// surface them client-side (mirroring how the Jellyfin sort list is built). + /// De-duped by key so we never double up if a future Plex version starts + /// advertising them. List _withExtraSorts(List base, String? libraryType) { final type = libraryType?.toLowerCase(); if (type != 'movie' && type != 'show') return base; final keys = base.map((s) => s.key).toSet(); final extras = [ + _dateAddedSort(), MediaSort( key: 'viewCount', descKey: 'viewCount:desc', @@ -1818,18 +1820,22 @@ class PlexClient return [...base, ...extras]; } + MediaSort _dateAddedSort() { + return MediaSort( + key: 'addedAt', + descKey: 'addedAt:desc', + title: t.libraries.sortLabels.dateAdded, + defaultDirection: 'desc', + ); + } + /// Build fallback sort options based on library type. /// /// If [libraryType] is null, returns generic sorts without the show-specific options. List _getFallbackSorts(String? libraryType) { final fallbackSorts = [ MediaSort(key: 'titleSort', title: t.libraries.sortLabels.title, defaultDirection: 'asc'), - MediaSort( - key: 'addedAt', - descKey: 'addedAt:desc', - title: t.libraries.sortLabels.dateAdded, - defaultDirection: 'desc', - ), + _dateAddedSort(), ]; // Add "Latest Episode Air Date" only for TV show libraries diff --git a/test/services/plex_library_details_test.dart b/test/services/plex_library_details_test.dart index 631ed673..caa7a2dd 100644 --- a/test/services/plex_library_details_test.dart +++ b/test/services/plex_library_details_test.dart @@ -77,7 +77,7 @@ void main() { ]); }); - test('appends Plays and User Rating sorts only for movie/show libraries', () async { + test('appends Date Added, Plays, and User Rating sorts only for movie/show libraries', () async { PlexClient clientReturning() => makeClient((request) async { if (request.url.path == '/library/sections/1/sorts') { return http.Response( @@ -99,7 +99,11 @@ void main() { final client = clientReturning(); addTearDown(client.close); final sorts = await client.fetchSortOptions('1', libraryType: type); - expect(sorts.map((s) => s.key), ['titleSort', 'viewCount', 'userRating'], reason: type); + expect(sorts.map((s) => s.key), ['titleSort', 'addedAt', 'viewCount', 'userRating'], reason: type); + + final dateAdded = sorts.singleWhere((s) => s.key == 'addedAt'); + expect(dateAdded.descKey, 'addedAt:desc', reason: type); + expect(dateAdded.defaultDirection, 'desc', reason: type); } // Other library types (e.g. music) are left as the server returned them. @@ -109,7 +113,7 @@ void main() { expect(musicSorts.map((s) => s.key), ['titleSort']); }); - test('does not duplicate Plays/User Rating when the server already advertises them', () async { + test('does not duplicate Date Added/Plays when the server already advertises them', () async { final client = makeClient((request) async { if (request.url.path == '/library/sections/1/sorts') { return http.Response( @@ -117,6 +121,7 @@ void main() { 'MediaContainer': { 'Directory': [ {'key': 'titleSort', 'title': 'Title', 'defaultDirection': 'asc'}, + {'key': 'addedAt', 'title': 'Date Added', 'defaultDirection': 'desc'}, {'key': 'viewCount', 'title': 'Plays', 'defaultDirection': 'desc'}, ], }, @@ -130,8 +135,8 @@ void main() { addTearDown(client.close); final sorts = await client.fetchSortOptions('1', libraryType: 'movie'); - // viewCount already advertised -> not duplicated; userRating still appended. - expect(sorts.map((s) => s.key), ['titleSort', 'viewCount', 'userRating']); + // addedAt/viewCount already advertised -> not duplicated; userRating still appended. + expect(sorts.map((s) => s.key), ['titleSort', 'addedAt', 'viewCount', 'userRating']); }); test('library content stamps known section when Plex omits librarySectionID on rows', () async {