mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-17 07:23:21 +01:00
Add various updates to collapsed events.
This commit is contained in:
@@ -3,7 +3,9 @@ package org.thoughtcrime.securesms.database
|
||||
import androidx.core.content.contentValuesOf
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.mockk.every
|
||||
import io.mockk.mockkObject
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.unmockkObject
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
@@ -298,4 +300,24 @@ class CollapsingMessagesTests {
|
||||
assertEquals(CollapsedState.COLLAPSED, msgCall4.collapsedState)
|
||||
assertEquals(call3.messageId, msgCall4.collapsedHeadId)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun givenMaxCollapsedSet_whenIAddAnotherEvent_thenIExpectANewHead() {
|
||||
mockkObject(CollapsibleEvents)
|
||||
every { CollapsibleEvents.MAX_SIZE } returns 2
|
||||
|
||||
val messageId1 = message.insertCallLog(alice, MessageTypes.INCOMING_AUDIO_CALL_TYPE, 1000L, false).messageId
|
||||
val messageId2 = message.insertCallLog(alice, MessageTypes.INCOMING_AUDIO_CALL_TYPE, 2000L, false).messageId
|
||||
val messageId3 = message.insertCallLog(alice, MessageTypes.INCOMING_AUDIO_CALL_TYPE, 3000L, false).messageId
|
||||
|
||||
val msg1 = message.getMessageRecord(messageId1)
|
||||
val msg2 = message.getMessageRecord(messageId2)
|
||||
val msg3 = message.getMessageRecord(messageId3)
|
||||
|
||||
assertEquals(CollapsedState.HEAD_COLLAPSED, msg1.collapsedState)
|
||||
assertEquals(CollapsedState.PENDING_COLLAPSED, msg2.collapsedState)
|
||||
assertEquals(CollapsedState.HEAD_COLLAPSED, msg3.collapsedState)
|
||||
assertEquals(messageId3, msg3.collapsedHeadId)
|
||||
unmockkObject(CollapsibleEvents)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ class ConversationRepository(
|
||||
metadata.threadSize
|
||||
)
|
||||
val config = PagingConfig.Builder().setPageSize(25)
|
||||
.setBufferPages(2)
|
||||
.setBufferPages(3)
|
||||
.setStartIndex(max(metadata.getStartPosition(), 0))
|
||||
.build()
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras
|
||||
*/
|
||||
object CollapsibleEvents {
|
||||
|
||||
const val MAX_SIZE = 50
|
||||
|
||||
@JvmStatic
|
||||
fun isCollapsibleType(type: Long, messageExtras: MessageExtras?): Boolean {
|
||||
return getCollapsibleType(type, messageExtras) != null
|
||||
@@ -41,6 +43,18 @@ object CollapsibleEvents {
|
||||
return CollapsibleType.CHAT_UPDATE
|
||||
}
|
||||
|
||||
if (MessageTypes.isPinnedMessageUpdate(type)) {
|
||||
return CollapsibleType.CHAT_UPDATE
|
||||
}
|
||||
|
||||
if (MessageTypes.isPollTerminate(type)) {
|
||||
return CollapsibleType.CHAT_UPDATE
|
||||
}
|
||||
|
||||
if (MessageTypes.isChangeNumber(type)) {
|
||||
return CollapsibleType.CHAT_UPDATE
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -3631,12 +3631,29 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
.limit(1)
|
||||
.run()
|
||||
.readToSingleObject { cursor ->
|
||||
PotentialCollapsibleMessage(
|
||||
val message = PotentialCollapsibleMessage(
|
||||
type = cursor.requireLong(TYPE),
|
||||
dateReceived = cursor.requireLong(DATE_RECEIVED),
|
||||
collapsedHeadId = cursor.requireLong(COLLAPSED_HEAD_ID),
|
||||
messageExtras = cursor.requireBlob(MESSAGE_EXTRAS)?.let { MessageExtras.ADAPTER.decode(it) }
|
||||
)
|
||||
|
||||
val collapsedSize = if (message.collapsedHeadId != 0L) {
|
||||
readableDatabase
|
||||
.count()
|
||||
.from(TABLE_NAME)
|
||||
.where("$COLLAPSED_HEAD_ID = ?", message.collapsedHeadId)
|
||||
.run()
|
||||
.readToSingleInt()
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
|
||||
if (collapsedSize in 1..<CollapsibleEvents.MAX_SIZE) {
|
||||
message
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}?.takeIf { DateUtils.isSameDay(it.dateReceived, dateReceived) }
|
||||
}
|
||||
|
||||
|
||||
@@ -82,11 +82,11 @@ class BackfillCollapsedMessageJob private constructor(
|
||||
} else {
|
||||
val previous = lastMessageByThread[message.threadId]
|
||||
|
||||
val (collapsedState, headId) = if ((previous?.collapsibleType == collapsibleType) && DateUtils.isSameDay(previous.dateReceived, message.dateReceived)) {
|
||||
val (collapsedState, headId, size) = if ((previous?.collapsibleType == collapsibleType) && DateUtils.isSameDay(previous.dateReceived, message.dateReceived) && previous.collapsedSetSize < CollapsibleEvents.MAX_SIZE) {
|
||||
val state = if (message.read) CollapsedState.COLLAPSED.id else CollapsedState.PENDING_COLLAPSED.id
|
||||
Pair(state, previous.headId)
|
||||
Triple(state, previous.headId, previous.collapsedSetSize)
|
||||
} else {
|
||||
Pair(CollapsedState.HEAD_COLLAPSED.id, message.id)
|
||||
Triple(CollapsedState.HEAD_COLLAPSED.id, message.id, 0)
|
||||
}
|
||||
|
||||
db.update(MessageTable.TABLE_NAME)
|
||||
@@ -96,7 +96,7 @@ class BackfillCollapsedMessageJob private constructor(
|
||||
)
|
||||
.where("${MessageTable.ID} = ?", message.id)
|
||||
.run()
|
||||
lastMessageByThread[message.threadId] = LastMessage(collapsibleType, headId, message.dateReceived)
|
||||
lastMessageByThread[message.threadId] = LastMessage(collapsibleType, headId, message.dateReceived, size + 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,8 @@ class BackfillCollapsedMessageJob private constructor(
|
||||
private data class LastMessage(
|
||||
val collapsibleType: CollapsibleEvents.CollapsibleType?,
|
||||
val headId: Long,
|
||||
val dateReceived: Long
|
||||
val dateReceived: Long,
|
||||
val collapsedSetSize: Int
|
||||
)
|
||||
|
||||
class Factory : Job.Factory<BackfillCollapsedMessageJob> {
|
||||
|
||||
@@ -57,6 +57,7 @@ import org.thoughtcrime.securesms.migrations.AttributesMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.AvatarColorStorageServiceMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.AvatarIdRemovalMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.AvatarMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.BackfillCollapsedEventsMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.BackfillDigestsForDuplicatesMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.BackupJitterMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.BackupNotificationMigrationJob;
|
||||
@@ -313,6 +314,7 @@ public final class JobManagerFactories {
|
||||
put(AvatarColorStorageServiceMigrationJob.KEY, new AvatarColorStorageServiceMigrationJob.Factory());
|
||||
put(AvatarIdRemovalMigrationJob.KEY, new AvatarIdRemovalMigrationJob.Factory());
|
||||
put(AvatarMigrationJob.KEY, new AvatarMigrationJob.Factory());
|
||||
put(BackfillCollapsedEventsMigrationJob.KEY, new BackfillCollapsedEventsMigrationJob.Factory());
|
||||
put(BackfillDigestsForDuplicatesMigrationJob.KEY, new BackfillDigestsForDuplicatesMigrationJob.Factory());
|
||||
put(BackupJitterMigrationJob.KEY, new BackupJitterMigrationJob.Factory());
|
||||
put(BackupNotificationMigrationJob.KEY, new BackupNotificationMigrationJob.Factory());
|
||||
|
||||
@@ -196,9 +196,10 @@ public class ApplicationMigrations {
|
||||
static final int DELETED_BY_DB_MIGRATION = 152;
|
||||
static final int RELEASE_CHANNEL_RECIPIENT_FIX = 153;
|
||||
static final int EMOJI_VERSION_13 = 154;
|
||||
static final int COLLAPSED_EVENTS = 155;
|
||||
}
|
||||
|
||||
public static final int CURRENT_VERSION = 154;
|
||||
public static final int CURRENT_VERSION = 155;
|
||||
|
||||
/**
|
||||
* This *must* be called after the {@link JobManager} has been instantiated, but *before* the call
|
||||
@@ -909,6 +910,10 @@ public class ApplicationMigrations {
|
||||
jobs.put(Version.EMOJI_VERSION_13, new EmojiDownloadMigrationJob());
|
||||
}
|
||||
|
||||
if (lastSeenVersion < Version.COLLAPSED_EVENTS) {
|
||||
jobs.put(Version.COLLAPSED_EVENTS, new BackfillCollapsedEventsMigrationJob());
|
||||
}
|
||||
|
||||
return jobs;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.thoughtcrime.securesms.migrations
|
||||
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.jobmanager.Job
|
||||
import org.thoughtcrime.securesms.jobs.BackfillCollapsedMessageJob
|
||||
|
||||
/**
|
||||
* Schedules the [BackfillCollapsedMessageJob] to run.
|
||||
*/
|
||||
internal class BackfillCollapsedEventsMigrationJob private constructor(parameters: Parameters) : MigrationJob(parameters) {
|
||||
|
||||
companion object {
|
||||
const val KEY = "BackfillCollapsedEventsMigrationJob"
|
||||
}
|
||||
|
||||
internal constructor() : this(Parameters.Builder().build())
|
||||
|
||||
override fun isUiBlocking(): Boolean = false
|
||||
|
||||
override fun getFactoryKey(): String = KEY
|
||||
|
||||
override fun performMigration() {
|
||||
val jobManager = AppDependencies.jobManager
|
||||
jobManager.add(BackfillCollapsedMessageJob())
|
||||
}
|
||||
|
||||
override fun shouldRetry(e: Exception): Boolean = false
|
||||
|
||||
class Factory : Job.Factory<BackfillCollapsedEventsMigrationJob> {
|
||||
override fun create(parameters: Parameters, serializedData: ByteArray?): BackfillCollapsedEventsMigrationJob {
|
||||
return BackfillCollapsedEventsMigrationJob(parameters)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user