scrollToMessage method

void scrollToMessage(
  1. String messageId
)

Scrolls to a specific message by ID with improved position calculation

Implementation

void scrollToMessage(String messageId) {
  if (_scrollController?.hasClients != true) return;

  // Don't interrupt user's manual scrolling
  if (_isManuallyScrolling) {
    debugPrint('SCROLL CANCELED: User is manually scrolling');
    return;
  }

  try {
    // Find the message index
    final index = _messages.indexWhere((msg) => _getMessageId(msg) == messageId);
    if (index == -1) {
      debugPrint('MESSAGE NOT FOUND: Cannot scroll to message $messageId');
      return;
    }

    debugPrint(
        'SCROLLING: To message at index $index with ID $messageId, reverseOrder: ${paginationConfig.reverseOrder}');

    // Get configuration for animation timing
    final config = scrollBehaviorConfig;

    // Use the same improved logic as forceScrollToFirstMessageInChain
    final maxExtent = _scrollController!.position.maxScrollExtent;
    final itemCount = _messages.length;

    debugPrint('SCROLL INFO: maxExtent=$maxExtent, itemCount=$itemCount, messageIndex=$index');

    double targetPosition;

    if (paginationConfig.reverseOrder) {
      // In reverse order mode (newest messages at bottom)
      if (index == 0) {
        targetPosition = 0.0; // Show the newest message (at bottom)
      } else {
        // Calculate position to show this message near the top of the viewport
        targetPosition = maxExtent * (index / itemCount) * 0.8;
      }
    } else {
      // In chronological mode (oldest messages at top)
      if (index < itemCount * 0.2) {
        // If message is in first 20% of list, scroll to top
        targetPosition = 0.0;
      } else {
        // Calculate position to show this message near the top of viewport
        targetPosition = (maxExtent * (index / itemCount)) - (maxExtent * 0.2);
      }
    }

    // Clamp to valid range
    targetPosition = targetPosition.clamp(0.0, maxExtent);

    debugPrint('SCROLLING: To position $targetPosition');

    _scrollController!.animateTo(
      targetPosition,
      duration: config.scrollAnimationDuration,
      curve: config.scrollAnimationCurve,
    );
  } catch (e) {
    debugPrint('ERROR SCROLLING: $e');
    // Do not scroll to bottom as fallback - this causes the double-scroll issue
  }
}