|
...
|
...
|
@@ -7,6 +7,7 @@ import 'package:doublefeel_flutter/app/modules/home/controllers/trend/trend_cont |
|
|
|
import 'package:doublefeel_flutter/app/modules/home/widgets/today/friend_select_bottom_sheet.dart';
|
|
|
|
import 'package:doublefeel_flutter/app/modules/home/widgets/today/no_health_data_page.dart';
|
|
|
|
import 'package:doublefeel_flutter/app/routes/app_pages.dart';
|
|
|
|
import 'package:doublefeel_flutter/core/constants/intent_keys.dart';
|
|
|
|
import 'package:doublefeel_flutter/core/constants/membership.dart';
|
|
|
|
import 'package:doublefeel_flutter/core/logging/app_logger.dart';
|
|
|
|
import 'package:doublefeel_flutter/core/network/api/friend_api.dart';
|
|
...
|
...
|
@@ -190,35 +191,42 @@ class TodayController extends GetMaterialController { |
|
|
|
}
|
|
|
|
|
|
|
|
void checkAddFriendVisible() {
|
|
|
|
_refreshFriendList(onFriendListUpdated: () {
|
|
|
|
if (friendsList.isNotEmpty ||
|
|
|
|
friendsList.value.length >= friendsListLimit) {
|
|
|
|
showPartnerAdBanner.value = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// 关闭后 3 天内不再显示
|
|
|
|
final userId =
|
|
|
|
Get.find<UserPreferencesStorage>().preferences.value.meUserInfo?.id ??
|
|
|
|
0;
|
|
|
|
final lastShowTime =
|
|
|
|
Get.find<UserAccountStorage>().getLastAddFriendBannerShowTime(userId);
|
|
|
|
if (lastShowTime != null) {
|
|
|
|
final diff = DateTime.now()
|
|
|
|
.difference(DateTime.fromMillisecondsSinceEpoch(lastShowTime));
|
|
|
|
if (diff.inDays < 3) {
|
|
|
|
if (isFriend) {
|
|
|
|
showPartnerAdBanner.value = false;
|
|
|
|
} else {
|
|
|
|
_refreshFriendList(onFriendListUpdated: () {
|
|
|
|
if (friendsList.isNotEmpty ||
|
|
|
|
friendsList.value.length >= friendsListLimit) {
|
|
|
|
showPartnerAdBanner.value = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
showPartnerAdBanner.value = true;
|
|
|
|
});
|
|
|
|
// 关闭后 3 天内不再显示
|
|
|
|
final userId = Get.find<UserPreferencesStorage>()
|
|
|
|
.preferences
|
|
|
|
.value
|
|
|
|
.meUserInfo
|
|
|
|
?.id ??
|
|
|
|
0;
|
|
|
|
final lastShowTime = Get.find<UserAccountStorage>()
|
|
|
|
.getLastAddFriendBannerShowTime(userId);
|
|
|
|
if (lastShowTime != null) {
|
|
|
|
final diff = DateTime.now()
|
|
|
|
.difference(DateTime.fromMillisecondsSinceEpoch(lastShowTime));
|
|
|
|
if (diff.inDays < 3) {
|
|
|
|
showPartnerAdBanner.value = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
showPartnerAdBanner.value = true;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void changeDate(DateTime date, {DateTime? focused}) {
|
|
|
|
final normalizedDate = _clampDate(date);
|
|
|
|
if (!DateUtils.isSameDay(date, lastSelectableDay) &&
|
|
|
|
!_userStateService.isVip) {
|
|
|
|
toPremiumPage();
|
|
|
|
toPremiumPage('今日-查看非当日数据');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
selectedDate.value = normalizedDate;
|
|
...
|
...
|
@@ -334,20 +342,40 @@ class TodayController extends GetMaterialController { |
|
|
|
|
|
|
|
Future<void> checkHealthDataAuthCardVisible(
|
|
|
|
[HealthAuthorization? preResult]) async {
|
|
|
|
try {
|
|
|
|
final result = preResult ?? await _hostApi.checkHealthAppAuthorization();
|
|
|
|
ta.setSuperProperties(
|
|
|
|
{'health_data_permission': result.status.clamp(0, 1)});
|
|
|
|
if (result.status == 1) {
|
|
|
|
await _performDataUpload();
|
|
|
|
}
|
|
|
|
final hasUploaded =
|
|
|
|
switch (await _healthApi.getHealthDataEverUploaded()) {
|
|
|
|
AppSuccess(:final data) => data,
|
|
|
|
AppFailure() => false,
|
|
|
|
};
|
|
|
|
showHealthDataAuthCardStatus.value = !hasUploaded ? -1 : result.status;
|
|
|
|
} catch (e) {}
|
|
|
|
final firstTime = DateUtils.dateOnly(
|
|
|
|
DateTime(lastSelectableDay.year, lastSelectableDay.month - 6,
|
|
|
|
lastSelectableDay.day),
|
|
|
|
);
|
|
|
|
if (isFriend) {
|
|
|
|
showHealthDataAuthCardStatus.value = 1;
|
|
|
|
firstSelectableDay.value = firstTime;
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
final result =
|
|
|
|
preResult ?? await _hostApi.checkHealthAppAuthorization();
|
|
|
|
ta.setSuperProperties(
|
|
|
|
{'health_data_permission': result.status.clamp(0, 1)});
|
|
|
|
if (result.status == 1) {
|
|
|
|
await _performDataUpload();
|
|
|
|
}
|
|
|
|
bool hasUploaded = false;
|
|
|
|
switch (await _healthApi.getHealthDataEverUploaded()) {
|
|
|
|
case AppSuccess(:final data):
|
|
|
|
hasUploaded = data.flag ?? false;
|
|
|
|
if (hasUploaded && data.startTime != null && data.startTime! > 0) {
|
|
|
|
final firstDayTime = DateUtils.dateOnly(
|
|
|
|
DateTime.fromMillisecondsSinceEpoch(data.startTime! * 1000),
|
|
|
|
);
|
|
|
|
if (firstDayTime.isBefore(firstTime)) {
|
|
|
|
firstSelectableDay.value = firstDayTime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case AppFailure():
|
|
|
|
hasUploaded = false;
|
|
|
|
}
|
|
|
|
showHealthDataAuthCardStatus.value = !hasUploaded ? -1 : result.status;
|
|
|
|
} catch (e) {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> checkNotificationCardVisible() async {
|
|
...
|
...
|
@@ -388,12 +416,6 @@ class TodayController extends GetMaterialController { |
|
|
|
switch (await _healthApi.getV2StressScore(friendUserId, intDate)) {
|
|
|
|
case AppSuccess(:final data):
|
|
|
|
v2StressScore.value = data;
|
|
|
|
|
|
|
|
// var nextInt = Random().nextInt(4);
|
|
|
|
// v2StressScore.value = V2StressScore(
|
|
|
|
// state: nextInt,
|
|
|
|
// comprehensiveScore: 100 - (nextInt * 25),
|
|
|
|
// );
|
|
|
|
case AppFailure():
|
|
|
|
v2StressScore.value = null;
|
|
|
|
}
|
|
...
|
...
|
@@ -408,25 +430,6 @@ class TodayController extends GetMaterialController { |
|
|
|
switch (await _healthApi.getV2HrvTrend(friendUserId, intDate)) {
|
|
|
|
case AppSuccess(:final data):
|
|
|
|
hrvChartData.assignAll(data.list ?? []);
|
|
|
|
// hrvChartData.assignAll([
|
|
|
|
// // 每小时一条,00:00 ~ 15:00(CST 午夜 = 1782057600)
|
|
|
|
// V2HrvTrendItem(time: 1782057600, trendHrv: 45, state: 3), // 00:00
|
|
|
|
// V2HrvTrendItem(time: 1782061200, trendHrv: 42, state: 3), // 01:00
|
|
|
|
// V2HrvTrendItem(time: 1782064800, trendHrv: 38, state: 3), // 02:00
|
|
|
|
// V2HrvTrendItem(time: 1782068400, trendHrv: 35, state: 2), // 03:00
|
|
|
|
// V2HrvTrendItem(time: 1782072000, trendHrv: 40, state: 3), // 04:00
|
|
|
|
// V2HrvTrendItem(time: 1782075600, trendHrv: 55, state: 4), // 05:00
|
|
|
|
// V2HrvTrendItem(time: 1782079200, trendHrv: 65, state: 4), // 06:00
|
|
|
|
// V2HrvTrendItem(time: 1782082800, trendHrv: 72, state: 4), // 07:00
|
|
|
|
// V2HrvTrendItem(time: 1782086400, trendHrv: 68, state: 4), // 08:00
|
|
|
|
// V2HrvTrendItem(time: 1782090000, trendHrv: 58, state: 4), // 09:00
|
|
|
|
// V2HrvTrendItem(time: 1782093600, trendHrv: 52, state: 3), // 10:00
|
|
|
|
// V2HrvTrendItem(time: 1782097200, trendHrv: 48, state: 3), // 11:00
|
|
|
|
// V2HrvTrendItem(time: 1782100800, trendHrv: 44, state: 3), // 12:00
|
|
|
|
// V2HrvTrendItem(time: 1782104400, trendHrv: 38, state: 2), // 13:00
|
|
|
|
// V2HrvTrendItem(time: 1782108000, trendHrv: 42, state: 3), // 14:00
|
|
|
|
// V2HrvTrendItem(time: 1782111600, trendHrv: 45, state: 3), // 15:00
|
|
|
|
// ]);
|
|
|
|
case AppFailure():
|
|
|
|
hrvChartData.clear();
|
|
|
|
}
|
|
...
|
...
|
@@ -434,40 +437,6 @@ class TodayController extends GetMaterialController { |
|
|
|
switch (await _healthApi.getV2RealtimeStress(friendUserId, intDate)) {
|
|
|
|
case AppSuccess(:final data):
|
|
|
|
stressChartData.assignAll(data.list ?? []);
|
|
|
|
// stressChartData.assignAll(
|
|
|
|
// // 每 6 分钟一条,00:00 ~ 15:00(共 150 条)
|
|
|
|
// // midnight CST = 1782057600,步长 360s
|
|
|
|
// List.generate(150, (i) {
|
|
|
|
// const midnight = 1782057600;
|
|
|
|
// final ts = midnight + i * 360;
|
|
|
|
// final minutesFromMidnight = i * 6;
|
|
|
|
// final hour = minutesFromMidnight ~/ 60;
|
|
|
|
// final minInHour = minutesFromMidnight % 60;
|
|
|
|
// // 用正弦波模拟真实波动,早高峰(7-9点)压力最高
|
|
|
|
// final base = hour < 6
|
|
|
|
// ? 25.0 // 深夜低压力
|
|
|
|
// : hour < 9
|
|
|
|
// ? 55.0 + (hour - 6) * 10.0 // 早高峰爬升
|
|
|
|
// : hour < 12
|
|
|
|
// ? 75.0 - (hour - 9) * 8.0 // 上午下降
|
|
|
|
// : 50.0 - (hour - 12) * 3.0; // 下午缓降
|
|
|
|
// // 叠加微小波动(用 i 模拟随机)
|
|
|
|
// final jitter = (i % 7 - 3) * 2.0 + (minInHour % 3) * 1.5;
|
|
|
|
// final value = (base + jitter).clamp(10.0, 100.0).round();
|
|
|
|
// final int state;
|
|
|
|
// if (value >= 75) {
|
|
|
|
// state = 1;
|
|
|
|
// } else if (value >= 55) {
|
|
|
|
// state = 2;
|
|
|
|
// } else if (value >= 35) {
|
|
|
|
// state = 3;
|
|
|
|
// } else {
|
|
|
|
// state = 4;
|
|
|
|
// }
|
|
|
|
// return V2RealtimeStressItem(time: ts, value: value, state: state);
|
|
|
|
// }),
|
|
|
|
// );
|
|
|
|
|
|
|
|
case AppFailure():
|
|
|
|
stressChartData.clear();
|
|
|
|
}
|
|
...
|
...
|
@@ -479,12 +448,6 @@ class TodayController extends GetMaterialController { |
|
|
|
v2ActivityTarget.value = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Future.delayed(const Duration(milliseconds: 5000), () {
|
|
|
|
// firstSelectableDay.value = DateUtils.dateOnly(
|
|
|
|
// DateTime(
|
|
|
|
// DateTime.now().year, DateTime.now().month, DateTime.now().day - 1),
|
|
|
|
// );
|
|
|
|
// });
|
|
|
|
}
|
|
|
|
|
|
|
|
void _clearRealTimeData() {
|
|
...
|
...
|
@@ -588,8 +551,11 @@ class TodayController extends GetMaterialController { |
|
|
|
RxList<FriendItem> friendsList = RxList.empty();
|
|
|
|
int friendsListLimit = 10;
|
|
|
|
|
|
|
|
Future<void> toPremiumPage() async {
|
|
|
|
await Get.toNamed(Routes.PURCHASE);
|
|
|
|
Future<void> toPremiumPage(String channelType) async {
|
|
|
|
await Get.toNamed(
|
|
|
|
Routes.PURCHASE,
|
|
|
|
arguments: {IntentKeys.channelType: channelType},
|
|
|
|
);
|
|
|
|
final vipResult = await _vipApi.getVipInfo();
|
|
|
|
if (vipResult case AppSuccess(data: final vip)) {
|
|
|
|
try {
|
|
...
|
...
|
@@ -688,4 +654,11 @@ class TodayController extends GetMaterialController { |
|
|
|
unawaited(loadDataForDate(selectedDate.value));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> refreshTab() async {
|
|
|
|
checkAddFriendVisible();
|
|
|
|
checkHrvAdBannerVisible();
|
|
|
|
checkHealthDataAuthCardVisible();
|
|
|
|
await loadDataForDate(selectedDate.value);
|
|
|
|
}
|
|
|
|
} |
...
|
...
|
|