Skip to content

Commit 479d323

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

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
@@ -665,6 +665,9 @@ class PerAccountStore extends PerAccountStoreBase with ChangeNotifier, EmojiStor
665665
bool isUserMuted(int userId, {MutedUsersEvent? event}) =>
666666
_users.isUserMuted(userId, event: event);
667667

668+
@override
669+
UserStatus getUserStatus(int userId) => _users.getUserStatus(userId);
670+
668671
final UserStoreImpl _users;
669672

670673
final TypingStatus typingStatus;
@@ -930,8 +933,9 @@ class PerAccountStore extends PerAccountStoreBase with ChangeNotifier, EmojiStor
930933
notifyListeners();
931934

932935
case UserStatusEvent():
933-
// TODO: handle
934-
break;
936+
assert(debugLog("server event: user_status"));
937+
_users.handleUserStatusEvent(event);
938+
notifyListeners();
935939

936940
case UserTopicEvent():
937941
assert(debugLog("server event: user_topic"));

lib/model/user.dart

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ mixin UserStore on PerAccountStoreBase {
8585
/// Looks for [userId] in a private [Set],
8686
/// or in [event.mutedUsers] instead if event is non-null.
8787
bool isUserMuted(int userId, {MutedUsersEvent? event});
88+
89+
/// The status of the user with the given ID.
90+
///
91+
/// If no status is set for a user, returns [UserStatus.zero].
92+
UserStatus getUserStatus(int userId);
8893
}
8994

9095
/// The implementation of [UserStore] that does the work.
@@ -101,7 +106,9 @@ class UserStoreImpl extends PerAccountStoreBase with UserStore {
101106
.followedBy(initialSnapshot.realmNonActiveUsers)
102107
.followedBy(initialSnapshot.crossRealmBots)
103108
.map((user) => MapEntry(user.userId, user))),
104-
_mutedUsers = Set.from(initialSnapshot.mutedUsers.map((item) => item.id));
109+
_mutedUsers = Set.from(initialSnapshot.mutedUsers.map((item) => item.id)),
110+
_userStatuses = initialSnapshot.userStatuses.map((userId, change) =>
111+
MapEntry(userId, change.apply(UserStatus.zero)));
105112

106113
final Map<int, User> _users;
107114

@@ -118,6 +125,11 @@ class UserStoreImpl extends PerAccountStoreBase with UserStore {
118125
return (event?.mutedUsers.map((item) => item.id) ?? _mutedUsers).contains(userId);
119126
}
120127

128+
final Map<int, UserStatus> _userStatuses;
129+
130+
@override
131+
UserStatus getUserStatus(int userId) => _userStatuses[userId] ?? UserStatus.zero;
132+
121133
void handleRealmUserEvent(RealmUserEvent event) {
122134
switch (event) {
123135
case RealmUserAddEvent():
@@ -157,6 +169,11 @@ class UserStoreImpl extends PerAccountStoreBase with UserStore {
157169
}
158170
}
159171

172+
void handleUserStatusEvent(UserStatusEvent event) {
173+
_userStatuses[event.userId] =
174+
event.change.apply(getUserStatus(event.userId));
175+
}
176+
160177
void handleMutedUsersEvent(MutedUsersEvent event) {
161178
_mutedUsers.clear();
162179
_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
@@ -7,6 +7,12 @@ import '../api/model/model_checks.dart';
77
import '../example_data.dart' as eg;
88
import 'test_store.dart';
99

10+
typedef StatusData = (String? statusText, String? emojiName, String? emojiCode,
11+
String? reactionType);
12+
13+
typedef StatusEventData = (int userId, String? statusText, String? emojiName,
14+
String? emojiCode, String? reactionType);
15+
1016
void main() {
1117
group('userDisplayName', () {
1218
test('on a known user', () async {
@@ -80,6 +86,82 @@ void main() {
8086
});
8187
});
8288

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)
99+
.text.equals(expected.$1);
100+
101+
switch (expected) {
102+
case (_, String emojiName, String emojiCode, String reactionType):
103+
check(userStatus.emoji!)
104+
..emojiName.equals(emojiName)
105+
..emojiCode.equals(emojiCode)
106+
..reactionType.equals(ReactionType.fromApiValue(reactionType));
107+
default:
108+
check(userStatus.emoji).isNull();
109+
}
110+
}
111+
112+
UserStatusEvent userStatusEvent(StatusEventData data) => UserStatusEvent(
113+
id: 1,
114+
userId: data.$1,
115+
change: UserStatusChange.fromJson({
116+
'status_text': data.$2,
117+
'emoji_name': data.$3,
118+
'emoji_code': data.$4,
119+
'reaction_type': data.$5,
120+
}),
121+
);
122+
123+
final store = eg.store(initialSnapshot: eg.initialSnapshot(
124+
userStatuses: {
125+
1: userStatus(('Busy', 'working_on_it', '1f6e0', 'unicode_emoji')),
126+
2: userStatus((null, 'calendar', '1f4c5', 'unicode_emoji')),
127+
3: userStatus(('Commuting', null, null, null)),
128+
}
129+
));
130+
checkUserStatus(store.getUserStatus(1),
131+
('Busy', 'working_on_it', '1f6e0', 'unicode_emoji'));
132+
checkUserStatus(store.getUserStatus(2),
133+
(null, 'calendar', '1f4c5', 'unicode_emoji'));
134+
checkUserStatus(store.getUserStatus(3),
135+
('Commuting', null, null, null));
136+
check(store.getUserStatus(4))..text.isNull()..emoji.isNull();
137+
check(store.getUserStatus(5))..text.isNull()..emoji.isNull();
138+
139+
await store.handleEvent(userStatusEvent((1,
140+
'Out sick', 'sick', '1f912', 'unicode_emoji')));
141+
checkUserStatus(store.getUserStatus(1),
142+
('Out sick', 'sick', '1f912', 'unicode_emoji'));
143+
144+
await store.handleEvent(userStatusEvent((2,
145+
'In a meeting', null, null, null)));
146+
checkUserStatus(store.getUserStatus(2),
147+
('In a meeting', 'calendar', '1f4c5', 'unicode_emoji'));
148+
149+
await store.handleEvent(userStatusEvent((3,
150+
'', 'bus', '1f68c', 'unicode_emoji')));
151+
checkUserStatus(store.getUserStatus(3),
152+
(null, 'bus', '1f68c', 'unicode_emoji'));
153+
154+
await store.handleEvent(userStatusEvent((4,
155+
'Vacationing', null, null, null)));
156+
checkUserStatus(store.getUserStatus(4),
157+
('Vacationing', null, null, null));
158+
159+
await store.handleEvent(userStatusEvent((5,
160+
'Working remotely', '', '', '')));
161+
checkUserStatus(store.getUserStatus(5),
162+
('Working remotely', null, null, null));
163+
});
164+
83165
testWidgets('MutedUsersEvent', (tester) async {
84166
final user1 = eg.user(userId: 1);
85167
final user2 = eg.user(userId: 2);

0 commit comments

Comments
 (0)