@@ -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,16 @@ 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)
589565
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- }
566+ val thread = createNewThreadIfRequired(scope, remoteMessage, existingThreads, existingMessages)
567+ val impactedThreads = updateExistingThreads(scope, remoteMessage, existingThreads, existingMessages)
595568
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- }
569+ return thread to impactedThreads
604570 }
605571
606572 private fun TypedRealm.createNewThreadIfRequired (
@@ -621,33 +587,73 @@ class RefreshController @Inject constructor(
621587 return newThread
622588 }
623589
624- private fun MutableRealm.updateOtherExistingThreads (
590+ private fun MutableRealm.updateExistingThreads (
625591 scope : CoroutineScope ,
626592 remoteMessage : Message ,
627593 existingThreads : RealmResults <Thread >,
628594 existingMessages : Set <Message >,
629- impactedThreadsManaged : MutableSet <Thread >,
630- ) {
631- if (existingThreads.isEmpty()) return
595+ ): Set <Thread > {
632596
633- val allExistingMessages = mutableSetOf<Message >().apply {
597+ val impactedThreads = mutableSetOf<Thread >()
598+
599+ // Update already existing Threads (i.e. in other Folders, or specific cases like Snoozed)
600+ impactedThreads + = addAllMessagesToAllThreads(scope, remoteMessage, existingThreads, existingMessages)
601+
602+ // Some Messages don't have references to all previous Messages of the Thread (ex: these from the iOS Mail app).
603+ // Because we are missing the links between Messages, it will create multiple Threads for the same Folder.
604+ // Hence, we need to find these duplicates, and remove them.
605+ val duplicatedThreads = identifyExtraDuplicatedThreads(remoteMessage.messageIds)
606+ impactedThreads - = duplicatedThreads
607+ duplicatedThreads.forEach(::delete) // Delete the other Threads. Sorry bro, you won't be missed.
608+
609+ return impactedThreads
610+ }
611+
612+ private fun MutableRealm.addAllMessagesToAllThreads (
613+ scope : CoroutineScope ,
614+ remoteMessage : Message ,
615+ existingThreads : RealmResults <Thread >,
616+ existingMessages : Set <Message >,
617+ ): Set <Thread > {
618+
619+ if (existingThreads.isEmpty()) return emptySet()
620+
621+ val allExistingMessages = buildSet {
634622 addAll(existingMessages)
635623 add(remoteMessage)
636624 }
637625
638- existingThreads.forEach { thread ->
639- scope.ensureActive()
640-
641- allExistingMessages.forEach { existingMessage ->
626+ return buildSet {
627+ existingThreads.forEach { thread ->
642628 scope.ensureActive()
643629
644- if (! thread.messages.contains(existingMessage)) {
645- thread.messagesIds + = existingMessage.messageIds
646- thread.addMessageWithConditions(existingMessage, realm = this )
630+ allExistingMessages.forEach { existingMessage ->
631+ scope.ensureActive()
632+
633+ if (! thread.messages.contains(existingMessage)) {
634+ thread.messagesIds + = existingMessage.messageIds
635+ thread.addMessageWithConditions(existingMessage, realm = this @addAllMessagesToAllThreads)
636+ }
647637 }
638+
639+ add(thread)
648640 }
641+ }
642+ }
643+
644+ private fun MutableRealm.identifyExtraDuplicatedThreads (messageIds : RealmSet <String >): Set <Thread > {
649645
650- impactedThreadsManaged + = thread
646+ // Create a map with all duplicated Threads of the same Thread in a list.
647+ val map = mutableMapOf<String , MutableList <Thread >>()
648+ ThreadController .getThreadsByMessageIds(messageIds, realm = this ).forEach {
649+ map.getOrPut(it.folderId) { mutableListOf () }.add(it)
650+ }
651+
652+ return buildSet {
653+ map.values.forEach { threads ->
654+ // We want to keep only 1 duplicated Thread, so we skip the 1st one. (He's the chosen one!)
655+ addAll(threads.subList(1 , threads.count()))
656+ }
651657 }
652658 }
653659
0 commit comments