mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-25 11:05:25 +00:00
fix: unreads work now for incoming messages, need to sync conv volatile properly still
This commit is contained in:
parent
1b580cca1b
commit
8c512c7b6e
@ -479,7 +479,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
|||||||
poller.setUserPublicKey(userPublicKey);
|
poller.setUserPublicKey(userPublicKey);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
poller = new Poller(configFactory);
|
poller = new Poller(configFactory, new Timer());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startPollingIfNeeded() {
|
public void startPollingIfNeeded() {
|
||||||
|
@ -128,8 +128,27 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
|
|||||||
|
|
||||||
override fun markConversationAsRead(threadId: Long, lastSeenTime: Long) {
|
override fun markConversationAsRead(threadId: Long, lastSeenTime: Long) {
|
||||||
val threadDb = DatabaseComponent.get(context).threadDatabase()
|
val threadDb = DatabaseComponent.get(context).threadDatabase()
|
||||||
getRecipientForThread(threadId)?.let {
|
getRecipientForThread(threadId)?.let { recipient ->
|
||||||
threadDb.markAllAsRead(threadId, it.isGroupRecipient, lastSeenTime)
|
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")
|
Log.d("Loki-DBG", "Should update thread $threadId")
|
||||||
if (threadId >= 0) {
|
if (threadId >= 0) {
|
||||||
DatabaseComponent.get(context).threadDatabase()
|
markConversationAsRead(threadId, conversation.lastRead)
|
||||||
.setLastSeen(threadId, conversation.lastRead)
|
updateThread(threadId, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,8 +64,6 @@ import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
|
|||||||
import org.thoughtcrime.securesms.util.SessionMetaProtocol;
|
import org.thoughtcrime.securesms.util.SessionMetaProtocol;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
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 HAS_SENT = "has_sent";
|
||||||
public static final String IS_PINNED = "is_pinned";
|
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 + " (" +
|
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" +
|
||||||
ID + " INTEGER PRIMARY KEY, " + DATE + " INTEGER DEFAULT 0, " +
|
ID + " INTEGER PRIMARY KEY, " + DATE + " INTEGER DEFAULT 0, " +
|
||||||
MESSAGE_COUNT + " INTEGER DEFAULT 0, " + ADDRESS + " TEXT, " + SNIPPET + " TEXT, " +
|
MESSAGE_COUNT + " INTEGER DEFAULT 0, " + ADDRESS + " TEXT, " + SNIPPET + " TEXT, " +
|
||||||
@ -522,9 +518,19 @@ public class ThreadDatabase extends Database {
|
|||||||
contentValues.put(LAST_SEEN, lastSeenTime);
|
contentValues.put(LAST_SEEN, lastSeenTime);
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {String.valueOf(threadId)});
|
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 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 reflectUpdates = "UPDATE "+TABLE_NAME+" AS t SET "+UNREAD_COUNT+" = ("+countSubQuery+") WHERE t."+ID+" = ?";
|
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";
|
||||||
db.query(reflectUpdates, new String[]{threadId+"", threadId+""});
|
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.setTransactionSuccessful();
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
notifyConversationListListeners();
|
notifyConversationListListeners();
|
||||||
|
@ -88,10 +88,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||||||
private static final int lokiV39 = 60;
|
private static final int lokiV39 = 60;
|
||||||
private static final int lokiV40 = 61;
|
private static final int lokiV40 = 61;
|
||||||
private static final int lokiV41 = 62;
|
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
|
// 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 int MIN_DATABASE_VERSION = lokiV7;
|
||||||
private static final String CIPHER3_DATABASE_NAME = "signal.db";
|
private static final String CIPHER3_DATABASE_NAME = "signal.db";
|
||||||
public static final String DATABASE_NAME = "signal_v4.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);
|
db.execSQL(ConfigDatabase.CREATE_CONFIG_TABLE_COMMAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldVersion < lokiV42) {
|
|
||||||
// db.execSQL(ThreadDatabase.getCreateLastSeenTrigger());
|
|
||||||
}
|
|
||||||
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
|
@ -107,14 +107,14 @@ class ConfigFactory(private val context: Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun persist(forConfigObject: ConfigBase) {
|
override fun persist(forConfigObject: ConfigBase) {
|
||||||
|
listeners.forEach { listener ->
|
||||||
|
listener.notifyUpdates(forConfigObject)
|
||||||
|
}
|
||||||
when (forConfigObject) {
|
when (forConfigObject) {
|
||||||
is UserProfile -> persistUserConfigDump()
|
is UserProfile -> persistUserConfigDump()
|
||||||
is Contacts -> persistContactsConfigDump()
|
is Contacts -> persistContactsConfigDump()
|
||||||
is ConversationVolatileConfig -> persistConvoVolatileConfigDump()
|
is ConversationVolatileConfig -> persistConvoVolatileConfigDump()
|
||||||
}
|
}
|
||||||
listeners.forEach { listener ->
|
|
||||||
listener.notifyUpdates(forConfigObject)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun appendHash(configObject: ConfigBase, hash: String) {
|
override fun appendHash(configObject: ConfigBase, hash: String) {
|
||||||
|
@ -176,7 +176,7 @@ class BatchMessageReceiveJob(
|
|||||||
}
|
}
|
||||||
// increment unreads, notify, and update thread
|
// 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)
|
// 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)
|
storage.updateThread(threadId, true)
|
||||||
SSKEnvironment.shared.notificationManager.updateNotification(context, threadId)
|
SSKEnvironment.shared.notificationManager.updateNotification(context, threadId)
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ data class ConfigurationSyncJob(val destination: Destination): Job {
|
|||||||
override var failureCount: Int = 0
|
override var failureCount: Int = 0
|
||||||
override val maxFailureCount: Int = 1
|
override val maxFailureCount: Int = 1
|
||||||
|
|
||||||
override suspend fun execute() {
|
override suspend fun execute(dispatcherName: String) {
|
||||||
val userEdKeyPair = MessagingModuleConfiguration.shared.getUserED25519KeyPair()
|
val userEdKeyPair = MessagingModuleConfiguration.shared.getUserED25519KeyPair()
|
||||||
val userPublicKey = MessagingModuleConfiguration.shared.storage.getUserPublicKey()
|
val userPublicKey = MessagingModuleConfiguration.shared.storage.getUserPublicKey()
|
||||||
val delegate = delegate
|
val delegate = delegate
|
||||||
@ -37,7 +37,7 @@ data class ConfigurationSyncJob(val destination: Destination): Job {
|
|||||||
|| (destination is Destination.Contact && destination.publicKey != userPublicKey)
|
|| (destination is Destination.Contact && destination.publicKey != userPublicKey)
|
||||||
) {
|
) {
|
||||||
Log.w(TAG, "No need to run config sync job, TODO")
|
Log.w(TAG, "No need to run config sync job, TODO")
|
||||||
delegate?.handleJobSucceeded(this)
|
delegate?.handleJobSucceeded(this, dispatcherName)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ data class ConfigurationSyncJob(val destination: Destination): Job {
|
|||||||
).filter { config -> config.needsPush() }
|
).filter { config -> config.needsPush() }
|
||||||
|
|
||||||
// don't run anything if we don't need to push anything
|
// 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
|
// allow null results here so the list index matches configsRequiringPush
|
||||||
val batchObjects: List<Pair<SharedConfigurationMessage, SnodeAPI.SnodeBatchRequestInfo>?> = configsRequiringPush.map { config ->
|
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 }) {
|
if (batchObjects.any { it == null }) {
|
||||||
// stop running here, something like a signing error occurred
|
// 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>()
|
val allRequests = mutableListOf<SnodeAPI.SnodeBatchRequestInfo>()
|
||||||
@ -145,9 +145,9 @@ data class ConfigurationSyncJob(val destination: Destination): Job {
|
|||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Error performing batch request", e)
|
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) {
|
fun Destination.destinationPublicKey(): String = when (this) {
|
||||||
|
@ -26,6 +26,7 @@ import org.session.libsession.snode.RawResponse
|
|||||||
import org.session.libsession.snode.SnodeAPI
|
import org.session.libsession.snode.SnodeAPI
|
||||||
import org.session.libsession.snode.SnodeModule
|
import org.session.libsession.snode.SnodeModule
|
||||||
import org.session.libsession.utilities.ConfigFactoryProtocol
|
import org.session.libsession.utilities.ConfigFactoryProtocol
|
||||||
|
import org.session.libsession.utilities.WindowDebouncer
|
||||||
import org.session.libsignal.utilities.Log
|
import org.session.libsignal.utilities.Log
|
||||||
import org.session.libsignal.utilities.Namespace
|
import org.session.libsignal.utilities.Namespace
|
||||||
import org.session.libsignal.utilities.Snode
|
import org.session.libsignal.utilities.Snode
|
||||||
@ -35,13 +36,15 @@ import java.util.TimerTask
|
|||||||
|
|
||||||
private class PromiseCanceledException : Exception("Promise canceled.")
|
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() ?: ""
|
var userPublicKey = MessagingModuleConfiguration.shared.storage.getUserPublicKey() ?: ""
|
||||||
private var hasStarted: Boolean = false
|
private var hasStarted: Boolean = false
|
||||||
private val usedSnodes: MutableSet<Snode> = mutableSetOf()
|
private val usedSnodes: MutableSet<Snode> = mutableSetOf()
|
||||||
var isCaughtUp = false
|
var isCaughtUp = false
|
||||||
var configPollingJob: Job? = null
|
var configPollingJob: Job? = null
|
||||||
|
|
||||||
|
val configDebouncer = WindowDebouncer(3000, debounceTimer)
|
||||||
|
|
||||||
// region Settings
|
// region Settings
|
||||||
companion object {
|
companion object {
|
||||||
private const val retryInterval: Long = 2 * 1000
|
private const val retryInterval: Long = 2 * 1000
|
||||||
@ -208,6 +211,7 @@ class Poller(private val configFactory: ConfigFactoryProtocol) {
|
|||||||
if (key == Namespace.DEFAULT) {
|
if (key == Namespace.DEFAULT) {
|
||||||
processPersonalMessages(snode, body)
|
processPersonalMessages(snode, body)
|
||||||
} else {
|
} else {
|
||||||
|
configDebouncer.publish {
|
||||||
when (ConfigBase.kindFor(key)) {
|
when (ConfigBase.kindFor(key)) {
|
||||||
UserProfile::class.java -> processConfig(snode, body, key, configFactory.user)
|
UserProfile::class.java -> processConfig(snode, body, key, configFactory.user)
|
||||||
Contacts::class.java -> processConfig(snode, body, key, configFactory.contacts)
|
Contacts::class.java -> processConfig(snode, body, key, configFactory.contacts)
|
||||||
@ -216,6 +220,7 @@ class Poller(private val configFactory: ConfigFactoryProtocol) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
poll(snode, deferred)
|
poll(snode, deferred)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user