From 03964ca313a91391b1c1dbb5c6401bff473ba8af Mon Sep 17 00:00:00 2001 From: weishaupt <1+weishaupt@noreply.localhost> Date: Thu, 29 Oct 2026 02:30:39 +0000 Subject: [PATCH] Loosen buffer line spacing for all fonts Add extra vertical space to every buffer line (LINE_SPACING_EXTRA, 30% of font size) on top of the font natural line height. The same style measures and draws rows so whole-line snapping stays in step. Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01JW57ZwRSygeowNBguQEUUB --- src/main/kotlin/ui/ChannelScreen.kt | 42 +++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/src/main/kotlin/ui/ChannelScreen.kt b/src/main/kotlin/ui/ChannelScreen.kt index c2959bd..c05d355 100644 --- a/src/main/kotlin/ui/ChannelScreen.kt +++ b/src/main/kotlin/ui/ChannelScreen.kt @@ -1,3 +1,5 @@ +@file:OptIn(androidx.compose.ui.text.ExperimentalTextApi::class) + package ui import androidx.compose.animation.core.animateFloatAsState @@ -847,14 +849,30 @@ fun MessageScrollback( // then converts that now-stale pixel value using the NEW density, so the // two silently disagreed until the window (and this remember scope) was // recreated by closing and reopening it. - val lineHeightPx = remember(displaySettings.fontSize, displaySettings.fontId, density) { - textMeasurer.measure( - text = "Mg", - style = androidx.compose.ui.text.TextStyle( - fontFamily = AppFonts.familyFor(displaySettings.fontId), - fontSize = displaySettings.fontSize.sp + // The buffer text style gets extra vertical air on top of the font's own natural + // line height (every bundled font has different metrics, so a fixed multiplier + // would loosen some fonts and tighten others). The same style is used to measure + // the line height below AND to draw every row, so the whole-line snapping stays + // exactly in step with what is on screen. LineHeightStyle with Trim.None and a + // centered alignment makes each line exactly lineHeight tall, with the extra + // space split above and below the text. + val bufferTextStyle = remember(displaySettings.fontSize, displaySettings.fontId, density) { + val base = androidx.compose.ui.text.TextStyle( + fontFamily = AppFonts.familyFor(displaySettings.fontId), + fontSize = displaySettings.fontSize.sp + ) + val naturalPx = textMeasurer.measure(text = "Mg", style = base).size.height + val spacedLine = with(density) { naturalPx.toSp() } + (displaySettings.fontSize * LINE_SPACING_EXTRA).sp + base.copy( + lineHeight = spacedLine, + lineHeightStyle = androidx.compose.ui.text.style.LineHeightStyle( + alignment = androidx.compose.ui.text.style.LineHeightStyle.Alignment.Center, + trim = androidx.compose.ui.text.style.LineHeightStyle.Trim.None ) - ).size.height + ) + } + val lineHeightPx = remember(bufferTextStyle, density) { + textMeasurer.measure(text = "Mg", style = bufferTextStyle).size.height } val lineHeightDp = with(density) { lineHeightPx.toDp() } // Ruled out (see task: newest-message-missing investigation) as the @@ -885,10 +903,7 @@ fun MessageScrollback( // offset correction through stickToBottom's own effect instead of a // second independent one. - val textStyle = androidx.compose.ui.text.TextStyle( - fontFamily = AppFonts.familyFor(displaySettings.fontId), - fontSize = displaySettings.fontSize.sp - ) + val textStyle = bufferTextStyle val selection = selectionState.selection Column(modifier = Modifier.fillMaxSize()) { @@ -1114,6 +1129,11 @@ fun MessageScrollback( } } +// Extra vertical space added to every buffer line, as a fraction of the font size, on top of +// the font's natural line height. 0.30 is a modest loosening; raise it for more air between +// lines (0.45 is roomy), lower it for less. Applies to every font in the font list. +private const val LINE_SPACING_EXTRA = 0.30f + // Reports this element's height as a whole number of text lines ([linePx] each): rounded up // for image slots (the picture is never cut), to the nearest line for text rows (a wrapped // message can measure a pixel or two off an exact multiple). Content is drawn from the top.