adding normalised room display name field and making use of it when filtering rooms by name
- fixes non latin-1 character set room names from being ignored when searching with inexact casing
This commit is contained in:
parent
d5ed95988d
commit
4ae04fc297
|
@ -39,4 +39,6 @@ sealed interface QueryStringValue {
|
||||||
INSENSITIVE,
|
INSENSITIVE,
|
||||||
NORMALIZED
|
NORMALIZED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isNormalized() = this is ContentQueryStringValue && case == Case.NORMALIZED
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,11 +45,17 @@ import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
|
||||||
import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntityFields
|
import org.matrix.android.sdk.internal.database.model.presence.UserPresenceEntityFields
|
||||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
import org.matrix.android.sdk.internal.query.process
|
import org.matrix.android.sdk.internal.query.process
|
||||||
|
import org.matrix.android.sdk.internal.util.Normalizer
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal object RealmSessionStoreMigration : RealmMigration {
|
internal class RealmSessionStoreMigration @Inject constructor(
|
||||||
|
private val normalizer: Normalizer
|
||||||
|
) : RealmMigration {
|
||||||
|
|
||||||
const val SESSION_STORE_SCHEMA_VERSION = 18L
|
companion object {
|
||||||
|
const val SESSION_STORE_SCHEMA_VERSION = 19L
|
||||||
|
}
|
||||||
|
|
||||||
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
||||||
Timber.v("Migrating Realm Session from $oldVersion to $newVersion")
|
Timber.v("Migrating Realm Session from $oldVersion to $newVersion")
|
||||||
|
@ -72,6 +78,7 @@ internal object RealmSessionStoreMigration : RealmMigration {
|
||||||
if (oldVersion <= 15) migrateTo16(realm)
|
if (oldVersion <= 15) migrateTo16(realm)
|
||||||
if (oldVersion <= 16) migrateTo17(realm)
|
if (oldVersion <= 16) migrateTo17(realm)
|
||||||
if (oldVersion <= 17) migrateTo18(realm)
|
if (oldVersion <= 17) migrateTo18(realm)
|
||||||
|
if (oldVersion <= 18) migrateTo19(realm)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun migrateTo1(realm: DynamicRealm) {
|
private fun migrateTo1(realm: DynamicRealm) {
|
||||||
|
@ -364,4 +371,16 @@ internal object RealmSessionStoreMigration : RealmMigration {
|
||||||
realm.schema.get("RoomMemberSummaryEntity")
|
realm.schema.get("RoomMemberSummaryEntity")
|
||||||
?.addRealmObjectField(RoomMemberSummaryEntityFields.USER_PRESENCE_ENTITY.`$`, userPresenceEntity)
|
?.addRealmObjectField(RoomMemberSummaryEntityFields.USER_PRESENCE_ENTITY.`$`, userPresenceEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun migrateTo19(realm: DynamicRealm) {
|
||||||
|
Timber.d("Step 18 -> 19")
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ private const val REALM_NAME = "disk_store.realm"
|
||||||
*/
|
*/
|
||||||
internal class SessionRealmConfigurationFactory @Inject constructor(
|
internal class SessionRealmConfigurationFactory @Inject constructor(
|
||||||
private val realmKeysUtils: RealmKeysUtils,
|
private val realmKeysUtils: RealmKeysUtils,
|
||||||
|
private val realmSessionStoreMigration: RealmSessionStoreMigration,
|
||||||
@SessionFilesDirectory val directory: File,
|
@SessionFilesDirectory val directory: File,
|
||||||
@SessionId val sessionId: String,
|
@SessionId val sessionId: String,
|
||||||
@UserMd5 val userMd5: String,
|
@UserMd5 val userMd5: String,
|
||||||
|
@ -71,7 +72,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor(
|
||||||
.allowWritesOnUiThread(true)
|
.allowWritesOnUiThread(true)
|
||||||
.modules(SessionRealmModule())
|
.modules(SessionRealmModule())
|
||||||
.schemaVersion(RealmSessionStoreMigration.SESSION_STORE_SCHEMA_VERSION)
|
.schemaVersion(RealmSessionStoreMigration.SESSION_STORE_SCHEMA_VERSION)
|
||||||
.migration(RealmSessionStoreMigration)
|
.migration(realmSessionStoreMigration)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
// Try creating a realm instance and if it succeeds we can clear the flag
|
// Try creating a realm instance and if it succeeds we can clear the flag
|
||||||
|
|
|
@ -40,6 +40,17 @@ internal open class RoomSummaryEntity(
|
||||||
set(value) {
|
set(value) {
|
||||||
if (value != field) field = value
|
if (value != field) field = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Workaround for Realm only supporting Latin-1 character sets when sorting
|
||||||
|
* or filtering by case
|
||||||
|
* See https://github.com/realm/realm-core/issues/777
|
||||||
|
*/
|
||||||
|
var normalizedDisplayName: String? = ""
|
||||||
|
set(value) {
|
||||||
|
if (value != field) field = value
|
||||||
|
}
|
||||||
|
|
||||||
var avatarUrl: String? = ""
|
var avatarUrl: String? = ""
|
||||||
set(value) {
|
set(value) {
|
||||||
if (value != field) field = value
|
if (value != field) field = value
|
||||||
|
@ -284,5 +295,6 @@ internal open class RoomSummaryEntity(
|
||||||
roomEncryptionTrustLevelStr = value?.name
|
roomEncryptionTrustLevelStr = value?.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object
|
companion object
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,7 +245,11 @@ internal class RoomSummaryDataSource @Inject constructor(
|
||||||
val query = with(queryStringValueProcessor) {
|
val query = with(queryStringValueProcessor) {
|
||||||
val query = RoomSummaryEntity.where(realm)
|
val query = RoomSummaryEntity.where(realm)
|
||||||
query.process(RoomSummaryEntityFields.ROOM_ID, queryParams.roomId)
|
query.process(RoomSummaryEntityFields.ROOM_ID, queryParams.roomId)
|
||||||
query.process(RoomSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
|
if (queryParams.displayName.isNormalized()) {
|
||||||
|
query.process(RoomSummaryEntityFields.NORMALIZED_DISPLAY_NAME, queryParams.displayName)
|
||||||
|
} else {
|
||||||
|
query.process(RoomSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
|
||||||
|
}
|
||||||
query.process(RoomSummaryEntityFields.CANONICAL_ALIAS, queryParams.canonicalAlias)
|
query.process(RoomSummaryEntityFields.CANONICAL_ALIAS, queryParams.canonicalAlias)
|
||||||
query.process(RoomSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
|
query.process(RoomSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
|
||||||
query.equalTo(RoomSummaryEntityFields.IS_HIDDEN_FROM_USER, false)
|
query.equalTo(RoomSummaryEntityFields.IS_HIDDEN_FROM_USER, false)
|
||||||
|
|
|
@ -65,6 +65,7 @@ import org.matrix.android.sdk.internal.session.room.accountdata.RoomAccountDataD
|
||||||
import org.matrix.android.sdk.internal.session.room.membership.RoomDisplayNameResolver
|
import org.matrix.android.sdk.internal.session.room.membership.RoomDisplayNameResolver
|
||||||
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
|
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
|
||||||
import org.matrix.android.sdk.internal.session.room.relationship.RoomChildRelationInfo
|
import org.matrix.android.sdk.internal.session.room.relationship.RoomChildRelationInfo
|
||||||
|
import org.matrix.android.sdk.internal.util.Normalizer
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
|
@ -75,7 +76,8 @@ internal class RoomSummaryUpdater @Inject constructor(
|
||||||
private val roomAvatarResolver: RoomAvatarResolver,
|
private val roomAvatarResolver: RoomAvatarResolver,
|
||||||
private val eventDecryptor: EventDecryptor,
|
private val eventDecryptor: EventDecryptor,
|
||||||
private val crossSigningService: DefaultCrossSigningService,
|
private val crossSigningService: DefaultCrossSigningService,
|
||||||
private val roomAccountDataDataSource: RoomAccountDataDataSource) {
|
private val roomAccountDataDataSource: RoomAccountDataDataSource,
|
||||||
|
private val normalizer: Normalizer) {
|
||||||
|
|
||||||
fun update(realm: Realm,
|
fun update(realm: Realm,
|
||||||
roomId: String,
|
roomId: String,
|
||||||
|
@ -136,7 +138,9 @@ internal class RoomSummaryUpdater @Inject constructor(
|
||||||
// avoid this call if we are sure there are unread events
|
// avoid this call if we are sure there are unread events
|
||||||
!isEventRead(realm.configuration, userId, roomId, latestPreviewableEvent?.eventId)
|
!isEventRead(realm.configuration, userId, roomId, latestPreviewableEvent?.eventId)
|
||||||
|
|
||||||
roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(realm, roomId)
|
val roomDisplayName = roomDisplayNameResolver.resolve(realm, roomId)
|
||||||
|
roomSummaryEntity.displayName = roomDisplayName
|
||||||
|
roomSummaryEntity.normalizedDisplayName = normalizer.normalize(roomDisplayName)
|
||||||
roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(realm, roomId)
|
roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(realm, roomId)
|
||||||
roomSummaryEntity.name = ContentMapper.map(lastNameEvent?.content).toModel<RoomNameContent>()?.name
|
roomSummaryEntity.name = ContentMapper.map(lastNameEvent?.content).toModel<RoomNameContent>()?.name
|
||||||
roomSummaryEntity.topic = ContentMapper.map(lastTopicEvent?.content).toModel<RoomTopicContent>()?.topic
|
roomSummaryEntity.topic = ContentMapper.map(lastTopicEvent?.content).toModel<RoomTopicContent>()?.topic
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021 New Vector Ltd
|
* Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
|
|
@ -191,7 +191,7 @@ class RoomListViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
updatableQuery?.updateQuery {
|
updatableQuery?.updateQuery {
|
||||||
it.copy(
|
it.copy(
|
||||||
displayName = QueryStringValue.Contains(action.filter, QueryStringValue.Case.INSENSITIVE)
|
displayName = QueryStringValue.Contains(action.filter, QueryStringValue.Case.NORMALIZED)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue