mirror of
https://github.com/vector-im/riotX-android
synced 2025-10-06 00:02:48 +02:00
change (leave room) : warn on last admin when leaving rooms
This commit is contained in:
@@ -686,6 +686,7 @@
|
|||||||
<string name="room_participants_leave_prompt_title">Leave room</string>
|
<string name="room_participants_leave_prompt_title">Leave room</string>
|
||||||
<string name="room_participants_leave_prompt_msg">Are you sure you want to leave the room?</string>
|
<string name="room_participants_leave_prompt_msg">Are you sure you want to leave the room?</string>
|
||||||
<string name="room_participants_leave_private_warning">This room is not public. You will not be able to rejoin without an invite.</string>
|
<string name="room_participants_leave_private_warning">This room is not public. You will not be able to rejoin without an invite.</string>
|
||||||
|
<string name="room_participants_leave_last_admin">You\'re the only admin of this room. Leaving it will mean no one has control over it.</string>
|
||||||
|
|
||||||
<string name="room_participants_header_direct_chats">Direct Messages</string>
|
<string name="room_participants_header_direct_chats">Direct Messages</string>
|
||||||
|
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.api.session.room
|
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.QueryStateEventValue
|
||||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
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.model.create.getRoomCreateContentWithSender
|
||||||
import org.matrix.android.sdk.api.session.room.powerlevels.RoomPowerLevels
|
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.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.
|
* Get a TimelineEvent using the TimelineService of a Room.
|
||||||
|
@@ -25,7 +25,6 @@ import com.airbnb.epoxy.OnModelBuildFinishedListener
|
|||||||
import com.airbnb.mvrx.args
|
import com.airbnb.mvrx.args
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.LayoutManagerStateRestorer
|
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.home.room.list.widget.NotifsFabMenuView
|
||||||
import im.vector.app.features.matrixto.OriginOfMatrixTo
|
import im.vector.app.features.matrixto.OriginOfMatrixTo
|
||||||
import im.vector.app.features.notifications.NotificationDrawerManager
|
import im.vector.app.features.notifications.NotificationDrawerManager
|
||||||
|
import im.vector.app.features.room.LeaveRoomPrompt
|
||||||
import im.vector.lib.strings.CommonStrings
|
import im.vector.lib.strings.CommonStrings
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
@@ -422,7 +422,7 @@ class RoomListFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleQuickActions(quickAction: RoomListQuickActionsSharedAction) {
|
private suspend fun handleQuickActions(quickAction: RoomListQuickActionsSharedAction) {
|
||||||
when (quickAction) {
|
when (quickAction) {
|
||||||
is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> {
|
is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> {
|
||||||
roomListViewModel.handle(RoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.ALL_MESSAGES_NOISY))
|
roomListViewModel.handle(RoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.ALL_MESSAGES_NOISY))
|
||||||
@@ -451,26 +451,11 @@ class RoomListFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun promptLeaveRoom(roomId: String) {
|
private suspend fun promptLeaveRoom(roomId: String) {
|
||||||
val isPublicRoom = roomListViewModel.isPublicRoom(roomId)
|
val warning = roomListViewModel.getLeaveRoomWarning(roomId)
|
||||||
val message = buildString {
|
LeaveRoomPrompt.show(requireContext(), warning) {
|
||||||
append(getString(CommonStrings.room_participants_leave_prompt_msg))
|
roomListViewModel.handle(RoomListAction.LeaveRoom(roomId))
|
||||||
if (!isPublicRoom) {
|
|
||||||
append("\n\n")
|
|
||||||
append(getString(CommonStrings.room_participants_leave_private_warning))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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 ->
|
override fun invalidate() = withState(roomListViewModel) { state ->
|
||||||
|
@@ -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.analytics.plan.JoinedRoom
|
||||||
import im.vector.app.features.displayname.getBestName
|
import im.vector.app.features.displayname.getBestName
|
||||||
import im.vector.app.features.invite.AutoAcceptInvites
|
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 im.vector.app.features.settings.VectorPreferences
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
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.localecho.RoomLocalEcho
|
||||||
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
|
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.roomSummaryQueryParams
|
||||||
import org.matrix.android.sdk.api.session.room.state.isPublic
|
|
||||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
import org.matrix.android.sdk.flow.flow
|
import org.matrix.android.sdk.flow.flow
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@@ -150,10 +151,11 @@ class RoomListViewModel @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isPublicRoom(roomId: String): Boolean {
|
suspend fun getLeaveRoomWarning(roomId: String): LeaveRoomPrompt.Warning {
|
||||||
return session.getRoom(roomId)?.stateService()?.isPublic().orFalse()
|
return session.getLeaveRoomWarning(roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// PRIVATE METHODS *****************************************************************************
|
// PRIVATE METHODS *****************************************************************************
|
||||||
|
|
||||||
private fun handleSelectRoom(action: RoomListAction.SelectRoom) = withState {
|
private fun handleSelectRoom(action: RoomListAction.SelectRoom) = withState {
|
||||||
|
@@ -18,7 +18,6 @@ import androidx.recyclerview.widget.ConcatAdapter.Config.StableIdMode
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.airbnb.epoxy.OnModelBuildFinishedListener
|
import com.airbnb.epoxy.OnModelBuildFinishedListener
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.core.epoxy.LayoutManagerStateRestorer
|
import im.vector.app.core.epoxy.LayoutManagerStateRestorer
|
||||||
import im.vector.app.core.extensions.cleanup
|
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.HomeRoomFilter
|
||||||
import im.vector.app.features.home.room.list.home.header.HomeRoomsHeadersController
|
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.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.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
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) {
|
when (quickAction) {
|
||||||
is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> {
|
is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> {
|
||||||
roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.ALL_MESSAGES_NOISY))
|
roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.ALL_MESSAGES_NOISY))
|
||||||
@@ -185,26 +184,11 @@ class HomeRoomListFragment :
|
|||||||
concatAdapter.addAdapter(roomsAdapter)
|
concatAdapter.addAdapter(roomsAdapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun promptLeaveRoom(roomId: String) {
|
private suspend fun promptLeaveRoom(roomId: String) {
|
||||||
val isPublicRoom = roomListViewModel.isPublicRoom(roomId)
|
val warning = roomListViewModel.getLeaveRoomWarning(roomId)
|
||||||
val message = buildString {
|
LeaveRoomPrompt.show(requireContext(), warning) {
|
||||||
append(getString(CommonStrings.room_participants_leave_prompt_msg))
|
roomListViewModel.handle(HomeRoomListAction.LeaveRoom(roomId))
|
||||||
if (!isPublicRoom) {
|
|
||||||
append("\n\n")
|
|
||||||
append(getString(CommonStrings.room_participants_leave_private_warning))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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() {
|
private fun onInvitesCounterClicked() {
|
||||||
|
@@ -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.analytics.plan.UserProperties
|
||||||
import im.vector.app.features.displayname.getBestName
|
import im.vector.app.features.displayname.getBestName
|
||||||
import im.vector.app.features.home.room.list.home.header.HomeRoomFilter
|
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 im.vector.lib.strings.CommonStrings
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
@@ -331,8 +333,8 @@ class HomeRoomListViewModel @AssistedInject constructor(
|
|||||||
filteredPagedRoomSummariesLive.queryParams = getFilteredQueryParams(newFilter, filteredPagedRoomSummariesLive.queryParams)
|
filteredPagedRoomSummariesLive.queryParams = getFilteredQueryParams(newFilter, filteredPagedRoomSummariesLive.queryParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isPublicRoom(roomId: String): Boolean {
|
suspend fun getLeaveRoomWarning(roomId: String): LeaveRoomPrompt.Warning {
|
||||||
return session.getRoom(roomId)?.stateService()?.isPublic().orFalse()
|
return session.getLeaveRoomWarning(roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSelectRoom(action: HomeRoomListAction.SelectRoom) = withState {
|
private fun handleSelectRoom(action: HomeRoomListAction.SelectRoom) = withState {
|
||||||
|
@@ -7,6 +7,37 @@
|
|||||||
|
|
||||||
package im.vector.app.features.powerlevel
|
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.api.session.room.powerlevels.Role
|
||||||
|
import org.matrix.android.sdk.flow.flow
|
||||||
|
|
||||||
fun Role.isOwner() = this == Role.Creator || this == Role.SuperAdmin
|
fun Role.isOwner() = this == Role.Creator || this == Role.SuperAdmin
|
||||||
|
|
||||||
|
fun Room.membersByRoleFlow(): Flow<Map<Role, List<RoomMemberSummary>>> {
|
||||||
|
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<Boolean> {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -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.RoomListQuickActionsSharedAction
|
||||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
||||||
import im.vector.app.features.navigation.SettingsActivityPayload
|
import im.vector.app.features.navigation.SettingsActivityPayload
|
||||||
|
import im.vector.app.features.room.LeaveRoomPrompt
|
||||||
import im.vector.lib.strings.CommonStrings
|
import im.vector.lib.strings.CommonStrings
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
@@ -320,25 +321,16 @@ class RoomProfileFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onLeaveRoomClicked() {
|
override fun onLeaveRoomClicked() {
|
||||||
val isPublicRoom = roomProfileViewModel.isPublicRoom()
|
withState(roomProfileViewModel){ state ->
|
||||||
val message = buildString {
|
val warning = when {
|
||||||
append(getString(CommonStrings.room_participants_leave_prompt_msg))
|
state.isLastAdmin -> LeaveRoomPrompt.Warning.LAST_ADMIN
|
||||||
if (!isPublicRoom) {
|
state.roomSummary()?.isPublic == false -> LeaveRoomPrompt.Warning.PRIVATE_ROOM
|
||||||
append("\n\n")
|
else -> LeaveRoomPrompt.Warning.NONE
|
||||||
append(getString(CommonStrings.room_participants_leave_private_warning))
|
}
|
||||||
|
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() {
|
override fun onRoomAliasesClicked() {
|
||||||
|
@@ -20,6 +20,7 @@ import im.vector.app.features.analytics.AnalyticsTracker
|
|||||||
import im.vector.app.features.analytics.plan.Interaction
|
import im.vector.app.features.analytics.plan.Interaction
|
||||||
import im.vector.app.features.home.ShortcutCreator
|
import im.vector.app.features.home.ShortcutCreator
|
||||||
import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
|
import im.vector.app.features.powerlevel.PowerLevelsFlowFactory
|
||||||
|
import im.vector.app.features.powerlevel.isLastAdminFlow
|
||||||
import im.vector.app.features.session.coroutineScope
|
import im.vector.app.features.session.coroutineScope
|
||||||
import im.vector.lib.strings.CommonStrings
|
import im.vector.lib.strings.CommonStrings
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -72,6 +73,14 @@ class RoomProfileViewModel @AssistedInject constructor(
|
|||||||
observePermissions()
|
observePermissions()
|
||||||
observePowerLevels()
|
observePowerLevels()
|
||||||
observeCryptoSettings(flowRoom)
|
observeCryptoSettings(flowRoom)
|
||||||
|
observeIsLastAdmin()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeIsLastAdmin() {
|
||||||
|
room.isLastAdminFlow(session.myUserId)
|
||||||
|
.onEach { isLastAdmin ->
|
||||||
|
setState { copy(isLastAdmin = isLastAdmin) }
|
||||||
|
}.launchIn(viewModelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeCryptoSettings(flowRoom: FlowRoom) {
|
private fun observeCryptoSettings(flowRoom: FlowRoom) {
|
||||||
|
@@ -30,6 +30,7 @@ data class RoomProfileViewState(
|
|||||||
val encryptToVerifiedDeviceOnly: Async<Boolean> = Uninitialized,
|
val encryptToVerifiedDeviceOnly: Async<Boolean> = Uninitialized,
|
||||||
val globalCryptoConfig: Async<GlobalCryptoConfig> = Uninitialized,
|
val globalCryptoConfig: Async<GlobalCryptoConfig> = Uninitialized,
|
||||||
val unverifiedDevicesInTheRoom: Async<Boolean> = Uninitialized,
|
val unverifiedDevicesInTheRoom: Async<Boolean> = Uninitialized,
|
||||||
|
val isLastAdmin: Boolean = false
|
||||||
) : MavericksState {
|
) : MavericksState {
|
||||||
|
|
||||||
constructor(args: RoomProfileArgs) : this(roomId = args.roomId)
|
constructor(args: RoomProfileArgs) : this(roomId = args.roomId)
|
||||||
|
@@ -21,7 +21,7 @@ data class SpaceLeaveAdvanceViewState(
|
|||||||
val currentFilter: String = "",
|
val currentFilter: String = "",
|
||||||
val leaveState: Async<Unit> = Uninitialized,
|
val leaveState: Async<Unit> = Uninitialized,
|
||||||
val isFilteringEnabled: Boolean = false,
|
val isFilteringEnabled: Boolean = false,
|
||||||
val isLastOwner: Boolean = false
|
val isLastAdmin: Boolean = false
|
||||||
) : MavericksState {
|
) : MavericksState {
|
||||||
|
|
||||||
constructor(args: SpaceBottomSheetSettingsArgs) : this(
|
constructor(args: SpaceBottomSheetSettingsArgs) : this(
|
||||||
|
@@ -50,27 +50,12 @@ class SpaceLeaveAdvancedFragment :
|
|||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
controller.listener = this
|
controller.listener = this
|
||||||
|
|
||||||
withState(viewModel) { state ->
|
withState(viewModel) { state ->
|
||||||
setupToolbar(views.toolbar)
|
setupToolbar(views.toolbar)
|
||||||
.setSubtitle(state.spaceSummary?.name)
|
.setSubtitle(state.spaceSummary?.name)
|
||||||
.allowBack()
|
.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)
|
views.roomList.configureWith(controller)
|
||||||
@@ -107,6 +92,19 @@ class SpaceLeaveAdvancedFragment :
|
|||||||
override fun invalidate() = withState(viewModel) { state ->
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
super.invalidate()
|
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) {
|
if (state.isFilteringEnabled) {
|
||||||
views.appBarLayout.setExpanded(false)
|
views.appBarLayout.setExpanded(false)
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,7 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
|||||||
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||||
import im.vector.app.core.platform.EmptyViewEvents
|
import im.vector.app.core.platform.EmptyViewEvents
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
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.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
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.query.SpaceFilter
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.getRoom
|
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.model.Membership
|
||||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||||
import org.matrix.android.sdk.flow.flow
|
import org.matrix.android.sdk.flow.flow
|
||||||
@@ -44,20 +43,13 @@ class SpaceLeaveAdvancedViewModel @AssistedInject constructor(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
val space = session.getRoom(initialState.spaceId)
|
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) }
|
setState { copy(spaceSummary = spaceSummary) }
|
||||||
session.getRoom(initialState.spaceId)
|
session.getRoom(initialState.spaceId)
|
||||||
?.flow()
|
?.flow()
|
||||||
|
Reference in New Issue
Block a user