app_home_controller.dart
5.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import 'dart:async';
import 'package:doublefeel_flutter/app/modules/friends/controllers/friends_controller.dart';
import 'package:doublefeel_flutter/app/modules/friends/models/friend_health_data.dart';
import 'package:doublefeel_flutter/core/network/api/friend_api.dart';
import 'package:doublefeel_flutter/core/network/api/health_api.dart';
import 'package:doublefeel_flutter/core/network/api/pay_api.dart';
import 'package:doublefeel_flutter/core/network/api/vip_api.dart';
import 'package:doublefeel_flutter/core/services/raw_data_service/health_raw_data_core_service.dart';
import 'package:doublefeel_flutter/core/services/user_state_service.dart';
import 'package:doublefeel_flutter/data/datasource/health/health_datasource_wrapper.dart';
import 'package:doublefeel_flutter/data/datasource/health/health_local_datasource.dart';
import 'package:doublefeel_flutter/data/datasource/health/health_remote_datasource.dart';
import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart';
import 'package:doublefeel_flutter/data/models/friend/friend_models.dart'
show FriendItem;
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'today_controller.dart';
/// Owns the Today controllers embedded in the first app tab.
///
/// The self and watched-friend controllers deliberately have different tags so
/// their date, scroll position, and loaded health data remain isolated.
class AppHomeController extends GetxController {
AppHomeController({
FriendsController? friendsController,
UserPreferencesStorage? userPreferencesStorage,
}) : _friendsController = friendsController ?? Get.find<FriendsController>(),
_userPreferencesStorage =
userPreferencesStorage ?? Get.find<UserPreferencesStorage>();
static const selfTodayTag = 'app_home_self';
static const _friendTodayTagPrefix = 'app_home_friend_';
final FriendsController _friendsController;
final UserPreferencesStorage _userPreferencesStorage;
final selectedTargetId = selfTodayTag.obs;
final watchedFriend = Rxn<FriendHealthData>();
late final Worker _friendsWorker;
String? _friendTodayTag;
TodayController get selfTodayController =>
Get.find<TodayController>(tag: selfTodayTag);
TodayController get selectedTodayController {
final tag = selectedTargetId.value;
if (tag == selfTodayTag || !Get.isRegistered<TodayController>(tag: tag)) {
return selfTodayController;
}
return Get.find<TodayController>(tag: tag);
}
bool get hasWatchedFriend => watchedFriend.value != null;
bool get hasAnyFriend => _friendsController.friends.isNotEmpty;
bool get isShowingSelf => selectedTargetId.value == selfTodayTag;
String get selfName {
final info = _userPreferencesStorage.preferences.value.meUserInfo;
return info?.nickname?.trim().isNotEmpty == true
? info!.nickname!.trim()
: '我';
}
String? get selfAvatar =>
_userPreferencesStorage.preferences.value.meUserInfo?.avatar;
@override
void onInit() {
super.onInit();
_registerSelfController();
_friendsWorker = ever<List<FriendHealthData>>(
_friendsController.friends,
_syncWatchedFriend,
);
unawaited(_friendsController.loadFriends());
_syncWatchedFriend(_friendsController.friends);
}
void selectSelf() => selectedTargetId.value = selfTodayTag;
void selectFriend() {
final tag = _friendTodayTag;
if (tag != null && Get.isRegistered<TodayController>(tag: tag)) {
selectedTargetId.value = tag;
}
}
Future<void> refreshSelectedToday() => selectedTodayController.refreshTab();
void scrollSelectedToLatestHrv() {
final controller = selectedTodayController;
if (!controller.scrollController.hasClients) return;
controller.scrollController.animateTo(
850,
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
);
}
void _syncWatchedFriend(List<FriendHealthData> friends) {
final next = friends
.where(
(friend) =>
friend.isOnWatchFace && friend.friendItem.friendUserId != null,
)
.firstOrNull;
final previousId = watchedFriend.value?.friendItem.friendUserId;
final nextId = next?.friendItem.friendUserId;
if (previousId == nextId) {
watchedFriend.value = next;
return;
}
final oldTag = _friendTodayTag;
if (oldTag != null && Get.isRegistered<TodayController>(tag: oldTag)) {
Get.delete<TodayController>(tag: oldTag, force: true);
}
_friendTodayTag = null;
watchedFriend.value = next;
selectSelf();
if (next == null || nextId == null) return;
final tag = '$_friendTodayTagPrefix$nextId';
Get.put<TodayController>(_createTodayController(next.friendItem), tag: tag);
_friendTodayTag = tag;
}
void _registerSelfController() {
if (Get.isRegistered<TodayController>(tag: selfTodayTag)) return;
Get.put<TodayController>(_createTodayController(null), tag: selfTodayTag);
}
TodayController _createTodayController(FriendItem? friendInfo) =>
TodayController(
Get.find<PayApi>(),
Get.find<VipApi>(),
HealthDataSourceWrapper(
remoteDataSource: RemoteHealthDataSource(Get.find<HealthApi>()),
localDataSource: LocalHealthDataSource(
coreService: Get.find<HealthRawDataCoreService>(),
),
),
Get.find<FriendApi>(),
Get.find<UserStateService>(),
friendInfo: friendInfo,
);
@override
void onClose() {
_friendsWorker.dispose();
Get.delete<TodayController>(tag: selfTodayTag, force: true);
final tag = _friendTodayTag;
if (tag != null) Get.delete<TodayController>(tag: tag, force: true);
super.onClose();
}
}