fix: unreads work now for incoming messages, need to sync conv volatile properly still

This commit is contained in:
0x330a 2023-02-20 17:36:35 +11:00
parent 1b580cca1b
commit 8c512c7b6e
No known key found for this signature in database
GPG Key ID: 267811D6E6A2698C
8 changed files with 58 additions and 33 deletions

View File

@ -479,7 +479,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
poller.setUserPublicKey(userPublicKey);
return;
}
poller = new Poller(configFactory);
poller = new Poller(configFactory, new Timer());
}
public void startPollingIfNeeded() {

View File

@ -128,8 +128,27 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
override fun markConversationAsRead(threadId: Long, lastSeenTime: Long) {
val threadDb = DatabaseComponent.get(context).threadDatabase()
getRecipientForThread(threadId)?.let {
threadDb.markAllAsRead(threadId, it.isGroupRecipient, lastSeenTime)
getRecipientForThread(threadId)?.let { recipient ->
threadDb.markAllAsRead(threadId, recipient.isGroupRecipient, lastSeenTime)
configFactory.convoVolatile?.let { config ->
val convo = when {
// recipient closed group
recipient.isClosedGroupRecipient -> config.getOrConstructLegacyClosedGroup(recipient.address.serialize())
// recipient is open group
recipient.isOpenGroupRecipient -> {
val openGroupJoinUrl = getOpenGroup(threadId)?.joinURL ?: return
Conversation.OpenGroup.parseFullUrl(openGroupJoinUrl)?.let { (base, room, pubKey) ->
config.getOrConstructOpenGroup(base, room, pubKey)
} ?: return
}
// otherwise recipient is one to one
recipient.isContactRecipient -> config.getOrConstructOneToOne(recipient.address.serialize())
else -> throw NullPointerException("Weren't expecting to have a convo with address ${recipient.address.serialize()}")
}
convo.lastRead = lastSeenTime
config.set(convo)
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(context)
}
}
}
@ -346,8 +365,8 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
}
Log.d("Loki-DBG", "Should update thread $threadId")
if (threadId >= 0) {
DatabaseComponent.get(context).threadDatabase()
.setLastSeen(threadId, conversation.lastRead)
markConversationAsRead(threadId, conversation.lastRead)
updateThread(threadId, false)
}
}
}

View File

@ -64,8 +64,6 @@ import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
import org.thoughtcrime.securesms.util.SessionMetaProtocol;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@ -101,8 +99,6 @@ public class ThreadDatabase extends Database {
public static final String HAS_SENT = "has_sent";
public static final String IS_PINNED = "is_pinned";
public static final String LAST_SEEN_TRIGGER = "thread_last_seen_trigger";
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" +
ID + " INTEGER PRIMARY KEY, " + DATE + " INTEGER DEFAULT 0, " +
MESSAGE_COUNT + " INTEGER DEFAULT 0, " + ADDRESS + " TEXT, " + SNIPPET + " TEXT, " +
@ -522,9 +518,19 @@ public class ThreadDatabase extends Database {
contentValues.put(LAST_SEEN, lastSeenTime);
db.beginTransaction();
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {String.valueOf(threadId)});
String countSubQuery = "SELECT COUNT(*) FROM "+SmsDatabase.TABLE_NAME+" AS s INNER JOIN "+TABLE_NAME+" AS t ON s.thread_id = t._id WHERE t._id = ? AND s."+SmsDatabase.DATE_SENT+" > t."+LAST_SEEN+"";
String reflectUpdates = "UPDATE "+TABLE_NAME+" AS t SET "+UNREAD_COUNT+" = ("+countSubQuery+") WHERE t."+ID+" = ?";
db.query(reflectUpdates, new String[]{threadId+"", threadId+""});
String smsCountSubQuery = "SELECT COUNT(*) FROM "+SmsDatabase.TABLE_NAME+" AS s WHERE t."+ID+" = s."+SmsDatabase.THREAD_ID+" AND s."+SmsDatabase.DATE_SENT+" > t."+LAST_SEEN+" AND s."+SmsDatabase.READ+" = 0";
String smsMentionCountSubQuery = "SELECT COUNT(*) FROM "+SmsDatabase.TABLE_NAME+" AS s WHERE t."+ID+" = s."+SmsDatabase.THREAD_ID+" AND s."+SmsDatabase.DATE_SENT+" > t."+LAST_SEEN+" AND s."+SmsDatabase.READ+" = 0 AND s."+SmsDatabase.HAS_MENTION+" = 1";
String smsReactionCountSubQuery = "SELECT COUNT(*) FROM "+SmsDatabase.TABLE_NAME+" AS s WHERE t."+ID+" = s."+SmsDatabase.THREAD_ID+" AND s."+SmsDatabase.DATE_SENT+" > t."+LAST_SEEN+" AND s."+SmsDatabase.REACTIONS_UNREAD+" = 1";
String mmsCountSubQuery = "SELECT COUNT(*) FROM "+MmsDatabase.TABLE_NAME+" AS m WHERE t."+ID+" = m."+MmsDatabase.THREAD_ID+" AND m."+MmsDatabase.DATE_SENT+" > t."+LAST_SEEN+" AND m."+MmsDatabase.READ+" = 0";
String mmsMentionCountSubQuery = "SELECT COUNT(*) FROM "+MmsDatabase.TABLE_NAME+" AS m WHERE t."+ID+" = m."+MmsDatabase.THREAD_ID+" AND m."+MmsDatabase.DATE_SENT+" > t."+LAST_SEEN+" AND m."+MmsDatabase.READ+" = 0 AND m."+MmsDatabase.HAS_MENTION+" = 1";
String mmsReactionCountSubQuery = "SELECT COUNT(*) FROM "+MmsDatabase.TABLE_NAME+" AS m WHERE t."+ID+" = m."+MmsDatabase.THREAD_ID+" AND m."+MmsDatabase.DATE_SENT+" > t."+LAST_SEEN+" AND m."+MmsDatabase.REACTIONS_UNREAD+" = 1";
String allSmsUnread = "(("+smsCountSubQuery+") + ("+smsReactionCountSubQuery+"))";
String allMmsUnread = "(("+mmsCountSubQuery+") + ("+mmsReactionCountSubQuery+"))";
String allUnread = "(("+allSmsUnread+") + ("+allMmsUnread+"))";
String allUnreadMention = "(("+smsMentionCountSubQuery+") + ("+mmsMentionCountSubQuery+"))";
String reflectUpdates = "UPDATE "+TABLE_NAME+" AS t SET "+UNREAD_COUNT+" = "+allUnread+", "+UNREAD_MENTION_COUNT+" = "+allUnreadMention+" WHERE "+ID+" = ?";
db.execSQL(reflectUpdates, new Object[]{threadId});
db.setTransactionSuccessful();
db.endTransaction();
notifyConversationListListeners();

View File

@ -88,10 +88,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
private static final int lokiV39 = 60;
private static final int lokiV40 = 61;
private static final int lokiV41 = 62;
private static final int lokiV42 = 63;
// Loki - onUpgrade(...) must be updated to use Loki version numbers if Signal makes any database changes
private static final int DATABASE_VERSION = lokiV42;
private static final int DATABASE_VERSION = lokiV41;
private static final int MIN_DATABASE_VERSION = lokiV7;
private static final String CIPHER3_DATABASE_NAME = "signal.db";
public static final String DATABASE_NAME = "signal_v4.db";
@ -596,10 +595,6 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
db.execSQL(ConfigDatabase.CREATE_CONFIG_TABLE_COMMAND);
}
if (oldVersion < lokiV42) {
// db.execSQL(ThreadDatabase.getCreateLastSeenTrigger());
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();

View File

@ -107,14 +107,14 @@ class ConfigFactory(private val context: Context,
}
override fun persist(forConfigObject: ConfigBase) {
listeners.forEach { listener ->
listener.notifyUpdates(forConfigObject)
}
when (forConfigObject) {
is UserProfile -> persistUserConfigDump()
is Contacts -> persistContactsConfigDump()
is ConversationVolatileConfig -> persistConvoVolatileConfigDump()
}
listeners.forEach { listener ->
listener.notifyUpdates(forConfigObject)
}
}
override fun appendHash(configObject: ConfigBase, hash: String) {

View File

@ -176,7 +176,7 @@ class BatchMessageReceiveJob(
}
// increment unreads, notify, and update thread
// last seen will be the current last seen if not changed (re-computes the read counts for thread record)
storage.markConversationAsRead(threadId, 0)
storage.markConversationAsRead(threadId, myLastSeen)
storage.updateThread(threadId, true)
SSKEnvironment.shared.notificationManager.updateNotification(context, threadId)
}

View File

@ -20,7 +20,7 @@ data class ConfigurationSyncJob(val destination: Destination): Job {
override var failureCount: Int = 0
override val maxFailureCount: Int = 1
override suspend fun execute() {
override suspend fun execute(dispatcherName: String) {
val userEdKeyPair = MessagingModuleConfiguration.shared.getUserED25519KeyPair()
val userPublicKey = MessagingModuleConfiguration.shared.storage.getUserPublicKey()
val delegate = delegate
@ -37,7 +37,7 @@ data class ConfigurationSyncJob(val destination: Destination): Job {
|| (destination is Destination.Contact && destination.publicKey != userPublicKey)
) {
Log.w(TAG, "No need to run config sync job, TODO")
delegate?.handleJobSucceeded(this)
delegate?.handleJobSucceeded(this, dispatcherName)
return
}
@ -52,7 +52,7 @@ data class ConfigurationSyncJob(val destination: Destination): Job {
).filter { config -> config.needsPush() }
// don't run anything if we don't need to push anything
if (configsRequiringPush.isEmpty()) return delegate.handleJobSucceeded(this)
if (configsRequiringPush.isEmpty()) return delegate.handleJobSucceeded(this, dispatcherName)
// allow null results here so the list index matches configsRequiringPush
val batchObjects: List<Pair<SharedConfigurationMessage, SnodeAPI.SnodeBatchRequestInfo>?> = configsRequiringPush.map { config ->
@ -79,7 +79,7 @@ data class ConfigurationSyncJob(val destination: Destination): Job {
if (batchObjects.any { it == null }) {
// stop running here, something like a signing error occurred
return delegate.handleJobFailedPermanently(this, NullPointerException("One or more requests had a null batch request info"))
return delegate.handleJobFailedPermanently(this, dispatcherName, NullPointerException("One or more requests had a null batch request info"))
}
val allRequests = mutableListOf<SnodeAPI.SnodeBatchRequestInfo>()
@ -145,9 +145,9 @@ data class ConfigurationSyncJob(val destination: Destination): Job {
}
} catch (e: Exception) {
Log.e(TAG, "Error performing batch request", e)
return delegate.handleJobFailedPermanently(this, e)
return delegate.handleJobFailedPermanently(this, dispatcherName, e)
}
delegate.handleJobSucceeded(this)
delegate.handleJobSucceeded(this, dispatcherName)
}
fun Destination.destinationPublicKey(): String = when (this) {

View File

@ -26,6 +26,7 @@ import org.session.libsession.snode.RawResponse
import org.session.libsession.snode.SnodeAPI
import org.session.libsession.snode.SnodeModule
import org.session.libsession.utilities.ConfigFactoryProtocol
import org.session.libsession.utilities.WindowDebouncer
import org.session.libsignal.utilities.Log
import org.session.libsignal.utilities.Namespace
import org.session.libsignal.utilities.Snode
@ -35,13 +36,15 @@ import java.util.TimerTask
private class PromiseCanceledException : Exception("Promise canceled.")
class Poller(private val configFactory: ConfigFactoryProtocol) {
class Poller(private val configFactory: ConfigFactoryProtocol, debounceTimer: Timer) {
var userPublicKey = MessagingModuleConfiguration.shared.storage.getUserPublicKey() ?: ""
private var hasStarted: Boolean = false
private val usedSnodes: MutableSet<Snode> = mutableSetOf()
var isCaughtUp = false
var configPollingJob: Job? = null
val configDebouncer = WindowDebouncer(3000, debounceTimer)
// region Settings
companion object {
private const val retryInterval: Long = 2 * 1000
@ -208,6 +211,7 @@ class Poller(private val configFactory: ConfigFactoryProtocol) {
if (key == Namespace.DEFAULT) {
processPersonalMessages(snode, body)
} else {
configDebouncer.publish {
when (ConfigBase.kindFor(key)) {
UserProfile::class.java -> processConfig(snode, body, key, configFactory.user)
Contacts::class.java -> processConfig(snode, body, key, configFactory.contacts)
@ -216,6 +220,7 @@ class Poller(private val configFactory: ConfigFactoryProtocol) {
}
}
}
}
poll(snode, deferred)
}
}