diff --git a/lib/src/collection_changes.dart b/lib/src/collection_changes.dart index 99773e9f1..a4aebde16 100644 --- a/lib/src/collection_changes.dart +++ b/lib/src/collection_changes.dart @@ -71,4 +71,9 @@ class RealmCollectionChanges { class RealmResultsChanges extends RealmCollectionChanges { final RealmResults results; RealmResultsChanges(this.results, RealmCollectionChanges changes) : super(changes._handle, changes.realm); -} \ No newline at end of file +} + +class RealmListChanges extends RealmCollectionChanges { + final RealmList list; + RealmListChanges(this.list, RealmCollectionChanges changes) : super(changes._handle, changes.realm); +} diff --git a/lib/src/list.dart b/lib/src/list.dart index 175c1f5ca..055ea3a17 100644 --- a/lib/src/list.dart +++ b/lib/src/list.dart @@ -66,6 +66,13 @@ class RealmList extends collection.ListBase { void clear() { realmCore.listClear(this); } + + Stream> get changed => realmCore + .listChanged( + this, + realm.scheduler.handle, + ) + .map((changes) => RealmListChanges(this, changes)); } /// @nodoc diff --git a/lib/src/native/realm_core.dart b/lib/src/native/realm_core.dart index af419d2ab..856964f58 100644 --- a/lib/src/native/realm_core.dart +++ b/lib/src/native/realm_core.dart @@ -391,7 +391,6 @@ class _RealmCore { }); } - Counts getCollectionChangesCounts(RealmCollectionChangesHandle changes) { return using((arena) { final out_num_deletions = arena(); @@ -480,6 +479,31 @@ class _RealmCore { return controller.stream; } + Stream listChanged(RealmList list, SchedulerHandle scheduler) { + late StreamController controller; + + void callback(Pointer data) { + final changes = RealmCollectionChanges( + RealmCollectionChangesHandle._(_realmLib.realm_clone(data).cast()), + list.realm, + ); + controller.add(changes); + } + + controller = _constructRealmNotificationStreamController( + (userData, callback, free, error) => _realmLib.realm_list_add_notification_callback( + list.handle._pointer, + userData, + free, + callback.cast(), + error, + scheduler._pointer, + ), + callback); + + return controller.stream; + } + RealmLinkHandle _getObjectAsLink(RealmObject object) { final realm_link = _realmLib.realm_object_as_link(object.handle._pointer); return RealmLinkHandle._(realm_link); diff --git a/test/realm_test.dart b/test/realm_test.dart index 06a1c6e22..7743b15b8 100644 --- a/test/realm_test.dart +++ b/test/realm_test.dart @@ -836,6 +836,46 @@ Future main([List? args]) async { } await forceGC?.call(); }); + + test('RealmList.changed', () async { + var config = Configuration([Team.schema, Person.schema]); + var realm = Realm(config); + + final team = Team('Ferari'); + realm.write(() => realm.add(team)); + + void write(void Function() writer) async { + realm.write(writer); + realm.write(() {}); // dummy write to raise notification from previous write + } + + final stream = (team.players as RealmList).changed.asBroadcastStream(); + + var callbacks = 0; + final subscription = stream.listen((_) => ++callbacks); + + { + final event = stream.skip(1).first; + write(() => team.players.add(Person('Niki'))); + final change = await event; + expect(callbacks, 2); // first time + expect(change.counts, Counts(0, 1, 0, 0)); + expect(change.changes.insertions, [0]); + } + { + final event = stream.first; + write(() { + team.players[0].name = 'Michael'; + team.players.add(Person('Kimi')); + }); + final change = await event; + expect(callbacks, 3); // once per transaction, not once per change + expect(change.counts, Counts(0, 1, 1, 0)); + expect(change.changes.insertions, [1]); + expect(change.changes.modifications, [0]); + } + subscription.cancel(); + }); }); test('RealmObject add with list properties', () {