mirror of
https://github.com/vector-im/riotX-android
synced 2025-10-06 00:02:48 +02:00
Realm: migrate identity db to realm-kotlin
This commit is contained in:
@@ -32,7 +32,7 @@ interface IdentityService {
|
|||||||
/**
|
/**
|
||||||
* Return the current identity server URL used by this account. Returns null if no identity server is configured.
|
* 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.
|
* 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
|
* @return the value stored using [setUserConsent] or false if [setUserConsent] has never been called, or if the identity server
|
||||||
* has been changed
|
* 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
|
* 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.
|
* 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.
|
* @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.
|
* Get the status of the current user's threePid.
|
||||||
|
@@ -51,7 +51,7 @@ internal class RealmInstance(
|
|||||||
|
|
||||||
suspend fun open() {
|
suspend fun open() {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
realm.join()
|
realm.await()
|
||||||
}.join()
|
}.join()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.internal.network
|
package org.matrix.android.sdk.internal.network
|
||||||
|
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.matrix.android.sdk.internal.network.token.AccessTokenProvider
|
import org.matrix.android.sdk.internal.network.token.AccessTokenProvider
|
||||||
@@ -26,12 +27,13 @@ internal class AccessTokenInterceptor(private val accessTokenProvider: AccessTok
|
|||||||
var request = chain.request()
|
var request = chain.request()
|
||||||
|
|
||||||
// Add the access token to all requests if it is set
|
// Add the access token to all requests if it is set
|
||||||
accessTokenProvider.getToken()?.let { token ->
|
runBlocking {
|
||||||
|
accessTokenProvider.getToken()
|
||||||
|
}?.let { token ->
|
||||||
val newRequestBuilder = request.newBuilder()
|
val newRequestBuilder = request.newBuilder()
|
||||||
newRequestBuilder.header(HttpHeaders.Authorization, "Bearer $token")
|
newRequestBuilder.header(HttpHeaders.Authorization, "Bearer $token")
|
||||||
request = newRequestBuilder.build()
|
request = newRequestBuilder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
return chain.proceed(request)
|
return chain.proceed(request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,5 +17,5 @@
|
|||||||
package org.matrix.android.sdk.internal.network.token
|
package org.matrix.android.sdk.internal.network.token
|
||||||
|
|
||||||
internal interface AccessTokenProvider {
|
internal interface AccessTokenProvider {
|
||||||
fun getToken(): String?
|
suspend fun getToken(): String?
|
||||||
}
|
}
|
||||||
|
@@ -24,5 +24,5 @@ internal class HomeserverAccessTokenProvider @Inject constructor(
|
|||||||
@SessionId private val sessionId: String,
|
@SessionId private val sessionId: String,
|
||||||
private val sessionParamsStore: SessionParamsStore
|
private val sessionParamsStore: SessionParamsStore
|
||||||
) : AccessTokenProvider {
|
) : AccessTokenProvider {
|
||||||
override fun getToken() = sessionParamsStore.get(sessionId)?.credentials?.accessToken
|
override suspend fun getToken() = sessionParamsStore.get(sessionId)?.credentials?.accessToken
|
||||||
}
|
}
|
||||||
|
@@ -90,7 +90,6 @@ internal class DefaultSession @Inject constructor(
|
|||||||
override val coroutineDispatchers: MatrixCoroutineDispatchers,
|
override val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||||
@SessionDatabase private val realmConfiguration: RealmConfiguration,
|
@SessionDatabase private val realmConfiguration: RealmConfiguration,
|
||||||
@CryptoDatabase private val realmConfigurationCrypto: RealmConfiguration,
|
@CryptoDatabase private val realmConfigurationCrypto: RealmConfiguration,
|
||||||
@IdentityDatabase private val realmConfigurationIdentity: RealmConfiguration,
|
|
||||||
@ContentScannerDatabase private val realmConfigurationContentScanner: RealmConfiguration,
|
@ContentScannerDatabase private val realmConfigurationContentScanner: RealmConfiguration,
|
||||||
private val lifecycleObservers: Set<@JvmSuppressWildcards SessionLifecycleObserver>,
|
private val lifecycleObservers: Set<@JvmSuppressWildcards SessionLifecycleObserver>,
|
||||||
private val sessionListeners: SessionListeners,
|
private val sessionListeners: SessionListeners,
|
||||||
@@ -266,7 +265,7 @@ internal class DefaultSession @Inject constructor(
|
|||||||
override fun logDbUsageInfo() {
|
override fun logDbUsageInfo() {
|
||||||
RealmDebugTools(realmConfiguration).logInfo("Session")
|
RealmDebugTools(realmConfiguration).logInfo("Session")
|
||||||
RealmDebugTools(realmConfigurationCrypto).logInfo("Crypto")
|
RealmDebugTools(realmConfigurationCrypto).logInfo("Crypto")
|
||||||
RealmDebugTools(realmConfigurationIdentity).logInfo("Identity")
|
//RealmDebugTools(realmConfigurationIdentity).logInfo("Identity")
|
||||||
RealmDebugTools(realmConfigurationContentScanner).logInfo("ContentScanner")
|
RealmDebugTools(realmConfigurationContentScanner).logInfo("ContentScanner")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,7 +273,7 @@ internal class DefaultSession @Inject constructor(
|
|||||||
return listOf(
|
return listOf(
|
||||||
realmConfiguration,
|
realmConfiguration,
|
||||||
realmConfigurationCrypto,
|
realmConfigurationCrypto,
|
||||||
realmConfigurationIdentity,
|
//realmConfigurationIdentity,
|
||||||
realmConfigurationContentScanner,
|
realmConfigurationContentScanner,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,8 @@ import androidx.lifecycle.Lifecycle
|
|||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.LifecycleRegistry
|
import androidx.lifecycle.LifecycleRegistry
|
||||||
import dagger.Lazy
|
import dagger.Lazy
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
|
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.ThreePid
|
||||||
import org.matrix.android.sdk.api.session.identity.model.SignInvitationResult
|
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.AuthenticatedIdentity
|
||||||
|
import org.matrix.android.sdk.internal.di.SessionCoroutineScope
|
||||||
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate
|
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate
|
||||||
import org.matrix.android.sdk.internal.extensions.observeNotNull
|
import org.matrix.android.sdk.internal.extensions.observeNotNull
|
||||||
import org.matrix.android.sdk.internal.network.RetrofitFactory
|
import org.matrix.android.sdk.internal.network.RetrofitFactory
|
||||||
@@ -81,7 +84,8 @@ internal class DefaultIdentityService @Inject constructor(
|
|||||||
private val accountDataDataSource: UserAccountDataDataSource,
|
private val accountDataDataSource: UserAccountDataDataSource,
|
||||||
private val homeServerCapabilitiesService: HomeServerCapabilitiesService,
|
private val homeServerCapabilitiesService: HomeServerCapabilitiesService,
|
||||||
private val sign3pidInvitationTask: Sign3pidInvitationTask,
|
private val sign3pidInvitationTask: Sign3pidInvitationTask,
|
||||||
private val sessionParams: SessionParams
|
private val sessionParams: SessionParams,
|
||||||
|
@SessionCoroutineScope private val coroutineScope: CoroutineScope,
|
||||||
) : IdentityService, SessionLifecycleObserver {
|
) : IdentityService, SessionLifecycleObserver {
|
||||||
|
|
||||||
private val lifecycleOwner: LifecycleOwner = LifecycleOwner { lifecycleRegistry }
|
private val lifecycleOwner: LifecycleOwner = LifecycleOwner { lifecycleRegistry }
|
||||||
@@ -95,14 +99,17 @@ internal class DefaultIdentityService @Inject constructor(
|
|||||||
accountDataDataSource
|
accountDataDataSource
|
||||||
.getLiveAccountDataEvent(UserAccountDataTypes.TYPE_IDENTITY_SERVER)
|
.getLiveAccountDataEvent(UserAccountDataTypes.TYPE_IDENTITY_SERVER)
|
||||||
.observeNotNull(lifecycleOwner) {
|
.observeNotNull(lifecycleOwner) {
|
||||||
notifyIdentityServerUrlChange(it.getOrNull()?.content?.toModel<IdentityServerContent>()?.baseUrl)
|
coroutineScope.notifyIdentityServerUrlChange(it.getOrNull()?.content?.toModel<IdentityServerContent>()?.baseUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init identityApi
|
// 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)
|
// This is maybe not a real change (echo of account data we are just setting)
|
||||||
if (identityStore.getIdentityData()?.identityServerUrl == baseUrl) {
|
if (identityStore.getIdentityData()?.identityServerUrl == baseUrl) {
|
||||||
Timber.d("Echo of local identity server url change, or no change")
|
Timber.d("Echo of local identity server url change, or no change")
|
||||||
@@ -129,7 +136,7 @@ internal class DefaultIdentityService @Inject constructor(
|
|||||||
?: homeServerCapabilitiesService.getHomeServerCapabilities().defaultIdentityServerUrl
|
?: homeServerCapabilitiesService.getHomeServerCapabilities().defaultIdentityServerUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getCurrentIdentityServerUrl(): String? {
|
override suspend fun getCurrentIdentityServerUrl(): String? {
|
||||||
return identityStore.getIdentityData()?.identityServerUrl
|
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()
|
return identityStore.getIdentityData()?.userConsent.orFalse()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setUserConsent(newValue: Boolean) {
|
override suspend fun setUserConsent(newValue: Boolean) {
|
||||||
identityStore.setUserConsent(newValue)
|
identityStore.setUserConsent(newValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,5 +23,5 @@ import javax.inject.Inject
|
|||||||
internal class IdentityAccessTokenProvider @Inject constructor(
|
internal class IdentityAccessTokenProvider @Inject constructor(
|
||||||
private val identityStore: IdentityStore
|
private val identityStore: IdentityStore
|
||||||
) : AccessTokenProvider {
|
) : AccessTokenProvider {
|
||||||
override fun getToken() = identityStore.getIdentityData()?.token
|
override suspend fun getToken() = identityStore.getIdentityData()?.token
|
||||||
}
|
}
|
||||||
|
@@ -19,13 +19,17 @@ package org.matrix.android.sdk.internal.session.identity
|
|||||||
import dagger.Binds
|
import dagger.Binds
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import io.realm.RealmConfiguration
|
import io.realm.kotlin.RealmConfiguration
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import org.matrix.android.sdk.api.MatrixConfiguration
|
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.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.database.RealmKeysUtils
|
||||||
import org.matrix.android.sdk.internal.di.AuthenticatedIdentity
|
import org.matrix.android.sdk.internal.di.AuthenticatedIdentity
|
||||||
import org.matrix.android.sdk.internal.di.IdentityDatabase
|
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.SessionFilesDirectory
|
||||||
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate
|
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate
|
||||||
import org.matrix.android.sdk.internal.di.UserMd5
|
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.SessionModule
|
||||||
import org.matrix.android.sdk.internal.session.SessionScope
|
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.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.RealmIdentityStore
|
||||||
import org.matrix.android.sdk.internal.session.identity.db.RealmIdentityStoreMigration
|
import org.matrix.android.sdk.internal.session.identity.db.RealmIdentityStoreMigration
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -64,25 +68,38 @@ internal abstract class IdentityModule {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Provides
|
@Provides
|
||||||
@IdentityDatabase
|
@IdentityDatabase
|
||||||
@SessionScope
|
fun providesRealmConfiguration(
|
||||||
fun providesIdentityRealmConfiguration(
|
|
||||||
realmKeysUtils: RealmKeysUtils,
|
realmKeysUtils: RealmKeysUtils,
|
||||||
realmIdentityStoreMigration: RealmIdentityStoreMigration,
|
identityStoreMigration: RealmIdentityStoreMigration,
|
||||||
@SessionFilesDirectory directory: File,
|
@SessionFilesDirectory directory: File,
|
||||||
@UserMd5 userMd5: String
|
@UserMd5 userMd5: String
|
||||||
): RealmConfiguration {
|
): RealmConfiguration {
|
||||||
return RealmConfiguration.Builder()
|
return RealmConfiguration.Builder(IDENTITY_REALM_SCHEMA)
|
||||||
.directory(directory)
|
.directory(directory.path)
|
||||||
.name("matrix-sdk-identity.realm")
|
|
||||||
.apply {
|
.apply {
|
||||||
realmKeysUtils.configureEncryption(this, SessionModule.getKeyAlias(userMd5))
|
realmKeysUtils.configureEncryption(this, SessionModule.getKeyAlias(userMd5))
|
||||||
}
|
}
|
||||||
.schemaVersion(realmIdentityStoreMigration.schemaVersion)
|
.name("matrix-sdk-global.realm")
|
||||||
.migration(realmIdentityStoreMigration)
|
.schemaVersion(identityStoreMigration.schemaVersion)
|
||||||
.allowWritesOnUiThread(true)
|
.migration(identityStoreMigration)
|
||||||
.modules(IdentityRealmModule())
|
|
||||||
.build()
|
.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
|
@Binds
|
||||||
|
@@ -21,26 +21,26 @@ import org.matrix.android.sdk.internal.session.identity.model.IdentityHashDetail
|
|||||||
|
|
||||||
internal interface IdentityStore {
|
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.
|
* 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("://")
|
return getIdentityData()?.identityServerUrl?.substringAfter("://")
|
||||||
}
|
}
|
||||||
|
@@ -16,18 +16,14 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.internal.session.identity.db
|
package org.matrix.android.sdk.internal.session.identity.db
|
||||||
|
|
||||||
import io.realm.RealmList
|
import io.realm.kotlin.ext.realmListOf
|
||||||
import io.realm.RealmModel
|
import io.realm.kotlin.types.RealmList
|
||||||
import io.realm.annotations.RealmClass
|
import io.realm.kotlin.types.RealmObject
|
||||||
|
|
||||||
@RealmClass
|
internal class IdentityDataEntity : RealmObject {
|
||||||
internal open class IdentityDataEntity(
|
var identityServerUrl: String? = null
|
||||||
var identityServerUrl: String? = null,
|
var token: String? = null
|
||||||
var token: String? = null,
|
var hashLookupPepper: String? = null
|
||||||
var hashLookupPepper: String? = null,
|
var hashLookupAlgorithm: RealmList<String> = realmListOf()
|
||||||
var hashLookupAlgorithm: RealmList<String> = RealmList(),
|
|
||||||
var userConsent: Boolean = false
|
var userConsent: Boolean = false
|
||||||
) : RealmModel {
|
|
||||||
|
|
||||||
companion object
|
|
||||||
}
|
}
|
||||||
|
@@ -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<IdentityDataEntity>().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<IdentityDataEntity>().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<String>
|
|
||||||
) {
|
|
||||||
get(realm)?.apply {
|
|
||||||
hashLookupPepper = pepper
|
|
||||||
hashLookupAlgorithm = RealmList<String>().apply { addAll(algorithms) }
|
|
||||||
}
|
|
||||||
}
|
|
@@ -16,22 +16,22 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.internal.session.identity.db
|
package org.matrix.android.sdk.internal.session.identity.db
|
||||||
|
|
||||||
import io.realm.RealmModel
|
import io.realm.kotlin.types.RealmObject
|
||||||
import io.realm.annotations.PrimaryKey
|
import io.realm.kotlin.types.annotations.PrimaryKey
|
||||||
import io.realm.annotations.RealmClass
|
|
||||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
import org.matrix.android.sdk.api.session.identity.ThreePid
|
||||||
import org.matrix.android.sdk.api.session.identity.toMedium
|
import org.matrix.android.sdk.api.session.identity.toMedium
|
||||||
|
|
||||||
@RealmClass
|
internal class IdentityPendingBindingEntity : RealmObject {
|
||||||
internal open class IdentityPendingBindingEntity(
|
@PrimaryKey var threePid: String = ""
|
||||||
@PrimaryKey var threePid: String = "",
|
|
||||||
/* Managed by Riot */
|
/* Managed by Riot */
|
||||||
var clientSecret: String = "",
|
var clientSecret: String = ""
|
||||||
|
|
||||||
/* Managed by Riot */
|
/* Managed by Riot */
|
||||||
var sendAttempt: Int = 0,
|
var sendAttempt: Int = 0
|
||||||
|
|
||||||
/* Provided by the identity server */
|
/* Provided by the identity server */
|
||||||
var sid: String = ""
|
var sid: String = ""
|
||||||
) : RealmModel {
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun ThreePid.toPrimaryKey() = "${toMedium()}_$value"
|
fun ThreePid.toPrimaryKey() = "${toMedium()}_$value"
|
||||||
|
@@ -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<IdentityPendingBindingEntity>()
|
|
||||||
.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<IdentityPendingBindingEntity>()
|
|
||||||
.findAll()
|
|
||||||
.deleteAllFromRealm()
|
|
||||||
}
|
|
@@ -16,16 +16,7 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.internal.session.identity.db
|
package org.matrix.android.sdk.internal.session.identity.db
|
||||||
|
|
||||||
import io.realm.annotations.RealmModule
|
internal val IDENTITY_REALM_SCHEMA = setOf(
|
||||||
|
|
||||||
/**
|
|
||||||
* Realm module for identity server classes.
|
|
||||||
*/
|
|
||||||
@RealmModule(
|
|
||||||
library = true,
|
|
||||||
classes = [
|
|
||||||
IdentityDataEntity::class,
|
IdentityDataEntity::class,
|
||||||
IdentityPendingBindingEntity::class
|
IdentityPendingBindingEntity::class,
|
||||||
]
|
|
||||||
)
|
)
|
||||||
internal class IdentityRealmModule
|
|
||||||
|
@@ -16,84 +16,102 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.internal.session.identity.db
|
package org.matrix.android.sdk.internal.session.identity.db
|
||||||
|
|
||||||
import io.realm.Realm
|
import io.realm.kotlin.UpdatePolicy
|
||||||
import io.realm.RealmConfiguration
|
|
||||||
import org.matrix.android.sdk.api.session.identity.ThreePid
|
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.di.IdentityDatabase
|
||||||
import org.matrix.android.sdk.internal.session.SessionScope
|
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.IdentityData
|
||||||
import org.matrix.android.sdk.internal.session.identity.data.IdentityPendingBinding
|
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.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 org.matrix.android.sdk.internal.session.identity.model.IdentityHashDetailResponse
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@SessionScope
|
@SessionScope
|
||||||
internal class RealmIdentityStore @Inject constructor(
|
internal class RealmIdentityStore @Inject constructor(
|
||||||
@IdentityDatabase
|
@IdentityDatabase
|
||||||
private val realmConfiguration: RealmConfiguration
|
private val realmInstance: RealmInstance,
|
||||||
) : IdentityStore {
|
) : IdentityStore {
|
||||||
|
|
||||||
override fun getIdentityData(): IdentityData? {
|
override suspend fun getIdentityData(): IdentityData? {
|
||||||
return Realm.getInstance(realmConfiguration).use { realm ->
|
return getIdentityDataEntity()
|
||||||
IdentityDataEntity.get(realm)?.let { IdentityMapper.map(it) }
|
?.let {
|
||||||
|
IdentityMapper.map(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setUrl(url: String?) {
|
override suspend fun setUrl(url: String?) {
|
||||||
Realm.getInstance(realmConfiguration).use {
|
val identityData = getIdentityDataEntity() ?: return
|
||||||
it.executeTransaction { realm ->
|
realmInstance.write {
|
||||||
IdentityDataEntity.setUrl(realm, url)
|
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 setToken(token: String?) {
|
override suspend fun storePendingBinding(threePid: ThreePid, data: IdentityPendingBinding) {
|
||||||
Realm.getInstance(realmConfiguration).use {
|
realmInstance.write {
|
||||||
it.executeTransaction { realm ->
|
val pendingBindingEntity = IdentityPendingBindingEntity().apply {
|
||||||
IdentityDataEntity.setToken(realm, token)
|
this.threePid = threePid.toPrimaryKey()
|
||||||
|
clientSecret = data.clientSecret
|
||||||
|
sendAttempt = data.sendAttempt
|
||||||
|
sid = data.sid
|
||||||
|
}
|
||||||
|
copyToRealm(pendingBindingEntity, updatePolicy = UpdatePolicy.ALL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setUserConsent(consent: Boolean) {
|
private suspend fun getPendingBindingEntity(threePid: ThreePid): IdentityPendingBindingEntity? {
|
||||||
Realm.getInstance(realmConfiguration).use {
|
return realmInstance.getRealm()
|
||||||
it.executeTransaction { realm ->
|
.query(IdentityPendingBindingEntity::class, "threePid == $0", threePid.toPrimaryKey())
|
||||||
IdentityDataEntity.setUserConsent(realm, consent)
|
.first()
|
||||||
}
|
.await()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setHashDetails(hashDetailResponse: IdentityHashDetailResponse) {
|
private suspend fun getIdentityDataEntity(): IdentityDataEntity? {
|
||||||
Realm.getInstance(realmConfiguration).use {
|
return realmInstance.getRealm()
|
||||||
it.executeTransaction { realm ->
|
.query(IdentityDataEntity::class)
|
||||||
IdentityDataEntity.setHashDetails(realm, hashDetailResponse.pepper, hashDetailResponse.algorithms)
|
.first()
|
||||||
}
|
.await()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 fun getPendingBinding(threePid: ThreePid): IdentityPendingBinding? {
|
|
||||||
return Realm.getInstance(realmConfiguration).use { realm ->
|
|
||||||
IdentityPendingBindingEntity.get(realm, threePid)?.let { IdentityMapper.map(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun deletePendingBinding(threePid: ThreePid) {
|
|
||||||
Realm.getInstance(realmConfiguration).use {
|
|
||||||
it.executeTransaction { realm ->
|
|
||||||
IdentityPendingBindingEntity.delete(realm, threePid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,15 +16,16 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.internal.session.identity.db
|
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.session.identity.db.migration.MigrateIdentityTo001
|
||||||
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class RealmIdentityStoreMigration @Inject constructor() : MatrixRealmMigration(
|
internal class RealmIdentityStoreMigration @Inject constructor() : MatrixAutomaticSchemaMigration(
|
||||||
dbName = "Identity",
|
dbName = "Identity",
|
||||||
schemaVersion = 1L,
|
schemaVersion = 1L,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forces all RealmIdentityStoreMigration instances to be equal.
|
* Forces all RealmIdentityStoreMigration instances to be equal.
|
||||||
* Avoids Realm throwing when multiple instances of the migration are set.
|
* 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 equals(other: Any?) = other is RealmIdentityStoreMigration
|
||||||
override fun hashCode() = 3000
|
override fun hashCode() = 3000
|
||||||
|
|
||||||
override fun doMigrate(realm: DynamicRealm, oldVersion: Long) {
|
override fun doMigrate(oldVersion: Long, migrationContext: AutomaticSchemaMigration.MigrationContext) {
|
||||||
if (oldVersion < 1) MigrateIdentityTo001(realm).perform()
|
if (oldVersion < 1) MigrateIdentityTo001(migrationContext).perform()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,16 +16,13 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.internal.session.identity.db.migration
|
package org.matrix.android.sdk.internal.session.identity.db.migration
|
||||||
|
|
||||||
import io.realm.DynamicRealm
|
import io.realm.kotlin.migration.AutomaticSchemaMigration
|
||||||
import org.matrix.android.sdk.internal.session.identity.db.IdentityDataEntityFields
|
import org.matrix.android.sdk.internal.database.KotlinRealmMigrator
|
||||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
|
||||||
import timber.log.Timber
|
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")
|
Timber.d("Add field userConsent (Boolean) and set the value to false")
|
||||||
realm.schema.get("IdentityDataEntity")
|
|
||||||
?.addField(IdentityDataEntityFields.USER_CONSENT, Boolean::class.java)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,6 +31,7 @@ import im.vector.app.core.platform.VectorViewModel
|
|||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.discovery.fetchIdentityServerWithTerms
|
import im.vector.app.features.discovery.fetchIdentityServerWithTerms
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.identity.IdentityServiceError
|
import org.matrix.android.sdk.api.session.identity.IdentityServiceError
|
||||||
@@ -63,15 +64,19 @@ class ContactsBookViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun loadContacts() {
|
private fun loadContacts() {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
|
||||||
|
val identityServerUrl = session.identityService().getCurrentIdentityServerUrl()
|
||||||
|
val userConsent = session.identityService().getUserConsent()
|
||||||
|
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
mappedContacts = Loading(),
|
mappedContacts = Loading(),
|
||||||
identityServerUrl = session.identityService().getCurrentIdentityServerUrl(),
|
identityServerUrl = identityServerUrl,
|
||||||
userConsent = session.identityService().getUserConsent()
|
userConsent = userConsent
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
|
||||||
allContacts = contactsDataSource.getContacts(
|
allContacts = contactsDataSource.getContacts(
|
||||||
withEmails = true,
|
withEmails = true,
|
||||||
// Do not handle phone numbers for the moment
|
// Do not handle phone numbers for the moment
|
||||||
@@ -90,11 +95,10 @@ class ContactsBookViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun performLookup(contacts: List<MappedContact>) {
|
private suspend fun performLookup(contacts: List<MappedContact>) = coroutineScope {
|
||||||
if (!session.identityService().getUserConsent()) {
|
if (!session.identityService().getUserConsent()) {
|
||||||
return
|
return@coroutineScope
|
||||||
}
|
}
|
||||||
viewModelScope.launch {
|
|
||||||
val threePids = contacts.flatMap { contact ->
|
val threePids = contacts.flatMap { contact ->
|
||||||
contact.emails.map { ThreePid.Email(it.email) } +
|
contact.emails.map { ThreePid.Email(it.email) } +
|
||||||
contact.msisdns.map { ThreePid.Msisdn(it.phoneNumber) }
|
contact.msisdns.map { ThreePid.Msisdn(it.phoneNumber) }
|
||||||
@@ -111,7 +115,7 @@ class ContactsBookViewModel @AssistedInject constructor(
|
|||||||
copy(userConsent = false)
|
copy(userConsent = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return@launch
|
return@coroutineScope
|
||||||
}
|
}
|
||||||
|
|
||||||
mappedContacts = allContacts.map { contactModel ->
|
mappedContacts = allContacts.map { contactModel ->
|
||||||
@@ -141,7 +145,6 @@ class ContactsBookViewModel @AssistedInject constructor(
|
|||||||
|
|
||||||
updateFilteredMappedContacts()
|
updateFilteredMappedContacts()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateFilteredMappedContacts() = withState { state ->
|
private fun updateFilteredMappedContacts() = withState { state ->
|
||||||
val filteredMappedContacts = mappedContacts
|
val filteredMappedContacts = mappedContacts
|
||||||
@@ -159,6 +162,7 @@ class ContactsBookViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun handle(action: ContactsBookAction) {
|
override fun handle(action: ContactsBookAction) {
|
||||||
|
|
||||||
when (action) {
|
when (action) {
|
||||||
is ContactsBookAction.FilterWith -> handleFilterWith(action)
|
is ContactsBookAction.FilterWith -> handleFilterWith(action)
|
||||||
is ContactsBookAction.OnlyBoundContacts -> handleOnlyBoundContacts(action)
|
is ContactsBookAction.OnlyBoundContacts -> handleOnlyBoundContacts(action)
|
||||||
@@ -180,15 +184,15 @@ class ContactsBookViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleUserConsentGranted() {
|
private fun handleUserConsentGranted() {
|
||||||
|
viewModelScope.launch {
|
||||||
session.identityService().setUserConsent(true)
|
session.identityService().setUserConsent(true)
|
||||||
|
|
||||||
setState {
|
setState {
|
||||||
copy(userConsent = true)
|
copy(userConsent = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the lookup
|
// Perform the lookup
|
||||||
performLookup(allContacts)
|
performLookup(allContacts)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleOnlyBoundContacts(action: ContactsBookAction.OnlyBoundContacts) {
|
private fun handleOnlyBoundContacts(action: ContactsBookAction.OnlyBoundContacts) {
|
||||||
setState {
|
setState {
|
||||||
|
@@ -60,10 +60,11 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||||||
runCatching { fetchIdentityServerWithTerms() }.fold(
|
runCatching { fetchIdentityServerWithTerms() }.fold(
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
val currentIS = state.identityServer()
|
val currentIS = state.identityServer()
|
||||||
|
val userConsent = identityService.getUserConsent()
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
identityServer = Success(it),
|
identityServer = Success(it),
|
||||||
userConsent = identityService.getUserConsent()
|
userConsent = userConsent
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (currentIS != it) retrieveBinding()
|
if (currentIS != it) retrieveBinding()
|
||||||
@@ -75,16 +76,24 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setState {
|
loadInitialState()
|
||||||
copy(
|
|
||||||
identityServer = Success(identityService.getCurrentIdentityServerUrl()?.let { ServerAndPolicies(it, emptyList()) }),
|
|
||||||
userConsent = identityService.getUserConsent()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
startListenToIdentityManager()
|
startListenToIdentityManager()
|
||||||
observeThreePids()
|
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() {
|
private fun observeThreePids() {
|
||||||
session.flow()
|
session.flow()
|
||||||
.liveThreePIds(true)
|
.liveThreePIds(true)
|
||||||
@@ -116,13 +125,14 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleUpdateUserConsent(action: DiscoverySettingsAction.UpdateUserConsent) {
|
private fun handleUpdateUserConsent(action: DiscoverySettingsAction.UpdateUserConsent) {
|
||||||
|
viewModelScope.launch {
|
||||||
identityService.setUserConsent(action.newConsent)
|
identityService.setUserConsent(action.newConsent)
|
||||||
setState { copy(userConsent = action.newConsent) }
|
setState { copy(userConsent = action.newConsent) }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun disconnectIdentityServer() {
|
private fun disconnectIdentityServer() {
|
||||||
setState { copy(identityServer = Loading()) }
|
setState { copy(identityServer = Loading()) }
|
||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
try {
|
try {
|
||||||
session.identityService().disconnect()
|
session.identityService().disconnect()
|
||||||
|
@@ -293,11 +293,13 @@ class VectorSettingsGeneralFragment @Inject constructor(
|
|||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
viewLifecycleOwner.lifecycleScope.launchWhenResumed {
|
||||||
// Refresh identity server summary
|
// Refresh identity server summary
|
||||||
mIdentityServerPreference.summary = session.identityService().getCurrentIdentityServerUrl() ?: getString(R.string.identity_server_not_defined)
|
mIdentityServerPreference.summary = session.identityService().getCurrentIdentityServerUrl() ?: getString(R.string.identity_server_not_defined)
|
||||||
refreshIntegrationManagerSettings()
|
refreshIntegrationManagerSettings()
|
||||||
session.integrationManagerService().addListener(integrationServiceListener)
|
session.integrationManagerService().addListener(integrationServiceListener)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
@@ -52,7 +52,9 @@ class LegalsViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData() = withState { state ->
|
private fun loadData() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val state = awaitState()
|
||||||
loadHomeserver(state)
|
loadHomeserver(state)
|
||||||
val url = session.identityService().getCurrentIdentityServerUrl()
|
val url = session.identityService().getCurrentIdentityServerUrl()
|
||||||
if (url.isNullOrEmpty()) {
|
if (url.isNullOrEmpty()) {
|
||||||
@@ -62,6 +64,7 @@ class LegalsViewModel @AssistedInject constructor(
|
|||||||
loadIdentityServer(state)
|
loadIdentityServer(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun loadHomeserver(state: LegalsState) {
|
private fun loadHomeserver(state: LegalsState) {
|
||||||
if (state.homeServer !is Success) {
|
if (state.homeServer !is Success) {
|
||||||
|
@@ -53,6 +53,7 @@ class CreateSpaceViewModel @AssistedInject constructor(
|
|||||||
|
|
||||||
private val identityServerManagerListener = object : IdentityServiceListener {
|
private val identityServerManagerListener = object : IdentityServiceListener {
|
||||||
override fun onIdentityServerChange() {
|
override fun onIdentityServerChange() {
|
||||||
|
viewModelScope.launch {
|
||||||
val identityServerUrl = identityService.getCurrentIdentityServerUrl()
|
val identityServerUrl = identityService.getCurrentIdentityServerUrl()
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
@@ -61,8 +62,20 @@ class CreateSpaceViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
loadInitialState()
|
||||||
|
startListenToIdentityManager()
|
||||||
|
}
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface Factory : MavericksAssistedViewModelFactory<CreateSpaceViewModel, CreateSpaceState> {
|
||||||
|
override fun create(initialState: CreateSpaceState): CreateSpaceViewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadInitialState() {
|
||||||
|
viewModelScope.launch {
|
||||||
val identityServerUrl = identityService.getCurrentIdentityServerUrl()
|
val identityServerUrl = identityService.getCurrentIdentityServerUrl()
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
@@ -70,12 +83,7 @@ class CreateSpaceViewModel @AssistedInject constructor(
|
|||||||
canInviteByMail = identityServerUrl != null
|
canInviteByMail = identityServerUrl != null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
startListenToIdentityManager()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AssistedFactory
|
|
||||||
interface Factory : MavericksAssistedViewModelFactory<CreateSpaceViewModel, CreateSpaceState> {
|
|
||||||
override fun create(initialState: CreateSpaceState): CreateSpaceViewModel
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startListenToIdentityManager() {
|
private fun startListenToIdentityManager() {
|
||||||
|
@@ -31,6 +31,7 @@ import im.vector.app.core.extensions.toggle
|
|||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.discovery.fetchIdentityServerWithTerms
|
import im.vector.app.features.discovery.fetchIdentityServerWithTerms
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.debounce
|
import kotlinx.coroutines.flow.debounce
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
@@ -73,26 +74,32 @@ class UserListViewModel @AssistedInject constructor(
|
|||||||
|
|
||||||
private val identityServerListener = object : IdentityServiceListener {
|
private val identityServerListener = object : IdentityServiceListener {
|
||||||
override fun onIdentityServerChange() {
|
override fun onIdentityServerChange() {
|
||||||
withState {
|
viewModelScope.launch {
|
||||||
identityServerUsersSearch.tryEmit(UserSearch(it.searchTerm))
|
identityServerUsersSearch.tryEmit(UserSearch(awaitState().searchTerm))
|
||||||
val identityServerURL = cleanISURL(session.identityService().getCurrentIdentityServerUrl())
|
updateConfiguredIdentityServer()
|
||||||
setState {
|
|
||||||
copy(configuredIdentityServer = identityServerURL)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
loadInitialState()
|
||||||
observeUsers()
|
observeUsers()
|
||||||
setState {
|
|
||||||
copy(
|
|
||||||
configuredIdentityServer = cleanISURL(session.identityService().getCurrentIdentityServerUrl())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
session.identityService().addListener(identityServerListener)
|
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? {
|
private fun cleanISURL(url: String?): String? {
|
||||||
return url?.removePrefix("https://")
|
return url?.removePrefix("https://")
|
||||||
}
|
}
|
||||||
@@ -128,11 +135,13 @@ class UserListViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleISUpdateConsent(action: UserListAction.UpdateUserConsent) {
|
private fun handleISUpdateConsent(action: UserListAction.UpdateUserConsent) {
|
||||||
|
viewModelScope.launch {
|
||||||
session.identityService().setUserConsent(action.consent)
|
session.identityService().setUserConsent(action.consent)
|
||||||
withState {
|
withState {
|
||||||
retryUserSearch(it)
|
retryUserSearch(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleResumed() {
|
private fun handleResumed() {
|
||||||
withState {
|
withState {
|
||||||
|
Reference in New Issue
Block a user