Showing
18 changed files
with
192 additions
and
98 deletions
assets/images/today/bg_stress_state_0.png
0 → 100644
8.54 KB
assets/images/today/bg_stress_state_1.png
0 → 100644
6.42 KB
assets/images/today/bg_stress_state_2.png
0 → 100644
9.88 KB
assets/images/today/bg_stress_state_3.png
0 → 100644
8.22 KB
assets/images/today/bg_stress_state_4.png
0 → 100644
13.4 KB
1.97 KB
5.66 KB
| @@ -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 |
-
Please register or login to post a comment