update method

void update(
  1. double dt,
  2. String? hitNodeId, {
  3. bool dwellEnabled = true,
})

Call each frame with the currently gazed node ID (or null).

Set dwellEnabled to false while another input source suppresses auto selection. Hover and explicit taps remain available, but dwell progress is discarded. Re-enabling starts a fresh dwell even on the same target.

Implementation

void update(double dt, String? hitNodeId, {bool dwellEnabled = true}) {
  if (!dwellEnabled) {
    _gazeTimer = 0;
    _selected = false;
    _graceSavedGazeTimer = 0;
    dwellProgress = 0;
    final target = _gazeTargetId;
    if (target != null) onDwellProgress?.call(target, 0);
  }
  // Grace period: brief loss of the target preserves the dwell timer.
  if (hitNodeId == null && _gazeTargetId != null && !_selected) {
    if (_graceTargetId != _gazeTargetId) {
      _graceTargetId = _gazeTargetId;
      _graceTimer = 0;
      _graceSavedGazeTimer = _gazeTimer;
    }
    _graceTimer += dt;
    if (_graceTimer < gazeGracePeriod) {
      // Hold progress steady during the grace window.
      return;
    }
  }

  if (hitNodeId != _gazeTargetId) {
    // Gaze changed target
    if (_gazeTargetId != null) onGazeExit?.call(_gazeTargetId!);

    // Restoring the same target within the grace window resumes the timer.
    final resumed =
        hitNodeId != null &&
        hitNodeId == _graceTargetId &&
        _graceTimer < gazeGracePeriod;

    _gazeTargetId = hitNodeId;
    _gazeTimer = resumed ? _graceSavedGazeTimer : 0;
    _selected = false;
    dwellProgress = resumed
        ? (_gazeTimer / _effectiveDwell).clamp(0.0, 1.0)
        : 0;
    _graceTargetId = null;
    _graceTimer = 0;
    if (hitNodeId != null) {
      if (enableHaptics) {
        HapticFeedback.selectionClick();
      }
      onGazeEnter?.call(hitNodeId);
    }
    return;
  }

  if (hitNodeId == null) {
    dwellProgress = 0;
    return;
  }

  _graceTargetId = null;
  _graceTimer = 0;

  if (!dwellEnabled) return;

  _gazeTimer += dt;
  dwellProgress = (_gazeTimer / _effectiveDwell).clamp(0.0, 1.0);
  onDwellProgress?.call(hitNodeId, dwellProgress);

  if (dwellProgress >= 1.0 && !_selected) {
    _selected = true;
    _applyAdaptation(hitNodeId);
    if (enableHaptics) {
      HapticFeedback.lightImpact();
    }
    onDwellSelect?.call(hitNodeId);
  }
}