mirror of
https://github.com/oxen-io/session-android.git
synced 2025-01-11 16:33:39 +00:00
Fix excessive last sent calls
This commit is contained in:
parent
cf13caaee4
commit
4904524af5
@ -57,6 +57,7 @@ import org.signal.aesgcmprovider.AesGcmProvider;
|
||||
import org.thoughtcrime.securesms.components.TypingStatusSender;
|
||||
import org.thoughtcrime.securesms.crypto.KeyPairUtilities;
|
||||
import org.thoughtcrime.securesms.database.EmojiSearchDatabase;
|
||||
import org.thoughtcrime.securesms.database.LastSentTimestampCache;
|
||||
import org.thoughtcrime.securesms.database.LokiAPIDatabase;
|
||||
import org.thoughtcrime.securesms.database.Storage;
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
@ -149,6 +150,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
||||
@Inject TextSecurePreferences textSecurePreferences;
|
||||
@Inject PushRegistry pushRegistry;
|
||||
@Inject ConfigFactory configFactory;
|
||||
@Inject LastSentTimestampCache lastSentTimestampCache;
|
||||
CallMessageProcessor callMessageProcessor;
|
||||
MessagingModuleConfiguration messagingModuleConfiguration;
|
||||
|
||||
@ -218,7 +220,8 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
||||
device,
|
||||
messageDataProvider,
|
||||
()-> KeyPairUtilities.INSTANCE.getUserED25519KeyPair(this),
|
||||
configFactory
|
||||
configFactory,
|
||||
lastSentTimestampCache
|
||||
);
|
||||
callMessageProcessor = new CallMessageProcessor(this, textSecurePreferences, ProcessLifecycleOwner.get().getLifecycle(), storage);
|
||||
Log.i(TAG, "onCreate()");
|
||||
|
@ -5,6 +5,8 @@ import android.text.TextUtils
|
||||
import com.google.protobuf.ByteString
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.session.libsession.database.MessageDataProvider
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.messages.control.UnsendRequest
|
||||
import org.session.libsession.messaging.sending_receiving.attachments.Attachment
|
||||
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId
|
||||
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentState
|
||||
@ -185,9 +187,15 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
|
||||
val messagingDatabase: MessagingDatabase = if (isSms) DatabaseComponent.get(context).smsDatabase()
|
||||
else DatabaseComponent.get(context).mmsDatabase()
|
||||
|
||||
val (threadId, timestamp) = runCatching { messagingDatabase.getMessageRecord(messageID).run { threadId to timestamp } }.getOrNull() ?: (null to null)
|
||||
|
||||
messagingDatabase.deleteMessage(messageID)
|
||||
DatabaseComponent.get(context).lokiMessageDatabase().deleteMessage(messageID, isSms)
|
||||
DatabaseComponent.get(context).lokiMessageDatabase().deleteMessageServerHash(messageID, mms = !isSms)
|
||||
|
||||
threadId ?: return
|
||||
timestamp ?: return
|
||||
MessagingModuleConfiguration.shared.lastSentTimestampCache.delete(threadId, timestamp)
|
||||
}
|
||||
|
||||
override fun deleteMessages(messageIDs: List<Long>, threadId: Long, isSms: Boolean) {
|
||||
@ -195,12 +203,17 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
|
||||
val messagingDatabase: MessagingDatabase = if (isSms) DatabaseComponent.get(context).smsDatabase()
|
||||
else DatabaseComponent.get(context).mmsDatabase()
|
||||
|
||||
val messages = messageIDs.mapNotNull { runCatching { messagingDatabase.getMessageRecord(it) }.getOrNull() }
|
||||
|
||||
// Perform local delete
|
||||
messagingDatabase.deleteMessages(messageIDs.toLongArray(), threadId)
|
||||
|
||||
// Perform online delete
|
||||
DatabaseComponent.get(context).lokiMessageDatabase().deleteMessages(messageIDs)
|
||||
DatabaseComponent.get(context).lokiMessageDatabase().deleteMessageServerHashes(messageIDs, mms = !isSms)
|
||||
|
||||
val threadId = messages.firstOrNull()?.threadId
|
||||
threadId?.let{ MessagingModuleConfiguration.shared.lastSentTimestampCache.delete(it, messages.map { it.timestamp }) }
|
||||
}
|
||||
|
||||
override fun updateMessageAsDeleted(timestamp: Long, author: String): Long? {
|
||||
|
@ -332,11 +332,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
}
|
||||
},
|
||||
onAttachmentNeedsDownload = { attachmentId, mmsId ->
|
||||
|
||||
alreadyAttemptedAttachmentDownloads.takeUnless {
|
||||
attachmentId in alreadyAttemptedAttachmentDownloads
|
||||
}.let {
|
||||
alreadyAttemptedAttachmentDownloads += attachmentId
|
||||
attachmentId in it
|
||||
}?.let {
|
||||
it += attachmentId
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
JobQueue.shared.add(AttachmentDownloadJob(attachmentId, mmsId))
|
||||
}
|
||||
@ -387,8 +386,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
const val PICK_GIF = 10
|
||||
const val PICK_FROM_LIBRARY = 12
|
||||
const val INVITE_CONTACTS = 124
|
||||
|
||||
var lastSentMessageId = -1L;
|
||||
}
|
||||
// endregion
|
||||
|
||||
@ -515,9 +512,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
viewModel.run {
|
||||
binding?.toolbarContent?.update(recipient ?: return, openGroup, expirationConfiguration)
|
||||
}
|
||||
|
||||
// Update our last sent message Id on startup / resume (resume is called after onCreate)
|
||||
lastSentMessageId = mmsSmsDb.getLastOutgoingMessage(viewModel.threadId)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
@ -2226,11 +2220,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
// to the bottom of long messages as required by Jira SES-789 / GitHub 1364).
|
||||
recyclerView.scrollToPosition(adapter.itemCount)
|
||||
}
|
||||
|
||||
// Update our cached last sent message to ensure we have accurate details.
|
||||
// Note: This `onChanged` method is not triggered when scrolling so should minimally
|
||||
// affect performance.
|
||||
lastSentMessageId = mmsSmsDb.getLastOutgoingMessage(viewModel.threadId)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,12 +22,10 @@ import kotlinx.coroutines.launch
|
||||
import network.loki.messenger.R
|
||||
import network.loki.messenger.databinding.ViewVisibleMessageBinding
|
||||
import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.conversation.v2.messages.ControlMessageView
|
||||
import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView
|
||||
import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageViewDelegate
|
||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter
|
||||
import org.thoughtcrime.securesms.database.MmsSmsColumns
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
@ -207,19 +205,6 @@ class ConversationAdapter(
|
||||
return messageDB.readerFor(cursor).current
|
||||
}
|
||||
|
||||
private fun getLastSentMessageId(cursor: Cursor): Long {
|
||||
// If we don't move to first (or at least step backwards) we can step off the end of the
|
||||
// cursor and any query will return an "Index = -1" error.
|
||||
val cursorHasContent = cursor.moveToFirst()
|
||||
if (cursorHasContent) {
|
||||
val thisThreadId = cursor.getLong(4) // Column index 4 is "thread_id"
|
||||
if (thisThreadId != -1L) {
|
||||
return messageDB.getLastOutgoingMessage(thisThreadId)
|
||||
}
|
||||
}
|
||||
return -1L
|
||||
}
|
||||
|
||||
override fun changeCursor(cursor: Cursor?) {
|
||||
super.changeCursor(cursor)
|
||||
|
||||
|
@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.conversation.v2
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||
import org.thoughtcrime.securesms.util.AbstractCursorLoader
|
||||
|
||||
@ -12,6 +13,7 @@ class ConversationLoader(
|
||||
) : AbstractCursorLoader(context) {
|
||||
|
||||
override fun getCursor(): Cursor {
|
||||
MessagingModuleConfiguration.shared.lastSentTimestampCache.refresh(threadID)
|
||||
return DatabaseComponent.get(context).mmsSmsDatabase().getConversation(threadID, reverse)
|
||||
}
|
||||
}
|
@ -22,7 +22,6 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.marginBottom
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
@ -32,13 +31,12 @@ import org.session.libsession.messaging.contacts.Contact
|
||||
import org.session.libsession.messaging.contacts.Contact.ContactContext
|
||||
import org.session.libsession.messaging.open_groups.OpenGroupApi
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsession.utilities.ViewUtil
|
||||
import org.session.libsession.utilities.getColorFromAttr
|
||||
import org.session.libsession.utilities.modifyLayoutParams
|
||||
import org.session.libsignal.utilities.IdPrefix
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
|
||||
import org.thoughtcrime.securesms.database.LastSentTimestampCache
|
||||
import org.thoughtcrime.securesms.database.LokiAPIDatabase
|
||||
import org.thoughtcrime.securesms.database.LokiThreadDatabase
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase
|
||||
@ -73,6 +71,7 @@ class VisibleMessageView : LinearLayout {
|
||||
@Inject lateinit var mmsSmsDb: MmsSmsDatabase
|
||||
@Inject lateinit var smsDb: SmsDatabase
|
||||
@Inject lateinit var mmsDb: MmsDatabase
|
||||
@Inject lateinit var lastSentTimestampCache: LastSentTimestampCache
|
||||
|
||||
private val binding by lazy { ViewVisibleMessageBinding.bind(this) }
|
||||
private val swipeToReplyIcon = ContextCompat.getDrawable(context, R.drawable.ic_baseline_reply_24)!!.mutate()
|
||||
@ -302,9 +301,6 @@ class VisibleMessageView : LinearLayout {
|
||||
|
||||
// --- If we got here then we know the message is outgoing ---
|
||||
|
||||
val lastSentMessageId = ConversationActivityV2.lastSentMessageId;
|
||||
val isLastSentMessage = lastSentMessageId == message.id
|
||||
|
||||
// ----- Case ii.) Message is outgoing but NOT scheduled to disappear -----
|
||||
if (!scheduledToDisappear) {
|
||||
// If this isn't a disappearing message then we never show the timer
|
||||
@ -317,9 +313,11 @@ class VisibleMessageView : LinearLayout {
|
||||
} else {
|
||||
// ..but if the message HAS been successfully sent or read then only display the delivery status
|
||||
// text and image if this is the last sent message.
|
||||
binding.messageStatusTextView.isVisible = isLastSentMessage
|
||||
binding.messageStatusImageView.isVisible = isLastSentMessage
|
||||
if (isLastSentMessage) { binding.messageStatusImageView.bringToFront() }
|
||||
val lastSentTimestamp = lastSentTimestampCache.getTimestamp(message.threadId)
|
||||
val isLastSent = lastSentTimestamp == message.timestamp
|
||||
binding.messageStatusTextView.isVisible = isLastSent
|
||||
binding.messageStatusImageView.isVisible = isLastSent
|
||||
if (isLastSent) { binding.messageStatusImageView.bringToFront() }
|
||||
}
|
||||
}
|
||||
else // ----- Case iii.) Message is outgoing AND scheduled to disappear -----
|
||||
|
@ -0,0 +1,38 @@
|
||||
package org.thoughtcrime.securesms.database
|
||||
|
||||
import org.session.libsession.messaging.LastSentTimestampCache
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class LastSentTimestampCache @Inject constructor(
|
||||
val mmsSmsDatabase: MmsSmsDatabase
|
||||
): LastSentTimestampCache {
|
||||
|
||||
private val map = mutableMapOf<Long, Long>()
|
||||
|
||||
@Synchronized
|
||||
override fun getTimestamp(threadId: Long): Long? = map[threadId]
|
||||
|
||||
@Synchronized
|
||||
override fun submitTimestamp(threadId: Long, timestamp: Long) {
|
||||
if (map[threadId]?.let { timestamp <= it } == true) return
|
||||
|
||||
map[threadId] = timestamp
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun delete(threadId: Long, timestamps: List<Long>) {
|
||||
if (map[threadId]?.let { it !in timestamps } == true) return
|
||||
map.remove(threadId)
|
||||
refresh(threadId)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun refresh(threadId: Long) {
|
||||
if (map[threadId]?.let { it > 0 } == true) return
|
||||
val lastOutgoingTimestamp = mmsSmsDatabase.getLastOutgoingTimestamp(threadId)
|
||||
if (lastOutgoingTimestamp <= 0) return
|
||||
map[threadId] = lastOutgoingTimestamp
|
||||
}
|
||||
}
|
@ -295,7 +295,7 @@ public class MmsSmsDatabase extends Database {
|
||||
return identifiedMessages;
|
||||
}
|
||||
|
||||
public long getLastOutgoingMessage(long threadId) {
|
||||
public long getLastOutgoingTimestamp(long threadId) {
|
||||
String order = MmsSmsColumns.NORMALIZED_DATE_SENT + " DESC";
|
||||
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
|
||||
|
||||
@ -303,10 +303,13 @@ public class MmsSmsDatabase extends Database {
|
||||
try (Cursor cursor = queryTables(PROJECTION, selection, order, null)) {
|
||||
try (MmsSmsDatabase.Reader reader = readerFor(cursor)) {
|
||||
MessageRecord messageRecord;
|
||||
long attempts = 0;
|
||||
long maxAttempts = 20;
|
||||
while ((messageRecord = reader.getNext()) != null) {
|
||||
// Note: We rely on the message order to get us the most recent outgoing message - so we
|
||||
// take the first outgoing message we find as the last outgoing message.
|
||||
if (messageRecord.isOutgoing()) return messageRecord.id;
|
||||
if (messageRecord.isOutgoing()) return messageRecord.getTimestamp();
|
||||
if (attempts++ > maxAttempts) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
package org.session.libsession.messaging
|
||||
|
||||
interface LastSentTimestampCache {
|
||||
fun getTimestamp(threadId: Long): Long?
|
||||
fun submitTimestamp(threadId: Long, timestamp: Long)
|
||||
fun delete(threadId: Long, timestamps: List<Long>)
|
||||
fun delete(threadId: Long, timestamp: Long) = delete(threadId, listOf(timestamp))
|
||||
fun refresh(threadId: Long)
|
||||
}
|
@ -13,7 +13,8 @@ class MessagingModuleConfiguration(
|
||||
val device: Device,
|
||||
val messageDataProvider: MessageDataProvider,
|
||||
val getUserED25519KeyPair: () -> KeyPair?,
|
||||
val configFactory: ConfigFactoryProtocol
|
||||
val configFactory: ConfigFactoryProtocol,
|
||||
val lastSentTimestampCache: LastSentTimestampCache
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
@ -73,6 +73,7 @@ object MessageSender {
|
||||
|
||||
// Convenience
|
||||
fun send(message: Message, destination: Destination, isSyncMessage: Boolean): Promise<Unit, Exception> {
|
||||
if (message is VisibleMessage) MessagingModuleConfiguration.shared.lastSentTimestampCache.submitTimestamp(message.threadID!!, message.sentTimestamp!!)
|
||||
return if (destination is Destination.LegacyOpenGroup || destination is Destination.OpenGroup || destination is Destination.OpenGroupInbox) {
|
||||
sendToOpenGroupDestination(destination, message)
|
||||
} else {
|
||||
|
@ -290,6 +290,7 @@ fun MessageReceiver.handleVisibleMessage(
|
||||
): Long? {
|
||||
val storage = MessagingModuleConfiguration.shared.storage
|
||||
val context = MessagingModuleConfiguration.shared.context
|
||||
message.sentTimestamp?.let { MessagingModuleConfiguration.shared.lastSentTimestampCache.submitTimestamp(threadId, it) }
|
||||
val userPublicKey = storage.getUserPublicKey()
|
||||
val messageSender: String? = message.sender
|
||||
|
||||
@ -410,12 +411,7 @@ fun MessageReceiver.handleVisibleMessage(
|
||||
message.hasMention = listOf(userPublicKey, userBlindedKey)
|
||||
.filterNotNull()
|
||||
.any { key ->
|
||||
return@any (
|
||||
messageText != null &&
|
||||
messageText.contains("@$key")
|
||||
) || (
|
||||
(quoteModel?.author?.serialize() ?: "") == key
|
||||
)
|
||||
messageText?.contains("@$key") == true || key == (quoteModel?.author?.serialize() ?: "")
|
||||
}
|
||||
|
||||
// Persist the message
|
||||
|
Loading…
x
Reference in New Issue
Block a user