Commit e969282fff44e2e1bb9ed51d287c08c9ae3fe0df

Authored by 常守达
1 parent 3bde5fcd

fix(today):睡眠卡片

@@ -18,6 +18,7 @@ class TodaySleepCard extends StatelessWidget { @@ -18,6 +18,7 @@ class TodaySleepCard extends StatelessWidget {
18 onTap: controller.toTrendSleepPage, 18 onTap: controller.toTrendSleepPage,
19 child: Obx(() { 19 child: Obx(() {
20 var healthData = controller.v2HealthData.value; 20 var healthData = controller.v2HealthData.value;
  21 + var activityTarget = controller.v2ActivityTarget.value;
21 22
22 int sleepDuration = healthData?.sleepDuration ?? 0; 23 int sleepDuration = healthData?.sleepDuration ?? 0;
23 int sleepHours = sleepDuration ~/ 3600; 24 int sleepHours = sleepDuration ~/ 3600;
@@ -31,9 +32,13 @@ class TodaySleepCard extends StatelessWidget { @@ -31,9 +32,13 @@ class TodaySleepCard extends StatelessWidget {
31 (healthData?.hrAvg == null || healthData?.hrAvg == 0) 32 (healthData?.hrAvg == null || healthData?.hrAvg == 0)
32 ? '-' 33 ? '-'
33 : '${healthData?.hrAvg}'; 34 : '${healthData?.hrAvg}';
34 - double sleepDurationProgress = sleepDuration == 0  
35 - ? -1  
36 - : ((healthData?.sleepDurationScore() ?? 0) * 3.60); 35 + double sleepDurationProgress =
  36 + (activityTarget?.sleepTargetDuration ?? 0) == 0 ||
  37 + sleepDuration == 0
  38 + ? -1
  39 + : ((healthData?.sleepDuration ?? 0) /
  40 + (activityTarget?.sleepTargetDuration ?? 0) *
  41 + 360);
37 double sleepScoreProgress = 42 double sleepScoreProgress =
38 sleepDuration == 0 ? -1 : (healthData?.sleepScore ?? 0.0) * 3.6; 43 sleepDuration == 0 ? -1 : (healthData?.sleepScore ?? 0.0) * 3.6;
39 44
1 -import 'dart:math' show cos, min, pi, sin; 1 +import 'dart:math' show min, pi, asin;
2 2
3 import 'package:flutter/material.dart'; 3 import 'package:flutter/material.dart';
4 4
@@ -48,7 +48,6 @@ class ProgressPainter extends CustomPainter { @@ -48,7 +48,6 @@ class ProgressPainter extends CustomPainter {
48 var centerY = wh / 2; 48 var centerY = wh / 2;
49 var radius = wh / 2 - strokeWidth / 2; 49 var radius = wh / 2 - strokeWidth / 2;
50 50
51 - double startAngle = 0;  
52 var rect = Rect.fromCenter( 51 var rect = Rect.fromCenter(
53 center: Offset(centerX, centerY), 52 center: Offset(centerX, centerY),
54 width: wh - strokeWidth, 53 width: wh - strokeWidth,
@@ -63,7 +62,7 @@ class ProgressPainter extends CustomPainter { @@ -63,7 +62,7 @@ class ProgressPainter extends CustomPainter {
63 } 62 }
64 63
65 var shader = SweepGradient( 64 var shader = SweepGradient(
66 - startAngle: startAngle.toRadians(), 65 + startAngle: 0.toRadians(),
67 endAngle: 360.toRadians(), 66 endAngle: 360.toRadians(),
68 colors: reverse 67 colors: reverse
69 ? progressColor[colorRangeIndex].reversed.toList() 68 ? progressColor[colorRangeIndex].reversed.toList()
@@ -82,11 +81,6 @@ class ProgressPainter extends CustomPainter { @@ -82,11 +81,6 @@ class ProgressPainter extends CustomPainter {
82 ..strokeCap = StrokeCap.butt 81 ..strokeCap = StrokeCap.butt
83 ..style = PaintingStyle.stroke; 82 ..style = PaintingStyle.stroke;
84 83
85 - var startCapPosition = Offset(  
86 - centerX + radius * cos(startAngle.toRadians()),  
87 - centerY + radius * sin(startAngle.toRadians()),  
88 - );  
89 -  
90 canvas.drawArc( 84 canvas.drawArc(
91 rect, 85 rect,
92 0.toRadians(), 86 0.toRadians(),
@@ -94,7 +88,31 @@ class ProgressPainter extends CustomPainter { @@ -94,7 +88,31 @@ class ProgressPainter extends CustomPainter {
94 false, 88 false,
95 backgroundPaint, 89 backgroundPaint,
96 ); 90 );
  91 +
97 if (sweepAngle >= 0) { 92 if (sweepAngle >= 0) {
  93 + double capAngle = 0;
  94 + if (radius > 0) {
  95 + capAngle = asin((strokeWidth / 2) / radius) * 180 / pi;
  96 + }
  97 +
  98 + double actualCapAngle = capAngle;
  99 + if (sweepAngle < 360) {
  100 + if (sweepAngle < 2 * capAngle) {
  101 + actualCapAngle = sweepAngle / 2;
  102 + }
  103 + } else {
  104 + actualCapAngle = 0;
  105 + }
  106 +
  107 + double startAngle = actualCapAngle;
  108 + double drawnSweepAngle = sweepAngle;
  109 + if (sweepAngle < 360) {
  110 + drawnSweepAngle = sweepAngle - 2 * actualCapAngle;
  111 + if (drawnSweepAngle < 0) {
  112 + drawnSweepAngle = 0;
  113 + }
  114 + }
  115 +
98 canvas.save(); 116 canvas.save();
99 // Move the canvas origin to the center 117 // Move the canvas origin to the center
100 canvas.translate(centerX, centerY); 118 canvas.translate(centerX, centerY);
@@ -111,9 +129,12 @@ class ProgressPainter extends CustomPainter { @@ -111,9 +129,12 @@ class ProgressPainter extends CustomPainter {
111 canvas.translate(-centerX, -centerY); 129 canvas.translate(-centerX, -centerY);
112 130
113 if (sweepAngle < 360) { 131 if (sweepAngle < 360) {
  132 + canvas.save();
  133 + canvas.translate(centerX, centerY);
  134 + canvas.rotate(reverse ? -startAngle.toRadians() : startAngle.toRadians());
114 canvas.drawArc( 135 canvas.drawArc(
115 Rect.fromCenter( 136 Rect.fromCenter(
116 - center: startCapPosition, 137 + center: Offset(radius, 0),
117 width: strokeWidth, 138 width: strokeWidth,
118 height: strokeWidth, 139 height: strokeWidth,
119 ), 140 ),
@@ -122,76 +143,73 @@ class ProgressPainter extends CustomPainter { @@ -122,76 +143,73 @@ class ProgressPainter extends CustomPainter {
122 true, 143 true,
123 Paint()..color = progressColor[0].first, 144 Paint()..color = progressColor[0].first,
124 ); 145 );
  146 + canvas.drawRect(
  147 + Rect.fromCenter(
  148 + center: Offset(radius, 0),
  149 + width: strokeWidth,
  150 + height: 1,
  151 + ),
  152 + Paint()..color = progressColor[0].first,
  153 + );
  154 + canvas.restore();
125 } 155 }
  156 +
126 canvas.drawArc( 157 canvas.drawArc(
127 rect, 158 rect,
128 - 0.toRadians(), 159 + reverse ? -startAngle.toRadians() : startAngle.toRadians(),
129 reverse 160 reverse
130 - ? -(startAngle + sweepAngle).toRadians()  
131 - : (startAngle + sweepAngle).toRadians(), 161 + ? -drawnSweepAngle.toRadians()
  162 + : drawnSweepAngle.toRadians(),
132 false, 163 false,
133 paint, 164 paint,
134 ); 165 );
135 - if (sweepAngle < 360) { 166 +
  167 + if (sweepAngle != 360) {
  168 + final endAngle = startAngle + drawnSweepAngle;
  169 + canvas.save();
  170 + canvas.translate(centerX, centerY);
  171 + canvas.rotate(reverse ? -endAngle.toRadians() : endAngle.toRadians());
  172 +
  173 + final endColor =
  174 + getColorAtAngle(sweepAngle, progressColor[colorRangeIndex]);
  175 +
  176 + final bool shouldDrawShadow = sweepAngle > 360 || (sweepAngle > 355 && sweepAngle < 360);
  177 + if (shouldDrawShadow) {
  178 + //Draw arc shadow
  179 + var shadowPosition = Offset(
  180 + radius,
  181 + reverse ? -4 : 4,
  182 + );
  183 + final Paint shadowPaint = Paint()
  184 + ..color = Colors.black.withOpacity(0.35)
  185 + ..style = PaintingStyle.fill
  186 + ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 3);
  187 + canvas.drawCircle(shadowPosition, strokeWidth / 2, shadowPaint);
  188 + }
  189 +
  190 + //Draw the ending arc
  191 + canvas.drawArc(
  192 + Rect.fromCenter(
  193 + center: Offset(radius, 0),
  194 + width: strokeWidth,
  195 + height: strokeWidth,
  196 + ),
  197 + 0,
  198 + reverse ? -180.toRadians() : 180.toRadians(),
  199 + true,
  200 + Paint()..color = endColor,
  201 + );
136 canvas.drawRect( 202 canvas.drawRect(
137 Rect.fromCenter( 203 Rect.fromCenter(
138 - center: startCapPosition, 204 + center: Offset(radius, 0),
139 width: strokeWidth, 205 width: strokeWidth,
140 height: 1, 206 height: 1,
141 ), 207 ),
142 - Paint()..color = progressColor[0].first, 208 + Paint()..color = endColor,
143 ); 209 );
  210 + canvas.restore();
144 } 211 }
145 212
146 - canvas.translate(centerX, centerY);  
147 - if (sweepAngle < 360) {  
148 - final endCapRotate = 360 - sweepAngle;  
149 - canvas.rotate(  
150 - reverse ? endCapRotate.toRadians() : -endCapRotate.toRadians());  
151 - }  
152 - //0.1 is because the angle calculation is not accurate enough, so we need to go back a little bit.  
153 - var endCapPosition = Offset(  
154 - centerX + radius * cos((startAngle).toRadians()),  
155 - centerY + radius * sin((startAngle).toRadians()),  
156 - );  
157 -  
158 - canvas.translate(-centerX, -centerY);  
159 - final endColor =  
160 - getColorAtAngle(sweepAngle, progressColor[colorRangeIndex]);  
161 - if (sweepAngle > 355) {  
162 - //Draw arc shadow  
163 - var shadowPosition = Offset(  
164 - centerX + radius * cos((startAngle).toRadians()),  
165 - centerY + (reverse ? -4 : 4) + radius * sin((startAngle).toRadians()),  
166 - );  
167 - final Paint shadowPaint = Paint()  
168 - ..color = Colors.black.withOpacity(0.35)  
169 - ..style = PaintingStyle.fill  
170 - ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 3);  
171 - canvas.drawCircle(shadowPosition, strokeWidth / 2, shadowPaint);  
172 - }  
173 -  
174 - //Draw the ending arc  
175 - canvas.drawArc(  
176 - Rect.fromCenter(  
177 - center: endCapPosition,  
178 - width: strokeWidth,  
179 - height: strokeWidth,  
180 - ),  
181 - 0,  
182 - reverse ? -180.toRadians() : 180.toRadians(),  
183 - true,  
184 - Paint()..color = endColor,  
185 - );  
186 - canvas.drawRect(  
187 - Rect.fromCenter(  
188 - center: endCapPosition,  
189 - width: strokeWidth,  
190 - height: 1,  
191 - ),  
192 - Paint()..color = endColor,  
193 - );  
194 -  
195 // // Restore the canvas to the saved state 213 // // Restore the canvas to the saved state
196 canvas.restore(); 214 canvas.restore();
197 } 215 }
@@ -160,19 +160,6 @@ class V2HealthData { @@ -160,19 +160,6 @@ class V2HealthData {
160 return val; 160 return val;
161 } 161 }
162 162
163 - /// 根据睡眠时长(秒)计算得分。  
164 - int sleepDurationScore() {  
165 - final duration = sleepDuration;  
166 - if (duration == null || duration <= 0) return 0;  
167 - final hours = duration / 3600.0;  
168 - if (hours >= 7 && hours <= 9) return 100;  
169 - if (hours > 9 && hours <= 10) return 80;  
170 - if (hours >= 6 && hours < 7) return 80;  
171 - if (hours >= 5 && hours < 6) return 60;  
172 - if (hours > 10) return 50;  
173 - return 30; // < 5h  
174 - }  
175 -  
176 sleepStateColor(BuildContext context) { 163 sleepStateColor(BuildContext context) {
177 switch (sleepState) { 164 switch (sleepState) {
178 case 1: 165 case 1:
@@ -393,6 +380,7 @@ class V2ActivityTarget { @@ -393,6 +380,7 @@ class V2ActivityTarget {
393 this.exercise, 380 this.exercise,
394 this.createTime, 381 this.createTime,
395 this.updateTime, 382 this.updateTime,
  383 + this.sleepTargetDuration,
396 }); 384 });
397 385
398 final int? id; 386 final int? id;
@@ -412,6 +400,7 @@ class V2ActivityTarget { @@ -412,6 +400,7 @@ class V2ActivityTarget {
412 400
413 final int? createTime; 401 final int? createTime;
414 final int? updateTime; 402 final int? updateTime;
  403 + final int? sleepTargetDuration;
415 404
416 factory V2ActivityTarget.fromJson(Map<String, dynamic> json) { 405 factory V2ActivityTarget.fromJson(Map<String, dynamic> json) {
417 return V2ActivityTarget( 406 return V2ActivityTarget(
@@ -423,6 +412,7 @@ class V2ActivityTarget { @@ -423,6 +412,7 @@ class V2ActivityTarget {
423 exercise: _parseInt(json['exercise']), 412 exercise: _parseInt(json['exercise']),
424 createTime: _parseInt(json['create_time']), 413 createTime: _parseInt(json['create_time']),
425 updateTime: _parseInt(json['update_time']), 414 updateTime: _parseInt(json['update_time']),
  415 + sleepTargetDuration: _parseInt(json['sleep_target_duration']),
426 ); 416 );
427 } 417 }
428 418
@@ -436,6 +426,9 @@ class V2ActivityTarget { @@ -436,6 +426,9 @@ class V2ActivityTarget {
436 if (exercise != null) val['exercise'] = exercise; 426 if (exercise != null) val['exercise'] = exercise;
437 if (createTime != null) val['create_time'] = createTime; 427 if (createTime != null) val['create_time'] = createTime;
438 if (updateTime != null) val['update_time'] = updateTime; 428 if (updateTime != null) val['update_time'] = updateTime;
  429 + if (sleepTargetDuration != null) {
  430 + val['sleep_target_duration'] = sleepTargetDuration;
  431 + }
439 return val; 432 return val;
440 } 433 }
441 } 434 }