优化细节

This commit is contained in:
BBIT-Kai
2026-05-29 11:34:55 +08:00
parent c5a72e938f
commit f91251adc6
2 changed files with 464 additions and 220 deletions
@@ -1,7 +1,10 @@
package com.bbitcn.f8.pad.ui.screen.mainFunc
import android.content.res.Configuration
import androidx.compose.foundation.Canvas
import android.graphics.Paint
import android.graphics.RectF
import android.text.TextPaint
import android.text.TextUtils
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
@@ -13,9 +16,6 @@ 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.layout.widthIn
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.DatePickerDefaults
import androidx.compose.material3.DatePickerDialog
@@ -31,7 +31,6 @@ import androidx.compose.material3.rememberDateRangePickerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -40,18 +39,16 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.drawText
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.dp
import com.bbitcn.f8.pad.M
import com.bbitcn.f8.pad.base.MainFuncFrame
@@ -362,10 +359,7 @@ fun InfoList(
},
columns = columns,
item = { data, index ->
val isSelected by remember(data.czSysid) {
derivedStateOf { data.czSysid == selectedId.value }
}
InfoItem(isSelect = isSelected, data = data) {
InfoItem(isSelect = data.czSysid == selectedId.value, data = data) {
selectedId.value = data.czSysid
onClick(data)
}
@@ -397,55 +391,12 @@ fun InfoItem(
)
.clickable(onClick = onClick)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = M
.fillMaxWidth()
.height(32.dp)
.background(color = if (isSelect) MyColors.BlueGreen else MyColors.White)
) {
Text(
text = data.nhName,
fontSize = MaterialTheme.typography.bodyMedium.fontSize,
modifier = M
.padding(horizontal = 10.dp)
.widthIn(max = 50.dp),
maxLines = 1,
overflow = TextOverflow.Ellipsis, // 超出部分显示省略号
color = if (isSelect) MyColors.White else MyColors.Black,
fontWeight = FontWeight.Bold
)
Spacer(modifier = M.weight(1f))
Text(
text = data.billCode.toString(),
fontSize = MaterialTheme.typography.bodyMedium.fontSize,
modifier = M.padding(start = 4.dp),
color = if (isSelect) MyColors.White else MyColors.Black,
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Box(
modifier = M
.padding(start = 6.dp)
.height(32.dp)
.wrapContentWidth()
.background(
color = MyColors.Orange,
shape = RoundedCornerShape(bottomStart = 7.dp)
),
contentAlignment = Alignment.Center
) {
Text(
text = data.billState,
modifier = M.padding(horizontal = 6.dp),
color = MyColors.White,
fontSize = MaterialTheme.typography.bodyMedium.fontSize,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
}
PurchaseCardHeader(
isSelect = isSelect,
name = data.nhName,
billCode = data.billCode.toString(),
billState = data.billState
)
PurchaseSummaryTable(
visibleItems = visibleItems,
hiddenCount = hiddenCount
@@ -457,17 +408,149 @@ fun InfoItem(
}
}
private data class PurchaseCardHeaderText(
val name: String,
val billCode: String,
val billState: String,
val stateWidth: Float
)
@Composable
private fun PurchaseCardHeader(
isSelect: Boolean,
name: String,
billCode: String,
billState: String
) {
val fontSize = MaterialTheme.typography.bodyMedium.fontSize
val backgroundColor = if (isSelect) MyColors.BlueGreen else MyColors.White
val textColor = if (isSelect) MyColors.White else MyColors.Black
val statusColor = MyColors.Orange
val statusTextColor = MyColors.White
Box(
modifier = M
.fillMaxWidth()
.height(32.dp)
.drawWithCache {
val boldPaint = TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
color = textColor.toArgb()
textSize = fontSize.toPx()
textAlign = Paint.Align.LEFT
isFakeBoldText = true
isSubpixelText = true
}
val billPaint = TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
color = textColor.toArgb()
textSize = fontSize.toPx()
textAlign = Paint.Align.RIGHT
isFakeBoldText = true
isSubpixelText = true
}
val statusTextPaint = TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
color = statusTextColor.toArgb()
textSize = fontSize.toPx()
textAlign = Paint.Align.CENTER
isSubpixelText = true
}
val statusFillPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = statusColor.toArgb()
style = Paint.Style.FILL
}
val horizontalPadding = 10.dp.toPx()
val statusHorizontalPadding = 6.dp.toPx()
val nameMaxWidth = 50.dp.toPx()
val gap = 6.dp.toPx()
val stateMaxWidth = (size.width * 0.34f).coerceAtLeast(48.dp.toPx())
val stateText = TextUtils.ellipsize(
billState,
statusTextPaint,
(stateMaxWidth - statusHorizontalPadding * 2).coerceAtLeast(1f),
TextUtils.TruncateAt.END
).toString()
val stateWidth = (
statusTextPaint.measureText(stateText) + statusHorizontalPadding * 2
).coerceAtMost(stateMaxWidth)
val nameText = TextUtils.ellipsize(
name,
boldPaint,
nameMaxWidth,
TextUtils.TruncateAt.END
).toString()
val billRight = (size.width - stateWidth - gap).coerceAtLeast(horizontalPadding)
val billMaxWidth = (billRight - horizontalPadding - nameMaxWidth - gap).coerceAtLeast(1f)
val billText = TextUtils.ellipsize(
billCode,
billPaint,
billMaxWidth,
TextUtils.TruncateAt.END
).toString()
val clippedText = PurchaseCardHeaderText(
name = nameText,
billCode = billText,
billState = stateText,
stateWidth = stateWidth
)
val cornerRadius = 7.dp.toPx()
onDrawBehind {
drawRect(color = backgroundColor, topLeft = Offset.Zero)
val baseline = (size.height - boldPaint.fontMetrics.ascent - boldPaint.fontMetrics.descent) / 2f
drawIntoCanvas { canvas ->
val nativeCanvas = canvas.nativeCanvas
nativeCanvas.drawText(clippedText.name, horizontalPadding, baseline, boldPaint)
nativeCanvas.drawText(clippedText.billCode, billRight, baseline, billPaint)
val left = size.width - clippedText.stateWidth
val path = android.graphics.Path().apply {
moveTo(left, 0f)
lineTo(size.width, 0f)
lineTo(size.width, size.height)
lineTo(left + cornerRadius, size.height)
arcTo(
RectF(
left,
size.height - cornerRadius * 2,
left + cornerRadius * 2,
size.height
),
90f,
90f
)
lineTo(left, 0f)
close()
}
nativeCanvas.drawPath(path, statusFillPaint)
nativeCanvas.drawText(
clippedText.billState,
left + clippedText.stateWidth / 2f,
baseline,
statusTextPaint
)
}
}
}
)
}
private data class PurchaseSummaryTableText(
val headers: List<String>,
val rows: List<List<String>>,
val moreText: String?
)
@Composable
private fun PurchaseSummaryTable(
visibleItems: List<PurchaseDataResponse.Data.ChengZhongItemSum>,
hiddenCount: Int
) {
val textMeasurer = rememberTextMeasurer()
val bodyFontSize = MaterialTheme.typography.bodyMedium.fontSize
val labelFontSize = MaterialTheme.typography.labelSmall.fontSize
val headerBackground = MyColors.White
val headerTextColor = MyColors.Black
val rowBackground = MyColors.White
val rowTextColor = MyColors.Black
val moreTextColor = MyColors.Gray
val headers = remember {
listOf("茧别", "毛重", "皮重", "扣重", "净重", "单价")
@@ -484,128 +567,216 @@ private fun PurchaseSummaryTable(
)
}
}
val headerStyle = TextStyle(
color = headerTextColor,
fontSize = bodyFontSize,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center
)
val rowStyle = TextStyle(
color = MyColors.Black,
fontSize = bodyFontSize,
textAlign = TextAlign.Center
)
val moreStyle = TextStyle(
color = moreTextColor,
fontSize = labelFontSize
)
Canvas(
Box(
modifier = M
.fillMaxWidth()
.height(88.dp)
) {
val headerHeight = 28.dp.toPx()
val rowHeight = 24.dp.toPx()
val cellWidth = size.width / headers.size
val cellConstraints = Constraints.fixedWidth(cellWidth.toInt().coerceAtLeast(1))
fun drawCell(text: String, column: Int, top: Float, height: Float, style: TextStyle) {
val result = textMeasurer.measure(
text = AnnotatedString(text),
style = style,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
constraints = cellConstraints
)
drawText(
textLayoutResult = result,
topLeft = Offset(
x = column * cellWidth,
y = top + (height - result.size.height) / 2f
.drawWithCache {
val headerPaint = TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
color = headerTextColor.toArgb()
textSize = bodyFontSize.toPx()
textAlign = Paint.Align.CENTER
isFakeBoldText = true
isSubpixelText = true
}
val rowPaint = TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
color = rowTextColor.toArgb()
textSize = bodyFontSize.toPx()
textAlign = Paint.Align.CENTER
isSubpixelText = true
}
val morePaint = TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
color = moreTextColor.toArgb()
textSize = labelFontSize.toPx()
textAlign = Paint.Align.LEFT
isSubpixelText = true
}
val headerHeight = 28.dp.toPx()
val rowHeight = 24.dp.toPx()
val cellWidth = size.width / headers.size
val cellTextWidthPx = (cellWidth - 8.dp.toPx()).coerceAtLeast(1f)
val moreTextWidthPx = (size.width - 16.dp.toPx()).coerceAtLeast(1f)
val clippedText = PurchaseSummaryTableText(
headers = headers.map { text ->
TextUtils.ellipsize(
text,
headerPaint,
cellTextWidthPx,
TextUtils.TruncateAt.END
).toString()
},
rows = rows.map { row ->
row.map { text ->
TextUtils.ellipsize(
text,
rowPaint,
cellTextWidthPx,
TextUtils.TruncateAt.END
).toString()
}
},
moreText = if (hiddenCount > 0) {
TextUtils.ellipsize(
"+$hiddenCount",
morePaint,
moreTextWidthPx,
TextUtils.TruncateAt.END
).toString()
} else {
null
}
)
)
}
drawRect(color = headerBackground, topLeft = Offset.Zero)
headers.forEachIndexed { index, text ->
drawCell(text, index, 0f, headerHeight, headerStyle)
}
onDrawBehind {
fun drawNativeText(
text: String,
x: Float,
top: Float,
height: Float,
paint: TextPaint
) {
val baseline = top + (height - paint.fontMetrics.ascent - paint.fontMetrics.descent) / 2f
drawIntoCanvas { canvas ->
canvas.nativeCanvas.drawText(text, x, baseline, paint)
}
}
rows.forEachIndexed { rowIndex, row ->
val rowTop = headerHeight + rowIndex * rowHeight
drawRect(
color = rowBackground,
topLeft = Offset(0f, rowTop),
size = androidx.compose.ui.geometry.Size(size.width, rowHeight)
)
row.forEachIndexed { columnIndex, text ->
drawCell(text, columnIndex, rowTop, rowHeight, rowStyle)
fun drawCell(text: String, column: Int, top: Float, height: Float, paint: TextPaint) {
drawNativeText(
text = text,
x = column * cellWidth + cellWidth / 2f,
top = top,
height = height,
paint = paint
)
}
drawRect(color = headerBackground, topLeft = Offset.Zero)
clippedText.headers.forEachIndexed { index, text ->
drawCell(text, index, 0f, headerHeight, headerPaint)
}
clippedText.rows.forEachIndexed { rowIndex, row ->
val rowTop = headerHeight + rowIndex * rowHeight
drawRect(
color = rowBackground,
topLeft = Offset(0f, rowTop),
size = androidx.compose.ui.geometry.Size(size.width, rowHeight)
)
row.forEachIndexed { columnIndex, text ->
drawCell(text, columnIndex, rowTop, rowHeight, rowPaint)
}
}
clippedText.moreText?.let { text ->
val moreTop = headerHeight + clippedText.rows.size * rowHeight + 2.dp.toPx()
drawNativeText(
text = text,
x = 8.dp.toPx(),
top = moreTop,
height = (size.height - moreTop).coerceAtLeast(1f),
paint = morePaint
)
}
}
}
}
if (hiddenCount > 0) {
val moreTop = headerHeight + rows.size * rowHeight + 2.dp.toPx()
val result = textMeasurer.measure(
text = AnnotatedString("+$hiddenCount"),
style = moreStyle,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
constraints = Constraints(maxWidth = size.width.toInt().coerceAtLeast(1))
)
drawText(
textLayoutResult = result,
topLeft = Offset(8.dp.toPx(), moreTop)
)
}
}
)
}
private data class PurchaseStateChip(
val text: String,
val selected: Boolean
)
@Composable
fun StateList(hasPrice: Boolean, hasTare: Boolean, hasConfirm: Boolean, hasPay: Boolean) {
Row(
val selectedBackgroundColor = MyColors.LightLightBlueGreen
val normalBackgroundColor = Color(0xFFF4F6F8)
val selectedTextColor = MyColors.BlueGreen
val normalTextColor = MyColors.Gray
val fontSize = MaterialTheme.typography.labelSmall.fontSize
val states = remember(hasPrice, hasTare, hasConfirm, hasPay) {
listOf(
PurchaseStateChip("定价", hasPrice),
PurchaseStateChip("扣皮", hasTare),
PurchaseStateChip(if (hasConfirm) "确认" else "确认售", hasConfirm),
PurchaseStateChip("支付", hasPay)
)
}
Box(
modifier = M
.fillMaxWidth()
.height(38.dp)
.padding(horizontal = 4.dp, vertical = 3.dp),
verticalAlignment = Alignment.CenterVertically
) {
StateItem("定价", hasPrice, M.weight(1f))
StateItem("扣皮", hasTare, M.weight(1f))
StateItem(if (hasConfirm) "确认" else "确认售", hasConfirm, M.weight(1f))
StateItem("支付", hasPay, M.weight(1f))
}
}
.drawWithCache {
val selectedPaint = TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
color = selectedTextColor.toArgb()
textSize = fontSize.toPx()
textAlign = Paint.Align.CENTER
isSubpixelText = true
}
val normalPaint = TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
color = normalTextColor.toArgb()
textSize = fontSize.toPx()
textAlign = Paint.Align.CENTER
isSubpixelText = true
}
val outerPaddingX = 4.dp.toPx()
val chipGap = 4.dp.toPx()
val chipPaddingX = 6.dp.toPx()
val chipHeight = 28.dp.toPx()
val chipTop = (size.height - chipHeight) / 2f
val chipWidth = (size.width - outerPaddingX * 2 - chipGap * 3) / 4f
val dotRadius = 3.dp.toPx()
val dotGap = 4.dp.toPx()
val cornerRadius = chipHeight / 2f
val maxTextWidth = (chipWidth - chipPaddingX * 2 - dotRadius * 2 - dotGap).coerceAtLeast(1f)
val clippedStates = states.map { state ->
state.copy(
text = TextUtils.ellipsize(
state.text,
if (state.selected) selectedPaint else normalPaint,
maxTextWidth,
TextUtils.TruncateAt.END
).toString()
)
}
@Composable
fun StateItem(text: String, isSelect: Boolean, modifier: Modifier) {
val backgroundColor = if (isSelect) MyColors.LightLightBlueGreen else Color(0xFFF4F6F8)
val borderColor = if (isSelect) MyColors.BlueGreen else MyColors.LightGray
Box(
modifier = modifier
.height(28.dp)
.padding(horizontal = 2.dp)
.background(backgroundColor, RoundedCornerShape(50))
.padding(horizontal = 6.dp, vertical = 4.dp),
contentAlignment = Alignment.Center
) {
Row(verticalAlignment = Alignment.CenterVertically) {
if (isSelect) {
Box(
modifier = M
.padding(end = 4.dp)
.width(6.dp)
.height(6.dp)
.background(borderColor, CircleShape)
)
onDrawBehind {
clippedStates.forEachIndexed { index, state ->
val left = outerPaddingX + index * (chipWidth + chipGap)
val backgroundColor = if (state.selected) selectedBackgroundColor else normalBackgroundColor
val textPaint = if (state.selected) selectedPaint else normalPaint
drawRoundRect(
color = backgroundColor,
topLeft = Offset(left, chipTop),
size = androidx.compose.ui.geometry.Size(chipWidth, chipHeight),
cornerRadius = CornerRadius(cornerRadius, cornerRadius)
)
val textWidth = textPaint.measureText(state.text)
val groupWidth = if (state.selected) dotRadius * 2 + dotGap + textWidth else textWidth
val textCenterX = if (state.selected) {
left + chipWidth / 2f + (dotRadius * 2 + dotGap) / 2f
} else {
left + chipWidth / 2f
}
if (state.selected) {
val dotCenterX = left + (chipWidth - groupWidth) / 2f + dotRadius
drawCircle(
color = selectedTextColor,
radius = dotRadius,
center = Offset(dotCenterX, chipTop + chipHeight / 2f)
)
}
val baseline = chipTop + (chipHeight - textPaint.fontMetrics.ascent - textPaint.fontMetrics.descent) / 2f
drawIntoCanvas { canvas ->
canvas.nativeCanvas.drawText(state.text, textCenterX, baseline, textPaint)
}
}
}
}
Text(
text = text,
color = if (isSelect) MyColors.BlueGreen else MyColors.Gray,
modifier = M.padding(horizontal = 5.dp),
fontSize = MaterialTheme.typography.labelSmall.fontSize,
)
}
}
)
}
@@ -3,47 +3,47 @@ package com.bbitcn.f8.pad.ui.screen.view.common
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight
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.size
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.itemsIndexed
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.bbitcn.f8.pad.M
import com.bbitcn.f8.pad.R
import com.bbitcn.f8.pad.base.RedPointBadge
import com.bbitcn.f8.pad.base.TableHeadLine
import com.bbitcn.f8.pad.ui.theme.MyColors
import java.time.LocalDate
private const val RANGE_NONE = -1
private const val RANGE_START = 0
private const val RANGE_END = 1
private const val RANGE_MIDDLE = 2
private const val RANGE_SINGLE = 3
@Preview(showBackground = true)
@Composable
fun DatePickerRangePV() {
@@ -148,28 +148,30 @@ fun DatePickerRange(
)
)
val firstDayOffset = currentDate.withDayOfMonth(1).dayOfWeek.value % 7
LazyVerticalGrid(
columns = GridCells.Fixed(7),
) {
// 填充上个月的日期
items((currentDate.withDayOfMonth(1).dayOfWeek.value - 1) % 7) {
items(firstDayOffset) {
CalendarDay(0)
}
// 填充当前月的日期
items(currentDate.lengthOfMonth() + 1) { day ->
items(currentDate.lengthOfMonth()) { index ->
val day = index + 1
CalendarDay(
day,
importantDaySet.contains(day),
rangeType = if (day == selectedStartDay)
if (selectedEndDay == -1
|| selectedEndDay == selectedStartDay
)
3
else
0
else if (day == selectedEndDay) 1
else if (day in selectedStartDay..selectedEndDay) 2
else -1,
rangeType = when {
day == selectedStartDay &&
(selectedEndDay == -1 || selectedEndDay == selectedStartDay) -> RANGE_SINGLE
day == selectedStartDay -> RANGE_START
day == selectedEndDay -> RANGE_END
selectedStartDay != -1 &&
selectedEndDay != -1 &&
day in selectedStartDay..selectedEndDay -> RANGE_MIDDLE
else -> RANGE_NONE
},
) {
if (selectedStartDay == -1 // 开始日期没选
|| selectedEndDay != -1 // 已经选了结束日期
@@ -194,28 +196,80 @@ fun DatePickerRange(
fun CalendarDay(
day: Int,
isImportant: Boolean = false,
rangeType: Int = -1,// -1:不在范围内 0:在第一天 1:在最后一天 2:在中间 3:只有一天
rangeType: Int = RANGE_NONE,
onClick: () -> Unit = {}
) {
if (day != 0) {
Box(
modifier = M.background(
color = if (rangeType != -1) MyColors.Gray else MyColors.Transparent,
shape = when (rangeType) {
-1, 3 -> CircleShape // 圆形
0 -> RoundedCornerShape(topStart = 50.dp, bottomStart = 50.dp) // 左半圆右矩形
1 -> RoundedCornerShape(topEnd = 50.dp, bottomEnd = 50.dp) // 右半圆左矩形
2 -> RectangleShape // 全矩形
else -> RectangleShape
}
Box(
modifier = M
.fillMaxWidth()
.aspectRatio(1f)
.padding(vertical = 2.dp),
contentAlignment = Alignment.Center
) {
if (day == 0) {
Spacer(modifier = M.fillMaxSize())
} else {
val isEndpoint =
rangeType == RANGE_START || rangeType == RANGE_END || rangeType == RANGE_SINGLE
if (rangeType != RANGE_NONE && rangeType != RANGE_SINGLE) {
CalendarRangeTrack(rangeType)
}
CalText(
day.toString(),
isSelect = rangeType != RANGE_NONE,
isEndpoint = isEndpoint,
onClick = onClick
)
) {
if (isImportant) {
RedPointBadge {
CalText(day.toString(), isSelect = rangeType != -1, onClick = onClick)
}
} else {
CalText(day.toString(), isSelect = rangeType != -1, onClick = onClick)
Box(
modifier = M
.align(Alignment.TopEnd)
.padding(top = 6.dp, end = 7.dp)
.size(6.dp)
.background(MyColors.Red, CircleShape)
)
}
}
}
}
@Composable
private fun BoxScope.CalendarRangeTrack(rangeType: Int) {
val trackColor = MyColors.LightBlueGreen.copy(alpha = 0.72f)
Row(
modifier = M
.fillMaxWidth()
.height(28.dp)
.align(Alignment.Center)
) {
when (rangeType) {
RANGE_START -> {
Spacer(modifier = M.weight(1f))
Box(
modifier = M
.weight(1f)
.fillMaxHeight()
.background(trackColor)
)
}
RANGE_END -> {
Box(
modifier = M
.weight(1f)
.fillMaxHeight()
.background(trackColor)
)
Spacer(modifier = M.weight(1f))
}
RANGE_MIDDLE -> {
Box(
modifier = M
.fillMaxSize()
.background(trackColor)
)
}
}
}
@@ -225,21 +279,40 @@ fun CalendarDay(
fun CalText(
day: String,
isSelect: Boolean = false,
isEndpoint: Boolean = false,
onClick: () -> Unit
) {
Box(
modifier = Modifier
.aspectRatio(1f)
.fillMaxSize()
.clickable {
onClick()
},
contentAlignment = Alignment.Center
) {
val animatedColor = if (isSelect) MyColors.White else MyColors.Black
Text(
text = day,
fontSize = MaterialTheme.typography.bodyMedium.fontSize,
color = animatedColor
)
val dayCircleModifier = if (isEndpoint) {
M
.size(30.dp)
.background(MyColors.BlueGreen, CircleShape)
} else {
M.size(30.dp)
}
val animatedColor = when {
isEndpoint -> MyColors.White
isSelect -> MyColors.BlueGreen
else -> MyColors.Black
}
Box(
modifier = dayCircleModifier,
contentAlignment = Alignment.Center
) {
Text(
text = day,
fontSize = MaterialTheme.typography.bodyMedium.fontSize,
color = animatedColor,
fontWeight = if (isSelect) FontWeight.Bold else FontWeight.Normal
)
}
}
}