From 58573f465789937f3c1040e7b7e847e259aaec92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B4=94=E9=B2=81=E6=AD=A3?= <13780741225@163.com> Date: Thu, 10 Sep 2026 11:20:51 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=BB=9F=E4=B8=80=E8=BF=90=E5=8A=A8?= =?UTF-8?q?=E5=8E=86=E5=8F=B2=E7=A9=BA=E6=80=81=E6=96=87=E5=AD=97=E9=A2=9C?= =?UTF-8?q?=E8=89=B2=E5=B9=B6=E8=A1=A5=E5=85=85=E9=A1=B5=E9=9D=A2=E9=A2=84?= =?UTF-8?q?=E8=A7=88=E4=B8=8E=E9=A1=BA=E5=BA=8F=E6=96=AD=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/workout/WorkoutHistoryScreen.kt | 45 ++++++++++++++++++- .../feature/workout/WorkoutScreen.kt | 34 ++++++++++++++ .../feature/workout/WorkoutViewModelTest.kt | 6 ++- 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/placeholder/ringhealth/feature/workout/WorkoutHistoryScreen.kt b/app/src/main/java/com/placeholder/ringhealth/feature/workout/WorkoutHistoryScreen.kt index 0f14fcf..4fd455f 100644 --- a/app/src/main/java/com/placeholder/ringhealth/feature/workout/WorkoutHistoryScreen.kt +++ b/app/src/main/java/com/placeholder/ringhealth/feature/workout/WorkoutHistoryScreen.kt @@ -15,12 +15,16 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import com.placeholder.ringhealth.AppViewModelProvider import com.placeholder.ringhealth.R import com.placeholder.ringhealth.core.designsystem.MetricGreen +import com.placeholder.ringhealth.core.designsystem.RingHealthTheme +import com.placeholder.ringhealth.core.designsystem.TextSecondary +import com.placeholder.ringhealth.domain.model.WorkoutRecord /** 运动历史子页:展示全部运动记录。 */ @Composable @@ -29,7 +33,15 @@ fun WorkoutHistoryScreen( viewModel: WorkoutViewModel = viewModel(factory = AppViewModelProvider.Factory), ) { val state by viewModel.uiState.collectAsStateWithLifecycle() + WorkoutHistoryContent(state = state, modifier = modifier) +} +/** 无状态运动历史内容,便于 Preview。 */ +@Composable +private fun WorkoutHistoryContent( + state: WorkoutUiState, + modifier: Modifier = Modifier, +) { // 必须先判 loading 再判空(ledger Ruling R25):Mock 仓库有 200ms 延迟, // records 在加载完成前就是 emptyList,若先判空会先闪一下「暂无运动记录」, // 数据到了再跳成列表 —— 用户看到的是「明明有记录却说没有」。 @@ -47,7 +59,7 @@ fun WorkoutHistoryScreen( Text( text = stringResource(R.string.workout_empty), style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant, + color = TextSecondary, ) } return @@ -62,3 +74,34 @@ fun WorkoutHistoryScreen( } } } + +/** 预览入口:以固定示例数据渲染 [WorkoutHistoryContent],便于在 IDE 中免真机查看历史页效果。 */ +@Preview(showBackground = true) +@Composable +private fun WorkoutHistoryContentPreview() { + RingHealthTheme { + WorkoutHistoryContent( + state = WorkoutUiState( + loading = false, + records = listOf( + WorkoutRecord( + id = "preview-0", + type = "户外跑步", + startTime = 1_757_000_000_000L, + durationMinutes = 42, + distanceKm = 5.20, + calories = 286, + ), + WorkoutRecord( + id = "preview-1", + type = "健走", + startTime = 1_756_900_000_000L, + durationMinutes = 31, + distanceKm = 2.80, + calories = 143, + ), + ), + ), + ) + } +} diff --git a/app/src/main/java/com/placeholder/ringhealth/feature/workout/WorkoutScreen.kt b/app/src/main/java/com/placeholder/ringhealth/feature/workout/WorkoutScreen.kt index ee27966..e89eb56 100644 --- a/app/src/main/java/com/placeholder/ringhealth/feature/workout/WorkoutScreen.kt +++ b/app/src/main/java/com/placeholder/ringhealth/feature/workout/WorkoutScreen.kt @@ -23,6 +23,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel @@ -34,6 +35,7 @@ import com.placeholder.ringhealth.core.common.formatDate import com.placeholder.ringhealth.core.common.formatDistance import com.placeholder.ringhealth.core.common.formatDuration import com.placeholder.ringhealth.core.designsystem.MetricGreen +import com.placeholder.ringhealth.core.designsystem.RingHealthTheme import com.placeholder.ringhealth.core.designsystem.TextSecondary import com.placeholder.ringhealth.core.designsystem.component.HealthCard import com.placeholder.ringhealth.core.designsystem.component.SectionHeader @@ -139,3 +141,35 @@ internal fun WorkoutRecordCard(record: WorkoutRecord, modifier: Modifier = Modif } } } + +/** 预览入口:以固定示例数据渲染 [WorkoutContent],便于在 IDE 中免真机查看运动页效果。 */ +@Preview(showBackground = true) +@Composable +private fun WorkoutContentPreview() { + RingHealthTheme { + WorkoutContent( + state = WorkoutUiState( + loading = false, + records = listOf( + WorkoutRecord( + id = "preview-0", + type = "户外跑步", + startTime = 1_757_000_000_000L, + durationMinutes = 42, + distanceKm = 5.20, + calories = 286, + ), + WorkoutRecord( + id = "preview-1", + type = "健走", + startTime = 1_756_900_000_000L, + durationMinutes = 31, + distanceKm = 2.80, + calories = 143, + ), + ), + ), + onOpenHistory = {}, + ) + } +} diff --git a/app/src/test/java/com/placeholder/ringhealth/feature/workout/WorkoutViewModelTest.kt b/app/src/test/java/com/placeholder/ringhealth/feature/workout/WorkoutViewModelTest.kt index 797b1a3..b15ac43 100644 --- a/app/src/test/java/com/placeholder/ringhealth/feature/workout/WorkoutViewModelTest.kt +++ b/app/src/test/java/com/placeholder/ringhealth/feature/workout/WorkoutViewModelTest.kt @@ -12,6 +12,7 @@ import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test @@ -46,7 +47,8 @@ class WorkoutViewModelTest { val state = viewModel.uiState.value assertFalse(state.loading) assertEquals(5, state.records.size) - // Mock 的运动记录是倒序生成的,最近的在最前 - assertEquals("户外跑步", state.records.first().type) + // 列表必须按时间倒序(最近的在最前):直接比首尾时间戳,而不是比记录类型 + // —— Mock 数据的首尾类型恰好相同,用类型断言无法察觉顺序被反转。 + assertTrue(state.records.first().startTime > state.records.last().startTime) } }