mergeScreenCache function

ScreenCacheFile mergeScreenCache(
  1. ScreenCacheFile? existing,
  2. UiSnapshot snap,
  3. String now(), {
  4. int maxNodes = kMaxNodesPerScreen,
})

Merge one capture into a screen's cumulative file.

Implementation

ScreenCacheFile mergeScreenCache(
  ScreenCacheFile? existing,
  UiSnapshot snap,
  String Function() now, {
  int maxNodes = kMaxNodesPerScreen,
}) {
  final base = migrateScreenCacheFile(existing);
  final ts = now();

  final incoming = <WireNode>[
    for (final n in snap.nodes)
      if (n.overlayId == 0) n.toWire(),
  ];
  final hasOpenOverlay =
      snap.overlays.isNotEmpty || snap.nodes.any((n) => n.overlayId != 0);
  final merged = mergeNodeUnion(
    base?.nodes,
    incoming,
    ts,
    staleBefore: stalePruneCutoff(
      now: ts,
      existingCount: base?.nodes.length ?? 0,
      incomingCount: incoming.length,
      hasOpenOverlay: hasOpenOverlay,
    ),
    maxNodes: maxNodes,
  );

  final viewport = <double>[
    snap.viewportSize.width,
    snap.viewportSize.height,
  ];
  final overlays = _mergeOverlays(base?.overlays, snap, ts);

  final viewportChanged = base != null &&
      base.lastViewport.length == 2 &&
      (base.lastViewport[0] != viewport[0] ||
          base.lastViewport[1] != viewport[1]);

  final changed =
      base == null || merged.changed || viewportChanged || overlays.changed;
  if (base != null && !changed) return base;

  final nodes = merged.nodes;
  final keptIds = <String>{
    for (final n in nodes)
      if (n['id'] is String) n['id'] as String,
  };
  final allPaths = <String, String>{...?base?.paths, ...snap.paths};

  return ScreenCacheFile(
    schemaVersion: kCacheSchemaVersion,
    type: 'screen_cache',
    screen: snap.screen.trim(),
    firstSeen: base?.firstSeen.isNotEmpty == true ? base!.firstSeen : ts,
    lastSeen: ts,
    captureCount: (base?.captureCount ?? 0) + 1,
    lastViewport: viewport,
    nodes: nodes,
    paths: <String, String>{
      for (final e in allPaths.entries)
        if (keptIds.contains(e.key)) e.key: e.value,
    },
    overlays: overlays.records.isEmpty ? null : overlays.records,
    sync: (base?.sync ?? SyncMeta.clean).markDirty(ts),
  );
}