mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-20 02:58:45 +00:00
Add various fixes for pinned messages.
This commit is contained in:
committed by
jeffrey-signal
parent
864867f60e
commit
804f479cb0
@@ -685,11 +685,10 @@ public final class ConversationUpdateItem extends FrameLayout
|
||||
passthroughClickListener.onClick(v);
|
||||
}
|
||||
});
|
||||
} else if (MessageRecordUtil.hasPinnedMessageUpdate(conversationMessage.getMessageRecord())) {
|
||||
} else if (MessageRecordUtil.hasPinnedMessageUpdate(conversationMessage.getMessageRecord()) && conversationMessage.getMessageRecord().getMessageExtras().pinnedMessage.pinnedMessageId != -1) {
|
||||
actionButton.setText(R.string.PinnedMessage__go_to_message);
|
||||
actionButton.setVisibility(VISIBLE);
|
||||
actionButton.setOnClickListener(v -> {
|
||||
// TODO(michelle): Handle when a message gets deleted
|
||||
if (batchSelected.isEmpty() && eventListener != null && MessageRecordUtil.hasPinnedMessageUpdate(conversationMessage.getMessageRecord())) {
|
||||
eventListener.onViewPinnedMessage(conversationMessage.getMessageRecord().getMessageExtras().pinnedMessage.pinnedMessageId);
|
||||
} else {
|
||||
|
||||
@@ -682,6 +682,8 @@ public final class ConversationListItem extends ConstraintLayout implements Bind
|
||||
}
|
||||
} else if (MessageTypes.isPollTerminate(thread.getType())) {
|
||||
return emphasisAdded(context, thread.getBody(), Glyph.POLL, defaultTint);
|
||||
} else if (MessageTypes.isPinnedMessageUpdate(thread.getType())) {
|
||||
return emphasisAdded(context, thread.getBody(), Glyph.PIN, defaultTint);
|
||||
} else {
|
||||
ThreadTable.Extra extra = thread.getExtra();
|
||||
if (extra != null && extra.isViewOnce()) {
|
||||
|
||||
@@ -2270,6 +2270,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
disassociateStoryQuotes(messageId)
|
||||
polls.deletePoll(messageId)
|
||||
disassociatePollFromPollTerminate(polls.getPollTerminateMessageId(messageId))
|
||||
disassociatePinnedMessage(messageId)
|
||||
|
||||
val threadId = getThreadIdForMessage(messageId)
|
||||
threads.update(threadId, false)
|
||||
@@ -2820,7 +2821,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
retrieved.type == MessageType.IDENTITY_VERIFIED ||
|
||||
retrieved.type == MessageType.IDENTITY_UPDATE
|
||||
|
||||
val read = silent || retrieved.type == MessageType.EXPIRATION_UPDATE
|
||||
val read = silent || retrieved.type == MessageType.EXPIRATION_UPDATE || MessageTypes.isPinnedMessageUpdate(type)
|
||||
|
||||
val contentValues = contentValuesOf(
|
||||
DATE_SENT to retrieved.sentTimeMillis,
|
||||
@@ -3669,6 +3670,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
groupReceipts.deleteRowsForMessage(messageId)
|
||||
mentions.deleteMentionsForMessage(messageId)
|
||||
disassociatePollFromPollTerminate(polls.getPollTerminateMessageId(messageId))
|
||||
disassociatePinnedMessage(messageId)
|
||||
|
||||
writableDatabase
|
||||
.delete(TABLE_NAME)
|
||||
@@ -3764,6 +3766,62 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When a message gets deleted, clear the pinned record and remove any references
|
||||
*/
|
||||
fun disassociatePinnedMessage(messageId: Long) {
|
||||
if (messageId == -1L) {
|
||||
return
|
||||
}
|
||||
|
||||
writableDatabase.withinTransaction { db ->
|
||||
// Clear pinned message info
|
||||
val updated = db.update(TABLE_NAME)
|
||||
.values(
|
||||
PINNED_AT to 0,
|
||||
PINNED_UNTIL to 0
|
||||
)
|
||||
.where("$ID = ? AND $PINNED_UNTIL > 0", messageId)
|
||||
.run() > 0
|
||||
|
||||
if (!updated) {
|
||||
return@withinTransaction
|
||||
}
|
||||
|
||||
// Find the pinned message chat update
|
||||
val pinningMessageId = db
|
||||
.select(PINNING_MESSAGE_ID)
|
||||
.from(TABLE_NAME)
|
||||
.where("$ID = ?", messageId)
|
||||
.run()
|
||||
.readToSingleInt(-1)
|
||||
|
||||
if (pinningMessageId == -1) {
|
||||
return@withinTransaction
|
||||
}
|
||||
|
||||
// Disassociate chat update from pinned message
|
||||
val messageExtras = db
|
||||
.select(MESSAGE_EXTRAS)
|
||||
.from(TABLE_NAME)
|
||||
.where("$ID = ?", pinningMessageId)
|
||||
.run()
|
||||
.readToSingleObject { cursor ->
|
||||
val messageExtraBytes = cursor.requireBlob(MESSAGE_EXTRAS)
|
||||
messageExtraBytes?.let { MessageExtras.ADAPTER.decode(it) }
|
||||
}
|
||||
|
||||
if (messageExtras?.pinnedMessage != null) {
|
||||
val updatedMessageExtras = messageExtras.newBuilder().pinnedMessage(pinnedMessage = messageExtras.pinnedMessage.copy(pinnedMessageId = -1)).build()
|
||||
db
|
||||
.update(TABLE_NAME)
|
||||
.values(MESSAGE_EXTRAS to updatedMessageExtras.encode())
|
||||
.where("$ID = ?", pinningMessageId)
|
||||
.run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getSerializedSharedContacts(insertedAttachmentIds: Map<Attachment, AttachmentId>, contacts: List<Contact>): String? {
|
||||
if (contacts.isEmpty()) {
|
||||
return null
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.thoughtcrime.securesms.database.model.StoryType
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.PinnedMessage
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.PollTerminate
|
||||
import org.thoughtcrime.securesms.database.model.toBodyRangeList
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
@@ -251,6 +252,11 @@ object SyncMessageProcessor {
|
||||
threadId = SignalDatabase.threads.getOrCreateThreadIdFor(getSyncMessageDestination(sent))
|
||||
}
|
||||
dataMessage.pollTerminate != null -> threadId = handleSynchronizedPollEnd(envelope, dataMessage, sent, senderRecipient, earlyMessageCacheEntry)
|
||||
dataMessage.pinMessage != null -> threadId = handleSynchronizedPinMessage(envelope, dataMessage, sent, senderRecipient, earlyMessageCacheEntry)
|
||||
dataMessage.unpinMessage != null -> {
|
||||
DataMessageProcessor.handleUnpinMessage(envelope, dataMessage, senderRecipient, threadRecipient, earlyMessageCacheEntry)
|
||||
threadId = SignalDatabase.threads.getOrCreateThreadIdFor(getSyncMessageDestination(sent))
|
||||
}
|
||||
else -> threadId = handleSynchronizeSentTextMessage(sent, envelope.timestamp!!)
|
||||
}
|
||||
|
||||
@@ -1857,6 +1863,59 @@ object SyncMessageProcessor {
|
||||
return threadId
|
||||
}
|
||||
|
||||
private fun handleSynchronizedPinMessage(
|
||||
envelope: Envelope,
|
||||
message: DataMessage,
|
||||
sent: Sent,
|
||||
senderRecipient: Recipient,
|
||||
earlyMessageCacheEntry: EarlyMessageCacheEntry?
|
||||
): Long {
|
||||
if (!RemoteConfig.receivePinnedMessages) {
|
||||
log(envelope.timestamp!!, "Sync pinned messages not allowed due to remote config.")
|
||||
}
|
||||
|
||||
log(envelope.timestamp!!, "Synchronize pinned message")
|
||||
|
||||
val recipient = getSyncMessageDestination(sent)
|
||||
val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)
|
||||
|
||||
val expiresInMillis = message.expireTimerDuration.inWholeMilliseconds
|
||||
if (recipient.expiresInSeconds != message.expireTimerDuration.inWholeSeconds.toInt() || ((message.expireTimerVersion ?: -1) > recipient.expireTimerVersion)) {
|
||||
handleSynchronizeSentExpirationUpdate(sent, sideEffect = true)
|
||||
}
|
||||
|
||||
val pinMessage = message.pinMessage!!
|
||||
val targetMessage = SignalDatabase.messages.getMessageFor(pinMessage.targetSentTimestamp!!, Recipient.self().id)
|
||||
if (targetMessage == null) {
|
||||
warn(envelope.timestamp!!, "Unable to find target message for sync message. Putting in early message cache.")
|
||||
if (earlyMessageCacheEntry != null) {
|
||||
AppDependencies.earlyMessageCache.store(senderRecipient.id, pinMessage.targetSentTimestamp!!, earlyMessageCacheEntry)
|
||||
PushProcessEarlyMessagesJob.enqueue()
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
val duration = if (pinMessage.pinDurationForever == true) MessageTable.PIN_FOREVER else pinMessage.pinDurationSeconds!!.toLong()
|
||||
val outgoingMessage = OutgoingMessage.pinMessage(
|
||||
threadRecipient = recipient,
|
||||
sentTimeMillis = sent.timestamp!!,
|
||||
expiresIn = recipient.expiresInSeconds.seconds.inWholeMilliseconds,
|
||||
messageExtras = MessageExtras(pinnedMessage = PinnedMessage(pinnedMessageId = targetMessage.id, targetAuthorAci = pinMessage.targetAuthorAciBinary!!, targetTimestamp = pinMessage.targetSentTimestamp!!, pinDurationInSeconds = duration))
|
||||
)
|
||||
|
||||
val messageId = SignalDatabase.messages.insertMessageOutbox(outgoingMessage, threadId, false, GroupReceiptTable.STATUS_UNKNOWN, null).messageId
|
||||
SignalDatabase.messages.markAsSent(messageId, true)
|
||||
|
||||
log(envelope.timestamp!!, "Inserted sync pin message as messageId $messageId")
|
||||
|
||||
if (expiresInMillis > 0) {
|
||||
SignalDatabase.messages.markExpireStarted(messageId, sent.expirationStartTimestamp ?: 0)
|
||||
AppDependencies.expiringMessageManager.scheduleDeletion(messageId, recipient.isGroup, sent.expirationStartTimestamp ?: 0, expiresInMillis)
|
||||
}
|
||||
|
||||
return threadId
|
||||
}
|
||||
|
||||
private fun ConversationIdentifier.toRecipientId(): RecipientId? {
|
||||
val threadServiceId = ServiceId.parseOrNull(this.threadServiceId, this.threadServiceIdBinary)
|
||||
return when {
|
||||
|
||||
Reference in New Issue
Block a user