android, desktop: block member for all (#3711)
* android: block member for all * old buttons (revert this) * blocked by admin text * revise notification
This commit is contained in:
parent
7d2f6a3609
commit
106556812c
@ -1279,6 +1279,7 @@ data class GroupMember (
|
||||
val memberCategory: GroupMemberCategory,
|
||||
val memberStatus: GroupMemberStatus,
|
||||
val memberSettings: GroupMemberSettings,
|
||||
val blockedByAdmin: Boolean,
|
||||
val invitedBy: InvitedBy,
|
||||
val localDisplayName: String,
|
||||
val memberProfile: LocalProfile,
|
||||
@ -1297,6 +1298,7 @@ data class GroupMember (
|
||||
val image: String? get() = memberProfile.image
|
||||
val contactLink: String? = memberProfile.contactLink
|
||||
val verified get() = activeConn?.connectionCode != null
|
||||
val blocked get() = blockedByAdmin || !memberSettings.showMessages
|
||||
|
||||
val chatViewName: String
|
||||
get() {
|
||||
@ -1345,7 +1347,7 @@ data class GroupMember (
|
||||
fun canBeRemoved(groupInfo: GroupInfo): Boolean {
|
||||
val userRole = groupInfo.membership.memberRole
|
||||
return memberStatus != GroupMemberStatus.MemRemoved && memberStatus != GroupMemberStatus.MemLeft
|
||||
&& userRole >= GroupMemberRole.Admin && userRole >= memberRole && groupInfo.membership.memberCurrent
|
||||
&& userRole >= GroupMemberRole.Admin && userRole >= memberRole && groupInfo.membership.memberActive
|
||||
}
|
||||
|
||||
fun canChangeRoleTo(groupInfo: GroupInfo): List<GroupMemberRole>? =
|
||||
@ -1354,6 +1356,12 @@ data class GroupMember (
|
||||
GroupMemberRole.values().filter { it <= userRole && it != GroupMemberRole.Author }
|
||||
}
|
||||
|
||||
fun canBlockForAll(groupInfo: GroupInfo): Boolean {
|
||||
val userRole = groupInfo.membership.memberRole
|
||||
return memberStatus != GroupMemberStatus.MemRemoved && memberStatus != GroupMemberStatus.MemLeft && memberRole < GroupMemberRole.Admin
|
||||
&& userRole >= GroupMemberRole.Admin && userRole >= memberRole && groupInfo.membership.memberActive
|
||||
}
|
||||
|
||||
val memberIncognito = memberProfile.profileId != memberContactProfileId
|
||||
|
||||
companion object {
|
||||
@ -1365,6 +1373,7 @@ data class GroupMember (
|
||||
memberCategory = GroupMemberCategory.InviteeMember,
|
||||
memberStatus = GroupMemberStatus.MemComplete,
|
||||
memberSettings = GroupMemberSettings(showMessages = true),
|
||||
blockedByAdmin = false,
|
||||
invitedBy = InvitedBy.IBUser(),
|
||||
localDisplayName = "alice",
|
||||
memberProfile = LocalProfile.sampleData,
|
||||
@ -1734,6 +1743,7 @@ data class ChatItem (
|
||||
is CIContent.RcvDeleted -> true
|
||||
is CIContent.SndModerated -> true
|
||||
is CIContent.RcvModerated -> true
|
||||
is CIContent.RcvBlocked -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
@ -1785,20 +1795,18 @@ data class ChatItem (
|
||||
}
|
||||
}
|
||||
|
||||
private val showNtfDir: Boolean get() = !chatDir.sent
|
||||
|
||||
val showNotification: Boolean get() =
|
||||
when (content) {
|
||||
is CIContent.SndMsgContent -> showNtfDir
|
||||
is CIContent.RcvMsgContent -> showNtfDir
|
||||
is CIContent.SndDeleted -> showNtfDir
|
||||
is CIContent.RcvDeleted -> showNtfDir
|
||||
is CIContent.SndCall -> showNtfDir
|
||||
is CIContent.SndMsgContent -> false
|
||||
is CIContent.RcvMsgContent -> meta.itemDeleted == null
|
||||
is CIContent.SndDeleted -> false
|
||||
is CIContent.RcvDeleted -> false
|
||||
is CIContent.SndCall -> false
|
||||
is CIContent.RcvCall -> false // notification is shown on CallInvitation instead
|
||||
is CIContent.RcvIntegrityError -> showNtfDir
|
||||
is CIContent.RcvDecryptionError -> showNtfDir
|
||||
is CIContent.RcvGroupInvitation -> showNtfDir
|
||||
is CIContent.SndGroupInvitation -> showNtfDir
|
||||
is CIContent.RcvIntegrityError -> false
|
||||
is CIContent.RcvDecryptionError -> false
|
||||
is CIContent.RcvGroupInvitation -> true
|
||||
is CIContent.SndGroupInvitation -> false
|
||||
is CIContent.RcvDirectEventContent -> when (content.rcvDirectEvent) {
|
||||
is RcvDirectEvent.ContactDeleted -> false
|
||||
is RcvDirectEvent.ProfileUpdated -> true
|
||||
@ -1808,28 +1816,30 @@ data class ChatItem (
|
||||
is RcvGroupEvent.MemberConnected -> false
|
||||
is RcvGroupEvent.MemberLeft -> false
|
||||
is RcvGroupEvent.MemberRole -> false
|
||||
is RcvGroupEvent.UserRole -> showNtfDir
|
||||
is RcvGroupEvent.MemberBlocked -> false
|
||||
is RcvGroupEvent.UserRole -> true
|
||||
is RcvGroupEvent.MemberDeleted -> false
|
||||
is RcvGroupEvent.UserDeleted -> showNtfDir
|
||||
is RcvGroupEvent.GroupDeleted -> showNtfDir
|
||||
is RcvGroupEvent.UserDeleted -> true
|
||||
is RcvGroupEvent.GroupDeleted -> true
|
||||
is RcvGroupEvent.GroupUpdated -> false
|
||||
is RcvGroupEvent.InvitedViaGroupLink -> false
|
||||
is RcvGroupEvent.MemberCreatedContact -> false
|
||||
is RcvGroupEvent.MemberProfileUpdated -> false
|
||||
}
|
||||
is CIContent.SndGroupEventContent -> showNtfDir
|
||||
is CIContent.SndGroupEventContent -> false
|
||||
is CIContent.RcvConnEventContent -> false
|
||||
is CIContent.SndConnEventContent -> showNtfDir
|
||||
is CIContent.SndConnEventContent -> false
|
||||
is CIContent.RcvChatFeature -> false
|
||||
is CIContent.SndChatFeature -> showNtfDir
|
||||
is CIContent.SndChatFeature -> false
|
||||
is CIContent.RcvChatPreference -> false
|
||||
is CIContent.SndChatPreference -> showNtfDir
|
||||
is CIContent.SndChatPreference -> false
|
||||
is CIContent.RcvGroupFeature -> false
|
||||
is CIContent.SndGroupFeature -> showNtfDir
|
||||
is CIContent.RcvChatFeatureRejected -> showNtfDir
|
||||
is CIContent.RcvGroupFeatureRejected -> showNtfDir
|
||||
is CIContent.SndModerated -> true
|
||||
is CIContent.RcvModerated -> true
|
||||
is CIContent.SndGroupFeature -> false
|
||||
is CIContent.RcvChatFeatureRejected -> true
|
||||
is CIContent.RcvGroupFeatureRejected -> false
|
||||
is CIContent.SndModerated -> false
|
||||
is CIContent.RcvModerated -> false
|
||||
is CIContent.RcvBlocked -> false
|
||||
is CIContent.InvalidJSON -> false
|
||||
}
|
||||
|
||||
@ -2174,6 +2184,7 @@ enum class SndCIStatusProgress {
|
||||
sealed class CIDeleted {
|
||||
@Serializable @SerialName("deleted") class Deleted(val deletedTs: Instant?): CIDeleted()
|
||||
@Serializable @SerialName("blocked") class Blocked(val deletedTs: Instant?): CIDeleted()
|
||||
@Serializable @SerialName("blockedByAdmin") class BlockedByAdmin(val deletedTs: Instant?): CIDeleted()
|
||||
@Serializable @SerialName("moderated") class Moderated(val deletedTs: Instant?, val byGroupMember: GroupMember): CIDeleted()
|
||||
}
|
||||
|
||||
@ -2218,6 +2229,7 @@ sealed class CIContent: ItemContent {
|
||||
@Serializable @SerialName("rcvGroupFeatureRejected") class RcvGroupFeatureRejected(val groupFeature: GroupFeature): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("sndModerated") object SndModerated: CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("rcvModerated") object RcvModerated: CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("rcvBlocked") object RcvBlocked: CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("invalidJSON") data class InvalidJSON(val json: String): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
|
||||
override val text: String get() = when (this) {
|
||||
@ -2246,6 +2258,7 @@ sealed class CIContent: ItemContent {
|
||||
is RcvGroupFeatureRejected -> "${groupFeature.text}: ${generalGetString(MR.strings.feature_received_prohibited)}"
|
||||
is SndModerated -> generalGetString(MR.strings.moderated_description)
|
||||
is RcvModerated -> generalGetString(MR.strings.moderated_description)
|
||||
is RcvBlocked -> generalGetString(MR.strings.blocked_by_admin_item_description)
|
||||
is InvalidJSON -> "invalid data"
|
||||
}
|
||||
|
||||
@ -2258,6 +2271,7 @@ sealed class CIContent: ItemContent {
|
||||
is RcvDecryptionError -> true
|
||||
is RcvGroupInvitation -> true
|
||||
is RcvModerated -> true
|
||||
is RcvBlocked -> true
|
||||
is InvalidJSON -> true
|
||||
else -> false
|
||||
}
|
||||
@ -2958,6 +2972,7 @@ sealed class RcvGroupEvent() {
|
||||
@Serializable @SerialName("memberConnected") class MemberConnected(): RcvGroupEvent()
|
||||
@Serializable @SerialName("memberLeft") class MemberLeft(): RcvGroupEvent()
|
||||
@Serializable @SerialName("memberRole") class MemberRole(val groupMemberId: Long, val profile: Profile, val role: GroupMemberRole): RcvGroupEvent()
|
||||
@Serializable @SerialName("memberBlocked") class MemberBlocked(val groupMemberId: Long, val profile: Profile, val blocked: Boolean): RcvGroupEvent()
|
||||
@Serializable @SerialName("userRole") class UserRole(val role: GroupMemberRole): RcvGroupEvent()
|
||||
@Serializable @SerialName("memberDeleted") class MemberDeleted(val groupMemberId: Long, val profile: Profile): RcvGroupEvent()
|
||||
@Serializable @SerialName("userDeleted") class UserDeleted(): RcvGroupEvent()
|
||||
@ -2972,6 +2987,11 @@ sealed class RcvGroupEvent() {
|
||||
is MemberConnected -> generalGetString(MR.strings.rcv_group_event_member_connected)
|
||||
is MemberLeft -> generalGetString(MR.strings.rcv_group_event_member_left)
|
||||
is MemberRole -> String.format(generalGetString(MR.strings.rcv_group_event_changed_member_role), profile.profileViewName, role.text)
|
||||
is MemberBlocked -> if (blocked) {
|
||||
String.format(generalGetString(MR.strings.rcv_group_event_member_blocked), profile.profileViewName)
|
||||
} else {
|
||||
String.format(generalGetString(MR.strings.rcv_group_event_member_unblocked), profile.profileViewName)
|
||||
}
|
||||
is UserRole -> String.format(generalGetString(MR.strings.rcv_group_event_changed_your_role), role.text)
|
||||
is MemberDeleted -> String.format(generalGetString(MR.strings.rcv_group_event_member_deleted), profile.profileViewName)
|
||||
is UserDeleted -> generalGetString(MR.strings.rcv_group_event_user_deleted)
|
||||
@ -3000,6 +3020,7 @@ sealed class RcvGroupEvent() {
|
||||
sealed class SndGroupEvent() {
|
||||
@Serializable @SerialName("memberRole") class MemberRole(val groupMemberId: Long, val profile: Profile, val role: GroupMemberRole): SndGroupEvent()
|
||||
@Serializable @SerialName("userRole") class UserRole(val role: GroupMemberRole): SndGroupEvent()
|
||||
@Serializable @SerialName("memberBlocked") class MemberBlocked(val groupMemberId: Long, val profile: Profile, val blocked: Boolean): SndGroupEvent()
|
||||
@Serializable @SerialName("memberDeleted") class MemberDeleted(val groupMemberId: Long, val profile: Profile): SndGroupEvent()
|
||||
@Serializable @SerialName("userLeft") class UserLeft(): SndGroupEvent()
|
||||
@Serializable @SerialName("groupUpdated") class GroupUpdated(val groupProfile: GroupProfile): SndGroupEvent()
|
||||
@ -3007,6 +3028,11 @@ sealed class SndGroupEvent() {
|
||||
val text: String get() = when (this) {
|
||||
is MemberRole -> String.format(generalGetString(MR.strings.snd_group_event_changed_member_role), profile.profileViewName, role.text)
|
||||
is UserRole -> String.format(generalGetString(MR.strings.snd_group_event_changed_role_for_yourself), role.text)
|
||||
is MemberBlocked -> if (blocked) {
|
||||
String.format(generalGetString(MR.strings.snd_group_event_member_blocked), profile.profileViewName)
|
||||
} else {
|
||||
String.format(generalGetString(MR.strings.snd_group_event_member_unblocked), profile.profileViewName)
|
||||
}
|
||||
is MemberDeleted -> String.format(generalGetString(MR.strings.snd_group_event_member_deleted), profile.profileViewName)
|
||||
is UserLeft -> generalGetString(MR.strings.snd_group_event_user_left)
|
||||
is GroupUpdated -> generalGetString(MR.strings.snd_group_event_group_profile_updated)
|
||||
|
@ -1332,6 +1332,17 @@ object ChatController {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun apiBlockMemberForAll(rh: Long?, groupId: Long, memberId: Long, blocked: Boolean): GroupMember =
|
||||
when (val r = sendCmd(rh, CC.ApiBlockMemberForAll(groupId, memberId, blocked))) {
|
||||
is CR.MemberBlockedForAllUser -> r.member
|
||||
else -> {
|
||||
if (!(networkErrorAlert(r))) {
|
||||
apiErrorAlert("apiBlockMemberForAll", generalGetString(MR.strings.error_blocking_member_for_all), r)
|
||||
}
|
||||
throw Exception("failed to block member for all: ${r.responseType} ${r.details}")
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun apiLeaveGroup(rh: Long?, groupId: Long): GroupInfo? {
|
||||
val r = sendCmd(rh, CC.ApiLeaveGroup(groupId))
|
||||
if (r is CR.LeftMemberUser) return r.groupInfo
|
||||
@ -1786,6 +1797,10 @@ object ChatController {
|
||||
if (active(r.user)) {
|
||||
chatModel.upsertGroupMember(rhId, r.groupInfo, r.member)
|
||||
}
|
||||
is CR.MemberBlockedForAll ->
|
||||
if (active(r.user)) {
|
||||
chatModel.upsertGroupMember(rhId, r.groupInfo, r.member)
|
||||
}
|
||||
is CR.GroupDeleted -> // TODO update user member
|
||||
if (active(r.user)) {
|
||||
chatModel.updateGroup(rhId, r.groupInfo)
|
||||
@ -2275,6 +2290,7 @@ sealed class CC {
|
||||
class ApiAddMember(val groupId: Long, val contactId: Long, val memberRole: GroupMemberRole): CC()
|
||||
class ApiJoinGroup(val groupId: Long): CC()
|
||||
class ApiMemberRole(val groupId: Long, val memberId: Long, val memberRole: GroupMemberRole): CC()
|
||||
class ApiBlockMemberForAll(val groupId: Long, val memberId: Long, val blocked: Boolean): CC()
|
||||
class ApiRemoveMember(val groupId: Long, val memberId: Long): CC()
|
||||
class ApiLeaveGroup(val groupId: Long): CC()
|
||||
class ApiListMembers(val groupId: Long): CC()
|
||||
@ -2409,6 +2425,7 @@ sealed class CC {
|
||||
is ApiAddMember -> "/_add #$groupId $contactId ${memberRole.memberRole}"
|
||||
is ApiJoinGroup -> "/_join #$groupId"
|
||||
is ApiMemberRole -> "/_member role #$groupId $memberId ${memberRole.memberRole}"
|
||||
is ApiBlockMemberForAll -> "/_block #$groupId $memberId blocked=${onOff(blocked)}"
|
||||
is ApiRemoveMember -> "/_remove #$groupId $memberId"
|
||||
is ApiLeaveGroup -> "/_leave #$groupId"
|
||||
is ApiListMembers -> "/_members #$groupId"
|
||||
@ -2538,6 +2555,7 @@ sealed class CC {
|
||||
is ApiAddMember -> "apiAddMember"
|
||||
is ApiJoinGroup -> "apiJoinGroup"
|
||||
is ApiMemberRole -> "apiMemberRole"
|
||||
is ApiBlockMemberForAll -> "apiBlockMemberForAll"
|
||||
is ApiRemoveMember -> "apiRemoveMember"
|
||||
is ApiLeaveGroup -> "apiLeaveGroup"
|
||||
is ApiListMembers -> "apiListMembers"
|
||||
@ -3928,6 +3946,8 @@ sealed class CR {
|
||||
@Serializable @SerialName("joinedGroupMemberConnecting") class JoinedGroupMemberConnecting(val user: UserRef, val groupInfo: GroupInfo, val hostMember: 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("memberRoleUser") class MemberRoleUser(val user: UserRef, val groupInfo: GroupInfo, val member: GroupMember, val fromRole: GroupMemberRole, val toRole: GroupMemberRole): CR()
|
||||
@Serializable @SerialName("memberBlockedForAll") class MemberBlockedForAll(val user: UserRef, val groupInfo: GroupInfo, val byMember: GroupMember, val member: GroupMember, val blocked: Boolean): CR()
|
||||
@Serializable @SerialName("memberBlockedForAllUser") class MemberBlockedForAllUser(val user: UserRef, val groupInfo: GroupInfo, val member: GroupMember, val blocked: Boolean): CR()
|
||||
@Serializable @SerialName("deletedMemberUser") class DeletedMemberUser(val user: UserRef, val groupInfo: GroupInfo, val member: GroupMember): CR()
|
||||
@Serializable @SerialName("deletedMember") class DeletedMember(val user: UserRef, val groupInfo: GroupInfo, val byMember: GroupMember, val deletedMember: GroupMember): CR()
|
||||
@Serializable @SerialName("leftMember") class LeftMember(val user: UserRef, val groupInfo: GroupInfo, val member: GroupMember): CR()
|
||||
@ -4080,6 +4100,8 @@ sealed class CR {
|
||||
is JoinedGroupMemberConnecting -> "joinedGroupMemberConnecting"
|
||||
is MemberRole -> "memberRole"
|
||||
is MemberRoleUser -> "memberRoleUser"
|
||||
is MemberBlockedForAll -> "memberBlockedForAll"
|
||||
is MemberBlockedForAllUser -> "memberBlockedForAllUser"
|
||||
is DeletedMemberUser -> "deletedMemberUser"
|
||||
is DeletedMember -> "deletedMember"
|
||||
is LeftMember -> "leftMember"
|
||||
@ -4227,6 +4249,8 @@ sealed class CR {
|
||||
is JoinedGroupMemberConnecting -> withUser(user, "groupInfo: $groupInfo\nhostMember: $hostMember\nmember: $member")
|
||||
is MemberRole -> withUser(user, "groupInfo: $groupInfo\nbyMember: $byMember\nmember: $member\nfromRole: $fromRole\ntoRole: $toRole")
|
||||
is MemberRoleUser -> withUser(user, "groupInfo: $groupInfo\nmember: $member\nfromRole: $fromRole\ntoRole: $toRole")
|
||||
is MemberBlockedForAll -> withUser(user, "groupInfo: $groupInfo\nbyMember: $byMember\nmember: $member\nblocked: $blocked")
|
||||
is MemberBlockedForAllUser -> withUser(user, "groupInfo: $groupInfo\nmember: $member\nblocked: $blocked")
|
||||
is DeletedMemberUser -> withUser(user, "groupInfo: $groupInfo\nmember: $member")
|
||||
is DeletedMember -> withUser(user, "groupInfo: $groupInfo\nbyMember: $byMember\ndeletedMember: $deletedMember")
|
||||
is LeftMember -> withUser(user, "groupInfo: $groupInfo\nmember: $member")
|
||||
|
@ -368,6 +368,18 @@ private fun AddMembersButton(tint: Color = MaterialTheme.colors.primary, onClick
|
||||
|
||||
@Composable
|
||||
private fun MemberRow(member: GroupMember, user: Boolean = false, onClick: (() -> Unit)? = null) {
|
||||
@Composable
|
||||
fun MemberInfo() {
|
||||
if (member.blocked) {
|
||||
Text(stringResource(MR.strings.member_info_member_blocked), color = MaterialTheme.colors.secondary)
|
||||
} else {
|
||||
val role = member.memberRole
|
||||
if (role in listOf(GroupMemberRole.Owner, GroupMemberRole.Admin, GroupMemberRole.Observer)) {
|
||||
Text(role.text, color = MaterialTheme.colors.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
@ -401,10 +413,7 @@ private fun MemberRow(member: GroupMember, user: Boolean = false, onClick: (() -
|
||||
)
|
||||
}
|
||||
}
|
||||
val role = member.memberRole
|
||||
if (role in listOf(GroupMemberRole.Owner, GroupMemberRole.Admin, GroupMemberRole.Observer)) {
|
||||
Text(role.text, color = MaterialTheme.colors.secondary)
|
||||
}
|
||||
MemberInfo()
|
||||
}
|
||||
}
|
||||
|
||||
@ -415,6 +424,7 @@ private fun MemberVerifiedShield() {
|
||||
|
||||
@Composable
|
||||
private fun DropDownMenuForMember(rhId: Long?, member: GroupMember, groupInfo: GroupInfo, showMenu: MutableState<Boolean>) {
|
||||
// revert from this:
|
||||
DefaultDropdownMenu(showMenu) {
|
||||
if (member.canBeRemoved(groupInfo)) {
|
||||
ItemAction(stringResource(MR.strings.remove_member_button), painterResource(MR.images.ic_delete), color = MaterialTheme.colors.error, onClick = {
|
||||
@ -434,6 +444,49 @@ private fun DropDownMenuForMember(rhId: Long?, member: GroupMember, groupInfo: G
|
||||
})
|
||||
}
|
||||
}
|
||||
// revert to this: vvv
|
||||
// if (groupInfo.membership.memberRole >= GroupMemberRole.Admin) {
|
||||
// val canBlockForAll = member.canBlockForAll(groupInfo)
|
||||
// val canRemove = member.canBeRemoved(groupInfo)
|
||||
// if (canBlockForAll || canRemove) {
|
||||
// DefaultDropdownMenu(showMenu) {
|
||||
// if (canBlockForAll) {
|
||||
// if (member.blockedByAdmin) {
|
||||
// ItemAction(stringResource(MR.strings.unblock_for_all), painterResource(MR.images.ic_do_not_touch), onClick = {
|
||||
// unblockForAllAlert(rhId, groupInfo, member)
|
||||
// showMenu.value = false
|
||||
// })
|
||||
// } else {
|
||||
// ItemAction(stringResource(MR.strings.block_for_all), painterResource(MR.images.ic_back_hand), color = MaterialTheme.colors.error, onClick = {
|
||||
// blockForAllAlert(rhId, groupInfo, member)
|
||||
// showMenu.value = false
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// if (canRemove) {
|
||||
// ItemAction(stringResource(MR.strings.remove_member_button), painterResource(MR.images.ic_delete), color = MaterialTheme.colors.error, onClick = {
|
||||
// removeMemberAlert(rhId, groupInfo, member)
|
||||
// showMenu.value = false
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else if (!member.blockedByAdmin) {
|
||||
// DefaultDropdownMenu(showMenu) {
|
||||
// if (member.memberSettings.showMessages) {
|
||||
// ItemAction(stringResource(MR.strings.block_member_button), painterResource(MR.images.ic_back_hand), color = MaterialTheme.colors.error, onClick = {
|
||||
// blockMemberAlert(rhId, groupInfo, member)
|
||||
// showMenu.value = false
|
||||
// })
|
||||
// } else {
|
||||
// ItemAction(stringResource(MR.strings.unblock_member_button), painterResource(MR.images.ic_do_not_touch), onClick = {
|
||||
// unblockMemberAlert(rhId, groupInfo, member)
|
||||
// showMenu.value = false
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ^^^
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
@ -3,9 +3,11 @@ package chat.simplex.common.views.chat.group
|
||||
import InfoRow
|
||||
import SectionBottomSpacer
|
||||
import SectionDividerSpaced
|
||||
import SectionItemView
|
||||
import SectionSpacer
|
||||
import SectionTextFooter
|
||||
import SectionView
|
||||
import TextIconSpaced
|
||||
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||
import java.net.URI
|
||||
import androidx.compose.foundation.*
|
||||
@ -99,6 +101,8 @@ fun GroupMemberInfoView(
|
||||
},
|
||||
blockMember = { blockMemberAlert(rhId, groupInfo, member) },
|
||||
unblockMember = { unblockMemberAlert(rhId, groupInfo, member) },
|
||||
blockForAll = { blockForAllAlert(rhId, groupInfo, member) },
|
||||
unblockForAll = { unblockForAllAlert(rhId, groupInfo, member) },
|
||||
removeMember = { removeMemberDialog(rhId, groupInfo, member, chatModel, close) },
|
||||
onRoleSelected = {
|
||||
if (it == newRole.value) return@GroupMemberInfoLayout
|
||||
@ -230,6 +234,8 @@ fun GroupMemberInfoLayout(
|
||||
connectViaAddress: (String) -> Unit,
|
||||
blockMember: () -> Unit,
|
||||
unblockMember: () -> Unit,
|
||||
blockForAll: () -> Unit,
|
||||
unblockForAll: () -> Unit,
|
||||
removeMember: () -> Unit,
|
||||
onRoleSelected: (GroupMemberRole) -> Unit,
|
||||
switchMemberAddress: () -> Unit,
|
||||
@ -248,6 +254,46 @@ fun GroupMemberInfoLayout(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AdminDestructiveSection() {
|
||||
val canBlockForAll = member.canBlockForAll(groupInfo)
|
||||
val canRemove = member.canBeRemoved(groupInfo)
|
||||
if (canBlockForAll || canRemove) {
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
SectionView {
|
||||
if (canBlockForAll) {
|
||||
if (member.blockedByAdmin) {
|
||||
UnblockForAllButton(unblockForAll)
|
||||
} else {
|
||||
BlockForAllButton(blockForAll)
|
||||
}
|
||||
}
|
||||
if (canRemove) {
|
||||
RemoveMemberButton(removeMember)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NonAdminBlockSection() {
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
SectionView {
|
||||
if (member.blockedByAdmin) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_back_hand),
|
||||
stringResource(MR.strings.member_blocked_by_admin),
|
||||
click = null,
|
||||
disabled = true
|
||||
)
|
||||
} else if (member.memberSettings.showMessages) {
|
||||
BlockMemberButton(blockMember)
|
||||
} else {
|
||||
UnblockMemberButton(unblockMember)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
@ -344,6 +390,7 @@ fun GroupMemberInfoLayout(
|
||||
}
|
||||
}
|
||||
|
||||
// revert from this:
|
||||
SectionDividerSpaced(maxBottomPadding = false)
|
||||
SectionView {
|
||||
if (member.memberSettings.showMessages) {
|
||||
@ -355,6 +402,13 @@ fun GroupMemberInfoLayout(
|
||||
RemoveMemberButton(removeMember)
|
||||
}
|
||||
}
|
||||
// revert to this: vvv
|
||||
// if (groupInfo.membership.memberRole >= GroupMemberRole.Admin) {
|
||||
// AdminDestructiveSection()
|
||||
// } else {
|
||||
// NonAdminBlockSection()
|
||||
// }
|
||||
// ^^^
|
||||
|
||||
if (developerTools) {
|
||||
SectionDividerSpaced()
|
||||
@ -427,6 +481,26 @@ fun UnblockMemberButton(onClick: () -> Unit) {
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BlockForAllButton(onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_back_hand),
|
||||
stringResource(MR.strings.block_for_all),
|
||||
click = onClick,
|
||||
textColor = Color.Red,
|
||||
iconColor = Color.Red,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UnblockForAllButton(onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_do_not_touch),
|
||||
stringResource(MR.strings.unblock_for_all),
|
||||
click = onClick
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RemoveMemberButton(onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
@ -553,6 +627,36 @@ fun updateMemberSettings(rhId: Long?, gInfo: GroupInfo, member: GroupMember, mem
|
||||
}
|
||||
}
|
||||
|
||||
fun blockForAllAlert(rhId: Long?, gInfo: GroupInfo, mem: GroupMember) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.block_for_all_question),
|
||||
text = generalGetString(MR.strings.block_member_desc).format(mem.chatViewName),
|
||||
confirmText = generalGetString(MR.strings.block_for_all),
|
||||
onConfirm = {
|
||||
blockMemberForAll(rhId, gInfo, mem, true)
|
||||
},
|
||||
destructive = true,
|
||||
)
|
||||
}
|
||||
|
||||
fun unblockForAllAlert(rhId: Long?, gInfo: GroupInfo, mem: GroupMember) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.unblock_for_all_question),
|
||||
text = generalGetString(MR.strings.unblock_member_desc).format(mem.chatViewName),
|
||||
confirmText = generalGetString(MR.strings.unblock_for_all),
|
||||
onConfirm = {
|
||||
blockMemberForAll(rhId, gInfo, mem, false)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fun blockMemberForAll(rhId: Long?, gInfo: GroupInfo, member: GroupMember, blocked: Boolean) {
|
||||
withBGApi {
|
||||
val updatedMember = ChatController.apiBlockMemberForAll(rhId, gInfo.groupId, member.groupMemberId, blocked)
|
||||
chatModel.upsertGroupMember(rhId, gInfo, updatedMember)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewGroupMemberInfoLayout() {
|
||||
@ -570,6 +674,8 @@ fun PreviewGroupMemberInfoLayout() {
|
||||
connectViaAddress = {},
|
||||
blockMember = {},
|
||||
unblockMember = {},
|
||||
blockForAll = {},
|
||||
unblockForAll = {},
|
||||
removeMember = {},
|
||||
onRoleSelected = {},
|
||||
switchMemberAddress = {},
|
||||
|
@ -319,7 +319,7 @@ fun ChatItemView(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable fun DeletedItem() {
|
||||
@Composable fun LegacyDeletedItem() {
|
||||
DeletedItemView(cItem, cInfo.timedMessagesTTL)
|
||||
DefaultDropdownMenu(showMenu) {
|
||||
ItemInfoAction(cInfo, cItem, showItemDetails, showMenu)
|
||||
@ -371,7 +371,7 @@ fun ChatItemView(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ModeratedItem() {
|
||||
fun DeletedItem() {
|
||||
MarkedDeletedItemView(cItem, cInfo.timedMessagesTTL, revealed)
|
||||
DefaultDropdownMenu(showMenu) {
|
||||
ItemInfoAction(cInfo, cItem, showItemDetails, showMenu)
|
||||
@ -382,8 +382,8 @@ fun ChatItemView(
|
||||
when (val c = cItem.content) {
|
||||
is CIContent.SndMsgContent -> ContentItem()
|
||||
is CIContent.RcvMsgContent -> ContentItem()
|
||||
is CIContent.SndDeleted -> DeletedItem()
|
||||
is CIContent.RcvDeleted -> DeletedItem()
|
||||
is CIContent.SndDeleted -> LegacyDeletedItem()
|
||||
is CIContent.RcvDeleted -> LegacyDeletedItem()
|
||||
is CIContent.SndCall -> CallItem(c.status, c.duration)
|
||||
is CIContent.RcvCall -> CallItem(c.status, c.duration)
|
||||
is CIContent.RcvIntegrityError -> if (developerTools) {
|
||||
@ -449,8 +449,9 @@ fun ChatItemView(
|
||||
CIChatFeatureView(cItem, c.groupFeature, Color.Red, revealed = revealed, showMenu = showMenu)
|
||||
MsgContentItemDropdownMenu()
|
||||
}
|
||||
is CIContent.SndModerated -> ModeratedItem()
|
||||
is CIContent.RcvModerated -> ModeratedItem()
|
||||
is CIContent.SndModerated -> DeletedItem()
|
||||
is CIContent.RcvModerated -> DeletedItem()
|
||||
is CIContent.RcvBlocked -> DeletedItem()
|
||||
is CIContent.InvalidJSON -> CIInvalidJSONView(c.json)
|
||||
}
|
||||
}
|
||||
|
@ -209,7 +209,10 @@ fun FramedItemView(
|
||||
is CIDeleted.Blocked -> {
|
||||
FramedItemHeader(stringResource(MR.strings.blocked_item_description), true, painterResource(MR.images.ic_back_hand))
|
||||
}
|
||||
else -> {
|
||||
is CIDeleted.BlockedByAdmin -> {
|
||||
FramedItemHeader(stringResource(MR.strings.blocked_by_admin_item_description), true, painterResource(MR.images.ic_back_hand))
|
||||
}
|
||||
is CIDeleted.Deleted -> {
|
||||
FramedItemHeader(stringResource(MR.strings.marked_deleted_description), true, painterResource(MR.images.ic_delete))
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ private fun MergedMarkedDeletedText(chatItem: ChatItem, revealed: MutableState<B
|
||||
val reversedChatItems = ChatModel.chatItems.asReversed()
|
||||
var moderated = 0
|
||||
var blocked = 0
|
||||
var blockedByAdmin = 0
|
||||
var deleted = 0
|
||||
val moderatedBy: MutableSet<String> = mutableSetOf()
|
||||
while (i < reversedChatItems.size) {
|
||||
@ -59,16 +60,19 @@ private fun MergedMarkedDeletedText(chatItem: ChatItem, revealed: MutableState<B
|
||||
moderatedBy.add(itemDeleted.byGroupMember.displayName)
|
||||
}
|
||||
is CIDeleted.Blocked -> blocked += 1
|
||||
is CIDeleted.BlockedByAdmin -> blockedByAdmin +=1
|
||||
is CIDeleted.Deleted -> deleted += 1
|
||||
}
|
||||
i++
|
||||
}
|
||||
val total = moderated + blocked + deleted
|
||||
val total = moderated + blocked + blockedByAdmin + deleted
|
||||
if (total <= 1)
|
||||
markedDeletedText(chatItem.meta)
|
||||
else if (total == moderated)
|
||||
stringResource(MR.strings.moderated_items_description).format(total, moderatedBy.joinToString(", "))
|
||||
else if (total == blocked)
|
||||
else if (total == blockedByAdmin)
|
||||
stringResource(MR.strings.blocked_by_admin_items_description).format(total)
|
||||
else if (total == blocked + blockedByAdmin)
|
||||
stringResource(MR.strings.blocked_items_description).format(total)
|
||||
else
|
||||
stringResource(MR.strings.marked_deleted_items_description).format(total)
|
||||
@ -93,7 +97,9 @@ private fun markedDeletedText(meta: CIMeta): String =
|
||||
String.format(generalGetString(MR.strings.moderated_item_description), meta.itemDeleted.byGroupMember.displayName)
|
||||
is CIDeleted.Blocked ->
|
||||
generalGetString(MR.strings.blocked_item_description)
|
||||
else ->
|
||||
is CIDeleted.BlockedByAdmin ->
|
||||
generalGetString(MR.strings.blocked_by_admin_item_description)
|
||||
is CIDeleted.Deleted, null ->
|
||||
generalGetString(MR.strings.marked_deleted_description)
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,9 @@
|
||||
<string name="moderated_item_description">moderated by %s</string>
|
||||
<string name="moderated_items_description">%1$d messages moderated by %2$s</string>
|
||||
<string name="blocked_item_description">blocked</string>
|
||||
<string name="blocked_by_admin_item_description">blocked by admin</string>
|
||||
<string name="blocked_items_description">%d messages blocked</string>
|
||||
<string name="blocked_by_admin_items_description">%d messages blocked by admin</string>
|
||||
<string name="sending_files_not_yet_supported">sending files is not supported yet</string>
|
||||
<string name="receiving_files_not_yet_supported">receiving files is not supported yet</string>
|
||||
<string name="sender_you_pronoun">you</string>
|
||||
@ -1176,6 +1178,8 @@
|
||||
<string name="rcv_group_event_member_connected">connected</string>
|
||||
<string name="rcv_group_event_member_left">left</string>
|
||||
<string name="rcv_group_event_changed_member_role">changed role of %s to %s</string>
|
||||
<string name="rcv_group_event_member_blocked">blocked %s</string>
|
||||
<string name="rcv_group_event_member_unblocked">unblocked %s</string>
|
||||
<string name="rcv_group_event_changed_your_role">changed your role to %s</string>
|
||||
<string name="rcv_group_event_member_deleted">removed %1$s</string>
|
||||
<string name="rcv_group_event_user_deleted">removed you</string>
|
||||
@ -1185,6 +1189,8 @@
|
||||
<string name="rcv_group_event_member_created_contact">connected directly</string>
|
||||
<string name="snd_group_event_changed_member_role">you changed role of %s to %s</string>
|
||||
<string name="snd_group_event_changed_role_for_yourself">you changed role for yourself to %s</string>
|
||||
<string name="snd_group_event_member_blocked">you blocked %s</string>
|
||||
<string name="snd_group_event_member_unblocked">you unblocked %s</string>
|
||||
<string name="snd_group_event_member_deleted">you removed %1$s</string>
|
||||
<string name="snd_group_event_user_left">you left</string>
|
||||
<string name="snd_group_event_group_profile_updated">group profile updated</string>
|
||||
@ -1339,11 +1345,17 @@
|
||||
<string name="block_member_question">Block member?</string>
|
||||
<string name="block_member_button">Block member</string>
|
||||
<string name="block_member_confirmation">Block</string>
|
||||
<string name="block_for_all_question">Block member for all?</string>
|
||||
<string name="block_for_all">Block for all</string>
|
||||
<string name="block_member_desc">All new messages from %s will be hidden!</string>
|
||||
<string name="unblock_member_question">Unblock member?</string>
|
||||
<string name="unblock_member_button">Unblock member</string>
|
||||
<string name="unblock_member_confirmation">Unblock</string>
|
||||
<string name="unblock_for_all_question">Unblock member for all?</string>
|
||||
<string name="unblock_for_all">Unblock for all</string>
|
||||
<string name="unblock_member_desc">Messages from %s will be shown!</string>
|
||||
<string name="member_blocked_by_admin">Blocked by admin</string>
|
||||
<string name="member_info_member_blocked">blocked</string>
|
||||
<string name="member_info_section_title_member">MEMBER</string>
|
||||
<string name="role_in_group">Role</string>
|
||||
<string name="change_role">Change role</string>
|
||||
@ -1356,6 +1368,7 @@
|
||||
<string name="connect_via_member_address_alert_desc">Сonnection request will be sent to this group member.</string>
|
||||
<string name="error_removing_member">Error removing member</string>
|
||||
<string name="error_changing_role">Error changing role</string>
|
||||
<string name="error_blocking_member_for_all">Error blocking member for all</string>
|
||||
<string name="info_row_group">Group</string>
|
||||
<string name="info_row_connection">Connection</string>
|
||||
<string name="conn_level_desc_direct">direct</string>
|
||||
|
Loading…
Reference in New Issue
Block a user