mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 04: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);
|
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.setText(R.string.PinnedMessage__go_to_message);
|
||||||
actionButton.setVisibility(VISIBLE);
|
actionButton.setVisibility(VISIBLE);
|
||||||
actionButton.setOnClickListener(v -> {
|
actionButton.setOnClickListener(v -> {
|
||||||
// TODO(michelle): Handle when a message gets deleted
|
|
||||||
if (batchSelected.isEmpty() && eventListener != null && MessageRecordUtil.hasPinnedMessageUpdate(conversationMessage.getMessageRecord())) {
|
if (batchSelected.isEmpty() && eventListener != null && MessageRecordUtil.hasPinnedMessageUpdate(conversationMessage.getMessageRecord())) {
|
||||||
eventListener.onViewPinnedMessage(conversationMessage.getMessageRecord().getMessageExtras().pinnedMessage.pinnedMessageId);
|
eventListener.onViewPinnedMessage(conversationMessage.getMessageRecord().getMessageExtras().pinnedMessage.pinnedMessageId);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -682,6 +682,8 @@ public final class ConversationListItem extends ConstraintLayout implements Bind
|
|||||||
}
|
}
|
||||||
} else if (MessageTypes.isPollTerminate(thread.getType())) {
|
} else if (MessageTypes.isPollTerminate(thread.getType())) {
|
||||||
return emphasisAdded(context, thread.getBody(), Glyph.POLL, defaultTint);
|
return emphasisAdded(context, thread.getBody(), Glyph.POLL, defaultTint);
|
||||||
|
} else if (MessageTypes.isPinnedMessageUpdate(thread.getType())) {
|
||||||
|
return emphasisAdded(context, thread.getBody(), Glyph.PIN, defaultTint);
|
||||||
} else {
|
} else {
|
||||||
ThreadTable.Extra extra = thread.getExtra();
|
ThreadTable.Extra extra = thread.getExtra();
|
||||||
if (extra != null && extra.isViewOnce()) {
|
if (extra != null && extra.isViewOnce()) {
|
||||||
|
|||||||
@@ -2270,6 +2270,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
|||||||
disassociateStoryQuotes(messageId)
|
disassociateStoryQuotes(messageId)
|
||||||
polls.deletePoll(messageId)
|
polls.deletePoll(messageId)
|
||||||
disassociatePollFromPollTerminate(polls.getPollTerminateMessageId(messageId))
|
disassociatePollFromPollTerminate(polls.getPollTerminateMessageId(messageId))
|
||||||
|
disassociatePinnedMessage(messageId)
|
||||||
|
|
||||||
val threadId = getThreadIdForMessage(messageId)
|
val threadId = getThreadIdForMessage(messageId)
|
||||||
threads.update(threadId, false)
|
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_VERIFIED ||
|
||||||
retrieved.type == MessageType.IDENTITY_UPDATE
|
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(
|
val contentValues = contentValuesOf(
|
||||||
DATE_SENT to retrieved.sentTimeMillis,
|
DATE_SENT to retrieved.sentTimeMillis,
|
||||||
@@ -3669,6 +3670,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
|||||||
groupReceipts.deleteRowsForMessage(messageId)
|
groupReceipts.deleteRowsForMessage(messageId)
|
||||||
mentions.deleteMentionsForMessage(messageId)
|
mentions.deleteMentionsForMessage(messageId)
|
||||||
disassociatePollFromPollTerminate(polls.getPollTerminateMessageId(messageId))
|
disassociatePollFromPollTerminate(polls.getPollTerminateMessageId(messageId))
|
||||||
|
disassociatePinnedMessage(messageId)
|
||||||
|
|
||||||
writableDatabase
|
writableDatabase
|
||||||
.delete(TABLE_NAME)
|
.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? {
|
fun getSerializedSharedContacts(insertedAttachmentIds: Map<Attachment, AttachmentId>, contacts: List<Contact>): String? {
|
||||||
if (contacts.isEmpty()) {
|
if (contacts.isEmpty()) {
|
||||||
return null
|
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.BodyRangeList
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
|
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras
|
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.databaseprotos.PollTerminate
|
||||||
import org.thoughtcrime.securesms.database.model.toBodyRangeList
|
import org.thoughtcrime.securesms.database.model.toBodyRangeList
|
||||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||||
@@ -251,6 +252,11 @@ object SyncMessageProcessor {
|
|||||||
threadId = SignalDatabase.threads.getOrCreateThreadIdFor(getSyncMessageDestination(sent))
|
threadId = SignalDatabase.threads.getOrCreateThreadIdFor(getSyncMessageDestination(sent))
|
||||||
}
|
}
|
||||||
dataMessage.pollTerminate != null -> threadId = handleSynchronizedPollEnd(envelope, dataMessage, sent, senderRecipient, earlyMessageCacheEntry)
|
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!!)
|
else -> threadId = handleSynchronizeSentTextMessage(sent, envelope.timestamp!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1857,6 +1863,59 @@ object SyncMessageProcessor {
|
|||||||
return threadId
|
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? {
|
private fun ConversationIdentifier.toRecipientId(): RecipientId? {
|
||||||
val threadServiceId = ServiceId.parseOrNull(this.threadServiceId, this.threadServiceIdBinary)
|
val threadServiceId = ServiceId.parseOrNull(this.threadServiceId, this.threadServiceIdBinary)
|
||||||
return when {
|
return when {
|
||||||
|
|||||||
Reference in New Issue
Block a user