DayCell 中右上角班次("班"/"休")标签去除 surface 背景圆,
文字直接浮在单元格上,视觉更轻量。同步清理
CalendarViewModel、AnimatedGif、BottomCard 的未使用导入,
并格式化 YearGridView 与 CalendarUtilsExtraTest。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
153 lines
6.6 KiB
Kotlin
153 lines
6.6 KiB
Kotlin
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.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 外部布局修饰符
|
||
*/
|
||
@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
|
||
.fillMaxWidth()
|
||
.pointerInput(viewModel.isCollapsed) {
|
||
val velocityTracker = androidx.compose.ui.input.pointer.util.VelocityTracker()
|
||
if (viewModel.isCollapsed) {
|
||
// 折叠状态:下拉恢复到月视图
|
||
detectVerticalDragGestures(
|
||
onDragEnd = {
|
||
val velocity = velocityTracker.calculateVelocity()
|
||
// 上滑为正(折叠方向),下拉为负(展开方向)
|
||
val velocityDpPerSec = with(density) { -velocity.y.toDp().value }
|
||
viewModel.onExpandDragEnd(velocityDpPerSec)
|
||
},
|
||
onDragCancel = {
|
||
viewModel.onExpandDragEnd()
|
||
}
|
||
) { change, dragAmount ->
|
||
velocityTracker.addPosition(change.uptimeMillis, change.position)
|
||
val delta = -dragAmount / dragRangePx
|
||
viewModel.onExpandDrag(delta)
|
||
}
|
||
} else {
|
||
// 展开状态:上拉折叠到周视图
|
||
detectVerticalDragGestures(
|
||
onDragEnd = {
|
||
val velocity = velocityTracker.calculateVelocity()
|
||
// 上滑为正(折叠方向),下拉为负(展开方向)
|
||
val velocityDpPerSec = with(density) { -velocity.y.toDp().value }
|
||
viewModel.onDragEnd(velocityDpPerSec)
|
||
},
|
||
onDragCancel = {
|
||
viewModel.onDragEnd()
|
||
}
|
||
) { change, dragAmount ->
|
||
velocityTracker.addPosition(change.uptimeMillis, change.position)
|
||
val delta = -dragAmount / dragRangePx
|
||
viewModel.onDrag(delta)
|
||
}
|
||
}
|
||
},
|
||
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
|
||
color = MaterialTheme.colorScheme.surfaceVariant,
|
||
shadowElevation = 4.dp
|
||
) {
|
||
Column(modifier = Modifier.fillMaxSize()) {
|
||
// 拖拽把手
|
||
Box(
|
||
modifier = Modifier
|
||
.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
|
||
)
|
||
}
|
||
}
|
||
}
|
||
}
|