diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestChatPanel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestChatPanel.kt index 355f0f263..27334b1ef 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestChatPanel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestChatPanel.kt @@ -35,6 +35,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember @@ -100,6 +101,19 @@ internal fun ColumnScope.NestChatPanel( val listState = rememberLazyListState() + // Auto-stick to the newest message. With reverseLayout=true, item 0 + // is the bottom of the viewport (newest). When a new message is + // prepended, LazyColumn preserves visual position by shifting + // firstVisibleItemIndex from 0 → 1, leaving the new message just + // below the viewport. If the user was at (or near) the bottom, + // scroll back to 0 so the new message becomes visible. If they're + // reading older history, leave them where they are. + LaunchedEffect(messages.firstOrNull()?.idHex) { + if (listState.firstVisibleItemIndex <= 1) { + listState.animateScrollToItem(0) + } + } + Column(modifier = modifier.fillMaxWidth()) { Box( modifier = diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lobby/NestLobbyScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lobby/NestLobbyScreen.kt index 6aefe6b9c..2e44feb77 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lobby/NestLobbyScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/lobby/NestLobbyScreen.kt @@ -164,6 +164,19 @@ private fun NestLobbyContent( val listState = rememberLazyListState() val scope = rememberCoroutineScope() + // Auto-stick to the newest message. With reverseLayout=true, item 0 + // is the bottom of the viewport (newest). When a new message is + // prepended, LazyColumn preserves visual position by shifting + // firstVisibleItemIndex from 0 → 1, leaving the new message just + // below the viewport. If the user was at (or near) the bottom, + // scroll back to 0 so the new message becomes visible. If they're + // reading older history, leave them where they are. + LaunchedEffect(messages.firstOrNull()?.idHex) { + if (listState.firstVisibleItemIndex <= 1) { + listState.animateScrollToItem(0) + } + } + Scaffold( contentWindowInsets = WindowInsets(0), topBar = {