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); |
} |
} |