@@ -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