diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/model/BaseItem.kt b/app/src/main/java/com/github/damontecres/wholphin/data/model/BaseItem.kt index 5ca6bf95..50df6071 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/data/model/BaseItem.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/data/model/BaseItem.kt @@ -54,7 +54,7 @@ data class BaseItem( get() = type.playable override val sortName: String - get() = data.sortName ?: data.name ?: "" + get() = data.alphabetSortName val type get() = data.type @@ -305,6 +305,9 @@ data class BaseItem( val BaseItemDto.aspectRatioFloat: Float? get() = width?.let { w -> height?.let { h -> w.toFloat() / h.toFloat() } } +/** The server strips leading articles (eg "The ") from [BaseItemDto.sortName]. */ +val BaseItemDto.alphabetSortName: String get() = sortName ?: name ?: "" + @Immutable data class BaseItemUi( val episodeCornerText: String?, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderView.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderView.kt index e64115aa..1a7992d5 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderView.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderView.kt @@ -399,6 +399,7 @@ class CollectionFolderViewModel GetArtistsRequest( parentId = item?.id, enableImageTypes = listOf(ImageType.PRIMARY, ImageType.THUMB), + fields = SlimItemFields, ), ) } @@ -477,6 +478,7 @@ class CollectionFolderViewModel GetArtistsHandler.countMatching( createGetArtistsRequest(filter).copy( enableImageTypes = null, + fields = null, nameLessThan = letter.toString(), limit = 0, enableTotalRecordCount = true, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/GenreCardGrid.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/GenreCardGrid.kt index 00dfbb56..aeae3fd7 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/GenreCardGrid.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/GenreCardGrid.kt @@ -20,6 +20,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.model.BaseItem +import com.github.damontecres.wholphin.data.model.alphabetSortName import com.github.damontecres.wholphin.data.model.createGenreDestination import com.github.damontecres.wholphin.services.ImageUrlService import com.github.damontecres.wholphin.services.NavigationManager @@ -104,7 +105,12 @@ class GenreViewModel .execute(api, request) .content.items .map { - Genre(it.id, it.name ?: "", null) + Genre( + id = it.id, + name = it.name ?: "", + imageUrl = null, + sortName = it.alphabetSortName, + ) } _state.update { it.copy( @@ -243,10 +249,10 @@ data class Genre( val id: UUID, val name: String, val imageUrl: String?, + override val sortName: String = name, ) : CardGridItem { override val gridId: String get() = id.toString() override val playable: Boolean = false - override val sortName: String get() = name } /** diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/StudioCardGrid.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/StudioCardGrid.kt index 3f424bad..461d1d94 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/StudioCardGrid.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/StudioCardGrid.kt @@ -20,6 +20,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.model.BaseItem +import com.github.damontecres.wholphin.data.model.alphabetSortName import com.github.damontecres.wholphin.data.model.createStudioDestination import com.github.damontecres.wholphin.services.ImageUrlService import com.github.damontecres.wholphin.services.NavigationManager @@ -97,7 +98,12 @@ class StudioViewModel imageType = ImageType.THUMB, fillWidth = cardWidthPx, ) - Studio(it.id, it.name ?: "", imageUrl) + Studio( + id = it.id, + name = it.name ?: "", + imageUrl = imageUrl, + sortName = it.alphabetSortName, + ) } _state.update { it.copy( @@ -133,10 +139,10 @@ data class Studio( val id: UUID, val name: String, val imageUrl: String?, + override val sortName: String = name, ) : CardGridItem { override val gridId: String get() = id.toString() override val playable: Boolean = false - override val sortName: String get() = name } data class StudioGridState( diff --git a/app/src/test/java/com/github/damontecres/wholphin/data/model/AlphabetSortNameTest.kt b/app/src/test/java/com/github/damontecres/wholphin/data/model/AlphabetSortNameTest.kt new file mode 100644 index 00000000..0b18cc8e --- /dev/null +++ b/app/src/test/java/com/github/damontecres/wholphin/data/model/AlphabetSortNameTest.kt @@ -0,0 +1,36 @@ +package com.github.damontecres.wholphin.data.model + +import org.jellyfin.sdk.model.api.BaseItemDto +import org.jellyfin.sdk.model.api.BaseItemKind +import org.junit.Assert.assertEquals +import org.junit.Test +import java.util.UUID + +class AlphabetSortNameTest { + @Test + fun prefersSortNameOverName() { + val dto = + BaseItemDto( + id = UUID.randomUUID(), + type = BaseItemKind.MUSIC_ARTIST, + name = "The Beatles", + sortName = "beatles", + ) + + assertEquals("beatles", dto.alphabetSortName) + assertEquals("beatles", BaseItem(dto).sortName) + } + + @Test + fun fallsBackToNameWhenSortNameMissing() { + val dto = + BaseItemDto( + id = UUID.randomUUID(), + type = BaseItemKind.STUDIO, + name = "The Walt Disney Company", + sortName = null, + ) + + assertEquals("The Walt Disney Company", dto.alphabetSortName) + } +} diff --git a/app/src/test/java/com/github/damontecres/wholphin/ui/components/CollectionFolderViewModelTest.kt b/app/src/test/java/com/github/damontecres/wholphin/ui/components/CollectionFolderViewModelTest.kt index 2d10f1a3..978cd70c 100644 --- a/app/src/test/java/com/github/damontecres/wholphin/ui/components/CollectionFolderViewModelTest.kt +++ b/app/src/test/java/com/github/damontecres/wholphin/ui/components/CollectionFolderViewModelTest.kt @@ -33,10 +33,12 @@ import org.jellyfin.sdk.api.operations.UserLibraryApi import org.jellyfin.sdk.model.api.BaseItemDto import org.jellyfin.sdk.model.api.BaseItemKind import org.jellyfin.sdk.model.api.CollectionType +import org.jellyfin.sdk.model.api.ItemFields import org.jellyfin.sdk.model.api.request.GetArtistsRequest import org.jellyfin.sdk.model.api.request.GetItemsRequest import org.junit.After import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import java.util.UUID @@ -141,6 +143,19 @@ class CollectionFolderViewModelTest { coVerify(exactly = 0) { GetItemsRequestHandler.execute(any(), any()) } } + /** + * Without SortName, the alphabet highlight falls back to Name and highlights "T" for artists + * like "The Beatles" even though the grid sorts them under "B". + */ + @Test + fun `artist pager requests SortName for alphabet highlighting`() = + runTest(testDispatcher) { + createViewModel(GetItemsFilter(override = GetItemsFilterOverride.ARTIST)) + advanceUntilIdle() + + assertTrue(ItemFields.SORT_NAME in artistsRequest.captured.fields.orEmpty()) + } + /** * /Persons has no nameLessThan or startIndex, so counting up to a letter is not expressible. * Falling back to /Items would count media rather than people, ie the same defect as the artist