realm-kotlin : make app compile!

This commit is contained in:
ganfra 2022-10-14 12:02:25 +02:00
parent 6379c199ea
commit 3aba7803dd
97 changed files with 202 additions and 2046 deletions

View File

@ -34,7 +34,7 @@ signing.element.keyId=Secret
signing.element.keyPassword=Secret
# This belongs here as it's the only way to share the version number between the plugin and the library.
realmKotlinVersion = 1.0.1
realmKotlinVersion = 1.2.0
# Dummy values for signing secrets / nightly
signing.element.nightly.storePassword=Secret

View File

@ -1,14 +1,3 @@
buildscript {
repositories {
// Do not use `mavenCentral()`, it prevents Dependabot from working properly
maven {
url 'https://repo1.maven.org/maven2'
}
}
dependencies {
classpath "io.realm:realm-gradle-plugin:10.11.1"
}
}
plugins {
id("io.realm.kotlin") version "${realmKotlinVersion}"
@ -18,7 +7,6 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-parcelize'
apply plugin: 'realm-android'
apply plugin: "org.jetbrains.dokka"
if (project.hasProperty("coverage")) {
@ -154,6 +142,9 @@ dependencies {
implementation libs.androidx.lifecycleProcess
implementation libs.androidx.lifecycleLivedata
// Paging
implementation libs.androidx.pagingRuntimeKtx
// Network
implementation libs.squareup.retrofit
implementation libs.squareup.retrofitMoshi
@ -176,9 +167,7 @@ dependencies {
implementation libs.androidx.exifinterface
// Database
implementation 'com.github.Zhuinden:realm-monarchy:0.7.1'
implementation libs.realm.base
kapt 'dk.ilios:realmfieldnameshelper:2.0.0'
// Shared Preferences

View File

@ -23,7 +23,6 @@ import androidx.lifecycle.ProcessLifecycleOwner
import androidx.work.Configuration
import androidx.work.WorkManager
import androidx.work.WorkerFactory
import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.auth.HomeServerHistoryService
@ -73,7 +72,6 @@ class Matrix(context: Context, matrixConfiguration: MatrixConfiguration) {
init {
val appContext = context.applicationContext
Monarchy.init(appContext)
DaggerMatrixComponent.factory().create(appContext, matrixConfiguration).inject(this)
if (appContext !is Configuration.Provider) {
val configuration = Configuration.Builder()

View File

@ -54,7 +54,6 @@ data class TimelineEvent(
*/
val localId: Long,
val eventId: String,
var chunkId: ObjectId? = null,
/**
* This display index is the position in the current chunk.
* It's not unique on the timeline as it's reset on each chunk.

View File

@ -17,56 +17,11 @@
package org.matrix.android.sdk.internal.crypto.store.db
import android.util.Base64
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.RealmModel
import java.io.ByteArrayOutputStream
import java.io.ObjectOutputStream
import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream
/**
* Get realm, invoke the action, close realm, and return the result of the action.
*/
internal fun <T> doWithRealm(realmConfiguration: RealmConfiguration, action: (Realm) -> T): T {
return Realm.getInstance(realmConfiguration).use { realm ->
action.invoke(realm)
}
}
/**
* Get realm, do the query, copy from realm, close realm, and return the copied result.
*/
internal fun <T : RealmModel> doRealmQueryAndCopy(realmConfiguration: RealmConfiguration, action: (Realm) -> T?): T? {
return Realm.getInstance(realmConfiguration).use { realm ->
action.invoke(realm)?.let { realm.copyFromRealm(it) }
}
}
/**
* Get realm, do the list query, copy from realm, close realm, and return the copied result.
*/
internal fun <T : RealmModel> doRealmQueryAndCopyList(realmConfiguration: RealmConfiguration, action: (Realm) -> Iterable<T>): Iterable<T> {
return Realm.getInstance(realmConfiguration).use { realm ->
action.invoke(realm).let { realm.copyFromRealm(it) }
}
}
/**
* Get realm instance, invoke the action in a transaction and close realm.
*/
internal fun doRealmTransaction(realmConfiguration: RealmConfiguration, action: (Realm) -> Unit) {
Realm.getInstance(realmConfiguration).use { realm ->
realm.executeTransaction { action.invoke(it) }
}
}
internal fun doRealmTransactionAsync(realmConfiguration: RealmConfiguration, action: (Realm) -> Unit) {
Realm.getInstance(realmConfiguration).use { realm ->
realm.executeTransactionAsync { action.invoke(it) }
}
}
/**
* Serialize any Serializable object, zip it and convert to Base64 String.
*/

View File

@ -1,61 +0,0 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database
import com.zhuinden.monarchy.Monarchy
import io.realm.Realm
import io.realm.RealmConfiguration
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
import kotlin.system.measureTimeMillis
internal fun <T> CoroutineScope.asyncTransaction(monarchy: Monarchy, transaction: suspend (realm: Realm) -> T) {
asyncTransaction(monarchy.realmConfiguration, transaction)
}
internal fun <T> CoroutineScope.asyncTransaction(realmConfiguration: RealmConfiguration, transaction: suspend (realm: Realm) -> T) {
launch {
awaitTransaction(realmConfiguration, transaction)
}
}
internal suspend fun <T> awaitTransaction(config: RealmConfiguration, transaction: suspend (realm: Realm) -> T): T {
return withContext(Realm.WRITE_EXECUTOR.asCoroutineDispatcher()) {
Realm.getInstance(config).use { bgRealm ->
bgRealm.beginTransaction()
val result: T
try {
measureTimeMillis {
result = transaction(bgRealm)
if (isActive) {
bgRealm.commitTransaction()
}
}.also {
Timber.v("Execute transaction in $it millis")
}
} finally {
if (bgRealm.isInTransaction) {
bgRealm.cancelTransaction()
}
}
result
}
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database
import io.realm.DefaultCompactOnLaunchCallback
class RealmCompactOnLaunch : DefaultCompactOnLaunchCallback() {
/**
* Forces all RealmCompactOnLaunch instances to be equal.
* Avoids Realm throwing when multiple instances of this class are used.
*/
override fun equals(other: Any?) = other is RealmCompactOnLaunch
override fun hashCode() = 0x1000
}

View File

@ -3,6 +3,7 @@ package org.matrix.android.sdk.internal.database
import androidx.lifecycle.asFlow
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
import androidx.paging.PagedList.BoundaryCallback
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.Realm
import io.realm.kotlin.RealmConfiguration
@ -19,6 +20,7 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapConcat
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
@ -99,18 +101,35 @@ internal class RealmInstance(
fun <T : RealmObject, R> queryPagedList(
config: PagedList.Config,
mapper: RealmObjectMapper<T, R>,
boundaryCallback: BoundaryCallback<R>? = null,
queryBuilder: RealmQueryBuilder<T>,
): Flow<PagedList<R>> {
return queryUpdatablePagedList(
config = config,
mapper = mapper,
boundaryCallback = boundaryCallback,
liveQueryBuilder = flowOf(queryBuilder)
)
}
fun <T : RealmObject, R> queryUpdatablePagedList(
config: PagedList.Config,
mapper: RealmObjectMapper<T, R>,
boundaryCallback: BoundaryCallback<R>? = null,
liveQueryBuilder: Flow<RealmQueryBuilder<T>>,
): Flow<PagedList<R>> {
return getRealmFlow().flatMapConcat { realm ->
val livePagedList = LivePagedListBuilder(
RealmTiledDataSource.Factory(
realm = realm,
queryBuilder = queryBuilder,
liveQueryBuilder = liveQueryBuilder,
mapper = mapper,
coroutineScope = coroutineScope
),
config
).build()
).apply {
setBoundaryCallback(boundaryCallback)
}.build()
livePagedList.asFlow()
}
}

View File

@ -1,35 +0,0 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database
import io.realm.Realm
import java.io.Closeable
internal class RealmInstanceWrapper(private val realm: Realm, private val closeRealmOnClose: Boolean) : Closeable {
override fun close() {
if (closeRealmOnClose) {
realm.close()
}
}
fun <R> withRealm(block: (Realm) -> R): R {
return use {
block(it.realm)
}
}
}

View File

@ -18,8 +18,7 @@ package org.matrix.android.sdk.internal.database
import android.content.Context
import android.util.Base64
import androidx.core.content.edit
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.kotlin.Realm
import org.matrix.android.sdk.BuildConfig
import org.matrix.android.sdk.api.securestorage.SecretStoringUtils
import timber.log.Timber
@ -89,12 +88,6 @@ internal class RealmKeysUtils @Inject constructor(
return Base64.decode(b64, Base64.NO_PADDING)
}
fun configureEncryption(realmConfigurationBuilder: RealmConfiguration.Builder, alias: String) {
val key = getRealmEncryptionKey(alias)
realmConfigurationBuilder.encryptionKey(key)
}
fun configureEncryption(realmConfigurationBuilder: io.realm.kotlin.RealmConfiguration.Builder, alias: String) {
val key = getRealmEncryptionKey(alias)
realmConfigurationBuilder.encryptionKey(key)

View File

@ -302,7 +302,7 @@ internal fun updateNotificationsNew(roomId: String, realm: MutableRealm, current
val readReceiptChunkTimelineEvents = TimelineEventEntity.whereChunkId(realm, chunkId = readReceiptChunk.chunkId)
.sort("displayIndex", Sort.ASCENDING)
.find() ?: return
.find()
val readReceiptChunkPosition = readReceiptChunkTimelineEvents.indexOfFirst { it.eventId == readReceipt }

View File

@ -40,7 +40,6 @@ import org.matrix.android.sdk.internal.database.model.RoomEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
import org.matrix.android.sdk.internal.database.model.cleanUp
import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntity
import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntityFields
import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore
import org.matrix.android.sdk.internal.database.query.getOrCreate
import org.matrix.android.sdk.internal.database.query.getOrNull
@ -202,7 +201,7 @@ internal fun ThreadSummaryEntity.Companion.createOrUpdate(
} else {
// ThreadSummary do not exists lets try to create one
Timber.i("###THREADS ThreadSummaryHelper ADD root eventId:$rootThreadEventId do not exists, lets try to create one")
threadEventEntity.findRootThreadEvent()?.let { rootThreadEventEntity ->
threadEventEntity.findRootThreadEvent(realm)?.let { rootThreadEventEntity ->
// Root thread event entity exists so lets create a new record
ThreadSummaryEntity.getOrCreate(realm, roomId, rootThreadEventEntity.eventId).let {
it.updateThreadSummary(
@ -316,7 +315,7 @@ private fun getLatestEvent(rootThreadEvent: Event): Event? {
internal fun ThreadSummaryEntity.Companion.findAllThreadsForRoomId(realm: TypedRealm, roomId: String): RealmQuery<ThreadSummaryEntity> =
ThreadSummaryEntity
.where(realm, roomId = roomId)
.sort(ThreadSummaryEntityFields.LATEST_THREAD_EVENT_ENTITY.ORIGIN_SERVER_TS, Sort.DESCENDING)
.sort("latestThreadEventEntity.originServerTs", Sort.DESCENDING)
/**
* Enhance each [ThreadSummary] root and latest event with the equivalent decrypted text edition/replacement.

View File

@ -19,14 +19,12 @@ package org.matrix.android.sdk.internal.database.mapper
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.livelocation.LiveLocationShareAggregatedSummary
import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocationDataContent
import org.matrix.android.sdk.internal.database.RealmObjectMapper
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
import javax.inject.Inject
internal class LiveLocationShareAggregatedSummaryMapper @Inject constructor() :
RealmObjectMapper<LiveLocationShareAggregatedSummaryEntity, LiveLocationShareAggregatedSummary> {
internal class LiveLocationShareAggregatedSummaryMapper @Inject constructor() {
override fun map(realmObject: LiveLocationShareAggregatedSummaryEntity): LiveLocationShareAggregatedSummary {
fun map(realmObject: LiveLocationShareAggregatedSummaryEntity): LiveLocationShareAggregatedSummary {
return LiveLocationShareAggregatedSummary(
userId = realmObject.userId,
isActive = realmObject.isActive,

View File

@ -16,7 +16,6 @@
package org.matrix.android.sdk.internal.database.mapper
import io.realm.RealmList
import io.realm.kotlin.ext.realmListOf
import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.events.model.toModel

View File

@ -107,7 +107,7 @@ internal class RoomSummaryMapper @Inject constructor(
)
},
directParentNames = roomSummaryEntity.directParentNames.toList(),
flattenParentIds = roomSummaryEntity.flattenParentIds?.split("|") ?: emptyList(),
flattenParentIds = roomSummaryEntity.flattenParentIds,
roomEncryptionAlgorithm = when (val alg = roomSummaryEntity.e2eAlgorithm) {
// I should probably use #hasEncryptorClassForAlgorithm but it says it supports
// OLM which is some legacy? Now only megolm allowed in rooms

View File

@ -1,33 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo001(realm: DynamicRealm) : RealmMigrator(realm, 1) {
override fun doMigrate(realm: DynamicRealm) {
// Add hasFailedSending in RoomSummary and a small warning icon on room list
realm.schema.get("RoomSummaryEntity")
?.addField(RoomSummaryEntityFields.HAS_FAILED_SENDING, Boolean::class.java)
?.transform { obj ->
obj.setBoolean(RoomSummaryEntityFields.HAS_FAILED_SENDING, false)
}
}
}

View File

@ -1,31 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo002(realm: DynamicRealm) : RealmMigrator(realm, 2) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("HomeServerCapabilitiesEntity")
?.addField("adminE2EByDefault", Boolean::class.java)
?.transform { obj ->
obj.setBoolean("adminE2EByDefault", true)
}
}
}

View File

@ -1,30 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.extensions.forceRefreshOfHomeServerCapabilities
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo003(realm: DynamicRealm) : RealmMigrator(realm, 3) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("HomeServerCapabilitiesEntity")
?.addField("preferredJitsiDomain", String::class.java)
?.forceRefreshOfHomeServerCapabilities()
}
}

View File

@ -1,36 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.PendingThreePidEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo004(realm: DynamicRealm) : RealmMigrator(realm, 4) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.create("PendingThreePidEntity")
.addField(PendingThreePidEntityFields.CLIENT_SECRET, String::class.java)
.setRequired(PendingThreePidEntityFields.CLIENT_SECRET, true)
.addField(PendingThreePidEntityFields.EMAIL, String::class.java)
.addField(PendingThreePidEntityFields.MSISDN, String::class.java)
.addField(PendingThreePidEntityFields.SEND_ATTEMPT, Int::class.java)
.addField(PendingThreePidEntityFields.SID, String::class.java)
.setRequired(PendingThreePidEntityFields.SID, true)
.addField(PendingThreePidEntityFields.SUBMIT_URL, String::class.java)
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo005(realm: DynamicRealm) : RealmMigrator(realm, 5) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("HomeServerCapabilitiesEntity")
?.removeField("adminE2EByDefault")
?.removeField("preferredJitsiDomain")
}
}

View File

@ -1,37 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.PreviewUrlCacheEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo006(realm: DynamicRealm) : RealmMigrator(realm, 6) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.create("PreviewUrlCacheEntity")
.addField(PreviewUrlCacheEntityFields.URL, String::class.java)
.setRequired(PreviewUrlCacheEntityFields.URL, true)
.addPrimaryKey(PreviewUrlCacheEntityFields.URL)
.addField(PreviewUrlCacheEntityFields.URL_FROM_SERVER, String::class.java)
.addField(PreviewUrlCacheEntityFields.SITE_NAME, String::class.java)
.addField(PreviewUrlCacheEntityFields.TITLE, String::class.java)
.addField(PreviewUrlCacheEntityFields.DESCRIPTION, String::class.java)
.addField(PreviewUrlCacheEntityFields.MXC_URL, String::class.java)
.addField(PreviewUrlCacheEntityFields.LAST_UPDATED_TIMESTAMP, Long::class.java)
}
}

View File

@ -1,38 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.RoomEntityFields
import org.matrix.android.sdk.internal.database.model.RoomMembersLoadStatusType
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo007(realm: DynamicRealm) : RealmMigrator(realm, 7) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("RoomEntity")
?.addField(RoomEntityFields.MEMBERS_LOAD_STATUS_STR, String::class.java)
?.transform { obj ->
if (obj.getBoolean("areAllMembersLoaded")) {
obj.setString("membersLoadStatusStr", RoomMembersLoadStatusType.LOADED.name)
} else {
obj.setString("membersLoadStatusStr", RoomMembersLoadStatusType.NONE.name)
}
}
?.removeField("areAllMembersLoaded")
}
}

View File

@ -1,47 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.EditAggregatedSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.EditionOfEventFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo008(realm: DynamicRealm) : RealmMigrator(realm, 8) {
override fun doMigrate(realm: DynamicRealm) {
val editionOfEventSchema = realm.schema.create("EditionOfEvent")
.addField(EditionOfEventFields.CONTENT, String::class.java)
.addField(EditionOfEventFields.EVENT_ID, String::class.java)
.setRequired(EditionOfEventFields.EVENT_ID, true)
.addField(EditionOfEventFields.SENDER_ID, String::class.java)
.setRequired(EditionOfEventFields.SENDER_ID, true)
.addField(EditionOfEventFields.TIMESTAMP, Long::class.java)
.addField(EditionOfEventFields.IS_LOCAL_ECHO, Boolean::class.java)
realm.schema.get("EditAggregatedSummaryEntity")
?.removeField("aggregatedContent")
?.removeField("sourceEvents")
?.removeField("lastEditTs")
?.removeField("sourceLocalEchoEvents")
?.addRealmListField(EditAggregatedSummaryEntityFields.EDITIONS.`$`, editionOfEventSchema)
// This has to be done once a parent use the model as a child
// See https://github.com/realm/realm-java/issues/7402
editionOfEventSchema.isEmbedded = true
}
}

View File

@ -1,65 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import io.realm.FieldAttribute
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
import org.matrix.android.sdk.internal.database.model.EventEntityFields
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.RoomTagEntityFields
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo009(realm: DynamicRealm) : RealmMigrator(realm, 9) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("RoomSummaryEntity")
?.addField(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Long::class.java, FieldAttribute.INDEXED)
?.setNullable(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, true)
?.addIndex(RoomSummaryEntityFields.MEMBERSHIP_STR)
?.addIndex(RoomSummaryEntityFields.IS_DIRECT)
?.addIndex(RoomSummaryEntityFields.VERSIONING_STATE_STR)
?.addField(RoomSummaryEntityFields.IS_FAVOURITE, Boolean::class.java)
?.addIndex(RoomSummaryEntityFields.IS_FAVOURITE)
?.addField(RoomSummaryEntityFields.IS_LOW_PRIORITY, Boolean::class.java)
?.addIndex(RoomSummaryEntityFields.IS_LOW_PRIORITY)
?.addField(RoomSummaryEntityFields.IS_SERVER_NOTICE, Boolean::class.java)
?.addIndex(RoomSummaryEntityFields.IS_SERVER_NOTICE)
?.transform { obj ->
val isFavorite = obj.getList(RoomSummaryEntityFields.TAGS.`$`).any {
it.getString(RoomTagEntityFields.TAG_NAME) == RoomTag.ROOM_TAG_FAVOURITE
}
obj.setBoolean(RoomSummaryEntityFields.IS_FAVOURITE, isFavorite)
val isLowPriority = obj.getList(RoomSummaryEntityFields.TAGS.`$`).any {
it.getString(RoomTagEntityFields.TAG_NAME) == RoomTag.ROOM_TAG_LOW_PRIORITY
}
obj.setBoolean(RoomSummaryEntityFields.IS_LOW_PRIORITY, isLowPriority)
// XXX migrate last message origin server ts
obj.getObject(RoomSummaryEntityFields.LATEST_PREVIEWABLE_EVENT.`$`)
?.getObject(TimelineEventEntityFields.ROOT.`$`)
?.getLong(EventEntityFields.ORIGIN_SERVER_TS)?.let {
obj.setLong(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, it)
}
}
}
}

View File

@ -1,70 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
import org.matrix.android.sdk.internal.database.model.EventEntityFields
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.SpaceChildSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.SpaceParentSummaryEntityFields
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo010(realm: DynamicRealm) : RealmMigrator(realm, 10) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.create("SpaceChildSummaryEntity")
?.addField(SpaceChildSummaryEntityFields.ORDER, String::class.java)
?.addField(SpaceChildSummaryEntityFields.CHILD_ROOM_ID, String::class.java)
?.addField(SpaceChildSummaryEntityFields.AUTO_JOIN, Boolean::class.java)
?.setNullable(SpaceChildSummaryEntityFields.AUTO_JOIN, true)
?.addRealmObjectField(SpaceChildSummaryEntityFields.CHILD_SUMMARY_ENTITY.`$`, realm.schema.get("RoomSummaryEntity")!!)
?.addRealmListField(SpaceChildSummaryEntityFields.VIA_SERVERS.`$`, String::class.java)
realm.schema.create("SpaceParentSummaryEntity")
?.addField(SpaceParentSummaryEntityFields.PARENT_ROOM_ID, String::class.java)
?.addField(SpaceParentSummaryEntityFields.CANONICAL, Boolean::class.java)
?.setNullable(SpaceParentSummaryEntityFields.CANONICAL, true)
?.addRealmObjectField(SpaceParentSummaryEntityFields.PARENT_SUMMARY_ENTITY.`$`, realm.schema.get("RoomSummaryEntity")!!)
?.addRealmListField(SpaceParentSummaryEntityFields.VIA_SERVERS.`$`, String::class.java)
val creationContentAdapter = MoshiProvider.providesMoshi().adapter(RoomCreateContent::class.java)
realm.schema.get("RoomSummaryEntity")
?.addField(RoomSummaryEntityFields.ROOM_TYPE, String::class.java)
?.addField(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, String::class.java)
?.addField("groupIds", String::class.java)
?.transform { obj ->
val creationEvent = realm.where("CurrentStateEventEntity")
.equalTo(CurrentStateEventEntityFields.ROOM_ID, obj.getString(RoomSummaryEntityFields.ROOM_ID))
.equalTo(CurrentStateEventEntityFields.TYPE, EventType.STATE_ROOM_CREATE)
.findFirst()
val roomType = creationEvent?.getObject(CurrentStateEventEntityFields.ROOT.`$`)
?.getString(EventEntityFields.CONTENT)?.let {
creationContentAdapter.fromJson(it)?.type
}
obj.setString(RoomSummaryEntityFields.ROOM_TYPE, roomType)
}
?.addRealmListField(RoomSummaryEntityFields.PARENTS.`$`, realm.schema.get("SpaceParentSummaryEntity")!!)
?.addRealmListField(RoomSummaryEntityFields.CHILDREN.`$`, realm.schema.get("SpaceChildSummaryEntity")!!)
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.EventEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo011(realm: DynamicRealm) : RealmMigrator(realm, 11) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("EventEntity")
?.addField(EventEntityFields.SEND_STATE_DETAILS, String::class.java)
}
}

View File

@ -1,53 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
import org.matrix.android.sdk.internal.database.model.EventEntityFields
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.SpaceChildSummaryEntityFields
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo012(realm: DynamicRealm) : RealmMigrator(realm, 12) {
override fun doMigrate(realm: DynamicRealm) {
val joinRulesContentAdapter = MoshiProvider.providesMoshi().adapter(RoomJoinRulesContent::class.java)
realm.schema.get("RoomSummaryEntity")
?.addField(RoomSummaryEntityFields.JOIN_RULES_STR, String::class.java)
?.transform { obj ->
val joinRulesEvent = realm.where("CurrentStateEventEntity")
.equalTo(CurrentStateEventEntityFields.ROOM_ID, obj.getString(RoomSummaryEntityFields.ROOM_ID))
.equalTo(CurrentStateEventEntityFields.TYPE, EventType.STATE_ROOM_JOIN_RULES)
.findFirst()
val roomJoinRules = joinRulesEvent?.getObject(CurrentStateEventEntityFields.ROOT.`$`)
?.getString(EventEntityFields.CONTENT)?.let {
joinRulesContentAdapter.fromJson(it)?.joinRules
}
obj.setString(RoomSummaryEntityFields.JOIN_RULES_STR, roomJoinRules?.name)
}
realm.schema.get("SpaceChildSummaryEntity")
?.addField(SpaceChildSummaryEntityFields.SUGGESTED, Boolean::class.java)
?.setNullable(SpaceChildSummaryEntityFields.SUGGESTED, true)
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.SpaceChildSummaryEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo013(realm: DynamicRealm) : RealmMigrator(realm, 13) {
override fun doMigrate(realm: DynamicRealm) {
// Fix issue with the nightly build. Eventually play again the migration which has been included in migrateTo12()
realm.schema.get("SpaceChildSummaryEntity")
?.takeIf { !it.hasField(SpaceChildSummaryEntityFields.SUGGESTED) }
?.addField(SpaceChildSummaryEntityFields.SUGGESTED, Boolean::class.java)
?.setNullable(SpaceChildSummaryEntityFields.SUGGESTED, true)
}
}

View File

@ -1,46 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import io.realm.FieldAttribute
import org.matrix.android.sdk.api.session.room.model.VersioningState
import org.matrix.android.sdk.internal.database.model.RoomAccountDataEntityFields
import org.matrix.android.sdk.internal.database.model.RoomEntityFields
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo014(realm: DynamicRealm) : RealmMigrator(realm, 14) {
override fun doMigrate(realm: DynamicRealm) {
val roomAccountDataSchema = realm.schema.create("RoomAccountDataEntity")
.addField(RoomAccountDataEntityFields.CONTENT_STR, String::class.java)
.addField(RoomAccountDataEntityFields.TYPE, String::class.java, FieldAttribute.INDEXED)
realm.schema.get("RoomEntity")
?.addRealmListField(RoomEntityFields.ACCOUNT_DATA.`$`, roomAccountDataSchema)
realm.schema.get("RoomSummaryEntity")
?.addField(RoomSummaryEntityFields.IS_HIDDEN_FROM_USER, Boolean::class.java, FieldAttribute.INDEXED)
?.transform {
val isHiddenFromUser = it.getString(RoomSummaryEntityFields.VERSIONING_STATE_STR) == VersioningState.UPGRADED_ROOM_JOINED.name
it.setBoolean(RoomSummaryEntityFields.IS_HIDDEN_FROM_USER, isHiddenFromUser)
}
roomAccountDataSchema.isEmbedded = true
}
}

View File

@ -1,38 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.query.process
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo015(realm: DynamicRealm) : RealmMigrator(realm, 15) {
override fun doMigrate(realm: DynamicRealm) {
// fix issue with flattenParentIds on DM that kept growing with duplicate
// so we reset it, will be updated next sync
realm.where("RoomSummaryEntity")
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships())
.equalTo(RoomSummaryEntityFields.IS_DIRECT, true)
.findAll()
.onEach {
it.setString(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, null)
}
}
}

View File

@ -1,31 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
import org.matrix.android.sdk.internal.extensions.forceRefreshOfHomeServerCapabilities
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo016(realm: DynamicRealm) : RealmMigrator(realm, 16) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("HomeServerCapabilitiesEntity")
?.addField(HomeServerCapabilitiesEntityFields.ROOM_VERSIONS_JSON, String::class.java)
?.forceRefreshOfHomeServerCapabilities()
}
}

View File

@ -1,29 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.EventInsertEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo017(realm: DynamicRealm) : RealmMigrator(realm, 17) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("EventInsertEntity")
?.addField(EventInsertEntityFields.CAN_BE_PROCESSED, Boolean::class.java)
}
}

View File

@ -1,48 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo018(realm: DynamicRealm) : RealmMigrator(realm, 18) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.create("UserPresenceEntity")
?.addField(UserPresenceEntityFields.USER_ID, String::class.java)
?.addPrimaryKey(UserPresenceEntityFields.USER_ID)
?.setRequired(UserPresenceEntityFields.USER_ID, true)
?.addField(UserPresenceEntityFields.PRESENCE_STR, String::class.java)
?.addField(UserPresenceEntityFields.LAST_ACTIVE_AGO, Long::class.java)
?.setNullable(UserPresenceEntityFields.LAST_ACTIVE_AGO, true)
?.addField(UserPresenceEntityFields.STATUS_MESSAGE, String::class.java)
?.addField(UserPresenceEntityFields.IS_CURRENTLY_ACTIVE, Boolean::class.java)
?.setNullable(UserPresenceEntityFields.IS_CURRENTLY_ACTIVE, true)
?.addField(UserPresenceEntityFields.AVATAR_URL, String::class.java)
?.addField(UserPresenceEntityFields.DISPLAY_NAME, String::class.java)
val userPresenceEntity = realm.schema.get("UserPresenceEntity") ?: return
realm.schema.get("RoomSummaryEntity")
?.addRealmObjectField(RoomSummaryEntityFields.DIRECT_USER_PRESENCE.`$`, userPresenceEntity)
realm.schema.get("RoomMemberSummaryEntity")
?.addRealmObjectField(RoomMemberSummaryEntityFields.USER_PRESENCE_ENTITY.`$`, userPresenceEntity)
}
}

View File

@ -1,39 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.util.Normalizer
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo019(
realm: DynamicRealm,
private val normalizer: Normalizer
) : RealmMigrator(realm, 19) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("RoomSummaryEntity")
?.addField(RoomSummaryEntityFields.NORMALIZED_DISPLAY_NAME, String::class.java)
?.transform {
it.getString(RoomSummaryEntityFields.DISPLAY_NAME)?.let { displayName ->
val normalised = normalizer.normalize(displayName)
it.set(RoomSummaryEntityFields.NORMALIZED_DISPLAY_NAME, normalised)
}
}
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.ChunkEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo020(realm: DynamicRealm) : RealmMigrator(realm, 20) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("ChunkEntity")?.apply {
if (hasField("numberOfTimelineEvents")) {
removeField("numberOfTimelineEvents")
}
var cleanOldChunks = false
if (!hasField(ChunkEntityFields.NEXT_CHUNK.`$`)) {
cleanOldChunks = true
addRealmObjectField(ChunkEntityFields.NEXT_CHUNK.`$`, this)
}
if (!hasField(ChunkEntityFields.PREV_CHUNK.`$`)) {
cleanOldChunks = true
addRealmObjectField(ChunkEntityFields.PREV_CHUNK.`$`, this)
}
if (cleanOldChunks) {
val chunkEntities = realm.where("ChunkEntity").equalTo(ChunkEntityFields.IS_LAST_FORWARD, false).findAll()
chunkEntities.deleteAllFromRealm()
}
}
}
}

View File

@ -1,55 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventContent
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
import org.matrix.android.sdk.internal.database.model.EventEntityFields
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo021(realm: DynamicRealm) : RealmMigrator(realm, 21) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("RoomSummaryEntity")
?.addField(RoomSummaryEntityFields.E2E_ALGORITHM, String::class.java)
?.transform { obj ->
val encryptionContentAdapter = MoshiProvider.providesMoshi().adapter(EncryptionEventContent::class.java)
val encryptionEvent = realm.where("CurrentStateEventEntity")
.equalTo(CurrentStateEventEntityFields.ROOM_ID, obj.getString(RoomSummaryEntityFields.ROOM_ID))
.equalTo(CurrentStateEventEntityFields.TYPE, EventType.STATE_ROOM_ENCRYPTION)
.findFirst()
val encryptionEventRoot = encryptionEvent?.getObject(CurrentStateEventEntityFields.ROOT.`$`)
val algorithm = encryptionEventRoot
?.getString(EventEntityFields.CONTENT)?.let {
encryptionContentAdapter.fromJson(it)?.algorithm
}
obj.setString(RoomSummaryEntityFields.E2E_ALGORITHM, algorithm)
obj.setBoolean(RoomSummaryEntityFields.IS_ENCRYPTED, encryptionEvent != null)
encryptionEventRoot?.getLong(EventEntityFields.ORIGIN_SERVER_TS)?.let {
obj.setLong(RoomSummaryEntityFields.ENCRYPTION_EVENT_TS, it)
}
}
}
}

View File

@ -1,42 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
import org.matrix.android.sdk.internal.database.model.RoomEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import timber.log.Timber
internal class MigrateSessionTo022(realm: DynamicRealm) : RealmMigrator(realm, 22) {
override fun doMigrate(realm: DynamicRealm) {
val listJoinedRoomIds = realm.where("RoomEntity")
.equalTo(RoomEntityFields.MEMBERSHIP_STR, Membership.JOIN.name).findAll()
.map { it.getString(RoomEntityFields.ROOM_ID) }
val hasMissingStateEvent = realm.where("CurrentStateEventEntity")
.`in`(CurrentStateEventEntityFields.ROOM_ID, listJoinedRoomIds.toTypedArray())
.isNull(CurrentStateEventEntityFields.ROOT.`$`).findFirst() != null
if (hasMissingStateEvent) {
Timber.v("Has some missing state event, clear session cache")
realm.deleteAll()
}
}
}

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import io.realm.FieldAttribute
import org.matrix.android.sdk.api.session.threads.ThreadNotificationState
import org.matrix.android.sdk.internal.database.model.EventEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo023(realm: DynamicRealm) : RealmMigrator(realm, 23) {
override fun doMigrate(realm: DynamicRealm) {
val eventEntity = realm.schema.get("TimelineEventEntity") ?: return
realm.schema.get("EventEntity")
?.addField(EventEntityFields.IS_ROOT_THREAD, Boolean::class.java, FieldAttribute.INDEXED)
?.addField(EventEntityFields.ROOT_THREAD_EVENT_ID, String::class.java, FieldAttribute.INDEXED)
?.addField(EventEntityFields.NUMBER_OF_THREADS, Int::class.java)
?.addField(EventEntityFields.THREAD_NOTIFICATION_STATE_STR, String::class.java)
?.transform {
it.setString(EventEntityFields.THREAD_NOTIFICATION_STATE_STR, ThreadNotificationState.NO_NEW_MESSAGE.name)
}
?.addRealmObjectField(EventEntityFields.THREAD_SUMMARY_LATEST_MESSAGE.`$`, eventEntity)
}
}

View File

@ -1,32 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.PreviewUrlCacheEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo024(realm: DynamicRealm) : RealmMigrator(realm, 24) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("PreviewUrlCacheEntity")
?.addField(PreviewUrlCacheEntityFields.IMAGE_WIDTH, Int::class.java)
?.setNullable(PreviewUrlCacheEntityFields.IMAGE_WIDTH, true)
?.addField(PreviewUrlCacheEntityFields.IMAGE_HEIGHT, Int::class.java)
?.setNullable(PreviewUrlCacheEntityFields.IMAGE_HEIGHT, true)
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
import org.matrix.android.sdk.internal.extensions.forceRefreshOfHomeServerCapabilities
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo025(realm: DynamicRealm) : RealmMigrator(realm, 25) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("HomeServerCapabilitiesEntity")
?.addField(HomeServerCapabilitiesEntityFields.CAN_CHANGE_DISPLAY_NAME, Boolean::class.java)
?.addField(HomeServerCapabilitiesEntityFields.CAN_CHANGE_AVATAR, Boolean::class.java)
?.addField(HomeServerCapabilitiesEntityFields.CAN_CHANGE3PID, Boolean::class.java)
?.forceRefreshOfHomeServerCapabilities()
}
}

View File

@ -1,65 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import io.realm.FieldAttribute
import org.matrix.android.sdk.internal.database.model.ChunkEntityFields
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
import org.matrix.android.sdk.internal.database.model.RoomEntityFields
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntityFields
import org.matrix.android.sdk.internal.extensions.forceRefreshOfHomeServerCapabilities
import org.matrix.android.sdk.internal.util.database.RealmMigrator
/**
* Migrating to:
* Live thread list: using enhanced /messages api MSC3440
* Live thread timeline: using /relations api.
*/
internal class MigrateSessionTo026(realm: DynamicRealm) : RealmMigrator(realm, 26) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("ChunkEntity")
?.addField(ChunkEntityFields.ROOT_THREAD_EVENT_ID, String::class.java, FieldAttribute.INDEXED)
?.addField(ChunkEntityFields.IS_LAST_FORWARD_THREAD, Boolean::class.java, FieldAttribute.INDEXED)
realm.schema.get("TimelineEventEntity")
?.addField(TimelineEventEntityFields.OWNED_BY_THREAD_CHUNK, Boolean::class.java)
val eventEntity = realm.schema.get("EventEntity") ?: return
val threadSummaryEntity = realm.schema.create("ThreadSummaryEntity")
.addField(ThreadSummaryEntityFields.ROOT_THREAD_EVENT_ID, String::class.java, FieldAttribute.INDEXED)
.addField(ThreadSummaryEntityFields.ROOT_THREAD_SENDER_NAME, String::class.java)
.addField(ThreadSummaryEntityFields.ROOT_THREAD_SENDER_AVATAR, String::class.java)
.addField(ThreadSummaryEntityFields.ROOT_THREAD_IS_UNIQUE_DISPLAY_NAME, Boolean::class.java)
.addField(ThreadSummaryEntityFields.LATEST_THREAD_SENDER_NAME, String::class.java)
.addField(ThreadSummaryEntityFields.LATEST_THREAD_SENDER_AVATAR, String::class.java)
.addField(ThreadSummaryEntityFields.LATEST_THREAD_IS_UNIQUE_DISPLAY_NAME, Boolean::class.java)
.addField(ThreadSummaryEntityFields.NUMBER_OF_THREADS, Int::class.java)
.addField(ThreadSummaryEntityFields.IS_USER_PARTICIPATING, Boolean::class.java)
.addRealmObjectField(ThreadSummaryEntityFields.ROOT_THREAD_EVENT_ENTITY.`$`, eventEntity)
.addRealmObjectField(ThreadSummaryEntityFields.LATEST_THREAD_EVENT_ENTITY.`$`, eventEntity)
realm.schema.get("RoomEntity")
?.addRealmListField(RoomEntityFields.THREAD_SUMMARIES.`$`, threadSummaryEntity)
realm.schema.get("HomeServerCapabilitiesEntity")
?.addField(HomeServerCapabilitiesEntityFields.CAN_USE_THREADING, Boolean::class.java)
?.forceRefreshOfHomeServerCapabilities()
}
}

View File

@ -1,46 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import io.realm.FieldAttribute
import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
/**
* Migrating to:
* Live location sharing aggregated summary.
*/
internal class MigrateSessionTo027(realm: DynamicRealm) : RealmMigrator(realm, 27) {
override fun doMigrate(realm: DynamicRealm) {
val liveLocationSummaryEntity = realm.schema.get("LiveLocationShareAggregatedSummaryEntity")
?: realm.schema.create("LiveLocationShareAggregatedSummaryEntity")
.addField(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID, String::class.java, FieldAttribute.REQUIRED)
.addField(LiveLocationShareAggregatedSummaryEntityFields.ROOM_ID, String::class.java, FieldAttribute.REQUIRED)
.addField(LiveLocationShareAggregatedSummaryEntityFields.IS_ACTIVE, Boolean::class.java)
.setNullable(LiveLocationShareAggregatedSummaryEntityFields.IS_ACTIVE, true)
.addField(LiveLocationShareAggregatedSummaryEntityFields.END_OF_LIVE_TIMESTAMP_MILLIS, Long::class.java)
.setNullable(LiveLocationShareAggregatedSummaryEntityFields.END_OF_LIVE_TIMESTAMP_MILLIS, true)
.addField(LiveLocationShareAggregatedSummaryEntityFields.LAST_LOCATION_CONTENT, String::class.java)
?: return
realm.schema.get("EventAnnotationsSummaryEntity")
?.addRealmObjectField(EventAnnotationsSummaryEntityFields.LIVE_LOCATION_SHARE_AGGREGATED_SUMMARY.`$`, liveLocationSummaryEntity)
}
}

View File

@ -1,34 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
/**
* Migrating to:
* Live location sharing aggregated summary.
*/
internal class MigrateSessionTo028(realm: DynamicRealm) : RealmMigrator(realm, 28) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("LiveLocationShareAggregatedSummaryEntity")
?.takeIf { !it.hasPrimaryKey() }
?.addPrimaryKey(LiveLocationShareAggregatedSummaryEntityFields.EVENT_ID)
}
}

View File

@ -1,37 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import io.realm.FieldAttribute
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
/**
* Migrating to:
* Live location sharing aggregated summary: adding new field userId.
*/
internal class MigrateSessionTo029(realm: DynamicRealm) : RealmMigrator(realm, 29) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("LiveLocationShareAggregatedSummaryEntity")
?.addField(LiveLocationShareAggregatedSummaryEntityFields.USER_ID, String::class.java, FieldAttribute.REQUIRED)
?.transform { obj ->
obj.setString(LiveLocationShareAggregatedSummaryEntityFields.USER_ID, "")
}
}
}

View File

@ -1,61 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.ChunkEntityFields
import org.matrix.android.sdk.internal.database.model.EventEntityFields
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
import timber.log.Timber
/**
* Migrating to:
* Cleaning old chunks which may have broken links.
*/
internal class MigrateSessionTo030(realm: DynamicRealm) : RealmMigrator(realm, 30) {
override fun doMigrate(realm: DynamicRealm) {
// Delete all previous chunks
val chunks = realm.where("ChunkEntity")
.equalTo(ChunkEntityFields.IS_LAST_FORWARD, false)
.findAll()
val nbOfDeletedChunks = chunks.size
var nbOfDeletedTimelineEvents = 0
var nbOfDeletedEvents = 0
chunks.forEach { chunk ->
val timelineEvents = chunk.getList(ChunkEntityFields.TIMELINE_EVENTS.`$`)
timelineEvents.forEach { timelineEvent ->
// Don't delete state events
val event = timelineEvent.getObject(TimelineEventEntityFields.ROOT.`$`)
if (event?.isNull(EventEntityFields.STATE_KEY) == true) {
nbOfDeletedEvents++
event.deleteFromRealm()
}
}
nbOfDeletedTimelineEvents += timelineEvents.size
timelineEvents.deleteAllFromRealm()
}
chunks.deleteAllFromRealm()
Timber.d(
"MigrateSessionTo030: $nbOfDeletedChunks deleted chunk(s)," +
" $nbOfDeletedTimelineEvents deleted TimelineEvent(s)" +
" and $nbOfDeletedEvents deleted Event(s)."
)
}
}

View File

@ -1,31 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
import org.matrix.android.sdk.internal.extensions.forceRefreshOfHomeServerCapabilities
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo031(realm: DynamicRealm) : RealmMigrator(realm, 31) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("HomeServerCapabilitiesEntity")
?.addField(HomeServerCapabilitiesEntityFields.CAN_CONTROL_LOGOUT_DEVICES, Boolean::class.java)
?.forceRefreshOfHomeServerCapabilities()
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo032(realm: DynamicRealm) : RealmMigrator(realm, 32) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("RoomSummaryEntity")
?.removeField("groupIds")
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
/**
* Migrating to:
* Live location sharing aggregated summary: adding new field relatedEventIds.
*/
internal class MigrateSessionTo033(realm: DynamicRealm) : RealmMigrator(realm, 33) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("LiveLocationShareAggregatedSummaryEntity")
?.addRealmListField(LiveLocationShareAggregatedSummaryEntityFields.RELATED_EVENT_IDS.`$`, String::class.java)
}
}

View File

@ -1,34 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
/**
* Migrating to:
* Live location sharing aggregated summary: adding new field startOfLiveTimestampMillis.
*/
internal class MigrateSessionTo034(realm: DynamicRealm) : RealmMigrator(realm, 34) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("LiveLocationShareAggregatedSummaryEntity")
?.addField(LiveLocationShareAggregatedSummaryEntityFields.START_OF_LIVE_TIMESTAMP_MILLIS, Long::class.java)
?.setNullable(LiveLocationShareAggregatedSummaryEntityFields.START_OF_LIVE_TIMESTAMP_MILLIS, true)
}
}

View File

@ -1,31 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import io.realm.RealmList
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo035(realm: DynamicRealm) : RealmMigrator(realm, 35) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("RoomSummaryEntity")
?.addRealmListField(RoomSummaryEntityFields.DIRECT_PARENT_NAMES.`$`, String::class.java)
?.transform { it.setList(RoomSummaryEntityFields.DIRECT_PARENT_NAMES.`$`, RealmList("")) }
}
}

View File

@ -39,12 +39,12 @@ internal class ChunkEntity : RealmObject {
var timelineEvents: RealmList<TimelineEventEntity> = realmListOf()
// Only one chunk will have isLastForward == true
@Index var isLastForward: Boolean = false
@Index var isLastBackward: Boolean = false
var isLastForward: Boolean = false
var isLastBackward: Boolean = false
// Threads
@Index var rootThreadEventId: String? = null
@Index var isLastForwardThread: Boolean = false
var isLastForwardThread: Boolean = false
fun identifier() = "${prevToken}_$nextToken"

View File

@ -44,7 +44,7 @@ internal class EventEntity : RealmObject {
var ageLocalTs: Long? = null
// Thread related, no need to create a new Entity for performance
@Index var isRootThread: Boolean = false
var isRootThread: Boolean = false
@Index var rootThreadEventId: String? = null
// Number messages within the thread

View File

@ -92,7 +92,6 @@ internal class RoomSummaryEntity : RealmObject {
if (value != field) field = value
}
@Index
var isDirect: Boolean = false
set(value) {
if (value != field) field = value
@ -157,19 +156,16 @@ internal class RoomSummaryEntity : RealmObject {
isServerNotice = newTags.any { it.first == RoomTag.ROOM_TAG_SERVER_NOTICE }
}
@Index
var isFavourite: Boolean = false
set(value) {
if (value != field) field = value
}
@Index
var isLowPriority: Boolean = false
set(value) {
if (value != field) field = value
}
@Index
var isServerNotice: Boolean = false
set(value) {
if (value != field) field = value
@ -257,7 +253,6 @@ internal class RoomSummaryEntity : RealmObject {
}
}
@Index
var isHiddenFromUser: Boolean = false
set(value) {
if (value != field) field = value

View File

@ -3,19 +3,22 @@ package org.matrix.android.sdk.internal.database.pagedlist
import androidx.paging.DataSource
import io.realm.kotlin.Realm
import io.realm.kotlin.notifications.UpdatedResults
import io.realm.kotlin.query.RealmResults
import io.realm.kotlin.types.RealmObject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapConcat
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.take
import org.matrix.android.sdk.internal.database.RealmObjectMapper
import org.matrix.android.sdk.internal.database.RealmQueryBuilder
internal class RealmTiledDataSource<T : RealmObject, R> internal constructor(
realm: Realm,
queryBuilder: RealmQueryBuilder<T>,
liveQueryBuilder: Flow<RealmQueryBuilder<T>>,
private val mapper: RealmObjectMapper<T, R>,
coroutineScope: CoroutineScope
) :
@ -23,30 +26,35 @@ internal class RealmTiledDataSource<T : RealmObject, R> internal constructor(
class Factory<T : RealmObject, R>(
private val realm: Realm,
private val queryBuilder: RealmQueryBuilder<T>,
private val liveQueryBuilder: Flow<RealmQueryBuilder<T>>,
private val mapper: RealmObjectMapper<T, R>,
private val coroutineScope: CoroutineScope,
) : DataSource.Factory<Int, R>() {
override fun create(): DataSource<Int, R> {
val childScope = CoroutineScope(SupervisorJob() + coroutineScope.coroutineContext)
return RealmTiledDataSource(realm, queryBuilder, mapper, childScope)
return RealmTiledDataSource(realm, liveQueryBuilder, mapper, childScope)
}
}
private val results: RealmResults<T>
private var results: List<T> = emptyList()
init {
addInvalidatedCallback {
coroutineScope.coroutineContext.cancelChildren()
}
results = queryBuilder.build(realm).find()
results.asFlow()
liveQueryBuilder
.take(1)
.flatMapConcat {
it.build(realm).asFlow()
}
.onEach { resultsChange ->
when (resultsChange) {
is UpdatedResults -> invalidate()
else -> Unit
}
}.onCompletion {
invalidate()
}
.launchIn(coroutineScope)
}

View File

@ -23,7 +23,6 @@ import io.realm.kotlin.types.RealmList
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.internal.database.andIf
import org.matrix.android.sdk.internal.database.model.EventEntity
import org.matrix.android.sdk.internal.database.model.EventEntityFields
import org.matrix.android.sdk.internal.database.model.EventInsertEntity
import org.matrix.android.sdk.internal.database.model.EventInsertType
import org.matrix.android.sdk.internal.database.queryIn
@ -92,7 +91,7 @@ internal fun EventEntity.Companion.whereTypes(
}
internal fun RealmList<EventEntity>.find(eventId: String): EventEntity? {
return return firstOrNull { it.eventId == eventId }
return firstOrNull { it.eventId == eventId }
}
internal fun RealmList<EventEntity>.fastContains(eventId: String): Boolean {

View File

@ -23,7 +23,6 @@ import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.internal.database.andIf
import org.matrix.android.sdk.internal.database.model.EventEntity
import org.matrix.android.sdk.internal.database.model.RoomEntity
import org.matrix.android.sdk.internal.extensions.realm
internal fun RoomEntity.Companion.where(realm: TypedRealm, roomId: String): RealmQuery<RoomEntity> {
return realm.query(RoomEntity::class)

View File

@ -20,9 +20,7 @@ import io.realm.kotlin.MutableRealm
import io.realm.kotlin.TypedRealm
import io.realm.kotlin.query.RealmQuery
import io.realm.kotlin.types.RealmList
import io.realm.kotlin.where
import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntity
import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntityFields
internal fun ThreadSummaryEntity.Companion.where(realm: TypedRealm, roomId: String): RealmQuery<ThreadSummaryEntity> {
return realm.query(ThreadSummaryEntity::class)
@ -50,11 +48,13 @@ internal fun ThreadSummaryEntity.Companion.getOrNull(realm: TypedRealm, roomId:
return where(realm, roomId, rootThreadEventId).first().find()
}
/*
internal fun RealmList<ThreadSummaryEntity>.find(rootThreadEventId: String): ThreadSummaryEntity? {
return this.where()
.equalTo(ThreadSummaryEntityFields.ROOT_THREAD_EVENT_ID, rootThreadEventId)
.findFirst()
}
*/
internal fun ThreadSummaryEntity.Companion.findRootOrLatest(realm: TypedRealm, eventId: String): ThreadSummaryEntity? {
return realm.query(ThreadSummaryEntity::class)

View File

@ -21,12 +21,15 @@ import io.realm.kotlin.query.RealmQuery
import io.realm.kotlin.query.RealmResults
import io.realm.kotlin.types.ObjectId
import io.realm.kotlin.types.RealmList
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.events.model.RelationType
import org.matrix.android.sdk.api.session.events.model.getRelationContent
import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.api.session.room.timeline.TimelineEventFilters
import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.RoomEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
import org.matrix.android.sdk.internal.database.queryIn
internal fun TimelineEventEntity.Companion.where(realm: TypedRealm): RealmQuery<TimelineEventEntity> {
@ -84,53 +87,42 @@ internal fun TimelineEventEntity.Companion.latestEvent(
includesSending: Boolean,
filters: TimelineEventFilters = TimelineEventFilters()
): TimelineEventEntity? {
val roomEntity = RoomEntity.where(realm, roomId).first().find() ?: return null
val sendingTimelineEvents = roomEntity.sendingTimelineEvents.where().filterEvents(filters)
val liveEvents = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId)?.timelineEvents?.where()?.filterEvents(filters)
val query = if (includesSending && sendingTimelineEvents.findAll().isNotEmpty()) {
val roomEntity = RoomEntity.where(realm, roomId).first().find() ?: return null
val sendingTimelineEvents = roomEntity.sendingTimelineEvents
val liveEvents = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId)?.timelineEvents.orEmpty()
val events = if (includesSending && sendingTimelineEvents.isNotEmpty()) {
sendingTimelineEvents
} else {
liveEvents
}
return query
?.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING)
?.findFirst()
}
internal fun RealmQuery<TimelineEventEntity>.filterEvents(filters: TimelineEventFilters): RealmQuery<TimelineEventEntity> {
if (filters.filterTypes && filters.allowedTypes.isNotEmpty()) {
beginGroup()
filters.allowedTypes.forEachIndexed { index, filter ->
if (filter.stateKey == null) {
equalTo(TimelineEventEntityFields.ROOT.TYPE, filter.eventType)
} else {
beginGroup()
equalTo(TimelineEventEntityFields.ROOT.TYPE, filter.eventType)
and()
equalTo(TimelineEventEntityFields.ROOT.STATE_KEY, filter.stateKey)
endGroup()
return events
.lastOrNull { timelineEvent ->
if (filters.filterUseless && timelineEvent.root?.isUseless.orFalse()) {
return@lastOrNull false
}
if (filters.filterTypes && filters.allowedTypes.isNotEmpty() &&
filters.allowedTypes.none { it.eventType == timelineEvent.root?.type }) {
return@lastOrNull false
}
val event by lazy {
timelineEvent.root?.asDomain()
}
val relationContent by lazy {
event?.getRelationContent()
}
if (filters.filterEdits &&
(relationContent?.type == RelationType.REPLACE) ||
relationContent?.type == RelationType.RESPONSE ||
relationContent?.type == RelationType.REFERENCE
) {
return@lastOrNull false
}
if (filters.filterRedacted && event?.isRedacted().orFalse()) {
return@lastOrNull false
}
true
}
if (index != filters.allowedTypes.size - 1) {
or()
}
}
endGroup()
}
if (filters.filterUseless) {
not()
.equalTo(TimelineEventEntityFields.ROOT.IS_USELESS, true)
}
if (filters.filterEdits) {
not().like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.EDIT)
not().like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.RESPONSE)
not().like(TimelineEventEntityFields.ROOT.CONTENT, TimelineEventFilter.Content.REFERENCE)
}
if (filters.filterRedacted) {
not().like(TimelineEventEntityFields.ROOT.UNSIGNED_DATA, TimelineEventFilter.Unsigned.REDACTED)
}
return this
}
internal fun RealmQuery<TimelineEventEntity>.filterTypes(filterTypes: List<String>): RealmQuery<TimelineEventEntity> {

View File

@ -1,61 +0,0 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.extensions
import io.realm.Realm
import io.realm.RealmList
import io.realm.RealmModel
import io.realm.RealmObject
import io.realm.RealmObjectSchema
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
import org.matrix.android.sdk.internal.util.fatalError
internal fun RealmModel.assertIsManaged() {
check(RealmObject.isManaged(this)) { "${javaClass.simpleName} entity should be managed to use this function" }
}
internal val RealmModel.realm: Realm
get() {
return RealmObject.getRealm(this)
}
/**
* Clear a RealmList by deleting all its items calling the provided lambda.
* The lambda is supposed to delete the item, which means that after this operation, the list will be empty.
*/
internal fun <T> RealmList<T>.clearWith(delete: (T) -> Unit) {
map { item ->
// Create a lambda for all items of the list
{ delete(item) }
}.forEach { lambda ->
// Then invoke all the lambda
lambda.invoke()
}
if (isNotEmpty()) {
fatalError("`clearWith` MUST delete all elements of the RealmList")
}
}
/**
* Schedule a refresh of the HomeServers capabilities.
*/
internal fun RealmObjectSchema?.forceRefreshOfHomeServerCapabilities(): RealmObjectSchema? {
return this?.transform { obj ->
obj.setLong(HomeServerCapabilitiesEntityFields.LAST_UPDATED_TIMESTAMP, 0)
}
}

View File

@ -20,21 +20,20 @@ import io.realm.kotlin.query.RealmQuery
import io.realm.kotlin.query.Sort
import org.matrix.android.sdk.api.session.room.RoomSortOrder
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
internal fun RealmQuery<RoomSummaryEntity>.process(sortOrder: RoomSortOrder): RealmQuery<RoomSummaryEntity> {
when (sortOrder) {
RoomSortOrder.NAME -> {
sort(RoomSummaryEntityFields.DISPLAY_NAME, Sort.ASCENDING)
sort("displayName", Sort.ASCENDING)
}
RoomSortOrder.ACTIVITY -> {
sort(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Sort.DESCENDING)
sort("lastActivityTime", Sort.DESCENDING)
}
RoomSortOrder.PRIORITY_AND_ACTIVITY -> {
sort(
RoomSummaryEntityFields.IS_FAVOURITE to Sort.DESCENDING,
RoomSummaryEntityFields.IS_LOW_PRIORITY to Sort.ASCENDING,
RoomSummaryEntityFields.LAST_ACTIVITY_TIME to Sort.DESCENDING
"isFavourite" to Sort.DESCENDING,
"isLowPriority" to Sort.ASCENDING,
"lastActivityTime" to Sort.DESCENDING
)
}
RoomSortOrder.NONE -> {

View File

@ -16,7 +16,6 @@
package org.matrix.android.sdk.internal.session.call
import io.realm.Realm
import io.realm.kotlin.MutableRealm
import org.matrix.android.sdk.api.logger.LoggerTag
import org.matrix.android.sdk.api.session.events.model.Event

View File

@ -32,10 +32,10 @@ internal class IntegrationManagerConfigExtractor @Inject constructor() {
if (apiUrl != null &&
apiUrl.startsWith("https://") &&
uiUrl!!.startsWith("https://")) {
return WellknownIntegrationManagerConfigEntity(
apiUrl = apiUrl,
uiUrl = uiUrl
)
return WellknownIntegrationManagerConfigEntity().apply {
this.apiUrl = apiUrl
this.uiUrl = uiUrl
}
}
}
}

View File

@ -84,16 +84,15 @@ internal class DefaultGetPreviewUrlTask @Inject constructor(
private suspend fun doRequestWithCache(url: String, timestamp: Long?, validityDurationInMillis: Long, strict: Boolean): PreviewUrlData {
// Get data from cache
var dataFromCache: PreviewUrlData? = null
var isCacheValid = false
val dataFromCache: PreviewUrlData?
val isCacheValid: Boolean
val realm = realmInstance.getRealm()
val entity = PreviewUrlCacheEntity.get(realm, url)
dataFromCache = entity?.toDomain()
isCacheValid = entity != null && Date().time < entity.lastUpdatedTimestamp + validityDurationInMillis
val finalDataFromCache = dataFromCache
if (finalDataFromCache != null && isCacheValid) {
return finalDataFromCache
if (dataFromCache != null && isCacheValid) {
return dataFromCache
}
// No cache or outdated cache
@ -101,7 +100,7 @@ internal class DefaultGetPreviewUrlTask @Inject constructor(
doRequest(url, timestamp)
} catch (throwable: Throwable) {
// In case of error, we can return value from cache even if outdated
return finalDataFromCache
return dataFromCache
?.takeIf { !strict }
?: throw throwable
}

View File

@ -15,7 +15,6 @@
*/
package org.matrix.android.sdk.internal.session.pushers
import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.api.session.pushers.PusherState
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.mapper.toEntity
@ -25,7 +24,6 @@ import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.task.Task
import org.matrix.android.sdk.internal.util.awaitTransaction
import javax.inject.Inject
internal interface GetPushersTask : Task<Unit, Unit>

View File

@ -15,7 +15,6 @@
*/
package org.matrix.android.sdk.internal.session.room
import io.realm.Realm
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.TypedRealm
import org.matrix.android.sdk.api.query.QueryStringValue
@ -52,7 +51,6 @@ import org.matrix.android.sdk.internal.database.model.EventInsertType
import org.matrix.android.sdk.internal.database.model.ReactionAggregatedSummaryEntity
import org.matrix.android.sdk.internal.database.model.ReferencesAggregatedSummaryEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
import org.matrix.android.sdk.internal.database.query.create
import org.matrix.android.sdk.internal.database.query.getOrCreate
import org.matrix.android.sdk.internal.database.query.where
@ -103,7 +101,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(
Timber.w("Event has no room id ${event.eventId}")
return
}
val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId ?: "")
val isLocalEcho = LocalEcho.isLocalEchoId(event.eventId)
when (event.type) {
EventType.REACTION -> {
// we got a reaction!!

View File

@ -19,11 +19,9 @@ package org.matrix.android.sdk.internal.session.room.aggregation.livelocation
import android.content.Context
import androidx.work.WorkerParameters
import com.squareup.moshi.JsonClass
import io.realm.RealmConfiguration
import org.matrix.android.sdk.api.util.md5
import org.matrix.android.sdk.internal.SessionManager
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.awaitTransaction
import org.matrix.android.sdk.internal.database.model.livelocation.LiveLocationShareAggregatedSummaryEntity
import org.matrix.android.sdk.internal.database.query.get
import org.matrix.android.sdk.internal.di.SessionDatabase

View File

@ -17,8 +17,6 @@
package org.matrix.android.sdk.internal.session.room.aggregation.livelocation
import androidx.work.ExistingWorkPolicy
import io.realm.Realm
import io.realm.RealmList
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.ext.realmListOf
import org.matrix.android.sdk.api.extensions.orTrue

View File

@ -16,7 +16,6 @@
package org.matrix.android.sdk.internal.session.room.aggregation.poll
import io.realm.Realm
import io.realm.kotlin.MutableRealm
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.Session

View File

@ -175,6 +175,7 @@ internal class DefaultCreateLocalRoomTask @Inject constructor(
}
chunkEntity.addTimelineEvent(
realm = realm,
roomId = roomId,
eventEntity = eventEntity,
direction = PaginationDirection.FORWARDS,

View File

@ -113,7 +113,7 @@ internal class DefaultLocationSharingService @AssistedInject constructor(
}
override fun getRunningLiveLocationShareSummaries(): LiveData<List<LiveLocationShareAggregatedSummary>> {
return realmInstance.queryList(liveLocationShareAggregatedSummaryMapper) {
return realmInstance.queryList(liveLocationShareAggregatedSummaryMapper::map) {
LiveLocationShareAggregatedSummaryEntity.findRunningLiveInRoom(it, roomId = roomId)
}.asLiveData()
}

View File

@ -34,7 +34,6 @@ import org.matrix.android.sdk.internal.database.helper.findLatestSessionInfo
import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.RoomMembersLoadStatusType
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.di.UserId
@ -103,9 +102,9 @@ internal class DefaultMembershipService @AssistedInject constructor(
private fun roomMembersQuery(realm: TypedRealm, queryParams: RoomMemberQueryParams): RealmQuery<RoomMemberSummaryEntity> {
return with(queryStringValueProcessor) {
RoomMemberHelper(realm, roomId).queryRoomMembersEvent()
.process(RoomMemberSummaryEntityFields.USER_ID, queryParams.userId)
.process(RoomMemberSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
.process(RoomMemberSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
.process("userId", queryParams.userId)
.process("membershipStr", queryParams.memberships)
.process("displayName", queryParams.displayName)
.apply {
if (queryParams.excludeSelf) {
query("userId != $0", userId)

View File

@ -16,7 +16,6 @@
package org.matrix.android.sdk.internal.session.room.membership
import io.realm.Realm
import io.realm.kotlin.TypedRealm
import org.matrix.android.sdk.api.MatrixConfiguration
import org.matrix.android.sdk.api.extensions.orFalse
@ -29,7 +28,6 @@ import org.matrix.android.sdk.internal.database.mapper.ContentMapper
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.model.RoomEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
import org.matrix.android.sdk.internal.database.query.getOrNull
import org.matrix.android.sdk.internal.database.query.where
@ -78,7 +76,6 @@ internal class RoomDisplayNameResolver @Inject constructor(
}
val roomMembers = RoomMemberHelper(realm, roomId)
val activeMembers = roomMembers.queryActiveRoomMembersEvent().find()
if (roomEntity?.membership == Membership.INVITE) {
val inviteMeEvent = roomMembers.getLastStateEvent(userId)

View File

@ -24,15 +24,14 @@ internal object RoomMemberEntityFactory {
fun create(roomId: String, userId: String, roomMember: RoomMemberContent, presence: UserPresenceEntity?): RoomMemberSummaryEntity {
val primaryKey = "${roomId}_$userId"
return RoomMemberSummaryEntity(
primaryKey = primaryKey,
userId = userId,
roomId = roomId,
displayName = roomMember.displayName,
avatarUrl = roomMember.avatarUrl
).apply {
membership = roomMember.membership
userPresenceEntity = presence
return RoomMemberSummaryEntity().apply {
this.primaryKey = primaryKey
this.userId = userId
this.roomId = roomId
this.displayName = roomMember.displayName
this.avatarUrl = roomMember.avatarUrl
this.membership = roomMember.membership
this.userPresenceEntity = presence
}
}
}

View File

@ -153,6 +153,7 @@ internal class DefaultFetchThreadTimelineTask @Inject constructor(
val eventEntity = createEventEntity(params.roomId, event, this)
roomMemberContentsByUser.addSenderState(this, params.roomId, event.senderId)
threadChunk.addTimelineEvent(
realm = this,
roomId = params.roomId,
eventEntity = eventEntity,
direction = PaginationDirection.FORWARDS,
@ -177,6 +178,7 @@ internal class DefaultFetchThreadTimelineTask @Inject constructor(
val eventEntity = createEventEntity(params.roomId, threadRootEvent, this)
roomMemberContentsByUser.addSenderState(this, params.roomId, threadRootEvent.senderId)
threadChunk.addTimelineEvent(
realm = this,
roomId = params.roomId,
eventEntity = eventEntity,
direction = PaginationDirection.FORWARDS,

View File

@ -19,14 +19,11 @@ package org.matrix.android.sdk.internal.session.room.send
import android.content.Context
import androidx.work.WorkerParameters
import com.squareup.moshi.JsonClass
import io.realm.RealmConfiguration
import org.matrix.android.sdk.api.failure.shouldBeRetried
import org.matrix.android.sdk.api.session.crypto.CryptoService
import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.internal.SessionManager
import org.matrix.android.sdk.internal.crypto.tasks.SendEventTask
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.session.SessionComponent
import org.matrix.android.sdk.internal.util.toMatrixErrorStr
import org.matrix.android.sdk.internal.worker.SessionSafeCoroutineWorker

View File

@ -29,7 +29,6 @@ import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.andIf
import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
import org.matrix.android.sdk.internal.database.queryIn
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.query.QueryStringValueProcessor
@ -92,7 +91,7 @@ internal class StateEventDataSource @Inject constructor(
queryIn("type", eventTypes.toList())
}
// It's OK to cast stateKey as QueryStringValue
.process(CurrentStateEventEntityFields.STATE_KEY, stateKey as QueryStringValue)
.process("stateKey", stateKey as QueryStringValue)
}
}
}

View File

@ -21,11 +21,11 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.asLiveData
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
import io.realm.kotlin.TypedRealm
import io.realm.kotlin.query.RealmQuery
import io.realm.kotlin.query.sum
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.map
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.query.RoomCategoryFilter
@ -44,9 +44,9 @@ import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotification
import org.matrix.android.sdk.api.session.space.SpaceSummaryQueryParams
import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.RealmQueryBuilder
import org.matrix.android.sdk.internal.database.mapper.RoomSummaryMapper
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.database.query.findByAlias
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.database.queryIn
@ -185,36 +185,32 @@ internal class RoomSummaryDataSource @Inject constructor(
pagedListConfig: PagedList.Config,
sortOrder: RoomSortOrder,
): UpdatableLivePageResult {
val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
roomSummariesQuery(realm, queryParams).process(sortOrder)
}
val dataSourceFactory = realmDataSourceFactory.map {
roomSummaryMapper.map(it)
}
val boundaries = MutableLiveData(ResultBoundaries())
val boundaryCallback = object : PagedList.BoundaryCallback<RoomSummary>() {
override fun onItemAtEndLoaded(itemAtEnd: RoomSummary) {
boundaries.postValue(boundaries.value?.copy(frontLoaded = true))
}
val mapped = monarchy.findAllPagedWithChanges(
realmDataSourceFactory,
LivePagedListBuilder(dataSourceFactory, pagedListConfig).also {
it.setBoundaryCallback(object : PagedList.BoundaryCallback<RoomSummary>() {
override fun onItemAtEndLoaded(itemAtEnd: RoomSummary) {
boundaries.postValue(boundaries.value?.copy(frontLoaded = true))
}
override fun onItemAtFrontLoaded(itemAtFront: RoomSummary) {
boundaries.postValue(boundaries.value?.copy(endLoaded = true))
}
override fun onItemAtFrontLoaded(itemAtFront: RoomSummary) {
boundaries.postValue(boundaries.value?.copy(endLoaded = true))
}
override fun onZeroItemsLoaded() {
boundaries.postValue(boundaries.value?.copy(zeroItemLoaded = true))
}
}
override fun onZeroItemsLoaded() {
boundaries.postValue(boundaries.value?.copy(zeroItemLoaded = true))
}
})
}
)
fun queryBuilder(queryParams: RoomSummaryQueryParams) = RealmQueryBuilder {
roomSummariesQuery(it, queryParams).process(sortOrder)
}
val liveQueryBuilder = MutableStateFlow(queryBuilder((queryParams)))
val livePagedList = realmInstance.queryUpdatablePagedList(pagedListConfig, roomSummaryMapper::map, boundaryCallback, liveQueryBuilder).asLiveData()
return object : UpdatableLivePageResult {
override val livePagedList: LiveData<PagedList<RoomSummary>> = mapped
override val livePagedList: LiveData<PagedList<RoomSummary>> = livePagedList
override val liveBoundaries: LiveData<ResultBoundaries>
get() = boundaries
@ -222,9 +218,7 @@ internal class RoomSummaryDataSource @Inject constructor(
override var queryParams: RoomSummaryQueryParams = queryParams
set(value) {
field = value
realmDataSourceFactory.updateQuery {
roomSummariesQuery(it, value).process(sortOrder)
}
liveQueryBuilder.tryEmit(queryBuilder(value))
}
}
}
@ -251,10 +245,10 @@ internal class RoomSummaryDataSource @Inject constructor(
private fun roomSummariesQuery(realm: TypedRealm, queryParams: RoomSummaryQueryParams): RealmQuery<RoomSummaryEntity> {
var query = with(queryStringValueProcessor) {
RoomSummaryEntity.where(realm)
.process(RoomSummaryEntityFields.ROOM_ID, QueryStringValue.IsNotEmpty)
.process("roomId", QueryStringValue.IsNotEmpty)
.process(queryParams.displayName.toDisplayNameField(), queryParams.displayName)
.process(RoomSummaryEntityFields.CANONICAL_ALIAS, queryParams.canonicalAlias)
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
.process("canonicalAlias", queryParams.canonicalAlias)
.process("membershipStr", queryParams.memberships)
.query("isHiddenFromUser == false")
}
@ -302,9 +296,9 @@ internal class RoomSummaryDataSource @Inject constructor(
private fun QueryStringValue.toDisplayNameField(): String {
return if (isNormalized()) {
RoomSummaryEntityFields.NORMALIZED_DISPLAY_NAME
"normalizedDisplayName"
} else {
RoomSummaryEntityFields.DISPLAY_NAME
"displayName"
}
}

View File

@ -46,7 +46,6 @@ import org.matrix.android.sdk.internal.database.mapper.ContentMapper
import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.SpaceChildSummaryEntity
import org.matrix.android.sdk.internal.database.model.SpaceParentSummaryEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
@ -251,7 +250,7 @@ internal class RoomSummaryUpdater @Inject constructor(
)
RoomSummaryEntity.where(realm, child.roomId)
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships())
.process("membershipStr", Membership.activeMemberships())
.first()
.find()
?.let { childSum ->
@ -317,7 +316,7 @@ internal class RoomSummaryUpdater @Inject constructor(
)
RoomSummaryEntity.where(realm, parentInfo.roomId)
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships())
.process("membershipStr", Membership.activeMemberships())
.first()
.find()
?.let { parentSum ->
@ -385,7 +384,7 @@ internal class RoomSummaryUpdater @Inject constructor(
// it's more annoying as based on if the other members belong the space or not
RoomSummaryEntity.where(realm)
.query("isDirect == true")
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships())
.process("membershipStr", Membership.activeMemberships())
.find()
.forEach { dmRoom ->
val relatedSpaces = lookupMap.keys
@ -411,14 +410,14 @@ internal class RoomSummaryUpdater @Inject constructor(
// Maybe a good place to count the number of notifications for spaces?
realm.query(RoomSummaryEntity::class)
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, Membership.activeMemberships())
.process("membershipStr", Membership.activeMemberships())
.query("roomType == $0", RoomType.SPACE)
.find().forEach { space ->
// get all children
var highlightCount = 0
var notificationCount = 0
realm.query(RoomSummaryEntity::class)
.process(RoomSummaryEntityFields.MEMBERSHIP_STR, listOf(Membership.JOIN))
.process("membershipStr", listOf(Membership.JOIN))
.query("roomType != $0", RoomType.SPACE)
.query("ANY flattenParentIds == $0", space.roomId)
.find().forEach {

View File

@ -16,9 +16,6 @@
package org.matrix.android.sdk.internal.session.room.timeline
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.kotlin.TypedRealm
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
@ -32,7 +29,6 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.internal.closeQuietly
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.room.model.Membership

View File

@ -17,7 +17,6 @@
package org.matrix.android.sdk.internal.session.room.timeline
import androidx.lifecycle.LiveData
import com.zhuinden.monarchy.Monarchy
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject

View File

@ -43,9 +43,7 @@ import org.matrix.android.sdk.api.settings.LightweightSettingsStorage
import org.matrix.android.sdk.internal.database.mapper.EventMapper
import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper
import org.matrix.android.sdk.internal.database.model.ChunkEntity
import org.matrix.android.sdk.internal.database.model.ChunkEntityFields
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
import org.matrix.android.sdk.internal.database.query.whereChunkId
import org.matrix.android.sdk.internal.session.room.relation.threads.DefaultFetchThreadTimelineTask
import org.matrix.android.sdk.internal.session.room.relation.threads.FetchThreadTimelineTask
@ -469,19 +467,19 @@ internal class TimelineChunk(
fun onChunkUpdated(updatedObject: UpdatedObject<ChunkEntity>) {
Timber.v("on chunk (${chunkEntity.identifier()}) changed: ${updatedObject.changedFields.joinToString(",")}")
if (updatedObject.isFieldChanged(ChunkEntityFields.IS_LAST_FORWARD)) {
if (updatedObject.isFieldChanged("isLastForward")) {
isLastForward.set(chunkEntity.isLastForward)
}
if (updatedObject.isFieldChanged(ChunkEntityFields.IS_LAST_BACKWARD)) {
if (updatedObject.isFieldChanged("isLastBackward")) {
isLastBackward.set(chunkEntity.isLastBackward)
}
if (updatedObject.isFieldChanged(ChunkEntityFields.NEXT_CHUNK.`$`)) {
if (updatedObject.isFieldChanged("nextChunk")) {
nextChunk = createTimelineChunk(chunkEntity.nextChunk).also {
it?.prevChunk = this
}
nextChunkLatch?.complete(Unit)
}
if (updatedObject.isFieldChanged(ChunkEntityFields.PREV_CHUNK.`$`)) {
if (updatedObject.isFieldChanged("prevChunk")) {
prevChunk = createTimelineChunk(chunkEntity.prevChunk).also {
it?.nextChunk = this
}
@ -507,7 +505,7 @@ internal class TimelineChunk(
if (isLastForward.get()) {
val firstBuiltEvent = builtEvents.firstOrNull()
if (firstBuiltEvent != null) {
val lastInsertion = results[range.startIndex + range.length - 1] ?: return false
val lastInsertion = results.getOrNull(range.startIndex + range.length - 1) ?: return false
if (firstBuiltEvent.displayIndex + 1 != lastInsertion.displayIndex) {
Timber.v("There is no continuation in the chunk, chunk is not fully loaded yet, skip insert.")
return false
@ -539,7 +537,7 @@ internal class TimelineChunk(
val modifications = updatedResults.changeRanges
for (range in modifications) {
for (modificationIndex in (range.startIndex until range.startIndex + range.length)) {
val updatedEntity = results[modificationIndex] ?: continue
val updatedEntity = results.getOrNull(modificationIndex) ?: continue
val builtEventIndex = builtEventsIndexes[updatedEntity.eventId] ?: continue
try {
builtEvents[builtEventIndex] = updatedEntity.buildAndDecryptIfNeeded()
@ -624,13 +622,13 @@ private fun RealmQuery<TimelineEventEntity>.offsets(
): RealmQuery<TimelineEventEntity> {
return if (direction == Timeline.Direction.BACKWARDS) {
query("displayIndex <= $0", startDisplayIndex)
.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING)
.sort("displayIndex", Sort.DESCENDING)
.limit(count)
} else {
query("displayIndex >= $0", startDisplayIndex)
.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.ASCENDING)
.sort("displayIndex", Sort.ASCENDING)
.limit(count)
.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING)
.sort("displayIndex", Sort.DESCENDING)
}
}

View File

@ -24,7 +24,6 @@ import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.database.query.whereRoomId
import org.matrix.android.sdk.internal.di.SessionDatabase
@ -51,7 +50,7 @@ internal class TimelineEventDataSource @Inject constructor(
val realm = realmInstance.getBlockingRealm()
return TimelineEventEntity.whereRoomId(realm, roomId)
.sort("root.originServerTs", io.realm.kotlin.query.Sort.ASCENDING)
.distinct(TimelineEventEntityFields.EVENT_ID)
.distinct("eventId")
.find()
.mapNotNull { timelineEventMapper.map(it).takeIf { it.root.isImageMessage() || it.root.isVideoMessage() } }
}

View File

@ -28,7 +28,6 @@ import org.matrix.android.sdk.api.session.room.uploads.UploadEvent
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.model.EventEntity
import org.matrix.android.sdk.internal.database.model.EventEntityFields
import org.matrix.android.sdk.internal.database.query.TimelineEventFilter
import org.matrix.android.sdk.internal.database.query.whereType
import org.matrix.android.sdk.internal.di.SessionDatabase
@ -75,7 +74,7 @@ internal class DefaultGetUploadsTask @Inject constructor(
events = EventEntity.whereType(realm, EventType.ENCRYPTED, params.roomId)
.query("decryptionResultJson LIKE $0", TimelineEventFilter.DecryptedContent.URL)
.sort(EventEntityFields.ORIGIN_SERVER_TS, Sort.DESCENDING)
.sort("originServerTs", Sort.DESCENDING)
.find()
.map { it.asDomain() }
// Exclude stickers
@ -96,13 +95,11 @@ internal class DefaultGetUploadsTask @Inject constructor(
events = chunk.events
}
var uploadEvents = listOf<UploadEvent>()
val cacheOfSenderInfos = mutableMapOf<String, SenderInfo>()
// Get a snapshot of all room members
val roomMemberHelper = RoomMemberHelper(realm, params.roomId)
uploadEvents = events.mapNotNull { event ->
val uploadEvents = events.mapNotNull { event ->
val eventId = event.eventId ?: return@mapNotNull null
val messageContent = event.getClearContent()?.toModel<MessageContent>() ?: return@mapNotNull null
val messageWithAttachmentContent = (messageContent as? MessageWithAttachmentContent) ?: return@mapNotNull null

View File

@ -19,10 +19,11 @@ package org.matrix.android.sdk.internal.session.search
import org.matrix.android.sdk.api.session.search.EventAndSender
import org.matrix.android.sdk.api.session.search.SearchResult
import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.internal.database.RealmSessionProvider
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.session.search.request.SearchRequestBody
@ -53,7 +54,7 @@ internal interface SearchTask : Task<SearchTask.Params, SearchResult> {
internal class DefaultSearchTask @Inject constructor(
private val searchAPI: SearchAPI,
private val globalErrorReceiver: GlobalErrorReceiver,
private val realmSessionProvider: RealmSessionProvider
@SessionDatabase private val realmInstance: RealmInstance
) : SearchTask {
override suspend fun execute(params: SearchTask.Params): SearchResult {
@ -79,7 +80,7 @@ internal class DefaultSearchTask @Inject constructor(
}.toDomain()
}
private fun SearchResponse.toDomain(): SearchResult {
private suspend fun SearchResponse.toDomain(): SearchResult {
val localTimelineEvents = findRootThreadEventsFromDB(searchCategories.roomEvents?.results)
return SearchResult(
nextBatch = searchCategories.roomEvents?.nextBatch,
@ -114,15 +115,14 @@ internal class DefaultSearchTask @Inject constructor(
/**
* Find local events if exists in order to enhance the result with thread summary.
*/
private fun findRootThreadEventsFromDB(searchResponseItemList: List<SearchResponseItem>?): List<TimelineEventEntity>? {
return realmSessionProvider.withRealm { realm ->
searchResponseItemList?.mapNotNull {
private suspend fun findRootThreadEventsFromDB(searchResponseItemList: List<SearchResponseItem>?): List<TimelineEventEntity>? {
val realm = realmInstance.getRealm()
return searchResponseItemList?.mapNotNull {
it.event.roomId ?: return@mapNotNull null
it.event.eventId ?: return@mapNotNull null
TimelineEventEntity.where(realm, it.event.roomId, it.event.eventId).findFirst()
TimelineEventEntity.where(realm, it.event.roomId, it.event.eventId).first().find()
}?.filter {
it.root?.isRootThread == true || it.root?.isThread() == true
}
}
}
}

View File

@ -54,8 +54,8 @@ internal class PresenceSyncHandler @Inject constructor(private val matrixConfigu
* Store user presence to DB and update Direct Rooms and Room Member Summaries accordingly.
*/
private fun storePresenceToDB(realm: MutableRealm, userPresenceEntity: UserPresenceEntity) =
realm.copyToRealm(userPresenceEntity, updatePolicy = UpdatePolicy.ALL)?.also {
RoomSummaryEntity.updateDirectUserPresence(realm, userPresenceEntity.userId, this)
RoomMemberSummaryEntity.updateUserPresence(realm, userPresenceEntity.userId, this)
realm.copyToRealm(userPresenceEntity, updatePolicy = UpdatePolicy.ALL).also {
RoomSummaryEntity.updateDirectUserPresence(realm, userPresenceEntity.userId, it)
RoomMemberSummaryEntity.updateUserPresence(realm, userPresenceEntity.userId, it)
}
}

View File

@ -21,9 +21,7 @@ import io.realm.kotlin.UpdatePolicy
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.internal.database.model.ReadReceiptEntity
import org.matrix.android.sdk.internal.database.model.ReadReceiptsSummaryEntity
import org.matrix.android.sdk.internal.database.query.createUnmanaged
import org.matrix.android.sdk.internal.database.query.getOrCreate
import org.matrix.android.sdk.internal.database.query.readReceiptSummaryEntityQueries
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.session.sync.RoomSyncEphemeralTemporaryStore
import org.matrix.android.sdk.internal.session.sync.SyncResponsePostTreatmentAggregator
@ -134,16 +132,17 @@ internal class ReadReceiptHandler @Inject constructor(
for ((eventId, receiptDict) in content) {
val userIdsDict = receiptDict[READ_KEY] ?: continue
val readReceiptsSummary = ReadReceiptsSummaryEntity.where(realm, eventId).find()
?: realm.createObject(ReadReceiptsSummaryEntity::class.java, eventId).apply {
?: realm.copyToRealm(ReadReceiptsSummaryEntity().apply {
this.eventId = eventId
this.roomId = roomId
}
})
for ((userId, paramsDict) in userIdsDict) {
val ts = paramsDict[TIMESTAMP_KEY] ?: 0.0
val receiptEntity = ReadReceiptEntity.getOrCreate(realm, roomId, userId)
// ensure new ts is superior to the previous one
if (ts > receiptEntity.originServerTs) {
ReadReceiptsSummaryEntity.where(realm, receiptEntity.eventId).findFirst()?.also {
ReadReceiptsSummaryEntity.where(realm, receiptEntity.eventId).find()?.also {
it.readReceipts.remove(receiptEntity)
}
receiptEntity.eventId = eventId

View File

@ -183,9 +183,9 @@ internal class RoomSyncHandler @Inject constructor(
handlingStrategy.data.keys
.chunked(bestChunkSize.chunkSize)
.forEachIndexed { index, roomIds ->
val roomEntities = roomIds
roomIds
.also { Timber.d("INIT_SYNC insert ${roomIds.size} rooms") }
.map {
.forEach {
handleJoinedRoom(
realm = realm,
roomId = it,

View File

@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.session.sync.handler.room
import io.realm.kotlin.MutableRealm
import io.realm.kotlin.TypedRealm
import io.realm.kotlin.where
import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult
import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.events.model.Event
@ -44,7 +43,6 @@ import org.matrix.android.sdk.internal.database.mapper.EventMapper
import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.mapper.toEntity
import org.matrix.android.sdk.internal.database.model.EventEntity
import org.matrix.android.sdk.internal.database.model.EventEntityFields
import org.matrix.android.sdk.internal.database.model.EventInsertType
import org.matrix.android.sdk.internal.database.query.copyToRealmOrIgnore
import org.matrix.android.sdk.internal.database.query.where
@ -53,7 +51,6 @@ import org.matrix.android.sdk.internal.di.SessionDatabase
import org.matrix.android.sdk.internal.session.permalinks.PermalinkFactory
import org.matrix.android.sdk.internal.session.room.send.LocalEchoEventFactory
import org.matrix.android.sdk.internal.session.room.timeline.GetEventTask
import org.matrix.android.sdk.internal.util.awaitTransaction
import org.matrix.android.sdk.internal.util.time.Clock
import javax.inject.Inject
@ -253,7 +250,7 @@ internal class ThreadsAwarenessHandler @Inject constructor(
): String? {
event.eventId ?: return null
val rootThreadEventId = if (isFromCache) event.eventId else event.getRootThreadEventId() ?: return null
eventThatRelatesTo(realm, event.eventId, rootThreadEventId)?.forEach { eventEntityFound ->
eventThatRelatesTo(realm, event.eventId, rootThreadEventId).forEach { eventEntityFound ->
val newEventFound = eventEntityFound.asDomain()
val newEventBody = newEventFound.getDecryptedTextSummary() ?: return null
val newEventPayload = newEventFound.mxDecryptionResult?.payload?.toMutableMap() ?: return null

View File

@ -16,7 +16,6 @@
package org.matrix.android.sdk.internal.session.sync.parsing
import io.realm.Realm
import io.realm.kotlin.MutableRealm
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataTypes
@ -25,7 +24,6 @@ import org.matrix.android.sdk.api.session.sync.model.RoomSyncAccountData
import org.matrix.android.sdk.api.util.JsonDict
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
import org.matrix.android.sdk.internal.database.model.RoomAccountDataEntity
import org.matrix.android.sdk.internal.database.model.RoomAccountDataEntityFields
import org.matrix.android.sdk.internal.database.model.RoomEntity
import org.matrix.android.sdk.internal.database.query.getOrCreate
import org.matrix.android.sdk.internal.session.room.read.FullyReadContent
@ -57,14 +55,16 @@ internal class RoomSyncAccountDataHandler @Inject constructor(
}
private fun handleGeneric(roomEntity: RoomEntity, content: JsonDict?, eventType: String) {
val existing = roomEntity.accountData.where().equalTo(RoomAccountDataEntityFields.TYPE, eventType).findFirst()
val existing = roomEntity.accountData.firstOrNull {
it.type == eventType
}
if (existing != null) {
existing.contentStr = ContentMapper.map(content)
} else {
val roomAccountData = RoomAccountDataEntity(
type = eventType,
contentStr = ContentMapper.map(content)
)
val roomAccountData = RoomAccountDataEntity().apply {
this.type = eventType
this.contentStr = ContentMapper.map(content)
}
roomEntity.accountData.add(roomAccountData)
}
}

View File

@ -24,9 +24,7 @@ import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.internal.database.RealmInstance
import org.matrix.android.sdk.internal.database.mapper.asDomain
import org.matrix.android.sdk.internal.database.model.IgnoredUserEntity
import org.matrix.android.sdk.internal.database.model.IgnoredUserEntityFields
import org.matrix.android.sdk.internal.database.model.UserEntity
import org.matrix.android.sdk.internal.database.model.UserEntityFields
import org.matrix.android.sdk.internal.database.query.where
import org.matrix.android.sdk.internal.database.queryNotIn
import org.matrix.android.sdk.internal.di.SessionDatabase
@ -82,7 +80,7 @@ internal class UserDataSource @Inject constructor(
?.let {
query = query.queryNotIn("userId", it)
}
query.sort(UserEntityFields.DISPLAY_NAME)
query.sort("displayName")
}.asLiveData()
}
@ -95,7 +93,7 @@ internal class UserDataSource @Inject constructor(
return realmInstance.queryList(::mapper) { realm ->
realm.query(IgnoredUserEntity::class)
.query("userId != ''")
.sort(IgnoredUserEntityFields.USER_ID)
.sort("userId")
}.asLiveData()
}
}

View File

@ -23,18 +23,18 @@ import org.matrix.android.sdk.internal.database.model.UserEntity
internal object UserEntityFactory {
fun create(userId: String, roomMember: RoomMemberContent): UserEntity {
return UserEntity(
userId = userId,
displayName = roomMember.displayName.orEmpty(),
avatarUrl = roomMember.avatarUrl.orEmpty()
)
return UserEntity().apply {
this.userId = userId
this.displayName = roomMember.displayName.orEmpty()
this.avatarUrl = roomMember.avatarUrl.orEmpty()
}
}
fun create(user: User): UserEntity {
return UserEntity(
userId = user.userId,
displayName = user.displayName.orEmpty(),
avatarUrl = user.avatarUrl.orEmpty()
)
return UserEntity().apply {
this.userId = user.userId
this.displayName = user.displayName.orEmpty()
this.avatarUrl = user.avatarUrl.orEmpty()
}
}
}

View File

@ -17,7 +17,6 @@
package org.matrix.android.sdk.internal.session.user.accountdata
import androidx.lifecycle.LiveData
import com.zhuinden.monarchy.Monarchy
import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataEvent
import org.matrix.android.sdk.api.session.events.model.Content

View File

@ -1,49 +0,0 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.util
import com.zhuinden.monarchy.Monarchy
import io.realm.Realm
import io.realm.RealmModel
import org.matrix.android.sdk.internal.database.awaitTransaction
import java.util.concurrent.atomic.AtomicReference
internal suspend fun <T> Monarchy.awaitTransaction(transaction: suspend (realm: Realm) -> T): T {
return awaitTransaction(realmConfiguration, transaction)
}
internal fun <T : RealmModel> Monarchy.fetchCopied(query: (Realm) -> T?): T? {
val ref = AtomicReference<T>()
doWithRealm { realm ->
val result = query.invoke(realm)?.let {
realm.copyFromRealm(it)
}
ref.set(result)
}
return ref.get()
}
internal fun <U, T : RealmModel> Monarchy.fetchCopyMap(query: (Realm) -> T?, map: (T, realm: Realm) -> U): U? {
val ref = AtomicReference<U?>()
doWithRealm { realm ->
val result = query.invoke(realm)?.let {
map(realm.copyFromRealm(it), realm)
}
ref.set(result)
}
return ref.get()
}

View File

@ -1,37 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.util.database
import io.realm.DynamicRealm
import io.realm.RealmMigration
import timber.log.Timber
import kotlin.system.measureTimeMillis
internal abstract class MatrixRealmMigration(
private val dbName: String,
val schemaVersion: Long,
) : RealmMigration {
final override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
Timber.d("Migrating Realm $dbName from $oldVersion to $newVersion")
val duration = measureTimeMillis {
doMigrate(realm, oldVersion)
}
Timber.d("Migrating Realm $dbName from $oldVersion to $newVersion took $duration ms.")
}
abstract fun doMigrate(realm: DynamicRealm, oldVersion: Long)
}

View File

@ -1,58 +0,0 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.util.database
import io.realm.DynamicRealm
import io.realm.RealmObjectSchema
import timber.log.Timber
import kotlin.system.measureTimeMillis
internal abstract class RealmMigrator(
private val realm: DynamicRealm,
private val targetSchemaVersion: Int
) {
fun perform() {
Timber.d("Migrate ${realm.configuration.realmFileName} to $targetSchemaVersion")
val duration = measureTimeMillis {
doMigrate(realm)
}
Timber.d("Migrate ${realm.configuration.realmFileName} to $targetSchemaVersion took $duration ms.")
}
abstract fun doMigrate(realm: DynamicRealm)
protected fun RealmObjectSchema.addFieldIfNotExists(fieldName: String, fieldType: Class<*>): RealmObjectSchema {
if (!hasField(fieldName)) {
addField(fieldName, fieldType)
}
return this
}
protected fun RealmObjectSchema.removeFieldIfExists(fieldName: String): RealmObjectSchema {
if (hasField(fieldName)) {
removeField(fieldName)
}
return this
}
protected fun RealmObjectSchema.setRequiredIfNotAlready(fieldName: String, isRequired: Boolean): RealmObjectSchema {
if (isRequired != isRequired(fieldName)) {
setRequired(fieldName, isRequired)
}
return this
}
}

View File

@ -20,17 +20,13 @@ import android.content.Context
import com.facebook.flipper.android.AndroidFlipperClient
import com.facebook.flipper.android.utils.FlipperUtils
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin
import com.facebook.flipper.plugins.inspector.DescriptorMapping
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin
import com.facebook.soloader.SoLoader
import com.kgurgul.flipper.RealmDatabaseDriver
import com.kgurgul.flipper.RealmDatabaseProvider
import im.vector.app.core.debug.FlipperProxy
import io.realm.RealmConfiguration
import org.matrix.android.sdk.api.Matrix
import javax.inject.Inject
import javax.inject.Singleton
@ -50,6 +46,7 @@ class VectorFlipperProxy @Inject constructor(
client.addPlugin(SharedPreferencesFlipperPlugin(context))
client.addPlugin(InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()))
client.addPlugin(networkFlipperPlugin)
/*
client.addPlugin(
DatabasesFlipperPlugin(
RealmDatabaseDriver(
@ -61,6 +58,7 @@ class VectorFlipperProxy @Inject constructor(
})
)
)
*/
client.start()
}
}

View File

@ -151,12 +151,8 @@ class RoomMemberProfileViewModel @AssistedInject constructor(
ignored.find {
it.userId == initialState.userId
} != null
}
.map {
}
.execute {
it
copy(isIgnored = it)
}
}