getUpdatesWithData method
Implementation
Iterable<DataDiffUpdate<T>> getUpdatesWithData() {
final delegate = _mCallback;
if (delegate is! IndexableItemDiffDelegate<T>) {
throw Exception(
"$delegate is not a IndexableItemDiffDelegate<$T>. call getUpdates() instead or implement IndexableItemDiffDelegate in your DiffDelegate ");
}
final updates = <DataDiffUpdate<T>>[];
// track up to date current list size for moves
// when a move is found, we record its position from the end of the list (which is
// less likely to change since we iterate in reverse).
// Later when we find the match of that move, we dispatch the update
int currentListSize = _mOldListSize;
// list of postponed moves
final postponedUpdates = <_PostponedUpdate>[];
// posX and posY are exclusive
int posX = _mOldListSize;
int posY = _mNewListSize;
// iterate from end of the list to the beginning.
// this just makes offsets easier since changes in the earlier indices has an effect
// on the later indices.
for (int diagonalIndex = _mDiagonals.length - 1;
diagonalIndex >= 0;
diagonalIndex--) {
final _Diagonal diagonal = _mDiagonals[(diagonalIndex)];
final int endX = diagonal.endX();
final int endY = diagonal.endY();
// dispatch removals and additions until we reach to that diagonal
// first remove then add so that it can go into its place and we don't need
// to offset values
while (posX > endX) {
posX--;
// REMOVAL
final int status = _mOldItemStatuses[posX];
final item = delegate.getOldItemAtIndex(posX);
if ((status & FLAG_MOVED) != 0) {
final int newPos = status >> FLAG_OFFSET;
// get postponed addition
final _PostponedUpdate? postponedUpdate =
getPostponedUpdate(postponedUpdates, newPos, false);
if (postponedUpdate != null) {
// this is an addition that was postponed. Now dispatch it.
final int updatedNewPos =
currentListSize - postponedUpdate.currentPos;
updates
.add(DataMove(from: posX, to: updatedNewPos - 1, data: item));
if ((status & FLAG_MOVED_CHANGED) != 0) {
updates.add(DataChange(
position: updatedNewPos - 1,
newData: delegate.getNewItemAtIndex(newPos),
oldData: item,
));
}
} else {
// first time we are seeing this, we'll see a matching addition
postponedUpdates.add(_PostponedUpdate(
posInOwnerList: posX,
currentPos: currentListSize - posX - 1,
removal: true));
}
} else {
// simple removal
updates.add(DataRemove(position: posX, data: item));
currentListSize--;
}
}
while (posY > endY) {
posY--;
// ADDITION
final int status = _mNewItemStatuses[posY];
final item = delegate.getNewItemAtIndex(posY);
if ((status & FLAG_MOVED) != 0) {
// this is a move not an addition.
// see if this is postponed
final int oldPos = status >> FLAG_OFFSET;
// get postponed removal
final _PostponedUpdate? postponedUpdate =
getPostponedUpdate(postponedUpdates, oldPos, true);
// empty size returns 0 for indexOf
if (postponedUpdate == null) {
// postpone it until we see the removal
postponedUpdates.add(_PostponedUpdate(
posInOwnerList: posY,
currentPos: currentListSize - posX,
removal: false));
} else {
// oldPosFromEnd = foundListSize - posX
// we can find posX if we swap the list sizes
// posX = listSize - oldPosFromEnd
final int updatedOldPos =
currentListSize - postponedUpdate.currentPos - 1;
updates.add(DataMove(from: updatedOldPos, to: posX, data: item));
if ((status & FLAG_MOVED_CHANGED) != 0) {
updates.add(DataDiffUpdate.change(
position: posX,
oldData: delegate.getOldItemAtIndex(oldPos),
newData: item));
}
}
} else {
// simple addition
updates.add(DataInsert(position: posX, data: item));
currentListSize++;
}
}
// now dispatch updates for the diagonal
posX = diagonal.x;
posY = diagonal.y;
for (int i = 0; i < diagonal.size; i++) {
// dispatch changes
if ((_mOldItemStatuses[posX] & FLAG_MASK) == FLAG_CHANGED) {
updates.add(DataDiffUpdate.change(
position: posX,
oldData: delegate.getOldItemAtIndex(posX),
newData: delegate.getNewItemAtIndex(posY)));
//updates.add(Change(position: posX, payload: changePayload));
}
posX++;
posY++;
}
// snap back for the next diagonal
posX = diagonal.x;
posY = diagonal.y;
}
return updates;
}