Skip to content

Commit bfa5040

Browse files
committed
model: Handle live-updates to savedSnippets
1 parent d317158 commit bfa5040

File tree

6 files changed

+126
-1
lines changed

6 files changed

+126
-1
lines changed

lib/model/saved_snippet.dart

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import 'package:collection/collection.dart';
2+
3+
import '../api/model/events.dart';
4+
import '../api/model/model.dart';
5+
import 'store.dart';
6+
7+
mixin SavedSnippetStore {
8+
Map<int, SavedSnippet> get savedSnippets;
9+
}
10+
11+
class SavedSnippetStoreImpl extends PerAccountStoreBase with SavedSnippetStore {
12+
SavedSnippetStoreImpl({
13+
required super.core,
14+
required Iterable<SavedSnippet> savedSnippets,
15+
}) : _savedSnippets = {
16+
for (final savedSnippet in savedSnippets)
17+
savedSnippet.id: savedSnippet,
18+
};
19+
20+
@override
21+
late Map<int, SavedSnippet> savedSnippets = UnmodifiableMapView(_savedSnippets);
22+
final Map<int, SavedSnippet> _savedSnippets;
23+
24+
void handleSavedSnippetsEvent(SavedSnippetsEvent event) {
25+
switch (event) {
26+
case SavedSnippetsAddEvent(:final savedSnippet):
27+
_savedSnippets[savedSnippet.id] = savedSnippet;
28+
29+
case SavedSnippetsUpdateEvent(:final savedSnippet):
30+
assert(_savedSnippets[savedSnippet.id]!.dateCreated
31+
== savedSnippet.dateCreated); // TODO(log)
32+
_savedSnippets[savedSnippet.id] = savedSnippet;
33+
34+
case SavedSnippetsRemoveEvent(:final savedSnippetId):
35+
_savedSnippets.remove(savedSnippetId);
36+
}
37+
}
38+
}

lib/model/store.dart

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import 'message_list.dart';
2929
import 'recent_dm_conversations.dart';
3030
import 'recent_senders.dart';
3131
import 'channel.dart';
32+
import 'saved_snippet.dart';
3233
import 'settings.dart';
3334
import 'typing_status.dart';
3435
import 'unreads.dart';
@@ -431,7 +432,7 @@ Uri? tryResolveUrl(Uri baseUrl, String reference) {
431432
/// This class does not attempt to poll an event queue
432433
/// to keep the data up to date. For that behavior, see
433434
/// [UpdateMachine].
434-
class PerAccountStore extends PerAccountStoreBase with ChangeNotifier, EmojiStore, UserStore, ChannelStore, MessageStore {
435+
class PerAccountStore extends PerAccountStoreBase with ChangeNotifier, EmojiStore, SavedSnippetStore, UserStore, ChannelStore, MessageStore {
435436
/// Construct a store for the user's data, starting from the given snapshot.
436437
///
437438
/// The global store must already have been updated with
@@ -485,6 +486,8 @@ class PerAccountStore extends PerAccountStoreBase with ChangeNotifier, EmojiStor
485486
emailAddressVisibility: initialSnapshot.emailAddressVisibility,
486487
emoji: EmojiStoreImpl(
487488
core: core, allRealmEmoji: initialSnapshot.realmEmoji),
489+
savedSnippets: SavedSnippetStoreImpl(
490+
core: core, savedSnippets: initialSnapshot.savedSnippets ?? []),
488491
userSettings: initialSnapshot.userSettings,
489492
typingNotifier: TypingNotifier(
490493
core: core,
@@ -523,6 +526,7 @@ class PerAccountStore extends PerAccountStoreBase with ChangeNotifier, EmojiStor
523526
required this.customProfileFields,
524527
required this.emailAddressVisibility,
525528
required EmojiStoreImpl emoji,
529+
required SavedSnippetStoreImpl savedSnippets,
526530
required this.userSettings,
527531
required this.typingNotifier,
528532
required UserStoreImpl users,
@@ -534,6 +538,7 @@ class PerAccountStore extends PerAccountStoreBase with ChangeNotifier, EmojiStor
534538
required this.recentSenders,
535539
}) : _realmEmptyTopicDisplayName = realmEmptyTopicDisplayName,
536540
_emoji = emoji,
541+
_savedSnippets = savedSnippets,
537542
_users = users,
538543
_channels = channels,
539544
_messages = messages;
@@ -619,6 +624,10 @@ class PerAccountStore extends PerAccountStoreBase with ChangeNotifier, EmojiStor
619624
////////////////////////////////
620625
// Data attached to the self-account on the realm.
621626

627+
@override
628+
Map<int, SavedSnippet> get savedSnippets => _savedSnippets.savedSnippets;
629+
final SavedSnippetStoreImpl _savedSnippets;
630+
622631
final UserSettings? userSettings; // TODO(server-5)
623632

624633
final TypingNotifier typingNotifier;
@@ -868,6 +877,11 @@ class PerAccountStore extends PerAccountStoreBase with ChangeNotifier, EmojiStor
868877
autocompleteViewManager.handleRealmUserUpdateEvent(event);
869878
notifyListeners();
870879

880+
case SavedSnippetsEvent():
881+
assert(debugLog('server event: saved_snippets/${event.op}'));
882+
_savedSnippets.handleSavedSnippetsEvent(event);
883+
notifyListeners();
884+
871885
case ChannelEvent():
872886
assert(debugLog("server event: stream/${event.op}"));
873887
_channels.handleChannelEvent(event);

test/api/model/model_checks.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ extension UserChecks on Subject<User> {
2121
Subject<bool> get isSystemBot => has((x) => x.isSystemBot, 'isSystemBot');
2222
}
2323

24+
extension SavedSnippetChecks on Subject<SavedSnippet> {
25+
Subject<int> get id => has((x) => x.id, 'id');
26+
Subject<String> get title => has((x) => x.title, 'title');
27+
Subject<String> get content => has((x) => x.content, 'content');
28+
}
29+
2430
extension ZulipStreamChecks on Subject<ZulipStream> {
2531
}
2632

test/example_data.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,28 @@ final User thirdUser = user(fullName: 'Third User');
250250

251251
final User fourthUser = user(fullName: 'Fourth User');
252252

253+
////////////////////////////////////////////////////////////////
254+
// Data attached to the self-account on the realm
255+
//
256+
257+
int _nextSavedSnippetId() => _lastSavedSnippetId++;
258+
int _lastSavedSnippetId = 1;
259+
260+
SavedSnippet savedSnippet({
261+
int? id,
262+
String? title,
263+
String? content,
264+
int? dateCreated,
265+
}) {
266+
_checkPositive(id, 'saved snippet ID');
267+
return SavedSnippet(
268+
id: id ?? _nextSavedSnippetId(),
269+
title: title ?? 'A saved snippet',
270+
content: content ?? 'foo bar baz',
271+
dateCreated: dateCreated ?? 1234567890, // TODO generate timestamp
272+
);
273+
}
274+
253275
////////////////////////////////////////////////////////////////
254276
// Streams and subscriptions.
255277
//

test/model/saved_snippet.dart

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import 'package:checks/checks.dart';
2+
import 'package:flutter_test/flutter_test.dart';
3+
import 'package:zulip/api/model/events.dart';
4+
import 'package:zulip/api/model/model.dart';
5+
6+
import '../api/model/model_checks.dart';
7+
import '../example_data.dart' as eg;
8+
import 'store_checks.dart';
9+
10+
void main() {
11+
test('handleSavedSnippetsEvent', () async {
12+
final store = eg.store(initialSnapshot: eg.initialSnapshot(
13+
savedSnippets: [eg.savedSnippet(id: 101)]));
14+
check(store).savedSnippets.values.single.id.equals(101);
15+
16+
await store.handleEvent(SavedSnippetsAddEvent(id: 1,
17+
savedSnippet: eg.savedSnippet(
18+
id: 102,
19+
title: 'foo title',
20+
content: 'foo content',
21+
)));
22+
check(store).savedSnippets.values.deepEquals(<Condition<Object?>>[
23+
(it) => it.isA<SavedSnippet>().id.equals(101),
24+
(it) => it.isA<SavedSnippet>()..id.equals(102)
25+
..title.equals('foo title')
26+
..content.equals('foo content')
27+
]);
28+
29+
await store.handleEvent(SavedSnippetsRemoveEvent(id: 1, savedSnippetId: 101));
30+
check(store).savedSnippets.values.single.id.equals(102);
31+
32+
await store.handleEvent(SavedSnippetsUpdateEvent(id: 1,
33+
savedSnippet: eg.savedSnippet(
34+
id: 102,
35+
title: 'bar title',
36+
content: 'bar content',
37+
dateCreated: store.savedSnippets.values.single.dateCreated,
38+
)));
39+
check(store).savedSnippets.values.single
40+
..id.equals(102)
41+
..title.equals('bar title')
42+
..content.equals('bar content');
43+
});
44+
}

test/model/store_checks.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ extension PerAccountStoreChecks on Subject<PerAccountStore> {
5555
Subject<int> get accountId => has((x) => x.accountId, 'accountId');
5656
Subject<Account> get account => has((x) => x.account, 'account');
5757
Subject<int> get selfUserId => has((x) => x.selfUserId, 'selfUserId');
58+
Subject<Map<int, SavedSnippet>> get savedSnippets => has((x) => x.savedSnippets, 'savedSnippets');
5859
Subject<UserSettings?> get userSettings => has((x) => x.userSettings, 'userSettings');
5960
Subject<Map<int, ZulipStream>> get streams => has((x) => x.streams, 'streams');
6061
Subject<Map<String, ZulipStream>> get streamsByName => has((x) => x.streamsByName, 'streamsByName');

0 commit comments

Comments
 (0)