From 49d21903c60630267942c463d8c290380bef020d Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Wed, 23 Sep 2026 14:02:35 +0200 Subject: [PATCH] Trim the chip line box and give the rows back the space (#190) --- .../calendula/ui/common/CalendarText.kt | 41 +++++++++++++++++++ .../calendula/ui/day/DayScreen.kt | 6 ++- .../calendula/ui/month/MonthScreen.kt | 10 ++++- .../calendula/ui/week/WeekScreen.kt | 6 ++- 4 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 app/src/main/java/de/jeanlucmakiola/calendula/ui/common/CalendarText.kt diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/CalendarText.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/CalendarText.kt new file mode 100644 index 0000000..125c492 --- /dev/null +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/CalendarText.kt @@ -0,0 +1,41 @@ +package de.jeanlucmakiola.calendula.ui.common + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.rememberTextMeasurer +import androidx.compose.ui.text.style.LineHeightStyle +import androidx.compose.ui.unit.Dp + +/** + * The calendar surfaces' line-height treatment. Material wraps an 11sp glyph in + * a 16sp line box — room a label wants when it stands on its own, and close to + * a fifth of an event row when it doesn't. The outer edges only, so a wrapped + * title keeps its interior line spacing (#190). + * + * Trimmed rather than set to a smaller line height: the font picker can load a + * serif, a monospace or a file of the user's own, and a line height under a + * face's own ascent and descent overlaps its lines. There is nothing to trim + * below that, so this is safe whatever font is chosen. + */ +private val TrimmedLines = LineHeightStyle( + alignment = LineHeightStyle.Alignment.Center, + trim = LineHeightStyle.Trim.Both, +) + +/** Ascenders and descenders both, so a line is measured at its full extent. */ +private const val LINE_SAMPLE = "Ag" + +/** [this] with Material's outer leading trimmed — see [TrimmedLines]. */ +fun TextStyle.trimmedLines(): TextStyle = copy(lineHeightStyle = TrimmedLines) + +/** What one trimmed line of [style] actually draws in. */ +@Composable +fun rememberTrimmedLineHeight(style: TextStyle): Dp { + val measurer = rememberTextMeasurer() + val density = LocalDensity.current + return remember(style, density, measurer) { + with(density) { measurer.measure(LINE_SAMPLE, style.trimmedLines()).size.height.toDp() } + } +} diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/day/DayScreen.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/day/DayScreen.kt index ba70d12..1639b0d 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/day/DayScreen.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/day/DayScreen.kt @@ -115,6 +115,7 @@ import de.jeanlucmakiola.calendula.ui.common.rememberCalendarPageSwipe import de.jeanlucmakiola.floret.identity.rememberReduceMotion import de.jeanlucmakiola.calendula.ui.common.next import de.jeanlucmakiola.calendula.ui.common.EventChipShape +import de.jeanlucmakiola.calendula.ui.common.trimmedLines import de.jeanlucmakiola.calendula.ui.common.rememberCalendarSlideSpec import de.jeanlucmakiola.floret.locale.currentLocale import de.jeanlucmakiola.calendula.ui.common.LocalUse24HourFormat @@ -140,7 +141,8 @@ import kotlin.time.Clock import java.util.Locale import kotlin.math.roundToInt -private val ALL_DAY_ROW_HEIGHT = 24.dp +/** One lane of the all-day strip, sized to a trimmed bar line (#190). */ +private val ALL_DAY_ROW_HEIGHT = 20.dp private val ALL_DAY_VERTICAL_PADDING = 6.dp /** Total all-day strip height for the day (0 when there are no all-day events). */ @@ -529,7 +531,7 @@ private fun AllDayBar( val titleOverflow = eventTitleOverflow() Text( text = title, - style = MaterialTheme.typography.labelSmall, + style = MaterialTheme.typography.labelSmall.trimmedLines(), maxLines = 1, overflow = titleOverflow.overflow, softWrap = titleOverflow.softWrap, diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/month/MonthScreen.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/month/MonthScreen.kt index 4b5d54b..9634943 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/month/MonthScreen.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/month/MonthScreen.kt @@ -153,6 +153,7 @@ import de.jeanlucmakiola.calendula.ui.common.LocalUse24HourFormat import de.jeanlucmakiola.calendula.ui.common.inlineTimeLabel import de.jeanlucmakiola.calendula.ui.common.eventAccent import de.jeanlucmakiola.calendula.ui.common.EventChipShape +import de.jeanlucmakiola.calendula.ui.common.trimmedLines import de.jeanlucmakiola.calendula.ui.common.monthBarShape import de.jeanlucmakiola.calendula.ui.common.rememberCurrentMinute import de.jeanlucmakiola.calendula.ui.common.ViewSwitcherPill @@ -760,7 +761,12 @@ internal fun WeekdayHeader(weekStart: DayOfWeek, showWeekNumbers: Boolean) { } } -private val EVENT_ROW_HEIGHT = 20.dp +/** + * One lane of a day cell. Sized to a trimmed chip line rather than to Material's + * line box, so the three lanes a cell can draw cost it nine dp less and a + * six-row month keeps its third chip instead of demoting it to a dot (#190). + */ +private val EVENT_ROW_HEIGHT = 17.dp private val DAY_NUMBER_HEIGHT = 22.dp /** Width of the optional left calendar-week gutter (#25); narrow, since it only * seats a one- or two-digit week number in a full-height tonal pill. */ @@ -2544,7 +2550,7 @@ private fun MonthBar( val titleOverflow = eventTitleOverflow() Text( text = label, - style = MaterialTheme.typography.labelSmall, + style = MaterialTheme.typography.labelSmall.trimmedLines(), maxLines = 1, overflow = titleOverflow.overflow, softWrap = titleOverflow.softWrap, diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/week/WeekScreen.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/week/WeekScreen.kt index 7c55ce1..7380709 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/week/WeekScreen.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/week/WeekScreen.kt @@ -118,6 +118,7 @@ import de.jeanlucmakiola.calendula.ui.common.rememberTimelineDragController import de.jeanlucmakiola.calendula.ui.common.startInstant import de.jeanlucmakiola.calendula.ui.common.LocalDimCutoff import de.jeanlucmakiola.calendula.ui.common.EventChipShape +import de.jeanlucmakiola.calendula.ui.common.trimmedLines import de.jeanlucmakiola.calendula.ui.common.NowLine import de.jeanlucmakiola.calendula.ui.common.rememberCurrentMinute import de.jeanlucmakiola.calendula.ui.common.ViewSwitcherPill @@ -155,7 +156,8 @@ import kotlin.time.Clock import java.time.format.TextStyle as JavaTextStyle import java.util.Locale -private val ALL_DAY_ROW_HEIGHT = 24.dp +/** One lane of the all-day strip, sized to a trimmed bar line (#190). */ +private val ALL_DAY_ROW_HEIGHT = 20.dp private val ALL_DAY_VERTICAL_PADDING = 6.dp /** Gap between day columns; part of the column pitch a drag maps positions through. */ private val COLUMN_GAP = 2.dp @@ -664,7 +666,7 @@ private fun AllDayBar( val titleOverflow = eventTitleOverflow() Text( text = title, - style = MaterialTheme.typography.labelSmall, + style = MaterialTheme.typography.labelSmall.trimmedLines(), maxLines = 1, overflow = titleOverflow.overflow, softWrap = titleOverflow.softWrap,