mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Merge pull request #5772 from vector-im/feature/bma/ignore_users
Delete Events from ignored users and trigger a clear cache request dialog when unignoring user(s)
This commit is contained in:
commit
7f3e72b9cb
1
changelog.d/5772.feature
Normal file
1
changelog.d/5772.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
Improve management of ignored users
|
@ -23,5 +23,10 @@ sealed class GlobalError {
|
|||||||
data class InvalidToken(val softLogout: Boolean) : GlobalError()
|
data class InvalidToken(val softLogout: Boolean) : GlobalError()
|
||||||
data class ConsentNotGivenError(val consentUri: String) : GlobalError()
|
data class ConsentNotGivenError(val consentUri: String) : GlobalError()
|
||||||
data class CertificateError(val fingerprint: Fingerprint) : GlobalError()
|
data class CertificateError(val fingerprint: Fingerprint) : GlobalError()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SDK requires the app (which should request the user) to perform an initial sync.
|
||||||
|
*/
|
||||||
|
data class InitialSyncRequest(val reason: InitialSyncRequestReason) : GlobalError()
|
||||||
object ExpiredAccount : GlobalError()
|
object ExpiredAccount : GlobalError()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.api.failure
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This enum provide the reason why the SDK request an initial sync to the application
|
||||||
|
*/
|
||||||
|
enum class InitialSyncRequestReason {
|
||||||
|
/**
|
||||||
|
* The list of ignored users has changed, and at least one user who was ignored is not ignored anymore
|
||||||
|
*/
|
||||||
|
IGNORED_USERS_LIST_CHANGE,
|
||||||
|
}
|
@ -298,6 +298,7 @@ interface Session :
|
|||||||
* Possible cases:
|
* Possible cases:
|
||||||
* - The access token is not valid anymore,
|
* - The access token is not valid anymore,
|
||||||
* - a M_CONSENT_NOT_GIVEN error has been received from the homeserver
|
* - a M_CONSENT_NOT_GIVEN error has been received from the homeserver
|
||||||
|
* See [GlobalError] for all the possible cases
|
||||||
*/
|
*/
|
||||||
fun onGlobalError(session: Session, globalError: GlobalError) = Unit
|
fun onGlobalError(session: Session, globalError: GlobalError) = Unit
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.api.session.room.timeline
|
package org.matrix.android.sdk.api.session.room.timeline
|
||||||
|
|
||||||
|
// TODO Move to internal, strange?
|
||||||
data class TimelineEventFilters(
|
data class TimelineEventFilters(
|
||||||
/**
|
/**
|
||||||
* A flag to filter edit events
|
* A flag to filter edit events
|
||||||
|
@ -31,7 +31,8 @@ data class TimelineSettings(
|
|||||||
/**
|
/**
|
||||||
* The root thread eventId if this is a thread timeline, or null if this is NOT a thread timeline
|
* The root thread eventId if this is a thread timeline, or null if this is NOT a thread timeline
|
||||||
*/
|
*/
|
||||||
val rootThreadEventId: String? = null) {
|
val rootThreadEventId: String? = null,
|
||||||
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this is a thread timeline or false otherwise
|
* Returns true if this is a thread timeline or false otherwise
|
||||||
|
@ -100,6 +100,7 @@ internal class DefaultTimeline(private val roomId: String,
|
|||||||
threadsAwarenessHandler = threadsAwarenessHandler,
|
threadsAwarenessHandler = threadsAwarenessHandler,
|
||||||
lightweightSettingsStorage = lightweightSettingsStorage,
|
lightweightSettingsStorage = lightweightSettingsStorage,
|
||||||
onEventsUpdated = this::sendSignalToPostSnapshot,
|
onEventsUpdated = this::sendSignalToPostSnapshot,
|
||||||
|
onEventsDeleted = this::onEventsDeleted,
|
||||||
onLimitedTimeline = this::onLimitedTimeline,
|
onLimitedTimeline = this::onLimitedTimeline,
|
||||||
onNewTimelineEvents = this::onNewTimelineEvents
|
onNewTimelineEvents = this::onNewTimelineEvents
|
||||||
)
|
)
|
||||||
@ -304,6 +305,12 @@ internal class DefaultTimeline(private val roomId: String,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onEventsDeleted() {
|
||||||
|
// Some event have been deleted, for instance when a user has been ignored.
|
||||||
|
// Restart the timeline (live)
|
||||||
|
restartWithEventId(null)
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun postSnapshot() {
|
private suspend fun postSnapshot() {
|
||||||
val snapshot = strategy.buildSnapshot()
|
val snapshot = strategy.buildSnapshot()
|
||||||
Timber.v("Post snapshot of ${snapshot.size} events")
|
Timber.v("Post snapshot of ${snapshot.size} events")
|
||||||
|
@ -95,6 +95,7 @@ internal class LoadTimelineStrategy(
|
|||||||
val threadsAwarenessHandler: ThreadsAwarenessHandler,
|
val threadsAwarenessHandler: ThreadsAwarenessHandler,
|
||||||
val lightweightSettingsStorage: LightweightSettingsStorage,
|
val lightweightSettingsStorage: LightweightSettingsStorage,
|
||||||
val onEventsUpdated: (Boolean) -> Unit,
|
val onEventsUpdated: (Boolean) -> Unit,
|
||||||
|
val onEventsDeleted: () -> Unit,
|
||||||
val onLimitedTimeline: () -> Unit,
|
val onLimitedTimeline: () -> Unit,
|
||||||
val onNewTimelineEvents: (List<String>) -> Unit
|
val onNewTimelineEvents: (List<String>) -> Unit
|
||||||
)
|
)
|
||||||
@ -302,7 +303,8 @@ internal class LoadTimelineStrategy(
|
|||||||
threadsAwarenessHandler = dependencies.threadsAwarenessHandler,
|
threadsAwarenessHandler = dependencies.threadsAwarenessHandler,
|
||||||
lightweightSettingsStorage = dependencies.lightweightSettingsStorage,
|
lightweightSettingsStorage = dependencies.lightweightSettingsStorage,
|
||||||
initialEventId = mode.originEventId(),
|
initialEventId = mode.originEventId(),
|
||||||
onBuiltEvents = dependencies.onEventsUpdated
|
onBuiltEvents = dependencies.onEventsUpdated,
|
||||||
|
onEventsDeleted = dependencies.onEventsDeleted,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,11 +59,13 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||||||
private val realmConfiguration: RealmConfiguration,
|
private val realmConfiguration: RealmConfiguration,
|
||||||
private val fetchTokenAndPaginateTask: FetchTokenAndPaginateTask,
|
private val fetchTokenAndPaginateTask: FetchTokenAndPaginateTask,
|
||||||
private val timelineEventMapper: TimelineEventMapper,
|
private val timelineEventMapper: TimelineEventMapper,
|
||||||
private val uiEchoManager: UIEchoManager? = null,
|
private val uiEchoManager: UIEchoManager?,
|
||||||
private val threadsAwarenessHandler: ThreadsAwarenessHandler,
|
private val threadsAwarenessHandler: ThreadsAwarenessHandler,
|
||||||
private val lightweightSettingsStorage: LightweightSettingsStorage,
|
private val lightweightSettingsStorage: LightweightSettingsStorage,
|
||||||
private val initialEventId: String?,
|
private val initialEventId: String?,
|
||||||
private val onBuiltEvents: (Boolean) -> Unit) {
|
private val onBuiltEvents: (Boolean) -> Unit,
|
||||||
|
private val onEventsDeleted: () -> Unit,
|
||||||
|
) {
|
||||||
|
|
||||||
private val isLastForward = AtomicBoolean(chunkEntity.isLastForward)
|
private val isLastForward = AtomicBoolean(chunkEntity.isLastForward)
|
||||||
private val isLastBackward = AtomicBoolean(chunkEntity.isLastBackward)
|
private val isLastBackward = AtomicBoolean(chunkEntity.isLastBackward)
|
||||||
@ -505,6 +507,11 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||||||
if (insertions.isNotEmpty() || modifications.isNotEmpty()) {
|
if (insertions.isNotEmpty() || modifications.isNotEmpty()) {
|
||||||
onBuiltEvents(true)
|
onBuiltEvents(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val deletions = changeSet.deletions
|
||||||
|
if (deletions.isNotEmpty()) {
|
||||||
|
onEventsDeleted()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNextDisplayIndex(direction: Timeline.Direction): Int? {
|
private fun getNextDisplayIndex(direction: Timeline.Direction): Int? {
|
||||||
@ -543,7 +550,8 @@ internal class TimelineChunk(private val chunkEntity: ChunkEntity,
|
|||||||
threadsAwarenessHandler = threadsAwarenessHandler,
|
threadsAwarenessHandler = threadsAwarenessHandler,
|
||||||
lightweightSettingsStorage = lightweightSettingsStorage,
|
lightweightSettingsStorage = lightweightSettingsStorage,
|
||||||
initialEventId = null,
|
initialEventId = null,
|
||||||
onBuiltEvents = this.onBuiltEvents
|
onBuiltEvents = this.onBuiltEvents,
|
||||||
|
onEventsDeleted = this.onEventsDeleted
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,8 @@ import com.zhuinden.monarchy.Monarchy
|
|||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmList
|
import io.realm.RealmList
|
||||||
import io.realm.kotlin.where
|
import io.realm.kotlin.where
|
||||||
|
import org.matrix.android.sdk.api.failure.GlobalError
|
||||||
|
import org.matrix.android.sdk.api.failure.InitialSyncRequestReason
|
||||||
import org.matrix.android.sdk.api.pushrules.RuleScope
|
import org.matrix.android.sdk.api.pushrules.RuleScope
|
||||||
import org.matrix.android.sdk.api.pushrules.RuleSetKey
|
import org.matrix.android.sdk.api.pushrules.RuleSetKey
|
||||||
import org.matrix.android.sdk.api.pushrules.rest.GetPushRulesResponse
|
import org.matrix.android.sdk.api.pushrules.rest.GetPushRulesResponse
|
||||||
@ -31,6 +33,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
|
|||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import org.matrix.android.sdk.api.session.sync.model.InvitedRoomSync
|
import org.matrix.android.sdk.api.session.sync.model.InvitedRoomSync
|
||||||
import org.matrix.android.sdk.api.session.sync.model.UserAccountDataSync
|
import org.matrix.android.sdk.api.session.sync.model.UserAccountDataSync
|
||||||
|
import org.matrix.android.sdk.internal.SessionManager
|
||||||
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
|
import org.matrix.android.sdk.internal.database.mapper.ContentMapper
|
||||||
import org.matrix.android.sdk.internal.database.mapper.PushRulesMapper
|
import org.matrix.android.sdk.internal.database.mapper.PushRulesMapper
|
||||||
import org.matrix.android.sdk.internal.database.mapper.asDomain
|
import org.matrix.android.sdk.internal.database.mapper.asDomain
|
||||||
@ -39,6 +42,8 @@ import org.matrix.android.sdk.internal.database.model.IgnoredUserEntity
|
|||||||
import org.matrix.android.sdk.internal.database.model.PushRulesEntity
|
import org.matrix.android.sdk.internal.database.model.PushRulesEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
|
||||||
|
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
|
||||||
import org.matrix.android.sdk.internal.database.model.UserAccountDataEntity
|
import org.matrix.android.sdk.internal.database.model.UserAccountDataEntity
|
||||||
import org.matrix.android.sdk.internal.database.model.UserAccountDataEntityFields
|
import org.matrix.android.sdk.internal.database.model.UserAccountDataEntityFields
|
||||||
import org.matrix.android.sdk.internal.database.model.deleteOnCascade
|
import org.matrix.android.sdk.internal.database.model.deleteOnCascade
|
||||||
@ -46,7 +51,10 @@ import org.matrix.android.sdk.internal.database.query.getDirectRooms
|
|||||||
import org.matrix.android.sdk.internal.database.query.getOrCreate
|
import org.matrix.android.sdk.internal.database.query.getOrCreate
|
||||||
import org.matrix.android.sdk.internal.database.query.where
|
import org.matrix.android.sdk.internal.database.query.where
|
||||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||||
|
import org.matrix.android.sdk.internal.di.SessionId
|
||||||
import org.matrix.android.sdk.internal.di.UserId
|
import org.matrix.android.sdk.internal.di.UserId
|
||||||
|
import org.matrix.android.sdk.internal.session.SessionListeners
|
||||||
|
import org.matrix.android.sdk.internal.session.dispatchTo
|
||||||
import org.matrix.android.sdk.internal.session.room.RoomAvatarResolver
|
import org.matrix.android.sdk.internal.session.room.RoomAvatarResolver
|
||||||
import org.matrix.android.sdk.internal.session.room.membership.RoomDisplayNameResolver
|
import org.matrix.android.sdk.internal.session.room.membership.RoomDisplayNameResolver
|
||||||
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
|
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
|
||||||
@ -65,7 +73,10 @@ internal class UserAccountDataSyncHandler @Inject constructor(
|
|||||||
private val directChatsHelper: DirectChatsHelper,
|
private val directChatsHelper: DirectChatsHelper,
|
||||||
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
|
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
|
||||||
private val roomAvatarResolver: RoomAvatarResolver,
|
private val roomAvatarResolver: RoomAvatarResolver,
|
||||||
private val roomDisplayNameResolver: RoomDisplayNameResolver
|
private val roomDisplayNameResolver: RoomDisplayNameResolver,
|
||||||
|
@SessionId private val sessionId: String,
|
||||||
|
private val sessionManager: SessionManager,
|
||||||
|
private val sessionListeners: SessionListeners
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun handle(realm: Realm, accountData: UserAccountDataSync?) {
|
fun handle(realm: Realm, accountData: UserAccountDataSync?) {
|
||||||
@ -184,12 +195,39 @@ internal class UserAccountDataSyncHandler @Inject constructor(
|
|||||||
|
|
||||||
private fun handleIgnoredUsers(realm: Realm, event: UserAccountDataEvent) {
|
private fun handleIgnoredUsers(realm: Realm, event: UserAccountDataEvent) {
|
||||||
val userIds = event.content.toModel<IgnoredUsersContent>()?.ignoredUsers?.keys ?: return
|
val userIds = event.content.toModel<IgnoredUsersContent>()?.ignoredUsers?.keys ?: return
|
||||||
realm.where(IgnoredUserEntity::class.java)
|
val currentIgnoredUsers = realm.where(IgnoredUserEntity::class.java).findAll()
|
||||||
.findAll()
|
val currentIgnoredUserIds = currentIgnoredUsers.map { it.userId }
|
||||||
.deleteAllFromRealm()
|
// Delete the previous list
|
||||||
|
currentIgnoredUsers.deleteAllFromRealm()
|
||||||
// And save the new received list
|
// And save the new received list
|
||||||
userIds.forEach { realm.createObject(IgnoredUserEntity::class.java).apply { userId = it } }
|
userIds.forEach { realm.createObject(IgnoredUserEntity::class.java).apply { userId = it } }
|
||||||
// TODO If not initial sync, we should execute a init sync
|
|
||||||
|
// Delete all the TimelineEvents for all the ignored users
|
||||||
|
// See https://spec.matrix.org/latest/client-server-api/#client-behaviour-22 :
|
||||||
|
// "Once ignored, the client will no longer receive events sent by that user, with the exception of state events"
|
||||||
|
// So just delete all non-state events from our local storage.
|
||||||
|
realm.where(TimelineEventEntity::class.java)
|
||||||
|
.`in`(TimelineEventEntityFields.ROOT.SENDER, userIds.toTypedArray())
|
||||||
|
.isNull(TimelineEventEntityFields.ROOT.STATE_KEY)
|
||||||
|
.findAll()
|
||||||
|
.also { Timber.d("Deleting ${it.size} TimelineEventEntity from ignored users") }
|
||||||
|
.forEach {
|
||||||
|
it.deleteOnCascade(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the case when some users are unignored from another session
|
||||||
|
val mustRefreshCache = currentIgnoredUserIds.any { currentIgnoredUserId -> currentIgnoredUserId !in userIds }
|
||||||
|
if (mustRefreshCache) {
|
||||||
|
Timber.d("A user has been unignored from another session, an initial sync should be performed")
|
||||||
|
dispatchMustRefresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dispatchMustRefresh() {
|
||||||
|
val session = sessionManager.getSessionComponent(sessionId)?.session()
|
||||||
|
session.dispatchTo(sessionListeners) { safeSession, listener ->
|
||||||
|
listener.onGlobalError(safeSession, GlobalError.InitialSyncRequest(InitialSyncRequestReason.IGNORED_USERS_LIST_CHANGE))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleBreadcrumbs(realm: Realm, event: UserAccountDataEvent) {
|
private fun handleBreadcrumbs(realm: Realm, event: UserAccountDataEvent) {
|
||||||
|
@ -21,9 +21,7 @@ import dagger.Module
|
|||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import org.matrix.android.sdk.api.session.user.UserService
|
import org.matrix.android.sdk.api.session.user.UserService
|
||||||
import org.matrix.android.sdk.internal.session.SessionScope
|
import org.matrix.android.sdk.internal.session.SessionScope
|
||||||
import org.matrix.android.sdk.internal.session.user.accountdata.DefaultSaveIgnoredUsersTask
|
|
||||||
import org.matrix.android.sdk.internal.session.user.accountdata.DefaultUpdateIgnoredUserIdsTask
|
import org.matrix.android.sdk.internal.session.user.accountdata.DefaultUpdateIgnoredUserIdsTask
|
||||||
import org.matrix.android.sdk.internal.session.user.accountdata.SaveIgnoredUsersTask
|
|
||||||
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateIgnoredUserIdsTask
|
import org.matrix.android.sdk.internal.session.user.accountdata.UpdateIgnoredUserIdsTask
|
||||||
import org.matrix.android.sdk.internal.session.user.model.DefaultSearchUserTask
|
import org.matrix.android.sdk.internal.session.user.model.DefaultSearchUserTask
|
||||||
import org.matrix.android.sdk.internal.session.user.model.SearchUserTask
|
import org.matrix.android.sdk.internal.session.user.model.SearchUserTask
|
||||||
@ -48,9 +46,6 @@ internal abstract class UserModule {
|
|||||||
@Binds
|
@Binds
|
||||||
abstract fun bindSearchUserTask(task: DefaultSearchUserTask): SearchUserTask
|
abstract fun bindSearchUserTask(task: DefaultSearchUserTask): SearchUserTask
|
||||||
|
|
||||||
@Binds
|
|
||||||
abstract fun bindSaveIgnoredUsersTask(task: DefaultSaveIgnoredUsersTask): SaveIgnoredUsersTask
|
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindUpdateIgnoredUserIdsTask(task: DefaultUpdateIgnoredUserIdsTask): UpdateIgnoredUserIdsTask
|
abstract fun bindUpdateIgnoredUserIdsTask(task: DefaultUpdateIgnoredUserIdsTask): UpdateIgnoredUserIdsTask
|
||||||
|
|
||||||
|
@ -1,47 +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.user.accountdata
|
|
||||||
|
|
||||||
import com.zhuinden.monarchy.Monarchy
|
|
||||||
import org.matrix.android.sdk.internal.database.model.IgnoredUserEntity
|
|
||||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
|
||||||
import org.matrix.android.sdk.internal.task.Task
|
|
||||||
import org.matrix.android.sdk.internal.util.awaitTransaction
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save the ignored users list in DB
|
|
||||||
*/
|
|
||||||
internal interface SaveIgnoredUsersTask : Task<SaveIgnoredUsersTask.Params, Unit> {
|
|
||||||
data class Params(
|
|
||||||
val userIds: List<String>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class DefaultSaveIgnoredUsersTask @Inject constructor(@SessionDatabase private val monarchy: Monarchy) : SaveIgnoredUsersTask {
|
|
||||||
|
|
||||||
override suspend fun execute(params: SaveIgnoredUsersTask.Params) {
|
|
||||||
monarchy.awaitTransaction { realm ->
|
|
||||||
// clear current ignored users
|
|
||||||
realm.where(IgnoredUserEntity::class.java)
|
|
||||||
.findAll()
|
|
||||||
.deleteAllFromRealm()
|
|
||||||
|
|
||||||
// And save the new received list
|
|
||||||
params.userIds.forEach { realm.createObject(IgnoredUserEntity::class.java).apply { userId = it } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -38,7 +38,6 @@ internal interface UpdateIgnoredUserIdsTask : Task<UpdateIgnoredUserIdsTask.Para
|
|||||||
internal class DefaultUpdateIgnoredUserIdsTask @Inject constructor(
|
internal class DefaultUpdateIgnoredUserIdsTask @Inject constructor(
|
||||||
private val accountDataApi: AccountDataAPI,
|
private val accountDataApi: AccountDataAPI,
|
||||||
@SessionDatabase private val monarchy: Monarchy,
|
@SessionDatabase private val monarchy: Monarchy,
|
||||||
private val saveIgnoredUsersTask: SaveIgnoredUsersTask,
|
|
||||||
@UserId private val userId: String,
|
@UserId private val userId: String,
|
||||||
private val globalErrorReceiver: GlobalErrorReceiver
|
private val globalErrorReceiver: GlobalErrorReceiver
|
||||||
) : UpdateIgnoredUserIdsTask {
|
) : UpdateIgnoredUserIdsTask {
|
||||||
@ -66,8 +65,5 @@ internal class DefaultUpdateIgnoredUserIdsTask @Inject constructor(
|
|||||||
executeRequest(globalErrorReceiver) {
|
executeRequest(globalErrorReceiver) {
|
||||||
accountDataApi.setAccountData(userId, UserAccountDataTypes.TYPE_IGNORED_USER_LIST, body)
|
accountDataApi.setAccountData(userId, UserAccountDataTypes.TYPE_IGNORED_USER_LIST, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the DB right now (do not wait for the sync to come back with updated data, for a faster UI update)
|
|
||||||
saveIgnoredUsersTask.execute(SaveIgnoredUsersTask.Params(list))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ import androidx.viewbinding.ViewBinding
|
|||||||
import com.airbnb.mvrx.MavericksView
|
import com.airbnb.mvrx.MavericksView
|
||||||
import com.bumptech.glide.util.Util
|
import com.bumptech.glide.util.Util
|
||||||
import com.google.android.material.appbar.MaterialToolbar
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import dagger.hilt.android.EntryPointAccessors
|
import dagger.hilt.android.EntryPointAccessors
|
||||||
import im.vector.app.BuildConfig
|
import im.vector.app.BuildConfig
|
||||||
@ -86,6 +87,7 @@ import kotlinx.coroutines.flow.launchIn
|
|||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.api.failure.GlobalError
|
import org.matrix.android.sdk.api.failure.GlobalError
|
||||||
|
import org.matrix.android.sdk.api.failure.InitialSyncRequestReason
|
||||||
import reactivecircus.flowbinding.android.view.clicks
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -266,9 +268,27 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
|
|||||||
is GlobalError.CertificateError ->
|
is GlobalError.CertificateError ->
|
||||||
handleCertificateError(globalError)
|
handleCertificateError(globalError)
|
||||||
GlobalError.ExpiredAccount -> Unit // TODO Handle account expiration
|
GlobalError.ExpiredAccount -> Unit // TODO Handle account expiration
|
||||||
|
is GlobalError.InitialSyncRequest -> handleInitialSyncRequest(globalError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleInitialSyncRequest(initialSyncRequest: GlobalError.InitialSyncRequest) {
|
||||||
|
MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.initial_sync_request_title)
|
||||||
|
.setMessage(
|
||||||
|
getString(R.string.initial_sync_request_content, getString(
|
||||||
|
when (initialSyncRequest.reason) {
|
||||||
|
InitialSyncRequestReason.IGNORED_USERS_LIST_CHANGE -> R.string.initial_sync_request_reason_unignored_users
|
||||||
|
}
|
||||||
|
))
|
||||||
|
)
|
||||||
|
.setPositiveButton(R.string.ok) { _, _ ->
|
||||||
|
MainActivity.restartApp(this, MainActivityArgs(clearCache = true))
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.later, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleCertificateError(certificateError: GlobalError.CertificateError) {
|
private fun handleCertificateError(certificateError: GlobalError.CertificateError) {
|
||||||
singletonEntryPoint()
|
singletonEntryPoint()
|
||||||
.unrecognizedCertificateDialog()
|
.unrecognizedCertificateDialog()
|
||||||
|
@ -119,8 +119,6 @@ import im.vector.app.core.utils.startInstallFromSourceIntent
|
|||||||
import im.vector.app.core.utils.toast
|
import im.vector.app.core.utils.toast
|
||||||
import im.vector.app.databinding.DialogReportContentBinding
|
import im.vector.app.databinding.DialogReportContentBinding
|
||||||
import im.vector.app.databinding.FragmentTimelineBinding
|
import im.vector.app.databinding.FragmentTimelineBinding
|
||||||
import im.vector.app.features.MainActivity
|
|
||||||
import im.vector.app.features.MainActivityArgs
|
|
||||||
import im.vector.app.features.analytics.extensions.toAnalyticsInteraction
|
import im.vector.app.features.analytics.extensions.toAnalyticsInteraction
|
||||||
import im.vector.app.features.analytics.plan.Interaction
|
import im.vector.app.features.analytics.plan.Interaction
|
||||||
import im.vector.app.features.analytics.plan.MobileScreen
|
import im.vector.app.features.analytics.plan.MobileScreen
|
||||||
@ -1733,10 +1731,6 @@ class TimelineFragment @Inject constructor(
|
|||||||
is ParsedCommand.SetMarkdown -> {
|
is ParsedCommand.SetMarkdown -> {
|
||||||
showSnackWithMessage(getString(if (parsedCommand.enable) R.string.markdown_has_been_enabled else R.string.markdown_has_been_disabled))
|
showSnackWithMessage(getString(if (parsedCommand.enable) R.string.markdown_has_been_enabled else R.string.markdown_has_been_disabled))
|
||||||
}
|
}
|
||||||
is ParsedCommand.UnignoreUser -> {
|
|
||||||
// A user has been un-ignored, perform a initial sync
|
|
||||||
MainActivity.restartApp(requireActivity(), MainActivityArgs(clearCache = true))
|
|
||||||
}
|
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,8 +47,6 @@ import im.vector.app.databinding.DialogBaseEditTextBinding
|
|||||||
import im.vector.app.databinding.DialogShareQrCodeBinding
|
import im.vector.app.databinding.DialogShareQrCodeBinding
|
||||||
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
import im.vector.app.databinding.FragmentMatrixProfileBinding
|
||||||
import im.vector.app.databinding.ViewStubRoomMemberProfileHeaderBinding
|
import im.vector.app.databinding.ViewStubRoomMemberProfileHeaderBinding
|
||||||
import im.vector.app.features.MainActivity
|
|
||||||
import im.vector.app.features.MainActivityArgs
|
|
||||||
import im.vector.app.features.analytics.plan.MobileScreen
|
import im.vector.app.features.analytics.plan.MobileScreen
|
||||||
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
import im.vector.app.features.crypto.verification.VerificationBottomSheet
|
||||||
import im.vector.app.features.displayname.getBestName
|
import im.vector.app.features.displayname.getBestName
|
||||||
@ -133,20 +131,13 @@ class RoomMemberProfileFragment @Inject constructor(
|
|||||||
is RoomMemberProfileViewEvents.OnKickActionSuccess -> Unit
|
is RoomMemberProfileViewEvents.OnKickActionSuccess -> Unit
|
||||||
is RoomMemberProfileViewEvents.OnSetPowerLevelSuccess -> Unit
|
is RoomMemberProfileViewEvents.OnSetPowerLevelSuccess -> Unit
|
||||||
is RoomMemberProfileViewEvents.OnBanActionSuccess -> Unit
|
is RoomMemberProfileViewEvents.OnBanActionSuccess -> Unit
|
||||||
is RoomMemberProfileViewEvents.OnIgnoreActionSuccess -> handleOnIgnoreActionSuccess(it)
|
is RoomMemberProfileViewEvents.OnIgnoreActionSuccess -> Unit
|
||||||
is RoomMemberProfileViewEvents.OnInviteActionSuccess -> Unit
|
is RoomMemberProfileViewEvents.OnInviteActionSuccess -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setupLongClicks()
|
setupLongClicks()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleOnIgnoreActionSuccess(action: RoomMemberProfileViewEvents.OnIgnoreActionSuccess) {
|
|
||||||
if (action.shouldPerformInitialSync) {
|
|
||||||
// A user has been un-ignored, perform a initial sync
|
|
||||||
MainActivity.restartApp(requireActivity(), MainActivityArgs(clearCache = true))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupLongClicks() {
|
private fun setupLongClicks() {
|
||||||
headerViews.memberProfileNameView.copyOnLongClick()
|
headerViews.memberProfileNameView.copyOnLongClick()
|
||||||
headerViews.memberProfileIdView.copyOnLongClick()
|
headerViews.memberProfileIdView.copyOnLongClick()
|
||||||
|
@ -25,7 +25,7 @@ sealed class RoomMemberProfileViewEvents : VectorViewEvents {
|
|||||||
data class Loading(val message: CharSequence? = null) : RoomMemberProfileViewEvents()
|
data class Loading(val message: CharSequence? = null) : RoomMemberProfileViewEvents()
|
||||||
data class Failure(val throwable: Throwable) : RoomMemberProfileViewEvents()
|
data class Failure(val throwable: Throwable) : RoomMemberProfileViewEvents()
|
||||||
|
|
||||||
data class OnIgnoreActionSuccess(val shouldPerformInitialSync: Boolean) : RoomMemberProfileViewEvents()
|
object OnIgnoreActionSuccess : RoomMemberProfileViewEvents()
|
||||||
object OnSetPowerLevelSuccess : RoomMemberProfileViewEvents()
|
object OnSetPowerLevelSuccess : RoomMemberProfileViewEvents()
|
||||||
object OnInviteActionSuccess : RoomMemberProfileViewEvents()
|
object OnInviteActionSuccess : RoomMemberProfileViewEvents()
|
||||||
object OnKickActionSuccess : RoomMemberProfileViewEvents()
|
object OnKickActionSuccess : RoomMemberProfileViewEvents()
|
||||||
|
@ -390,7 +390,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(
|
|||||||
} else {
|
} else {
|
||||||
session.ignoreUserIds(listOf(state.userId))
|
session.ignoreUserIds(listOf(state.userId))
|
||||||
}
|
}
|
||||||
RoomMemberProfileViewEvents.OnIgnoreActionSuccess(isIgnored)
|
RoomMemberProfileViewEvents.OnIgnoreActionSuccess
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
RoomMemberProfileViewEvents.Failure(failure)
|
RoomMemberProfileViewEvents.Failure(failure)
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,6 @@ import im.vector.app.core.extensions.cleanup
|
|||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.databinding.FragmentGenericRecyclerBinding
|
import im.vector.app.databinding.FragmentGenericRecyclerBinding
|
||||||
import im.vector.app.features.MainActivity
|
|
||||||
import im.vector.app.features.MainActivityArgs
|
|
||||||
import im.vector.app.features.analytics.plan.MobileScreen
|
import im.vector.app.features.analytics.plan.MobileScreen
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -62,16 +60,11 @@ class VectorSettingsIgnoredUsersFragment @Inject constructor(
|
|||||||
when (it) {
|
when (it) {
|
||||||
is IgnoredUsersViewEvents.Loading -> showLoading(it.message)
|
is IgnoredUsersViewEvents.Loading -> showLoading(it.message)
|
||||||
is IgnoredUsersViewEvents.Failure -> showFailure(it.throwable)
|
is IgnoredUsersViewEvents.Failure -> showFailure(it.throwable)
|
||||||
IgnoredUsersViewEvents.Success -> handleSuccess()
|
IgnoredUsersViewEvents.Success -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSuccess() {
|
|
||||||
// A user has been un-ignored, perform a initial sync
|
|
||||||
MainActivity.restartApp(requireActivity(), MainActivityArgs(clearCache = true))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
ignoredUsersController.callback = null
|
ignoredUsersController.callback = null
|
||||||
views.genericRecyclerView.cleanup()
|
views.genericRecyclerView.cleanup()
|
||||||
|
@ -176,6 +176,9 @@
|
|||||||
<string name="initial_sync_start_importing_account_groups">Initial sync:\nImporting communities</string>
|
<string name="initial_sync_start_importing_account_groups">Initial sync:\nImporting communities</string>
|
||||||
<string name="initial_sync_start_importing_account_data">Initial sync:\nImporting account data</string>
|
<string name="initial_sync_start_importing_account_data">Initial sync:\nImporting account data</string>
|
||||||
|
|
||||||
|
<string name="initial_sync_request_title">Initial sync request</string>
|
||||||
|
<string name="initial_sync_request_content">${app_name} needs to perform a clear cache to be up to date, for the following reason:\n%s\n\nNote that this action will restart the app and it may take some time.</string>
|
||||||
|
<string name="initial_sync_request_reason_unignored_users">- Some users have been unignored</string>
|
||||||
|
|
||||||
<string name="event_status_sent_message">Message sent</string>
|
<string name="event_status_sent_message">Message sent</string>
|
||||||
<string name="event_status_sending_message">Sending message…</string>
|
<string name="event_status_sending_message">Sending message…</string>
|
||||||
@ -634,7 +637,7 @@
|
|||||||
<string name="room_participants_action_ignore">Ignore</string>
|
<string name="room_participants_action_ignore">Ignore</string>
|
||||||
|
|
||||||
<string name="room_participants_action_unignore_title">Unignore user</string>
|
<string name="room_participants_action_unignore_title">Unignore user</string>
|
||||||
<string name="room_participants_action_unignore_prompt_msg">Unignoring this user will show all messages from them again.\n\nNote that this action will restart the app and it may take some time.</string>
|
<string name="room_participants_action_unignore_prompt_msg">Unignoring this user will show all messages from them again.</string>
|
||||||
<string name="room_participants_action_unignore">Unignore</string>
|
<string name="room_participants_action_unignore">Unignore</string>
|
||||||
|
|
||||||
<string name="room_participants_action_cancel_invite_title">Cancel invite</string>
|
<string name="room_participants_action_cancel_invite_title">Cancel invite</string>
|
||||||
@ -1035,7 +1038,7 @@
|
|||||||
<string name="settings_fail_to_update_password">Failed to update password</string>
|
<string name="settings_fail_to_update_password">Failed to update password</string>
|
||||||
<string name="settings_fail_to_update_password_invalid_current_password">The password is not valid</string>
|
<string name="settings_fail_to_update_password_invalid_current_password">The password is not valid</string>
|
||||||
<string name="settings_password_updated">Your password has been updated</string>
|
<string name="settings_password_updated">Your password has been updated</string>
|
||||||
<string name="settings_unignore_user">Show all messages from %s?\n\nNote that this action will restart the app and it may take some time.</string>
|
<string name="settings_unignore_user">Show all messages from %s?</string>
|
||||||
|
|
||||||
<string name="settings_emails_and_phone_numbers_title">Emails and phone numbers</string>
|
<string name="settings_emails_and_phone_numbers_title">Emails and phone numbers</string>
|
||||||
<string name="settings_emails_and_phone_numbers_summary">Manage emails and phone numbers linked to your Matrix account</string>
|
<string name="settings_emails_and_phone_numbers_summary">Manage emails and phone numbers linked to your Matrix account</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user