Commit 2837b6c8e43bb69b84d72b9deef93c11b698fbd3

Authored by 常守达
1 parent 9a6eb289

feat(track):埋点相关

@@ -98,6 +98,19 @@ class PlatformHostApiImpl(private val application: android.app.Application) : Pl @@ -98,6 +98,19 @@ class PlatformHostApiImpl(private val application: android.app.Application) : Pl
98 return BuildConfig.DEBUG 98 return BuildConfig.DEBUG
99 } 99 }
100 100
  101 + override fun shareText(
  102 + text: String,
  103 + callback: (Result<Boolean>) -> Unit
  104 + ) {
  105 +
  106 + }
  107 +
  108 + override fun shareFileData(
  109 + databytes: ByteArray,
  110 + callback: (Result<Boolean>) -> Unit
  111 + ) {
  112 + }
  113 +
101 override fun requestAppReview(callback: (Result<Boolean>) -> Unit) { 114 override fun requestAppReview(callback: (Result<Boolean>) -> Unit) {
102 } 115 }
103 116
@@ -8,6 +8,7 @@ import 'package:doublefeel_flutter/core/error/app_error.dart'; @@ -8,6 +8,7 @@ import 'package:doublefeel_flutter/core/error/app_error.dart';
8 import 'package:doublefeel_flutter/core/error/http_error_handling_policy.dart'; 8 import 'package:doublefeel_flutter/core/error/http_error_handling_policy.dart';
9 import 'package:doublefeel_flutter/core/network/api/friend_api.dart'; 9 import 'package:doublefeel_flutter/core/network/api/friend_api.dart';
10 import 'package:doublefeel_flutter/core/result/app_result.dart'; 10 import 'package:doublefeel_flutter/core/result/app_result.dart';
  11 +import 'package:doublefeel_flutter/core/services/thinking_data_service.dart';
11 import 'package:doublefeel_flutter/core/services/user_state_service.dart'; 12 import 'package:doublefeel_flutter/core/services/user_state_service.dart';
12 import 'package:doublefeel_flutter/core/util/app_toast.dart'; 13 import 'package:doublefeel_flutter/core/util/app_toast.dart';
13 import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart'; 14 import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart';
@@ -34,12 +35,22 @@ class BindPartnerController extends GetxController { @@ -34,12 +35,22 @@ class BindPartnerController extends GetxController {
34 35
35 late bool isShowAppBarBack; 36 late bool isShowAppBarBack;
36 late bool isShowSkipButton; 37 late bool isShowSkipButton;
  38 + var channel = '';
37 39
38 @override 40 @override
39 void onInit() { 41 void onInit() {
40 super.onInit(); 42 super.onInit();
41 final from = Get.arguments?['from'] ?? ''; 43 final from = Get.arguments?['from'] ?? '';
42 if (from == 'onboarding') { 44 if (from == 'onboarding') {
  45 + channel = '新手引导';
  46 + } else if (from == 'FriendsTab') {
  47 + channel = '好友页';
  48 + } else if (from == 'today') {
  49 + channel = '首页';
  50 + } else {
  51 + channel = '其他';
  52 + }
  53 + if (from == 'onboarding') {
43 isShowAppBarBack = false; 54 isShowAppBarBack = false;
44 isShowSkipButton = true; 55 isShowSkipButton = true;
45 } else { 56 } else {
@@ -57,6 +68,13 @@ class BindPartnerController extends GetxController { @@ -57,6 +68,13 @@ class BindPartnerController extends GetxController {
57 } 68 }
58 69
59 @override 70 @override
  71 + void onReady() {
  72 + super.onReady();
  73 + ta.track('enter_doublefeel_add_friend_page',
  74 + properties: {'channel_type': channel});
  75 + }
  76 +
  77 + @override
60 void onClose() { 78 void onClose() {
61 partnerIdController.dispose(); 79 partnerIdController.dispose();
62 super.onClose(); 80 super.onClose();
@@ -66,6 +84,8 @@ class BindPartnerController extends GetxController { @@ -66,6 +84,8 @@ class BindPartnerController extends GetxController {
66 84
67 void onShareMyCode() async { 85 void onShareMyCode() async {
68 try { 86 try {
  87 + ta.track('enter_doublefeel_add_friend_page',
  88 + properties: {'channel_type': channel, 'click_content': '分享我的码'});
69 final success = await PlatformHostApi() 89 final success = await PlatformHostApi()
70 .shareText(l10n.sharePartnerCodeTemplate(myInviteCode.value)); 90 .shareText(l10n.sharePartnerCodeTemplate(myInviteCode.value));
71 } catch (e) { 91 } catch (e) {
@@ -74,6 +94,8 @@ class BindPartnerController extends GetxController { @@ -74,6 +94,8 @@ class BindPartnerController extends GetxController {
74 } 94 }
75 95
76 Future<void> onSubmitPartnerId() async { 96 Future<void> onSubmitPartnerId() async {
  97 + ta.track('enter_doublefeel_add_friend_page',
  98 + properties: {'channel_type': channel, 'click_content': '继续'});
77 if (!canSubmit || isSubmitting.value) return; 99 if (!canSubmit || isSubmitting.value) return;
78 isSubmitting.value = true; 100 isSubmitting.value = true;
79 try { 101 try {
@@ -120,6 +142,7 @@ class BindPartnerController extends GetxController { @@ -120,6 +142,7 @@ class BindPartnerController extends GetxController {
120 } else { 142 } else {
121 Get.to(_BindSuccessPage(friendItem)); 143 Get.to(_BindSuccessPage(friendItem));
122 } 144 }
  145 + ta.track('success_add_doubelfeel_friend');
123 break; 146 break;
124 } 147 }
125 } catch (e) { 148 } catch (e) {
@@ -129,6 +152,8 @@ class BindPartnerController extends GetxController { @@ -129,6 +152,8 @@ class BindPartnerController extends GetxController {
129 } 152 }
130 153
131 Future<void> onSkip() async { 154 Future<void> onSkip() async {
  155 + ta.track('enter_doublefeel_add_friend_page',
  156 + properties: {'channel_type': channel, 'click_content': '下次再说'});
132 final userStateService = Get.find<UserStateService>(); 157 final userStateService = Get.find<UserStateService>();
133 if (!userStateService.isVip) { 158 if (!userStateService.isVip) {
134 // 使用 offNamed 移除 BIND_PARTNER,并将 onboarding 标识传入 PURCHASE 159 // 使用 offNamed 移除 BIND_PARTNER,并将 onboarding 标识传入 PURCHASE
1 import 'package:doublefeel_flutter/app/widget/dash_divider.dart'; 1 import 'package:doublefeel_flutter/app/widget/dash_divider.dart';
  2 +import 'package:doublefeel_flutter/core/services/thinking_data_service.dart';
2 import 'package:doublefeel_flutter/core/theme/app_theme.dart'; 3 import 'package:doublefeel_flutter/core/theme/app_theme.dart';
3 import 'package:doublefeel_flutter/core/util/app_toast.dart'; 4 import 'package:doublefeel_flutter/core/util/app_toast.dart';
4 import 'package:flutter/material.dart'; 5 import 'package:flutter/material.dart';
@@ -198,6 +199,10 @@ class BindPartnerView extends GetView<BindPartnerController> { @@ -198,6 +199,10 @@ class BindPartnerView extends GetView<BindPartnerController> {
198 ClipboardData(text: controller.myInviteCode.value), 199 ClipboardData(text: controller.myInviteCode.value),
199 ); 200 );
200 AppToast.show('复制成功'); 201 AppToast.show('复制成功');
  202 + ta.track('enter_doublefeel_add_friend_page', properties: {
  203 + 'channel_type': controller.channel,
  204 + 'click_content': '复制共享码'
  205 + });
201 }, 206 },
202 child: Container( 207 child: Container(
203 width: 20, 208 width: 20,
@@ -2,6 +2,7 @@ import 'package:doublefeel_flutter/app/modules/friends/controllers/friend_trend_ @@ -2,6 +2,7 @@ import 'package:doublefeel_flutter/app/modules/friends/controllers/friend_trend_
2 import 'package:doublefeel_flutter/app/modules/friends/controllers/friends_controller.dart'; 2 import 'package:doublefeel_flutter/app/modules/friends/controllers/friends_controller.dart';
3 import 'package:doublefeel_flutter/core/network/api/friend_api.dart'; 3 import 'package:doublefeel_flutter/core/network/api/friend_api.dart';
4 import 'package:doublefeel_flutter/core/result/app_result.dart'; 4 import 'package:doublefeel_flutter/core/result/app_result.dart';
  5 +import 'package:doublefeel_flutter/core/services/thinking_data_service.dart';
5 import 'package:doublefeel_flutter/core/services/user_state_service.dart'; 6 import 'package:doublefeel_flutter/core/services/user_state_service.dart';
6 import 'package:doublefeel_flutter/data/local/local_storage.dart'; 7 import 'package:doublefeel_flutter/data/local/local_storage.dart';
7 import 'package:doublefeel_flutter/pigeon/platform_api.g.dart'; 8 import 'package:doublefeel_flutter/pigeon/platform_api.g.dart';
@@ -119,6 +120,14 @@ class HomeController extends GetxController { @@ -119,6 +120,14 @@ class HomeController extends GetxController {
119 } else if (previousIndex == friendsTabIndex && index != friendsTabIndex) { 120 } else if (previousIndex == friendsTabIndex && index != friendsTabIndex) {
120 Get.find<FriendsController>().markPageHidden(); 121 Get.find<FriendsController>().markPageHidden();
121 } 122 }
  123 + switch (index) {
  124 + case 0:
  125 + // ta.track('enter_doublefeel_my_page');
  126 + break;
  127 + case 3:
  128 + ta.track('enter_doublefeel_my_page');
  129 + break;
  130 + }
122 } 131 }
123 132
124 void openTrend(TrendType type, {DateTime? date, ReportPeriod? period}) { 133 void openTrend(TrendType type, {DateTime? date, ReportPeriod? period}) {
1 import 'dart:async'; 1 import 'dart:async';
  2 +import 'dart:ui';
2 3
3 import 'package:doublefeel_flutter/app/modules/friends/controllers/friend_trend_controller.dart'; 4 import 'package:doublefeel_flutter/app/modules/friends/controllers/friend_trend_controller.dart';
4 import 'package:doublefeel_flutter/app/modules/home/controllers/home_controller.dart'; 5 import 'package:doublefeel_flutter/app/modules/home/controllers/home_controller.dart';
@@ -14,6 +15,7 @@ import 'package:doublefeel_flutter/core/network/api/pay_api.dart'; @@ -14,6 +15,7 @@ import 'package:doublefeel_flutter/core/network/api/pay_api.dart';
14 import 'package:doublefeel_flutter/core/network/api/vip_api.dart'; 15 import 'package:doublefeel_flutter/core/network/api/vip_api.dart';
15 import 'package:doublefeel_flutter/core/result/app_result.dart'; 16 import 'package:doublefeel_flutter/core/result/app_result.dart';
16 import 'package:doublefeel_flutter/core/services/loading_service.dart'; 17 import 'package:doublefeel_flutter/core/services/loading_service.dart';
  18 +import 'package:doublefeel_flutter/core/services/thinking_data_service.dart';
17 import 'package:doublefeel_flutter/core/services/user_state_service.dart'; 19 import 'package:doublefeel_flutter/core/services/user_state_service.dart';
18 import 'package:doublefeel_flutter/core/util/app_toast.dart'; 20 import 'package:doublefeel_flutter/core/util/app_toast.dart';
19 import 'package:doublefeel_flutter/data/local/user_account_storage.dart'; 21 import 'package:doublefeel_flutter/data/local/user_account_storage.dart';
@@ -29,6 +31,7 @@ import 'package:doublefeel_flutter/pigeon/wear_engine_api.g.dart'; @@ -29,6 +31,7 @@ import 'package:doublefeel_flutter/pigeon/wear_engine_api.g.dart';
29 import 'package:flutter/material.dart'; 31 import 'package:flutter/material.dart';
30 import 'package:get/get.dart'; 32 import 'package:get/get.dart';
31 import 'package:intl/intl.dart'; 33 import 'package:intl/intl.dart';
  34 +import 'package:permission_handler/permission_handler.dart';
32 35
33 /// HRV 趋势数据点 36 /// HRV 趋势数据点
34 class HrvDataPoint { 37 class HrvDataPoint {
@@ -135,6 +138,15 @@ class TodayController extends GetMaterialController { @@ -135,6 +138,15 @@ class TodayController extends GetMaterialController {
135 final v2ActivityTarget = Rxn<V2ActivityTarget>(); 138 final v2ActivityTarget = Rxn<V2ActivityTarget>();
136 139
137 @override 140 @override
  141 + void onReady() {
  142 + super.onReady();
  143 + ta.track(
  144 + 'enter_doublefeel_today_status',
  145 + properties: {'user_role': isFriend ? '好友的' : '我的'},
  146 + );
  147 + }
  148 +
  149 + @override
138 void onInit() { 150 void onInit() {
139 super.onInit(); 151 super.onInit();
140 targetFriendInfo.value = _initialFriendInfo; 152 targetFriendInfo.value = _initialFriendInfo;
@@ -155,6 +167,7 @@ class TodayController extends GetMaterialController { @@ -155,6 +167,7 @@ class TodayController extends GetMaterialController {
155 checkAddFriendVisible(); 167 checkAddFriendVisible();
156 checkHrvAdBannerVisible(); 168 checkHrvAdBannerVisible();
157 checkHealthDataAuthCardVisible(); 169 checkHealthDataAuthCardVisible();
  170 + checkNotificationCardVisible();
158 if (!Get.find<UserStateService>().isVip) { 171 if (!Get.find<UserStateService>().isVip) {
159 getProductList(); 172 getProductList();
160 } 173 }
@@ -287,6 +300,7 @@ class TodayController extends GetMaterialController { @@ -287,6 +300,7 @@ class TodayController extends GetMaterialController {
287 } 300 }
288 301
289 Future<void> onAuthorizeTap() async { 302 Future<void> onAuthorizeTap() async {
  303 + ta.track('click_doublefeel_today_status', properties: {'ita': '授权访问健康数据'});
290 if (showHealthDataAuthCardStatus.value == 1) { 304 if (showHealthDataAuthCardStatus.value == 1) {
291 return; 305 return;
292 } else if (showHealthDataAuthCardStatus.value == 0) { 306 } else if (showHealthDataAuthCardStatus.value == 0) {
@@ -322,7 +336,7 @@ class TodayController extends GetMaterialController { @@ -322,7 +336,7 @@ class TodayController extends GetMaterialController {
322 [HealthAuthorization? preResult]) async { 336 [HealthAuthorization? preResult]) async {
323 try { 337 try {
324 final result = preResult ?? await _hostApi.checkHealthAppAuthorization(); 338 final result = preResult ?? await _hostApi.checkHealthAppAuthorization();
325 - 339 + ta.userSet({'health_data_permission': result.status.clamp(0, 1)});
326 if (result.status == 1) { 340 if (result.status == 1) {
327 await _performDataUpload(); 341 await _performDataUpload();
328 } 342 }
@@ -335,6 +349,26 @@ class TodayController extends GetMaterialController { @@ -335,6 +349,26 @@ class TodayController extends GetMaterialController {
335 } catch (e) {} 349 } catch (e) {}
336 } 350 }
337 351
  352 + Future<void> checkNotificationCardVisible() async {
  353 + try {
  354 + Permission.notification.status.then((status) {
  355 + ta.userSet({'notification_permission': status.isGranted ? 1 : 0});
  356 + // if (status.isGranted) {
  357 + // return;
  358 + // }
  359 +
  360 + // if (status.isPermanentlyDenied) {
  361 + // // await openAppSettings();
  362 + // return;
  363 + // }
  364 +
  365 + // final result = await Permission.notification.request();
  366 + });
  367 + } catch (error) {
  368 + AppLogger.e('Notification authorization failed: $error');
  369 + }
  370 + }
  371 +
338 Future<void> _refreshHealthDataForDate(DateTime date) async { 372 Future<void> _refreshHealthDataForDate(DateTime date) async {
339 _clearRealTimeData(); 373 _clearRealTimeData();
340 final intDate = int.parse(DateFormat('yyyyMMdd').format(date)); 374 final intDate = int.parse(DateFormat('yyyyMMdd').format(date));
@@ -4,6 +4,7 @@ import 'package:doublefeel_flutter/app/modules/home/widgets/today/hrv_measuremen @@ -4,6 +4,7 @@ import 'package:doublefeel_flutter/app/modules/home/widgets/today/hrv_measuremen
4 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';
5 import 'package:doublefeel_flutter/app/modules/report_common/widgets/report_bottom_slogan.dart'; 5 import 'package:doublefeel_flutter/app/modules/report_common/widgets/report_bottom_slogan.dart';
6 import 'package:doublefeel_flutter/app/modules/report_common/widgets/report_date_picker_sheet.dart'; 6 import 'package:doublefeel_flutter/app/modules/report_common/widgets/report_date_picker_sheet.dart';
  7 +import 'package:doublefeel_flutter/core/services/thinking_data_service.dart';
7 8
8 import 'package:doublefeel_flutter/core/services/user_state_service.dart'; 9 import 'package:doublefeel_flutter/core/services/user_state_service.dart';
9 import 'package:doublefeel_flutter/core/theme/app_theme.dart'; 10 import 'package:doublefeel_flutter/core/theme/app_theme.dart';
@@ -99,6 +100,8 @@ class TodayTabBody extends StatelessWidget { @@ -99,6 +100,8 @@ class TodayTabBody extends StatelessWidget {
99 ), 100 ),
100 onBackToToday: _backToToday, 101 onBackToToday: _backToToday,
101 onTapPremiumCard: () { 102 onTapPremiumCard: () {
  103 + ta.track('click_doublefeel_today_status',
  104 + properties: {'ita': '右上角VIP优惠入口'});
102 controller.toPremiumDiscoutPage(); 105 controller.toPremiumDiscoutPage();
103 }, 106 },
104 ), 107 ),
@@ -227,7 +230,11 @@ class TodayTabBody extends StatelessWidget { @@ -227,7 +230,11 @@ class TodayTabBody extends StatelessWidget {
227 return Get.find<UserStateService>().isVip 230 return Get.find<UserStateService>().isVip
228 ? const SizedBox.shrink() 231 ? const SizedBox.shrink()
229 : GestureDetector( 232 : GestureDetector(
230 - onTap: () => controller.toPremiumDiscoutPage(), 233 + onTap: () {
  234 + ta.track('click_doublefeel_today_status',
  235 + properties: {'ita': '会员banner'});
  236 + controller.toPremiumDiscoutPage();
  237 + },
231 child: PremiumCard( 238 child: PremiumCard(
232 controller, 239 controller,
233 )); 240 ));
@@ -674,6 +681,8 @@ class _TopFriendBar extends StatelessWidget { @@ -674,6 +681,8 @@ class _TopFriendBar extends StatelessWidget {
674 highlightColor: Colors.transparent, 681 highlightColor: Colors.transparent,
675 padding: EdgeInsets.zero, 682 padding: EdgeInsets.zero,
676 onPressed: () { 683 onPressed: () {
  684 + ta.track('click_doublefeel_today_status',
  685 + properties: {'ita': '切换好友'});
677 controller.showFriendListBottomSheet(); 686 controller.showFriendListBottomSheet();
678 }, 687 },
679 icon: Image.asset( 688 icon: Image.asset(
  1 +import 'package:doublefeel_flutter/core/services/thinking_data_service.dart';
1 import 'package:doublefeel_flutter/core/theme/app_theme.dart'; 2 import 'package:doublefeel_flutter/core/theme/app_theme.dart';
2 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; 3 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
3 import 'package:flutter/material.dart'; 4 import 'package:flutter/material.dart';
4 import 'package:get/get.dart'; 5 import 'package:get/get.dart';
5 6
6 void showHrvMeasurementBottomSheet() { 7 void showHrvMeasurementBottomSheet() {
  8 + ta.track('click_doublefeel_today_status', properties: {'ita': '立刻测量HRV'});
7 Get.bottomSheet( 9 Get.bottomSheet(
8 const FractionallySizedBox( 10 const FractionallySizedBox(
9 heightFactor: 0.9, 11 heightFactor: 0.9,
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/services/thinking_data_service.dart';
2 import 'package:doublefeel_flutter/core/theme/app_theme.dart'; 3 import 'package:doublefeel_flutter/core/theme/app_theme.dart';
3 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; 4 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
4 import 'package:flutter/material.dart'; 5 import 'package:flutter/material.dart';
@@ -18,6 +19,8 @@ class TodayHrvAdBanner extends StatelessWidget { @@ -18,6 +19,8 @@ class TodayHrvAdBanner extends StatelessWidget {
18 19
19 return GestureDetector( 20 return GestureDetector(
20 onTap: () async { 21 onTap: () async {
  22 + ta.track('click_doublefeel_today_status',
  23 + properties: {'ita': '点击添加HRV表盘'});
21 await Get.toNamed(Routes.WATCH_THEME); 24 await Get.toNamed(Routes.WATCH_THEME);
22 controller.checkAddFriendVisible(); 25 controller.checkAddFriendVisible();
23 }, 26 },
@@ -61,7 +64,9 @@ class TodayPartnerAdBanner extends StatelessWidget { @@ -61,7 +64,9 @@ class TodayPartnerAdBanner extends StatelessWidget {
61 64
62 return GestureDetector( 65 return GestureDetector(
63 onTap: () async { 66 onTap: () async {
64 - await Get.toNamed(AppRoutes.bindPartner); 67 + ta.track('click_doublefeel_today_status', properties: {'ita': '加好友'});
  68 + await Get.toNamed(AppRoutes.bindPartner,
  69 + arguments: {'from': 'today'});
65 controller.checkAddFriendVisible(); 70 controller.checkAddFriendVisible();
66 }, 71 },
67 child: _TodayGuideBanner( 72 child: _TodayGuideBanner(
@@ -34,8 +34,7 @@ class TodayHrvNumberCard extends StatelessWidget { @@ -34,8 +34,7 @@ class TodayHrvNumberCard extends StatelessWidget {
34 label: controller.isFriend 34 label: controller.isFriend
35 ? context.l10n.reportOtherPossessiveTitle(otherHrv) 35 ? context.l10n.reportOtherPossessiveTitle(otherHrv)
36 : otherHrv, 36 : otherHrv,
37 - value:  
38 - controller.v2HealthData.value?.hrvAvg?.toString() ?? '--', 37 + value: controller.v2HealthData.value?.hrvAvg?.toString() ?? '-',
39 unit: 'ms', 38 unit: 'ms',
40 ), 39 ),
41 ), 40 ),
@@ -48,7 +47,7 @@ class TodayHrvNumberCard extends StatelessWidget { @@ -48,7 +47,7 @@ class TodayHrvNumberCard extends StatelessWidget {
48 : context.l10n.restingHeartRate, 47 : context.l10n.restingHeartRate,
49 value: controller.v2HealthData.value?.lastRestingHrValue 48 value: controller.v2HealthData.value?.lastRestingHrValue
50 ?.toString() ?? 49 ?.toString() ??
51 - '--', 50 + '-',
52 unit: 'bpm', 51 unit: 'bpm',
53 ), 52 ),
54 ), 53 ),
@@ -13,6 +13,7 @@ class TodaySleepCard extends StatelessWidget { @@ -13,6 +13,7 @@ class TodaySleepCard extends StatelessWidget {
13 13
14 @override 14 @override
15 Widget build(BuildContext context) { 15 Widget build(BuildContext context) {
  16 + final l10n = context.l10n;
16 return GestureDetector( 17 return GestureDetector(
17 onTap: controller.toTrendSleepPage, 18 onTap: controller.toTrendSleepPage,
18 child: Obx(() { 19 child: Obx(() {
@@ -25,10 +26,10 @@ class TodaySleepCard extends StatelessWidget { @@ -25,10 +26,10 @@ class TodaySleepCard extends StatelessWidget {
25 ? context.colors.textPrimary 26 ? context.colors.textPrimary
26 : healthData?.sleepStateColor(context); 27 : healthData?.sleepStateColor(context);
27 String sleepStateStr = 28 String sleepStateStr =
28 - sleepDuration == 0 ? '--' : healthData?.sleepStateStr() ?? '--'; 29 + sleepDuration == 0 ? '-' : healthData?.sleepStateStr() ?? '-';
29 String sleepAverageHeartRate = 30 String sleepAverageHeartRate =
30 (healthData?.hrAvg == null || healthData?.hrAvg == 0) 31 (healthData?.hrAvg == null || healthData?.hrAvg == 0)
31 - ? '--' 32 + ? '-'
32 : '${healthData?.hrAvg}'; 33 : '${healthData?.hrAvg}';
33 double sleepDurationProgress = sleepDuration == 0 34 double sleepDurationProgress = sleepDuration == 0
34 ? -1 35 ? -1
@@ -39,36 +40,103 @@ class TodaySleepCard extends StatelessWidget { @@ -39,36 +40,103 @@ class TodaySleepCard extends StatelessWidget {
39 return _TodaySummaryCard( 40 return _TodaySummaryCard(
40 iconAsset: 'assets/images/common/ic_sleep_stroke.png', 41 iconAsset: 'assets/images/common/ic_sleep_stroke.png',
41 iconColor: context.colors.primary, 42 iconColor: context.colors.primary,
42 - title: context.l10n.sleep,  
43 - actionText: context.l10n.viewSleepReport, 43 + title: l10n.sleep,
  44 + actionText: l10n.viewSleepReport,
44 metrics: [ 45 metrics: [
45 - _MetricData(  
46 - label: context.l10n.duration,  
47 - labelColor: context.colors.primary,  
48 - valueSpans: [  
49 - _MetricValueSpan(  
50 - sleepHours > 0 ? '$sleepHours' : '--', l10n.reportUnitHour),  
51 - _MetricValueSpan(sleepMinutes > 0 ? '$sleepMinutes' : '--',  
52 - l10n.reportUnitMinute),  
53 - ],  
54 - ),  
55 - _MetricData(  
56 - label: context.l10n.quality, 46 + _MetricBlock(
  47 + label: l10n.duration,
  48 + labelColor: context.colors.primary,
  49 + value: (sleepDuration > 0)
  50 + ? Text.rich(
  51 + TextSpan(
  52 + style: TextStyle(
  53 + color: context.colors.textPrimary,
  54 + fontSize: 16,
  55 + fontWeight: FontWeight.w600,
  56 + height: 19 / 16,
  57 + ),
  58 + children: [
  59 + if (sleepHours > 0) ...[
  60 + TextSpan(text: '$sleepHours'),
  61 + TextSpan(
  62 + text: ' ${l10n.reportUnitHour} ',
  63 + style: TextStyle(
  64 + color: context.colors.textSecondary,
  65 + fontSize: 12,
  66 + fontWeight: FontWeight.w400,
  67 + ),
  68 + )
  69 + ],
  70 + if (sleepMinutes > 0) ...[
  71 + TextSpan(text: '$sleepMinutes'),
  72 + TextSpan(
  73 + text: ' ${l10n.reportUnitMinute}',
  74 + style: TextStyle(
  75 + color: context.colors.textSecondary,
  76 + fontSize: 12,
  77 + fontWeight: FontWeight.w400,
  78 + ),
  79 + ),
  80 + ]
  81 + ],
  82 + ),
  83 + )
  84 + : Text(
  85 + '-',
  86 + style: TextStyle(
  87 + color: context.colors.textPrimary,
  88 + fontSize: 16,
  89 + fontWeight: FontWeight.w600,
  90 + height: 19 / 16,
  91 + ),
  92 + )),
  93 + _MetricBlock(
  94 + label: l10n.quality,
57 labelColor: const Color(0xFF7B9BFB), 95 labelColor: const Color(0xFF7B9BFB),
58 - valueSpans: [  
59 - _MetricValueSpan(  
60 - sleepStateStr,  
61 - '',  
62 - valueColor: sleepStateColor, 96 + value: Text(
  97 + sleepStateStr,
  98 + style: TextStyle(
  99 + color: sleepStateColor,
  100 + fontSize: 16,
  101 + fontWeight: FontWeight.w600,
  102 + height: 19 / 16,
63 ), 103 ),
64 - ], 104 + ),
65 ), 105 ),
66 - _MetricData(  
67 - label: context.l10n.averageHeartRate, 106 + _MetricBlock(
  107 + label: l10n.averageHeartRate,
68 labelColor: context.colors.textSecondary, 108 labelColor: context.colors.textSecondary,
69 - valueSpans: [  
70 - _MetricValueSpan(sleepAverageHeartRate, 'bpm'),  
71 - ], 109 + value: sleepDuration > 0 && ((healthData?.hrAvg ?? 0) >= 0)
  110 + ? Text.rich(
  111 + TextSpan(
  112 + style: TextStyle(
  113 + color: context.colors.textPrimary,
  114 + fontSize: 16,
  115 + fontWeight: FontWeight.w600,
  116 + height: 19 / 16,
  117 + ),
  118 + children: [
  119 + TextSpan(text: sleepAverageHeartRate),
  120 + TextSpan(
  121 + text: ' bpm',
  122 + style: TextStyle(
  123 + color: context.colors.textSecondary,
  124 + fontSize: 12,
  125 + fontWeight: FontWeight.w400,
  126 + ),
  127 + ),
  128 + ],
  129 + ),
  130 + )
  131 + : Text(
  132 + '-',
  133 + style: TextStyle(
  134 + color: context.colors.textPrimary,
  135 + fontSize: 16,
  136 + fontWeight: FontWeight.w600,
  137 + height: 19 / 16,
  138 + ),
  139 + ),
72 ), 140 ),
73 ], 141 ],
74 rightWidget: Container( 142 rightWidget: Container(
@@ -104,6 +172,7 @@ class TodayActivityCard extends StatelessWidget { @@ -104,6 +172,7 @@ class TodayActivityCard extends StatelessWidget {
104 172
105 @override 173 @override
106 Widget build(BuildContext context) { 174 Widget build(BuildContext context) {
  175 + final l10n = context.l10n;
107 return GestureDetector( 176 return GestureDetector(
108 onTap: controller.toTrendActivityPage, 177 onTap: controller.toTrendActivityPage,
109 child: Obx(() { 178 child: Obx(() {
@@ -115,30 +184,100 @@ class TodayActivityCard extends StatelessWidget { @@ -115,30 +184,100 @@ class TodayActivityCard extends StatelessWidget {
115 184
116 var activityStr = (activity > 0 && (activityTarget?.move ?? 0) > 0) 185 var activityStr = (activity > 0 && (activityTarget?.move ?? 0) > 0)
117 ? '$activity' 186 ? '$activity'
118 - : '--'; 187 + : '-';
119 // exercise 单位为秒,转换为小时+分钟 188 // exercise 单位为秒,转换为小时+分钟
120 - List<_MetricValueSpan> exerciseSpans; 189 + Widget exerciseWidget;
121 if (exercise > 0 && (activityTarget?.exercise ?? 0) > 0) { 190 if (exercise > 0 && (activityTarget?.exercise ?? 0) > 0) {
122 final exHours = exercise ~/ 3600; 191 final exHours = exercise ~/ 3600;
123 final exMinutes = (exercise % 3600) ~/ 60; 192 final exMinutes = (exercise % 3600) ~/ 60;
124 - exerciseSpans = [  
125 - if (exHours > 0) _MetricValueSpan('$exHours', l10n.reportUnitHour),  
126 - if (exMinutes > 0 || exHours == 0)  
127 - _MetricValueSpan(  
128 - exMinutes > 0 ? '$exMinutes' : '0', l10n.reportUnitMinute),  
129 - ]; 193 + exerciseWidget = Text.rich(
  194 + TextSpan(
  195 + style: TextStyle(
  196 + color: context.colors.textPrimary,
  197 + fontSize: 16,
  198 + fontWeight: FontWeight.w600,
  199 + height: 19 / 16,
  200 + ),
  201 + children: [
  202 + if (exHours > 0) ...[
  203 + TextSpan(text: '$exHours'),
  204 + TextSpan(
  205 + text: ' ${l10n.reportUnitHour} ',
  206 + style: TextStyle(
  207 + color: context.colors.textSecondary,
  208 + fontSize: 12,
  209 + fontWeight: FontWeight.w400,
  210 + ),
  211 + ),
  212 + ],
  213 + if (exMinutes > 0 || exHours == 0) ...[
  214 + TextSpan(text: exMinutes > 0 ? '$exMinutes' : '0'),
  215 + TextSpan(
  216 + text: ' ${l10n.reportUnitMinute}',
  217 + style: TextStyle(
  218 + color: context.colors.textSecondary,
  219 + fontSize: 12,
  220 + fontWeight: FontWeight.w400,
  221 + ),
  222 + ),
  223 + ],
  224 + ],
  225 + ),
  226 + );
130 } else { 227 } else {
131 - exerciseSpans = [_MetricValueSpan('--', l10n.reportUnitMinute)]; 228 + exerciseWidget = Text.rich(
  229 + TextSpan(
  230 + style: TextStyle(
  231 + color: context.colors.textPrimary,
  232 + fontSize: 16,
  233 + fontWeight: FontWeight.w600,
  234 + height: 19 / 16,
  235 + ),
  236 + children: [
  237 + const TextSpan(text: '-'),
  238 + ],
  239 + ),
  240 + );
132 } 241 }
133 242
134 // stand 单位为秒,转换为小时+分钟 243 // stand 单位为秒,转换为小时+分钟
135 - List<_MetricValueSpan> standSpans; 244 + Widget standWidget;
136 if (stand > 0 && (activityTarget?.stand ?? 0) > 0) { 245 if (stand > 0 && (activityTarget?.stand ?? 0) > 0) {
137 - standSpans = [  
138 - _MetricValueSpan('$stand', l10n.reportUnitHour),  
139 - ]; 246 + standWidget = Text.rich(
  247 + TextSpan(
  248 + style: TextStyle(
  249 + color: context.colors.textPrimary,
  250 + fontSize: 16,
  251 + fontWeight: FontWeight.w600,
  252 + height: 19 / 16,
  253 + ),
  254 + children: [
  255 + TextSpan(text: '$stand'),
  256 + TextSpan(
  257 + text: ' ${l10n.reportUnitHour}',
  258 + style: TextStyle(
  259 + color: context.colors.textSecondary,
  260 + fontSize: 12,
  261 + fontWeight: FontWeight.w400,
  262 + ),
  263 + ),
  264 + ],
  265 + ),
  266 + );
140 } else { 267 } else {
141 - standSpans = [_MetricValueSpan('--', l10n.reportUnitHour)]; 268 + standWidget = Text.rich(
  269 + TextSpan(
  270 + style: TextStyle(
  271 + color: context.colors.textPrimary,
  272 + fontSize: 16,
  273 + fontWeight: FontWeight.w600,
  274 + height: 19 / 16,
  275 + ),
  276 + children: [
  277 + const TextSpan(text: '-'),
  278 + ],
  279 + ),
  280 + );
142 } 281 }
143 double activityProgress = 282 double activityProgress =
144 (activity > 0 && (activityTarget?.move ?? 0) > 0) 283 (activity > 0 && (activityTarget?.move ?? 0) > 0)
@@ -155,25 +294,43 @@ class TodayActivityCard extends StatelessWidget { @@ -155,25 +294,43 @@ class TodayActivityCard extends StatelessWidget {
155 return _TodaySummaryCard( 294 return _TodaySummaryCard(
156 iconAsset: 'assets/images/common/ic_exercise.png', 295 iconAsset: 'assets/images/common/ic_exercise.png',
157 iconColor: context.colors.warning, 296 iconColor: context.colors.warning,
158 - title: context.l10n.fitness,  
159 - actionText: context.l10n.viewFitnessReport, 297 + title: l10n.fitness,
  298 + actionText: l10n.viewFitnessReport,
160 metrics: [ 299 metrics: [
161 - _MetricData(  
162 - label: context.l10n.event, 300 + _MetricBlock(
  301 + label: l10n.event,
163 labelColor: context.colors.warning, 302 labelColor: context.colors.warning,
164 - valueSpans: [  
165 - _MetricValueSpan(activityStr, l10n.reportUnitKcal),  
166 - ], 303 + value: Text.rich(
  304 + TextSpan(
  305 + style: TextStyle(
  306 + color: context.colors.textPrimary,
  307 + fontSize: 16,
  308 + fontWeight: FontWeight.w600,
  309 + height: 19 / 16,
  310 + ),
  311 + children: [
  312 + TextSpan(text: activityStr),
  313 + TextSpan(
  314 + text: ' ${l10n.reportUnitKcal}',
  315 + style: TextStyle(
  316 + color: context.colors.textSecondary,
  317 + fontSize: 12,
  318 + fontWeight: FontWeight.w400,
  319 + ),
  320 + ),
  321 + ],
  322 + ),
  323 + ),
167 ), 324 ),
168 - _MetricData(  
169 - label: context.l10n.exercise, 325 + _MetricBlock(
  326 + label: l10n.exercise,
170 labelColor: context.colors.chartGreen, 327 labelColor: context.colors.chartGreen,
171 - valueSpans: exerciseSpans, 328 + value: exerciseWidget,
172 ), 329 ),
173 - _MetricData(  
174 - label: context.l10n.standing, 330 + _MetricBlock(
  331 + label: l10n.standing,
175 labelColor: const Color(0xFF7B9BFB), 332 labelColor: const Color(0xFF7B9BFB),
176 - valueSpans: standSpans, 333 + value: standWidget,
177 ), 334 ),
178 ], 335 ],
179 rightWidget: Container( 336 rightWidget: Container(
@@ -238,7 +395,7 @@ class _TodaySummaryCard extends StatelessWidget { @@ -238,7 +395,7 @@ class _TodaySummaryCard extends StatelessWidget {
238 final Color iconColor; 395 final Color iconColor;
239 final String title; 396 final String title;
240 final String actionText; 397 final String actionText;
241 - final List<_MetricData> metrics; 398 + final List<Widget> metrics;
242 399
243 final Widget rightWidget; 400 final Widget rightWidget;
244 401
@@ -299,8 +456,7 @@ class _TodaySummaryCard extends StatelessWidget { @@ -299,8 +456,7 @@ class _TodaySummaryCard extends StatelessWidget {
299 child: Row( 456 child: Row(
300 crossAxisAlignment: CrossAxisAlignment.start, 457 crossAxisAlignment: CrossAxisAlignment.start,
301 children: [ 458 children: [
302 - for (final metric in metrics)  
303 - Expanded(child: _MetricBlock(metric: metric)), 459 + for (final metric in metrics) Expanded(child: metric),
304 ], 460 ],
305 ), 461 ),
306 ), 462 ),
@@ -314,9 +470,15 @@ class _TodaySummaryCard extends StatelessWidget { @@ -314,9 +470,15 @@ class _TodaySummaryCard extends StatelessWidget {
314 } 470 }
315 471
316 class _MetricBlock extends StatelessWidget { 472 class _MetricBlock extends StatelessWidget {
317 - const _MetricBlock({required this.metric}); 473 + const _MetricBlock({
  474 + required this.label,
  475 + required this.labelColor,
  476 + required this.value,
  477 + });
318 478
319 - final _MetricData metric; 479 + final String label;
  480 + final Color labelColor;
  481 + final Widget value;
320 482
321 @override 483 @override
322 Widget build(BuildContext context) { 484 Widget build(BuildContext context) {
@@ -326,11 +488,11 @@ class _MetricBlock extends StatelessWidget { @@ -326,11 +488,11 @@ class _MetricBlock extends StatelessWidget {
326 crossAxisAlignment: CrossAxisAlignment.start, 488 crossAxisAlignment: CrossAxisAlignment.start,
327 children: [ 489 children: [
328 Text( 490 Text(
329 - metric.label, 491 + label,
330 maxLines: 1, 492 maxLines: 1,
331 overflow: TextOverflow.ellipsis, 493 overflow: TextOverflow.ellipsis,
332 style: TextStyle( 494 style: TextStyle(
333 - color: metric.labelColor, 495 + color: labelColor,
334 fontSize: 12, 496 fontSize: 12,
335 fontWeight: FontWeight.w500, 497 fontWeight: FontWeight.w500,
336 height: 17 / 12, 498 height: 17 / 12,
@@ -340,78 +502,10 @@ class _MetricBlock extends StatelessWidget { @@ -340,78 +502,10 @@ class _MetricBlock extends StatelessWidget {
340 FittedBox( 502 FittedBox(
341 fit: BoxFit.scaleDown, 503 fit: BoxFit.scaleDown,
342 alignment: Alignment.centerLeft, 504 alignment: Alignment.centerLeft,
343 - child: Row(  
344 - crossAxisAlignment: CrossAxisAlignment.end,  
345 - children: [  
346 - for (final span in metric.valueSpans) _MetricValue(value: span),  
347 - ],  
348 - ), 505 + child: value,
349 ), 506 ),
350 ], 507 ],
351 ), 508 ),
352 ); 509 );
353 } 510 }
354 } 511 }
355 -  
356 -class _MetricValue extends StatelessWidget {  
357 - const _MetricValue({required this.value});  
358 -  
359 - final _MetricValueSpan value;  
360 -  
361 - @override  
362 - Widget build(BuildContext context) {  
363 - return Row(  
364 - mainAxisSize: MainAxisSize.min,  
365 - crossAxisAlignment: CrossAxisAlignment.end,  
366 - children: [  
367 - Text(  
368 - value.value,  
369 - style: TextStyle(  
370 - color: value.valueColor ?? context.colors.textPrimary,  
371 - fontSize: 16,  
372 - fontWeight: FontWeight.w600,  
373 - height: 19 / 16,  
374 - ),  
375 - ),  
376 - if (value.unit.isNotEmpty)  
377 - Padding(  
378 - padding: const EdgeInsets.only(left: 1, bottom: 1),  
379 - child: Text(  
380 - value.unit,  
381 - style: TextStyle(  
382 - color: context.colors.textSecondary,  
383 - fontSize: 12,  
384 - fontWeight: FontWeight.w400,  
385 - height: 17 / 12,  
386 - ),  
387 - ),  
388 - ),  
389 - if (value.unit.isNotEmpty) const SizedBox(width: 4),  
390 - ],  
391 - );  
392 - }  
393 -}  
394 -  
395 -class _MetricData {  
396 - const _MetricData({  
397 - required this.label,  
398 - required this.labelColor,  
399 - required this.valueSpans,  
400 - });  
401 -  
402 - final String label;  
403 - final Color labelColor;  
404 - final List<_MetricValueSpan> valueSpans;  
405 -}  
406 -  
407 -class _MetricValueSpan {  
408 - const _MetricValueSpan(  
409 - this.value,  
410 - this.unit, {  
411 - this.valueColor,  
412 - });  
413 -  
414 - final String value;  
415 - final String unit;  
416 - final Color? valueColor;  
417 -}  
@@ -57,6 +57,7 @@ class LoginController extends GetxController { @@ -57,6 +57,7 @@ class LoginController extends GetxController {
57 AppToast.show(AppLocalizations.of(Get.context!)!.loginAgreeToTermsToast); 57 AppToast.show(AppLocalizations.of(Get.context!)!.loginAgreeToTermsToast);
58 return; 58 return;
59 } 59 }
  60 + ta.track('enter_doublefeel_telephone_login_page');
60 Get.toNamed(AppRoutes.phoneLogin); 61 Get.toNamed(AppRoutes.phoneLogin);
61 } 62 }
62 63
@@ -227,6 +228,7 @@ class LoginController extends GetxController { @@ -227,6 +228,7 @@ class LoginController extends GetxController {
227 String accessToken = loginData.accessToken; 228 String accessToken = loginData.accessToken;
228 229
229 if (isRegister) { 230 if (isRegister) {
  231 + ta.track('success_regist');
230 final regRes = await _userApi.register(isApple 232 final regRes = await _userApi.register(isApple
231 ? { 233 ? {
232 'login_type': 'apple', 234 'login_type': 'apple',
@@ -172,8 +172,8 @@ class PhoneLoginView extends GetView<LoginController> { @@ -172,8 +172,8 @@ class PhoneLoginView extends GetView<LoginController> {
172 return TextField( 172 return TextField(
173 controller: controller.codeController, 173 controller: controller.codeController,
174 focusNode: controller.codeFocusNode, 174 focusNode: controller.codeFocusNode,
175 - keyboardType: TextInputType.text,  
176 - maxLength: 8, 175 + keyboardType: TextInputType.phone,
  176 + maxLength: 6,
177 style: TextStyle( 177 style: TextStyle(
178 color: context.colors.textPrimary, 178 color: context.colors.textPrimary,
179 fontSize: 16, 179 fontSize: 16,
@@ -5,6 +5,7 @@ import 'package:doublefeel_flutter/core/logging/app_logger.dart'; @@ -5,6 +5,7 @@ import 'package:doublefeel_flutter/core/logging/app_logger.dart';
5 import 'package:doublefeel_flutter/core/network/api/pay_api.dart'; 5 import 'package:doublefeel_flutter/core/network/api/pay_api.dart';
6 import 'package:doublefeel_flutter/core/network/api/vip_api.dart'; 6 import 'package:doublefeel_flutter/core/network/api/vip_api.dart';
7 import 'package:doublefeel_flutter/core/result/app_result.dart'; 7 import 'package:doublefeel_flutter/core/result/app_result.dart';
  8 +import 'package:doublefeel_flutter/core/services/thinking_data_service.dart';
8 import 'package:doublefeel_flutter/core/util/app_toast.dart'; 9 import 'package:doublefeel_flutter/core/util/app_toast.dart';
9 import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart'; 10 import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart';
10 import 'package:doublefeel_flutter/data/models/local/user_preferences.dart'; 11 import 'package:doublefeel_flutter/data/models/local/user_preferences.dart';
@@ -214,4 +215,10 @@ class MembershipOfferController extends GetxController { @@ -214,4 +215,10 @@ class MembershipOfferController extends GetxController {
214 Get.back(); 215 Get.back();
215 } 216 }
216 } 217 }
  218 +
  219 + @override
  220 + void onReady() {
  221 + super.onReady();
  222 + ta.track('enter_doublefeel_vip_discount_page');
  223 + }
217 } 224 }
@@ -45,7 +45,7 @@ class MembershipOfferView extends GetView<MembershipOfferController> { @@ -45,7 +45,7 @@ class MembershipOfferView extends GetView<MembershipOfferController> {
45 0, 45 0,
46 MediaQuery.paddingOf(context).top + 4, 46 MediaQuery.paddingOf(context).top + 4,
47 0, 47 0,
48 - 140, 48 + 0,
49 ), 49 ),
50 child: Stack( 50 child: Stack(
51 children: [ 51 children: [
1 import 'package:doublefeel_flutter/app/apple_health_upload/apple_health_upload_tool.dart'; 1 import 'package:doublefeel_flutter/app/apple_health_upload/apple_health_upload_tool.dart';
2 import 'package:doublefeel_flutter/core/logging/app_logger.dart'; 2 import 'package:doublefeel_flutter/core/logging/app_logger.dart';
3 import 'package:doublefeel_flutter/core/network/api/user_api.dart'; 3 import 'package:doublefeel_flutter/core/network/api/user_api.dart';
  4 +import 'package:doublefeel_flutter/core/services/thinking_data_service.dart';
4 import 'package:doublefeel_flutter/core/services/user_state_service.dart'; 5 import 'package:doublefeel_flutter/core/services/user_state_service.dart';
5 import 'package:doublefeel_flutter/data/local/user_account_storage.dart'; 6 import 'package:doublefeel_flutter/data/local/user_account_storage.dart';
6 import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart'; 7 import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart';
@@ -119,6 +120,11 @@ class UserOnboardingController extends GetxController { @@ -119,6 +120,11 @@ class UserOnboardingController extends GetxController {
119 report(); 120 report();
120 } on Exception catch (e) {} 121 } on Exception catch (e) {}
121 currentPageIndex.value++; 122 currentPageIndex.value++;
  123 + if (currentPageIndex.value == 7) {
  124 + ta.track('enter_doublefeel_health_grant_page');
  125 + } else if (currentPageIndex.value == 8) {
  126 + ta.track('enter_doublefeel_notification_grant_page');
  127 + }
122 } 128 }
123 129
124 void report() { 130 void report() {
@@ -26,11 +26,13 @@ class AppErrorHandler { @@ -26,11 +26,13 @@ class AppErrorHandler {
26 } 26 }
27 if (businessCode == null || 27 if (businessCode == null ||
28 !policy.excludeErrorCodeList.contains(businessCode)) { 28 !policy.excludeErrorCodeList.contains(businessCode)) {
29 - _showMessage(businessMessage ?? error.displayMessage); 29 + if (businessMessage != null) {
  30 + _showMessage(businessMessage);
  31 + }
30 } 32 }
31 case AppNetworkError(): 33 case AppNetworkError():
32 case AppUnknownError(): 34 case AppUnknownError():
33 - _showMessage(error.displayMessage); 35 + // _showMessage(error.displayMessage);
34 case AppCancelledError(): 36 case AppCancelledError():
35 break; 37 break;
36 } 38 }
@@ -18,6 +18,13 @@ class ThinkingDataService { @@ -18,6 +18,13 @@ class ThinkingDataService {
18 ); 18 );
19 TDAnalytics.init( 19 TDAnalytics.init(
20 _environment.thinkingDataAppId, AppConst.thinkingDataServerUrl); 20 _environment.thinkingDataAppId, AppConst.thinkingDataServerUrl);
  21 + TDAnalytics.calibrateTimeWithNtp('time.apple.com');
  22 + TDAnalytics.enableAutoTrack(TDAutoTrackEventType.APP_START |
  23 + TDAutoTrackEventType.APP_END |
  24 + TDAutoTrackEventType.APP_INSTALL);
  25 + if (_environment.isDebug) {
  26 + TDAnalytics.enableLog(true);
  27 + }
21 } 28 }
22 29
23 void login(String userId) { 30 void login(String userId) {
@@ -32,7 +39,7 @@ class ThinkingDataService { @@ -32,7 +39,7 @@ class ThinkingDataService {
32 39
33 void userSet(Map<String, Object?> properties) { 40 void userSet(Map<String, Object?> properties) {
34 AppLogger.i('ThinkingData userSet $properties'); 41 AppLogger.i('ThinkingData userSet $properties');
35 - TDAnalytics.setSuperProperties(properties); 42 + TDAnalytics.userSet(properties);
36 } 43 }
37 44
38 void timeEvent(String s) { 45 void timeEvent(String s) {
@@ -61,10 +61,16 @@ class UserStateService { @@ -61,10 +61,16 @@ class UserStateService {
61 final partner = _userPrefs.preferences.value.partnerUserInfo; 61 final partner = _userPrefs.preferences.value.partnerUserInfo;
62 final props = <String, Object?>{}; 62 final props = <String, Object?>{};
63 if ((me?.id ?? 0) > 0) { 63 if ((me?.id ?? 0) > 0) {
64 - props['uid'] = me!.id; 64 + props['user_id'] = me!.id;
65 } 65 }
66 - if ((partner?.id ?? 0) > 0) {  
67 - props['lid'] = partner!.id; 66 + if (me?.telephone != null) {
  67 + props['user_phone'] = me!.telephone;
  68 + }
  69 + if (me?.thirdAccountId != null) {
  70 + props['apple_id'] = me!.thirdAccountId;
  71 + }
  72 + if ((me?.createTime ?? 0) > 0) {
  73 + props['account_create_time'] = me!.createTime;
68 } 74 }
69 if (props.isNotEmpty) { 75 if (props.isNotEmpty) {
70 _thinkingDataService.userSet(props); 76 _thinkingDataService.userSet(props);