Skip to content

Commit 93b00ec

Browse files
committed
reimplement message search
Co-authored by: AI-assistant: Copilot 1.8.2 (Claude Sonnet 4.6) Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
1 parent 520261e commit 93b00ec

31 files changed

Lines changed: 1416 additions & 372 deletions

app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import com.nextcloud.talk.models.json.status.predefined.PredefinedStatusOverall
2626
import com.nextcloud.talk.models.json.testNotification.TestNotificationOverall
2727
import com.nextcloud.talk.models.json.threads.ThreadOverall
2828
import com.nextcloud.talk.models.json.threads.ThreadsOverall
29+
import com.nextcloud.talk.models.json.unifiedsearch.UnifiedSearchOverall
2930
import com.nextcloud.talk.models.json.upcomingEvents.UpcomingEventsOverall
3031
import com.nextcloud.talk.models.json.userAbsence.UserAbsenceOverall
3132
import okhttp3.MultipartBody
@@ -451,6 +452,16 @@ interface NcApiCoroutines {
451452
@Query("reaction") reaction: String?
452453
): ReactionsOverall
453454

455+
@GET
456+
suspend fun performUnifiedSearch(
457+
@Header("Authorization") authorization: String?,
458+
@Url url: String,
459+
@Query("term") term: String,
460+
@Query("from") fromUrl: String?,
461+
@Query("limit") limit: Int,
462+
@Query("cursor") cursor: Int
463+
): UnifiedSearchOverall
464+
454465
// Url is: /api/{apiVersion}/chat/{token}/read
455466
@FormUrlEncoded
456467
@POST

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

Lines changed: 367 additions & 40 deletions
Large diffs are not rendered by default.

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

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,18 @@ import kotlinx.coroutines.flow.Flow
2121
@Suppress("TooManyFunctions")
2222
interface ChatMessageRepository : LifecycleAwareManager {
2323

24+
enum class LoadMoreDirection {
25+
OLDER,
26+
NEWER
27+
}
28+
29+
data class MessagesRange(val oldestMessageId: Long, val newestMessageId: Long)
30+
2431
/**
2532
* Stream of a list of messages to be handled using the associated boolean
2633
* false for past messages, true for future messages.
2734
*/
28-
val messageFlow:
29-
Flow<
30-
Triple<
31-
Boolean,
32-
Boolean,
33-
List<ChatMessage>
34-
>
35-
>
35+
val messageFlow: Flow<Triple<Boolean, Boolean, List<ChatMessage>>>
3636

3737
val updateMessageFlow: Flow<ChatMessage>
3838

@@ -68,11 +68,12 @@ interface ChatMessageRepository : LifecycleAwareManager {
6868
* [withNetworkParams] credentials and url
6969
*/
7070
suspend fun loadMoreMessages(
71-
beforeMessageId: Long,
71+
anchorMessageId: Long,
72+
direction: LoadMoreDirection,
7273
roomToken: String,
7374
withMessageLimit: Int,
7475
withNetworkParams: Bundle
75-
)
76+
): MessagesRange?
7677

7778
/**
7879
* Gets a individual message.
@@ -160,5 +161,9 @@ interface ChatMessageRepository : LifecycleAwareManager {
160161

161162
suspend fun onSignalingChatMessageReceived(chatMessages: List<ChatMessageJson>)
162163

163-
fun observeMessages(internalConversationId: String): Flow<List<ChatMessageEntity>>
164+
fun observeLatestMessages(internalConversationId: String): Flow<List<ChatMessageEntity>>
165+
166+
fun observeMessagesForAnchor(internalConversationId: String, anchorMessageId: Long): Flow<List<ChatMessageEntity>>
167+
168+
suspend fun loadMessageContext(messageId: Long, limit: Int, threadId: Long? = null): Result<MessagesRange>
164169
}

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

Lines changed: 90 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ class OfflineFirstChatRepository @Inject constructor(
112112
private var itIsPaused = false
113113

114114
lateinit var internalConversationId: String
115+
private lateinit var roomToken: String
115116
private lateinit var conversationModel: ConversationModel
116117
private lateinit var credentials: String
117118
private lateinit var urlForChatting: String
@@ -129,6 +130,7 @@ class OfflineFirstChatRepository @Inject constructor(
129130
threadId: Long?
130131
) {
131132
this.currentUser = currentUser
133+
this.roomToken = roomToken
132134

133135
internalConversationId = currentUser.id.toString() + "@" + roomToken
134136
this.credentials = credentials
@@ -283,24 +285,34 @@ class OfflineFirstChatRepository @Inject constructor(
283285
}
284286

285287
override suspend fun loadMoreMessages(
286-
beforeMessageId: Long,
288+
anchorMessageId: Long,
289+
direction: ChatMessageRepository.LoadMoreDirection,
287290
roomToken: String,
288291
withMessageLimit: Int,
289292
withNetworkParams: Bundle
290-
) {
291-
Log.d(TAG, "---- loadMoreMessages for $beforeMessageId ------------")
293+
): ChatMessageRepository.MessagesRange? {
294+
Log.d(TAG, "---- loadMoreMessages for $anchorMessageId ($direction) ------------")
295+
296+
val lookIntoFuture = direction == ChatMessageRepository.LoadMoreDirection.NEWER
292297

293298
val fieldMap = getFieldMap(
294-
lookIntoFuture = false,
299+
lookIntoFuture = lookIntoFuture,
295300
timeout = 0,
296-
includeLastKnown = false,
297-
lastKnown = beforeMessageId.toInt(),
301+
includeLastKnown = true,
302+
lastKnown = anchorMessageId.toInt(),
298303
limit = withMessageLimit
299304
)
300305
withNetworkParams.putSerializable(BundleKeys.KEY_FIELD_MAP, fieldMap)
301306

302307
Log.d(TAG, "Starting online request for loadMoreMessages")
303308
getAndPersistMessages(withNetworkParams)
309+
310+
return getBlockOfMessage(anchorMessageId.toInt())?.let {
311+
ChatMessageRepository.MessagesRange(
312+
oldestMessageId = it.oldestMessageId,
313+
newestMessageId = it.newestMessageId
314+
)
315+
}
304316
}
305317

306318
@Suppress("LongParameterList")
@@ -355,6 +367,51 @@ class OfflineFirstChatRepository @Inject constructor(
355367
)
356368
}
357369

370+
@Suppress("Detekt.TooGenericExceptionCaught")
371+
override suspend fun loadMessageContext(
372+
messageId: Long,
373+
limit: Int,
374+
threadId: Long?
375+
): Result<ChatMessageRepository.MessagesRange> =
376+
runCatching {
377+
val messages = network.getContextForChatMessage(
378+
credentials = credentials,
379+
baseUrl = currentUser.baseUrl!!,
380+
token = roomToken,
381+
messageId = messageId.toString(),
382+
limit = limit,
383+
threadId = threadId?.toInt()
384+
)
385+
386+
val filteredMessages = if (threadId == null) {
387+
messages.filter { !it.hasThread || it.threadId == it.id }
388+
} else {
389+
messages
390+
}
391+
392+
require(filteredMessages.isNotEmpty()) { "No context messages returned" }
393+
394+
val persisted = persistChatMessagesAndHandleSystemMessages(filteredMessages)
395+
val oldestId = persisted.minOf { it.id }
396+
val newestId = persisted.maxOf { it.id }
397+
398+
val block = ChatBlockEntity(
399+
internalConversationId = internalConversationId,
400+
accountId = currentUser.id!!,
401+
token = roomToken,
402+
threadId = this.threadId,
403+
oldestMessageId = oldestId,
404+
newestMessageId = newestId,
405+
hasHistory = true
406+
)
407+
updateBlocks(block)
408+
409+
ChatMessageRepository.MessagesRange(
410+
oldestMessageId = oldestId,
411+
newestMessageId = newestId
412+
)
413+
}
414+
358415
override fun observeParentMessages(parentIds: List<Long>): Flow<List<ChatMessage>> =
359416
chatDao.getMessagesFromIds(parentIds)
360417
.map { entities -> entities.map { it.toDomainModel() } }
@@ -381,7 +438,7 @@ class OfflineFirstChatRepository @Inject constructor(
381438
val messages = network.getContextForChatMessage(
382439
credentials = credentials,
383440
baseUrl = currentUser.baseUrl!!,
384-
token = conversationModel.token,
441+
token = roomToken,
385442
messageId = id.toString(),
386443
limit = 1,
387444
threadId = null
@@ -990,7 +1047,7 @@ class OfflineFirstChatRepository @Inject constructor(
9901047
return chatMessageEntities
9911048
}
9921049

993-
override fun observeMessages(internalConversationId: String): Flow<List<ChatMessageEntity>> =
1050+
override fun observeLatestMessages(internalConversationId: String): Flow<List<ChatMessageEntity>> =
9941051
chatBlocksDao
9951052
.getLatestChatBlock(internalConversationId, threadId)
9961053
.distinctUntilChanged()
@@ -1007,6 +1064,31 @@ class OfflineFirstChatRepository @Inject constructor(
10071064
}
10081065
}
10091066

1067+
override fun observeMessagesForAnchor(
1068+
internalConversationId: String,
1069+
anchorMessageId: Long
1070+
): Flow<List<ChatMessageEntity>> =
1071+
chatBlocksDao
1072+
.getChatBlocksContainingMessageId(
1073+
internalConversationId = internalConversationId,
1074+
threadId = threadId,
1075+
messageId = anchorMessageId
1076+
)
1077+
.distinctUntilChanged()
1078+
.flatMapLatest { blocks ->
1079+
val block = blocks.firstOrNull()
1080+
if (block == null) {
1081+
flowOf(emptyList())
1082+
} else {
1083+
chatDao.getMessagesInRange(
1084+
internalConversationId = internalConversationId,
1085+
threadId = threadId,
1086+
oldestMessageId = block.oldestMessageId,
1087+
newestMessageId = block.newestMessageId
1088+
)
1089+
}
1090+
}
1091+
10101092
@Suppress("LongParameterList")
10111093
override suspend fun sendScheduledChatMessage(
10121094
credentials: String,

0 commit comments

Comments
 (0)