scrollToMessage method
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
}
}