core, ui: allow to delete member support chat; rename reject action (#5927)

This commit is contained in:
spaced4ndy
2025-05-20 09:07:44 +00:00
committed by GitHub
parent ca9f6267e4
commit 1a80ecfc29
15 changed files with 212 additions and 48 deletions
@@ -1914,6 +1914,13 @@ object ChatController {
return null
}
suspend fun apiDeleteMemberSupportChat(rh: Long?, groupId: Long, groupMemberId: Long): Pair<GroupInfo, GroupMember>? {
val r = sendCmd(rh, CC.ApiDeleteMemberSupportChat(groupId, groupMemberId))
if (r is API.Result && r.res is CR.MemberSupportChatDeleted) return r.res.groupInfo to r.res.member
apiErrorAlert("apiDeleteMemberSupportChat", generalGetString(MR.strings.error_deleting_member_support_chat), r)
return null
}
suspend fun apiRemoveMembers(rh: Long?, groupId: Long, memberIds: List<Long>, withMessages: Boolean = false): Pair<GroupInfo, List<GroupMember>>? {
val r = sendCmd(rh, CC.ApiRemoveMembers(groupId, memberIds, withMessages))
if (r is API.Result && r.res is CR.UserDeletedMembers) return r.res.groupInfo to r.res.members
@@ -3345,6 +3352,7 @@ sealed class CC {
class ApiAddMember(val groupId: Long, val contactId: Long, val memberRole: GroupMemberRole): CC()
class ApiJoinGroup(val groupId: Long): CC()
class ApiAcceptMember(val groupId: Long, val groupMemberId: Long, val memberRole: GroupMemberRole): CC()
class ApiDeleteMemberSupportChat(val groupId: Long, val groupMemberId: Long): CC()
class ApiMembersRole(val groupId: Long, val memberIds: List<Long>, val memberRole: GroupMemberRole): CC()
class ApiBlockMembersForAll(val groupId: Long, val memberIds: List<Long>, val blocked: Boolean): CC()
class ApiRemoveMembers(val groupId: Long, val memberIds: List<Long>, val withMessages: Boolean): CC()
@@ -3531,6 +3539,7 @@ sealed class CC {
is ApiAddMember -> "/_add #$groupId $contactId ${memberRole.memberRole}"
is ApiJoinGroup -> "/_join #$groupId"
is ApiAcceptMember -> "/_accept member #$groupId $groupMemberId ${memberRole.memberRole}"
is ApiDeleteMemberSupportChat -> "/_delete member chat #$groupId $groupMemberId"
is ApiMembersRole -> "/_member role #$groupId ${memberIds.joinToString(",")} ${memberRole.memberRole}"
is ApiBlockMembersForAll -> "/_block #$groupId ${memberIds.joinToString(",")} blocked=${onOff(blocked)}"
is ApiRemoveMembers -> "/_remove #$groupId ${memberIds.joinToString(",")} messages=${onOff(withMessages)}"
@@ -3695,6 +3704,7 @@ sealed class CC {
is ApiAddMember -> "apiAddMember"
is ApiJoinGroup -> "apiJoinGroup"
is ApiAcceptMember -> "apiAcceptMember"
is ApiDeleteMemberSupportChat -> "apiDeleteMemberSupportChat"
is ApiMembersRole -> "apiMembersRole"
is ApiBlockMembersForAll -> "apiBlockMembersForAll"
is ApiRemoveMembers -> "apiRemoveMembers"
@@ -5849,6 +5859,7 @@ sealed class CR {
@Serializable @SerialName("groupDeletedUser") class GroupDeletedUser(val user: UserRef, val groupInfo: GroupInfo): CR()
@Serializable @SerialName("joinedGroupMemberConnecting") class JoinedGroupMemberConnecting(val user: UserRef, val groupInfo: GroupInfo, val hostMember: GroupMember, val member: GroupMember): CR()
@Serializable @SerialName("memberAccepted") class MemberAccepted(val user: UserRef, val groupInfo: GroupInfo, val member: GroupMember): CR()
@Serializable @SerialName("memberSupportChatDeleted") class MemberSupportChatDeleted(val user: UserRef, val groupInfo: GroupInfo, val member: GroupMember): CR()
@Serializable @SerialName("memberAcceptedByOther") class MemberAcceptedByOther(val user: UserRef, val groupInfo: GroupInfo, val acceptingMember: GroupMember, val member: GroupMember): CR()
@Serializable @SerialName("memberRole") class MemberRole(val user: UserRef, val groupInfo: GroupInfo, val byMember: GroupMember, val member: GroupMember, val fromRole: GroupMemberRole, val toRole: GroupMemberRole): CR()
@Serializable @SerialName("membersRoleUser") class MembersRoleUser(val user: UserRef, val groupInfo: GroupInfo, val members: List<GroupMember>, val toRole: GroupMemberRole): CR()
@@ -6027,6 +6038,7 @@ sealed class CR {
is GroupDeletedUser -> "groupDeletedUser"
is JoinedGroupMemberConnecting -> "joinedGroupMemberConnecting"
is MemberAccepted -> "memberAccepted"
is MemberSupportChatDeleted -> "memberSupportChatDeleted"
is MemberAcceptedByOther -> "memberAcceptedByOther"
is MemberRole -> "memberRole"
is MembersRoleUser -> "membersRoleUser"
@@ -6198,6 +6210,7 @@ sealed class CR {
is GroupDeletedUser -> withUser(user, json.encodeToString(groupInfo))
is JoinedGroupMemberConnecting -> withUser(user, "groupInfo: $groupInfo\nhostMember: $hostMember\nmember: $member")
is MemberAccepted -> withUser(user, "groupInfo: $groupInfo\nmember: $member")
is MemberSupportChatDeleted -> withUser(user, "groupInfo: $groupInfo\nmember: $member")
is MemberAcceptedByOther -> withUser(user, "groupInfo: $groupInfo\nacceptingMember: $acceptingMember\nmember: $member")
is MemberRole -> withUser(user, "groupInfo: $groupInfo\nbyMember: $byMember\nmember: $member\nfromRole: $fromRole\ntoRole: $toRole")
is MembersRoleUser -> withUser(user, "groupInfo: $groupInfo\nmembers: $members\ntoRole: $toRole")
@@ -13,6 +13,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import chat.simplex.common.model.*
import chat.simplex.common.platform.chatModel
import chat.simplex.common.views.chat.group.removeMember
import chat.simplex.common.views.chat.group.removeMemberDialog
import chat.simplex.common.views.helpers.*
import chat.simplex.res.MR
@@ -44,12 +45,12 @@ fun ComposeContextPendingMemberActionsView(
.fillMaxHeight()
.weight(1F)
.clickable {
removeMemberDialog(rhId, groupInfo, member, chatModel, close = { ModalManager.end.closeModal() })
rejectMemberDialog(rhId, member, chatModel, close = { ModalManager.end.closeModal() })
},
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(stringResource(MR.strings.remove_pending_member_button), color = Color.Red)
Text(stringResource(MR.strings.reject_pending_member_button), color = Color.Red)
}
Column(
@@ -69,6 +70,17 @@ fun ComposeContextPendingMemberActionsView(
}
}
fun rejectMemberDialog(rhId: Long?, member: GroupMember, chatModel: ChatModel, close: (() -> Unit)? = null) {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.reject_pending_member_alert_title),
confirmText = generalGetString(MR.strings.reject_pending_member_button),
onConfirm = {
removeMember(rhId, member, chatModel, close)
},
destructive = true,
)
}
fun acceptMemberDialog(rhId: Long?, groupInfo: GroupInfo, member: GroupMember, close: (() -> Unit)? = null) {
AlertManager.shared.showAlertDialogButtonsColumn(
title = generalGetString(MR.strings.accept_pending_member_alert_title),
@@ -105,12 +117,9 @@ private fun acceptMember(rhId: Long?, groupInfo: GroupInfo, member: GroupMember,
val r = chatModel.controller.apiAcceptMember(rhId, groupInfo.groupId, member.groupMemberId, role)
if (r != null) {
withContext(Dispatchers.Main) {
chatModel.chatsContext.upsertGroupMember(rhId, groupInfo, r.second)
chatModel.chatsContext.upsertGroupMember(rhId, r.first, r.second)
chatModel.chatsContext.updateGroup(rhId, r.first)
}
withContext(Dispatchers.Main) {
chatModel.secondaryChatsContext.value?.upsertGroupMember(rhId, groupInfo, r.second)
}
}
close?.invoke()
}
@@ -245,29 +245,28 @@ fun removeMemberDialog(rhId: Long?, groupInfo: GroupInfo, member: GroupMember, c
text = generalGetString(messageId),
confirmText = generalGetString(MR.strings.remove_member_confirmation),
onConfirm = {
withBGApi {
val r = chatModel.controller.apiRemoveMembers(rhId, member.groupId, listOf(member.groupMemberId))
if (r != null) {
val (updatedGroupInfo, removedMembers) = r
withContext(Dispatchers.Main) {
chatModel.chatsContext.updateGroup(rhId, updatedGroupInfo)
removedMembers.forEach { removedMember ->
chatModel.chatsContext.upsertGroupMember(rhId, updatedGroupInfo, removedMember)
}
}
withContext(Dispatchers.Main) {
removedMembers.forEach { removedMember ->
chatModel.secondaryChatsContext.value?.upsertGroupMember(rhId, updatedGroupInfo, removedMember)
}
}
}
close?.invoke()
}
removeMember(rhId, member, chatModel, close)
},
destructive = true,
)
}
fun removeMember(rhId: Long?, member: GroupMember, chatModel: ChatModel, close: (() -> Unit)? = null) {
withBGApi {
val r = chatModel.controller.apiRemoveMembers(rhId, member.groupId, listOf(member.groupMemberId))
if (r != null) {
val (updatedGroupInfo, removedMembers) = r
withContext(Dispatchers.Main) {
chatModel.chatsContext.updateGroup(rhId, updatedGroupInfo)
removedMembers.forEach { removedMember ->
chatModel.chatsContext.upsertGroupMember(rhId, updatedGroupInfo, removedMember)
}
}
}
close?.invoke()
}
}
@Composable
fun GroupMemberInfoLayout(
rhId: Long?,
@@ -28,7 +28,7 @@ import chat.simplex.common.views.chat.item.ItemAction
import chat.simplex.common.views.chatlist.*
import chat.simplex.res.MR
import dev.icerock.moko.resources.compose.painterResource
import kotlinx.coroutines.launch
import kotlinx.coroutines.*
@Composable
fun ModalData.MemberSupportView(
@@ -269,14 +269,34 @@ private fun DropDownMenuForSupportChat(rhId: Long?, member: GroupMember, groupIn
acceptMemberDialog(rhId, groupInfo, member)
showMenu.value = false
})
} else {
ItemAction(stringResource(MR.strings.delete_member_support_chat_button), painterResource(MR.images.ic_delete), color = MaterialTheme.colors.error, onClick = {
deleteMemberSupportChatDialog(rhId, groupInfo, member)
showMenu.value = false
})
}
}
}
fun deleteMemberSupportChatDialog(rhId: Long?, groupInfo: GroupInfo, member: GroupMember) {
AlertManager.shared.showAlertDialog(
title = generalGetString(MR.strings.delete_member_support_chat_alert_title),
confirmText = generalGetString(MR.strings.delete_member_support_chat_button),
onConfirm = {
deleteMemberSupportChat(rhId, groupInfo, member)
},
destructive = true,
)
}
private fun deleteMemberSupportChat(rhId: Long?, groupInfo: GroupInfo, member: GroupMember) {
withBGApi {
val r = chatModel.controller.apiDeleteMemberSupportChat(rhId, groupInfo.groupId, member.groupMemberId)
if (r != null) {
withContext(Dispatchers.Main) {
chatModel.chatsContext.upsertGroupMember(rhId, r.first, r.second)
chatModel.chatsContext.updateGroup(rhId, r.first)
}
}
ItemAction(stringResource(MR.strings.remove_pending_member_button), painterResource(MR.images.ic_delete), color = MaterialTheme.colors.error, onClick = {
removeMemberDialog(rhId, groupInfo, member, chatModel)
showMenu.value = false
})
// TODO [knocking] mark read, mark unread
// ItemAction(stringResource(MR.strings.mark_unread), painterResource(MR.images.ic_mark_chat_unread), onClick = {
// showMenu.value = false
// })
}
}
@@ -159,6 +159,7 @@
<string name="error_adding_members">Error adding member(s)</string>
<string name="error_joining_group">Error joining group</string>
<string name="error_accepting_member">Error accepting member</string>
<string name="error_deleting_member_support_chat">Error deleting member support chat</string>
<string name="cannot_receive_file">Cannot receive file</string>
<string name="sender_cancelled_file_transfer">Sender cancelled file transfer.</string>
<string name="file_not_approved_title">Unknown servers!</string>
@@ -2188,10 +2189,13 @@
<!-- MemberSupportView.kt -->
<string name="member_support">Chats with members</string>
<string name="no_support_chats">No chats with members</string>
<string name="delete_member_support_chat_button">Delete chat</string>
<string name="delete_member_support_chat_alert_title">Delete chat with member?</string>
<!-- MemberSupportChatView.kt -->
<string name="support_chat">Chat with admins</string>
<string name="remove_pending_member_button">Remove</string>
<string name="reject_pending_member_button">Reject</string>
<string name="reject_pending_member_alert_title">Reject member?</string>
<string name="accept_pending_member_button">Accept</string>
<string name="accept_pending_member_alert_title">Accept member</string>
<string name="accept_pending_member_alert_question">Member will join the group, accept member?</string>