Skip to content

Commit ebc4860

Browse files
refactor: Tidy up createNewThread()
1 parent dcafc65 commit ebc4860

1 file changed

Lines changed: 83 additions & 59 deletions

File tree

app/src/main/java/com/infomaniak/mail/data/cache/mailboxContent/RefreshController.kt

Lines changed: 83 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ class RefreshController @Inject constructor(
430430
val upToDateFolder = getUpToDateFolder(folder.id)
431431
val isConversationMode = localSettings.threadMode == ThreadMode.CONVERSATION
432432

433-
return@write createThreads(scope, upToDateFolder, messages, isConversationMode).also {
433+
return@write handleAddedMessages(scope, upToDateFolder, messages, isConversationMode).also {
434434

435435
// TODO: This count will be false for INBOX & SNOOZED when the snooze feature will be implemented
436436
val messagesCount = MessageController.getMessagesCountByFolderId(upToDateFolder.id, realm = this)
@@ -503,7 +503,7 @@ class RefreshController @Inject constructor(
503503
//endregion
504504

505505
//region Create Threads
506-
private fun MutableRealm.createThreads(
506+
private fun MutableRealm.handleAddedMessages(
507507
scope: CoroutineScope,
508508
folder: Folder,
509509
remoteMessages: List<Message>,
@@ -521,7 +521,9 @@ class RefreshController @Inject constructor(
521521
addedMessagesUids.add(remoteMessage.shortUid)
522522

523523
val newThread = if (isConversationMode) {
524-
createNewThread(scope, remoteMessage, impactedThreadsManaged)
524+
val (thread, impactThreads) = handleAddedMessage(scope, remoteMessage)
525+
impactedThreadsManaged += impactThreads
526+
thread
525527
} else {
526528
remoteMessage.toThread()
527529
}
@@ -542,31 +544,6 @@ class RefreshController @Inject constructor(
542544
return impactedThreadsUnmanaged
543545
}
544546

545-
private fun MutableRealm.createNewThread(
546-
scope: CoroutineScope,
547-
remoteMessage: Message,
548-
impactedThreadsManaged: MutableSet<Thread>,
549-
): Thread? {
550-
// Other pre-existing Threads that will also require this Message and will provide the prior Messages for this new Thread.
551-
val existingThreads = ThreadController.getThreadsByMessageIds(remoteMessage.messageIds, realm = this)
552-
val existingMessages = getExistingMessages(existingThreads)
553-
554-
// Some Messages don't have references to all previous Messages of the Thread (ex: these from the iOS Mail app).
555-
// Because we are missing the links between Messages, it will create multiple Threads for the same Folder.
556-
// Hence, we need to find these duplicates.
557-
val isThereDuplicatedThreads = isThereDuplicatedThreads(remoteMessage.messageIds, existingThreads.count())
558-
559-
// Create Thread in this Folder
560-
val thread = createNewThreadIfRequired(scope, remoteMessage, existingThreads, existingMessages)
561-
// Update Threads in other Folders
562-
updateOtherExistingThreads(scope, remoteMessage, existingThreads, existingMessages, impactedThreadsManaged)
563-
564-
// Now that all other existing Threads are updated, we need to remove the duplicated Threads.
565-
if (isThereDuplicatedThreads) removeDuplicatedThreads(remoteMessage.messageIds, impactedThreadsManaged)
566-
567-
return thread
568-
}
569-
570547
private fun initMessageLocalValues(remoteMessage: Message, folder: Folder) {
571548
remoteMessage.initLocalValues(
572549
MessageInitialState(
@@ -580,27 +557,33 @@ class RefreshController @Inject constructor(
580557
)
581558
}
582559

583-
private fun MutableRealm.isThereDuplicatedThreads(messageIds: RealmSet<String>, threadsCount: Int): Boolean {
584-
val foldersCount = ThreadController.getExistingThreadsFoldersCount(messageIds, realm = this)
585-
return foldersCount != threadsCount.toLong()
586-
}
560+
private fun MutableRealm.handleAddedMessage(scope: CoroutineScope, remoteMessage: Message): Pair<Thread?, Set<Thread>> {
587561

588-
private fun MutableRealm.removeDuplicatedThreads(messageIds: RealmSet<String>, impactedThreadsManaged: MutableSet<Thread>) {
562+
// Other pre-existing Threads that will also require this Message and will provide the prior Messages for this new Thread.
563+
val existingThreads = ThreadController.getThreadsByMessageIds(remoteMessage.messageIds, realm = this)
564+
val existingMessages = getExistingMessages(existingThreads)
565+
// Some Messages don't have references to all previous Messages of the Thread (ex: these from the iOS Mail app).
566+
// Because we are missing the links between Messages, it will create multiple Threads for the same Folder.
567+
// Hence, we need to find these duplicates.
568+
// TODO: Find a way to compute this boolean in `updateExistingThreads()` if possible
569+
val isThereDuplicatedThreads = isThereDuplicatedThreads(remoteMessage.messageIds, existingThreads.count())
589570

590-
// Create a map with all duplicated Threads of the same Thread in a list.
591-
val map = mutableMapOf<String, MutableList<Thread>>()
592-
ThreadController.getThreadsByMessageIds(messageIds, realm = this).forEach {
593-
map.getOrPut(it.folderId) { mutableListOf() }.add(it)
594-
}
571+
val thread = createNewThreadIfRequired(scope, remoteMessage, existingThreads, existingMessages)
595572

596-
map.values.forEach { threads ->
597-
threads.forEachIndexed { index, thread ->
598-
if (index > 0) { // We want to keep only 1 duplicated Thread, so we skip the 1st one. (He's the chosen one!)
599-
impactedThreadsManaged.remove(thread)
600-
delete(thread) // Delete the other Threads. Sorry bro, you won't be missed.
601-
}
602-
}
603-
}
573+
val impactedThreads = updateExistingThreads(
574+
scope = scope,
575+
remoteMessage = remoteMessage,
576+
existingThreads = existingThreads,
577+
existingMessages = existingMessages,
578+
isThereDuplicatedThreads = isThereDuplicatedThreads,
579+
)
580+
581+
return thread to impactedThreads
582+
}
583+
584+
private fun MutableRealm.isThereDuplicatedThreads(messageIds: RealmSet<String>, threadsCount: Int): Boolean {
585+
val foldersCount = ThreadController.getExistingThreadsFoldersCount(messageIds, realm = this)
586+
return foldersCount != threadsCount.toLong()
604587
}
605588

606589
private fun TypedRealm.createNewThreadIfRequired(
@@ -621,33 +604,74 @@ class RefreshController @Inject constructor(
621604
return newThread
622605
}
623606

624-
private fun MutableRealm.updateOtherExistingThreads(
607+
private fun MutableRealm.updateExistingThreads(
625608
scope: CoroutineScope,
626609
remoteMessage: Message,
627610
existingThreads: RealmResults<Thread>,
628611
existingMessages: Set<Message>,
629-
impactedThreadsManaged: MutableSet<Thread>,
630-
) {
631-
if (existingThreads.isEmpty()) return
612+
isThereDuplicatedThreads: Boolean,
613+
): Set<Thread> {
614+
615+
val impactedThreads = mutableSetOf<Thread>()
616+
617+
// Update already existing Threads (i.e. in other Folders, or specific cases like Snoozed)
618+
impactedThreads += addAllMessagesToAllThreads(scope, remoteMessage, existingThreads, existingMessages)
619+
620+
// Now that all existing Threads are updated, we need to remove the duplicated Threads.
621+
if (isThereDuplicatedThreads) {
622+
val duplicatedThreads = identifyExtraDuplicatedThreads(remoteMessage.messageIds)
623+
impactedThreads -= duplicatedThreads
624+
duplicatedThreads.forEach(::delete) // Delete the other Threads. Sorry bro, you won't be missed.
625+
}
626+
627+
return impactedThreads
628+
}
629+
630+
private fun MutableRealm.addAllMessagesToAllThreads(
631+
scope: CoroutineScope,
632+
remoteMessage: Message,
633+
existingThreads: RealmResults<Thread>,
634+
existingMessages: Set<Message>,
635+
): Set<Thread> {
632636

633-
val allExistingMessages = mutableSetOf<Message>().apply {
637+
if (existingThreads.isEmpty()) return emptySet()
638+
639+
val allExistingMessages = buildSet {
634640
addAll(existingMessages)
635641
add(remoteMessage)
636642
}
637643

638-
existingThreads.forEach { thread ->
639-
scope.ensureActive()
640-
641-
allExistingMessages.forEach { existingMessage ->
644+
return buildSet {
645+
existingThreads.forEach { thread ->
642646
scope.ensureActive()
643647

644-
if (!thread.messages.contains(existingMessage)) {
645-
thread.messagesIds += existingMessage.messageIds
646-
thread.addMessageWithConditions(existingMessage, realm = this)
648+
allExistingMessages.forEach { existingMessage ->
649+
scope.ensureActive()
650+
651+
if (!thread.messages.contains(existingMessage)) {
652+
thread.messagesIds += existingMessage.messageIds
653+
thread.addMessageWithConditions(existingMessage, realm = this@addAllMessagesToAllThreads)
654+
}
647655
}
656+
657+
add(thread)
648658
}
659+
}
660+
}
661+
662+
private fun MutableRealm.identifyExtraDuplicatedThreads(messageIds: RealmSet<String>): Set<Thread> {
649663

650-
impactedThreadsManaged += thread
664+
// Create a map with all duplicated Threads of the same Thread in a list.
665+
val map = mutableMapOf<String, MutableList<Thread>>()
666+
ThreadController.getThreadsByMessageIds(messageIds, realm = this).forEach {
667+
map.getOrPut(it.folderId) { mutableListOf() }.add(it)
668+
}
669+
670+
return buildSet {
671+
map.values.forEach { threads ->
672+
// We want to keep only 1 duplicated Thread, so we skip the 1st one. (He's the chosen one!)
673+
addAll(threads.subList(1, threads.count()))
674+
}
651675
}
652676
}
653677

0 commit comments

Comments
 (0)