|
...
|
...
|
@@ -13,75 +13,83 @@ class TodaySleepCard extends StatelessWidget { |
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Obx(
|
|
|
|
() => _TodaySummaryCard(
|
|
|
|
iconAsset: 'assets/images/common/ic_sleep_stroke.png',
|
|
|
|
iconColor: context.colors.primary,
|
|
|
|
title: context.l10n.sleep,
|
|
|
|
actionText: context.l10n.viewSleepReport,
|
|
|
|
progressValues: [controller.sleepProgress.value],
|
|
|
|
progressColors: [context.colors.primary],
|
|
|
|
metrics: [
|
|
|
|
_MetricData(
|
|
|
|
label: context.l10n.duration,
|
|
|
|
labelColor: context.colors.primary,
|
|
|
|
valueSpans: [
|
|
|
|
_MetricValueSpan(controller.sleepHours.value, '小时'),
|
|
|
|
_MetricValueSpan(controller.sleepMinutes.value, '分钟'),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
_MetricData(
|
|
|
|
label: context.l10n.quality,
|
|
|
|
labelColor: const Color(0xFF7B9BFB),
|
|
|
|
valueSpans: [
|
|
|
|
_MetricValueSpan(
|
|
|
|
controller.sleepQuality.value,
|
|
|
|
'',
|
|
|
|
valueColor: _qualityColor(controller.sleepQuality.value),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
_MetricData(
|
|
|
|
label: context.l10n.averageHeartRate,
|
|
|
|
labelColor: context.colors.textSecondary,
|
|
|
|
valueSpans: [
|
|
|
|
_MetricValueSpan(controller.sleepAverageHeartRate.value, 'bpm'),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
],
|
|
|
|
rightWidget: Container(
|
|
|
|
width: 50,
|
|
|
|
height: 50,
|
|
|
|
margin: EdgeInsets.only(right: 6, left: 4),
|
|
|
|
child: CircularGradientCombineWidget(
|
|
|
|
size: 50,
|
|
|
|
duration: const Duration(seconds: 1),
|
|
|
|
sweepAngles: const [240, 210],
|
|
|
|
backgroundColors: const [
|
|
|
|
Color(0xFFF3F3F3),
|
|
|
|
Color(0xFFF3F3F3),
|
|
|
|
return GestureDetector(
|
|
|
|
onTap: controller.toTrendSleepPage,
|
|
|
|
child: Obx(() {
|
|
|
|
var healthData = controller.v2HealthData.value;
|
|
|
|
|
|
|
|
int sleepDuration = healthData?.sleepDuration ?? 0;
|
|
|
|
int sleepHours = sleepDuration ~/ 3600;
|
|
|
|
int sleepMinutes = sleepDuration % 60;
|
|
|
|
Color sleepStateColor =
|
|
|
|
healthData?.sleepStateColor(context) ?? context.colors.chartGreen;
|
|
|
|
String sleepStateStr = healthData?.sleepStateStr() ?? '--';
|
|
|
|
String sleepAverageHeartRate =
|
|
|
|
(healthData?.hrAvg == null || healthData?.hrAvg == 0)
|
|
|
|
? '--'
|
|
|
|
: '${healthData?.hrAvg}';
|
|
|
|
double sleepDurationProgress =
|
|
|
|
((healthData?.sleepDurationScore() ?? 0) * 3.60);
|
|
|
|
double sleepScoreProgress = (healthData?.sleepScore ?? 0.0) * 3.6;
|
|
|
|
|
|
|
|
return _TodaySummaryCard(
|
|
|
|
iconAsset: 'assets/images/common/ic_sleep_stroke.png',
|
|
|
|
iconColor: context.colors.primary,
|
|
|
|
title: context.l10n.sleep,
|
|
|
|
actionText: context.l10n.viewSleepReport,
|
|
|
|
metrics: [
|
|
|
|
_MetricData(
|
|
|
|
label: context.l10n.duration,
|
|
|
|
labelColor: context.colors.primary,
|
|
|
|
valueSpans: [
|
|
|
|
_MetricValueSpan(sleepHours > 0 ? '$sleepHours' : '--', '小时'),
|
|
|
|
_MetricValueSpan(
|
|
|
|
sleepMinutes > 0 ? '$sleepMinutes' : '--', '分钟'),
|
|
|
|
],
|
|
|
|
gradientColors: [
|
|
|
|
[context.colors.primary],
|
|
|
|
[context.colors.chartBlue],
|
|
|
|
),
|
|
|
|
_MetricData(
|
|
|
|
label: context.l10n.quality,
|
|
|
|
labelColor: const Color(0xFF7B9BFB),
|
|
|
|
valueSpans: [
|
|
|
|
_MetricValueSpan(
|
|
|
|
sleepStateStr,
|
|
|
|
'',
|
|
|
|
valueColor: sleepStateColor,
|
|
|
|
),
|
|
|
|
],
|
|
|
|
centerCircleSizeRatio: 0.3,
|
|
|
|
gapRatio: 0.1,
|
|
|
|
interpolatedColorRatio: 1),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
_MetricData(
|
|
|
|
label: context.l10n.averageHeartRate,
|
|
|
|
labelColor: context.colors.textSecondary,
|
|
|
|
valueSpans: [
|
|
|
|
_MetricValueSpan(sleepAverageHeartRate, 'bpm'),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
],
|
|
|
|
rightWidget: Container(
|
|
|
|
width: 50,
|
|
|
|
height: 50,
|
|
|
|
margin: EdgeInsets.only(right: 6, left: 4),
|
|
|
|
child: CircularGradientCombineWidget(
|
|
|
|
size: 50,
|
|
|
|
duration: const Duration(seconds: 1),
|
|
|
|
sweepAngles: [sleepDurationProgress, sleepScoreProgress],
|
|
|
|
backgroundColors: const [
|
|
|
|
Color(0xFFF3F3F3),
|
|
|
|
Color(0xFFF3F3F3),
|
|
|
|
],
|
|
|
|
gradientColors: [
|
|
|
|
[context.colors.primary],
|
|
|
|
[context.colors.chartBlue],
|
|
|
|
],
|
|
|
|
centerCircleSizeRatio: 0.3,
|
|
|
|
gapRatio: 0.1,
|
|
|
|
interpolatedColorRatio: 1),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Color _qualityColor(String quality) {
|
|
|
|
return switch (quality) {
|
|
|
|
'优秀' => const Color(0xFF3BD49D),
|
|
|
|
'良好' => const Color(0xFF7B9BFB),
|
|
|
|
'一般' => const Color(0xFFFF9A6E),
|
|
|
|
'偏少' => const Color(0xFFFF5279),
|
|
|
|
_ => const Color(0xFF0F0F11),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class TodayActivityCard extends StatelessWidget {
|
|
...
|
...
|
@@ -91,91 +99,93 @@ class TodayActivityCard extends StatelessWidget { |
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Obx(
|
|
|
|
() => _TodaySummaryCard(
|
|
|
|
iconAsset: 'assets/images/common/ic_exercise.png',
|
|
|
|
iconColor: const Color(0xFFFF5279),
|
|
|
|
title: context.l10n.fitness,
|
|
|
|
actionText: context.l10n.viewFitnessReport,
|
|
|
|
progressValues: [
|
|
|
|
controller.activityMoveProgress.value,
|
|
|
|
controller.activityExerciseProgress.value,
|
|
|
|
controller.activityStandProgress.value,
|
|
|
|
],
|
|
|
|
progressColors: const [
|
|
|
|
Color(0xFFFF5279),
|
|
|
|
Color(0xFF3BD49D),
|
|
|
|
Color(0xFF7B9BFB),
|
|
|
|
],
|
|
|
|
metrics: [
|
|
|
|
_MetricData(
|
|
|
|
label: context.l10n.event,
|
|
|
|
labelColor: const Color(0xFFFF5279),
|
|
|
|
valueSpans: [
|
|
|
|
_MetricValueSpan(controller.activityCalories.value, '千卡'),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
_MetricData(
|
|
|
|
label: context.l10n.exercise,
|
|
|
|
labelColor: const Color(0xFF3BD49D),
|
|
|
|
valueSpans: [
|
|
|
|
_MetricValueSpan(
|
|
|
|
controller.activityExerciseMinutes.value,
|
|
|
|
'分钟',
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
_MetricData(
|
|
|
|
label: context.l10n.standing,
|
|
|
|
labelColor: const Color(0xFF7B9BFB),
|
|
|
|
valueSpans: [
|
|
|
|
_MetricValueSpan(controller.activityStandHours.value, '小时'),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
],
|
|
|
|
rightWidget: Container(
|
|
|
|
width: 50,
|
|
|
|
height: 50,
|
|
|
|
margin: EdgeInsets.only(right: 6, left: 4),
|
|
|
|
child: Stack(
|
|
|
|
children: [
|
|
|
|
Container(
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
shape: BoxShape.circle,
|
|
|
|
color: context.colors.textPrimary,
|
|
|
|
return GestureDetector(
|
|
|
|
onTap: controller.toTrendActivityPage,
|
|
|
|
child: Obx(() {
|
|
|
|
var healthData = controller.v2HealthData.value;
|
|
|
|
var activity = healthData?.move;
|
|
|
|
var stand = healthData?.stand ?? 0;
|
|
|
|
var exercise = healthData?.exercise ?? 0;
|
|
|
|
var standStr = stand > 0 ? '${stand ~/ 3600}' : '--';
|
|
|
|
var exerciseStr = exercise > 0 ? '${exercise % 60}' : '--';
|
|
|
|
|
|
|
|
return _TodaySummaryCard(
|
|
|
|
iconAsset: 'assets/images/common/ic_exercise.png',
|
|
|
|
iconColor: const Color(0xFFFF5279),
|
|
|
|
title: context.l10n.fitness,
|
|
|
|
actionText: context.l10n.viewFitnessReport,
|
|
|
|
metrics: [
|
|
|
|
_MetricData(
|
|
|
|
label: context.l10n.event,
|
|
|
|
labelColor: const Color(0xFFFF5279),
|
|
|
|
valueSpans: [
|
|
|
|
_MetricValueSpan(
|
|
|
|
(activity == null || activity == 0) ? '--' : '$activity',
|
|
|
|
'千卡'),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
_MetricData(
|
|
|
|
label: context.l10n.exercise,
|
|
|
|
labelColor: const Color(0xFF3BD49D),
|
|
|
|
valueSpans: [
|
|
|
|
_MetricValueSpan(
|
|
|
|
exerciseStr,
|
|
|
|
'分钟',
|
|
|
|
),
|
|
|
|
),
|
|
|
|
CircularGradientCombineWidget(
|
|
|
|
size: 50,
|
|
|
|
duration: const Duration(seconds: 1),
|
|
|
|
centerCircleSizeRatio: 0.2,
|
|
|
|
gapRatio: 0.06,
|
|
|
|
sweepAngles: const [
|
|
|
|
180,
|
|
|
|
230,
|
|
|
|
180,
|
|
|
|
],
|
|
|
|
backgroundColors: [
|
|
|
|
context.colors.chartPink.withOpacity(0.4),
|
|
|
|
context.colors.chartGreen.withOpacity(0.3),
|
|
|
|
context.colors.chartBlue.withOpacity(0.4),
|
|
|
|
],
|
|
|
|
gradientColors: [
|
|
|
|
[
|
|
|
|
context.colors.chartPink,
|
|
|
|
],
|
|
|
|
),
|
|
|
|
_MetricData(
|
|
|
|
label: context.l10n.standing,
|
|
|
|
labelColor: const Color(0xFF7B9BFB),
|
|
|
|
valueSpans: [
|
|
|
|
_MetricValueSpan(standStr, '小时'),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
],
|
|
|
|
rightWidget: Container(
|
|
|
|
width: 50,
|
|
|
|
height: 50,
|
|
|
|
margin: EdgeInsets.only(right: 6, left: 4),
|
|
|
|
child: Stack(
|
|
|
|
children: [
|
|
|
|
Container(
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
shape: BoxShape.circle,
|
|
|
|
color: context.colors.textPrimary,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
CircularGradientCombineWidget(
|
|
|
|
size: 50,
|
|
|
|
duration: const Duration(seconds: 1),
|
|
|
|
centerCircleSizeRatio: 0.2,
|
|
|
|
gapRatio: 0.06,
|
|
|
|
sweepAngles: const [
|
|
|
|
180,
|
|
|
|
230,
|
|
|
|
180,
|
|
|
|
],
|
|
|
|
[
|
|
|
|
context.colors.chartGreen,
|
|
|
|
backgroundColors: [
|
|
|
|
context.colors.chartPink.withOpacity(0.4),
|
|
|
|
context.colors.chartGreen.withOpacity(0.3),
|
|
|
|
context.colors.chartBlue.withOpacity(0.4),
|
|
|
|
],
|
|
|
|
[
|
|
|
|
context.colors.chartBlue,
|
|
|
|
gradientColors: [
|
|
|
|
[
|
|
|
|
context.colors.chartPink,
|
|
|
|
],
|
|
|
|
[
|
|
|
|
context.colors.chartGreen,
|
|
|
|
],
|
|
|
|
[
|
|
|
|
context.colors.chartBlue,
|
|
|
|
],
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
...
|
...
|
@@ -187,8 +197,6 @@ class _TodaySummaryCard extends StatelessWidget { |
|
|
|
required this.title,
|
|
|
|
required this.actionText,
|
|
|
|
required this.metrics,
|
|
|
|
required this.progressValues,
|
|
|
|
required this.progressColors,
|
|
|
|
required this.rightWidget,
|
|
|
|
});
|
|
|
|
|
|
...
|
...
|
@@ -197,8 +205,7 @@ class _TodaySummaryCard extends StatelessWidget { |
|
|
|
final String title;
|
|
|
|
final String actionText;
|
|
|
|
final List<_MetricData> metrics;
|
|
|
|
final List<double> progressValues;
|
|
|
|
final List<Color> progressColors;
|
|
|
|
|
|
|
|
final Widget rightWidget;
|
|
|
|
|
|
|
|
@override
|
...
|
...
|
|