From 8e61ab24bf1552fd8f42826655468dcb6f27bf7f Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Fri, 22 Aug 2025 22:01:11 +0200 Subject: [PATCH] Scroll fix (#281) * auto scroll * scroll fix --- .../java/com/bitchat/android/ui/ChatScreen.kt | 5 +++- .../bitchat/android/ui/MessageComponents.kt | 28 +++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/bitchat/android/ui/ChatScreen.kt b/app/src/main/java/com/bitchat/android/ui/ChatScreen.kt index 36bf9f67..9d7f044c 100644 --- a/app/src/main/java/com/bitchat/android/ui/ChatScreen.kt +++ b/app/src/main/java/com/bitchat/android/ui/ChatScreen.kt @@ -50,6 +50,7 @@ fun ChatScreen(viewModel: ChatViewModel) { var showPasswordDialog by remember { mutableStateOf(false) } var passwordInput by remember { mutableStateOf("") } var showLocationChannelsSheet by remember { mutableStateOf(false) } + var forceScrollToBottom by remember { mutableStateOf(false) } // Show password dialog when needed LaunchedEffect(showPasswordPrompt) { @@ -85,7 +86,8 @@ fun ChatScreen(viewModel: ChatViewModel) { messages = displayMessages, currentUserNickname = nickname, meshService = viewModel.meshService, - modifier = Modifier.weight(1f) + modifier = Modifier.weight(1f), + forceScrollToBottom = forceScrollToBottom ) // Input area - stays at bottom ChatInputSection( @@ -99,6 +101,7 @@ fun ChatScreen(viewModel: ChatViewModel) { if (messageText.text.trim().isNotEmpty()) { viewModel.sendMessage(messageText.text.trim()) messageText = TextFieldValue("") + forceScrollToBottom = !forceScrollToBottom // Toggle to trigger scroll } }, showCommandSuggestions = showCommandSuggestions, diff --git a/app/src/main/java/com/bitchat/android/ui/MessageComponents.kt b/app/src/main/java/com/bitchat/android/ui/MessageComponents.kt index 0cb9e977..d6ae9298 100644 --- a/app/src/main/java/com/bitchat/android/ui/MessageComponents.kt +++ b/app/src/main/java/com/bitchat/android/ui/MessageComponents.kt @@ -31,13 +31,37 @@ fun MessagesList( messages: List, currentUserNickname: String, meshService: BluetoothMeshService, - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + forceScrollToBottom: Boolean = false ) { val listState = rememberLazyListState() - // Auto-scroll to bottom when new messages arrive + // Track if this is the first time messages are being loaded + var hasScrolledToInitialPosition by remember { mutableStateOf(false) } + + // Smart scroll: auto-scroll to bottom for initial load, then only when user is at or near the bottom LaunchedEffect(messages.size) { if (messages.isNotEmpty()) { + val layoutInfo = listState.layoutInfo + val lastVisibleIndex = layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: -1 + val totalItems = layoutInfo.totalItemsCount + + // Always scroll to bottom on first load, or when user is near the bottom + val isFirstLoad = !hasScrolledToInitialPosition + val isNearBottom = lastVisibleIndex >= totalItems - 3 + + if (isFirstLoad || isNearBottom) { + listState.animateScrollToItem(messages.size - 1) + if (isFirstLoad) { + hasScrolledToInitialPosition = true + } + } + } + } + + // Force scroll to bottom when requested (e.g., when user sends a message) + LaunchedEffect(forceScrollToBottom) { + if (forceScrollToBottom && messages.isNotEmpty()) { listState.animateScrollToItem(messages.size - 1) } }