@@ -430,7 +430,7 @@ class RefreshController @Inject constructor(
430
430
val upToDateFolder = getUpToDateFolder(folder.id)
431
431
val isConversationMode = localSettings.threadMode == ThreadMode .CONVERSATION
432
432
433
- return @write createThreads (scope, upToDateFolder, messages, isConversationMode).also {
433
+ return @write handleAddedMessages (scope, upToDateFolder, messages, isConversationMode).also {
434
434
435
435
// TODO: This count will be false for INBOX & SNOOZED when the snooze feature will be implemented
436
436
val messagesCount = MessageController .getMessagesCountByFolderId(upToDateFolder.id, realm = this )
@@ -503,7 +503,7 @@ class RefreshController @Inject constructor(
503
503
// endregion
504
504
505
505
// region Create Threads
506
- private fun MutableRealm.createThreads (
506
+ private fun MutableRealm.handleAddedMessages (
507
507
scope : CoroutineScope ,
508
508
folder : Folder ,
509
509
remoteMessages : List <Message >,
@@ -521,7 +521,9 @@ class RefreshController @Inject constructor(
521
521
addedMessagesUids.add(remoteMessage.shortUid)
522
522
523
523
val newThread = if (isConversationMode) {
524
- createNewThread(scope, remoteMessage, impactedThreadsManaged)
524
+ val (thread, impactThreads) = handleAddedMessage(scope, remoteMessage)
525
+ impactedThreadsManaged + = impactThreads
526
+ thread
525
527
} else {
526
528
remoteMessage.toThread()
527
529
}
@@ -542,31 +544,6 @@ class RefreshController @Inject constructor(
542
544
return impactedThreadsUnmanaged
543
545
}
544
546
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
-
570
547
private fun initMessageLocalValues (remoteMessage : Message , folder : Folder ) {
571
548
remoteMessage.initLocalValues(
572
549
MessageInitialState (
@@ -580,27 +557,16 @@ class RefreshController @Inject constructor(
580
557
)
581
558
}
582
559
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 >> {
587
561
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)
589
565
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)
595
568
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
604
570
}
605
571
606
572
private fun TypedRealm.createNewThreadIfRequired (
@@ -621,33 +587,73 @@ class RefreshController @Inject constructor(
621
587
return newThread
622
588
}
623
589
624
- private fun MutableRealm.updateOtherExistingThreads (
590
+ private fun MutableRealm.updateExistingThreads (
625
591
scope : CoroutineScope ,
626
592
remoteMessage : Message ,
627
593
existingThreads : RealmResults <Thread >,
628
594
existingMessages : Set <Message >,
629
- impactedThreadsManaged : MutableSet <Thread >,
630
- ) {
631
- if (existingThreads.isEmpty()) return
595
+ ): Set <Thread > {
632
596
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 {
634
622
addAll(existingMessages)
635
623
add(remoteMessage)
636
624
}
637
625
638
- existingThreads.forEach { thread ->
639
- scope.ensureActive()
640
-
641
- allExistingMessages.forEach { existingMessage ->
626
+ return buildSet {
627
+ existingThreads.forEach { thread ->
642
628
scope.ensureActive()
643
629
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
+ }
647
637
}
638
+
639
+ add(thread)
648
640
}
641
+ }
642
+ }
643
+
644
+ private fun MutableRealm.identifyExtraDuplicatedThreads (messageIds : RealmSet <String >): Set <Thread > {
649
645
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
+ }
651
657
}
652
658
}
653
659
0 commit comments