Skip to content

Commit a1c6b84

Browse files
refactor: Tidy up createNewThread() (#2228)
2 parents dcafc65 + 9eedc82 commit a1c6b84

File tree

2 files changed

+65
-67
lines changed

2 files changed

+65
-67
lines changed

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

+65-59
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,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

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

-8
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,6 @@ class ThreadController @Inject constructor(
200200
return realm.query("ANY ${Thread::messagesIds.name} IN $0", messageIds)
201201
}
202202

203-
private fun getExistingThreadsFoldersCountQuery(messageIds: Set<String>, realm: TypedRealm): RealmScalarQuery<Long> {
204-
return getThreadsByMessageIdsQuery(messageIds, realm).distinct(Thread::folderId.name).count()
205-
}
206-
207203
private fun getSearchThreadsQuery(realm: TypedRealm): RealmQuery<Thread> {
208204
return realm.query<Thread>("${Thread::isFromSearch.name} == true").sort(Thread::date.name, Sort.DESCENDING)
209205
}
@@ -266,10 +262,6 @@ class ThreadController @Inject constructor(
266262
return getThreadsByMessageIdsQuery(messageIds, realm).find()
267263
}
268264

269-
fun getExistingThreadsFoldersCount(messageIds: Set<String>, realm: TypedRealm): Long {
270-
return getExistingThreadsFoldersCountQuery(messageIds, realm).find()
271-
}
272-
273265
fun getUnreadThreadsCount(folder: Folder): Int {
274266
return getUnreadThreadsCountQuery(folder).find().toInt()
275267
}

0 commit comments

Comments
 (0)