diff static method
Produce a diff from old to newSnap.
Implementation
static UiDiff diff(UiSnapshot? old, UiSnapshot newSnap) {
if (old == null || old.screen != newSnap.screen) {
return UiDiff(
screen: newSnap.screen,
oldCapturedAt: null,
newCapturedAt: newSnap.capturedAt,
added: [
for (final n in newSnap.nodes)
UiNodeAdded(node: n, path: newSnap.paths[n.stableId] ?? ''),
],
removed: const [],
updated: const [],
moved: const [],
visibilityChanged: const [],
);
}
final oldById = {for (final n in old.nodes) n.stableId: n};
final newById = {for (final n in newSnap.nodes) n.stableId: n};
final added = <UiNodeAdded>[];
final removed = <String>[];
final updated = <UiNodeUpdate>[];
final moved = <UiNodeMove>[];
final visibilityChanged = <UiVisibilityChange>[];
for (final entry in newById.entries) {
final id = entry.key;
final n = entry.value;
final o = oldById[id];
if (o == null) {
added.add(UiNodeAdded(node: n, path: newSnap.paths[id] ?? ''));
continue;
}
final roleChanged = o.role != n.role;
final textChanged = o.text != n.text;
final boundsChanged = !_rectEqual(o.bounds, n.bounds);
final scrollableChanged = o.scrollable != n.scrollable;
final hasActionChanged = o.hasAction != n.hasAction;
final actionsChanged = !_listEqual(o.actions, n.actions);
final valueChanged = o.value != n.value;
final checkedChanged = o.checked != n.checked;
final selectedChanged = o.selected != n.selected;
final disabledChanged = o.disabled != n.disabled;
final placeholderChanged = o.placeholder != n.placeholder;
final rangeChanged = o.range != n.range;
final normChanged =
textChanged || o.wireNormalizedText != n.wireNormalizedText;
final subtreeChanged = (o.wireSubtreeText ?? o.wireNormalizedText) !=
(n.wireSubtreeText ?? n.wireNormalizedText);
final layerChanged = o.layer != n.layer;
final editableChanged = o.editable != n.editable;
final secureChanged = o.secure != n.secure;
final parentChanged = o.parentId != n.parentId;
final visibilityFlipped = o.visible != n.visible;
final fractionMoved =
(o.wireVisibleFraction - n.wireVisibleFraction).abs() >
kVisibleFractionDelta + 1e-9;
final nonVisibilityChange = roleChanged ||
textChanged ||
boundsChanged ||
scrollableChanged ||
hasActionChanged ||
actionsChanged ||
valueChanged ||
checkedChanged ||
selectedChanged ||
disabledChanged ||
placeholderChanged ||
rangeChanged ||
normChanged ||
subtreeChanged ||
layerChanged ||
editableChanged ||
secureChanged ||
parentChanged;
final fractionChanged = visibilityFlipped || fractionMoved;
if (fractionChanged && !nonVisibilityChange) {
visibilityChanged.add(UiVisibilityChange(
stableId: id,
visible: n.visible,
visibleFraction: n.wireVisibleFraction,
));
} else if (nonVisibilityChange) {
updated.add(UiNodeUpdate(
stableId: id,
role: roleChanged ? n.role : null,
text: textChanged ? n.text : null,
bounds: boundsChanged ? _rectToList(n.bounds) : null,
scrollable: scrollableChanged ? n.scrollable : null,
hasAction: hasActionChanged ? n.hasAction : null,
visible: visibilityFlipped ? n.visible : null,
actions: actionsChanged ? n.actions : null,
value: valueChanged ? n.value : null,
checked: checkedChanged ? n.checked : null,
selected: selectedChanged ? n.selected : null,
disabledChanged: disabledChanged,
disabled: n.disabled,
placeholder: placeholderChanged ? n.placeholder : null,
rangeChanged: rangeChanged,
range: n.range,
normalizedText: normChanged ? n.wireNormalizedText : null,
subtreeText: subtreeChanged
? (n.wireSubtreeText ?? n.wireNormalizedText)
: null,
layer: layerChanged ? n.layer : null,
editable: editableChanged ? n.editable : null,
secure: secureChanged ? n.secure : null,
visibleFraction: fractionChanged ? n.wireVisibleFraction : null,
parentId: parentChanged ? n.parentId : null,
));
}
final oldPath = old.paths[id] ?? '';
final newPath = newSnap.paths[id] ?? '';
if (oldPath != newPath) {
moved.add(UiNodeMove(
stableId: id,
oldPath: oldPath,
newPath: newPath,
));
}
}
for (final id in oldById.keys) {
if (!newById.containsKey(id)) removed.add(id);
}
return UiDiff(
screen: newSnap.screen,
oldCapturedAt: old.capturedAt,
newCapturedAt: newSnap.capturedAt,
added: added,
removed: removed,
updated: updated,
moved: moved,
visibilityChanged: visibilityChanged,
);
}