节日改为只在当天显示,休/班改为右上角角标

之前法定假期的「春节休」之类文本占据了整段假期,把假期里出现
的节气(雨水、惊蛰等)和其他节日全部挤掉。现在拆成两条线:

- 主标注:按 农历节日 → 节气当天 → 公历节日 → 农历日期 的
  优先级,仅在节日/节气当天展示节日名。
- 右上角角标:单独读取法定假期标志,调休「休」为 error 色,
  调休「班」为 primary 色;非当月时整体降低不透明度。

DayCell 外层多包一层 Box 承载 aspectRatio,原内层保留圆形裁
剪与涟漪;角标放在外层 TopEnd,避免被 CircleShape 裁掉。
This commit is contained in:
meyou 2026-05-16 17:34:53 +08:00
parent 889a54db0e
commit c28eb8d0e5

View File

@ -9,7 +9,9 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
@ -25,6 +27,7 @@ import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.drawscope.Stroke
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
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -113,18 +116,18 @@ fun DayCell(
data class DayAnnotation(val text: String, val isHighlight: Boolean) data class DayAnnotation(val text: String, val isHighlight: Boolean)
val holidayBadge = remember(date) {
@Suppress("DEPRECATION") // monthNumber 无替代 API
val solarDay = SolarDay.fromYmd(date.year, date.monthNumber, date.day)
solarDay.getLegalHoliday()?.let { if (it.isWork()) "" else "" }
}
val annotation = remember(date) { val annotation = remember(date) {
@Suppress("DEPRECATION") // monthNumber 无替代 API
val solarDay = SolarDay.fromYmd(date.year, date.monthNumber, date.day) val solarDay = SolarDay.fromYmd(date.year, date.monthNumber, date.day)
val lunarDay = solarDay.getLunarDay() val lunarDay = solarDay.getLunarDay()
// 法定假日优先 // 农历传统节日(仅当天)
val legalHoliday = solarDay.getLegalHoliday()
if (legalHoliday != null) {
val suffix = if (legalHoliday.isWork()) "" else ""
return@remember DayAnnotation("${legalHoliday.getName()}$suffix", true)
}
// 农历传统节日
val lunarFestival = lunarDay.getFestival() val lunarFestival = lunarDay.getFestival()
if (lunarFestival != null) { if (lunarFestival != null) {
return@remember DayAnnotation(lunarFestival.getName(), true) return@remember DayAnnotation(lunarFestival.getName(), true)
@ -136,7 +139,7 @@ fun DayCell(
return@remember DayAnnotation(termDay.getSolarTerm().getName(), true) return@remember DayAnnotation(termDay.getSolarTerm().getName(), true)
} }
// 公历节日 // 公历节日(仅当天)
val solarFestival = solarDay.getFestival() val solarFestival = solarDay.getFestival()
if (solarFestival != null) { if (solarFestival != null) {
return@remember DayAnnotation(solarFestival.getName(), true) return@remember DayAnnotation(solarFestival.getName(), true)
@ -176,52 +179,75 @@ fun DayCell(
} }
} }
val holidayBadgeColor = when (holidayBadge) {
"" -> MaterialTheme.colorScheme.error
"" -> MaterialTheme.colorScheme.primary
else -> Color.Transparent
}
val holidayBadgeAlpha = if (isCurrentMonth) 1f else 0.38f
Box( Box(
modifier = modifier modifier = modifier.aspectRatio(1f)
.aspectRatio(1f)
.semantics {
@Suppress("DEPRECATION")
contentDescription = "${date.year}${date.monthNumber}${date.day}"
}
.clip(CircleShape)
.drawBehind {
if (revealProgress > 0f) {
val maxRadius = size.minDimension / 2f
drawCircle(
color = selectedColor,
radius = revealProgress * maxRadius,
center = Offset(size.width / 2f, size.height / 2f)
)
}
if (borderAlpha > 0f) {
drawCircle(
color = todayBorderColor.copy(alpha = borderAlpha.coerceAtMost(1f)),
radius = size.minDimension / 2f,
center = Offset(size.width / 2f, size.height / 2f),
style = Stroke(width = borderAlpha.coerceAtMost(1.5f) * 1.5.dp.toPx())
)
}
}
.clickable(onClick = onClick),
contentAlignment = Alignment.Center
) { ) {
Column( Box(
horizontalAlignment = Alignment.CenterHorizontally modifier = Modifier
.fillMaxSize()
.semantics {
@Suppress("DEPRECATION")
contentDescription = "${date.year}${date.monthNumber}${date.day}"
}
.clip(CircleShape)
.drawBehind {
if (revealProgress > 0f) {
val maxRadius = size.minDimension / 2f
drawCircle(
color = selectedColor,
radius = revealProgress * maxRadius,
center = Offset(size.width / 2f, size.height / 2f)
)
}
if (borderAlpha > 0f) {
drawCircle(
color = todayBorderColor.copy(alpha = borderAlpha.coerceAtMost(1f)),
radius = size.minDimension / 2f,
center = Offset(size.width / 2f, size.height / 2f),
style = Stroke(width = borderAlpha.coerceAtMost(1.5f) * 1.5.dp.toPx())
)
}
}
.clickable(onClick = onClick),
contentAlignment = Alignment.Center
) { ) {
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = date.day.toString(),
textAlign = TextAlign.Center,
color = contentColor,
style = MaterialTheme.typography.bodyMedium
)
Text(
text = annotation.text,
textAlign = TextAlign.Center,
color = lunarColor,
fontSize = 7.sp,
maxLines = 1,
overflow = TextOverflow.Clip,
lineHeight = 9.sp
)
}
}
if (holidayBadge != null) {
Text( Text(
text = date.day.toString(), text = holidayBadge,
textAlign = TextAlign.Center, color = holidayBadgeColor.copy(alpha = holidayBadgeAlpha),
color = contentColor, fontSize = 9.sp,
style = MaterialTheme.typography.bodyMedium fontWeight = FontWeight.Bold,
) lineHeight = 9.sp,
Text( modifier = Modifier
text = annotation.text, .align(Alignment.TopEnd)
textAlign = TextAlign.Center, .padding(top = 2.dp, end = 4.dp)
color = lunarColor,
fontSize = 7.sp,
maxLines = 1,
overflow = TextOverflow.Clip,
lineHeight = 9.sp
) )
} }
} }