From e90e10bd2621a0f6fa726d02fc61a03b4c251c1b Mon Sep 17 00:00:00 2001 From: IanRDavies Date: Wed, 9 Mar 2022 15:56:08 +0000 Subject: [PATCH 1/3] add variable to monitor scrolling as scroll fix --- .../app/src/main/java/chat/simplex/app/views/chat/ChatView.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt index d509cd97b3..6e0d1fa6c1 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt @@ -138,6 +138,7 @@ fun ChatInfoToolbar(chat: Chat, back: () -> Unit, info: () -> Unit) { @Composable fun ChatItemsList(chatItems: List) { val listState = rememberLazyListState() + var scrolled = false val scope = rememberCoroutineScope() val uriHandler = LocalUriHandler.current LazyColumn(state = listState) { @@ -145,8 +146,9 @@ fun ChatItemsList(chatItems: List) { ChatItemView(cItem, uriHandler) } val len = chatItems.count() - if (len > 1) { + if (len > 1 && !scrolled) { scope.launch { + scrolled = true listState.animateScrollToItem(len - 1) } } From ff3daed4c665b09dd7748b430fd1293356f67283 Mon Sep 17 00:00:00 2001 From: IanRDavies Date: Wed, 9 Mar 2022 16:30:47 +0000 Subject: [PATCH 2/3] fix scrolling issue using save/load state --- .../chat/simplex/app/views/chat/ChatView.kt | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt index 6e0d1fa6c1..ed1a342659 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt @@ -11,6 +11,8 @@ import androidx.compose.material.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.ArrowBack import androidx.compose.runtime.* +import androidx.compose.runtime.saveable.mapSaver +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalUriHandler @@ -80,7 +82,10 @@ fun ChatLayout( info: () -> Unit, sendMessage: (String) -> Unit ) { - Surface(Modifier.fillMaxWidth().background(MaterialTheme.colors.background)) { + Surface( + Modifier + .fillMaxWidth() + .background(MaterialTheme.colors.background)) { ProvideWindowInsets(windowInsetsAnimationsEnabled = true) { Scaffold( topBar = { ChatInfoToolbar(chat, back, info) }, @@ -135,10 +140,23 @@ fun ChatInfoToolbar(chat: Chat, back: () -> Unit, info: () -> Unit) { } } +data class MessageListState(val scrolled: Boolean, val msgCount: Int) + +val MessageListStateSaver = run { + val scrolledKey = "scrolled" + val countKey = "msgCount" + mapSaver( + save = { mapOf(scrolledKey to it.scrolled, countKey to it.msgCount)}, + restore = { MessageListState(it[scrolledKey] as Boolean, it[countKey] as Int) } + ) +} + @Composable fun ChatItemsList(chatItems: List) { val listState = rememberLazyListState() - var scrolled = false + var messageListState = rememberSaveable(stateSaver = MessageListStateSaver) { + mutableStateOf(MessageListState(false, chatItems.count())) + } val scope = rememberCoroutineScope() val uriHandler = LocalUriHandler.current LazyColumn(state = listState) { @@ -146,9 +164,9 @@ fun ChatItemsList(chatItems: List) { ChatItemView(cItem, uriHandler) } val len = chatItems.count() - if (len > 1 && !scrolled) { + if (len > 1 && (!messageListState.value.scrolled || len != messageListState.value.msgCount)) { scope.launch { - scrolled = true + messageListState.value = MessageListState(true, chatItems.count()) listState.animateScrollToItem(len - 1) } } From b749bf7b084099cd8b932b5bc3b2bda2d31afd55 Mon Sep 17 00:00:00 2001 From: IanRDavies Date: Wed, 9 Mar 2022 18:54:19 +0000 Subject: [PATCH 3/3] fix scrolling with keyboard --- .../chat/simplex/app/views/chat/ChatView.kt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt index ed1a342659..6340e8c29c 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt @@ -5,6 +5,7 @@ import android.util.Log import androidx.activity.compose.BackHandler import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.gestures.scrollBy import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.* import androidx.compose.material.* @@ -140,14 +141,15 @@ fun ChatInfoToolbar(chat: Chat, back: () -> Unit, info: () -> Unit) { } } -data class MessageListState(val scrolled: Boolean, val msgCount: Int) +data class MessageListState(val scrolled: Boolean, val msgCount: Int, val keyboardOffset: Int) val MessageListStateSaver = run { val scrolledKey = "scrolled" val countKey = "msgCount" + val keyboardKey = "keyboardOffset" mapSaver( - save = { mapOf(scrolledKey to it.scrolled, countKey to it.msgCount)}, - restore = { MessageListState(it[scrolledKey] as Boolean, it[countKey] as Int) } + save = { mapOf(scrolledKey to it.scrolled, countKey to it.msgCount, keyboardKey to it.keyboardOffset) }, + restore = { MessageListState(it[scrolledKey] as Boolean, it[countKey] as Int, it[keyboardKey] as Int) } ) } @@ -155,7 +157,7 @@ val MessageListStateSaver = run { fun ChatItemsList(chatItems: List) { val listState = rememberLazyListState() var messageListState = rememberSaveable(stateSaver = MessageListStateSaver) { - mutableStateOf(MessageListState(false, chatItems.count())) + mutableStateOf(MessageListState(false, chatItems.count(), listState.layoutInfo.viewportEndOffset)) } val scope = rememberCoroutineScope() val uriHandler = LocalUriHandler.current @@ -164,9 +166,16 @@ fun ChatItemsList(chatItems: List) { ChatItemView(cItem, uriHandler) } val len = chatItems.count() + if(listState.layoutInfo.viewportEndOffset != messageListState.value.keyboardOffset) { + scope.launch { + val scrollBy = maxOf(messageListState.value.keyboardOffset.toFloat() - listState.layoutInfo.viewportEndOffset.toFloat(), 0f) + listState.scrollBy( scrollBy) + messageListState.value = messageListState.value.copy(keyboardOffset = listState.layoutInfo.viewportEndOffset) + } + } if (len > 1 && (!messageListState.value.scrolled || len != messageListState.value.msgCount)) { scope.launch { - messageListState.value = MessageListState(true, chatItems.count()) + messageListState.value = MessageListState(true, chatItems.count(), listState.layoutInfo.viewportEndOffset) listState.animateScrollToItem(len - 1) } }