mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-15 00:42:54 +01:00
ui: show and expand the artist biography
Load the biography when the artist page is entered. A stored biography is rendered immediately while it refreshes in the background; otherwise the page starts with the loading message and falls back to the empty state. Collapse a biography to two lines and append a bold More only when the text does not fit. Tapping that line expands the biography, after which the first lines keep clear of the star and overflow buttons and the rest use the full width.
This commit is contained in:
@@ -303,6 +303,25 @@ class AppScreenshotTest {
|
||||
|
||||
@Test
|
||||
fun artistDetail() {
|
||||
renderArtistDetail(bioExpanded = false)
|
||||
awaitText("Kid A")
|
||||
composeRule.waitUntil(timeoutMillis = 5_000) {
|
||||
composeRule.onAllNodesWithTag(ARTIST_NAME_SCRIM_TAG).fetchSemanticsNodes().isNotEmpty()
|
||||
}
|
||||
composeRule.onRoot().captureRoboImage("src/test/screenshots/artist_detail.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun artistDetailExpandedBio() {
|
||||
renderArtistDetail(bioExpanded = true)
|
||||
awaitText("Kid A")
|
||||
composeRule.waitUntil(timeoutMillis = 5_000) {
|
||||
composeRule.onAllNodesWithTag(ARTIST_NAME_SCRIM_TAG).fetchSemanticsNodes().isNotEmpty()
|
||||
}
|
||||
composeRule.onRoot().captureRoboImage("src/test/screenshots/artist_detail_bio_expanded.png")
|
||||
}
|
||||
|
||||
private fun renderArtistDetail(bioExpanded: Boolean) {
|
||||
composeRule.setContent {
|
||||
SubtracksTheme {
|
||||
ArtistDetailScreen(
|
||||
@@ -311,6 +330,11 @@ class AppScreenshotTest {
|
||||
ArtistAlbums(
|
||||
albumCredits = Fixtures.albums.filter { it.artistId == Fixtures.artists.first().id },
|
||||
),
|
||||
bio =
|
||||
"Radiohead are an English rock band formed in Abingdon, Oxfordshire, in 1985. " +
|
||||
"The band consists of Thom Yorke, Jonny Greenwood, Colin Greenwood, Ed O'Brien, " +
|
||||
"and Philip Selway.",
|
||||
bioExpanded = bioExpanded,
|
||||
art = CoverArtRef("art-ar-radiohead", "test:art-ar-radiohead"),
|
||||
artwork = artworkColorsFromSeed(Color.rgb(120, 80, 200)),
|
||||
coverArt = { id, _ -> id?.let { CoverArtRef(it, "test:$it") } },
|
||||
@@ -320,11 +344,6 @@ class AppScreenshotTest {
|
||||
)
|
||||
}
|
||||
}
|
||||
awaitText("Kid A")
|
||||
composeRule.waitUntil(timeoutMillis = 5_000) {
|
||||
composeRule.onAllNodesWithTag(ARTIST_NAME_SCRIM_TAG).fetchSemanticsNodes().isNotEmpty()
|
||||
}
|
||||
composeRule.onRoot().captureRoboImage("src/test/screenshots/artist_detail.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package com.subtracks.ui.library
|
||||
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.test.assertCountEquals
|
||||
import androidx.compose.ui.test.hasScrollAction
|
||||
import androidx.compose.ui.test.hasText
|
||||
@@ -8,13 +12,20 @@ import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule
|
||||
import androidx.compose.ui.test.onAllNodesWithContentDescription
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import androidx.compose.ui.test.performScrollToNode
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.rememberTextMeasurer
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.subtracks.data.model.Album
|
||||
import com.subtracks.data.model.Artist
|
||||
import com.subtracks.data.model.ArtistAlbums
|
||||
import com.subtracks.ui.theme.SubtracksTheme
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
@@ -31,18 +42,25 @@ class ArtistDetailScreenTest {
|
||||
artistName: String,
|
||||
albums: ArtistAlbums = ArtistAlbums(),
|
||||
albumsLoaded: Boolean = true,
|
||||
bio: String? = null,
|
||||
bioLoading: Boolean = false,
|
||||
) {
|
||||
composeRule.setContent {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
SubtracksTheme {
|
||||
ArtistDetailScreen(
|
||||
artist = artist,
|
||||
artistName = artistName,
|
||||
albums = albums,
|
||||
albumsLoaded = albumsLoaded,
|
||||
bio = bio,
|
||||
bioLoading = bioLoading,
|
||||
bioExpanded = expanded,
|
||||
art = null,
|
||||
coverArt = { _, _ -> null },
|
||||
onBack = {},
|
||||
onAlbumClick = {},
|
||||
onExpandBio = { expanded = true },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -108,6 +126,98 @@ class ArtistDetailScreenTest {
|
||||
composeRule.onNodeWithText("Album artist · 0 albums").assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aStoredBioShowsImmediatelyEvenWhileItRefreshes() {
|
||||
render(
|
||||
artist = Artist(sourceId = 1, id = "ar-1", name = "Radiohead", albumCount = 1, starred = null),
|
||||
artistName = "Radiohead",
|
||||
bio = "A stored biography.",
|
||||
bioLoading = true,
|
||||
)
|
||||
|
||||
composeRule.onNodeWithText("A stored biography.").assertExists()
|
||||
composeRule.onNodeWithText("Loading artist bio…").assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aMissingBioShowsTheLoadingStateFirst() {
|
||||
render(
|
||||
artist = Artist(sourceId = 1, id = "ar-1", name = "Radiohead", albumCount = 1, starred = null),
|
||||
artistName = "Radiohead",
|
||||
bioLoading = true,
|
||||
)
|
||||
|
||||
composeRule.onNodeWithText("Loading artist bio…").assertExists()
|
||||
composeRule.onNodeWithText("No artist bio available.").assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aMissingBioShowsTheEmptyStateAfterTheRefresh() {
|
||||
render(
|
||||
artist = Artist(sourceId = 1, id = "ar-1", name = "Radiohead", albumCount = 1, starred = null),
|
||||
artistName = "Radiohead",
|
||||
)
|
||||
|
||||
composeRule.onNodeWithText("No artist bio available.").assertExists()
|
||||
composeRule.onNodeWithText("Loading artist bio…").assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aShortBioDoesNotOfferMore() {
|
||||
render(
|
||||
artist = Artist(sourceId = 1, id = "ar-1", name = "Radiohead", albumCount = 1, starred = null),
|
||||
artistName = "Radiohead",
|
||||
bio = "A short biography.",
|
||||
)
|
||||
|
||||
composeRule.onNodeWithTag(ARTIST_BIO_MORE_TAG).assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aLongBioExpandsWhenMoreIsTapped() {
|
||||
render(
|
||||
artist = Artist(sourceId = 1, id = "ar-1", name = "Radiohead", albumCount = 1, starred = null),
|
||||
artistName = "Radiohead",
|
||||
bio =
|
||||
"Radiohead are an English rock band formed in Abingdon, Oxfordshire, in 1985. " +
|
||||
"The band consists of Thom Yorke, Jonny Greenwood, Colin Greenwood, Ed O'Brien, " +
|
||||
"and Philip Selway.",
|
||||
)
|
||||
|
||||
composeRule.onNodeWithTag(ARTIST_BIO_MORE_TAG).performScrollTo().assertExists()
|
||||
|
||||
composeRule.onNodeWithTag(ARTIST_BIO_MORE_TAG).performClick()
|
||||
|
||||
composeRule.onNodeWithTag(ARTIST_BIO_MORE_TAG).assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun theCollapsedSecondLineContinuesWhereTheFirstLineEnds() {
|
||||
val bio =
|
||||
"Radiohead are an English rock band formed in Abingdon, Oxfordshire, in 1985. " +
|
||||
"The band consists of Thom Yorke, Jonny Greenwood, Colin Greenwood, Ed O'Brien, " +
|
||||
"and Philip Selway."
|
||||
var result: BioLines? = null
|
||||
composeRule.setContent {
|
||||
val measurer = rememberTextMeasurer()
|
||||
result = splitBioCollapsed(measurer, bio, TextStyle(fontSize = 14.sp), 400, 0, "More")
|
||||
}
|
||||
composeRule.waitForIdle()
|
||||
|
||||
val lines = requireNotNull(result)
|
||||
assertTrue(lines.more)
|
||||
val firstWords =
|
||||
lines.lines[0]
|
||||
.text
|
||||
.split(' ')
|
||||
.filter { it.isNotEmpty() }
|
||||
val next = bio.split(' ').filter { it.isNotEmpty() }[firstWords.size]
|
||||
assertTrue(
|
||||
"expected the second line to continue with $next, was ${lines.lines[1].text}",
|
||||
lines.lines[1].text.startsWith(next),
|
||||
)
|
||||
}
|
||||
|
||||
private fun album(
|
||||
id: String,
|
||||
name: String,
|
||||
|
||||
Reference in New Issue
Block a user