filter method
Filters all candidates, retuning only a subset that matches
Implementation
@override
Iterable<WidgetTreeNode> filter(Iterable<WidgetTreeNode> candidates) {
final tree = currentWidgetTreeSnapshot();
final List<WidgetSnapshot<Widget>> parentSnapshots = [];
for (final selector in parents) {
final WidgetSnapshot<Widget> widgetSnapshot =
snapshot(selector, validateQuantity: false);
// handle negates
if (selector.quantityConstraint.max == 0) {
throw UnimplementedError(
'Parents can not be negated, yet. Please upvote https://github.com/passsy/spot/issues/49',
);
} else {
widgetSnapshot.validateQuantity();
parentSnapshots.add(widgetSnapshot);
}
}
final List<Map<WidgetTreeNode, List<WidgetSnapshot>>> discoveryByParent =
[];
for (final parentSnapshot in parentSnapshots) {
final Map<WidgetTreeNode, List<WidgetSnapshot>> groups = {};
if (parentSnapshot.discovered.isEmpty) {
discoveryByParent.add(groups);
continue;
}
// remove elements when the parent is already in the list. This prevents searching all element of a subtree, resulting in always the same items
final rootNodes = parentSnapshot.discovered
.whereNot(
(element) => parentSnapshot.discovered.contains(element.parent),
)
.toList();
final visibilityMode = parentSnapshot.selector.widgetPresence;
for (final WidgetTreeNode node in rootNodes) {
groups[node] ??= [];
final WidgetSelector root = switch (visibilityMode) {
WidgetPresence.onstage => spot(),
WidgetPresence.offstage => spotOffstage(),
WidgetPresence.combined => spotAllWidgets(),
};
final subtree = tree.scope(node);
final snapshot = WidgetSnapshot(
selector: root.withParent(spotElement(node.element)),
discovered: [
node,
...subtree.allNodes,
],
scope: subtree,
debugCandidates: candidates.map((it) => it.element).toList(),
);
groups[node]!.add(snapshot);
}
discoveryByParent.add(groups);
}
final List<WidgetSnapshot> discoveredSnapshots =
discoveryByParent.map((it) => it.values).flatten().flatten().toList();
final List<WidgetTreeNode> allDiscoveredNodes =
discoveredSnapshots.map((it) => it.discovered).flatten().toList();
final List<Element> distinctElements =
allDiscoveredNodes.map((e) => e.element).toSet().toList();
// find nodes that exist in all parents
final List<Element> elementsInAllParents =
distinctElements.where((element) {
return discoveryByParent.all((
Map<WidgetTreeNode, List<WidgetSnapshot>> discovered,
) {
return discovered.values.any((List<WidgetSnapshot> list) {
return list.any((node) {
return node.discovered.map((e) => e.element).contains(element);
});
});
});
}).toList();
final remaining = elementsInAllParents.mapNotNull((e) {
return candidates.firstOrNullWhere((node) {
return node.element == e;
});
}).toList();
return remaining;
}