Showing
15 changed files
with
238 additions
and
46 deletions
| @@ -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 |
-
Please register or login to post a comment