capture static method

UiSnapshot? capture({
  1. required String screen,
  2. required Rect viewport,
})

Run the full pipeline: raw capture → normalize → stable IDs → snapshot.

Implementation

static UiSnapshot? capture({
  required String screen,
  required Rect viewport,
}) {
  final raw = TreeCapture.capture(viewport);
  if (raw == null) return null;

  final norm = TreeNormalizer.normalize(raw, screen: screen);
  final ids = StableIdAssigner.assign(norm, screen: screen);

  final nodes = <UiNode>[];
  final paths = <String, String>{};
  final visibleIndex = <int>[];
  final viewportArea = viewport.width * viewport.height;

  for (var i = 0; i < norm.nodes.length; i++) {
    final n = norm.nodes[i];
    final stableId = ids.stableIds[i];
    final inter = n.bounds.intersect(viewport);
    final coverage = viewportArea <= 0 || inter.isEmpty
        ? 0.0
        : (inter.width * inter.height) / viewportArea;
    nodes.add(UiNode(
      stableId: stableId,
      role: n.role,
      text: n.text,
      normalizedText: n.normalizedText,
      normalizedTokens: n.normalizedTokens,
      bounds: n.bounds,
      scrollable: n.scrollable,
      visible: n.visible,
      visibleFraction: n.visibleFraction,
      layer: n.layer,
      overlayId: n.overlayId,
      hasAction: n.hasAction,
      identifier: n.identifier,
      actions: n.actions,
      subtreeText: n.subtreeText,
      rawId: n.rawId,
      selected: n.selected,
      value: n.value,
      checked: n.checked,
      editable: n.editable,
      secure: n.secure,
      coversViewport: coverage >= kSubtreeTextOmitCoverage,
      disabled: n.disabled,
      placeholder: n.placeholder,
      range: n.range,
      parentId: n.parentIndex >= 0 ? ids.stableIds[n.parentIndex] : '',
      visual: n.visual,
    ));
    paths[stableId] = ids.paths[i];
    if (n.visible) visibleIndex.add(i);
  }

  return UiSnapshot(
    screen: screen,
    nodes: nodes,
    paths: paths,
    visibleIndex: visibleIndex,
    capturedAt: DateTime.now().toUtc(),
    viewportSize: Size(viewport.width, viewport.height),
    overlays: [
      for (final overlay in raw.overlays)
        if (nodes.any((node) => node.overlayId == overlay.id))
          UiOverlay(
            id: overlay.id,
            key: _overlayKey(overlay, nodes),
            kind: overlay.kind,
            layer: overlay.id,
            bounds: raw.nodes[overlay.rootIndex].bounds,
          ),
    ],
  );
}