Skip to content

Commit 37d84db

Browse files
committed
add handling to automatically set messages as read
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
1 parent 6eea865 commit 37d84db

2 files changed

Lines changed: 34 additions & 10 deletions

File tree

app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,9 @@ class ChatActivity :
640640
GetNewChatView(
641641
chatItems = chatItems,
642642
conversationThreadId = conversationThreadId,
643-
onLoadMore = { loadMoreMessagesCompose() }
643+
onLoadMore = { loadMoreMessagesCompose() },
644+
advanceLocalLastReadMessageIfNeeded = { advanceLocalLastReadMessageIfNeeded(it) },
645+
updateRemoteLastReadMessageIfNeeded = { updateRemoteLastReadMessageIfNeeded() }
644646
)
645647
}
646648
}
@@ -670,7 +672,7 @@ class ChatActivity :
670672
// With Jetpack Compose the flow will be used directly in the UI instead to clear and add everything.
671673
adapter!!.clear()
672674
adapter!!.addToEnd(chatMessages, false)
673-
advanceLocalLastReadMessageIfNeeded()
675+
advanceLocalLastReadMessageIfNeededChatKit()
674676
} else {
675677
Log.e(TAG, "adapter was null")
676678
}
@@ -1576,7 +1578,7 @@ class ChatActivity :
15761578
super.onScrollStateChanged(recyclerView, newState)
15771579

15781580
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
1579-
advanceLocalLastReadMessageIfNeeded()
1581+
advanceLocalLastReadMessageIfNeededChatKit()
15801582
updateRemoteLastReadMessageIfNeeded()
15811583
if (isScrolledToBottom()) {
15821584
binding.unreadMessagesPopup.visibility = View.GONE
@@ -2892,18 +2894,23 @@ class ChatActivity :
28922894
adapter = null
28932895
}
28942896

2895-
private fun advanceLocalLastReadMessageIfNeeded() {
2897+
@Deprecated("old implementation for ChatKit")
2898+
private fun advanceLocalLastReadMessageIfNeededChatKit() {
28962899
val position = layoutManager?.findFirstVisibleItemPosition()
28972900
position?.let {
28982901
// Casting could fail if it's not a chatMessage. It should not matter as the function is triggered often
28992902
// enough. If it's a problem, either improve or wait for migration to Jetpack Compose.
29002903
val message = adapter?.items?.getOrNull(it)?.item as? ChatMessage
29012904
message?.jsonMessageId?.let { messageId ->
2902-
chatViewModel.advanceLocalLastReadMessageIfNeeded(messageId)
2905+
advanceLocalLastReadMessageIfNeeded(messageId)
29032906
}
29042907
}
29052908
}
29062909

2910+
private fun advanceLocalLastReadMessageIfNeeded(messageId: Int) {
2911+
chatViewModel.advanceLocalLastReadMessageIfNeeded(messageId)
2912+
}
2913+
29072914
private fun updateRemoteLastReadMessageIfNeeded() {
29082915
val url = ApiUtils.getUrlForChatReadMarker(
29092916
ApiUtils.getChatApiVersion(spreedCapabilities, intArrayOf(ApiUtils.API_V1)),

app/src/main/java/com/nextcloud/talk/ui/chat/ChatView.kt

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
2828
import androidx.compose.material.icons.Icons
2929
import androidx.compose.material.icons.filled.KeyboardArrowDown
3030
import androidx.compose.material3.Icon
31-
import androidx.compose.material3.MaterialTheme
3231
import androidx.compose.material3.MaterialTheme.colorScheme
3332
import androidx.compose.material3.Surface
3433
import androidx.compose.material3.Text
@@ -41,6 +40,7 @@ import androidx.compose.runtime.mutableIntStateOf
4140
import androidx.compose.runtime.mutableStateOf
4241
import androidx.compose.runtime.remember
4342
import androidx.compose.runtime.rememberCoroutineScope
43+
import androidx.compose.runtime.rememberUpdatedState
4444
import androidx.compose.runtime.setValue
4545
import androidx.compose.runtime.snapshotFlow
4646
import androidx.compose.ui.Alignment
@@ -52,7 +52,6 @@ import androidx.compose.ui.platform.LocalResources
5252
import androidx.compose.ui.unit.dp
5353
import androidx.compose.ui.unit.sp
5454
import com.nextcloud.talk.R
55-
import com.nextcloud.talk.chat.UnreadMessagesPopup
5655
import com.nextcloud.talk.chat.data.model.ChatMessage
5756
import com.nextcloud.talk.chat.viewmodels.ChatViewModel
5857
import com.nextcloud.talk.data.user.model.User
@@ -74,7 +73,9 @@ private val AUTHOR_TEXT_SIZE = 12.sp
7473
fun GetNewChatView(
7574
chatItems: List<ChatViewModel.ChatItem>,
7675
conversationThreadId: Long? = null,
77-
onLoadMore: (() -> Unit?)?
76+
onLoadMore: (() -> Unit?)?,
77+
advanceLocalLastReadMessageIfNeeded: ((Int) -> Unit?)?,
78+
updateRemoteLastReadMessageIfNeeded: (() -> Unit?)?
7879
) {
7980
val listState = rememberLazyListState()
8081
val showUnreadPopup = remember { mutableStateOf(false) }
@@ -104,6 +105,8 @@ fun GetNewChatView(
104105
// Show floating scroll-to-newest button when not at newest
105106
val showScrollToNewest by remember { derivedStateOf { !isAtNewest } }
106107

108+
val latestChatItems by rememberUpdatedState(chatItems)
109+
107110
// Track newest message and show unread popup
108111
LaunchedEffect(chatItems) {
109112
if (chatItems.isEmpty()) return@LaunchedEffect
@@ -165,8 +168,7 @@ fun GetNewChatView(
165168
val stickyDateHeaderText by remember(listState, chatItems) {
166169
derivedStateOf {
167170
chatItems.getOrNull(
168-
listState.layoutInfo.visibleItemsInfo
169-
.lastOrNull()?.index ?: 0
171+
listState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: 0
170172
)?.let { item ->
171173
when (item) {
172174
is ChatViewModel.ChatItem.MessageItem ->
@@ -185,6 +187,7 @@ fun GetNewChatView(
185187
// Only listen to scroll if user is away from newest messages. This ensures the stickyHeader is not shown on
186188
// every new received message when being at the bottom of the list (because this triggers a scroll).
187189
if (!isNearNewest) {
190+
updateRemoteLastReadMessageIfNeeded?.invoke()
188191
snapshotFlow { listState.isScrollInProgress }
189192
.collectLatest { scrolling ->
190193
if (scrolling) {
@@ -199,6 +202,20 @@ fun GetNewChatView(
199202
}
200203
}
201204

205+
LaunchedEffect(isAtNewest) {
206+
if (!isAtNewest) return@LaunchedEffect
207+
208+
latestChatItems
209+
.getOrNull(listState.firstVisibleItemIndex)
210+
?.let { item ->
211+
// It might not always be a chat message. Not calling advanceLocalLastReadMessageIfNeeded should not
212+
// matter. This should be triggered often enough so it's okay when it's true the next times.
213+
if (item is ChatViewModel.ChatItem.MessageItem) {
214+
advanceLocalLastReadMessageIfNeeded?.invoke(item.message.jsonMessageId)
215+
}
216+
}
217+
}
218+
202219
val stickyDateHeaderAlpha by animateFloatAsState(
203220
targetValue = if (stickyDateHeader && stickyDateHeaderText.isNotEmpty()) 1f else 0f,
204221
animationSpec = tween(durationMillis = if (stickyDateHeader) 500 else 1000),

0 commit comments

Comments
 (0)