mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 11:59:12 +03:00
Delete the local rooms when the room list is shown
This commit is contained in:
parent
10d683ad5d
commit
7ea2d0a86d
11 changed files with 201 additions and 45 deletions
|
@ -47,6 +47,11 @@ interface RoomService {
|
|||
*/
|
||||
suspend fun createLocalRoom(createRoomParams: CreateRoomParams): String
|
||||
|
||||
/**
|
||||
* Delete a local room with all its related events.
|
||||
*/
|
||||
suspend fun deleteLocalRoom(roomId: String)
|
||||
|
||||
/**
|
||||
* Create a direct room asynchronously. This is a facility method to create a direct room with the necessary parameters.
|
||||
*/
|
||||
|
|
|
@ -23,13 +23,20 @@ import io.realm.kotlin.createObject
|
|||
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
|
||||
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
|
||||
|
||||
internal fun CurrentStateEventEntity.Companion.whereRoomId(
|
||||
realm: Realm,
|
||||
roomId: String
|
||||
): RealmQuery<CurrentStateEventEntity> {
|
||||
return realm.where(CurrentStateEventEntity::class.java)
|
||||
.equalTo(CurrentStateEventEntityFields.ROOM_ID, roomId)
|
||||
}
|
||||
|
||||
internal fun CurrentStateEventEntity.Companion.whereType(
|
||||
realm: Realm,
|
||||
roomId: String,
|
||||
type: String
|
||||
): RealmQuery<CurrentStateEventEntity> {
|
||||
return realm.where(CurrentStateEventEntity::class.java)
|
||||
.equalTo(CurrentStateEventEntityFields.ROOM_ID, roomId)
|
||||
return whereRoomId(realm = realm, roomId = roomId)
|
||||
.equalTo(CurrentStateEventEntityFields.TYPE, type)
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.matrix.android.sdk.internal.session.room.alias.DeleteRoomAliasTask
|
|||
import org.matrix.android.sdk.internal.session.room.alias.GetRoomIdByAliasTask
|
||||
import org.matrix.android.sdk.internal.session.room.create.CreateLocalRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.create.CreateRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.delete.DeleteLocalRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.membership.RoomChangeMembershipStateDataSource
|
||||
import org.matrix.android.sdk.internal.session.room.membership.RoomMemberHelper
|
||||
import org.matrix.android.sdk.internal.session.room.membership.joining.JoinRoomTask
|
||||
|
@ -62,6 +63,7 @@ internal class DefaultRoomService @Inject constructor(
|
|||
@SessionDatabase private val monarchy: Monarchy,
|
||||
private val createRoomTask: CreateRoomTask,
|
||||
private val createLocalRoomTask: CreateLocalRoomTask,
|
||||
private val deleteLocalRoomTask: DeleteLocalRoomTask,
|
||||
private val joinRoomTask: JoinRoomTask,
|
||||
private val markAllRoomsReadTask: MarkAllRoomsReadTask,
|
||||
private val updateBreadcrumbsTask: UpdateBreadcrumbsTask,
|
||||
|
@ -84,6 +86,10 @@ internal class DefaultRoomService @Inject constructor(
|
|||
return createLocalRoomTask.execute(createRoomParams)
|
||||
}
|
||||
|
||||
override suspend fun deleteLocalRoom(roomId: String) {
|
||||
deleteLocalRoomTask.execute(DeleteLocalRoomTask.Params(roomId))
|
||||
}
|
||||
|
||||
override fun getRoom(roomId: String): Room? {
|
||||
return roomGetter.getRoom(roomId)
|
||||
}
|
||||
|
|
|
@ -47,6 +47,8 @@ import org.matrix.android.sdk.internal.session.room.create.CreateLocalRoomTask
|
|||
import org.matrix.android.sdk.internal.session.room.create.CreateRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.create.DefaultCreateLocalRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.create.DefaultCreateRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.delete.DefaultDeleteLocalRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.delete.DeleteLocalRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.directory.DefaultGetPublicRoomTask
|
||||
import org.matrix.android.sdk.internal.session.room.directory.DefaultGetRoomDirectoryVisibilityTask
|
||||
import org.matrix.android.sdk.internal.session.room.directory.DefaultSetRoomDirectoryVisibilityTask
|
||||
|
@ -197,6 +199,9 @@ internal abstract class RoomModule {
|
|||
@Binds
|
||||
abstract fun bindCreateLocalRoomTask(task: DefaultCreateLocalRoomTask): CreateLocalRoomTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindDeleteLocalRoomTask(task: DefaultDeleteLocalRoomTask): DeleteLocalRoomTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindGetPublicRoomTask(task: DefaultGetPublicRoomTask): GetPublicRoomTask
|
||||
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.matrix.android.sdk.internal.session.room.delete
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
|
||||
import org.matrix.android.sdk.internal.database.model.ChunkEntity
|
||||
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntity
|
||||
import org.matrix.android.sdk.internal.database.model.EventEntity
|
||||
import org.matrix.android.sdk.internal.database.model.RoomEntity
|
||||
import org.matrix.android.sdk.internal.database.model.RoomMemberSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity
|
||||
import org.matrix.android.sdk.internal.database.model.TimelineEventEntity
|
||||
import org.matrix.android.sdk.internal.database.query.where
|
||||
import org.matrix.android.sdk.internal.database.query.whereRoomId
|
||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||
import org.matrix.android.sdk.internal.session.room.delete.DeleteLocalRoomTask.Params
|
||||
import org.matrix.android.sdk.internal.task.Task
|
||||
import org.matrix.android.sdk.internal.util.awaitTransaction
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface DeleteLocalRoomTask : Task<Params, Unit> {
|
||||
data class Params(val roomId: String)
|
||||
}
|
||||
|
||||
internal class DefaultDeleteLocalRoomTask @Inject constructor(
|
||||
@SessionDatabase private val monarchy: Monarchy,
|
||||
) : DeleteLocalRoomTask {
|
||||
|
||||
override suspend fun execute(params: Params) {
|
||||
val roomId = params.roomId
|
||||
|
||||
if (RoomLocalEcho.isLocalEchoId(roomId)) {
|
||||
monarchy.awaitTransaction { realm ->
|
||||
Timber.i("## DeleteLocalRoomTask - delete local room id $roomId")
|
||||
RoomMemberSummaryEntity.where(realm, roomId = roomId).findAll()
|
||||
?.also { Timber.i("## DeleteLocalRoomTask - RoomMemberSummaryEntity - delete ${it.size} entries") }
|
||||
?.deleteAllFromRealm()
|
||||
CurrentStateEventEntity.whereRoomId(realm, roomId = roomId).findAll()
|
||||
?.also { Timber.i("## DeleteLocalRoomTask - CurrentStateEventEntity - delete ${it.size} entries") }
|
||||
?.deleteAllFromRealm()
|
||||
EventEntity.whereRoomId(realm, roomId = roomId).findAll()
|
||||
?.also { Timber.i("## DeleteLocalRoomTask - EventEntity - delete ${it.size} entries") }
|
||||
?.deleteAllFromRealm()
|
||||
TimelineEventEntity.whereRoomId(realm, roomId = roomId).findAll()
|
||||
?.also { Timber.i("## DeleteLocalRoomTask - TimelineEventEntity - delete ${it.size} entries") }
|
||||
?.deleteAllFromRealm()
|
||||
ChunkEntity.where(realm, roomId = roomId).findAll()
|
||||
?.also { Timber.i("## DeleteLocalRoomTask - RoomMemberSummaryEntity - delete ${it.size} entries") }
|
||||
?.deleteAllFromRealm()
|
||||
RoomSummaryEntity.where(realm, roomId = roomId).findAll()
|
||||
?.also { Timber.i("## DeleteLocalRoomTask - RoomSummaryEntity - delete ${it.size} entries") }
|
||||
?.deleteAllFromRealm()
|
||||
RoomEntity.where(realm, roomId = roomId).findAll()
|
||||
?.also { Timber.i("## DeleteLocalRoomTask - RoomEntity - delete ${it.size} entries") }
|
||||
?.deleteAllFromRealm()
|
||||
}
|
||||
} else {
|
||||
Timber.i("## DeleteLocalRoomTask - Failed to remove room id $roomId: not a local room")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@ import org.matrix.android.sdk.api.session.events.model.Event
|
|||
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
|
||||
import org.matrix.android.sdk.api.session.room.sender.SenderInfo
|
||||
import org.matrix.android.sdk.api.session.sync.SyncRequestState
|
||||
import org.matrix.android.sdk.api.session.sync.SyncState
|
||||
|
@ -103,4 +104,6 @@ data class RoomDetailViewState(
|
|||
fun isDm() = asyncRoomSummary()?.isDirect == true
|
||||
|
||||
fun isThreadTimeline() = rootThreadEventId != null
|
||||
|
||||
fun isLocalRoom() = RoomLocalEcho.isLocalEchoId(roomId)
|
||||
}
|
||||
|
|
|
@ -1695,31 +1695,41 @@ class TimelineFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun renderToolbar(roomSummary: RoomSummary?) {
|
||||
if (!isThreadTimeLine()) {
|
||||
views.includeRoomToolbar.roomToolbarContentView.isVisible = true
|
||||
views.includeThreadToolbar.roomToolbarThreadConstraintLayout.isVisible = false
|
||||
if (roomSummary == null) {
|
||||
views.includeRoomToolbar.roomToolbarContentView.isClickable = false
|
||||
} else {
|
||||
views.includeRoomToolbar.roomToolbarContentView.isClickable = roomSummary.membership == Membership.JOIN
|
||||
views.includeRoomToolbar.roomToolbarTitleView.text = roomSummary.displayName
|
||||
avatarRenderer.render(roomSummary.toMatrixItem(), views.includeRoomToolbar.roomToolbarAvatarImageView)
|
||||
val showPresence = roomSummary.isDirect
|
||||
views.includeRoomToolbar.roomToolbarPresenceImageView.render(showPresence, roomSummary.directUserPresence)
|
||||
val shieldView = if (showPresence) views.includeRoomToolbar.roomToolbarTitleShield else views.includeRoomToolbar.roomToolbarAvatarShield
|
||||
shieldView.render(roomSummary.roomEncryptionTrustLevel)
|
||||
views.includeRoomToolbar.roomToolbarPublicImageView.isVisible = roomSummary.isPublic && !roomSummary.isDirect
|
||||
when {
|
||||
isLocalRoom() -> {
|
||||
views.includeRoomToolbar.roomToolbarContentView.isVisible = false
|
||||
views.includeThreadToolbar.roomToolbarThreadConstraintLayout.isVisible = false
|
||||
setupToolbar(views.roomToolbar)
|
||||
.setTitle(R.string.fab_menu_create_chat)
|
||||
.allowBack(useCross = true)
|
||||
}
|
||||
} else {
|
||||
views.includeRoomToolbar.roomToolbarContentView.isVisible = false
|
||||
views.includeThreadToolbar.roomToolbarThreadConstraintLayout.isVisible = true
|
||||
timelineArgs.threadTimelineArgs?.let {
|
||||
val matrixItem = MatrixItem.RoomItem(it.roomId, it.displayName, it.avatarUrl)
|
||||
avatarRenderer.render(matrixItem, views.includeThreadToolbar.roomToolbarThreadImageView)
|
||||
views.includeThreadToolbar.roomToolbarThreadShieldImageView.render(it.roomEncryptionTrustLevel)
|
||||
views.includeThreadToolbar.roomToolbarThreadSubtitleTextView.text = it.displayName
|
||||
isThreadTimeLine() -> {
|
||||
views.includeRoomToolbar.roomToolbarContentView.isVisible = false
|
||||
views.includeThreadToolbar.roomToolbarThreadConstraintLayout.isVisible = true
|
||||
timelineArgs.threadTimelineArgs?.let {
|
||||
val matrixItem = MatrixItem.RoomItem(it.roomId, it.displayName, it.avatarUrl)
|
||||
avatarRenderer.render(matrixItem, views.includeThreadToolbar.roomToolbarThreadImageView)
|
||||
views.includeThreadToolbar.roomToolbarThreadShieldImageView.render(it.roomEncryptionTrustLevel)
|
||||
views.includeThreadToolbar.roomToolbarThreadSubtitleTextView.text = it.displayName
|
||||
}
|
||||
views.includeThreadToolbar.roomToolbarThreadTitleTextView.text = resources.getText(R.string.thread_timeline_title)
|
||||
}
|
||||
else -> {
|
||||
views.includeRoomToolbar.roomToolbarContentView.isVisible = true
|
||||
views.includeThreadToolbar.roomToolbarThreadConstraintLayout.isVisible = false
|
||||
if (roomSummary == null) {
|
||||
views.includeRoomToolbar.roomToolbarContentView.isClickable = false
|
||||
} else {
|
||||
views.includeRoomToolbar.roomToolbarContentView.isClickable = roomSummary.membership == Membership.JOIN
|
||||
views.includeRoomToolbar.roomToolbarTitleView.text = roomSummary.displayName
|
||||
avatarRenderer.render(roomSummary.toMatrixItem(), views.includeRoomToolbar.roomToolbarAvatarImageView)
|
||||
val showPresence = roomSummary.isDirect
|
||||
views.includeRoomToolbar.roomToolbarPresenceImageView.render(showPresence, roomSummary.directUserPresence)
|
||||
val shieldView = if (showPresence) views.includeRoomToolbar.roomToolbarTitleShield else views.includeRoomToolbar.roomToolbarAvatarShield
|
||||
shieldView.render(roomSummary.roomEncryptionTrustLevel)
|
||||
views.includeRoomToolbar.roomToolbarPublicImageView.isVisible = roomSummary.isPublic && !roomSummary.isDirect
|
||||
}
|
||||
}
|
||||
views.includeThreadToolbar.roomToolbarThreadTitleTextView.text = resources.getText(R.string.thread_timeline_title)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2658,6 +2668,11 @@ class TimelineFragment @Inject constructor(
|
|||
*/
|
||||
private fun isThreadTimeLine(): Boolean = timelineArgs.threadTimelineArgs?.rootThreadEventId != null
|
||||
|
||||
/**
|
||||
* Returns true if the current room is a local room, false otherwise.
|
||||
*/
|
||||
private fun isLocalRoom(): Boolean = withState(timelineViewModel) { it.isLocalRoom() }
|
||||
|
||||
/**
|
||||
* Returns the root thread event if we are in a thread room, otherwise returns null.
|
||||
*/
|
||||
|
|
|
@ -732,26 +732,30 @@ class TimelineViewModel @AssistedInject constructor(
|
|||
return@withState false
|
||||
}
|
||||
|
||||
if (initialState.isThreadTimeline()) {
|
||||
when (itemId) {
|
||||
R.id.menu_thread_timeline_view_in_room,
|
||||
R.id.menu_thread_timeline_copy_link,
|
||||
R.id.menu_thread_timeline_share -> true
|
||||
else -> false
|
||||
when {
|
||||
initialState.isLocalRoom() -> false
|
||||
initialState.isThreadTimeline() -> {
|
||||
when (itemId) {
|
||||
R.id.menu_thread_timeline_view_in_room,
|
||||
R.id.menu_thread_timeline_copy_link,
|
||||
R.id.menu_thread_timeline_share -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
when (itemId) {
|
||||
R.id.timeline_setting -> true
|
||||
R.id.invite -> state.canInvite
|
||||
R.id.open_matrix_apps -> true
|
||||
R.id.voice_call -> state.isCallOptionAvailable()
|
||||
R.id.video_call -> state.isCallOptionAvailable() || state.jitsiState.confId == null || state.jitsiState.hasJoined
|
||||
// Show Join conference button only if there is an active conf id not joined. Otherwise fallback to default video disabled. ^
|
||||
R.id.join_conference -> !state.isCallOptionAvailable() && state.jitsiState.confId != null && !state.jitsiState.hasJoined
|
||||
R.id.search -> state.isSearchAvailable()
|
||||
R.id.menu_timeline_thread_list -> vectorPreferences.areThreadMessagesEnabled()
|
||||
R.id.dev_tools -> vectorPreferences.developerMode()
|
||||
else -> false
|
||||
else -> {
|
||||
when (itemId) {
|
||||
R.id.timeline_setting -> true
|
||||
R.id.invite -> state.canInvite
|
||||
R.id.open_matrix_apps -> true
|
||||
R.id.voice_call -> state.isCallOptionAvailable()
|
||||
R.id.video_call -> state.isCallOptionAvailable() || state.jitsiState.confId == null || state.jitsiState.hasJoined
|
||||
// Show Join conference button only if there is an active conf id not joined. Otherwise fallback to default video disabled. ^
|
||||
R.id.join_conference -> !state.isCallOptionAvailable() && state.jitsiState.confId != null && !state.jitsiState.hasJoined
|
||||
R.id.search -> state.isSearchAvailable()
|
||||
R.id.menu_timeline_thread_list -> vectorPreferences.areThreadMessagesEnabled()
|
||||
R.id.dev_tools -> vectorPreferences.developerMode()
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,6 +146,10 @@ class RoomListFragment @Inject constructor(
|
|||
(it.contentEpoxyController as? RoomSummaryPagedController)?.roomChangeMembershipStates = ms
|
||||
}
|
||||
}
|
||||
roomListViewModel.onEach(RoomListViewState::localRoomIds) {
|
||||
// Local rooms should not exist anymore when the room list is shown
|
||||
roomListViewModel.deleteLocalRooms(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshCollapseStates() {
|
||||
|
|
|
@ -48,7 +48,10 @@ import org.matrix.android.sdk.api.session.getRoom
|
|||
import org.matrix.android.sdk.api.session.getRoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult
|
||||
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.localecho.RoomLocalEcho
|
||||
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
|
||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.session.room.state.isPublic
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
|
@ -96,6 +99,7 @@ class RoomListViewModel @AssistedInject constructor(
|
|||
|
||||
init {
|
||||
observeMembershipChanges()
|
||||
observeLocalRooms()
|
||||
|
||||
appStateHandler.selectedRoomGroupingFlow
|
||||
.distinctUntilChanged()
|
||||
|
@ -123,6 +127,23 @@ class RoomListViewModel @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun observeLocalRooms() {
|
||||
val queryParams = roomSummaryQueryParams {
|
||||
memberships = listOf(Membership.JOIN)
|
||||
}
|
||||
session
|
||||
.flow()
|
||||
.liveRoomSummaries(queryParams)
|
||||
.map { roomSummaries ->
|
||||
roomSummaries.mapNotNull { summary ->
|
||||
summary.roomId.takeIf { RoomLocalEcho.isLocalEchoId(it) }
|
||||
}.toSet()
|
||||
}
|
||||
.setOnEach { roomIds ->
|
||||
copy(localRoomIds = roomIds)
|
||||
}
|
||||
}
|
||||
|
||||
companion object : MavericksViewModelFactory<RoomListViewModel, RoomListViewState> by hiltMavericksViewModelFactory()
|
||||
|
||||
private val roomListSectionBuilder = if (appStateHandler.getCurrentRoomGroupingMethod() is RoomGroupingMethod.BySpace) {
|
||||
|
@ -173,6 +194,14 @@ class RoomListViewModel @AssistedInject constructor(
|
|||
return session.getRoom(roomId)?.stateService()?.isPublic().orFalse()
|
||||
}
|
||||
|
||||
fun deleteLocalRooms(roomsIds: Set<String>) {
|
||||
viewModelScope.launch {
|
||||
roomsIds.forEach {
|
||||
session.roomService().deleteLocalRoom(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PRIVATE METHODS *****************************************************************************
|
||||
|
||||
private fun handleSelectRoom(action: RoomListAction.SelectRoom) = withState {
|
||||
|
|
|
@ -30,7 +30,8 @@ data class RoomListViewState(
|
|||
val roomMembershipChanges: Map<String, ChangeMembershipState> = emptyMap(),
|
||||
val asyncSuggestedRooms: Async<List<SpaceChildInfo>> = Uninitialized,
|
||||
val currentUserName: String? = null,
|
||||
val currentRoomGrouping: Async<RoomGroupingMethod> = Uninitialized
|
||||
val currentRoomGrouping: Async<RoomGroupingMethod> = Uninitialized,
|
||||
val localRoomIds: Set<String> = emptySet()
|
||||
) : MavericksState {
|
||||
|
||||
constructor(args: RoomListParams) : this(displayMode = args.displayMode)
|
||||
|
|
Loading…
Reference in a new issue