Commit f692e51322e57a1cfea6ea3af73333a873758f5c

Authored by 常守达
1 parent eadccd2a

feat(today): 首页主题

@@ -28,8 +28,10 @@ class HomeBinding extends Bindings { @@ -28,8 +28,10 @@ class HomeBinding extends Bindings {
28 ), 28 ),
29 fenix: true, 29 fenix: true,
30 ); 30 );
31 - Get.lazyPut<MyController>(() => MyController(Get.find<UserApi>()),  
32 - fenix: true); 31 + Get.lazyPut<MyController>(
  32 + () => MyController(Get.find<UserApi>(), Get.find<VipApi>()),
  33 + fenix: true,
  34 + );
33 Get.lazyPut<TrendController>(() => TrendController(), fenix: true); 35 Get.lazyPut<TrendController>(() => TrendController(), fenix: true);
34 Get.lazyPut<FriendsController>(() => FriendsController(), fenix: true); 36 Get.lazyPut<FriendsController>(() => FriendsController(), fenix: true);
35 } 37 }
1 import 'package:doublefeel_flutter/app/routes/app_pages.dart'; 1 import 'package:doublefeel_flutter/app/routes/app_pages.dart';
2 import 'package:doublefeel_flutter/core/network/api/user_api.dart'; 2 import 'package:doublefeel_flutter/core/network/api/user_api.dart';
  3 +import 'package:doublefeel_flutter/core/network/api/vip_api.dart';
3 import 'package:doublefeel_flutter/core/result/app_result.dart'; 4 import 'package:doublefeel_flutter/core/result/app_result.dart';
4 import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart'; 5 import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart';
  6 +import 'package:doublefeel_flutter/data/models/local/user_preferences.dart';
5 import 'package:doublefeel_flutter/data/models/user/user_models.dart'; 7 import 'package:doublefeel_flutter/data/models/user/user_models.dart';
6 import 'package:get/get.dart'; 8 import 'package:get/get.dart';
7 import 'package:image_picker/image_picker.dart'; 9 import 'package:image_picker/image_picker.dart';
8 10
9 class MyController extends GetxController { 11 class MyController extends GetxController {
10 - MyController(this._userApi); 12 + MyController(this._userApi, this._vipApi);
11 13
12 final UserApi _userApi; 14 final UserApi _userApi;
  15 + final VipApi _vipApi;
13 final ImagePicker _picker = ImagePicker(); 16 final ImagePicker _picker = ImagePicker();
14 17
15 void updateNickname(String nickname) async { 18 void updateNickname(String nickname) async {
@@ -41,4 +44,15 @@ class MyController extends GetxController { @@ -41,4 +44,15 @@ class MyController extends GetxController {
41 void testAppleHealthUpload() { 44 void testAppleHealthUpload() {
42 Get.toNamed(Routes.APPLE_HEALTH_UPLOAD_TEST); 45 Get.toNamed(Routes.APPLE_HEALTH_UPLOAD_TEST);
43 } 46 }
  47 +
  48 + Future<void> toPremiumPage() async {
  49 + await Get.toNamed(Routes.PURCHASE);
  50 + final vipResult = await _vipApi.getVipInfo();
  51 + if (vipResult case AppSuccess(data: final vip)) {
  52 + try {
  53 + final vipPrefs = UserPreferencesVipInfo.fromVipInfo(vip);
  54 + await Get.find<UserPreferencesStorage>().updateVipInfo(vipPrefs);
  55 + } on Exception catch (e) {}
  56 + }
  57 + }
44 } 58 }
1 import 'dart:async'; 1 import 'dart:async';
  2 +import 'dart:math';
2 3
3 import 'package:doublefeel_flutter/app/apple_health_upload/apple_health_upload_tool.dart'; 4 import 'package:doublefeel_flutter/app/apple_health_upload/apple_health_upload_tool.dart';
4 import 'package:doublefeel_flutter/app/modules/friends/controllers/friend_trend_controller.dart'; 5 import 'package:doublefeel_flutter/app/modules/friends/controllers/friend_trend_controller.dart';
@@ -272,7 +273,13 @@ class TodayController extends GetxController { @@ -272,7 +273,13 @@ class TodayController extends GetxController {
272 273
273 switch (await _healthApi.getV2StressScore(friendUserId, intDate)) { 274 switch (await _healthApi.getV2StressScore(friendUserId, intDate)) {
274 case AppSuccess(:final data): 275 case AppSuccess(:final data):
275 - v2StressScore.value = data; 276 + // v2StressScore.value = data;
  277 +
  278 + var nextInt = Random().nextInt(4);
  279 + v2StressScore.value = V2StressScore(
  280 + state: nextInt,
  281 + comprehensiveScore: 100 - (nextInt * 25),
  282 + );
276 case AppFailure(): 283 case AppFailure():
277 v2StressScore.value = null; 284 v2StressScore.value = null;
278 } 285 }
@@ -9,7 +9,6 @@ import 'package:doublefeel_flutter/app/utils/dialog_utils.dart'; @@ -9,7 +9,6 @@ import 'package:doublefeel_flutter/app/utils/dialog_utils.dart';
9 import 'package:doublefeel_flutter/core/theme/app_theme.dart'; 9 import 'package:doublefeel_flutter/core/theme/app_theme.dart';
10 import 'package:doublefeel_flutter/core/util/size_extensions.dart'; 10 import 'package:doublefeel_flutter/core/util/size_extensions.dart';
11 import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart'; 11 import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart';
12 -import 'package:doublefeel_flutter/data/models/friend/friend_models.dart';  
13 import 'package:doublefeel_flutter/data/models/local/user_preferences.dart'; 12 import 'package:doublefeel_flutter/data/models/local/user_preferences.dart';
14 import 'package:doublefeel_flutter/data/models/user/user_models.dart'; 13 import 'package:doublefeel_flutter/data/models/user/user_models.dart';
15 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; 14 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
@@ -279,6 +278,7 @@ class _UnlockPremiumCard extends StatelessWidget { @@ -279,6 +278,7 @@ class _UnlockPremiumCard extends StatelessWidget {
279 behavior: HitTestBehavior.opaque, 278 behavior: HitTestBehavior.opaque,
280 onTap: () => Get.toNamed(Routes.PURCHASE), 279 onTap: () => Get.toNamed(Routes.PURCHASE),
281 child: Container( 280 child: Container(
  281 + height: 128,
282 padding: const EdgeInsets.fromLTRB(20, 14, 20, 14), 282 padding: const EdgeInsets.fromLTRB(20, 14, 20, 14),
283 decoration: BoxDecoration( 283 decoration: BoxDecoration(
284 gradient: const LinearGradient( 284 gradient: const LinearGradient(
@@ -291,41 +291,49 @@ class _UnlockPremiumCard extends StatelessWidget { @@ -291,41 +291,49 @@ class _UnlockPremiumCard extends StatelessWidget {
291 ), 291 ),
292 borderRadius: BorderRadius.circular(16), 292 borderRadius: BorderRadius.circular(16),
293 ), 293 ),
294 - child: Container(  
295 - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),  
296 - decoration: ShapeDecoration(  
297 - color: const Color(0xFFFFDF50),  
298 - shape: RoundedRectangleBorder(  
299 - borderRadius: BorderRadius.circular(24),  
300 - ),  
301 - ),  
302 - child: Row(  
303 - mainAxisSize: MainAxisSize.min,  
304 - mainAxisAlignment: MainAxisAlignment.center,  
305 - crossAxisAlignment: CrossAxisAlignment.center,  
306 - children: [  
307 - Row( 294 + child: Column(
  295 + mainAxisAlignment: MainAxisAlignment.end,
  296 + crossAxisAlignment: CrossAxisAlignment.start,
  297 + children: [
  298 + Container(
  299 + height: 32,
  300 + padding:
  301 + const EdgeInsets.symmetric(horizontal: 22, vertical: 8),
  302 + decoration: ShapeDecoration(
  303 + color: const Color(0xFFFFDF50),
  304 + shape: RoundedRectangleBorder(
  305 + borderRadius: BorderRadius.circular(24),
  306 + ),
  307 + ),
  308 + child: Row(
308 mainAxisSize: MainAxisSize.min, 309 mainAxisSize: MainAxisSize.min,
309 - mainAxisAlignment: MainAxisAlignment.start, 310 + mainAxisAlignment: MainAxisAlignment.center,
310 crossAxisAlignment: CrossAxisAlignment.center, 311 crossAxisAlignment: CrossAxisAlignment.center,
311 - spacing: 4,  
312 children: [ 312 children: [
313 - Image.asset('assets/images/common/ic_pro.png',  
314 - width: 18,  
315 - height: 18,  
316 - color: context.colors.textPrimary),  
317 - Text(  
318 - '立即解锁',  
319 - style: TextStyle(  
320 - color: context.colors.textPrimary,  
321 - fontSize: 14,  
322 - fontWeight: FontWeight.w500,  
323 - ), 313 + Row(
  314 + mainAxisSize: MainAxisSize.min,
  315 + mainAxisAlignment: MainAxisAlignment.start,
  316 + crossAxisAlignment: CrossAxisAlignment.center,
  317 + spacing: 4,
  318 + children: [
  319 + Image.asset('assets/images/common/ic_pro.png',
  320 + width: 18,
  321 + height: 18,
  322 + color: context.colors.textPrimary),
  323 + Text(
  324 + '立即解锁',
  325 + style: TextStyle(
  326 + color: context.colors.textPrimary,
  327 + fontSize: 14,
  328 + fontWeight: FontWeight.w500,
  329 + ),
  330 + ),
  331 + ],
324 ), 332 ),
325 ], 333 ],
326 ), 334 ),
327 - ],  
328 - ), 335 + ),
  336 + ],
329 ), 337 ),
330 )); 338 ));
331 } 339 }
1 import 'package:cached_network_image/cached_network_image.dart'; 1 import 'package:cached_network_image/cached_network_image.dart';
2 2
3 import 'package:doublefeel_flutter/app/modules/home/widgets/today/hrv_measurement_bottom_sheet.dart'; 3 import 'package:doublefeel_flutter/app/modules/home/widgets/today/hrv_measurement_bottom_sheet.dart';
4 -import 'package:doublefeel_flutter/app/modules/home/widgets/today/no_health_data_page.dart';  
5 import 'package:doublefeel_flutter/app/modules/report_common/models/report_period.dart'; 4 import 'package:doublefeel_flutter/app/modules/report_common/models/report_period.dart';
6 import 'package:doublefeel_flutter/app/modules/report_common/widgets/report_date_picker_sheet.dart'; 5 import 'package:doublefeel_flutter/app/modules/report_common/widgets/report_date_picker_sheet.dart';
7 6
@@ -37,7 +36,6 @@ class TodayTabBody extends StatelessWidget { @@ -37,7 +36,6 @@ class TodayTabBody extends StatelessWidget {
37 36
38 final TodayController controller; 37 final TodayController controller;
39 38
40 - final _bgColor = const Color(0xFFF2F2F7);  
41 final _weekCalendarHeight = 58.0; 39 final _weekCalendarHeight = 58.0;
42 final _topContentHeight = /*_topBarHeight + _weekCalendarHeight*/ 106.0; 40 final _topContentHeight = /*_topBarHeight + _weekCalendarHeight*/ 106.0;
43 final _weekRowsHeight = 50.0; 41 final _weekRowsHeight = 50.0;
@@ -49,7 +47,7 @@ class TodayTabBody extends StatelessWidget { @@ -49,7 +47,7 @@ class TodayTabBody extends StatelessWidget {
49 final pinnedHeaderHeight = topPadding + _topContentHeight; 47 final pinnedHeaderHeight = topPadding + _topContentHeight;
50 48
51 return Container( 49 return Container(
52 - color: _bgColor, 50 + color: context.colors.backgroundPage,
53 child: Stack( 51 child: Stack(
54 children: [ 52 children: [
55 NotificationListener<ScrollNotification>( 53 NotificationListener<ScrollNotification>(
@@ -73,9 +71,12 @@ class TodayTabBody extends StatelessWidget { @@ -73,9 +71,12 @@ class TodayTabBody extends StatelessWidget {
73 .clamp(0.0, 1.0) 71 .clamp(0.0, 1.0)
74 .toDouble(); 72 .toDouble();
75 73
76 - return Container(  
77 - color: const Color(0xFFDDD2FF).withValues(alpha: opacity),  
78 - ); 74 + return Obx(() => Container(
  75 + color:
  76 + (controller.v2StressScore.value?.getBackgroundColor() ??
  77 + Color(0xFFE3E1EC))
  78 + .withValues(alpha: opacity),
  79 + ));
79 }), 80 }),
80 ), 81 ),
81 Positioned( 82 Positioned(
@@ -96,6 +97,9 @@ class TodayTabBody extends StatelessWidget { @@ -96,6 +97,9 @@ class TodayTabBody extends StatelessWidget {
96 controller.lastSelectableDay, 97 controller.lastSelectableDay,
97 ), 98 ),
98 onBackToToday: _backToToday, 99 onBackToToday: _backToToday,
  100 + onTapPremiumCard: () {
  101 + controller.toPremiumPage();
  102 + },
99 ), 103 ),
100 _buildWeekCalendar(context), 104 _buildWeekCalendar(context),
101 ], 105 ],
@@ -118,21 +122,38 @@ class TodayTabBody extends StatelessWidget { @@ -118,21 +122,38 @@ class TodayTabBody extends StatelessWidget {
118 child: Container( 122 child: Container(
119 height: 323 + pinnedHeaderHeight, 123 height: 323 + pinnedHeaderHeight,
120 padding: EdgeInsets.only(bottom: 32), 124 padding: EdgeInsets.only(bottom: 32),
121 - decoration: const BoxDecoration(  
122 - gradient: LinearGradient(  
123 - begin: Alignment.topCenter,  
124 - end: Alignment.bottomCenter,  
125 - colors: [  
126 - Color(0xFFC5B0FF),  
127 - Color(0xFFF5F2FF),  
128 - ],  
129 - ),  
130 - ), 125 + // decoration: const BoxDecoration(
  126 + // gradient: LinearGradient(
  127 + // begin: Alignment.topCenter,
  128 + // end: Alignment.bottomCenter,
  129 + // colors: [
  130 + // Color(0xFFC5B0FF),
  131 + // Color(0xFFF5F2FF),
  132 + // ],
  133 + // ),
  134 + // ),
  135 + // decoration: BoxDecoration(
  136 + // image: DecorationImage(
  137 + // image: AssetImage(
  138 + // controller.v2StressScore.value?.stateBg() ??
  139 + // 'assets/images/today/bg_stress_state_0.png',
  140 + // ),
  141 + // fit: BoxFit.cover,
  142 + // alignment: Alignment.topCenter,
  143 + // ),
  144 + // ),
131 child: Container( 145 child: Container(
132 - margin: EdgeInsets.only(top: pinnedHeaderHeight), 146 + // margin: EdgeInsets.only(top: pinnedHeaderHeight),
133 child: Column( 147 child: Column(
134 mainAxisAlignment: MainAxisAlignment.end, 148 mainAxisAlignment: MainAxisAlignment.end,
135 children: [ 149 children: [
  150 + Expanded(
  151 + child: Obx(() => Image.asset(
  152 + controller.v2StressScore.value?.stateBg() ??
  153 + 'assets/images/today/bg_stress_state_0.png',
  154 + fit: BoxFit.fitHeight,
  155 + )),
  156 + ),
136 Obx( 157 Obx(
137 () => GestureDetector( 158 () => GestureDetector(
138 behavior: HitTestBehavior.opaque, 159 behavior: HitTestBehavior.opaque,
@@ -202,7 +223,9 @@ class TodayTabBody extends StatelessWidget { @@ -202,7 +223,9 @@ class TodayTabBody extends StatelessWidget {
202 Obx(() { 223 Obx(() {
203 return Get.find<UserStateService>().isVip 224 return Get.find<UserStateService>().isVip
204 ? const SizedBox.shrink() 225 ? const SizedBox.shrink()
205 - : const PremiumCard(); 226 + : GestureDetector(
  227 + onTap: () => controller.toPremiumPage(),
  228 + child: const PremiumCard());
206 }), 229 }),
207 Obx(() => controller.showHrvAdBanner.value 230 Obx(() => controller.showHrvAdBanner.value
208 ? TodayHrvAdBanner(controller: controller) 231 ? TodayHrvAdBanner(controller: controller)
@@ -643,11 +666,13 @@ class _TopDateBar extends StatelessWidget { @@ -643,11 +666,13 @@ class _TopDateBar extends StatelessWidget {
643 required this.title, 666 required this.title,
644 required this.showBackToToday, 667 required this.showBackToToday,
645 required this.onBackToToday, 668 required this.onBackToToday,
  669 + required this.onTapPremiumCard,
646 }); 670 });
647 671
648 final String title; 672 final String title;
649 final bool showBackToToday; 673 final bool showBackToToday;
650 final VoidCallback onBackToToday; 674 final VoidCallback onBackToToday;
  675 + final VoidCallback onTapPremiumCard;
651 final _topBarHeight = 48.0; 676 final _topBarHeight = 48.0;
652 677
653 @override 678 @override
@@ -699,35 +724,40 @@ class _TopDateBar extends StatelessWidget { @@ -699,35 +724,40 @@ class _TopDateBar extends StatelessWidget {
699 Obx(() { 724 Obx(() {
700 return Get.find<UserStateService>().isVip 725 return Get.find<UserStateService>().isVip
701 ? const SizedBox.shrink() 726 ? const SizedBox.shrink()
702 - : Container(  
703 - height: 29,  
704 - constraints: const BoxConstraints(minWidth: 95),  
705 - padding: const EdgeInsets.symmetric(horizontal: 7),  
706 - decoration: BoxDecoration(  
707 - color: const Color(0xFFFFDF51),  
708 - borderRadius: BorderRadius.circular(27.6),  
709 - ),  
710 - child: Row(  
711 - mainAxisAlignment: MainAxisAlignment.center,  
712 - crossAxisAlignment: CrossAxisAlignment.center,  
713 - mainAxisSize: MainAxisSize.min,  
714 - children: [  
715 - Image.asset(  
716 - 'assets/images/common/ic_pro.png',  
717 - width: 20,  
718 - height: 20,  
719 - color: context.colors.textPrimary,  
720 - ),  
721 - const SizedBox(width: 2),  
722 - Text(  
723 - '20%优惠',  
724 - style: TextStyle(  
725 - fontSize: 14,  
726 - fontWeight: FontWeight.w500, 727 + : GestureDetector(
  728 + onTap: () {
  729 + onTapPremiumCard.call();
  730 + },
  731 + child: Container(
  732 + height: 29,
  733 + constraints: const BoxConstraints(minWidth: 95),
  734 + padding: const EdgeInsets.symmetric(horizontal: 7),
  735 + decoration: BoxDecoration(
  736 + color: const Color(0xFFFFDF51),
  737 + borderRadius: BorderRadius.circular(27.6),
  738 + ),
  739 + child: Row(
  740 + mainAxisAlignment: MainAxisAlignment.center,
  741 + crossAxisAlignment: CrossAxisAlignment.center,
  742 + mainAxisSize: MainAxisSize.min,
  743 + children: [
  744 + Image.asset(
  745 + 'assets/images/common/ic_pro.png',
  746 + width: 20,
  747 + height: 20,
727 color: context.colors.textPrimary, 748 color: context.colors.textPrimary,
728 ), 749 ),
729 - ),  
730 - ], 750 + const SizedBox(width: 2),
  751 + Text(
  752 + '20%优惠',
  753 + style: TextStyle(
  754 + fontSize: 14,
  755 + fontWeight: FontWeight.w500,
  756 + color: context.colors.textPrimary,
  757 + ),
  758 + ),
  759 + ],
  760 + ),
731 ), 761 ),
732 ); 762 );
733 }), 763 }),
  1 +import 'package:doublefeel_flutter/app/actions/dialog_action.dart';
  2 +import 'package:doublefeel_flutter/app/models/dialog_meta_data.dart';
1 import 'package:doublefeel_flutter/app/modules/home/controllers/my_controller.dart'; 3 import 'package:doublefeel_flutter/app/modules/home/controllers/my_controller.dart';
2 import 'package:doublefeel_flutter/app/routes/app_pages.dart'; 4 import 'package:doublefeel_flutter/app/routes/app_pages.dart';
  5 +import 'package:doublefeel_flutter/app/utils/dialog_utils.dart';
3 6
4 import 'package:doublefeel_flutter/core/network/api/user_api.dart'; 7 import 'package:doublefeel_flutter/core/network/api/user_api.dart';
5 import 'package:doublefeel_flutter/core/result/app_result.dart'; 8 import 'package:doublefeel_flutter/core/result/app_result.dart';
@@ -10,7 +13,6 @@ import 'package:doublefeel_flutter/core/util/app_toast.dart'; @@ -10,7 +13,6 @@ import 'package:doublefeel_flutter/core/util/app_toast.dart';
10 13
11 import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart'; 14 import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart';
12 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; 15 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
13 -import 'package:doublefeel_flutter/r.dart';  
14 import 'package:flutter/material.dart'; 16 import 'package:flutter/material.dart';
15 17
16 import 'package:get/get.dart'; 18 import 'package:get/get.dart';
@@ -160,6 +162,13 @@ class AccountSettingView extends GetView<MyController> { @@ -160,6 +162,13 @@ class AccountSettingView extends GetView<MyController> {
160 } 162 }
161 163
162 Future<void> _logout() async { 164 Future<void> _logout() async {
  165 + final confirmResult = await DialogUtils.showCommonDialog(DialogMetaData(
  166 + title: '退出登录',
  167 + message: '确认退出登录吗?',
  168 + confirmText: '确认退出',
  169 + iconAsset: null));
  170 + if (confirmResult.action != DialogAction.confirm) return;
  171 +
163 await Get.find<UserStateService>().onLogout(); 172 await Get.find<UserStateService>().onLogout();
164 AppToast.show('已退出登录'); 173 AppToast.show('已退出登录');
165 Get.offAllNamed(AppRoutes.login); 174 Get.offAllNamed(AppRoutes.login);
@@ -38,6 +38,7 @@ class TodayHrvAdBanner extends StatelessWidget { @@ -38,6 +38,7 @@ class TodayHrvAdBanner extends StatelessWidget {
38 ), 38 ),
39 ), 39 ),
40 ), 40 ),
  41 + leftImagePath: 'assets/images/today/ic_banner_watch_hrv_theme.png',
41 onClose: controller.dismissHrvAdBanner, 42 onClose: controller.dismissHrvAdBanner,
42 ); 43 );
43 }); 44 });
@@ -86,6 +87,7 @@ class TodayPartnerAdBanner extends StatelessWidget { @@ -86,6 +87,7 @@ class TodayPartnerAdBanner extends StatelessWidget {
86 ), 87 ),
87 ), 88 ),
88 ), 89 ),
  90 + leftImagePath: 'assets/images/today/ic_banner_add_contact.png',
89 onClose: controller.dismissPartnerAdBanner, 91 onClose: controller.dismissPartnerAdBanner,
90 ); 92 );
91 }); 93 });
@@ -98,12 +100,14 @@ class _TodayGuideBanner extends StatelessWidget { @@ -98,12 +100,14 @@ class _TodayGuideBanner extends StatelessWidget {
98 required this.subtitle, 100 required this.subtitle,
99 required this.onClose, 101 required this.onClose,
100 this.right, 102 this.right,
  103 + required this.leftImagePath,
101 }); 104 });
102 105
103 final String title; 106 final String title;
104 final String subtitle; 107 final String subtitle;
105 final VoidCallback onClose; 108 final VoidCallback onClose;
106 final Widget? right; 109 final Widget? right;
  110 + final String leftImagePath;
107 111
108 @override 112 @override
109 Widget build(BuildContext context) { 113 Widget build(BuildContext context) {
@@ -122,22 +126,10 @@ class _TodayGuideBanner extends StatelessWidget { @@ -122,22 +126,10 @@ class _TodayGuideBanner extends StatelessWidget {
122 Row( 126 Row(
123 crossAxisAlignment: CrossAxisAlignment.center, 127 crossAxisAlignment: CrossAxisAlignment.center,
124 children: [ 128 children: [
125 - SizedBox( 129 + Image.asset(
  130 + leftImagePath,
126 width: 100, 131 width: 100,
127 - height: double.infinity,  
128 - child: ColoredBox(  
129 - color: colors.chartPink.withValues(alpha: 0.72),  
130 - child: Center(  
131 - child: Text(  
132 - '插图',  
133 - style: TextStyle(  
134 - fontSize: 12,  
135 - color: colors.chartPink,  
136 - height: 1.2,  
137 - ),  
138 - ),  
139 - ),  
140 - ), 132 + height: 65,
141 ), 133 ),
142 const SizedBox(width: 12), 134 const SizedBox(width: 12),
143 Expanded( 135 Expanded(
@@ -569,7 +569,7 @@ class TodayHrvChartCard extends StatelessWidget { @@ -569,7 +569,7 @@ class TodayHrvChartCard extends StatelessWidget {
569 ), 569 ),
570 ), 570 ),
571 Positioned( 571 Positioned(
572 - top: 97, 572 + top: 57,
573 left: 0, 573 left: 0,
574 right: 0, 574 right: 0,
575 child: Column( 575 child: Column(
@@ -176,6 +176,7 @@ class LoginController extends GetxController { @@ -176,6 +176,7 @@ class LoginController extends GetxController {
176 176
177 if (loginRes is AppSuccess<LoginResponse>) { 177 if (loginRes is AppSuccess<LoginResponse>) {
178 await _handleLoginSuccess(loginRes.data); 178 await _handleLoginSuccess(loginRes.data);
  179 + await Get.find<LocalStorage>().setLastLoginMethod('phone');
179 } else { 180 } else {
180 isLoggingIn.value = false; 181 isLoggingIn.value = false;
181 } 182 }
@@ -187,6 +188,7 @@ class LoginController extends GetxController { @@ -187,6 +188,7 @@ class LoginController extends GetxController {
187 188
188 if (loginRes is AppSuccess<LoginResponse>) { 189 if (loginRes is AppSuccess<LoginResponse>) {
189 await _handleLoginSuccess(loginRes.data, appleModel: appleModel); 190 await _handleLoginSuccess(loginRes.data, appleModel: appleModel);
  191 + await Get.find<LocalStorage>().setLastLoginMethod('apple');
190 } else { 192 } else {
191 isLoggingIn.value = false; 193 isLoggingIn.value = false;
192 } 194 }
@@ -143,7 +143,7 @@ class LoginView extends GetView<LoginController> { @@ -143,7 +143,7 @@ class LoginView extends GetView<LoginController> {
143 right: rightOffset - 4, 143 right: rightOffset - 4,
144 bottom: Get.find<LocalStorage>().lastLoginMethod == 'apple' 144 bottom: Get.find<LocalStorage>().lastLoginMethod == 'apple'
145 ? bottom(117) 145 ? bottom(117)
146 - : bottom(200), 146 + : bottom(188),
147 child: Container( 147 child: Container(
148 padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2), 148 padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
149 decoration: ShapeDecoration( 149 decoration: ShapeDecoration(
  1 +import 'dart:ui';
  2 +
1 import 'package:doublefeel_flutter/core/theme/app_theme.dart'; 3 import 'package:doublefeel_flutter/core/theme/app_theme.dart';
2 import 'package:flutter/src/widgets/framework.dart'; 4 import 'package:flutter/src/widgets/framework.dart';
3 5
@@ -74,7 +76,7 @@ class V2SleepTimeRange { @@ -74,7 +76,7 @@ class V2SleepTimeRange {
74 const V2SleepTimeRange({required this.fromTime, required this.toTime}); 76 const V2SleepTimeRange({required this.fromTime, required this.toTime});
75 77
76 final int fromTime; // Unix 时间戳(秒) 78 final int fromTime; // Unix 时间戳(秒)
77 - final int toTime; // Unix 时间戳(秒) 79 + final int toTime; // Unix 时间戳(秒)
78 80
79 factory V2SleepTimeRange.fromJson(Map<String, dynamic> json) { 81 factory V2SleepTimeRange.fromJson(Map<String, dynamic> json) {
80 return V2SleepTimeRange( 82 return V2SleepTimeRange(
@@ -246,6 +248,34 @@ class V2StressScore { @@ -246,6 +248,34 @@ class V2StressScore {
246 } 248 }
247 return '等待数据'; 249 return '等待数据';
248 } 250 }
  251 +
  252 + String stateBg() {
  253 + switch (state) {
  254 + case 1:
  255 + return 'assets/images/today/bg_stress_state_1.png';
  256 + case 2:
  257 + return 'assets/images/today/bg_stress_state_2.png';
  258 + case 3:
  259 + return 'assets/images/today/bg_stress_state_3.png';
  260 + case 4:
  261 + return 'assets/images/today/bg_stress_state_4.png';
  262 + }
  263 + return 'assets/images/today/bg_stress_state_0.png';
  264 + }
  265 +
  266 + Color getBackgroundColor() {
  267 + switch (state) {
  268 + case 1:
  269 + return const Color(0xFFFFE3EE);
  270 + case 2:
  271 + return const Color(0xFFFFE8DE);
  272 + case 3:
  273 + return const Color(0xFFD4E2FF);
  274 + case 4:
  275 + return const Color(0xFFC8F6E5);
  276 + }
  277 + return const Color(0xFFE3E1EC);
  278 + }
249 } 279 }
250 280
251 /// Single item in v2/hrv_trend/ list 281 /// Single item in v2/hrv_trend/ list