mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 15:11:58 +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.combine
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
@@ -360,7 +361,11 @@ class LibraryRepository(
|
||||
fun artistBio(
|
||||
sourceId: Long,
|
||||
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(
|
||||
sourceId: Long,
|
||||
|
||||
@@ -605,16 +605,8 @@ private fun ArtistBio(
|
||||
Column(Modifier.fillMaxWidth()) {
|
||||
bioLines.lines.forEachIndexed { index, line ->
|
||||
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 = displayLine,
|
||||
text = line,
|
||||
style = style,
|
||||
color = color,
|
||||
maxLines = 1,
|
||||
@@ -737,35 +729,6 @@ private fun appendBioControl(
|
||||
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(
|
||||
val lines: List<AnnotatedString>,
|
||||
val more: Boolean,
|
||||
|
||||
@@ -338,6 +338,16 @@ class LibraryRepositoryTest {
|
||||
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
|
||||
fun aFailedRefreshKeepsTheStoredBio() =
|
||||
runBlocking {
|
||||
|
||||
@@ -17,7 +17,6 @@ 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.AnnotatedString
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.rememberTextMeasurer
|
||||
import androidx.compose.ui.unit.sp
|
||||
@@ -330,27 +329,6 @@ class ArtistDetailScreenTest {
|
||||
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(
|
||||
id: String,
|
||||
name: String,
|
||||
|
||||
Reference in New Issue
Block a user