Commit 76a7b3a9b3cfe68da52e82ad2d80932f38d722ab

Authored by 刘宏哲
1 parent ea1a3e95

feat(app): update ui

@@ -191,7 +191,6 @@ class FriendsTab extends GetView<FriendsController> { @@ -191,7 +191,6 @@ class FriendsTab extends GetView<FriendsController> {
191 ? () => _showFriendsLimitReached(context) 191 ? () => _showFriendsLimitReached(context)
192 : _handleAddFriend, 192 : _handleAddFriend,
193 ), 193 ),
194 - if (isFull) const _FullFriendsTip(),  
195 ], 194 ],
196 ), 195 ),
197 ), 196 ),
@@ -408,34 +407,12 @@ class _EmptyFriendsView extends StatelessWidget { @@ -408,34 +407,12 @@ class _EmptyFriendsView extends StatelessWidget {
408 enabled: enabled, 407 enabled: enabled,
409 onTap: onTap, 408 onTap: onTap,
410 ), 409 ),
411 - if (!enabled) const _FullFriendsTip(),  
412 ], 410 ],
413 ), 411 ),
414 ); 412 );
415 } 413 }
416 } 414 }
417 415
418 -class _FullFriendsTip extends StatelessWidget {  
419 - const _FullFriendsTip();  
420 -  
421 - @override  
422 - Widget build(BuildContext context) {  
423 - return Padding(  
424 - padding: const EdgeInsets.only(top: 10),  
425 - child: Center(  
426 - child: Text(  
427 - context.l10n.friendsLimitReached,  
428 - style: const TextStyle(  
429 - color: Color(0xFFB0B0B6),  
430 - fontSize: 12,  
431 - fontWeight: FontWeight.w400,  
432 - ),  
433 - ),  
434 - ),  
435 - );  
436 - }  
437 -}  
438 -  
439 class _AddFriendButton extends StatelessWidget { 416 class _AddFriendButton extends StatelessWidget {
440 const _AddFriendButton({ 417 const _AddFriendButton({
441 required this.enabled, 418 required this.enabled,
@@ -455,39 +432,53 @@ class _AddFriendButton extends StatelessWidget { @@ -455,39 +432,53 @@ class _AddFriendButton extends StatelessWidget {
455 child: GestureDetector( 432 child: GestureDetector(
456 onTap: onTap, 433 onTap: onTap,
457 behavior: HitTestBehavior.opaque, 434 behavior: HitTestBehavior.opaque,
458 - child: Opacity(  
459 - opacity: enabled ? 1 : 0.4,  
460 - child: Container( 435 + child: SizedBox(
461 width: 240, 436 width: 240,
462 height: 48, 437 height: 48,
463 - decoration: BoxDecoration(  
464 - color:  
465 - enabled ? const Color(0xFF845EEE) : const Color(0xFFD0D0D2),  
466 - borderRadius: BorderRadius.circular(24),  
467 - ),  
468 - child: Row(  
469 - mainAxisAlignment: MainAxisAlignment.center, 438 + child: Stack(
470 children: [ 439 children: [
471 - Image.asset(  
472 - 'assets/images/common/ic_add.png',  
473 - width: 18,  
474 - height: 18,  
475 - color: Colors.white,  
476 - ),  
477 - const SizedBox(width: 6),  
478 - Text(  
479 - _buttonText(context),  
480 - style: const TextStyle( 440 + Container(
  441 + width: double.infinity,
  442 + height: double.infinity,
  443 + decoration: BoxDecoration(
481 color: Colors.white, 444 color: Colors.white,
482 - fontSize: 16,  
483 - fontWeight: FontWeight.w600,  
484 - height: 1.4, 445 + borderRadius: BorderRadius.circular(24),
485 ), 446 ),
486 ), 447 ),
  448 + Opacity(
  449 + opacity: enabled ? 1 : 0.4,
  450 + child: Container(
  451 + width: 240,
  452 + height: 48,
  453 + decoration: BoxDecoration(
  454 + color: const Color(0xFF845EEE),
  455 + borderRadius: BorderRadius.circular(24),
  456 + ),
  457 + child: Row(
  458 + mainAxisAlignment: MainAxisAlignment.center,
  459 + children: [
  460 + Image.asset(
  461 + 'assets/images/common/ic_add.png',
  462 + width: 18,
  463 + height: 18,
  464 + color: Colors.white,
  465 + ),
  466 + const SizedBox(width: 6),
  467 + Text(
  468 + _buttonText(context),
  469 + style: const TextStyle(
  470 + color: Colors.white,
  471 + fontSize: 16,
  472 + fontWeight: FontWeight.w600,
  473 + height: 1.4,
  474 + ),
  475 + ),
  476 + ],
  477 + ),
  478 + ),
  479 + )
487 ], 480 ],
488 - ),  
489 - ),  
490 - ), 481 + )),
491 ), 482 ),
492 ); 483 );
493 } 484 }
@@ -158,15 +158,30 @@ class _HealthTrendContentState extends State<HealthTrendContent> @@ -158,15 +158,30 @@ class _HealthTrendContentState extends State<HealthTrendContent>
158 class _HealthTrendLoadingIndicator extends StatelessWidget { 158 class _HealthTrendLoadingIndicator extends StatelessWidget {
159 const _HealthTrendLoadingIndicator(); 159 const _HealthTrendLoadingIndicator();
160 160
  161 + static const _width = 130.0;
  162 + static const _height = 90.0;
  163 + static const _headerCenterOffset = Offset(0, -46);
  164 + static const _visualCenterOffset = Offset(0, -8);
  165 +
161 @override 166 @override
162 Widget build(BuildContext context) { 167 Widget build(BuildContext context) {
163 return Center( 168 return Center(
164 - child: Lottie.asset(  
165 - 'assets/lottie/loading.json',  
166 - width: 130,  
167 - height: 90,  
168 - repeat: true,  
169 - animate: true, 169 + child: Transform.translate(
  170 + offset: _headerCenterOffset,
  171 + child: SizedBox(
  172 + width: _width,
  173 + height: _height,
  174 + child: Transform.translate(
  175 + offset: _visualCenterOffset,
  176 + child: Lottie.asset(
  177 + 'assets/lottie/loading.json',
  178 + width: _width,
  179 + height: _height,
  180 + repeat: true,
  181 + animate: true,
  182 + ),
  183 + ),
  184 + ),
170 ), 185 ),
171 ); 186 );
172 } 187 }
@@ -211,7 +226,9 @@ class _HrvTrendSectionState extends State<_HrvTrendSection> { @@ -211,7 +226,9 @@ class _HrvTrendSectionState extends State<_HrvTrendSection> {
211 _dateWorker = ever(_logic.selectedDate, (date) { 226 _dateWorker = ever(_logic.selectedDate, (date) {
212 _scheduleQueryNotification(); 227 _scheduleQueryNotification();
213 }); 228 });
214 - _logic.loadReport(); 229 + if (widget.isVip) {
  230 + _logic.loadReport();
  231 + }
215 } 232 }
216 233
217 @override 234 @override
@@ -221,6 +238,10 @@ class _HrvTrendSectionState extends State<_HrvTrendSection> { @@ -221,6 +238,10 @@ class _HrvTrendSectionState extends State<_HrvTrendSection> {
221 _syncExternalQuery(); 238 _syncExternalQuery();
222 } else if (oldWidget.refreshToken != widget.refreshToken && 239 } else if (oldWidget.refreshToken != widget.refreshToken &&
223 widget.isSelected) { 240 widget.isSelected) {
  241 + if (widget.isVip) {
  242 + _logic.loadReport();
  243 + }
  244 + } else if (!oldWidget.isVip && widget.isVip) {
224 _logic.loadReport(); 245 _logic.loadReport();
225 } 246 }
226 } 247 }
@@ -229,7 +250,11 @@ class _HrvTrendSectionState extends State<_HrvTrendSection> { @@ -229,7 +250,11 @@ class _HrvTrendSectionState extends State<_HrvTrendSection> {
229 _syncingExternalQuery = true; 250 _syncingExternalQuery = true;
230 _logic.targetUserId.value = widget.query.targetUserId; 251 _logic.targetUserId.value = widget.query.targetUserId;
231 try { 252 try {
232 - await _logic.selectQuery(widget.query.period, widget.query.date); 253 + if (widget.isVip) {
  254 + await _logic.selectQuery(widget.query.period, widget.query.date);
  255 + } else {
  256 + _logic.initializeQuery(widget.query.period, widget.query.date);
  257 + }
233 } finally { 258 } finally {
234 _syncingExternalQuery = false; 259 _syncingExternalQuery = false;
235 } 260 }
@@ -77,6 +77,8 @@ class WeeklyHrvReport implements HrvPeriodReport { @@ -77,6 +77,8 @@ class WeeklyHrvReport implements HrvPeriodReport {
77 required this.days, 77 required this.days,
78 this.previousRelaxedDays, 78 this.previousRelaxedDays,
79 this.previousStressedDays, 79 this.previousStressedDays,
  80 + this.relaxedDaysOverride,
  81 + this.stressedDaysOverride,
80 this.distributionCounts, 82 this.distributionCounts,
81 this.minDayOverride, 83 this.minDayOverride,
82 this.maxDayOverride, 84 this.maxDayOverride,
@@ -89,6 +91,8 @@ class WeeklyHrvReport implements HrvPeriodReport { @@ -89,6 +91,8 @@ class WeeklyHrvReport implements HrvPeriodReport {
89 final int? previousRelaxedDays; 91 final int? previousRelaxedDays;
90 @override 92 @override
91 final int? previousStressedDays; 93 final int? previousStressedDays;
  94 + final int? relaxedDaysOverride;
  95 + final int? stressedDaysOverride;
92 final Map<HrvStressLevel, int>? distributionCounts; 96 final Map<HrvStressLevel, int>? distributionCounts;
93 final HrvDayReport? minDayOverride; 97 final HrvDayReport? minDayOverride;
94 final HrvDayReport? maxDayOverride; 98 final HrvDayReport? maxDayOverride;
@@ -114,10 +118,12 @@ class WeeklyHrvReport implements HrvPeriodReport { @@ -114,10 +118,12 @@ class WeeklyHrvReport implements HrvPeriodReport {
114 118
115 @override 119 @override
116 int get relaxedDays => 120 int get relaxedDays =>
  121 + relaxedDaysOverride ??
117 countFor(HrvStressLevel.excellent) + countFor(HrvStressLevel.normal); 122 countFor(HrvStressLevel.excellent) + countFor(HrvStressLevel.normal);
118 123
119 @override 124 @override
120 int get stressedDays => 125 int get stressedDays =>
  126 + stressedDaysOverride ??
121 countFor(HrvStressLevel.attention) + countFor(HrvStressLevel.overload); 127 countFor(HrvStressLevel.attention) + countFor(HrvStressLevel.overload);
122 128
123 @override 129 @override
@@ -144,6 +150,71 @@ class WeeklyHrvReport implements HrvPeriodReport { @@ -144,6 +150,71 @@ class WeeklyHrvReport implements HrvPeriodReport {
144 HrvDayReport(date: weekStart.add(Duration(days: i))), 150 HrvDayReport(date: weekStart.add(Duration(days: i))),
145 ], 151 ],
146 ); 152 );
  153 +
  154 + factory WeeklyHrvReport.premiumPreview(DateTime weekStart) {
  155 + final start = DateTime(weekStart.year, weekStart.month, weekStart.day);
  156 + final minDay = HrvDayReport(
  157 + date: start.add(const Duration(days: 6)),
  158 + averageHrv: 15,
  159 + averageHeartRate: 71,
  160 + level: HrvStressLevel.overload,
  161 + );
  162 + final maxDay = HrvDayReport(
  163 + date: start.add(const Duration(days: 1)),
  164 + averageHrv: 90,
  165 + averageHeartRate: 84,
  166 + level: HrvStressLevel.excellent,
  167 + );
  168 + return WeeklyHrvReport(
  169 + weekStart: start,
  170 + previousRelaxedDays: 5,
  171 + previousStressedDays: 2,
  172 + relaxedDaysOverride: 4,
  173 + stressedDaysOverride: 1,
  174 + distributionCounts: const {
  175 + HrvStressLevel.excellent: 4,
  176 + HrvStressLevel.normal: 1,
  177 + HrvStressLevel.attention: 1,
  178 + HrvStressLevel.overload: 1,
  179 + },
  180 + minDayOverride: minDay,
  181 + maxDayOverride: maxDay,
  182 + days: [
  183 + HrvDayReport(
  184 + date: start,
  185 + averageHrv: 62,
  186 + averageHeartRate: 86,
  187 + level: HrvStressLevel.normal,
  188 + ),
  189 + maxDay,
  190 + HrvDayReport(
  191 + date: start.add(const Duration(days: 2)),
  192 + averageHrv: 68,
  193 + averageHeartRate: 88,
  194 + level: HrvStressLevel.excellent,
  195 + ),
  196 + HrvDayReport(
  197 + date: start.add(const Duration(days: 3)),
  198 + averageHrv: 85,
  199 + averageHeartRate: 85,
  200 + level: HrvStressLevel.excellent,
  201 + ),
  202 + HrvDayReport(
  203 + date: start.add(const Duration(days: 4)),
  204 + averageHrv: 86,
  205 + averageHeartRate: 87,
  206 + level: HrvStressLevel.excellent,
  207 + ),
  208 + HrvDayReport(
  209 + date: start.add(const Duration(days: 5)),
  210 + averageHrv: 45,
  211 + averageHeartRate: 70,
  212 + level: HrvStressLevel.attention,
  213 + ),
  214 + minDay,
  215 + ],
  216 + );
  217 + }
147 } 218 }
148 219
149 class MonthlyHrvReport implements HrvPeriodReport { 220 class MonthlyHrvReport implements HrvPeriodReport {
@@ -9,6 +9,7 @@ import '../../report_common/widgets/report_date_picker_sheet.dart'; @@ -9,6 +9,7 @@ import '../../report_common/widgets/report_date_picker_sheet.dart';
9 import '../../report_common/widgets/report_date_switcher.dart'; 9 import '../../report_common/widgets/report_date_switcher.dart';
10 import '../../report_common/widgets/report_loading_indicator.dart'; 10 import '../../report_common/widgets/report_loading_indicator.dart';
11 import '../controllers/hrv_report_logic.dart'; 11 import '../controllers/hrv_report_logic.dart';
  12 +import '../models/hrv_report_models.dart';
12 import '../widgets/hrv_week_report_view.dart'; 13 import '../widgets/hrv_week_report_view.dart';
13 import '../widgets/hrv_year_report_view.dart'; 14 import '../widgets/hrv_year_report_view.dart';
14 15
@@ -86,7 +87,11 @@ class HrvReportView extends StatelessWidget { @@ -86,7 +87,11 @@ class HrvReportView extends StatelessWidget {
86 HrvMonthReportView(report: logic.monthlyReport.value) 87 HrvMonthReportView(report: logic.monthlyReport.value)
87 else 88 else
88 HrvWeekReportView( 89 HrvWeekReportView(
89 - report: logic.weeklyReport.value, 90 + report: isVip
  91 + ? logic.weeklyReport.value
  92 + : WeeklyHrvReport.premiumPreview(
  93 + logic.weekStart,
  94 + ),
90 showExample: !isVip, 95 showExample: !isVip,
91 onSubscribe: () => onSubscribe('解锁每日压力-HRV心率'), 96 onSubscribe: () => onSubscribe('解锁每日压力-HRV心率'),
92 ), 97 ),