Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b8da92157 |
@@ -123,7 +123,6 @@ import androidx.compose.ui.platform.LocalDensity
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.semantics.contentDescription
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.text.rememberTextMeasurer
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
@@ -745,7 +744,7 @@ internal fun WeekdayHeader(weekStart: DayOfWeek, showWeekNumbers: Boolean) {
|
|||||||
.padding(horizontal = AppBarSpacing.Inset, vertical = 4.dp),
|
.padding(horizontal = AppBarSpacing.Inset, vertical = 4.dp),
|
||||||
) {
|
) {
|
||||||
// Reserve the gutter so the weekday labels stay over their day columns.
|
// Reserve the gutter so the weekday labels stay over their day columns.
|
||||||
if (showWeekNumbers) Spacer(Modifier.width(rememberWeekNumberGutter()))
|
if (showWeekNumbers) Spacer(Modifier.width(WEEK_NUMBER_GUTTER))
|
||||||
days.forEach { dow ->
|
days.forEach { dow ->
|
||||||
val isWeekend = dow == DayOfWeek.SATURDAY || dow == DayOfWeek.SUNDAY
|
val isWeekend = dow == DayOfWeek.SATURDAY || dow == DayOfWeek.SUNDAY
|
||||||
val javaDow = java.time.DayOfWeek.of(dow.ordinal + 1)
|
val javaDow = java.time.DayOfWeek.of(dow.ordinal + 1)
|
||||||
@@ -763,34 +762,9 @@ internal fun WeekdayHeader(weekStart: DayOfWeek, showWeekNumbers: Boolean) {
|
|||||||
|
|
||||||
private val EVENT_ROW_HEIGHT = 20.dp
|
private val EVENT_ROW_HEIGHT = 20.dp
|
||||||
private val DAY_NUMBER_HEIGHT = 22.dp
|
private val DAY_NUMBER_HEIGHT = 22.dp
|
||||||
/** Padding between the week-number pill's edge and the number inside it. */
|
/** Width of the optional left calendar-week gutter (#25); narrow, since it only
|
||||||
private val WEEK_NUMBER_PADDING = 6.dp
|
* seats a one- or two-digit week number in a full-height tonal pill. */
|
||||||
|
private val WEEK_NUMBER_GUTTER = 40.dp
|
||||||
/** The widest week number an ISO year reaches; digits are tabular, so one
|
|
||||||
* measurement of it prices every week in the grid. */
|
|
||||||
private const val WEEK_NUMBER_SAMPLE = "53"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Width of the optional left calendar-week gutter (#25), measured rather than
|
|
||||||
* fixed: it is sized to the number it seats at the style the pill draws it in,
|
|
||||||
* so it follows the font scale instead of reserving slack for it, and spends
|
|
||||||
* nothing more on a column the grid would rather hand to the seven days (#213).
|
|
||||||
*/
|
|
||||||
@Composable
|
|
||||||
private fun rememberWeekNumberGutter(): Dp {
|
|
||||||
val measurer = rememberTextMeasurer()
|
|
||||||
val density = LocalDensity.current
|
|
||||||
val style = weekNumberStyle()
|
|
||||||
return remember(style, density, measurer) {
|
|
||||||
val text = with(density) { measurer.measure(WEEK_NUMBER_SAMPLE, style).size.width.toDp() }
|
|
||||||
text + (WEEK_NUMBER_PADDING + CELL_GAP) * 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The week number's own style — a step down from the day numbers beside it. */
|
|
||||||
@Composable
|
|
||||||
private fun weekNumberStyle() =
|
|
||||||
MaterialTheme.typography.labelMedium.copy(fontWeight = FontWeight.Bold)
|
|
||||||
private val DAY_NUMBER_GAP = 4.dp
|
private val DAY_NUMBER_GAP = 4.dp
|
||||||
private val CELL_TOP_PADDING = 6.dp
|
private val CELL_TOP_PADDING = 6.dp
|
||||||
/** Named separately because the split style's selection outline draws its own
|
/** Named separately because the split style's selection outline draws its own
|
||||||
@@ -1512,7 +1486,7 @@ internal fun SplitMonthGrid(
|
|||||||
WeekNumberGutter(
|
WeekNumberGutter(
|
||||||
weekStart = week.days.first(),
|
weekStart = week.days.first(),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(rememberWeekNumberGutter())
|
.width(WEEK_NUMBER_GUTTER)
|
||||||
.fillMaxHeight(),
|
.fillMaxHeight(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2033,7 +2007,7 @@ private fun MonthWeekRow(
|
|||||||
WeekNumberGutter(
|
WeekNumberGutter(
|
||||||
weekStart = week.days.first(),
|
weekStart = week.days.first(),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(rememberWeekNumberGutter())
|
.width(WEEK_NUMBER_GUTTER)
|
||||||
.fillMaxHeight(),
|
.fillMaxHeight(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2448,7 +2422,8 @@ private fun WeekNumberGutter(weekStart: LocalDate, modifier: Modifier = Modifier
|
|||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = weekNumber.toString(),
|
text = weekNumber.toString(),
|
||||||
style = weekNumberStyle(),
|
style = MaterialTheme.typography.titleSmall,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
color = MaterialTheme.colorScheme.onSecondaryContainer,
|
color = MaterialTheme.colorScheme.onSecondaryContainer,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,24 @@
|
|||||||
package de.jeanlucmakiola.calendula.ui.theme
|
package de.jeanlucmakiola.calendula.ui.theme
|
||||||
|
|
||||||
import androidx.compose.material3.Typography
|
import androidx.compose.material3.Typography
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default Material 3 Expressive typography. Custom font + tuned scale will
|
* Tracking the two label roles the calendar grids are set in. Material gives
|
||||||
* land in a later UI-design iteration; the defaults are intentional for V1
|
* both 0.5sp, tuned for isolated UI labels with room around them; a month chip
|
||||||
* scaffolding to keep the foundation lean.
|
* is a text box some 37dp wide, where 0.5sp on an 11sp glyph spends most of a
|
||||||
|
* character on spacing alone. 0.1sp is what Material itself sets labelLarge to,
|
||||||
|
* so the label family stays coherent (#190).
|
||||||
*/
|
*/
|
||||||
val CalendulaTypography = Typography()
|
private val LabelTracking = 0.1.sp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Material 3 Expressive typography with the label roles' tracking tightened.
|
||||||
|
* Everything else is the default scale.
|
||||||
|
*/
|
||||||
|
val CalendulaTypography: Typography = Typography().let { base ->
|
||||||
|
base.copy(
|
||||||
|
labelMedium = base.labelMedium.copy(letterSpacing = LabelTracking),
|
||||||
|
labelSmall = base.labelSmall.copy(letterSpacing = LabelTracking),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -571,7 +571,7 @@ private fun WeekDayHeader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Calendar-week badge shown in the header gutter, deliberately set apart with a
|
/** Calendar-week badge shown in the header gutter, deliberately set apart with a
|
||||||
* filled box and bold number — at the month grid's size, so the two agree (#213). */
|
* filled box and bold number. */
|
||||||
@Composable
|
@Composable
|
||||||
private fun WeekNumberBadge(weekNumber: Int, modifier: Modifier = Modifier) {
|
private fun WeekNumberBadge(weekNumber: Int, modifier: Modifier = Modifier) {
|
||||||
val label = stringResource(R.string.week_number_label)
|
val label = stringResource(R.string.week_number_label)
|
||||||
@@ -583,9 +583,9 @@ private fun WeekNumberBadge(weekNumber: Int, modifier: Modifier = Modifier) {
|
|||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = weekNumber.toString(),
|
text = weekNumber.toString(),
|
||||||
style = MaterialTheme.typography.labelMedium,
|
style = MaterialTheme.typography.titleSmall,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
modifier = Modifier.padding(horizontal = 6.dp, vertical = 3.dp),
|
modifier = Modifier.padding(horizontal = 8.dp, vertical = 3.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package de.jeanlucmakiola.calendula.ui.theme
|
package de.jeanlucmakiola.calendula.ui.theme
|
||||||
|
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
@@ -48,6 +49,19 @@ class FontsTest {
|
|||||||
assertThat(typography.labelSmall.fontFamily).isEqualTo(plain)
|
assertThat(typography.labelSmall.fontFamily).isEqualTo(plain)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `picking a font keeps the tightened label tracking`() {
|
||||||
|
// The font picker only swaps the family; the tracking the grids are laid
|
||||||
|
// out against has to survive it (#190).
|
||||||
|
val typography = calendulaTypography(
|
||||||
|
brand = BundledFont.Lora.family,
|
||||||
|
plain = BundledFont.AtkinsonHyperlegible.family,
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(typography.labelSmall.letterSpacing).isEqualTo(0.1.sp)
|
||||||
|
assertThat(typography.labelMedium.letterSpacing).isEqualTo(0.1.sp)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `a null role keeps that role's default family while the other is applied`() {
|
fun `a null role keeps that role's default family while the other is applied`() {
|
||||||
val plain = BundledFont.Lora.family
|
val plain = BundledFont.Lora.family
|
||||||
|
|||||||
Reference in New Issue
Block a user