mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 07:29:14 +01:00
ui: show plural artists in song subtitles and info dialog
This commit is contained in:
@@ -80,7 +80,7 @@ sealed interface MenuTarget {
|
|||||||
) : MenuTarget {
|
) : MenuTarget {
|
||||||
override val title: String get() = song.title
|
override val title: String get() = song.title
|
||||||
|
|
||||||
override val subtitle: String? get() = song.artist
|
override val subtitle: String? get() = song.artistSubtitle()
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Album(
|
data class Album(
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.subtracks.ui.components
|
||||||
|
|
||||||
|
import com.subtracks.data.model.Song
|
||||||
|
|
||||||
|
private const val ARTIST_SEPARATOR = " \u00B7 "
|
||||||
|
|
||||||
|
internal fun Song.artistSubtitle(): String? {
|
||||||
|
val names = artists.map { it.name }.filter { it.isNotBlank() }.distinct()
|
||||||
|
if (names.isEmpty()) return artist?.takeIf { it.isNotBlank() }
|
||||||
|
val primary = artist?.takeIf { it in names }
|
||||||
|
return buildList {
|
||||||
|
primary?.let(::add)
|
||||||
|
addAll(names.filterNot { it == primary })
|
||||||
|
}.joinToString(ARTIST_SEPARATOR)
|
||||||
|
}
|
||||||
@@ -54,7 +54,7 @@ fun SongInfoDialog(
|
|||||||
text = {
|
text = {
|
||||||
Column(verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
Column(verticalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
InfoRow(stringResource(R.string.resources_sort_by_title), song.title)
|
InfoRow(stringResource(R.string.resources_sort_by_title), song.title)
|
||||||
InfoRow(stringResource(R.string.resources_filter_artist), song.artist)
|
InfoRow(stringResource(R.string.resources_filter_artist), song.artistSubtitle())
|
||||||
InfoRow(stringResource(R.string.resources_filter_album), song.album)
|
InfoRow(stringResource(R.string.resources_filter_album), song.album)
|
||||||
InfoRow(stringResource(R.string.info_duration), song.duration?.let(DateUtils::formatElapsedTime))
|
InfoRow(stringResource(R.string.info_duration), song.duration?.let(DateUtils::formatElapsedTime))
|
||||||
InfoRow(
|
InfoRow(
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ import com.subtracks.data.model.DownloadStatus
|
|||||||
import com.subtracks.data.model.Song
|
import com.subtracks.data.model.Song
|
||||||
import com.subtracks.data.model.SongDownload
|
import com.subtracks.data.model.SongDownload
|
||||||
import com.subtracks.ui.components.CoverArt
|
import com.subtracks.ui.components.CoverArt
|
||||||
|
import com.subtracks.ui.components.artistSubtitle
|
||||||
|
|
||||||
private val TRACK_COLUMN_WIDTH = 24.dp
|
private val TRACK_COLUMN_WIDTH = 24.dp
|
||||||
private val TIME_COLUMN_WIDTH = 36.dp
|
private val TIME_COLUMN_WIDTH = 36.dp
|
||||||
@@ -146,7 +147,7 @@ fun SongRow(
|
|||||||
},
|
},
|
||||||
supportingContent = {
|
supportingContent = {
|
||||||
Text(
|
Text(
|
||||||
text = song.artist.orEmpty().ifEmpty { "\u00A0" },
|
text = song.artistSubtitle().orEmpty().ifEmpty { "\u00A0" },
|
||||||
color = if (isPlaying) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant,
|
color = if (isPlaying) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package com.subtracks.ui.components
|
||||||
|
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.compose.ui.test.assertIsDisplayed
|
||||||
|
import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule
|
||||||
|
import androidx.compose.ui.test.onNodeWithText
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import com.subtracks.data.model.ArtistRef
|
||||||
|
import com.subtracks.data.model.Song
|
||||||
|
import com.subtracks.ui.library.SongRow
|
||||||
|
import com.subtracks.ui.theme.SubtracksTheme
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.annotation.GraphicsMode
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@GraphicsMode(GraphicsMode.Mode.NATIVE)
|
||||||
|
class SongArtistDisplayTest {
|
||||||
|
@get:Rule
|
||||||
|
val composeRule = createAndroidComposeRule<ComponentActivity>()
|
||||||
|
|
||||||
|
private val song =
|
||||||
|
Song(
|
||||||
|
sourceId = 1,
|
||||||
|
id = "s1",
|
||||||
|
albumId = "al1",
|
||||||
|
artistId = "ar2",
|
||||||
|
title = "Song",
|
||||||
|
album = "Album",
|
||||||
|
artist = "Two",
|
||||||
|
duration = 100,
|
||||||
|
track = 1,
|
||||||
|
disc = 1,
|
||||||
|
starred = null,
|
||||||
|
artists = listOf(ArtistRef("ar1", "One"), ArtistRef("ar2", "Two"), ArtistRef("ar3", "Three")),
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun aSongRowListsThePluralArtistsWithTheSingularArtistFirst() {
|
||||||
|
composeRule.setContent {
|
||||||
|
SubtracksTheme {
|
||||||
|
SongRow(song = song)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
composeRule.onNodeWithText("Two · One · Three").assertIsDisplayed()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun theInfoDialogListsThePluralArtistsWithTheSingularArtistFirst() {
|
||||||
|
composeRule.setContent {
|
||||||
|
SubtracksTheme {
|
||||||
|
SongInfoDialog(
|
||||||
|
song = song,
|
||||||
|
download = null,
|
||||||
|
localFile = null,
|
||||||
|
streamEncoding = null,
|
||||||
|
onDismiss = {},
|
||||||
|
genres = emptyList(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
composeRule.onNodeWithText("Two · One · Three").assertIsDisplayed()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package com.subtracks.ui.library
|
||||||
|
|
||||||
|
import com.subtracks.data.model.ArtistRef
|
||||||
|
import com.subtracks.data.model.Song
|
||||||
|
import com.subtracks.ui.components.artistSubtitle
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNull
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class SongArtistSubtitleTest {
|
||||||
|
@Test
|
||||||
|
fun pluralArtistsAreJoinedWithDots() {
|
||||||
|
assertEquals("One · Two", song(artist = null, artists = listOf(ArtistRef("1", "One"), ArtistRef("2", "Two"))).artistSubtitle())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun singularArtistIsListedFirstWhenItIsAlsoPlural() {
|
||||||
|
assertEquals(
|
||||||
|
"Two · One · Three",
|
||||||
|
song(artist = "Two", artists = listOf(ArtistRef("1", "One"), ArtistRef("2", "Two"), ArtistRef("3", "Three")))
|
||||||
|
.artistSubtitle(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun singularArtistIsUsedWhenNoPluralArtistsExist() {
|
||||||
|
assertEquals("One", song(artist = "One", artists = emptyList()).artistSubtitle())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun noArtistGivesNoSubtitle() {
|
||||||
|
assertNull(song(artist = null, artists = emptyList()).artistSubtitle())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun song(
|
||||||
|
artist: String?,
|
||||||
|
artists: List<ArtistRef>,
|
||||||
|
) = Song(
|
||||||
|
sourceId = 1,
|
||||||
|
id = "s1",
|
||||||
|
albumId = "al1",
|
||||||
|
artistId = "ar1",
|
||||||
|
title = "Song",
|
||||||
|
album = "Album",
|
||||||
|
artist = artist,
|
||||||
|
duration = 100,
|
||||||
|
track = 1,
|
||||||
|
disc = 1,
|
||||||
|
starred = null,
|
||||||
|
artists = artists,
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user