diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 02fef53306..f1922645ac 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -686,6 +686,7 @@ Leave room Are you sure you want to leave the room? This room is not public. You will not be able to rejoin without an invite. + You\'re the only admin of this room. Leaving it will mean no one has control over it. Direct Messages diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomExtensions.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomExtensions.kt index 29638857bc..f9c04ac34e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomExtensions.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomExtensions.kt @@ -16,6 +16,7 @@ package org.matrix.android.sdk.api.session.room +import kotlinx.coroutines.flow.Flow import org.matrix.android.sdk.api.query.QueryStateEventValue import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.events.model.Event @@ -25,6 +26,8 @@ import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.create.getRoomCreateContentWithSender import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import org.matrix.android.sdk.api.session.user.model.User +import org.matrix.android.sdk.internal.di.UserId /** * Get a TimelineEvent using the TimelineService of a Room. diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt index 1e04880382..51b413058e 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt @@ -25,7 +25,6 @@ import com.airbnb.epoxy.OnModelBuildFinishedListener import com.airbnb.mvrx.args import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState -import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint import im.vector.app.R import im.vector.app.core.epoxy.LayoutManagerStateRestorer @@ -45,6 +44,7 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA import im.vector.app.features.home.room.list.widget.NotifsFabMenuView import im.vector.app.features.matrixto.OriginOfMatrixTo import im.vector.app.features.notifications.NotificationDrawerManager +import im.vector.app.features.room.LeaveRoomPrompt import im.vector.lib.strings.CommonStrings import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.launchIn @@ -422,7 +422,7 @@ class RoomListFragment : } } - private fun handleQuickActions(quickAction: RoomListQuickActionsSharedAction) { + private suspend fun handleQuickActions(quickAction: RoomListQuickActionsSharedAction) { when (quickAction) { is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> { roomListViewModel.handle(RoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.ALL_MESSAGES_NOISY)) @@ -451,26 +451,11 @@ class RoomListFragment : } } - private fun promptLeaveRoom(roomId: String) { - val isPublicRoom = roomListViewModel.isPublicRoom(roomId) - val message = buildString { - append(getString(CommonStrings.room_participants_leave_prompt_msg)) - if (!isPublicRoom) { - append("\n\n") - append(getString(CommonStrings.room_participants_leave_private_warning)) - } + private suspend fun promptLeaveRoom(roomId: String) { + val warning = roomListViewModel.getLeaveRoomWarning(roomId) + LeaveRoomPrompt.show(requireContext(), warning) { + roomListViewModel.handle(RoomListAction.LeaveRoom(roomId)) } - MaterialAlertDialogBuilder( - requireContext(), - if (isPublicRoom) 0 else im.vector.lib.ui.styles.R.style.ThemeOverlay_Vector_MaterialAlertDialog_Destructive - ) - .setTitle(CommonStrings.room_participants_leave_prompt_title) - .setMessage(message) - .setPositiveButton(CommonStrings.action_leave) { _, _ -> - roomListViewModel.handle(RoomListAction.LeaveRoom(roomId)) - } - .setNegativeButton(CommonStrings.action_cancel, null) - .show() } override fun invalidate() = withState(roomListViewModel) { state -> diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt index 907c4cca72..d5821fab81 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt @@ -26,6 +26,8 @@ import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom import im.vector.app.features.analytics.plan.JoinedRoom import im.vector.app.features.displayname.getBestName import im.vector.app.features.invite.AutoAcceptInvites +import im.vector.app.features.room.LeaveRoomPrompt +import im.vector.app.features.room.getLeaveRoomWarning import im.vector.app.features.settings.VectorPreferences import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.distinctUntilChanged @@ -41,7 +43,6 @@ import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState 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 import timber.log.Timber @@ -150,10 +151,11 @@ class RoomListViewModel @AssistedInject constructor( } } - fun isPublicRoom(roomId: String): Boolean { - return session.getRoom(roomId)?.stateService()?.isPublic().orFalse() + suspend fun getLeaveRoomWarning(roomId: String): LeaveRoomPrompt.Warning { + return session.getLeaveRoomWarning(roomId) } + // PRIVATE METHODS ***************************************************************************** private fun handleSelectRoom(action: RoomListAction.SelectRoom) = withState { diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt index 02d702685a..a6421f19a0 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt @@ -18,7 +18,6 @@ import androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode import androidx.recyclerview.widget.LinearLayoutManager import com.airbnb.epoxy.OnModelBuildFinishedListener import com.airbnb.mvrx.fragmentViewModel -import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.epoxy.LayoutManagerStateRestorer import im.vector.app.core.extensions.cleanup @@ -36,7 +35,7 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA import im.vector.app.features.home.room.list.home.header.HomeRoomFilter import im.vector.app.features.home.room.list.home.header.HomeRoomsHeadersController import im.vector.app.features.home.room.list.home.invites.InvitesActivity -import im.vector.lib.strings.CommonStrings +import im.vector.app.features.room.LeaveRoomPrompt import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -103,7 +102,7 @@ class HomeRoomListFragment : } } - private fun handleQuickActions(quickAction: RoomListQuickActionsSharedAction) { + private suspend fun handleQuickActions(quickAction: RoomListQuickActionsSharedAction) { when (quickAction) { is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> { roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.ALL_MESSAGES_NOISY)) @@ -185,26 +184,11 @@ class HomeRoomListFragment : concatAdapter.addAdapter(roomsAdapter) } - private fun promptLeaveRoom(roomId: String) { - val isPublicRoom = roomListViewModel.isPublicRoom(roomId) - val message = buildString { - append(getString(CommonStrings.room_participants_leave_prompt_msg)) - if (!isPublicRoom) { - append("\n\n") - append(getString(CommonStrings.room_participants_leave_private_warning)) - } + private suspend fun promptLeaveRoom(roomId: String) { + val warning = roomListViewModel.getLeaveRoomWarning(roomId) + LeaveRoomPrompt.show(requireContext(), warning) { + roomListViewModel.handle(HomeRoomListAction.LeaveRoom(roomId)) } - MaterialAlertDialogBuilder( - requireContext(), - if (isPublicRoom) 0 else im.vector.lib.ui.styles.R.style.ThemeOverlay_Vector_MaterialAlertDialog_Destructive - ) - .setTitle(CommonStrings.room_participants_leave_prompt_title) - .setMessage(message) - .setPositiveButton(CommonStrings.action_leave) { _, _ -> - roomListViewModel.handle(HomeRoomListAction.LeaveRoom(roomId)) - } - .setNegativeButton(CommonStrings.action_cancel, null) - .show() } private fun onInvitesCounterClicked() { diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt index d232dab3fb..2b367d75e9 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt @@ -26,6 +26,8 @@ import im.vector.app.features.analytics.extensions.toTrackingValue import im.vector.app.features.analytics.plan.UserProperties import im.vector.app.features.displayname.getBestName import im.vector.app.features.home.room.list.home.header.HomeRoomFilter +import im.vector.app.features.room.LeaveRoomPrompt +import im.vector.app.features.room.getLeaveRoomWarning import im.vector.lib.strings.CommonStrings import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine @@ -331,8 +333,8 @@ class HomeRoomListViewModel @AssistedInject constructor( filteredPagedRoomSummariesLive.queryParams = getFilteredQueryParams(newFilter, filteredPagedRoomSummariesLive.queryParams) } - fun isPublicRoom(roomId: String): Boolean { - return session.getRoom(roomId)?.stateService()?.isPublic().orFalse() + suspend fun getLeaveRoomWarning(roomId: String): LeaveRoomPrompt.Warning { + return session.getLeaveRoomWarning(roomId) } private fun handleSelectRoom(action: HomeRoomListAction.SelectRoom) = withState { diff --git a/vector/src/main/java/im/vector/app/features/powerlevel/Role.kt b/vector/src/main/java/im/vector/app/features/powerlevel/Role.kt index d61bbef768..6ac6449820 100644 --- a/vector/src/main/java/im/vector/app/features/powerlevel/Role.kt +++ b/vector/src/main/java/im/vector/app/features/powerlevel/Role.kt @@ -7,6 +7,37 @@ package im.vector.app.features.powerlevel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map +import org.matrix.android.sdk.api.session.room.Room +import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams +import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary import org.matrix.android.sdk.api.session.room.powerlevels.Role +import org.matrix.android.sdk.flow.flow fun Role.isOwner() = this == Role.Creator || this == Role.SuperAdmin + +fun Room.membersByRoleFlow(): Flow>> { + val roomMembersFlow = flow().liveRoomMembers(roomMemberQueryParams()) + val roomPowerLevelsFlow = PowerLevelsFlowFactory(this).createFlow() + return combine(roomMembersFlow, roomPowerLevelsFlow) { roomMembers, roomPowerLevels -> + roomMembers.groupBy { roomPowerLevels.getSuggestedRole(it.userId) } + }.distinctUntilChanged() +} + +fun Room.isLastAdminFlow(userId: String): Flow { + return membersByRoleFlow().map { membersByRole -> + val creatorMembers = membersByRole[Role.Creator].orEmpty() + val superAdminMembers = membersByRole[Role.SuperAdmin].orEmpty() + val adminMembers = membersByRole[Role.Admin].orEmpty() + val joinedAdmins = (adminMembers + creatorMembers + superAdminMembers).filter { it.membership == Membership.JOIN } + if (joinedAdmins.size == 1) { + joinedAdmins.first().userId == userId + } else { + false + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/room/LeaveRoomPrompt.kt b/vector/src/main/java/im/vector/app/features/room/LeaveRoomPrompt.kt new file mode 100644 index 0000000000..a43e7e35ed --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/room/LeaveRoomPrompt.kt @@ -0,0 +1,67 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package im.vector.app.features.room + +import android.content.Context +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import im.vector.app.features.powerlevel.isLastAdminFlow +import im.vector.app.features.room.LeaveRoomPrompt.Warning +import im.vector.lib.strings.CommonStrings +import im.vector.lib.ui.styles.R +import kotlinx.coroutines.flow.first +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.room.state.isPublic + +object LeaveRoomPrompt { + + enum class Warning { + LAST_ADMIN, + PRIVATE_ROOM, + NONE + }; + + fun show( + context: Context, + warning: Warning, + onLeaveClick: () -> Unit + ) { + val hasWarning = warning != Warning.NONE + val message = buildString { + append(context.getString(CommonStrings.room_participants_leave_prompt_msg)) + if (hasWarning) append("\n\n") + when (warning) { + Warning.LAST_ADMIN -> append(context.getString(CommonStrings.room_participants_leave_last_admin)) + Warning.PRIVATE_ROOM -> append(context.getString(CommonStrings.room_participants_leave_private_warning)) + Warning.NONE -> Unit + } + } + MaterialAlertDialogBuilder( + context, + if (hasWarning) R.style.ThemeOverlay_Vector_MaterialAlertDialog_Destructive else 0 + ) + .setTitle(CommonStrings.room_participants_leave_prompt_title) + .setMessage(message) + .setPositiveButton(CommonStrings.action_leave) { _, _ -> + onLeaveClick() + } + .setNegativeButton(CommonStrings.action_cancel, null) + .show() + } +} + +suspend fun Session.getLeaveRoomWarning(roomId: String): Warning { + val room = getRoom(roomId) ?: return Warning.NONE + val isLastAdmin = room.isLastAdminFlow(myUserId).first() + return when { + isLastAdmin -> Warning.LAST_ADMIN + !room.stateService().isPublic() -> Warning.PRIVATE_ROOM + else -> Warning.NONE + } +} + diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt index 1a56de9fab..54dc119696 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt @@ -45,6 +45,7 @@ import im.vector.app.features.home.room.detail.upgrade.MigrateRoomBottomSheet import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel import im.vector.app.features.navigation.SettingsActivityPayload +import im.vector.app.features.room.LeaveRoomPrompt import im.vector.lib.strings.CommonStrings import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -320,25 +321,16 @@ class RoomProfileFragment : } override fun onLeaveRoomClicked() { - val isPublicRoom = roomProfileViewModel.isPublicRoom() - val message = buildString { - append(getString(CommonStrings.room_participants_leave_prompt_msg)) - if (!isPublicRoom) { - append("\n\n") - append(getString(CommonStrings.room_participants_leave_private_warning)) + withState(roomProfileViewModel){ state -> + val warning = when { + state.isLastAdmin -> LeaveRoomPrompt.Warning.LAST_ADMIN + state.roomSummary()?.isPublic == false -> LeaveRoomPrompt.Warning.PRIVATE_ROOM + else -> LeaveRoomPrompt.Warning.NONE + } + LeaveRoomPrompt.show(requireContext(), warning){ + roomProfileViewModel.handle(RoomProfileAction.LeaveRoom) } } - MaterialAlertDialogBuilder( - requireContext(), - if (isPublicRoom) 0 else im.vector.lib.ui.styles.R.style.ThemeOverlay_Vector_MaterialAlertDialog_Destructive - ) - .setTitle(CommonStrings.room_participants_leave_prompt_title) - .setMessage(message) - .setPositiveButton(CommonStrings.action_leave) { _, _ -> - roomProfileViewModel.handle(RoomProfileAction.LeaveRoom) - } - .setNegativeButton(CommonStrings.action_cancel, null) - .show() } override fun onRoomAliasesClicked() { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt index deb609509a..87c760ce45 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt @@ -20,6 +20,7 @@ import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.analytics.plan.Interaction import im.vector.app.features.home.ShortcutCreator import im.vector.app.features.powerlevel.PowerLevelsFlowFactory +import im.vector.app.features.powerlevel.isLastAdminFlow import im.vector.app.features.session.coroutineScope import im.vector.lib.strings.CommonStrings import kotlinx.coroutines.Dispatchers @@ -72,6 +73,14 @@ class RoomProfileViewModel @AssistedInject constructor( observePermissions() observePowerLevels() observeCryptoSettings(flowRoom) + observeIsLastAdmin() + } + + private fun observeIsLastAdmin() { + room.isLastAdminFlow(session.myUserId) + .onEach { isLastAdmin -> + setState { copy(isLastAdmin = isLastAdmin) } + }.launchIn(viewModelScope) } private fun observeCryptoSettings(flowRoom: FlowRoom) { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt index d6784dc8a2..580b5a1283 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt @@ -30,6 +30,7 @@ data class RoomProfileViewState( val encryptToVerifiedDeviceOnly: Async = Uninitialized, val globalCryptoConfig: Async = Uninitialized, val unverifiedDevicesInTheRoom: Async = Uninitialized, + val isLastAdmin: Boolean = false ) : MavericksState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) diff --git a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvanceViewState.kt b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvanceViewState.kt index 0b1968b31e..48199cd2a2 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvanceViewState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvanceViewState.kt @@ -21,7 +21,7 @@ data class SpaceLeaveAdvanceViewState( val currentFilter: String = "", val leaveState: Async = Uninitialized, val isFilteringEnabled: Boolean = false, - val isLastOwner: Boolean = false + val isLastAdmin: Boolean = false ) : MavericksState { constructor(args: SpaceBottomSheetSettingsArgs) : this( diff --git a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedFragment.kt index 1c1f33faa8..3712c5c0ad 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedFragment.kt @@ -50,27 +50,12 @@ class SpaceLeaveAdvancedFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - controller.listener = this withState(viewModel) { state -> setupToolbar(views.toolbar) .setSubtitle(state.spaceSummary?.name) .allowBack() - - state.spaceSummary?.let { summary -> - val warningMessage: CharSequence? = when { - summary.otherMemberIds.isEmpty() -> getString(CommonStrings.space_leave_prompt_msg_only_you) - state.isLastOwner -> getString(CommonStrings.space_leave_prompt_msg_as_admin) - !summary.isPublic -> getString(CommonStrings.space_leave_prompt_msg_private) - else -> null - } - - views.spaceLeavePromptDescription.isVisible = warningMessage != null - views.spaceLeavePromptDescription.text = warningMessage - } - - views.spaceLeavePromptTitle.text = getString(CommonStrings.space_leave_prompt_msg_with_name, state.spaceSummary?.name ?: "") } views.roomList.configureWith(controller) @@ -107,6 +92,19 @@ class SpaceLeaveAdvancedFragment : override fun invalidate() = withState(viewModel) { state -> super.invalidate() + state.spaceSummary?.let { summary -> + val warningMessage: CharSequence? = when { + summary.otherMemberIds.isEmpty() -> getString(CommonStrings.space_leave_prompt_msg_only_you) + state.isLastAdmin -> getString(CommonStrings.space_leave_prompt_msg_as_admin) + !summary.isPublic -> getString(CommonStrings.space_leave_prompt_msg_private) + else -> null + } + views.spaceLeavePromptDescription.isVisible = warningMessage != null + views.spaceLeavePromptDescription.text = warningMessage + } + + views.spaceLeavePromptTitle.text = getString(CommonStrings.space_leave_prompt_msg_with_name, state.spaceSummary?.name ?: "") + if (state.isFilteringEnabled) { views.appBarLayout.setExpanded(false) } diff --git a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt index 3c06244888..7f0a2d4008 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedViewModel.kt @@ -20,7 +20,7 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.powerlevel.isOwner +import im.vector.app.features.powerlevel.isLastAdminFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -29,7 +29,6 @@ import org.matrix.android.sdk.api.query.RoomCategoryFilter import org.matrix.android.sdk.api.query.SpaceFilter import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.getRoom -import org.matrix.android.sdk.api.session.room.getRoomPowerLevels import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.flow.flow @@ -44,20 +43,13 @@ class SpaceLeaveAdvancedViewModel @AssistedInject constructor( init { val space = session.getRoom(initialState.spaceId) - val spaceSummary = space?.roomSummary() - val roomPowerLevels = space?.getRoomPowerLevels() - roomPowerLevels?.let { - val isOwner = roomPowerLevels.getSuggestedRole(session.myUserId).isOwner() - val otherOwnersCount = spaceSummary?.otherMemberIds - ?.map { roomPowerLevels.getSuggestedRole(it) } - ?.count { it.isOwner() } - ?: 0 - val isLastOwner = isOwner && otherOwnersCount == 0 - setState { - copy(isLastOwner = isLastOwner) - } - } + space?.isLastAdminFlow(session.myUserId) + ?.onEach { isLastAdmin -> + setState { copy(isLastAdmin = isLastAdmin) } + }?.launchIn(viewModelScope) + + val spaceSummary = space?.roomSummary() setState { copy(spaceSummary = spaceSummary) } session.getRoom(initialState.spaceId) ?.flow()