Commit e969282fff44e2e1bb9ed51d287c08c9ae3fe0df

Authored by 常守达
1 parent 3bde5fcd

fix(today):睡眠卡片

... ... @@ -18,6 +18,7 @@ class TodaySleepCard extends StatelessWidget {
onTap: controller.toTrendSleepPage,
child: Obx(() {
var healthData = controller.v2HealthData.value;
var activityTarget = controller.v2ActivityTarget.value;
int sleepDuration = healthData?.sleepDuration ?? 0;
int sleepHours = sleepDuration ~/ 3600;
... ... @@ -31,9 +32,13 @@ class TodaySleepCard extends StatelessWidget {
(healthData?.hrAvg == null || healthData?.hrAvg == 0)
? '-'
: '${healthData?.hrAvg}';
double sleepDurationProgress = sleepDuration == 0
? -1
: ((healthData?.sleepDurationScore() ?? 0) * 3.60);
double sleepDurationProgress =
(activityTarget?.sleepTargetDuration ?? 0) == 0 ||
sleepDuration == 0
? -1
: ((healthData?.sleepDuration ?? 0) /
(activityTarget?.sleepTargetDuration ?? 0) *
360);
double sleepScoreProgress =
sleepDuration == 0 ? -1 : (healthData?.sleepScore ?? 0.0) * 3.6;
... ...
import 'dart:math' show cos, min, pi, sin;
import 'dart:math' show min, pi, asin;
import 'package:flutter/material.dart';
... ... @@ -48,7 +48,6 @@ class ProgressPainter extends CustomPainter {
var centerY = wh / 2;
var radius = wh / 2 - strokeWidth / 2;
double startAngle = 0;
var rect = Rect.fromCenter(
center: Offset(centerX, centerY),
width: wh - strokeWidth,
... ... @@ -63,7 +62,7 @@ class ProgressPainter extends CustomPainter {
}
var shader = SweepGradient(
startAngle: startAngle.toRadians(),
startAngle: 0.toRadians(),
endAngle: 360.toRadians(),
colors: reverse
? progressColor[colorRangeIndex].reversed.toList()
... ... @@ -82,11 +81,6 @@ class ProgressPainter extends CustomPainter {
..strokeCap = StrokeCap.butt
..style = PaintingStyle.stroke;
var startCapPosition = Offset(
centerX + radius * cos(startAngle.toRadians()),
centerY + radius * sin(startAngle.toRadians()),
);
canvas.drawArc(
rect,
0.toRadians(),
... ... @@ -94,7 +88,31 @@ class ProgressPainter extends CustomPainter {
false,
backgroundPaint,
);
if (sweepAngle >= 0) {
double capAngle = 0;
if (radius > 0) {
capAngle = asin((strokeWidth / 2) / radius) * 180 / pi;
}
double actualCapAngle = capAngle;
if (sweepAngle < 360) {
if (sweepAngle < 2 * capAngle) {
actualCapAngle = sweepAngle / 2;
}
} else {
actualCapAngle = 0;
}
double startAngle = actualCapAngle;
double drawnSweepAngle = sweepAngle;
if (sweepAngle < 360) {
drawnSweepAngle = sweepAngle - 2 * actualCapAngle;
if (drawnSweepAngle < 0) {
drawnSweepAngle = 0;
}
}
canvas.save();
// Move the canvas origin to the center
canvas.translate(centerX, centerY);
... ... @@ -111,9 +129,12 @@ class ProgressPainter extends CustomPainter {
canvas.translate(-centerX, -centerY);
if (sweepAngle < 360) {
canvas.save();
canvas.translate(centerX, centerY);
canvas.rotate(reverse ? -startAngle.toRadians() : startAngle.toRadians());
canvas.drawArc(
Rect.fromCenter(
center: startCapPosition,
center: Offset(radius, 0),
width: strokeWidth,
height: strokeWidth,
),
... ... @@ -122,76 +143,73 @@ class ProgressPainter extends CustomPainter {
true,
Paint()..color = progressColor[0].first,
);
canvas.drawRect(
Rect.fromCenter(
center: Offset(radius, 0),
width: strokeWidth,
height: 1,
),
Paint()..color = progressColor[0].first,
);
canvas.restore();
}
canvas.drawArc(
rect,
0.toRadians(),
reverse ? -startAngle.toRadians() : startAngle.toRadians(),
reverse
? -(startAngle + sweepAngle).toRadians()
: (startAngle + sweepAngle).toRadians(),
? -drawnSweepAngle.toRadians()
: drawnSweepAngle.toRadians(),
false,
paint,
);
if (sweepAngle < 360) {
if (sweepAngle != 360) {
final endAngle = startAngle + drawnSweepAngle;
canvas.save();
canvas.translate(centerX, centerY);
canvas.rotate(reverse ? -endAngle.toRadians() : endAngle.toRadians());
final endColor =
getColorAtAngle(sweepAngle, progressColor[colorRangeIndex]);
final bool shouldDrawShadow = sweepAngle > 360 || (sweepAngle > 355 && sweepAngle < 360);
if (shouldDrawShadow) {
//Draw arc shadow
var shadowPosition = Offset(
radius,
reverse ? -4 : 4,
);
final Paint shadowPaint = Paint()
..color = Colors.black.withOpacity(0.35)
..style = PaintingStyle.fill
..maskFilter = const MaskFilter.blur(BlurStyle.normal, 3);
canvas.drawCircle(shadowPosition, strokeWidth / 2, shadowPaint);
}
//Draw the ending arc
canvas.drawArc(
Rect.fromCenter(
center: Offset(radius, 0),
width: strokeWidth,
height: strokeWidth,
),
0,
reverse ? -180.toRadians() : 180.toRadians(),
true,
Paint()..color = endColor,
);
canvas.drawRect(
Rect.fromCenter(
center: startCapPosition,
center: Offset(radius, 0),
width: strokeWidth,
height: 1,
),
Paint()..color = progressColor[0].first,
Paint()..color = endColor,
);
canvas.restore();
}
canvas.translate(centerX, centerY);
if (sweepAngle < 360) {
final endCapRotate = 360 - sweepAngle;
canvas.rotate(
reverse ? endCapRotate.toRadians() : -endCapRotate.toRadians());
}
//0.1 is because the angle calculation is not accurate enough, so we need to go back a little bit.
var endCapPosition = Offset(
centerX + radius * cos((startAngle).toRadians()),
centerY + radius * sin((startAngle).toRadians()),
);
canvas.translate(-centerX, -centerY);
final endColor =
getColorAtAngle(sweepAngle, progressColor[colorRangeIndex]);
if (sweepAngle > 355) {
//Draw arc shadow
var shadowPosition = Offset(
centerX + radius * cos((startAngle).toRadians()),
centerY + (reverse ? -4 : 4) + radius * sin((startAngle).toRadians()),
);
final Paint shadowPaint = Paint()
..color = Colors.black.withOpacity(0.35)
..style = PaintingStyle.fill
..maskFilter = const MaskFilter.blur(BlurStyle.normal, 3);
canvas.drawCircle(shadowPosition, strokeWidth / 2, shadowPaint);
}
//Draw the ending arc
canvas.drawArc(
Rect.fromCenter(
center: endCapPosition,
width: strokeWidth,
height: strokeWidth,
),
0,
reverse ? -180.toRadians() : 180.toRadians(),
true,
Paint()..color = endColor,
);
canvas.drawRect(
Rect.fromCenter(
center: endCapPosition,
width: strokeWidth,
height: 1,
),
Paint()..color = endColor,
);
// // Restore the canvas to the saved state
canvas.restore();
}
... ...
... ... @@ -160,19 +160,6 @@ class V2HealthData {
return val;
}
/// 根据睡眠时长(秒)计算得分。
int sleepDurationScore() {
final duration = sleepDuration;
if (duration == null || duration <= 0) return 0;
final hours = duration / 3600.0;
if (hours >= 7 && hours <= 9) return 100;
if (hours > 9 && hours <= 10) return 80;
if (hours >= 6 && hours < 7) return 80;
if (hours >= 5 && hours < 6) return 60;
if (hours > 10) return 50;
return 30; // < 5h
}
sleepStateColor(BuildContext context) {
switch (sleepState) {
case 1:
... ... @@ -393,6 +380,7 @@ class V2ActivityTarget {
this.exercise,
this.createTime,
this.updateTime,
this.sleepTargetDuration,
});
final int? id;
... ... @@ -412,6 +400,7 @@ class V2ActivityTarget {
final int? createTime;
final int? updateTime;
final int? sleepTargetDuration;
factory V2ActivityTarget.fromJson(Map<String, dynamic> json) {
return V2ActivityTarget(
... ... @@ -423,6 +412,7 @@ class V2ActivityTarget {
exercise: _parseInt(json['exercise']),
createTime: _parseInt(json['create_time']),
updateTime: _parseInt(json['update_time']),
sleepTargetDuration: _parseInt(json['sleep_target_duration']),
);
}
... ... @@ -436,6 +426,9 @@ class V2ActivityTarget {
if (exercise != null) val['exercise'] = exercise;
if (createTime != null) val['create_time'] = createTime;
if (updateTime != null) val['update_time'] = updateTime;
if (sleepTargetDuration != null) {
val['sleep_target_duration'] = sleepTargetDuration;
}
return val;
}
}
... ...