| Index: packages/observable/lib/src/observable_list.dart
|
| diff --git a/packages/observe/lib/src/observable_list.dart b/packages/observable/lib/src/observable_list.dart
|
| similarity index 76%
|
| rename from packages/observe/lib/src/observable_list.dart
|
| rename to packages/observable/lib/src/observable_list.dart
|
| index 9d09b38d560b43844f98b40f7d2ea2ff44a28cdd..16c49f579782d2e4db3ae806eb325d8eb902109e 100644
|
| --- a/packages/observe/lib/src/observable_list.dart
|
| +++ b/packages/observable/lib/src/observable_list.dart
|
| @@ -1,21 +1,22 @@
|
| -// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
| +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
| // for details. All rights reserved. Use of this source code is governed by a
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| -library observe.src.observable_list;
|
| +library observable.src.observable_list;
|
|
|
| import 'dart:async';
|
| import 'dart:collection' show ListBase, UnmodifiableListView;
|
| -import 'package:observe/observe.dart';
|
| -import 'list_diff.dart' show projectListSplices, calcSplices;
|
| +
|
| +import 'list_diff.dart' show ListChangeRecord, projectListSplices, calcSplices;
|
| +import 'observable.dart' show Observable;
|
|
|
| /// Represents an observable list of model values. If any items are added,
|
| /// removed, or replaced, then observers that are listening to [changes]
|
| /// will be notified.
|
| -class ObservableList<E> extends ListBase<E> with ChangeNotifier {
|
| +class ObservableList<E> extends ListBase<E> with Observable {
|
| List<ListChangeRecord> _listRecords;
|
|
|
| - StreamController _listChanges;
|
| + StreamController<List<ListChangeRecord>> _listChanges;
|
|
|
| /// The inner [List<E>] with the actual storage.
|
| final List<E> _list;
|
| @@ -30,6 +31,14 @@ class ObservableList<E> extends ListBase<E> with ChangeNotifier {
|
| ObservableList([int length])
|
| : _list = length != null ? new List<E>(length) : <E>[];
|
|
|
| + /// Creates an observable list of the given [length].
|
| + ///
|
| + /// This constructor exists to work around an issue in the VM whereby
|
| + /// classes that derive from [ObservableList] and mixin other classes
|
| + /// require a default generative constructor in the super class that
|
| + /// does not take optional arguments.
|
| + ObservableList.withLength(int length) : this(length);
|
| +
|
| /// Creates an observable list with the elements of [other]. The order in
|
| /// the list will be the order provided by the iterator of [other].
|
| factory ObservableList.from(Iterable<E> other) =>
|
| @@ -58,18 +67,21 @@ class ObservableList<E> extends ListBase<E> with ChangeNotifier {
|
| Stream<List<ListChangeRecord>> get listChanges {
|
| if (_listChanges == null) {
|
| // TODO(jmesserly): split observed/unobserved notions?
|
| - _listChanges = new StreamController.broadcast(sync: true,
|
| - onCancel: () { _listChanges = null; });
|
| + _listChanges = new StreamController.broadcast(
|
| + sync: true,
|
| + onCancel: () {
|
| + _listChanges = null;
|
| + },
|
| + );
|
| }
|
| return _listChanges.stream;
|
| }
|
|
|
| - bool get hasListObservers =>
|
| - _listChanges != null && _listChanges.hasListener;
|
| + bool get hasListObservers => _listChanges != null && _listChanges.hasListener;
|
|
|
| - @reflectable int get length => _list.length;
|
| + int get length => _list.length;
|
|
|
| - @reflectable set length(int value) {
|
| + set length(int value) {
|
| int len = _list.length;
|
| if (len == value) return;
|
|
|
| @@ -77,30 +89,28 @@ class ObservableList<E> extends ListBase<E> with ChangeNotifier {
|
| _notifyChangeLength(len, value);
|
| if (hasListObservers) {
|
| if (value < len) {
|
| - _recordChange(new ListChangeRecord(this, value,
|
| - removed: _list.getRange(value, len).toList()));
|
| + _notifyListChange(value, removed: _list.getRange(value, len).toList());
|
| } else {
|
| - _recordChange(new ListChangeRecord(this, len, addedCount: value - len));
|
| + _notifyListChange(len, addedCount: value - len);
|
| }
|
| }
|
|
|
| _list.length = value;
|
| }
|
|
|
| - @reflectable E operator [](int index) => _list[index];
|
| + E operator [](int index) => _list[index];
|
|
|
| - @reflectable void operator []=(int index, E value) {
|
| - var oldValue = _list[index];
|
| + void operator []=(int index, E value) {
|
| + E oldValue = _list[index];
|
| if (hasListObservers && oldValue != value) {
|
| - _recordChange(new ListChangeRecord(this, index, addedCount: 1,
|
| - removed: [oldValue]));
|
| + _notifyListChange(index, addedCount: 1, removed: [oldValue]);
|
| }
|
| _list[index] = value;
|
| }
|
|
|
| // Forwarders so we can reflect on the properties.
|
| - @reflectable bool get isEmpty => super.isEmpty;
|
| - @reflectable bool get isNotEmpty => super.isNotEmpty;
|
| + bool get isEmpty => super.isEmpty;
|
| + bool get isNotEmpty => super.isNotEmpty;
|
|
|
| // TODO(jmesserly): should we support first/last/single? They're kind of
|
| // dangerous to use in a path because they throw exceptions. Also we'd need
|
| @@ -113,10 +123,10 @@ class ObservableList<E> extends ListBase<E> with ChangeNotifier {
|
| if (iterable is! List && iterable is! Set) {
|
| iterable = iterable.toList();
|
| }
|
| - var len = iterable.length;
|
| - if (hasListObservers && len > 0) {
|
| - _recordChange(new ListChangeRecord(this, index, addedCount: len,
|
| - removed: _list.getRange(index, len).toList()));
|
| + int length = iterable.length;
|
| + if (hasListObservers && length > 0) {
|
| + _notifyListChange(index,
|
| + addedCount: length, removed: _list.sublist(index, length));
|
| }
|
| _list.setAll(index, iterable);
|
| }
|
| @@ -125,7 +135,7 @@ class ObservableList<E> extends ListBase<E> with ChangeNotifier {
|
| int len = _list.length;
|
| _notifyChangeLength(len, len + 1);
|
| if (hasListObservers) {
|
| - _recordChange(new ListChangeRecord(this, len, addedCount: 1));
|
| + _notifyListChange(len, addedCount: 1);
|
| }
|
|
|
| _list.add(value);
|
| @@ -139,7 +149,7 @@ class ObservableList<E> extends ListBase<E> with ChangeNotifier {
|
|
|
| int added = _list.length - len;
|
| if (hasListObservers && added > 0) {
|
| - _recordChange(new ListChangeRecord(this, len, addedCount: added));
|
| + _notifyListChange(len, addedCount: added);
|
| }
|
| }
|
|
|
| @@ -160,8 +170,7 @@ class ObservableList<E> extends ListBase<E> with ChangeNotifier {
|
|
|
| _notifyChangeLength(len, len - rangeLength);
|
| if (hasListObservers && rangeLength > 0) {
|
| - _recordChange(new ListChangeRecord(this, start,
|
| - removed: _list.getRange(start, end).toList()));
|
| + _notifyListChange(start, removed: _list.getRange(start, end).toList());
|
| }
|
|
|
| _list.removeRange(start, end);
|
| @@ -188,8 +197,7 @@ class ObservableList<E> extends ListBase<E> with ChangeNotifier {
|
| _notifyChangeLength(len, _list.length);
|
|
|
| if (hasListObservers && insertionLength > 0) {
|
| - _recordChange(new ListChangeRecord(this, index,
|
| - addedCount: insertionLength));
|
| + _notifyListChange(index, addedCount: insertionLength);
|
| }
|
| }
|
|
|
| @@ -210,12 +218,11 @@ class ObservableList<E> extends ListBase<E> with ChangeNotifier {
|
|
|
| _notifyChangeLength(_list.length - 1, _list.length);
|
| if (hasListObservers) {
|
| - _recordChange(new ListChangeRecord(this, index, addedCount: 1));
|
| + _notifyListChange(index, addedCount: 1);
|
| }
|
| _list[index] = element;
|
| }
|
|
|
| -
|
| E removeAt(int index) {
|
| E result = this[index];
|
| removeRange(index, index + 1);
|
| @@ -231,14 +238,14 @@ class ObservableList<E> extends ListBase<E> with ChangeNotifier {
|
| }
|
| }
|
|
|
| - void _recordChange(ListChangeRecord record) {
|
| + void _notifyListChange(int index, {List removed, int addedCount}) {
|
| if (!hasListObservers) return;
|
| -
|
| if (_listRecords == null) {
|
| _listRecords = [];
|
| scheduleMicrotask(deliverListChanges);
|
| }
|
| - _listRecords.add(record);
|
| + _listRecords.add(new ListChangeRecord(this, index,
|
| + removed: removed, addedCount: addedCount));
|
| }
|
|
|
| void _notifyChangeLength(int oldValue, int newValue) {
|
| @@ -247,10 +254,6 @@ class ObservableList<E> extends ListBase<E> with ChangeNotifier {
|
| notifyPropertyChange(#isNotEmpty, oldValue != 0, newValue != 0);
|
| }
|
|
|
| - /// Deprecated. Name had a typo, use [discardListChanges] instead.
|
| - @deprecated
|
| - void discardListChages() => discardListChanges();
|
| -
|
| void discardListChanges() {
|
| // Leave _listRecords set so we don't schedule another delivery.
|
| if (_listRecords != null) _listRecords = [];
|
| @@ -258,10 +261,10 @@ class ObservableList<E> extends ListBase<E> with ChangeNotifier {
|
|
|
| bool deliverListChanges() {
|
| if (_listRecords == null) return false;
|
| - var records = projectListSplices(this, _listRecords);
|
| + List<ListChangeRecord> records = projectListSplices(this, _listRecords);
|
| _listRecords = null;
|
|
|
| - if (hasListObservers && !records.isEmpty) {
|
| + if (hasListObservers && records.isNotEmpty) {
|
| _listChanges.add(new UnmodifiableListView<ListChangeRecord>(records));
|
| return true;
|
| }
|
| @@ -281,23 +284,22 @@ class ObservableList<E> extends ListBase<E> with ChangeNotifier {
|
| /// Complexity is `O(l * p)` where `l` is the length of the current list and
|
| /// `p` is the length of the old list.
|
| static List<ListChangeRecord> calculateChangeRecords(
|
| - List<Object> oldValue, List<Object> newValue) =>
|
| + List<Object> oldValue, List<Object> newValue) =>
|
| calcSplices(newValue, 0, newValue.length, oldValue, 0, oldValue.length);
|
|
|
| - /// Updates the [previous] list using the change [records]. For added items,
|
| + /// Updates the [previous] list using the [changeRecords]. For added items,
|
| /// the [current] list is used to find the current value.
|
| static void applyChangeRecords(List<Object> previous, List<Object> current,
|
| List<ListChangeRecord> changeRecords) {
|
| -
|
| if (identical(previous, current)) {
|
| throw new ArgumentError("can't use same list for previous and current");
|
| }
|
|
|
| - for (var change in changeRecords) {
|
| + for (ListChangeRecord change in changeRecords) {
|
| int addEnd = change.index + change.addedCount;
|
| int removeEnd = change.index + change.removed.length;
|
|
|
| - var addedItems = current.getRange(change.index, addEnd);
|
| + Iterable addedItems = current.getRange(change.index, addEnd);
|
| previous.replaceRange(change.index, removeEnd, addedItems);
|
| }
|
| }
|
|
|