feat: show tilted birthday crown with click bounce animation
This commit is contained in:
parent
f33e68d1db
commit
de47509a32
@ -1,9 +1,12 @@
|
|||||||
package plus.rua.project.ui
|
package plus.rua.project.ui
|
||||||
|
|
||||||
import androidx.compose.animation.animateColor
|
import androidx.compose.animation.animateColor
|
||||||
|
import androidx.compose.animation.core.Animatable
|
||||||
import androidx.compose.animation.core.FastOutSlowInEasing
|
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||||
|
import androidx.compose.animation.core.Spring
|
||||||
import androidx.compose.animation.core.animateFloat
|
import androidx.compose.animation.core.animateFloat
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
|
import androidx.compose.animation.core.spring
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.animation.core.updateTransition
|
import androidx.compose.animation.core.updateTransition
|
||||||
import androidx.compose.ui.graphics.TransformOrigin
|
import androidx.compose.ui.graphics.TransformOrigin
|
||||||
@ -16,14 +19,19 @@ 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.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.produceState
|
import androidx.compose.runtime.produceState
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
@ -31,6 +39,7 @@ import androidx.compose.ui.draw.drawBehind
|
|||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
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.res.painterResource
|
||||||
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.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
@ -44,6 +53,7 @@ import kotlinx.datetime.number
|
|||||||
import plus.rua.project.DayCellInfo
|
import plus.rua.project.DayCellInfo
|
||||||
import plus.rua.project.LunarCache
|
import plus.rua.project.LunarCache
|
||||||
import plus.rua.project.ShiftKind
|
import plus.rua.project.ShiftKind
|
||||||
|
import plus.rua.project.shared.R
|
||||||
|
|
||||||
enum class DayCellState {
|
enum class DayCellState {
|
||||||
NORMAL, OTHER_MONTH, TODAY, SELECTED, SELECTED_TODAY
|
NORMAL, OTHER_MONTH, TODAY, SELECTED, SELECTED_TODAY
|
||||||
@ -63,6 +73,9 @@ enum class DayCellState {
|
|||||||
* @param holidayEdgeInfo 假日在连续序列中的边缘状态,决定背景圆角。null 表示无假日。
|
* @param holidayEdgeInfo 假日在连续序列中的边缘状态,决定背景圆角。null 表示无假日。
|
||||||
* @param cellIndex 单元格在月网格中的线性索引(weekIndex*7+dayIndex),用于法定假日波浪动画延迟。
|
* @param cellIndex 单元格在月网格中的线性索引(weekIndex*7+dayIndex),用于法定假日波浪动画延迟。
|
||||||
* @param onClick 点击回调
|
* @param onClick 点击回调
|
||||||
|
* @param interactionSource 点击交互源
|
||||||
|
* @param lunarCache 农历缓存实例
|
||||||
|
* @param lunarData 预计算的日期信息;null 时内部自动获取
|
||||||
* @param modifier 外部布局修饰符
|
* @param modifier 外部布局修饰符
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
@ -76,10 +89,10 @@ fun DayCell(
|
|||||||
holidayEdgeInfo: HolidayEdgeInfo? = null,
|
holidayEdgeInfo: HolidayEdgeInfo? = null,
|
||||||
cellIndex: Int = 0,
|
cellIndex: Int = 0,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
lunarCache: LunarCache = LunarCache.default,
|
lunarCache: LunarCache = LunarCache.default,
|
||||||
lunarData: DayCellInfo? = null,
|
lunarData: DayCellInfo? = null,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
if (lunarData != null) {
|
if (lunarData != null) {
|
||||||
DayCellImpl(
|
DayCellImpl(
|
||||||
@ -136,6 +149,16 @@ private fun DayCellImpl(
|
|||||||
interactionSource: MutableInteractionSource,
|
interactionSource: MutableInteractionSource,
|
||||||
lunarData: DayCellInfo,
|
lunarData: DayCellInfo,
|
||||||
) {
|
) {
|
||||||
|
val isBirthday = lunarData.isBirthday
|
||||||
|
var birthdayClickTick by remember(date) { mutableIntStateOf(0) }
|
||||||
|
val crownScale = remember(date) { Animatable(1f) }
|
||||||
|
LaunchedEffect(birthdayClickTick) {
|
||||||
|
if (birthdayClickTick > 0) {
|
||||||
|
crownScale.animateTo(1.4f, spring(dampingRatio = Spring.DampingRatioMediumBouncy))
|
||||||
|
crownScale.animateTo(1f, spring(dampingRatio = Spring.DampingRatioMediumBouncy))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val annotationText = lunarData.annotationText
|
val annotationText = lunarData.annotationText
|
||||||
val isAnnotationHighlight = lunarData.isAnnotationHighlight
|
val isAnnotationHighlight = lunarData.isAnnotationHighlight
|
||||||
val holidayBadge = lunarData.holidayBadge
|
val holidayBadge = lunarData.holidayBadge
|
||||||
@ -296,7 +319,10 @@ private fun DayCellImpl(
|
|||||||
.clickable(
|
.clickable(
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
indication = null,
|
indication = null,
|
||||||
onClick = onClick
|
onClick = {
|
||||||
|
if (isBirthday) birthdayClickTick += 1
|
||||||
|
onClick()
|
||||||
|
}
|
||||||
),
|
),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
@ -346,5 +372,23 @@ private fun DayCellImpl(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isBirthday) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_birthday_crown),
|
||||||
|
contentDescription = "生日",
|
||||||
|
tint = Color.Unspecified,
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.TopStart)
|
||||||
|
.zIndex(1f)
|
||||||
|
.padding(start = 2.dp, top = 2.dp)
|
||||||
|
.size(14.dp)
|
||||||
|
.graphicsLayer {
|
||||||
|
rotationZ = -45f
|
||||||
|
transformOrigin = TransformOrigin.Center
|
||||||
|
scaleX = crownScale.value
|
||||||
|
scaleY = crownScale.value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user