hyphenate text fix for desktop

This commit is contained in:
Sergey Chernov 2026-05-17 02:48:53 +03:00
parent 3fd6606077
commit 14c9863a83
2 changed files with 62 additions and 4 deletions

View File

@ -26,15 +26,22 @@ import androidx.compose.material3.Card
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
@ -48,6 +55,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.isSpecified
import androidx.compose.ui.unit.sp
import net.sergeych.toread.fb2.Fb2Block
import net.sergeych.toread.fb2.Fb2Book
@ -57,6 +65,9 @@ import net.sergeych.toread.fb2.Fb2Text
import net.sergeych.toread.fb2.Fb2TextSpan
import net.sergeych.toread.fb2.Fb2TextStyle
import net.sergeych.toread.text.HyphenationRegistry
import net.sergeych.toread.text.SoftHyphen
import kotlin.math.max
import kotlin.math.min
@Composable
internal fun ContinuousBookReader(
@ -343,11 +354,50 @@ private fun ReaderText(
textAlign: TextAlign,
modifier: Modifier = Modifier,
) {
val annotatedText = text.toAnnotatedString(language, hyphenation)
val needsSoftHyphenPaintWorkaround = isDesktopPlatform()
var textLayout by remember(annotatedText) { mutableStateOf<TextLayoutResult?>(null) }
val desktopHyphenColor = MaterialTheme.colorScheme.onSurface
val desktopHyphenGutter = 8.dp
val textModifier = modifier
.fillMaxWidth()
.then(
if (needsSoftHyphenPaintWorkaround) {
Modifier.drawWithContent {
drawContent()
val layout = textLayout ?: return@drawWithContent
val layoutText = layout.layoutInput.text.text
val fontSizePx = if (style.fontSize.isSpecified) style.fontSize.toPx() else 18.sp.toPx()
val hyphenLength = fontSizePx * 0.36f
val strokeWidth = max(1f, fontSizePx * 0.055f)
for (line in 0 until layout.lineCount) {
if (!layout.endsAtSoftHyphen(layoutText, line)) continue
val lineRight = layout.getLineRight(line)
val x = min(lineRight + hyphenLength * 0.12f, size.width - hyphenLength)
val y = layout.getLineBaseline(line) - fontSizePx * 0.32f
drawLine(
color = desktopHyphenColor,
start = Offset(x, y),
end = Offset(x + hyphenLength, y),
strokeWidth = strokeWidth,
cap = StrokeCap.Square,
)
}
}.padding(end = desktopHyphenGutter)
} else {
Modifier
},
)
Text(
text = text.toAnnotatedString(language, hyphenation),
text = annotatedText,
style = style,
textAlign = textAlign,
modifier = modifier.fillMaxWidth(),
modifier = textModifier,
onTextLayout = { textLayout = it },
)
}
@ -364,6 +414,14 @@ private fun readerParagraphTextStyle(language: String?): TextStyle =
private fun isAndroidPlatform(): Boolean =
getPlatform().name.startsWith("Android")
private fun isDesktopPlatform(): Boolean =
getPlatform().name.startsWith("Java")
private fun TextLayoutResult.endsAtSoftHyphen(text: String, line: Int): Boolean {
val end = getLineEnd(line, visibleEnd = false)
return text.getOrNull(end - 1) == SoftHyphen || text.getOrNull(end) == SoftHyphen
}
@Composable
private fun BookImage(
book: Fb2Book,

View File

@ -11,13 +11,13 @@ androidx-lifecycle = "2.10.0"
androidx-testExt = "1.3.0"
composeHotReload = "1.1.0"
composeMaterialIcons = "1.7.3"
composeMultiplatform = "1.10.3"
composeMultiplatform = "1.11.0"
junit = "4.13.2"
kotlin = "2.3.21"
kotlinx-coroutines = "1.10.2"
ktor = "3.4.3"
logback = "1.5.32"
material3 = "1.10.0-alpha05"
material3 = "1.11.0-alpha07"
h2 = "2.4.240"
[libraries]