handleNodeToggleRecursive method

Future<SchematicLayoutResult?> handleNodeToggleRecursive(
  1. String nodeId
)

Recursive version of handleNodeToggle (Shift+click).

Expands/collapses the node and all descendant submodules.

Implementation

Future<SchematicLayoutResult?> handleNodeToggleRecursive(
  String nodeId,
) async {
  if (isToggling) {
    return null;
  }
  final engine = _layoutEngine;
  if (engine == null || schematicAdapter == null) {
    return null;
  }

  // Determine label before the toggle mutates state.
  final wasExpanded = schematicAdapter!.isExpanded(nodeId);
  final wasPartiallyExpanded =
      schematicAdapter!.schematic.nodeMap[nodeId]?.isPartiallyExpanded ??
          false;

  setState(() {
    isToggling = true;
    togglingLabel = (wasExpanded && !wasPartiallyExpanded)
        ? 'Collapsing...'
        : 'Expanding...';
    pendingToggleNodeId = nodeId;
  });

  final completer = Completer<void>();
  WidgetsBinding.instance.addPostFrameCallback((_) {
    completer.complete();
  });
  await completer.future;
  SchedulerBinding.instance.ensureVisualUpdate();

  try {
    final toggled = schematicAdapter!.toggleNodeRecursive(nodeId);
    if (!toggled) {
      if (mounted) {
        setState(() {
          isToggling = false;
          pendingToggleNodeId = null;
        });
      }
      return null;
    }

    final elkGraph = schematicAdapter!.schematic.toJsGraph();
    final newLayout = await engine.computeLayoutFromElkGraph(
      elkGraph,
      sessionId: _sessionId,
    );

    if (newLayout.hasError || !mounted) {
      if (mounted) {
        setState(() {
          isToggling = false;
          pendingToggleNodeId = null;
        });
      }
      return null;
    }

    // When collapsing, zoom to the parent boundary; when expanding,
    setState(() {
      layout = newLayout;
      isToggling = false;
      pendingToggleNodeId = null;
      recentlyToggledNodeId = nodeId;
    });

    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (mounted) {
        setState(() {
          recentlyToggledNodeId = null;
        });
      }
    });

    return newLayout;
  } on Exception {
    if (mounted) {
      setState(() {
        isToggling = false;
        pendingToggleNodeId = null;
      });
    }
    return null;
  }
}