Skip to content

Commit ce1c664

Browse files
sm-sayedichrisbobbe
andcommitted
store: Add UserStore.getUserStatus, with event updates
Co-authored-by: Chris Bobbe <[email protected]>
1 parent 3d814d2 commit ce1c664

File tree

3 files changed

+106
-3
lines changed

3 files changed

+106
-3
lines changed

lib/model/store.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,9 @@ class PerAccountStore extends PerAccountStoreBase with
688688
MutedUsersVisibilityEffect mightChangeShouldMuteDmConversation(MutedUsersEvent event) =>
689689
_users.mightChangeShouldMuteDmConversation(event);
690690

691+
@override
692+
UserStatus getUserStatus(int userId) => _users.getUserStatus(userId);
693+
691694
final UserStoreImpl _users;
692695

693696
final TypingStatus typingStatus;
@@ -960,8 +963,9 @@ class PerAccountStore extends PerAccountStoreBase with
960963
notifyListeners();
961964

962965
case UserStatusEvent():
963-
// TODO: handle
964-
break;
966+
assert(debugLog("server event: user_status"));
967+
_users.handleUserStatusEvent(event);
968+
notifyListeners();
965969

966970
case UserTopicEvent():
967971
assert(debugLog("server event: user_topic"));

lib/model/user.dart

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ mixin UserStore on PerAccountStoreBase {
102102
/// Whether the given event might change the result of [shouldMuteDmConversation]
103103
/// for its list of muted users, compared to the current state.
104104
MutedUsersVisibilityEffect mightChangeShouldMuteDmConversation(MutedUsersEvent event);
105+
106+
/// The status of the user with the given ID.
107+
///
108+
/// If no status is set for the user, returns [UserStatus.zero].
109+
UserStatus getUserStatus(int userId);
105110
}
106111

107112
/// Whether and how a given [MutedUsersEvent] may affect the results
@@ -135,7 +140,9 @@ class UserStoreImpl extends PerAccountStoreBase with UserStore {
135140
.followedBy(initialSnapshot.realmNonActiveUsers)
136141
.followedBy(initialSnapshot.crossRealmBots)
137142
.map((user) => MapEntry(user.userId, user))),
138-
_mutedUsers = Set.from(initialSnapshot.mutedUsers.map((item) => item.id));
143+
_mutedUsers = Set.from(initialSnapshot.mutedUsers.map((item) => item.id)),
144+
_userStatuses = initialSnapshot.userStatuses.map((userId, change) =>
145+
MapEntry(userId, change.apply(UserStatus.zero)));
139146

140147
final Map<int, User> _users;
141148

@@ -175,6 +182,11 @@ class UserStoreImpl extends PerAccountStoreBase with UserStore {
175182
}
176183
}
177184

185+
final Map<int, UserStatus> _userStatuses;
186+
187+
@override
188+
UserStatus getUserStatus(int userId) => _userStatuses[userId] ?? UserStatus.zero;
189+
178190
void handleRealmUserEvent(RealmUserEvent event) {
179191
switch (event) {
180192
case RealmUserAddEvent():
@@ -214,6 +226,11 @@ class UserStoreImpl extends PerAccountStoreBase with UserStore {
214226
}
215227
}
216228

229+
void handleUserStatusEvent(UserStatusEvent event) {
230+
_userStatuses[event.userId] =
231+
event.change.apply(getUserStatus(event.userId));
232+
}
233+
217234
void handleMutedUsersEvent(MutedUsersEvent event) {
218235
_mutedUsers.clear();
219236
_mutedUsers.addAll(event.mutedUsers.map((item) => item.id));

test/model/user_test.dart

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import '../api/model/model_checks.dart';
1010
import '../example_data.dart' as eg;
1111
import 'test_store.dart';
1212

13+
typedef StatusData = (String? statusText, String? emojiName, String? emojiCode,
14+
String? reactionType);
15+
1316
void main() {
1417
group('userDisplayName', () {
1518
test('on a known user', () async {
@@ -83,6 +86,85 @@ void main() {
8386
});
8487
});
8588

89+
testWidgets('UserStatusEvent', (tester) async {
90+
UserStatusChange userStatus(StatusData data) => UserStatusChange.fromJson({
91+
'status_text': data.$1,
92+
'emoji_name': data.$2,
93+
'emoji_code': data.$3,
94+
'reaction_type': data.$4,
95+
});
96+
97+
void checkUserStatus(UserStatus userStatus, StatusData expected) {
98+
check(userStatus).text.equals(expected.$1);
99+
100+
switch (expected) {
101+
case (_, String emojiName, String emojiCode, String reactionType):
102+
check(userStatus.emoji!)
103+
..emojiName.equals(emojiName)
104+
..emojiCode.equals(emojiCode)
105+
..reactionType.equals(ReactionType.fromApiValue(reactionType));
106+
default:
107+
check(userStatus.emoji).isNull();
108+
}
109+
}
110+
111+
UserStatusEvent userStatusEvent(StatusData data, {required int userId}) =>
112+
UserStatusEvent(
113+
id: 1,
114+
userId: userId,
115+
change: UserStatusChange.fromJson({
116+
'status_text': data.$1,
117+
'emoji_name': data.$2,
118+
'emoji_code': data.$3,
119+
'reaction_type': data.$4,
120+
}));
121+
122+
final store = eg.store(initialSnapshot: eg.initialSnapshot(
123+
userStatuses: {
124+
1: userStatus(('Busy', 'working_on_it', '1f6e0', 'unicode_emoji')),
125+
2: userStatus((null, 'calendar', '1f4c5', 'unicode_emoji')),
126+
3: userStatus(('Commuting', null, null, null)),
127+
}));
128+
checkUserStatus(store.getUserStatus(1),
129+
('Busy', 'working_on_it', '1f6e0', 'unicode_emoji'));
130+
checkUserStatus(store.getUserStatus(2),
131+
(null, 'calendar', '1f4c5', 'unicode_emoji'));
132+
checkUserStatus(store.getUserStatus(3),
133+
('Commuting', null, null, null));
134+
check(store.getUserStatus(4))..text.isNull()..emoji.isNull();
135+
check(store.getUserStatus(5))..text.isNull()..emoji.isNull();
136+
137+
await store.handleEvent(userStatusEvent(userId: 1,
138+
('Out sick', 'sick', '1f912', 'unicode_emoji')));
139+
checkUserStatus(store.getUserStatus(1),
140+
('Out sick', 'sick', '1f912', 'unicode_emoji'));
141+
142+
await store.handleEvent(userStatusEvent(userId: 2,
143+
('In a meeting', null, null, null)));
144+
checkUserStatus(store.getUserStatus(2),
145+
('In a meeting', 'calendar', '1f4c5', 'unicode_emoji'));
146+
147+
await store.handleEvent(userStatusEvent(userId: 3,
148+
('', 'bus', '1f68c', 'unicode_emoji')));
149+
checkUserStatus(store.getUserStatus(3),
150+
(null, 'bus', '1f68c', 'unicode_emoji'));
151+
152+
await store.handleEvent(userStatusEvent(userId: 4,
153+
('Vacationing', null, null, null)));
154+
checkUserStatus(store.getUserStatus(4),
155+
('Vacationing', null, null, null));
156+
157+
await store.handleEvent(userStatusEvent(userId: 5,
158+
('Working remotely', '', '', '')));
159+
checkUserStatus(store.getUserStatus(5),
160+
('Working remotely', null, null, null));
161+
162+
await store.handleEvent(userStatusEvent(userId: 1,
163+
('', '', '', '')));
164+
checkUserStatus(store.getUserStatus(1),
165+
(null, null, null, null));
166+
});
167+
86168
group('MutedUsersEvent', () {
87169
testWidgets('smoke', (tester) async {
88170
late PerAccountStore store;

0 commit comments

Comments
 (0)