diff --git a/core/src/main/kotlin/plus/rua/project/CalendarViewModel.kt b/core/src/main/kotlin/plus/rua/project/CalendarViewModel.kt index b3754b9..22655ab 100644 --- a/core/src/main/kotlin/plus/rua/project/CalendarViewModel.kt +++ b/core/src/main/kotlin/plus/rua/project/CalendarViewModel.kt @@ -18,7 +18,6 @@ import kotlinx.datetime.number import kotlinx.datetime.plus import kotlinx.datetime.todayIn import plus.rua.project.ui.COLLAPSE_THRESHOLD -import plus.rua.project.ui.FLING_VELOCITY_THRESHOLD_DP import plus.rua.project.ui.getMonthGridInfo import kotlin.time.Clock @@ -215,25 +214,17 @@ class CalendarViewModel( * @param delta 拖拽增量,已归一化到 [0,1] 区间 */ fun onDrag(delta: Float) { - val new = (_collapseProgress.value + delta).coerceIn(0f, 1f) - _collapseProgress.value = new + _collapseProgress.value = (_collapseProgress.value + delta).coerceIn(0f, 1f) } /** - * 展开状态拖拽结束,根据进度和速度决定折叠或回弹。 + * 展开状态拖拽结束,根据进度决定折叠或回弹。 * * 拖拽超过阈值时自动折叠到周视图,否则回弹到月视图。 - * - * @param velocityDpPerSec 松手时的 fling 速度 (dp/s),正值=上滑(折叠方向),负值=下滑(展开方向) */ - fun onDragEnd(velocityDpPerSec: Float = 0f) { + fun onDragEnd() { val progress = _collapseProgress.value - val shouldCollapse = when { - velocityDpPerSec > FLING_VELOCITY_THRESHOLD_DP -> true - velocityDpPerSec < -FLING_VELOCITY_THRESHOLD_DP -> false - else -> progress > COLLAPSE_THRESHOLD - } - if (shouldCollapse) { + if (progress > COLLAPSE_THRESHOLD) { _isCollapsed.value = true _collapseProgress.value = 1f } else { @@ -248,25 +239,17 @@ class CalendarViewModel( * @param delta 拖拽增量,已归一化到 [0,1] 区间 */ fun onExpandDrag(delta: Float) { - val new = (_collapseProgress.value + delta).coerceIn(0f, 1f) - _collapseProgress.value = new + _collapseProgress.value = (_collapseProgress.value + delta).coerceIn(0f, 1f) } /** - * 折叠状态拖拽结束,根据进度和速度决定展开或回弹。 + * 折叠状态拖拽结束,根据进度决定展开或回弹。 * * 下拉超过阈值时自动展开到月视图,否则回弹到周视图。 - * - * @param velocityDpPerSec 松手时的 fling 速度 (dp/s),正值=上滑,负值=下滑 */ - fun onExpandDragEnd(velocityDpPerSec: Float = 0f) { + fun onExpandDragEnd() { val progress = _collapseProgress.value - val shouldExpand = when { - velocityDpPerSec < -FLING_VELOCITY_THRESHOLD_DP -> true - velocityDpPerSec > FLING_VELOCITY_THRESHOLD_DP -> false - else -> progress < COLLAPSE_THRESHOLD - } - if (shouldExpand) { + if (progress < (1 - COLLAPSE_THRESHOLD)) { _isCollapsed.value = false _collapseProgress.value = 0f } else { diff --git a/core/src/main/kotlin/plus/rua/project/ui/BottomCard.kt b/core/src/main/kotlin/plus/rua/project/ui/BottomCard.kt index 108f9b4..eaffab3 100644 --- a/core/src/main/kotlin/plus/rua/project/ui/BottomCard.kt +++ b/core/src/main/kotlin/plus/rua/project/ui/BottomCard.kt @@ -60,13 +60,12 @@ fun BottomCard( today: LocalDate, shiftKind: ShiftKind?, onDrag: (Float) -> Unit, - onDragEnd: (Float) -> Unit, + onDragEnd: () -> Unit, onExpandDrag: (Float) -> Unit, - onExpandDragEnd: (Float) -> Unit, + onExpandDragEnd: () -> Unit, dragRangePx: Float, modifier: Modifier = Modifier ) { - val density = LocalDensity.current val relativeDesc = relativeDayDescription(selectedDate, today) @Suppress("DEPRECATION") // monthNumber 无替代 API,kotlinx-datetime 尚未提供新接口 @@ -87,36 +86,21 @@ fun BottomCard( modifier = modifier .fillMaxWidth() .pointerInput(isCollapsed) { - val velocityTracker = androidx.compose.ui.input.pointer.util.VelocityTracker() if (isCollapsed) { // 折叠状态:下拉恢复到月视图 detectVerticalDragGestures( - onDragEnd = { - val velocity = velocityTracker.calculateVelocity() - val velocityDpPerSec = with(density) { -velocity.y.toDp().value } - onExpandDragEnd(velocityDpPerSec) - }, - onDragCancel = { - onExpandDragEnd(0f) - } - ) { change, dragAmount -> - velocityTracker.addPosition(change.uptimeMillis, change.position) + onDragEnd = { onExpandDragEnd() }, + onDragCancel = { onExpandDragEnd() } + ) { _, dragAmount -> val delta = -dragAmount / dragRangePx onExpandDrag(delta) } } else { // 展开状态:上拉折叠到周视图 detectVerticalDragGestures( - onDragEnd = { - val velocity = velocityTracker.calculateVelocity() - val velocityDpPerSec = with(density) { -velocity.y.toDp().value } - onDragEnd(velocityDpPerSec) - }, - onDragCancel = { - onDragEnd(0f) - } - ) { change, dragAmount -> - velocityTracker.addPosition(change.uptimeMillis, change.position) + onDragEnd = { onDragEnd() }, + onDragCancel = { onDragEnd() } + ) { _, dragAmount -> val delta = -dragAmount / dragRangePx onDrag(delta) } diff --git a/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthView.kt b/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthView.kt index 9354161..d32db87 100644 --- a/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthView.kt +++ b/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthView.kt @@ -6,6 +6,9 @@ import androidx.compose.animation.EnterTransition import androidx.compose.animation.ExitTransition import androidx.compose.animation.SharedTransitionLayout import androidx.compose.animation.core.FastOutSlowInEasing +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut @@ -107,6 +110,13 @@ fun CalendarMonthView( val collapseProgress = uiState.collapseProgress val showLegalHoliday = uiState.showLegalHoliday + // 松手后 progress 从当前值 spring 动画到目标值(0 或 1) + val animatedCollapseProgress by animateFloatAsState( + targetValue = collapseProgress, + animationSpec = spring(stiffness = Spring.StiffnessMedium), + label = "collapseProgress" + ) + val density = LocalDensity.current val coroutineScope = rememberCoroutineScope() @@ -215,7 +225,7 @@ fun CalendarMonthView( selectedDate = selectedDate, today = today, isCollapsed = isCollapsed, - collapseProgress = collapseProgress, + collapseProgress = animatedCollapseProgress, showLegalHoliday = showLegalHoliday, rowHeightPx = rowHeightPx, screenWidthPx = screenWidthPx, @@ -562,9 +572,9 @@ private fun BottomCardArea( today = today, shiftKind = shiftKind, onDrag = { delta -> viewModel.onDrag(delta) }, - onDragEnd = { velocity -> viewModel.onDragEnd(velocity) }, + onDragEnd = { viewModel.onDragEnd() }, onExpandDrag = { delta -> viewModel.onExpandDrag(delta) }, - onExpandDragEnd = { velocity -> viewModel.onExpandDragEnd(velocity) }, + onExpandDragEnd = { viewModel.onExpandDragEnd() }, dragRangePx = dragRangePx, modifier = modifier .offset(y = with(density) { (slideProgress * 200).dp }) diff --git a/core/src/test/kotlin/plus/rua/project/CalendarViewModelStateTest.kt b/core/src/test/kotlin/plus/rua/project/CalendarViewModelStateTest.kt index af9dfbb..3d1aea5 100644 --- a/core/src/test/kotlin/plus/rua/project/CalendarViewModelStateTest.kt +++ b/core/src/test/kotlin/plus/rua/project/CalendarViewModelStateTest.kt @@ -311,7 +311,7 @@ class CalendarViewModelStateTest { fun onExpandDragEnd_progressBelowThreshold_expands() { val vm = createViewModel() vm.onDrag(1f) - vm.onExpandDrag(-0.95f) + vm.onExpandDrag(-0.15f) // progress = 0.85 < 0.92 vm.onExpandDragEnd() assertFalse(vm.isCollapsed.value) assertEquals(0f, vm.collapseProgress.value, 0.001f) @@ -321,50 +321,12 @@ class CalendarViewModelStateTest { fun onExpandDragEnd_progressAboveThreshold_staysCollapsed() { val vm = createViewModel() vm.onDrag(1f) - vm.onExpandDrag(-0.05f) + vm.onExpandDrag(-0.05f) // progress = 0.95 > 0.92 vm.onExpandDragEnd() assertTrue(vm.isCollapsed.value) assertEquals(1f, vm.collapseProgress.value, 0.001f) } - @Test - fun onDragEnd_fastFlingUp_setsCollapsed() { - val vm = createViewModel() - vm.onDrag(0.1f) - vm.onDragEnd(velocityDpPerSec = 900f) - assertTrue(vm.isCollapsed.value) - assertEquals(1f, vm.collapseProgress.value, 0.001f) - } - - @Test - fun onDragEnd_fastFlingDown_keepsExpanded() { - val vm = createViewModel() - vm.onDrag(0.9f) - vm.onDragEnd(velocityDpPerSec = -900f) - assertFalse(vm.isCollapsed.value) - assertEquals(0f, vm.collapseProgress.value, 0.001f) - } - - @Test - fun onExpandDragEnd_fastFlingDown_setsExpanded() { - val vm = createViewModel() - vm.onDrag(1f) - vm.onExpandDrag(-0.1f) - vm.onExpandDragEnd(velocityDpPerSec = -900f) - assertFalse(vm.isCollapsed.value) - assertEquals(0f, vm.collapseProgress.value, 0.001f) - } - - @Test - fun onExpandDragEnd_fastFlingUp_staysCollapsed() { - val vm = createViewModel() - vm.onDrag(1f) - vm.onExpandDrag(-0.9f) - vm.onExpandDragEnd(velocityDpPerSec = 900f) - assertTrue(vm.isCollapsed.value) - assertEquals(1f, vm.collapseProgress.value, 0.001f) - } - // ---- getMonthDays 与 selectedDate 配合 ---- @Test