Skip to content

Commit ceef454

Browse files
committed
use sticky header (WIP, experimental, to fix: reverse order issues)
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
1 parent 1d947ca commit ceef454

7 files changed

Lines changed: 104 additions & 7 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3434,7 +3434,7 @@ class ChatActivity :
34343434
withUrl = urlForChatting,
34353435
withCredentials = credentials!!,
34363436
withMessageLimit = MESSAGE_PULL_LIMIT,
3437-
roomToken = currentConversation!!.token
3437+
roomToken = roomToken
34383438
)
34393439
}
34403440
}

app/src/main/java/com/nextcloud/talk/chat/data/ChatMessageRepository.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,6 @@ interface ChatMessageRepository : LifecycleAwareManager {
157157
suspend fun onSignalingChatMessageReceived(chatMessage: ChatMessageJson)
158158

159159
fun observeMessages(internalConversationId: String): Flow<List<ChatMessageEntity>>
160+
161+
fun observeMessagesForChatKit(internalConversationId: String): Flow<List<ChatMessageEntity>>
160162
}

app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,23 @@ class OfflineFirstChatRepository @Inject constructor(
11321132
}
11331133
}
11341134

1135+
override fun observeMessagesForChatKit(internalConversationId: String): Flow<List<ChatMessageEntity>> =
1136+
chatBlocksDao
1137+
.getLatestChatBlock(internalConversationId, threadId)
1138+
.distinctUntilChanged()
1139+
.flatMapLatest { latestBlock ->
1140+
1141+
if (latestBlock == null) {
1142+
flowOf(emptyList())
1143+
} else {
1144+
chatDao.getMessagesNewerThanForChatKit(
1145+
internalConversationId = internalConversationId,
1146+
threadId = threadId,
1147+
oldestMessageId = latestBlock.oldestMessageId
1148+
)
1149+
}
1150+
}
1151+
11351152
@Suppress("LongParameterList")
11361153
override suspend fun sendScheduledChatMessage(
11371154
credentials: String,

app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ import java.time.Instant
8282
import java.time.LocalDate
8383
import java.time.ZoneId
8484
import javax.inject.Inject
85+
import kotlin.collections.asReversed
8586

8687
@Suppress("TooManyFunctions", "LongParameterList")
8788
class ChatViewModel @AssistedInject constructor(
@@ -354,15 +355,15 @@ class ChatViewModel @AssistedInject constructor(
354355
.map { messages ->
355356
buildList<ChatItem> {
356357
var lastDate: LocalDate? = null
357-
messages.asReversed().forEach { msg ->
358+
messages.forEach { msg ->
358359
val date = msg.dateKey()
359360
if (date != lastDate) {
360361
add(ChatItem.DateHeaderItem(date))
361362
lastDate = date
362363
}
363364
add(ChatItem.MessageItem(msg))
364365
}
365-
}.asReversed()
366+
}
366367
}
367368
.stateIn(
368369
scope = viewModelScope,
@@ -375,7 +376,7 @@ class ChatViewModel @AssistedInject constructor(
375376
internalConversationId
376377
.filterNotNull()
377378
.flatMapLatest { conversationId ->
378-
chatRepository.observeMessages(conversationId)
379+
chatRepository.observeMessagesForChatKit(conversationId)
379380
}
380381
.map { entities -> entities.map(ChatMessageEntity::asModel) }
381382
.onEach { messages ->
@@ -1326,6 +1327,7 @@ class ChatViewModel @AssistedInject constructor(
13261327

13271328
sealed interface ChatItem {
13281329
fun messageOrNull(): ChatMessage? = (this as? MessageItem)?.message
1330+
fun dateOrNull(): LocalDate? = (this as? DateHeaderItem)?.date
13291331

13301332
fun stableKey(): Any =
13311333
when (this) {

app/src/main/java/com/nextcloud/talk/data/database/dao/ChatMessagesDao.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ interface ChatMessagesDao {
3636
AND isTemporary = 0
3737
AND (:threadId IS NULL OR threadId = :threadId)
3838
AND id > :oldestMessageId
39-
ORDER BY timestamp DESC, id DESC
39+
ORDER BY timestamp ASC, id ASC
4040
"""
4141
)
4242
fun getMessagesNewerThan(
@@ -45,6 +45,23 @@ interface ChatMessagesDao {
4545
oldestMessageId: Long
4646
): Flow<List<ChatMessageEntity>>
4747

48+
@Query(
49+
"""
50+
SELECT *
51+
FROM ChatMessages
52+
WHERE internalConversationId = :internalConversationId
53+
AND isTemporary = 0
54+
AND (:threadId IS NULL OR threadId = :threadId)
55+
AND id > :oldestMessageId
56+
ORDER BY timestamp DESC, id DESC
57+
"""
58+
)
59+
fun getMessagesNewerThanForChatKit(
60+
internalConversationId: String,
61+
threadId: Long?,
62+
oldestMessageId: Long
63+
): Flow<List<ChatMessageEntity>>
64+
4865
@Query(
4966
"""
5067
SELECT *

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

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ import com.nextcloud.talk.R
3535
import com.nextcloud.talk.chat.UnreadMessagesPopup
3636
import com.nextcloud.talk.chat.data.model.ChatMessage
3737
import com.nextcloud.talk.chat.viewmodels.ChatViewModel
38+
import com.nextcloud.talk.chat.viewmodels.ChatViewModel.ChatItem.DateHeaderItem
39+
import com.nextcloud.talk.chat.viewmodels.ChatViewModel.ChatItem.MessageItem
3840
import com.nextcloud.talk.data.user.model.User
3941
import kotlinx.coroutines.Dispatchers
4042
import kotlinx.coroutines.delay
@@ -128,11 +130,53 @@ fun GetNewChatView(
128130
LazyColumn(
129131
state = listState,
130132
verticalArrangement = Arrangement.spacedBy(8.dp),
131-
reverseLayout = true,
133+
reverseLayout = false,
132134
modifier = Modifier
133135
.padding(16.dp)
134136
.fillMaxSize()
135137
) {
138+
stickyHeader {
139+
if (chatItems.isEmpty()) {
140+
Column(
141+
verticalArrangement = Arrangement.Center,
142+
horizontalAlignment = Alignment.CenterHorizontally,
143+
modifier = Modifier.fillMaxSize()
144+
) {
145+
ShimmerGroup()
146+
}
147+
} else {
148+
val item = chatItems[listState.firstVisibleItemIndex]
149+
val dateString = when (item) {
150+
is MessageItem -> formatTime(item.message.timestamp * LONG_1000)
151+
is DateHeaderItem -> formatTime(item.date)
152+
}
153+
val color = colorScheme.onSurfaceVariant
154+
val backgroundColor =
155+
LocalResources.current.getColor(R.color.bg_message_list_incoming_bubble, null)
156+
Row(
157+
horizontalArrangement = Arrangement.Absolute.Center,
158+
verticalAlignment = Alignment.CenterVertically
159+
) {
160+
Spacer(modifier = Modifier.weight(1f))
161+
Text(
162+
dateString,
163+
fontSize = AUTHOR_TEXT_SIZE,
164+
color = color,
165+
modifier = Modifier
166+
.padding(8.dp)
167+
.shadow(
168+
16.dp,
169+
spotColor = colorScheme.primary,
170+
ambientColor = colorScheme.primary
171+
)
172+
.background(color = Color(backgroundColor), shape = RoundedCornerShape(8.dp))
173+
.padding(8.dp)
174+
)
175+
Spacer(modifier = Modifier.weight(1f))
176+
}
177+
}
178+
}
179+
136180
items(
137181
displayedChatItems,
138182
key = {
@@ -364,8 +408,17 @@ private fun ChatMessage.shouldFilter(): Boolean =
364408
fun formatTime(timestampMillis: Long): String {
365409
val instant = Instant.ofEpochMilli(timestampMillis)
366410
val dateTime = instant.atZone(ZoneId.systemDefault()).toLocalDate()
411+
return formatTime(dateTime)
412+
}
413+
414+
fun formatTime(localDate: LocalDate): String {
367415
val formatter = DateTimeFormatter.ofPattern("MMM dd, yyyy")
368-
return dateTime.format(formatter)
416+
val text = when (localDate) {
417+
LocalDate.now() -> "Today"
418+
LocalDate.now().minusDays(1) -> "Yesterday"
419+
else -> localDate.format(formatter)
420+
}
421+
return text
369422
}
370423

371424
fun searchMessages(messages: List<ChatMessage>, searchId: String): Int {

app/src/main/java/com/nextcloud/talk/utils/preview/ComposePreviewUtilsDaos.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ class DummyChatMessagesDaoImpl : ChatMessagesDao {
2929
oldestMessageId: Long
3030
): Flow<List<ChatMessageEntity>> = flowOf()
3131

32+
override fun getMessagesNewerThanForChatKit(
33+
internalConversationId: String,
34+
threadId: Long?,
35+
oldestMessageId: Long
36+
): Flow<List<ChatMessageEntity>> = flowOf()
37+
3238
override fun getMessagesForConversation(
3339
internalConversationId: String,
3440
threadId: Long?

0 commit comments

Comments
 (0)