From b9e16d8377a5274ad8bd549f0e3ac85dc286be2c Mon Sep 17 00:00:00 2001 From: austinried <4966622+austinried@users.noreply.github.com> Date: Sun, 27 Sep 2026 07:29:16 +0000 Subject: [PATCH] put the download indicator on the artist line, tight to its left The glyph and the progress ring sat in the title row after the star, spaced 8dp; they now lead the subtitle row, 4dp from the artist name, which is where the artist line has room for them. `theDownloadedIndicatorSitsOnTheArtistLineToItsLeft` measures the unmerged bounds and fails if the indicator moves back up to the title line or to the artist's right. --- .../com/subtracks/ui/library/SongsContent.kt | 19 ++++++++++++------- .../ui/library/SongRowDownloadTest.kt | 15 +++++++++++++++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/app/src/main/kotlin/com/subtracks/ui/library/SongsContent.kt b/app/src/main/kotlin/com/subtracks/ui/library/SongsContent.kt index 854b78c1..da42156e 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/SongsContent.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/SongsContent.kt @@ -89,16 +89,21 @@ fun SongRow( modifier = Modifier.weight(1f, fill = false), ) StarredBadge(song.starred != null) - DownloadBadge(download) } }, supportingContent = { - Text( - text = song.artist.orEmpty().ifEmpty { "\u00A0" }, - color = if (isPlaying) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(4.dp), + ) { + DownloadBadge(download) + Text( + text = song.artist.orEmpty().ifEmpty { "\u00A0" }, + color = if (isPlaying) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } }, colors = ListItemDefaults.colors(containerColor = Color.Transparent), ) diff --git a/app/src/test/kotlin/com/subtracks/ui/library/SongRowDownloadTest.kt b/app/src/test/kotlin/com/subtracks/ui/library/SongRowDownloadTest.kt index cfb9eed0..fe9ca45b 100644 --- a/app/src/test/kotlin/com/subtracks/ui/library/SongRowDownloadTest.kt +++ b/app/src/test/kotlin/com/subtracks/ui/library/SongRowDownloadTest.kt @@ -5,15 +5,18 @@ import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 import com.subtracks.data.model.DownloadStatus import com.subtracks.data.model.Song import com.subtracks.data.model.SongDownload import com.subtracks.ui.theme.SubtracksTheme +import org.junit.Assert.assertTrue import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.robolectric.annotation.GraphicsMode +import kotlin.math.abs @RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) @@ -60,6 +63,18 @@ class SongRowDownloadTest { composeRule.onNodeWithContentDescription("Downloaded").assertDoesNotExist() } + @Test + fun theDownloadedIndicatorSitsOnTheArtistLineToItsLeft() { + render(download(DownloadStatus.Completed)) + + val badge = composeRule.onNodeWithContentDescription("Downloaded", useUnmergedTree = true).fetchSemanticsNode().boundsInRoot + val artist = composeRule.onNodeWithText("Artist", useUnmergedTree = true).fetchSemanticsNode().boundsInRoot + + assertTrue("expected the indicator left of the artist name, badge=$badge artist=$artist", badge.right <= artist.left) + val offBy = abs(badge.center.y - artist.center.y) + assertTrue("expected the indicator on the artist's line, off by ${offBy}px", offBy <= with(composeRule.density) { 2.dp.toPx() }) + } + private fun download(status: DownloadStatus) = SongDownload(sourceId = 1, songId = "s1", status = status, engineId = 7, bytes = 40, total = 100)