Commit bb436210b295bf09830aae0eb88f152e04c24aec

Authored by 刘宏哲
1 parent c14c1cfc

feat(app): update ui

@@ -483,7 +483,7 @@ class _MonthEnergyTrendCardState extends State<_MonthEnergyTrendCard> { @@ -483,7 +483,7 @@ class _MonthEnergyTrendCardState extends State<_MonthEnergyTrendCard> {
483 const SizedBox(width: 2), 483 const SizedBox(width: 2),
484 ], 484 ],
485 Text( 485 Text(
486 - _comparisonText(comparisonPercent), 486 + _comparisonText(context, comparisonPercent),
487 style: TextStyle( 487 style: TextStyle(
488 color: ActivityBurnMonthReportView._h2, 488 color: ActivityBurnMonthReportView._h2,
489 fontSize: 12, 489 fontSize: 12,
@@ -577,13 +577,15 @@ class _MonthEnergyTrendCardState extends State<_MonthEnergyTrendCard> { @@ -577,13 +577,15 @@ class _MonthEnergyTrendCardState extends State<_MonthEnergyTrendCard> {
577 widget.report.days.any((day) => (day.activeEnergy?.value ?? 0) > 0) || 577 widget.report.days.any((day) => (day.activeEnergy?.value ?? 0) > 0) ||
578 widget.report.activeEnergyGoal > 0; 578 widget.report.activeEnergyGoal > 0;
579 579
580 - String _comparisonText(int? percent) { 580 + String _comparisonText(BuildContext context, int? percent) {
581 if (percent == null || !widget.report.hasData) { 581 if (percent == null || !widget.report.hasData) {
582 - return '比上月-'; 582 + return context.l10n.activityComparedLastMonthUnavailable;
583 } 583 }
584 - if (percent == 0) return '与上月持平';  
585 - final direction = percent > 0 ? '多' : '少';  
586 - return '比上月$direction${percent.abs()}%'; 584 + if (percent == 0) return context.l10n.activitySameAsLastMonth;
  585 + final absPercent = percent.abs();
  586 + return percent > 0
  587 + ? context.l10n.activityMoreThanLastMonth(absPercent)
  588 + : context.l10n.activityLessThanLastMonth(absPercent);
587 } 589 }
588 590
589 double _barToY(int value, double maxY) { 591 double _barToY(int value, double maxY) {
@@ -438,6 +438,7 @@ class _StressStatusRingPainter extends CustomPainter { @@ -438,6 +438,7 @@ class _StressStatusRingPainter extends CustomPainter {
438 return; 438 return;
439 } 439 }
440 440
  441 + final activeSegmentIndex = stressState.segmentIndex;
441 const paintOrder = [3, 2, 1, 0]; 442 const paintOrder = [3, 2, 1, 0];
442 for (final i in paintOrder) { 443 for (final i in paintOrder) {
443 final visualSpec = _arcSpecs[i].withGap(_arcGapDegrees); 444 final visualSpec = _arcSpecs[i].withGap(_arcGapDegrees);
@@ -451,7 +452,9 @@ class _StressStatusRingPainter extends CustomPainter { @@ -451,7 +452,9 @@ class _StressStatusRingPainter extends CustomPainter {
451 borderPaint, 452 borderPaint,
452 ); 453 );
453 454
454 - segmentPaint.color = _segmentColors[i].withValues(alpha: 0.42); 455 + segmentPaint.color = _segmentColors[i].withValues(
  456 + alpha: i == activeSegmentIndex ? 1 : 0.42,
  457 + );
455 canvas.drawArc( 458 canvas.drawArc(
456 rect, 459 rect,
457 startAngle, 460 startAngle,
@@ -461,7 +464,7 @@ class _StressStatusRingPainter extends CustomPainter { @@ -461,7 +464,7 @@ class _StressStatusRingPainter extends CustomPainter {
461 ); 464 );
462 } 465 }
463 466
464 - final segmentIndex = stressState.segmentIndex; 467 + final segmentIndex = activeSegmentIndex;
465 if (segmentIndex == null) return; 468 if (segmentIndex == null) return;
466 final spec = _arcSpecs[segmentIndex].withGap(_arcGapDegrees); 469 final spec = _arcSpecs[segmentIndex].withGap(_arcGapDegrees);
467 final indicatorAngle = 470 final indicatorAngle =
@@ -132,11 +132,19 @@ class HomeController extends GetxController { @@ -132,11 +132,19 @@ class HomeController extends GetxController {
132 return true; 132 return true;
133 } 133 }
134 134
135 - void changeTab(int index) { 135 + void changeTab(
  136 + int index, {
  137 + TrendEntrySource trendEntrySource = TrendEntrySource.bottomTab,
  138 + }) {
136 final previousIndex = selectedIndex.value; 139 final previousIndex = selectedIndex.value;
137 selectedIndex.value = index; 140 selectedIndex.value = index;
138 - if (index == trendTabIndex && previousIndex != trendTabIndex) {  
139 - Get.find<TrendController>().markPageVisible(); 141 + if (index == trendTabIndex) {
  142 + final trendController = Get.find<TrendController>();
  143 + if (previousIndex != trendTabIndex) {
  144 + trendController.markPageVisible(source: trendEntrySource);
  145 + } else {
  146 + trendController.updateEntrySource(trendEntrySource);
  147 + }
140 } else if (previousIndex == trendTabIndex && index != trendTabIndex) { 148 } else if (previousIndex == trendTabIndex && index != trendTabIndex) {
141 Get.find<TrendController>().markPageHidden(); 149 Get.find<TrendController>().markPageHidden();
142 } 150 }
@@ -161,7 +169,10 @@ class HomeController extends GetxController { @@ -161,7 +169,10 @@ class HomeController extends GetxController {
161 if (fromTodayTab) { 169 if (fromTodayTab) {
162 Get.find<TrendController>().selectSelf(); 170 Get.find<TrendController>().selectSelf();
163 } 171 }
164 - changeTab(trendTabIndex); 172 + changeTab(
  173 + trendTabIndex,
  174 + trendEntrySource: TrendEntrySource.jump,
  175 + );
165 } 176 }
166 177
167 int _dateKey(DateTime date) => 178 int _dateKey(DateTime date) =>
@@ -273,7 +284,10 @@ class HomeController extends GetxController { @@ -273,7 +284,10 @@ class HomeController extends GetxController {
273 if (trendType != null) { 284 if (trendType != null) {
274 openTrend(trendType, fromTodayTab: false); 285 openTrend(trendType, fromTodayTab: false);
275 } else { 286 } else {
276 - changeTab(trendTabIndex); 287 + changeTab(
  288 + trendTabIndex,
  289 + trendEntrySource: TrendEntrySource.jump,
  290 + );
277 } 291 }
278 break; 292 break;
279 case 'friends': 293 case 'friends':
@@ -20,6 +20,11 @@ enum TrendType { @@ -20,6 +20,11 @@ enum TrendType {
20 int get tabIndex => index; 20 int get tabIndex => index;
21 } 21 }
22 22
  23 +enum TrendEntrySource {
  24 + bottomTab,
  25 + jump,
  26 +}
  27 +
23 /// 趋势页顶层 Controller,仅负责: 28 /// 趋势页顶层 Controller,仅负责:
24 /// 顶层 HRV / 活动 / 睡眠 类型切换 (selectedTypeIndex) 29 /// 顶层 HRV / 活动 / 睡眠 类型切换 (selectedTypeIndex)
25 class TrendController extends GetxController with HealthTrendControl { 30 class TrendController extends GetxController with HealthTrendControl {
@@ -28,6 +33,7 @@ class TrendController extends GetxController with HealthTrendControl { @@ -28,6 +33,7 @@ class TrendController extends GetxController with HealthTrendControl {
28 final FriendApi _friendApi; 33 final FriendApi _friendApi;
29 bool _isPageVisible = false; 34 bool _isPageVisible = false;
30 final refreshToken = 0.obs; 35 final refreshToken = 0.obs;
  36 + final entrySource = TrendEntrySource.bottomTab.obs;
31 37
32 // 当前查看的用户。null 表示查看自己;非 null 表示查看指定用户。 38 // 当前查看的用户。null 表示查看自己;非 null 表示查看指定用户。
33 final targetUserId = RxnInt(); 39 final targetUserId = RxnInt();
@@ -141,7 +147,17 @@ class TrendController extends GetxController with HealthTrendControl { @@ -141,7 +147,17 @@ class TrendController extends GetxController with HealthTrendControl {
141 ); 147 );
142 } 148 }
143 149
144 - void markPageVisible() { 150 + void updateEntrySource(TrendEntrySource source) {
  151 + entrySource.value = source;
  152 + }
  153 +
  154 + void markPageVisible({
  155 + TrendEntrySource source = TrendEntrySource.bottomTab,
  156 + }) {
  157 + updateEntrySource(source);
  158 + if (source == TrendEntrySource.bottomTab) {
  159 + _resetQueryForBottomTabEntry();
  160 + }
145 if (_isPageVisible) return; 161 if (_isPageVisible) return;
146 _isPageVisible = true; 162 _isPageVisible = true;
147 refreshToken.value++; 163 refreshToken.value++;
@@ -152,6 +168,11 @@ class TrendController extends GetxController with HealthTrendControl { @@ -152,6 +168,11 @@ class TrendController extends GetxController with HealthTrendControl {
152 _isPageVisible = false; 168 _isPageVisible = false;
153 } 169 }
154 170
  171 + void _resetQueryForBottomTabEntry() {
  172 + changeType(TrendType.hrv.tabIndex);
  173 + changeQuery(ReportPeriod.week, DateTime.now());
  174 + }
  175 +
155 void _trackEnterPage() { 176 void _trackEnterPage() {
156 HealthTrendAnalytics.trackEnterPage( 177 HealthTrendAnalytics.trackEnterPage(
157 selectedTypeIndex.value, 178 selectedTypeIndex.value,
@@ -36,7 +36,7 @@ class HomePage extends GetView<HomeController> { @@ -36,7 +36,7 @@ class HomePage extends GetView<HomeController> {
36 bottomNavigationBar: Obx( 36 bottomNavigationBar: Obx(
37 () => DfTabBar( 37 () => DfTabBar(
38 selectedIndex: controller.selectedIndex.value, 38 selectedIndex: controller.selectedIndex.value,
39 - onTap: controller.changeTab, 39 + onTap: (index) => controller.changeTab(index),
40 ), 40 ),
41 ), 41 ),
42 ), 42 ),
@@ -77,6 +77,9 @@ class _HomeTrendHeader extends GetView<TrendController> { @@ -77,6 +77,9 @@ class _HomeTrendHeader extends GetView<TrendController> {
77 avatarUrl: friendAvatar?.trim().isNotEmpty == true 77 avatarUrl: friendAvatar?.trim().isNotEmpty == true
78 ? friendAvatar 78 ? friendAvatar
79 : selfAvatar, 79 : selfAvatar,
  80 + onTap: controller.canSwitchFriend
  81 + ? controller.showFriendListBottomSheet
  82 + : null,
80 ); 83 );
81 }), 84 }),
82 Obx( 85 Obx(
@@ -104,14 +107,15 @@ class _HomeTrendHeader extends GetView<TrendController> { @@ -104,14 +107,15 @@ class _HomeTrendHeader extends GetView<TrendController> {
104 } 107 }
105 108
106 class _TrendHeaderAvatar extends StatelessWidget { 109 class _TrendHeaderAvatar extends StatelessWidget {
107 - const _TrendHeaderAvatar({this.avatarUrl}); 110 + const _TrendHeaderAvatar({this.avatarUrl, this.onTap});
108 111
109 final String? avatarUrl; 112 final String? avatarUrl;
  113 + final VoidCallback? onTap;
110 114
111 @override 115 @override
112 Widget build(BuildContext context) { 116 Widget build(BuildContext context) {
113 final imageUrl = avatarUrl?.trim(); 117 final imageUrl = avatarUrl?.trim();
114 - return Container( 118 + final avatar = Container(
115 width: 36, 119 width: 36,
116 height: 36, 120 height: 36,
117 decoration: ShapeDecoration( 121 decoration: ShapeDecoration(
@@ -128,6 +132,18 @@ class _TrendHeaderAvatar extends StatelessWidget { @@ -128,6 +132,18 @@ class _TrendHeaderAvatar extends StatelessWidget {
128 ), 132 ),
129 child: imageUrl?.isNotEmpty == true ? null : const _AvatarFallback(), 133 child: imageUrl?.isNotEmpty == true ? null : const _AvatarFallback(),
130 ); 134 );
  135 +
  136 + if (onTap == null) return avatar;
  137 +
  138 + return GestureDetector(
  139 + behavior: HitTestBehavior.opaque,
  140 + onTap: onTap,
  141 + child: SizedBox(
  142 + width: 44,
  143 + height: 44,
  144 + child: Center(child: avatar),
  145 + ),
  146 + );
131 } 147 }
132 } 148 }
133 149
@@ -425,7 +425,7 @@ class _TrendMetric extends StatelessWidget { @@ -425,7 +425,7 @@ class _TrendMetric extends StatelessWidget {
425 crossAxisAlignment: CrossAxisAlignment.start, 425 crossAxisAlignment: CrossAxisAlignment.start,
426 children: [ 426 children: [
427 Text(label, 427 Text(label,
428 - style: const TextStyle(color: Color(0xFFB0B0B6), fontSize: 11)), 428 + style: const TextStyle(color: Color(0xFF78787D), fontSize: 11)),
429 const SizedBox(height: 3), 429 const SizedBox(height: 3),
430 Row( 430 Row(
431 crossAxisAlignment: CrossAxisAlignment.end, 431 crossAxisAlignment: CrossAxisAlignment.end,
@@ -497,7 +497,7 @@ class _TrendMetric extends StatelessWidget { @@ -497,7 +497,7 @@ class _TrendMetric extends StatelessWidget {
497 497
498 Color _comparisonColor(int? difference) { 498 Color _comparisonColor(int? difference) {
499 if (difference == null || difference == 0) { 499 if (difference == null || difference == 0) {
500 - return const Color(0xFFB0B0B6); 500 + return const Color(0xFF78787D);
501 } 501 }
502 return _isGoodChange(difference) 502 return _isGoodChange(difference)
503 ? const Color(0xFF3BD49D) 503 ? const Color(0xFF3BD49D)
@@ -675,7 +675,7 @@ class _DistributionCard extends StatelessWidget { @@ -675,7 +675,7 @@ class _DistributionCard extends StatelessWidget {
675 Text( 675 Text(
676 context.l10n.hrvValidDays, 676 context.l10n.hrvValidDays,
677 style: const TextStyle( 677 style: const TextStyle(
678 - color: Color(0xFFB0B0B6), 678 + color: Color(0xFF78787D),
679 fontSize: 12, 679 fontSize: 12,
680 ), 680 ),
681 ), 681 ),
@@ -801,14 +801,14 @@ class _DistributionItem extends StatelessWidget { @@ -801,14 +801,14 @@ class _DistributionItem extends StatelessWidget {
801 style: TextStyle( 801 style: TextStyle(
802 color: report.hasData 802 color: report.hasData
803 ? const Color(0xFF0F0F11) 803 ? const Color(0xFF0F0F11)
804 - : const Color(0xFFB0B0B6), 804 + : const Color(0xFF78787D),
805 fontSize: report.hasData ? 20 : 18, 805 fontSize: report.hasData ? 20 : 18,
806 fontWeight: FontWeight.w500, 806 fontWeight: FontWeight.w500,
807 height: 1.2)), 807 height: 1.2)),
808 const SizedBox(height: 1), 808 const SizedBox(height: 1),
809 Text('$percent%', 809 Text('$percent%',
810 style: const TextStyle( 810 style: const TextStyle(
811 - color: Color(0xFFB0B0B6), 811 + color: Color(0xFF78787D),
812 fontSize: 12, 812 fontSize: 12,
813 height: 1.2, 813 height: 1.2,
814 )), 814 )),
@@ -860,7 +860,7 @@ class _ExtremeHrv extends StatelessWidget { @@ -860,7 +860,7 @@ class _ExtremeHrv extends StatelessWidget {
860 const SizedBox(height: 2), 860 const SizedBox(height: 2),
861 Text( 861 Text(
862 day == null ? '-月-日' : reportMonthDay(day!.date), 862 day == null ? '-月-日' : reportMonthDay(day!.date),
863 - style: const TextStyle(color: Color(0xFFB0B0B6), fontSize: 12), 863 + style: const TextStyle(color: Color(0xFF78787D), fontSize: 12),
864 ), 864 ),
865 ], 865 ],
866 ); 866 );
@@ -296,12 +296,12 @@ class _MonthExtreme extends StatelessWidget { @@ -296,12 +296,12 @@ class _MonthExtreme extends StatelessWidget {
296 final separator = 296 final separator =
297 Localizations.localeOf(context).languageCode == 'zh' ? ',' : ', '; 297 Localizations.localeOf(context).languageCode == 'zh' ? ',' : ', ';
298 final value = months.isEmpty 298 final value = months.isEmpty
299 - ? '-月' 299 + ? context.l10n.hrvEmptyMonthPlaceholder
300 : months.map((month) => reportMonth(month)).join(separator); 300 : months.map((month) => reportMonth(month)).join(separator);
301 return Column( 301 return Column(
302 crossAxisAlignment: CrossAxisAlignment.start, 302 crossAxisAlignment: CrossAxisAlignment.start,
303 children: [ 303 children: [
304 - Text(label, style: const TextStyle(color: _h3, fontSize: 11)), 304 + Text(label, style: const TextStyle(color: _h2, fontSize: 11)),
305 const SizedBox(height: 5), 305 const SizedBox(height: 5),
306 Text( 306 Text(
307 value, 307 value,
@@ -317,13 +317,19 @@ class _StressAxisLabels extends StatelessWidget { @@ -317,13 +317,19 @@ class _StressAxisLabels extends StatelessWidget {
317 317
318 @override 318 @override
319 Widget build(BuildContext context) { 319 Widget build(BuildContext context) {
320 - return const SizedBox( 320 + return SizedBox(
321 width: 14, 321 width: 14,
322 child: Column( 322 child: Column(
323 mainAxisAlignment: MainAxisAlignment.spaceBetween, 323 mainAxisAlignment: MainAxisAlignment.spaceBetween,
324 children: [ 324 children: [
325 - RotatedBox(quarterTurns: 1, child: _StressAxisText('轻松')),  
326 - RotatedBox(quarterTurns: 1, child: _StressAxisText('压力大')), 325 + RotatedBox(
  326 + quarterTurns: 1,
  327 + child: _StressAxisText(context.l10n.hrvRelaxedAxisLabel),
  328 + ),
  329 + RotatedBox(
  330 + quarterTurns: 1,
  331 + child: _StressAxisText(context.l10n.hrvStressedAxisLabel),
  332 + ),
327 ], 333 ],
328 ), 334 ),
329 ); 335 );
@@ -402,7 +408,7 @@ class _YearDistributionCard extends StatelessWidget { @@ -402,7 +408,7 @@ class _YearDistributionCard extends StatelessWidget {
402 crossAxisAlignment: CrossAxisAlignment.start, 408 crossAxisAlignment: CrossAxisAlignment.start,
403 children: [ 409 children: [
404 Text(context.l10n.hrvValidDays, 410 Text(context.l10n.hrvValidDays,
405 - style: const TextStyle(color: _h3, fontSize: 11)), 411 + style: const TextStyle(color: _h2, fontSize: 11)),
406 const SizedBox(height: 3), 412 const SizedBox(height: 3),
407 _Number( 413 _Number(
408 value: '${report.validDays}', 414 value: '${report.validDays}',
@@ -601,12 +607,14 @@ class _DateExtreme extends StatelessWidget { @@ -601,12 +607,14 @@ class _DateExtreme extends StatelessWidget {
601 Localizations.localeOf(context).languageCode == 'zh' ? ',' : ', '; 607 Localizations.localeOf(context).languageCode == 'zh' ? ',' : ', ';
602 final value = [ 608 final value = [
603 for (var i = 0; i < 2; i++) 609 for (var i = 0; i < 2; i++)
604 - i < days.length ? reportMonthDay(days[i].date) : '-月-日', 610 + i < days.length
  611 + ? reportMonthDay(days[i].date)
  612 + : context.l10n.hrvEmptyMonthDayPlaceholder,
605 ].join(separator); 613 ].join(separator);
606 return Column( 614 return Column(
607 crossAxisAlignment: CrossAxisAlignment.start, 615 crossAxisAlignment: CrossAxisAlignment.start,
608 children: [ 616 children: [
609 - Text(label, style: const TextStyle(color: _h3, fontSize: 10)), 617 + Text(label, style: const TextStyle(color: _h2, fontSize: 10)),
610 const SizedBox(height: 6), 618 const SizedBox(height: 6),
611 Text(value, 619 Text(value,
612 style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600)), 620 style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600)),
@@ -644,10 +652,10 @@ class _LevelItem extends StatelessWidget { @@ -644,10 +652,10 @@ class _LevelItem extends StatelessWidget {
644 ? '$count${context.l10n.reportUnitDay}' 652 ? '$count${context.l10n.reportUnitDay}'
645 : context.l10n.reportWaitingForData, 653 : context.l10n.reportWaitingForData,
646 style: TextStyle( 654 style: TextStyle(
647 - color: report.hasData ? _h1 : _h3, 655 + color: report.hasData ? _h1 : _h2,
648 fontSize: report.hasData ? 19 : 13, 656 fontSize: report.hasData ? 19 : 13,
649 fontWeight: FontWeight.w500)), 657 fontWeight: FontWeight.w500)),
650 - Text('$percent%', style: const TextStyle(color: _h3, fontSize: 9)), 658 + Text('$percent%', style: const TextStyle(color: _h2, fontSize: 9)),
651 ], 659 ],
652 ); 660 );
653 } 661 }
1 import 'package:doublefeel_flutter/app/widget/premium_benefit_list_view.dart'; 1 import 'package:doublefeel_flutter/app/widget/premium_benefit_list_view.dart';
  2 +import 'package:doublefeel_flutter/core/util/size_extensions.dart';
2 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; 3 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
3 import 'package:doublefeel_flutter/r.dart'; 4 import 'package:doublefeel_flutter/r.dart';
4 import 'package:flutter/material.dart'; 5 import 'package:flutter/material.dart';
@@ -43,7 +44,7 @@ class PurchaseView extends GetView<PurchaseController> { @@ -43,7 +44,7 @@ class PurchaseView extends GetView<PurchaseController> {
43 children: [ 44 children: [
44 const _HeroHeader(), 45 const _HeroHeader(),
45 Padding( 46 Padding(
46 - padding: const EdgeInsets.only(left: 18, top: 9), 47 + padding: EdgeInsets.only(left: 18, top: 9.h),
47 child: Text( 48 child: Text(
48 context.l10n.purchaseHeroTitle, 49 context.l10n.purchaseHeroTitle,
49 style: const TextStyle( 50 style: const TextStyle(
@@ -99,7 +100,7 @@ class _HeroHeader extends StatelessWidget { @@ -99,7 +100,7 @@ class _HeroHeader extends StatelessWidget {
99 @override 100 @override
100 Widget build(BuildContext context) { 101 Widget build(BuildContext context) {
101 return SizedBox( 102 return SizedBox(
102 - height: 320, 103 + height: 320.h,
103 width: double.infinity, 104 width: double.infinity,
104 child: Image.asset( 105 child: Image.asset(
105 R.assetsImagesPurchaseTopBg, 106 R.assetsImagesPurchaseTopBg,
@@ -27,13 +27,15 @@ class SleepQualityDialog extends StatelessWidget { @@ -27,13 +27,15 @@ class SleepQualityDialog extends StatelessWidget {
27 Widget build(BuildContext context) { 27 Widget build(BuildContext context) {
28 return SafeArea( 28 return SafeArea(
29 top: false, 29 top: false,
  30 + bottom: false,
30 child: Container( 31 child: Container(
31 - height: 291,  
32 decoration: const BoxDecoration( 32 decoration: const BoxDecoration(
33 color: _bg, 33 color: _bg,
34 borderRadius: BorderRadius.vertical(top: Radius.circular(20)), 34 borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
35 ), 35 ),
  36 + padding: const EdgeInsets.only(bottom: 50),
36 child: Column( 37 child: Column(
  38 + mainAxisSize: MainAxisSize.min,
37 children: [ 39 children: [
38 SizedBox( 40 SizedBox(
39 height: 56, 41 height: 56,
@@ -100,16 +102,6 @@ class SleepQualityDialog extends StatelessWidget { @@ -100,16 +102,6 @@ class SleepQualityDialog extends StatelessWidget {
100 ], 102 ],
101 ), 103 ),
102 ), 104 ),
103 - const Spacer(),  
104 - Container(  
105 - width: 134,  
106 - height: 5,  
107 - margin: const EdgeInsets.only(bottom: 8),  
108 - decoration: BoxDecoration(  
109 - color: SleepReportTextStyles.titleColor,  
110 - borderRadius: BorderRadius.circular(100),  
111 - ),  
112 - ),  
113 ], 105 ],
114 ), 106 ),
115 ), 107 ),
@@ -331,6 +331,10 @@ @@ -331,6 +331,10 @@
331 "hrvMoreStressed": "More stressed", 331 "hrvMoreStressed": "More stressed",
332 "hrvStressDistribution": "Stress Distribution", 332 "hrvStressDistribution": "Stress Distribution",
333 "hrvDailyStressDistribution": "Daily Stress Distribution", 333 "hrvDailyStressDistribution": "Daily Stress Distribution",
  334 + "hrvRelaxedAxisLabel": "Relaxed",
  335 + "hrvStressedAxisLabel": "Stressed",
  336 + "hrvEmptyMonthPlaceholder": "-",
  337 + "hrvEmptyMonthDayPlaceholder": "-",
334 "hrvValidDays": "Valid HRV days", 338 "hrvValidDays": "Valid HRV days",
335 "hrvLowest": "Lowest HRV", 339 "hrvLowest": "Lowest HRV",
336 "hrvHighest": "Highest HRV", 340 "hrvHighest": "Highest HRV",
@@ -354,6 +358,10 @@ @@ -354,6 +358,10 @@
354 "activityComparedLastWeek": "34% less than last week", 358 "activityComparedLastWeek": "34% less than last week",
355 "activityComparedLastMonth": "34% less than last month", 359 "activityComparedLastMonth": "34% less than last month",
356 "activityComparedUnavailable": "Compared with last week: -", 360 "activityComparedUnavailable": "Compared with last week: -",
  361 + "activityComparedLastMonthUnavailable": "Compared with last month: -",
  362 + "activitySameAsLastMonth": "Same as last month",
  363 + "activityMoreThanLastMonth": "{percent}% more than last month",
  364 + "activityLessThanLastMonth": "{percent}% less than last month",
357 "activityMove": "Move", 365 "activityMove": "Move",
358 "activityExercise": "Exercise", 366 "activityExercise": "Exercise",
359 "activityStand": "Stand", 367 "activityStand": "Stand",
@@ -503,6 +503,10 @@ @@ -503,6 +503,10 @@
503 "hrvMoreStressed": "压力较大", 503 "hrvMoreStressed": "压力较大",
504 "hrvStressDistribution": "压力分布", 504 "hrvStressDistribution": "压力分布",
505 "hrvDailyStressDistribution": "每日压力分布", 505 "hrvDailyStressDistribution": "每日压力分布",
  506 + "hrvRelaxedAxisLabel": "轻松",
  507 + "hrvStressedAxisLabel": "压力大",
  508 + "hrvEmptyMonthPlaceholder": "-月",
  509 + "hrvEmptyMonthDayPlaceholder": "-月-日",
506 "hrvValidDays": "HRV有效天数", 510 "hrvValidDays": "HRV有效天数",
507 "hrvLowest": "最低HRV", 511 "hrvLowest": "最低HRV",
508 "hrvHighest": "最高HRV", 512 "hrvHighest": "最高HRV",
@@ -540,6 +544,24 @@ @@ -540,6 +544,24 @@
540 "activityComparedLastWeek": "比上周少34%", 544 "activityComparedLastWeek": "比上周少34%",
541 "activityComparedLastMonth": "比上月少34%", 545 "activityComparedLastMonth": "比上月少34%",
542 "activityComparedUnavailable": "比上周-", 546 "activityComparedUnavailable": "比上周-",
  547 + "activityComparedLastMonthUnavailable": "比上月-",
  548 + "activitySameAsLastMonth": "与上月持平",
  549 + "activityMoreThanLastMonth": "比上月多{percent}%",
  550 + "@activityMoreThanLastMonth": {
  551 + "placeholders": {
  552 + "percent": {
  553 + "type": "int"
  554 + }
  555 + }
  556 + },
  557 + "activityLessThanLastMonth": "比上月少{percent}%",
  558 + "@activityLessThanLastMonth": {
  559 + "placeholders": {
  560 + "percent": {
  561 + "type": "int"
  562 + }
  563 + }
  564 + },
543 "activityMove": "活动", 565 "activityMove": "活动",
544 "activityExercise": "锻炼", 566 "activityExercise": "锻炼",
545 "activityStand": "站立", 567 "activityStand": "站立",
@@ -2085,6 +2085,30 @@ abstract class AppLocalizations { @@ -2085,6 +2085,30 @@ abstract class AppLocalizations {
2085 /// **'每日压力分布'** 2085 /// **'每日压力分布'**
2086 String get hrvDailyStressDistribution; 2086 String get hrvDailyStressDistribution;
2087 2087
  2088 + /// No description provided for @hrvRelaxedAxisLabel.
  2089 + ///
  2090 + /// In zh, this message translates to:
  2091 + /// **'轻松'**
  2092 + String get hrvRelaxedAxisLabel;
  2093 +
  2094 + /// No description provided for @hrvStressedAxisLabel.
  2095 + ///
  2096 + /// In zh, this message translates to:
  2097 + /// **'压力大'**
  2098 + String get hrvStressedAxisLabel;
  2099 +
  2100 + /// No description provided for @hrvEmptyMonthPlaceholder.
  2101 + ///
  2102 + /// In zh, this message translates to:
  2103 + /// **'-月'**
  2104 + String get hrvEmptyMonthPlaceholder;
  2105 +
  2106 + /// No description provided for @hrvEmptyMonthDayPlaceholder.
  2107 + ///
  2108 + /// In zh, this message translates to:
  2109 + /// **'-月-日'**
  2110 + String get hrvEmptyMonthDayPlaceholder;
  2111 +
2088 /// No description provided for @hrvValidDays. 2112 /// No description provided for @hrvValidDays.
2089 /// 2113 ///
2090 /// In zh, this message translates to: 2114 /// In zh, this message translates to:
@@ -2223,6 +2247,30 @@ abstract class AppLocalizations { @@ -2223,6 +2247,30 @@ abstract class AppLocalizations {
2223 /// **'比上周-'** 2247 /// **'比上周-'**
2224 String get activityComparedUnavailable; 2248 String get activityComparedUnavailable;
2225 2249
  2250 + /// No description provided for @activityComparedLastMonthUnavailable.
  2251 + ///
  2252 + /// In zh, this message translates to:
  2253 + /// **'比上月-'**
  2254 + String get activityComparedLastMonthUnavailable;
  2255 +
  2256 + /// No description provided for @activitySameAsLastMonth.
  2257 + ///
  2258 + /// In zh, this message translates to:
  2259 + /// **'与上月持平'**
  2260 + String get activitySameAsLastMonth;
  2261 +
  2262 + /// No description provided for @activityMoreThanLastMonth.
  2263 + ///
  2264 + /// In zh, this message translates to:
  2265 + /// **'比上月多{percent}%'**
  2266 + String activityMoreThanLastMonth(int percent);
  2267 +
  2268 + /// No description provided for @activityLessThanLastMonth.
  2269 + ///
  2270 + /// In zh, this message translates to:
  2271 + /// **'比上月少{percent}%'**
  2272 + String activityLessThanLastMonth(int percent);
  2273 +
2226 /// No description provided for @activityMove. 2274 /// No description provided for @activityMove.
2227 /// 2275 ///
2228 /// In zh, this message translates to: 2276 /// In zh, this message translates to:
@@ -1150,6 +1150,18 @@ class AppLocalizationsEn extends AppLocalizations { @@ -1150,6 +1150,18 @@ class AppLocalizationsEn extends AppLocalizations {
1150 String get hrvDailyStressDistribution => 'Daily Stress Distribution'; 1150 String get hrvDailyStressDistribution => 'Daily Stress Distribution';
1151 1151
1152 @override 1152 @override
  1153 + String get hrvRelaxedAxisLabel => 'Relaxed';
  1154 +
  1155 + @override
  1156 + String get hrvStressedAxisLabel => 'Stressed';
  1157 +
  1158 + @override
  1159 + String get hrvEmptyMonthPlaceholder => '-';
  1160 +
  1161 + @override
  1162 + String get hrvEmptyMonthDayPlaceholder => '-';
  1163 +
  1164 + @override
1153 String get hrvValidDays => 'Valid HRV days'; 1165 String get hrvValidDays => 'Valid HRV days';
1154 1166
1155 @override 1167 @override
@@ -1223,6 +1235,23 @@ class AppLocalizationsEn extends AppLocalizations { @@ -1223,6 +1235,23 @@ class AppLocalizationsEn extends AppLocalizations {
1223 String get activityComparedUnavailable => 'Compared with last week: -'; 1235 String get activityComparedUnavailable => 'Compared with last week: -';
1224 1236
1225 @override 1237 @override
  1238 + String get activityComparedLastMonthUnavailable =>
  1239 + 'Compared with last month: -';
  1240 +
  1241 + @override
  1242 + String get activitySameAsLastMonth => 'Same as last month';
  1243 +
  1244 + @override
  1245 + String activityMoreThanLastMonth(int percent) {
  1246 + return '$percent% more than last month';
  1247 + }
  1248 +
  1249 + @override
  1250 + String activityLessThanLastMonth(int percent) {
  1251 + return '$percent% less than last month';
  1252 + }
  1253 +
  1254 + @override
1226 String get activityMove => 'Move'; 1255 String get activityMove => 'Move';
1227 1256
1228 @override 1257 @override
@@ -1086,6 +1086,18 @@ class AppLocalizationsZh extends AppLocalizations { @@ -1086,6 +1086,18 @@ class AppLocalizationsZh extends AppLocalizations {
1086 String get hrvDailyStressDistribution => '每日压力分布'; 1086 String get hrvDailyStressDistribution => '每日压力分布';
1087 1087
1088 @override 1088 @override
  1089 + String get hrvRelaxedAxisLabel => '轻松';
  1090 +
  1091 + @override
  1092 + String get hrvStressedAxisLabel => '压力大';
  1093 +
  1094 + @override
  1095 + String get hrvEmptyMonthPlaceholder => '-月';
  1096 +
  1097 + @override
  1098 + String get hrvEmptyMonthDayPlaceholder => '-月-日';
  1099 +
  1100 + @override
1089 String get hrvValidDays => 'HRV有效天数'; 1101 String get hrvValidDays => 'HRV有效天数';
1090 1102
1091 @override 1103 @override
@@ -1159,6 +1171,22 @@ class AppLocalizationsZh extends AppLocalizations { @@ -1159,6 +1171,22 @@ class AppLocalizationsZh extends AppLocalizations {
1159 String get activityComparedUnavailable => '比上周-'; 1171 String get activityComparedUnavailable => '比上周-';
1160 1172
1161 @override 1173 @override
  1174 + String get activityComparedLastMonthUnavailable => '比上月-';
  1175 +
  1176 + @override
  1177 + String get activitySameAsLastMonth => '与上月持平';
  1178 +
  1179 + @override
  1180 + String activityMoreThanLastMonth(int percent) {
  1181 + return '比上月多$percent%';
  1182 + }
  1183 +
  1184 + @override
  1185 + String activityLessThanLastMonth(int percent) {
  1186 + return '比上月少$percent%';
  1187 + }
  1188 +
  1189 + @override
1162 String get activityMove => '活动'; 1190 String get activityMove => '活动';
1163 1191
1164 @override 1192 @override