mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 07:29:14 +01:00
ui: drop bio justification and normalize cached biographies
Read normalization heals biographies cached before line breaks were preserved, without waiting for a refresh.
This commit is contained in:
@@ -35,6 +35,7 @@ import kotlinx.coroutines.SupervisorJob
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
@@ -360,7 +361,11 @@ class LibraryRepository(
|
|||||||
fun artistBio(
|
fun artistBio(
|
||||||
sourceId: Long,
|
sourceId: Long,
|
||||||
artistId: String,
|
artistId: String,
|
||||||
): Flow<ArtistBio?> = db.libraryDao().artistBio(sourceId, artistId)
|
): Flow<ArtistBio?> =
|
||||||
|
db
|
||||||
|
.libraryDao()
|
||||||
|
.artistBio(sourceId, artistId)
|
||||||
|
.map { bio -> bio?.copy(biography = normalizeBiography(bio.biography)) }
|
||||||
|
|
||||||
suspend fun refreshArtistBio(
|
suspend fun refreshArtistBio(
|
||||||
sourceId: Long,
|
sourceId: Long,
|
||||||
|
|||||||
@@ -605,16 +605,8 @@ private fun ArtistBio(
|
|||||||
Column(Modifier.fillMaxWidth()) {
|
Column(Modifier.fillMaxWidth()) {
|
||||||
bioLines.lines.forEachIndexed { index, line ->
|
bioLines.lines.forEachIndexed { index, line ->
|
||||||
val isControl = index == bioLines.lines.lastIndex && (bioLines.more || bioLines.less)
|
val isControl = index == bioLines.lines.lastIndex && (bioLines.more || bioLines.less)
|
||||||
val nextBlank = index == bioLines.lines.lastIndex || bioLines.lines[index + 1].text.isBlank()
|
|
||||||
val available = bioLineWidth(index, fullWidth, reserve, reserveLines)
|
|
||||||
val displayLine =
|
|
||||||
if (!nextBlank && line.text.isNotBlank() && line.spanStyles.isEmpty()) {
|
|
||||||
justifyBioLine(line, measurer, style, available)
|
|
||||||
} else {
|
|
||||||
line
|
|
||||||
}
|
|
||||||
Text(
|
Text(
|
||||||
text = displayLine,
|
text = line,
|
||||||
style = style,
|
style = style,
|
||||||
color = color,
|
color = color,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
@@ -737,35 +729,6 @@ private fun appendBioControl(
|
|||||||
lines += control
|
lines += control
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun justifyBioLine(
|
|
||||||
line: AnnotatedString,
|
|
||||||
measurer: TextMeasurer,
|
|
||||||
style: TextStyle,
|
|
||||||
available: Int,
|
|
||||||
): AnnotatedString {
|
|
||||||
if (line.spanStyles.isNotEmpty()) return line
|
|
||||||
val parts = line.text.split(' ')
|
|
||||||
if (parts.size < 2) return line
|
|
||||||
val spaceWidth = measurer.measure(AnnotatedString(" "), style, maxLines = 1).size.width
|
|
||||||
if (spaceWidth <= 0) return line
|
|
||||||
val extra = available - measurer.measure(line, style, maxLines = 1).size.width
|
|
||||||
val spaces = extra / spaceWidth
|
|
||||||
if (spaces <= 0) return line
|
|
||||||
val gaps = parts.size - 1
|
|
||||||
val perGap = spaces / gaps
|
|
||||||
val remainder = spaces % gaps
|
|
||||||
return AnnotatedString(
|
|
||||||
buildString {
|
|
||||||
parts.forEachIndexed { index, part ->
|
|
||||||
append(part)
|
|
||||||
if (index < gaps) {
|
|
||||||
repeat(1 + perGap + if (index < remainder) 1 else 0) { append(' ') }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal data class BioLines(
|
internal data class BioLines(
|
||||||
val lines: List<AnnotatedString>,
|
val lines: List<AnnotatedString>,
|
||||||
val more: Boolean,
|
val more: Boolean,
|
||||||
|
|||||||
@@ -338,6 +338,16 @@ class LibraryRepositoryTest {
|
|||||||
assertNull(normalizeBiography(" "))
|
assertNull(normalizeBiography(" "))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun aPreviouslyStoredBioIsNormalizedWhenRead() =
|
||||||
|
runBlocking {
|
||||||
|
withSource {
|
||||||
|
val sourceId = sourceRepository.activeSourceIdOnce()!!
|
||||||
|
db.libraryDao().upsertArtistBio(ArtistBio(sourceId, "ar1", "One Two"))
|
||||||
|
assertEquals("One\n\nTwo", repository.artistBio(sourceId, "ar1").first()?.biography)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun aFailedRefreshKeepsTheStoredBio() =
|
fun aFailedRefreshKeepsTheStoredBio() =
|
||||||
runBlocking {
|
runBlocking {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import androidx.compose.ui.test.onNodeWithText
|
|||||||
import androidx.compose.ui.test.performClick
|
import androidx.compose.ui.test.performClick
|
||||||
import androidx.compose.ui.test.performScrollTo
|
import androidx.compose.ui.test.performScrollTo
|
||||||
import androidx.compose.ui.test.performScrollToNode
|
import androidx.compose.ui.test.performScrollToNode
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.rememberTextMeasurer
|
import androidx.compose.ui.text.rememberTextMeasurer
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
@@ -330,27 +329,6 @@ class ArtistDetailScreenTest {
|
|||||||
assertEquals(listOf("First paragraph.", "", "Second paragraph."), paragraphBreak)
|
assertEquals(listOf("First paragraph.", "", "Second paragraph."), paragraphBreak)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun aJustifiedLineFillsTheAvailableWidth() {
|
|
||||||
val style = TextStyle(fontSize = 14.sp)
|
|
||||||
var plainWidth = 0
|
|
||||||
var justifiedWidth = 0
|
|
||||||
var justified = ""
|
|
||||||
composeRule.setContent {
|
|
||||||
val measurer = rememberTextMeasurer()
|
|
||||||
val line = AnnotatedString("one two three four five")
|
|
||||||
plainWidth = measurer.measure(line, style, maxLines = 1).size.width
|
|
||||||
val result = justifyBioLine(line, measurer, style, 400)
|
|
||||||
justifiedWidth = measurer.measure(result, style, maxLines = 1).size.width
|
|
||||||
justified = result.text
|
|
||||||
}
|
|
||||||
composeRule.waitForIdle()
|
|
||||||
|
|
||||||
assertTrue(justifiedWidth > plainWidth)
|
|
||||||
assertTrue(justifiedWidth <= 400)
|
|
||||||
assertTrue(justified.contains(" "))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun album(
|
private fun album(
|
||||||
id: String,
|
id: String,
|
||||||
name: String,
|
name: String,
|
||||||
|
|||||||
Reference in New Issue
Block a user