From ed135bc4fc892b3e610608bf5895903d8f0765fc Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 28 Jul 2022 12:16:05 +0200 Subject: [PATCH] Realm: migrate identity db to realm-kotlin --- .../api/session/identity/IdentityService.kt | 6 +- .../sdk/internal/database/RealmInstance.kt | 2 +- .../network/AccessTokenInterceptor.kt | 6 +- .../network/token/AccessTokenProvider.kt | 2 +- .../token/HomeserverAccessTokenProvider.kt | 2 +- .../sdk/internal/session/DefaultSession.kt | 5 +- .../identity/DefaultIdentityService.kt | 21 ++- .../identity/IdentityAccessTokenProvider.kt | 2 +- .../session/identity/IdentityModule.kt | 41 ++++-- .../session/identity/data/IdentityStore.kt | 18 +-- .../session/identity/db/IdentityDataEntity.kt | 22 ++- .../identity/db/IdentityDataEntityQuery.kt | 77 ----------- .../db/IdentityPendingBindingEntity.kt | 26 ++-- .../db/IdentityPendingBindingEntityQuery.kt | 43 ------ .../identity/db/IdentityRealmModule.kt | 15 +- .../session/identity/db/RealmIdentityStore.kt | 128 ++++++++++-------- .../db/RealmIdentityStoreMigration.kt | 11 +- .../db/migration/MigrateIdentityTo001.kt | 11 +- .../contactsbook/ContactsBookViewModel.kt | 122 +++++++++-------- .../discovery/DiscoverySettingsViewModel.kt | 30 ++-- .../settings/VectorSettingsGeneralFragment.kt | 10 +- .../settings/legals/LegalsViewModel.kt | 19 +-- .../spaces/create/CreateSpaceViewModel.kt | 32 +++-- .../userdirectory/UserListViewModel.kt | 37 +++-- 24 files changed, 316 insertions(+), 372 deletions(-) delete mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntityQuery.kt delete mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityPendingBindingEntityQuery.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt index 2fb35d38e3..96fb256e9d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/identity/IdentityService.kt @@ -32,7 +32,7 @@ interface IdentityService { /** * Return the current identity server URL used by this account. Returns null if no identity server is configured. */ - fun getCurrentIdentityServerUrl(): String? + suspend fun getCurrentIdentityServerUrl(): String? /** * Check if the identity server is valid. @@ -105,7 +105,7 @@ interface IdentityService { * @return the value stored using [setUserConsent] or false if [setUserConsent] has never been called, or if the identity server * has been changed */ - fun getUserConsent(): Boolean + suspend fun getUserConsent(): Boolean /** * Set the user consent to the provided value. Application MUST explicitly ask for the user consent to send their private data @@ -113,7 +113,7 @@ interface IdentityService { * Please see https://support.google.com/googleplay/android-developer/answer/9888076?hl=en for more details. * @param newValue true if the user explicitly give their consent, false if the user wants to revoke their consent. */ - fun setUserConsent(newValue: Boolean) + suspend fun setUserConsent(newValue: Boolean) /** * Get the status of the current user's threePid. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstance.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstance.kt index 4599e87f98..b066f54ea2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstance.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmInstance.kt @@ -51,7 +51,7 @@ internal class RealmInstance( suspend fun open() { coroutineScope.launch { - realm.join() + realm.await() }.join() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/AccessTokenInterceptor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/AccessTokenInterceptor.kt index a34606a6bb..aed3fbcc5a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/AccessTokenInterceptor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/AccessTokenInterceptor.kt @@ -16,6 +16,7 @@ package org.matrix.android.sdk.internal.network +import kotlinx.coroutines.runBlocking import okhttp3.Interceptor import okhttp3.Response import org.matrix.android.sdk.internal.network.token.AccessTokenProvider @@ -26,12 +27,13 @@ internal class AccessTokenInterceptor(private val accessTokenProvider: AccessTok var request = chain.request() // Add the access token to all requests if it is set - accessTokenProvider.getToken()?.let { token -> + runBlocking { + accessTokenProvider.getToken() + }?.let { token -> val newRequestBuilder = request.newBuilder() newRequestBuilder.header(HttpHeaders.Authorization, "Bearer $token") request = newRequestBuilder.build() } - return chain.proceed(request) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/token/AccessTokenProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/token/AccessTokenProvider.kt index c0e08b5ad8..3804c33823 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/token/AccessTokenProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/token/AccessTokenProvider.kt @@ -17,5 +17,5 @@ package org.matrix.android.sdk.internal.network.token internal interface AccessTokenProvider { - fun getToken(): String? + suspend fun getToken(): String? } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/token/HomeserverAccessTokenProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/token/HomeserverAccessTokenProvider.kt index 82cde2399f..6efcc136bb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/token/HomeserverAccessTokenProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/token/HomeserverAccessTokenProvider.kt @@ -24,5 +24,5 @@ internal class HomeserverAccessTokenProvider @Inject constructor( @SessionId private val sessionId: String, private val sessionParamsStore: SessionParamsStore ) : AccessTokenProvider { - override fun getToken() = sessionParamsStore.get(sessionId)?.credentials?.accessToken + override suspend fun getToken() = sessionParamsStore.get(sessionId)?.credentials?.accessToken } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt index 57db187bdc..026df3b74e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt @@ -90,7 +90,6 @@ internal class DefaultSession @Inject constructor( override val coroutineDispatchers: MatrixCoroutineDispatchers, @SessionDatabase private val realmConfiguration: RealmConfiguration, @CryptoDatabase private val realmConfigurationCrypto: RealmConfiguration, - @IdentityDatabase private val realmConfigurationIdentity: RealmConfiguration, @ContentScannerDatabase private val realmConfigurationContentScanner: RealmConfiguration, private val lifecycleObservers: Set<@JvmSuppressWildcards SessionLifecycleObserver>, private val sessionListeners: SessionListeners, @@ -266,7 +265,7 @@ internal class DefaultSession @Inject constructor( override fun logDbUsageInfo() { RealmDebugTools(realmConfiguration).logInfo("Session") RealmDebugTools(realmConfigurationCrypto).logInfo("Crypto") - RealmDebugTools(realmConfigurationIdentity).logInfo("Identity") + //RealmDebugTools(realmConfigurationIdentity).logInfo("Identity") RealmDebugTools(realmConfigurationContentScanner).logInfo("ContentScanner") } @@ -274,7 +273,7 @@ internal class DefaultSession @Inject constructor( return listOf( realmConfiguration, realmConfigurationCrypto, - realmConfigurationIdentity, + //realmConfigurationIdentity, realmConfigurationContentScanner, ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt index 30c7773a8e..5b4cd413c5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/DefaultIdentityService.kt @@ -20,6 +20,8 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleRegistry import dagger.Lazy +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import okhttp3.OkHttpClient import org.matrix.android.sdk.api.MatrixCoroutineDispatchers @@ -41,6 +43,7 @@ import org.matrix.android.sdk.api.session.identity.SharedState import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.identity.model.SignInvitationResult import org.matrix.android.sdk.internal.di.AuthenticatedIdentity +import org.matrix.android.sdk.internal.di.SessionCoroutineScope import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate import org.matrix.android.sdk.internal.extensions.observeNotNull import org.matrix.android.sdk.internal.network.RetrofitFactory @@ -81,7 +84,8 @@ internal class DefaultIdentityService @Inject constructor( private val accountDataDataSource: UserAccountDataDataSource, private val homeServerCapabilitiesService: HomeServerCapabilitiesService, private val sign3pidInvitationTask: Sign3pidInvitationTask, - private val sessionParams: SessionParams + private val sessionParams: SessionParams, + @SessionCoroutineScope private val coroutineScope: CoroutineScope, ) : IdentityService, SessionLifecycleObserver { private val lifecycleOwner: LifecycleOwner = LifecycleOwner { lifecycleRegistry } @@ -95,14 +99,17 @@ internal class DefaultIdentityService @Inject constructor( accountDataDataSource .getLiveAccountDataEvent(UserAccountDataTypes.TYPE_IDENTITY_SERVER) .observeNotNull(lifecycleOwner) { - notifyIdentityServerUrlChange(it.getOrNull()?.content?.toModel()?.baseUrl) + coroutineScope.notifyIdentityServerUrlChange(it.getOrNull()?.content?.toModel()?.baseUrl) } // Init identityApi - updateIdentityAPI(identityStore.getIdentityData()?.identityServerUrl) + coroutineScope.launch { + val url = identityStore.getIdentityData()?.identityServerUrl + updateIdentityAPI(url) + } } - private fun notifyIdentityServerUrlChange(baseUrl: String?) { + private fun CoroutineScope.notifyIdentityServerUrlChange(baseUrl: String?) = launch { // This is maybe not a real change (echo of account data we are just setting) if (identityStore.getIdentityData()?.identityServerUrl == baseUrl) { Timber.d("Echo of local identity server url change, or no change") @@ -129,7 +136,7 @@ internal class DefaultIdentityService @Inject constructor( ?: homeServerCapabilitiesService.getHomeServerCapabilities().defaultIdentityServerUrl } - override fun getCurrentIdentityServerUrl(): String? { + override suspend fun getCurrentIdentityServerUrl(): String? { return identityStore.getIdentityData()?.identityServerUrl } @@ -225,11 +232,11 @@ internal class DefaultIdentityService @Inject constructor( ) } - override fun getUserConsent(): Boolean { + override suspend fun getUserConsent(): Boolean { return identityStore.getIdentityData()?.userConsent.orFalse() } - override fun setUserConsent(newValue: Boolean) { + override suspend fun setUserConsent(newValue: Boolean) { identityStore.setUserConsent(newValue) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAccessTokenProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAccessTokenProvider.kt index 492c3a5d0c..904ca51e26 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAccessTokenProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityAccessTokenProvider.kt @@ -23,5 +23,5 @@ import javax.inject.Inject internal class IdentityAccessTokenProvider @Inject constructor( private val identityStore: IdentityStore ) : AccessTokenProvider { - override fun getToken() = identityStore.getIdentityData()?.token + override suspend fun getToken() = identityStore.getIdentityData()?.token } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt index 33d8164895..b0d61473fb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityModule.kt @@ -19,13 +19,17 @@ package org.matrix.android.sdk.internal.session.identity import dagger.Binds import dagger.Module import dagger.Provides -import io.realm.RealmConfiguration +import io.realm.kotlin.RealmConfiguration +import kotlinx.coroutines.CoroutineScope import okhttp3.OkHttpClient import org.matrix.android.sdk.api.MatrixConfiguration +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.session.identity.IdentityService +import org.matrix.android.sdk.internal.database.RealmInstance import org.matrix.android.sdk.internal.database.RealmKeysUtils import org.matrix.android.sdk.internal.di.AuthenticatedIdentity import org.matrix.android.sdk.internal.di.IdentityDatabase +import org.matrix.android.sdk.internal.di.MatrixCoroutineScope import org.matrix.android.sdk.internal.di.SessionFilesDirectory import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate import org.matrix.android.sdk.internal.di.UserMd5 @@ -35,7 +39,7 @@ import org.matrix.android.sdk.internal.network.token.AccessTokenProvider import org.matrix.android.sdk.internal.session.SessionModule import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.identity.data.IdentityStore -import org.matrix.android.sdk.internal.session.identity.db.IdentityRealmModule +import org.matrix.android.sdk.internal.session.identity.db.IDENTITY_REALM_SCHEMA import org.matrix.android.sdk.internal.session.identity.db.RealmIdentityStore import org.matrix.android.sdk.internal.session.identity.db.RealmIdentityStoreMigration import java.io.File @@ -64,25 +68,38 @@ internal abstract class IdentityModule { @JvmStatic @Provides @IdentityDatabase - @SessionScope - fun providesIdentityRealmConfiguration( + fun providesRealmConfiguration( realmKeysUtils: RealmKeysUtils, - realmIdentityStoreMigration: RealmIdentityStoreMigration, + identityStoreMigration: RealmIdentityStoreMigration, @SessionFilesDirectory directory: File, @UserMd5 userMd5: String ): RealmConfiguration { - return RealmConfiguration.Builder() - .directory(directory) - .name("matrix-sdk-identity.realm") + return RealmConfiguration.Builder(IDENTITY_REALM_SCHEMA) + .directory(directory.path) .apply { realmKeysUtils.configureEncryption(this, SessionModule.getKeyAlias(userMd5)) } - .schemaVersion(realmIdentityStoreMigration.schemaVersion) - .migration(realmIdentityStoreMigration) - .allowWritesOnUiThread(true) - .modules(IdentityRealmModule()) + .name("matrix-sdk-global.realm") + .schemaVersion(identityStoreMigration.schemaVersion) + .migration(identityStoreMigration) .build() } + + @JvmStatic + @Provides + @IdentityDatabase + @SessionScope + fun providesRealmInstance( + @IdentityDatabase realmConfiguration: RealmConfiguration, + @MatrixCoroutineScope matrixCoroutineScope: CoroutineScope, + matrixCoroutineDispatchers: MatrixCoroutineDispatchers + ): RealmInstance { + return RealmInstance( + coroutineScope = matrixCoroutineScope, + realmConfiguration = realmConfiguration, + coroutineDispatcher = matrixCoroutineDispatchers.io + ) + } } @Binds diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityStore.kt index 51d4ed7c6d..0c56e3777d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/data/IdentityStore.kt @@ -21,26 +21,26 @@ import org.matrix.android.sdk.internal.session.identity.model.IdentityHashDetail internal interface IdentityStore { - fun getIdentityData(): IdentityData? + suspend fun getIdentityData(): IdentityData? - fun setUrl(url: String?) + suspend fun setUrl(url: String?) - fun setToken(token: String?) + suspend fun setToken(token: String?) - fun setUserConsent(consent: Boolean) + suspend fun setUserConsent(consent: Boolean) - fun setHashDetails(hashDetailResponse: IdentityHashDetailResponse) + suspend fun setHashDetails(hashDetailResponse: IdentityHashDetailResponse) /** * Store details about a current binding. */ - fun storePendingBinding(threePid: ThreePid, data: IdentityPendingBinding) + suspend fun storePendingBinding(threePid: ThreePid, data: IdentityPendingBinding) - fun getPendingBinding(threePid: ThreePid): IdentityPendingBinding? + suspend fun getPendingBinding(threePid: ThreePid): IdentityPendingBinding? - fun deletePendingBinding(threePid: ThreePid) + suspend fun deletePendingBinding(threePid: ThreePid) } -internal fun IdentityStore.getIdentityServerUrlWithoutProtocol(): String? { +internal suspend fun IdentityStore.getIdentityServerUrlWithoutProtocol(): String? { return getIdentityData()?.identityServerUrl?.substringAfter("://") } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntity.kt index d2c12131c0..f9624e213b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntity.kt @@ -16,18 +16,14 @@ package org.matrix.android.sdk.internal.session.identity.db -import io.realm.RealmList -import io.realm.RealmModel -import io.realm.annotations.RealmClass +import io.realm.kotlin.ext.realmListOf +import io.realm.kotlin.types.RealmList +import io.realm.kotlin.types.RealmObject -@RealmClass -internal open class IdentityDataEntity( - var identityServerUrl: String? = null, - var token: String? = null, - var hashLookupPepper: String? = null, - var hashLookupAlgorithm: RealmList = RealmList(), - var userConsent: Boolean = false -) : RealmModel { - - companion object +internal class IdentityDataEntity : RealmObject { + var identityServerUrl: String? = null + var token: String? = null + var hashLookupPepper: String? = null + var hashLookupAlgorithm: RealmList = realmListOf() + var userConsent: Boolean = false } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntityQuery.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntityQuery.kt deleted file mode 100644 index 08e5b43977..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityDataEntityQuery.kt +++ /dev/null @@ -1,77 +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.session.identity.db - -import io.realm.Realm -import io.realm.RealmList -import io.realm.kotlin.createObject -import io.realm.kotlin.where - -/** - * Only one object can be stored at a time. - */ -internal fun IdentityDataEntity.Companion.get(realm: Realm): IdentityDataEntity? { - return realm.where().findFirst() -} - -private fun IdentityDataEntity.Companion.getOrCreate(realm: Realm): IdentityDataEntity { - return get(realm) ?: realm.createObject() -} - -internal fun IdentityDataEntity.Companion.setUrl( - realm: Realm, - url: String? -) { - realm.where().findAll().deleteAllFromRealm() - // Delete all pending binding if any - IdentityPendingBindingEntity.deleteAll(realm) - - if (url != null) { - getOrCreate(realm).apply { - identityServerUrl = url - } - } -} - -internal fun IdentityDataEntity.Companion.setToken( - realm: Realm, - newToken: String? -) { - get(realm)?.apply { - token = newToken - } -} - -internal fun IdentityDataEntity.Companion.setUserConsent( - realm: Realm, - newConsent: Boolean -) { - get(realm)?.apply { - userConsent = newConsent - } -} - -internal fun IdentityDataEntity.Companion.setHashDetails( - realm: Realm, - pepper: String, - algorithms: List -) { - get(realm)?.apply { - hashLookupPepper = pepper - hashLookupAlgorithm = RealmList().apply { addAll(algorithms) } - } -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityPendingBindingEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityPendingBindingEntity.kt index f71f0f56c0..e5afbc8d5e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityPendingBindingEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityPendingBindingEntity.kt @@ -16,22 +16,22 @@ package org.matrix.android.sdk.internal.session.identity.db -import io.realm.RealmModel -import io.realm.annotations.PrimaryKey -import io.realm.annotations.RealmClass +import io.realm.kotlin.types.RealmObject +import io.realm.kotlin.types.annotations.PrimaryKey import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.identity.toMedium -@RealmClass -internal open class IdentityPendingBindingEntity( - @PrimaryKey var threePid: String = "", - /* Managed by Riot */ - var clientSecret: String = "", - /* Managed by Riot */ - var sendAttempt: Int = 0, - /* Provided by the identity server */ - var sid: String = "" -) : RealmModel { +internal class IdentityPendingBindingEntity : RealmObject { + @PrimaryKey var threePid: String = "" + + /* Managed by Riot */ + var clientSecret: String = "" + + /* Managed by Riot */ + var sendAttempt: Int = 0 + + /* Provided by the identity server */ + var sid: String = "" companion object { fun ThreePid.toPrimaryKey() = "${toMedium()}_$value" diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityPendingBindingEntityQuery.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityPendingBindingEntityQuery.kt deleted file mode 100644 index 3c18bdf7aa..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityPendingBindingEntityQuery.kt +++ /dev/null @@ -1,43 +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.session.identity.db - -import io.realm.Realm -import io.realm.kotlin.createObject -import io.realm.kotlin.deleteFromRealm -import io.realm.kotlin.where -import org.matrix.android.sdk.api.session.identity.ThreePid - -internal fun IdentityPendingBindingEntity.Companion.get(realm: Realm, threePid: ThreePid): IdentityPendingBindingEntity? { - return realm.where() - .equalTo(IdentityPendingBindingEntityFields.THREE_PID, threePid.toPrimaryKey()) - .findFirst() -} - -internal fun IdentityPendingBindingEntity.Companion.getOrCreate(realm: Realm, threePid: ThreePid): IdentityPendingBindingEntity { - return get(realm, threePid) ?: realm.createObject(threePid.toPrimaryKey()) -} - -internal fun IdentityPendingBindingEntity.Companion.delete(realm: Realm, threePid: ThreePid) { - get(realm, threePid)?.deleteFromRealm() -} - -internal fun IdentityPendingBindingEntity.Companion.deleteAll(realm: Realm) { - realm.where() - .findAll() - .deleteAllFromRealm() -} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityRealmModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityRealmModule.kt index a5ec6061ba..b5644487ba 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityRealmModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/IdentityRealmModule.kt @@ -16,16 +16,7 @@ package org.matrix.android.sdk.internal.session.identity.db -import io.realm.annotations.RealmModule - -/** - * Realm module for identity server classes. - */ -@RealmModule( - library = true, - classes = [ - IdentityDataEntity::class, - IdentityPendingBindingEntity::class - ] +internal val IDENTITY_REALM_SCHEMA = setOf( + IdentityDataEntity::class, + IdentityPendingBindingEntity::class, ) -internal class IdentityRealmModule diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStore.kt index ce8b78b2d0..3ae466fbd3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStore.kt @@ -16,84 +16,102 @@ package org.matrix.android.sdk.internal.session.identity.db -import io.realm.Realm -import io.realm.RealmConfiguration +import io.realm.kotlin.UpdatePolicy import org.matrix.android.sdk.api.session.identity.ThreePid +import org.matrix.android.sdk.internal.database.RealmInstance +import org.matrix.android.sdk.internal.database.await import org.matrix.android.sdk.internal.di.IdentityDatabase import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.identity.data.IdentityData import org.matrix.android.sdk.internal.session.identity.data.IdentityPendingBinding import org.matrix.android.sdk.internal.session.identity.data.IdentityStore +import org.matrix.android.sdk.internal.session.identity.db.IdentityPendingBindingEntity.Companion.toPrimaryKey import org.matrix.android.sdk.internal.session.identity.model.IdentityHashDetailResponse import javax.inject.Inject @SessionScope internal class RealmIdentityStore @Inject constructor( @IdentityDatabase - private val realmConfiguration: RealmConfiguration + private val realmInstance: RealmInstance, ) : IdentityStore { - override fun getIdentityData(): IdentityData? { - return Realm.getInstance(realmConfiguration).use { realm -> - IdentityDataEntity.get(realm)?.let { IdentityMapper.map(it) } - } - } - - override fun setUrl(url: String?) { - Realm.getInstance(realmConfiguration).use { - it.executeTransaction { realm -> - IdentityDataEntity.setUrl(realm, url) - } - } - } - - override fun setToken(token: String?) { - Realm.getInstance(realmConfiguration).use { - it.executeTransaction { realm -> - IdentityDataEntity.setToken(realm, token) - } - } - } - - override fun setUserConsent(consent: Boolean) { - Realm.getInstance(realmConfiguration).use { - it.executeTransaction { realm -> - IdentityDataEntity.setUserConsent(realm, consent) - } - } - } - - override fun setHashDetails(hashDetailResponse: IdentityHashDetailResponse) { - Realm.getInstance(realmConfiguration).use { - it.executeTransaction { realm -> - IdentityDataEntity.setHashDetails(realm, hashDetailResponse.pepper, hashDetailResponse.algorithms) - } - } - } - - override fun storePendingBinding(threePid: ThreePid, data: IdentityPendingBinding) { - Realm.getInstance(realmConfiguration).use { - it.executeTransaction { realm -> - IdentityPendingBindingEntity.getOrCreate(realm, threePid).let { entity -> - entity.clientSecret = data.clientSecret - entity.sendAttempt = data.sendAttempt - entity.sid = data.sid + override suspend fun getIdentityData(): IdentityData? { + return getIdentityDataEntity() + ?.let { + IdentityMapper.map(it) } + } + + override suspend fun setUrl(url: String?) { + val identityData = getIdentityDataEntity() ?: return + realmInstance.write { + findLatest(identityData)?.identityServerUrl = url + } + } + + override suspend fun setToken(token: String?) { + val identityData = getIdentityDataEntity() ?: return + realmInstance.write { + findLatest(identityData)?.token = token + } + } + + override suspend fun setUserConsent(consent: Boolean) { + val identityData = getIdentityDataEntity() ?: return + realmInstance.write { + findLatest(identityData)?.userConsent = consent + } + } + + override suspend fun setHashDetails(hashDetailResponse: IdentityHashDetailResponse) { + val identityData = getIdentityDataEntity() ?: return + realmInstance.write { + findLatest(identityData)?.apply { + hashLookupAlgorithm.clear() + hashLookupAlgorithm.addAll(hashDetailResponse.algorithms) + hashLookupPepper = hashDetailResponse.pepper } } } - override fun getPendingBinding(threePid: ThreePid): IdentityPendingBinding? { - return Realm.getInstance(realmConfiguration).use { realm -> - IdentityPendingBindingEntity.get(realm, threePid)?.let { IdentityMapper.map(it) } + override suspend fun storePendingBinding(threePid: ThreePid, data: IdentityPendingBinding) { + realmInstance.write { + val pendingBindingEntity = IdentityPendingBindingEntity().apply { + this.threePid = threePid.toPrimaryKey() + clientSecret = data.clientSecret + sendAttempt = data.sendAttempt + sid = data.sid + } + copyToRealm(pendingBindingEntity, updatePolicy = UpdatePolicy.ALL) } } - override fun deletePendingBinding(threePid: ThreePid) { - Realm.getInstance(realmConfiguration).use { - it.executeTransaction { realm -> - IdentityPendingBindingEntity.delete(realm, threePid) + override suspend fun getPendingBinding(threePid: ThreePid): IdentityPendingBinding? { + return getPendingBindingEntity(threePid)?.let { + IdentityMapper.map(it) + } + } + + override suspend fun deletePendingBinding(threePid: ThreePid) { + val pendingBindingEntity = getPendingBindingEntity(threePid) ?: return + realmInstance.write { + findLatest(pendingBindingEntity)?.also { + delete(it) } } } + + private suspend fun getPendingBindingEntity(threePid: ThreePid): IdentityPendingBindingEntity? { + return realmInstance.getRealm() + .query(IdentityPendingBindingEntity::class, "threePid == $0", threePid.toPrimaryKey()) + .first() + .await() + } + + private suspend fun getIdentityDataEntity(): IdentityDataEntity? { + return realmInstance.getRealm() + .query(IdentityDataEntity::class) + .first() + .await() + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt index 4756b41f4c..82fc6f47ff 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/RealmIdentityStoreMigration.kt @@ -16,15 +16,16 @@ package org.matrix.android.sdk.internal.session.identity.db -import io.realm.DynamicRealm +import io.realm.kotlin.migration.AutomaticSchemaMigration +import org.matrix.android.sdk.internal.database.MatrixAutomaticSchemaMigration import org.matrix.android.sdk.internal.session.identity.db.migration.MigrateIdentityTo001 -import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration import javax.inject.Inject -internal class RealmIdentityStoreMigration @Inject constructor() : MatrixRealmMigration( +internal class RealmIdentityStoreMigration @Inject constructor() : MatrixAutomaticSchemaMigration( dbName = "Identity", schemaVersion = 1L, ) { + /** * Forces all RealmIdentityStoreMigration instances to be equal. * Avoids Realm throwing when multiple instances of the migration are set. @@ -32,7 +33,7 @@ internal class RealmIdentityStoreMigration @Inject constructor() : MatrixRealmMi override fun equals(other: Any?) = other is RealmIdentityStoreMigration override fun hashCode() = 3000 - override fun doMigrate(realm: DynamicRealm, oldVersion: Long) { - if (oldVersion < 1) MigrateIdentityTo001(realm).perform() + override fun doMigrate(oldVersion: Long, migrationContext: AutomaticSchemaMigration.MigrationContext) { + if (oldVersion < 1) MigrateIdentityTo001(migrationContext).perform() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/migration/MigrateIdentityTo001.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/migration/MigrateIdentityTo001.kt index 17a23b828a..01139b561e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/migration/MigrateIdentityTo001.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/db/migration/MigrateIdentityTo001.kt @@ -16,16 +16,13 @@ package org.matrix.android.sdk.internal.session.identity.db.migration -import io.realm.DynamicRealm -import org.matrix.android.sdk.internal.session.identity.db.IdentityDataEntityFields -import org.matrix.android.sdk.internal.util.database.RealmMigrator +import io.realm.kotlin.migration.AutomaticSchemaMigration +import org.matrix.android.sdk.internal.database.KotlinRealmMigrator import timber.log.Timber -internal class MigrateIdentityTo001(realm: DynamicRealm) : RealmMigrator(realm, 1) { +internal class MigrateIdentityTo001(migrationContext: AutomaticSchemaMigration.MigrationContext) : KotlinRealmMigrator(migrationContext, 1) { - override fun doMigrate(realm: DynamicRealm) { + override fun doMigrate(migrationContext: AutomaticSchemaMigration.MigrationContext) { Timber.d("Add field userConsent (Boolean) and set the value to false") - realm.schema.get("IdentityDataEntity") - ?.addField(IdentityDataEntityFields.USER_CONSENT, Boolean::class.java) } } diff --git a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewModel.kt b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewModel.kt index 402fc40c9a..7f0831093d 100644 --- a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewModel.kt @@ -31,6 +31,7 @@ import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.features.discovery.fetchIdentityServerWithTerms import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.identity.IdentityServiceError @@ -63,15 +64,19 @@ class ContactsBookViewModel @AssistedInject constructor( } private fun loadContacts() { - setState { - copy( - mappedContacts = Loading(), - identityServerUrl = session.identityService().getCurrentIdentityServerUrl(), - userConsent = session.identityService().getUserConsent() - ) - } - viewModelScope.launch(Dispatchers.IO) { + + val identityServerUrl = session.identityService().getCurrentIdentityServerUrl() + val userConsent = session.identityService().getUserConsent() + + setState { + copy( + mappedContacts = Loading(), + identityServerUrl = identityServerUrl, + userConsent = userConsent + ) + } + allContacts = contactsDataSource.getContacts( withEmails = true, // Do not handle phone numbers for the moment @@ -90,57 +95,55 @@ class ContactsBookViewModel @AssistedInject constructor( } } - private fun performLookup(contacts: List) { + private suspend fun performLookup(contacts: List) = coroutineScope { if (!session.identityService().getUserConsent()) { - return + return@coroutineScope + } + val threePids = contacts.flatMap { contact -> + contact.emails.map { ThreePid.Email(it.email) } + + contact.msisdns.map { ThreePid.Msisdn(it.phoneNumber) } } - viewModelScope.launch { - val threePids = contacts.flatMap { contact -> - contact.emails.map { ThreePid.Email(it.email) } + - contact.msisdns.map { ThreePid.Msisdn(it.phoneNumber) } - } - val data = try { - session.identityService().lookUp(threePids) - } catch (failure: Throwable) { - Timber.w(failure, "Unable to perform the lookup") + val data = try { + session.identityService().lookUp(threePids) + } catch (failure: Throwable) { + Timber.w(failure, "Unable to perform the lookup") - // Should not happen, but just to be sure - if (failure is IdentityServiceError.UserConsentNotProvided) { - setState { - copy(userConsent = false) - } + // Should not happen, but just to be sure + if (failure is IdentityServiceError.UserConsentNotProvided) { + setState { + copy(userConsent = false) } - return@launch } - - mappedContacts = allContacts.map { contactModel -> - contactModel.copy( - emails = contactModel.emails.map { email -> - email.copy( - matrixId = data - .firstOrNull { foundThreePid -> foundThreePid.threePid.value == email.email } - ?.matrixId - ) - }, - msisdns = contactModel.msisdns.map { msisdn -> - msisdn.copy( - matrixId = data - .firstOrNull { foundThreePid -> foundThreePid.threePid.value == msisdn.phoneNumber } - ?.matrixId - ) - } - ) - } - - setState { - copy( - isBoundRetrieved = true - ) - } - - updateFilteredMappedContacts() + return@coroutineScope } + + mappedContacts = allContacts.map { contactModel -> + contactModel.copy( + emails = contactModel.emails.map { email -> + email.copy( + matrixId = data + .firstOrNull { foundThreePid -> foundThreePid.threePid.value == email.email } + ?.matrixId + ) + }, + msisdns = contactModel.msisdns.map { msisdn -> + msisdn.copy( + matrixId = data + .firstOrNull { foundThreePid -> foundThreePid.threePid.value == msisdn.phoneNumber } + ?.matrixId + ) + } + ) + } + + setState { + copy( + isBoundRetrieved = true + ) + } + + updateFilteredMappedContacts() } private fun updateFilteredMappedContacts() = withState { state -> @@ -159,6 +162,7 @@ class ContactsBookViewModel @AssistedInject constructor( } override fun handle(action: ContactsBookAction) { + when (action) { is ContactsBookAction.FilterWith -> handleFilterWith(action) is ContactsBookAction.OnlyBoundContacts -> handleOnlyBoundContacts(action) @@ -180,14 +184,14 @@ class ContactsBookViewModel @AssistedInject constructor( } private fun handleUserConsentGranted() { - session.identityService().setUserConsent(true) - - setState { - copy(userConsent = true) + viewModelScope.launch { + session.identityService().setUserConsent(true) + setState { + copy(userConsent = true) + } + // Perform the lookup + performLookup(allContacts) } - - // Perform the lookup - performLookup(allContacts) } private fun handleOnlyBoundContacts(action: ContactsBookAction.OnlyBoundContacts) { diff --git a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt index 2a975beb58..5528d19c96 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt @@ -60,10 +60,11 @@ class DiscoverySettingsViewModel @AssistedInject constructor( runCatching { fetchIdentityServerWithTerms() }.fold( onSuccess = { val currentIS = state.identityServer() + val userConsent = identityService.getUserConsent() setState { copy( identityServer = Success(it), - userConsent = identityService.getUserConsent() + userConsent = userConsent ) } if (currentIS != it) retrieveBinding() @@ -75,16 +76,24 @@ class DiscoverySettingsViewModel @AssistedInject constructor( } init { - setState { - copy( - identityServer = Success(identityService.getCurrentIdentityServerUrl()?.let { ServerAndPolicies(it, emptyList()) }), - userConsent = identityService.getUserConsent() - ) - } + loadInitialState() startListenToIdentityManager() observeThreePids() } + private fun loadInitialState() { + viewModelScope.launch { + val identityServer = identityService.getCurrentIdentityServerUrl()?.let { ServerAndPolicies(it, emptyList()) } + val userConsent = identityService.getUserConsent() + setState { + copy( + identityServer = Success(identityServer), + userConsent = userConsent + ) + } + } + } + private fun observeThreePids() { session.flow() .liveThreePIds(true) @@ -116,13 +125,14 @@ class DiscoverySettingsViewModel @AssistedInject constructor( } private fun handleUpdateUserConsent(action: DiscoverySettingsAction.UpdateUserConsent) { - identityService.setUserConsent(action.newConsent) - setState { copy(userConsent = action.newConsent) } + viewModelScope.launch { + identityService.setUserConsent(action.newConsent) + setState { copy(userConsent = action.newConsent) } + } } private fun disconnectIdentityServer() { setState { copy(identityServer = Loading()) } - viewModelScope.launch { try { session.identityService().disconnect() diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt index 7906de3796..5da68c79fd 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt @@ -293,10 +293,12 @@ class VectorSettingsGeneralFragment @Inject constructor( override fun onResume() { super.onResume() - // Refresh identity server summary - mIdentityServerPreference.summary = session.identityService().getCurrentIdentityServerUrl() ?: getString(R.string.identity_server_not_defined) - refreshIntegrationManagerSettings() - session.integrationManagerService().addListener(integrationServiceListener) + viewLifecycleOwner.lifecycleScope.launchWhenResumed { + // Refresh identity server summary + mIdentityServerPreference.summary = session.identityService().getCurrentIdentityServerUrl() ?: getString(R.string.identity_server_not_defined) + refreshIntegrationManagerSettings() + session.integrationManagerService().addListener(integrationServiceListener) + } } override fun onPause() { diff --git a/vector/src/main/java/im/vector/app/features/settings/legals/LegalsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsViewModel.kt index 1497c793c2..a273202c8a 100644 --- a/vector/src/main/java/im/vector/app/features/settings/legals/LegalsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsViewModel.kt @@ -52,14 +52,17 @@ class LegalsViewModel @AssistedInject constructor( } } - private fun loadData() = withState { state -> - loadHomeserver(state) - val url = session.identityService().getCurrentIdentityServerUrl() - if (url.isNullOrEmpty()) { - setState { copy(hasIdentityServer = false) } - } else { - setState { copy(hasIdentityServer = true) } - loadIdentityServer(state) + private fun loadData() { + viewModelScope.launch { + val state = awaitState() + loadHomeserver(state) + val url = session.identityService().getCurrentIdentityServerUrl() + if (url.isNullOrEmpty()) { + setState { copy(hasIdentityServer = false) } + } else { + setState { copy(hasIdentityServer = true) } + loadIdentityServer(state) + } } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt index b680f77df2..424e0572ea 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/create/CreateSpaceViewModel.kt @@ -53,23 +53,19 @@ class CreateSpaceViewModel @AssistedInject constructor( private val identityServerManagerListener = object : IdentityServiceListener { override fun onIdentityServerChange() { - val identityServerUrl = identityService.getCurrentIdentityServerUrl() - setState { - copy( - canInviteByMail = identityServerUrl != null - ) + viewModelScope.launch { + val identityServerUrl = identityService.getCurrentIdentityServerUrl() + setState { + copy( + canInviteByMail = identityServerUrl != null + ) + } } } } init { - val identityServerUrl = identityService.getCurrentIdentityServerUrl() - setState { - copy( - homeServerName = session.myUserId.getServerName(), - canInviteByMail = identityServerUrl != null - ) - } + loadInitialState() startListenToIdentityManager() } @@ -78,6 +74,18 @@ class CreateSpaceViewModel @AssistedInject constructor( override fun create(initialState: CreateSpaceState): CreateSpaceViewModel } + private fun loadInitialState() { + viewModelScope.launch { + val identityServerUrl = identityService.getCurrentIdentityServerUrl() + setState { + copy( + homeServerName = session.myUserId.getServerName(), + canInviteByMail = identityServerUrl != null + ) + } + } + } + private fun startListenToIdentityManager() { identityService.addListener(identityServerManagerListener) } diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt index 5a764f11fd..98b308e37a 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewModel.kt @@ -31,6 +31,7 @@ import im.vector.app.core.extensions.toggle import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.features.discovery.fetchIdentityServerWithTerms +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.filter @@ -73,26 +74,32 @@ class UserListViewModel @AssistedInject constructor( private val identityServerListener = object : IdentityServiceListener { override fun onIdentityServerChange() { - withState { - identityServerUsersSearch.tryEmit(UserSearch(it.searchTerm)) - val identityServerURL = cleanISURL(session.identityService().getCurrentIdentityServerUrl()) - setState { - copy(configuredIdentityServer = identityServerURL) - } + viewModelScope.launch { + identityServerUsersSearch.tryEmit(UserSearch(awaitState().searchTerm)) + updateConfiguredIdentityServer() } } } init { + loadInitialState() observeUsers() - setState { - copy( - configuredIdentityServer = cleanISURL(session.identityService().getCurrentIdentityServerUrl()) - ) - } session.identityService().addListener(identityServerListener) } + private fun loadInitialState() { + viewModelScope.launch { + updateConfiguredIdentityServer() + } + } + + private suspend fun updateConfiguredIdentityServer() = coroutineScope { + val identityServerURL = cleanISURL(session.identityService().getCurrentIdentityServerUrl()) + setState { + copy(configuredIdentityServer = identityServerURL) + } + } + private fun cleanISURL(url: String?): String? { return url?.removePrefix("https://") } @@ -128,9 +135,11 @@ class UserListViewModel @AssistedInject constructor( } private fun handleISUpdateConsent(action: UserListAction.UpdateUserConsent) { - session.identityService().setUserConsent(action.consent) - withState { - retryUserSearch(it) + viewModelScope.launch { + session.identityService().setUserConsent(action.consent) + withState { + retryUserSearch(it) + } } }