feat: 底部卡片展示选中日期的相对天数、公历与农历信息
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
39bb2301d3
commit
0d58be45bc
@ -2,27 +2,42 @@ package plus.rua.project.ui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.detectVerticalDragGestures
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import kotlinx.datetime.LocalDate
|
||||
import plus.rua.project.CalendarViewModel
|
||||
|
||||
/**
|
||||
* 底部卡片,折叠状态下支持垂直拖拽触发折叠动画。
|
||||
*
|
||||
* 卡片顶部显示拖拽把手,下方展示选中日期信息:
|
||||
* 左侧为相对今天的天数描述(A)和公历日期(B),
|
||||
* 右侧为农历日期(C)。
|
||||
*
|
||||
* @param viewModel 日历 ViewModel,用于读取折叠状态和驱动拖拽
|
||||
* @param selectedDate 当前选中的日期
|
||||
* @param today 今天的日期
|
||||
* @param dragRangePx 拖拽手势映射范围(像素),progress 从 0→1 对应手指移动此距离。
|
||||
* 应设为折叠时日历实际高度变化量 (weeks-1)×rowHeight,使拖拽跟手。
|
||||
* @param modifier 外部布局修饰符
|
||||
@ -30,10 +45,16 @@ import plus.rua.project.CalendarViewModel
|
||||
@Composable
|
||||
fun BottomCard(
|
||||
viewModel: CalendarViewModel,
|
||||
selectedDate: LocalDate,
|
||||
today: LocalDate,
|
||||
dragRangePx: Float,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
val relativeDesc = relativeDayDescription(selectedDate, today)
|
||||
@Suppress("DEPRECATION") // monthNumber 无替代 API,kotlinx-datetime 尚未提供新接口
|
||||
val solarDesc = "${selectedDate.monthNumber}月${selectedDate.day}日"
|
||||
val lunarDesc = formatLunarDate(selectedDate)
|
||||
|
||||
Surface(
|
||||
modifier = modifier
|
||||
@ -80,16 +101,52 @@ fun BottomCard(
|
||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||
shadowElevation = 4.dp
|
||||
) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
Column(modifier = Modifier.fillMaxSize()) {
|
||||
// 拖拽把手
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopCenter)
|
||||
.padding(top = 8.dp, bottom = 8.dp)
|
||||
.clip(RoundedCornerShape(2.dp))
|
||||
.background(MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.4f))
|
||||
.fillMaxWidth(0.15f)
|
||||
.height(4.dp)
|
||||
.align(Alignment.CenterHorizontally)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
// A / B / C 信息行
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 20.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// 左侧:A(相对天数)和 B(公历日期)在同一行
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = relativeDesc,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
fontSize = 14.sp
|
||||
)
|
||||
Spacer(modifier = Modifier.width(6.dp))
|
||||
Text(
|
||||
text = solarDesc,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
fontSize = 14.sp
|
||||
)
|
||||
}
|
||||
// 右侧:C(农历日期)
|
||||
Text(
|
||||
text = lunarDesc,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
fontSize = 14.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -311,6 +311,8 @@ fun CalendarMonthView(
|
||||
if (cardHeightPx > 0) {
|
||||
BottomCard(
|
||||
viewModel = viewModel,
|
||||
selectedDate = viewModel.selectedDate,
|
||||
today = today,
|
||||
dragRangePx = dragRangePx,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
package plus.rua.project.ui
|
||||
|
||||
import com.tyme.solar.SolarDay
|
||||
import kotlinx.datetime.DatePeriod
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.daysUntil
|
||||
import kotlinx.datetime.minus
|
||||
import kotlinx.datetime.number
|
||||
import kotlinx.datetime.plus
|
||||
@ -130,3 +132,40 @@ fun pageToWeekMonday(page: Int, initial: LocalDate): LocalDate {
|
||||
val offset = page - START_PAGE
|
||||
return initial.plus(DatePeriod(days = offset * 7))
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算选中日期相对于今天的天数描述。
|
||||
*
|
||||
* 例如今天 19 日,选中 18 日返回"昨天",17 日返回"2天前",
|
||||
* 20 日返回"明天",21 日返回"2天后",选中当天返回"今天"。
|
||||
*
|
||||
* @param selectedDate 选中日期
|
||||
* @param today 今天日期
|
||||
* @return 相对天数描述
|
||||
*/
|
||||
fun relativeDayDescription(selectedDate: LocalDate, today: LocalDate): String {
|
||||
val diff = today.daysUntil(selectedDate)
|
||||
return when {
|
||||
diff == 0 -> "今天"
|
||||
diff == -1 -> "昨天"
|
||||
diff == 1 -> "明天"
|
||||
diff < 0 -> "${-diff}天前"
|
||||
else -> "${diff}天后"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将公历日期格式化为农历日期字符串。
|
||||
*
|
||||
* 格式为"农历{月}{日}",例如"农历四月初三"。
|
||||
*
|
||||
* @param date 公历日期
|
||||
* @return 农历日期描述
|
||||
*/
|
||||
@Suppress("DEPRECATION") // monthNumber 无替代 API,kotlinx-datetime 尚未提供新接口
|
||||
fun formatLunarDate(date: LocalDate): String {
|
||||
val solarDay = SolarDay.fromYmd(date.year, date.monthNumber, date.day)
|
||||
val lunarDay = solarDay.getLunarDay()
|
||||
val lunarMonth = lunarDay.getLunarMonth()
|
||||
return "农历${lunarMonth.getName()}${lunarDay.getName()}"
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user