fix(downloader): support logger-backed deleted media in chat download menu
Add a fallback for Message Logger deleted media when the normal attachment payload is unavailable, while keeping standard download behavior unchanged.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
## v1.1.0
|
## v1.1.0
|
||||||
|
- Fix: Download Context Menu now resolves Message Logger deleted media when available.
|
||||||
- Fix: message preview overlap in French.
|
- Fix: message preview overlap in French.
|
||||||
- Fix: transparent gallery media send override dialog.
|
- Fix: transparent gallery media send override dialog.
|
||||||
- Fix: message logger autopurge "Never" no longer resets to 3 days.
|
- Fix: message logger autopurge "Never" no longer resets to 3 days.
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ import me.eternal.purrfectsnap.core.features.MessagingRuleFeature
|
|||||||
import me.eternal.purrfectsnap.core.features.impl.downloader.decoder.DecodedAttachment
|
import me.eternal.purrfectsnap.core.features.impl.downloader.decoder.DecodedAttachment
|
||||||
import me.eternal.purrfectsnap.core.features.impl.downloader.decoder.MessageDecoder
|
import me.eternal.purrfectsnap.core.features.impl.downloader.decoder.MessageDecoder
|
||||||
import me.eternal.purrfectsnap.core.features.impl.messaging.Messaging
|
import me.eternal.purrfectsnap.core.features.impl.messaging.Messaging
|
||||||
|
import me.eternal.purrfectsnap.core.features.impl.spying.MessageLogger
|
||||||
import me.eternal.purrfectsnap.core.features.impl.ui.OperaStoryOverlay
|
import me.eternal.purrfectsnap.core.features.impl.ui.OperaStoryOverlay
|
||||||
import me.eternal.purrfectsnap.core.ui.PurrfectGlassCard
|
import me.eternal.purrfectsnap.core.ui.PurrfectGlassCard
|
||||||
import me.eternal.purrfectsnap.core.ui.PurrfectOverlayPalette
|
import me.eternal.purrfectsnap.core.ui.PurrfectOverlayPalette
|
||||||
@@ -511,30 +512,63 @@ class MediaDownloader : MessagingRuleFeature("MediaDownloader", MessagingRuleTyp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun resolveLoggedMessageAttachments(conversationId: String, clientMessageId: Long): List<DecodedAttachment> {
|
||||||
|
val messageLogger = context.feature(MessageLogger::class)
|
||||||
|
if (!messageLogger.isEnabled) return emptyList()
|
||||||
|
|
||||||
|
val loggedMessageObject = runCatching {
|
||||||
|
messageLogger.getMessageObject(conversationId, clientMessageId)
|
||||||
|
}.getOrNull() ?: return emptyList()
|
||||||
|
|
||||||
|
val loggedMessageContent = loggedMessageObject.getAsJsonObject("mMessageContent") ?: return emptyList()
|
||||||
|
return runCatching {
|
||||||
|
MessageDecoder.decode(loggedMessageContent)
|
||||||
|
}.getOrDefault(emptyList())
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun downloadMessageId(messageId: Long, forceAllowDuplicate: Boolean = false, isPreview: Boolean = false, forceDownloadFirst: Boolean = false) {
|
suspend fun downloadMessageId(messageId: Long, forceAllowDuplicate: Boolean = false, isPreview: Boolean = false, forceDownloadFirst: Boolean = false) {
|
||||||
val modCtx = this@MediaDownloader.context
|
val modCtx = this@MediaDownloader.context
|
||||||
val message = modCtx.database.getConversationMessageFromId(messageId) ?: throw Exception("Message not found")
|
val message = modCtx.database.getConversationMessageFromId(messageId) ?: throw Exception("Message not found")
|
||||||
val friendInfo = modCtx.database.getFriendInfo(message.senderId!!) ?: throw Exception("Friend not found")
|
val friendInfo = modCtx.database.getFriendInfo(message.senderId!!) ?: throw Exception("Friend not found")
|
||||||
val decodedAttachments = MessageDecoder.decode(ProtoReader(message.messageContent!!)).toMutableList()
|
val decodedAttachments = message.messageContent?.let { content ->
|
||||||
if (decodedAttachments.isEmpty()) { modCtx.shortToast(translations["no_attachments_toast"] ?: "No Attachments"); return }
|
MessageDecoder.decode(ProtoReader(content))
|
||||||
|
}?.toMutableList() ?: mutableListOf()
|
||||||
|
|
||||||
|
if (decodedAttachments.isEmpty()) {
|
||||||
|
val messageLogger = context.feature(MessageLogger::class)
|
||||||
|
message.clientConversationId?.let { conversationId ->
|
||||||
|
val isDeletedMessage = runCatching {
|
||||||
|
ContentType.fromId(message.contentType) == ContentType.STATUS ||
|
||||||
|
(messageLogger.isEnabled && messageLogger.isMessageDeleted(conversationId, messageId))
|
||||||
|
}.getOrDefault(false)
|
||||||
|
if (isDeletedMessage) {
|
||||||
|
decodedAttachments.addAll(resolveLoggedMessageAttachments(conversationId, messageId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val downloadableAttachments = decodedAttachments.filter {
|
||||||
|
it.boltKey != null || it.directUrl != null
|
||||||
|
}.toMutableList()
|
||||||
|
if (downloadableAttachments.isEmpty()) { modCtx.shortToast(translations["no_attachments_toast"] ?: "No Attachments"); return }
|
||||||
|
|
||||||
if (!isPreview) {
|
if (!isPreview) {
|
||||||
if (forceDownloadFirst || decodedAttachments.size == 1 || modCtx.isMainActivityPaused) {
|
if (forceDownloadFirst || downloadableAttachments.size == 1 || modCtx.isMainActivityPaused) {
|
||||||
downloadMessageAttachments(friendInfo, message, friendInfo.usernameForSorting!!, listOf(decodedAttachments.first()), forceAllowDuplicate)
|
downloadMessageAttachments(friendInfo, message, friendInfo.usernameForSorting!!, listOf(downloadableAttachments.first()), forceAllowDuplicate)
|
||||||
} else {
|
} else {
|
||||||
withContext(Dispatchers.Main) { showAttachmentSelectionDialog(friendInfo, message, decodedAttachments, forceAllowDuplicate) }
|
withContext(Dispatchers.Main) { showAttachmentSelectionDialog(friendInfo, message, downloadableAttachments, forceAllowDuplicate) }
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decodedAttachments.size == 1) { previewAttachment(decodedAttachments.first()); return }
|
if (downloadableAttachments.size == 1) { previewAttachment(downloadableAttachments.first()); return }
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
val mainActivity = modCtx.mainActivity ?: return@withContext
|
val mainActivity = modCtx.mainActivity ?: return@withContext
|
||||||
ViewAppearanceHelper.newAlertDialogBuilder(mainActivity).apply {
|
ViewAppearanceHelper.newAlertDialogBuilder(mainActivity).apply {
|
||||||
var selected = 0
|
var selected = 0
|
||||||
setSingleChoiceItems(decodedAttachments.mapIndexed { i, a -> "${i + 1}: ${translations["attachment_type.${a.type.key}"] ?: a.type.key}" }.toTypedArray(), 0) { _, w -> selected = w }
|
setSingleChoiceItems(downloadableAttachments.mapIndexed { i, a -> "${i + 1}: ${translations["attachment_type.${a.type.key}"] ?: a.type.key}" }.toTypedArray(), 0) { _, w -> selected = w }
|
||||||
setPositiveButton(modCtx.translation["chat_action_menu.preview_button"] ?: "Preview") { _, _ -> previewAttachment(decodedAttachments[selected]) }
|
setPositiveButton(modCtx.translation["chat_action_menu.preview_button"] ?: "Preview") { _, _ -> previewAttachment(downloadableAttachments[selected]) }
|
||||||
}.show()
|
}.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user