Skip to content

Commit 08cca9b

Browse files
committed
Added updating the thread details during swipe-to-refresh and other updates.| #74
1 parent efdfa89 commit 08cca9b

File tree

5 files changed

+105
-98
lines changed

5 files changed

+105
-98
lines changed

FlowCrypt/src/main/java/com/flowcrypt/email/api/email/gmail/GmailApiHelper.kt

Lines changed: 14 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,9 @@ import com.flowcrypt.email.database.entity.AccountEntity
2222
import com.flowcrypt.email.database.entity.AttachmentEntity
2323
import com.flowcrypt.email.database.entity.MessageEntity
2424
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.disposition
25-
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.extractSubject
2625
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.getAttachmentInfoList
27-
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.getDraftsCount
28-
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.getUniqueLabelsSet
29-
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.getUniqueRecipients
30-
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.hasAttachments
31-
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.hasPgp
32-
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.hasUnreadMessages
3326
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.isMimeType
27+
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.toThreadInfo
3428
import com.flowcrypt.email.extensions.java.lang.printStackTraceIfDebugOnly
3529
import com.flowcrypt.email.extensions.uid
3630
import com.flowcrypt.email.model.KeyImportDetails
@@ -419,8 +413,7 @@ class GmailApiHelper {
419413
responseHeaders: HttpHeaders?
420414
) {
421415
t?.let { thread ->
422-
val gmailThreadInfo = extractGmailThreadInfo(accountEntity, thread, context)
423-
listResult.add(gmailThreadInfo)
416+
listResult.add(thread.toThreadInfo(context, accountEntity))
424417
}
425418
}
426419

@@ -442,39 +435,26 @@ class GmailApiHelper {
442435
format: String = RESPONSE_FORMAT_FULL,
443436
metadataHeaders: List<String>? = null,
444437
fields: List<String>? = null
445-
): GmailThreadInfo = withContext(Dispatchers.IO)
438+
): GmailThreadInfo? = withContext(Dispatchers.IO)
446439
{
447-
val gmailApiService = generateGmailApiService(context, accountEntity)
448-
449-
val request = gmailApiService
450-
.users()
451-
.threads()
452-
.get(DEFAULT_USER_ID, threadId)
453-
.setFormat(format)
454-
455-
metadataHeaders?.let { metadataHeaders ->
456-
request.metadataHeaders = metadataHeaders
457-
}
458-
459-
fields?.let { fields ->
460-
request.fields = fields.joinToString(separator = ",")
461-
}
462-
463-
val thread = request.execute()
464-
val gmailThreadInfo = extractGmailThreadInfo(accountEntity, thread, context)
465-
466-
return@withContext gmailThreadInfo
440+
return@withContext getThread(
441+
context = context,
442+
accountEntity = accountEntity,
443+
threadId = threadId,
444+
format = format,
445+
metadataHeaders = metadataHeaders,
446+
fields = fields
447+
)?.toThreadInfo(context, accountEntity)
467448
}
468449

469-
suspend fun loadMessagesInThread(
450+
suspend fun getThread(
470451
context: Context,
471452
accountEntity: AccountEntity,
472453
threadId: String,
473454
format: String = RESPONSE_FORMAT_FULL,
474455
metadataHeaders: List<String>? = null,
475456
fields: List<String>? = null
476-
): List<Message> = withContext(Dispatchers.IO)
477-
{
457+
): Thread? = withContext(Dispatchers.IO) {
478458
val gmailApiService = generateGmailApiService(context, accountEntity)
479459

480460
val request = gmailApiService
@@ -491,7 +471,7 @@ class GmailApiHelper {
491471
request.fields = fields.joinToString(separator = ",")
492472
}
493473

494-
return@withContext request.execute()?.messages ?: emptyList()
474+
return@withContext request.execute()
495475
}
496476

497477
suspend fun loadMsgs(
@@ -1291,29 +1271,5 @@ class GmailApiHelper {
12911271
} ?: e
12921272
}
12931273
}
1294-
1295-
private fun extractGmailThreadInfo(
1296-
accountEntity: AccountEntity,
1297-
thread: Thread,
1298-
context: Context
1299-
): GmailThreadInfo {
1300-
val receiverEmail = accountEntity.email
1301-
val gmailThreadInfo = GmailThreadInfo(
1302-
id = thread.id,
1303-
lastMessage = requireNotNull(
1304-
thread.messages?.lastOrNull {
1305-
!it.labelIds.contains(LABEL_DRAFT)
1306-
} ?: thread.messages.first()),
1307-
messagesCount = thread.messages?.size ?: 0,
1308-
draftsCount = thread.getDraftsCount(),
1309-
recipients = thread.getUniqueRecipients(receiverEmail),
1310-
subject = thread.extractSubject(context, receiverEmail),
1311-
labels = thread.getUniqueLabelsSet(),
1312-
hasAttachments = thread.hasAttachments(),
1313-
hasPgpThings = thread.hasPgp(),
1314-
hasUnreadMessages = thread.hasUnreadMessages()
1315-
)
1316-
return gmailThreadInfo
1317-
}
13181274
}
13191275
}

FlowCrypt/src/main/java/com/flowcrypt/email/api/email/gmail/GmailHistoryHandler.kt

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import com.flowcrypt.email.api.email.gmail.GmailApiHelper.Companion.LABEL_TRASH
1313
import com.flowcrypt.email.api.email.gmail.GmailApiHelper.Companion.labelsToImapFlags
1414
import com.flowcrypt.email.api.email.gmail.api.GmaiAPIMimeMessage
1515
import com.flowcrypt.email.api.email.model.LocalFolder
16-
import com.flowcrypt.email.api.email.model.MessageFlag
1716
import com.flowcrypt.email.database.FlowCryptRoomDatabase
1817
import com.flowcrypt.email.database.entity.AccountEntity
1918
import com.flowcrypt.email.database.entity.MessageEntity
@@ -182,9 +181,7 @@ object GmailHistoryHandler {
182181
threadDraftsCount = thread.draftsCount,
183182
labelIds = thread.labels.joinToString(separator = LABEL_IDS_SEPARATOR),
184183
hasAttachments = thread.hasAttachments,
185-
fromAddresses = InternetAddress.toString(
186-
thread.recipients.toTypedArray()
187-
),
184+
fromAddresses = InternetAddress.toString(thread.recipients.toTypedArray()),
188185
hasPgp = thread.hasPgpThings
189186
)
190187
}
@@ -211,26 +208,7 @@ object GmailHistoryHandler {
211208
onlyPgpModeEnabled = accountEntity.showOnlyEncrypted ?: false
212209
) { message, messageEntity ->
213210
if (message.threadId == thread.id) {
214-
messageEntity.copy(
215-
id = threadMessageEntity.id,
216-
uid = threadMessageEntity.uid,
217-
subject = thread.subject,
218-
threadMessagesCount = thread.messagesCount,
219-
threadDraftsCount = thread.draftsCount,
220-
labelIds = thread.labels.joinToString(separator = LABEL_IDS_SEPARATOR),
221-
hasAttachments = thread.hasAttachments,
222-
fromAddresses = InternetAddress.toString(thread.recipients.toTypedArray()),
223-
hasPgp = thread.hasPgpThings,
224-
flags = if (thread.hasUnreadMessages) {
225-
threadMessageEntity.flags?.replace(MessageFlag.SEEN.value, "")
226-
} else {
227-
if (threadMessageEntity.flags?.contains(MessageFlag.SEEN.value) == true) {
228-
threadMessageEntity.flags
229-
} else {
230-
threadMessageEntity.flags.plus("${MessageFlag.SEEN.value} ")
231-
}
232-
}
233-
)
211+
messageEntity.toUpdatedThreadCopy(threadMessageEntity, thread)
234212
} else messageEntity
235213
}
236214
}

FlowCrypt/src/main/java/com/flowcrypt/email/database/entity/MessageEntity.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import com.flowcrypt.email.api.email.EmailUtil
3030
import com.flowcrypt.email.api.email.FoldersManager
3131
import com.flowcrypt.email.api.email.JavaEmailConstants
3232
import com.flowcrypt.email.api.email.gmail.api.GmaiAPIMimeMessage
33+
import com.flowcrypt.email.api.email.gmail.model.GmailThreadInfo
3334
import com.flowcrypt.email.api.email.model.MessageFlag
3435
import com.flowcrypt.email.api.email.model.OutgoingMessageInfo
3536
import com.flowcrypt.email.database.MessageState
@@ -460,6 +461,29 @@ data class MessageEntity(
460461
} else charSequence
461462
}
462463

464+
fun toUpdatedThreadCopy(messageEntity: MessageEntity, thread: GmailThreadInfo): MessageEntity {
465+
return copy(
466+
id = messageEntity.id,
467+
uid = messageEntity.uid,
468+
subject = thread.subject,
469+
threadMessagesCount = thread.messagesCount,
470+
threadDraftsCount = thread.draftsCount,
471+
labelIds = thread.labels.joinToString(separator = LABEL_IDS_SEPARATOR),
472+
hasAttachments = thread.hasAttachments,
473+
fromAddresses = InternetAddress.toString(thread.recipients.toTypedArray()),
474+
hasPgp = thread.hasPgpThings,
475+
flags = if (thread.hasUnreadMessages) {
476+
messageEntity.flags?.replace(MessageFlag.SEEN.value, "")
477+
} else {
478+
if (messageEntity.flags?.contains(MessageFlag.SEEN.value) == true) {
479+
messageEntity.flags
480+
} else {
481+
messageEntity.flags.plus("${MessageFlag.SEEN.value} ")
482+
}
483+
}
484+
)
485+
}
486+
463487
private fun prepareDateHeaderValue(context: Context): String {
464488
val dateInMilliseconds: Long =
465489
if (JavaEmailConstants.FOLDER_OUTBOX.equals(folder, ignoreCase = true)) {

FlowCrypt/src/main/java/com/flowcrypt/email/extensions/com/google/api/services/gmail/model/ThreadExt.kt

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ package com.flowcrypt.email.extensions.com.google.api.services.gmail.model
88
import android.content.Context
99
import com.flowcrypt.email.R
1010
import com.flowcrypt.email.api.email.gmail.GmailApiHelper
11+
import com.flowcrypt.email.api.email.gmail.GmailApiHelper.Companion.LABEL_DRAFT
12+
import com.flowcrypt.email.api.email.gmail.model.GmailThreadInfo
13+
import com.flowcrypt.email.database.entity.AccountEntity
1114
import com.flowcrypt.email.extensions.kotlin.asInternetAddresses
1215
import com.google.api.services.gmail.model.Thread
1316
import jakarta.mail.internet.InternetAddress
@@ -56,7 +59,7 @@ fun Thread.getUniqueLabelsSet(): Set<String> {
5659
}
5760

5861
fun Thread.getDraftsCount(): Int {
59-
return messages?.filter { it.labelIds.contains(GmailApiHelper.LABEL_DRAFT) }?.size ?: 0
62+
return messages?.filter { it.labelIds.contains(LABEL_DRAFT) }?.size ?: 0
6063
}
6164

6265
fun Thread.hasUnreadMessages(): Boolean {
@@ -90,4 +93,27 @@ fun Thread.extractSubject(context: Context, receiverEmail: String): String {
9093
}?.getSubject()
9194
?: messages?.getOrNull(0)?.getSubject()
9295
?: context.getString(R.string.no_subject)
96+
}
97+
98+
fun Thread.toThreadInfo(
99+
context: Context,
100+
accountEntity: AccountEntity
101+
): GmailThreadInfo {
102+
val receiverEmail = accountEntity.email
103+
val gmailThreadInfo = GmailThreadInfo(
104+
id = id,
105+
lastMessage = requireNotNull(
106+
messages?.lastOrNull {
107+
!it.labelIds.contains(LABEL_DRAFT)
108+
} ?: messages.first()),
109+
messagesCount = messages?.size ?: 0,
110+
draftsCount = getDraftsCount(),
111+
recipients = getUniqueRecipients(receiverEmail),
112+
subject = extractSubject(context, receiverEmail),
113+
labels = getUniqueLabelsSet(),
114+
hasAttachments = hasAttachments(),
115+
hasPgpThings = hasPgp(),
116+
hasUnreadMessages = hasUnreadMessages()
117+
)
118+
return gmailThreadInfo
93119
}

FlowCrypt/src/main/java/com/flowcrypt/email/jetpack/viewmodel/ThreadDetailsViewModel.kt

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.flowcrypt.email.api.email.FoldersManager
1111
import com.flowcrypt.email.api.email.JavaEmailConstants
1212
import com.flowcrypt.email.api.email.MsgsCacheManager
1313
import com.flowcrypt.email.api.email.gmail.GmailApiHelper
14+
import com.flowcrypt.email.api.email.gmail.model.GmailThreadInfo
1415
import com.flowcrypt.email.api.email.model.LocalFolder
1516
import com.flowcrypt.email.api.email.model.MessageFlag
1617
import com.flowcrypt.email.api.retrofit.response.base.Result
@@ -20,6 +21,7 @@ import com.flowcrypt.email.database.entity.MessageEntity
2021
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.getInReplyTo
2122
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.getMessageId
2223
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.isDraft
24+
import com.flowcrypt.email.extensions.com.google.api.services.gmail.model.toThreadInfo
2325
import com.flowcrypt.email.extensions.java.lang.printStackTraceIfDebugOnly
2426
import com.flowcrypt.email.model.MessageAction
2527
import com.flowcrypt.email.ui.adapter.MessagesInThreadListAdapter
@@ -369,15 +371,32 @@ class ThreadDetailsViewModel(
369371
if (threadMessageEntity.threadIdAsHEX.isNullOrEmpty() || !activeAccount.isGoogleSignInAccount) {
370372
return Result.success(Data(silentUpdate = silentUpdate, list = listOf()))
371373
} else {
372-
val threadHeader =
373-
prepareThreadHeader(roomDatabase.msgDao().getMsgById(threadMessageEntityId))
374-
375374
try {
376-
val messagesInThread = GmailApiHelper.loadMessagesInThread(
377-
getApplication(),
378-
activeAccount,
379-
threadMessageEntity.threadIdAsHEX
380-
).toMutableList().apply {
375+
val thread = GmailApiHelper.getThread(
376+
context = getApplication(),
377+
accountEntity = activeAccount,
378+
threadId = threadMessageEntity.threadIdAsHEX,
379+
format = GmailApiHelper.RESPONSE_FORMAT_FULL
380+
) ?: error("Thread not found")
381+
382+
val threadInfo = thread.toThreadInfo(getApplication(), activeAccount)
383+
//keep thread info updated in the local cache
384+
roomDatabase.msgDao().updateSuspend(
385+
MessageEntity.genMessageEntities(
386+
context = getApplication(),
387+
account = activeAccount.email,
388+
accountType = activeAccount.accountType,
389+
label = localFolder.fullName,
390+
msgsList = listOf(threadInfo.lastMessage),
391+
isNew = false,
392+
onlyPgpModeEnabled = activeAccount.showOnlyEncrypted ?: false
393+
) { message, messageEntity ->
394+
if (message.threadId == threadMessageEntity.threadIdAsHEX) {
395+
messageEntity.toUpdatedThreadCopy(threadMessageEntity, threadInfo)
396+
} else messageEntity
397+
})
398+
399+
val messagesInThread = (thread.messages ?: emptyList()).toMutableList().apply {
381400
//try to put drafts in the right position
382401
val drafts = filter { it.isDraft() }
383402
drafts.forEach { draft ->
@@ -406,10 +425,6 @@ class ThreadDetailsViewModel(
406425
).associateBy({ it.message.id }, { it.id })
407426
} else emptyMap()
408427

409-
//update the actual thread size
410-
roomDatabase.msgDao()
411-
.updateSuspend(threadMessageEntity.copy(threadMessagesCount = messagesInThread.size))
412-
413428
val isOnlyPgpModeEnabled = activeAccount.showOnlyEncrypted ?: false
414429
val messageEntitiesBasedOnServerResult = MessageEntity.genMessageEntities(
415430
context = getApplication(),
@@ -503,6 +518,11 @@ class ThreadDetailsViewModel(
503518
} ?: messageItemBasedOnDataFromServer
504519
}
505520

521+
val threadHeader = prepareThreadHeader(
522+
messageEntity = roomDatabase.msgDao().getMsgById(threadMessageEntityId),
523+
threadInfo = threadInfo
524+
)
525+
506526
return Result.success(
507527
Data(
508528
silentUpdate = silentUpdate,
@@ -516,7 +536,10 @@ class ThreadDetailsViewModel(
516536
}
517537
}
518538

519-
private suspend fun prepareThreadHeader(messageEntity: MessageEntity?): MessagesInThreadListAdapter.ThreadHeader =
539+
private suspend fun prepareThreadHeader(
540+
messageEntity: MessageEntity?,
541+
threadInfo: GmailThreadInfo? = null
542+
): MessagesInThreadListAdapter.ThreadHeader =
520543
withContext(Dispatchers.IO) {
521544
val account =
522545
getActiveAccountSuspend() ?: return@withContext MessagesInThreadListAdapter.ThreadHeader(
@@ -530,13 +553,13 @@ class ThreadDetailsViewModel(
530553

531554
return@withContext try {
532555
//try to get the last changes from a server
533-
val latestLabelIds = GmailApiHelper.loadThreadInfo(
556+
val latestLabelIds = (threadInfo ?: GmailApiHelper.loadThreadInfo(
534557
context = getApplication(),
535558
accountEntity = account,
536559
threadId = messageEntity?.threadIdAsHEX ?: "",
537560
fields = listOf("id", "messages/labelIds"),
538561
format = GmailApiHelper.RESPONSE_FORMAT_MINIMAL
539-
).labels
562+
))?.labels ?: error("Thread not found")
540563
if (cachedLabelIds == null
541564
|| !(latestLabelIds.containsAll(cachedLabelIds)
542565
&& cachedLabelIds.containsAll(latestLabelIds))

0 commit comments

Comments
 (0)