mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-29 11:59:06 +00:00
ui: allow to change member role in channel (#7096)
This commit is contained in:
+15
-8
@@ -2617,8 +2617,15 @@ data class GroupMember (
|
||||
|
||||
fun canChangeRoleTo(groupInfo: GroupInfo): List<GroupMemberRole>? =
|
||||
if (memberRole == GroupMemberRole.Relay || !canBeRemoved(groupInfo) || memberStatus == GroupMemberStatus.MemRemoved || memberStatus == GroupMemberStatus.MemLeft || memberPending) null
|
||||
else if (groupInfo.useRelays && !groupInfo.isOwner) null
|
||||
else groupInfo.membership.memberRole.let { userRole ->
|
||||
GroupMemberRole.selectableRoles.filter { it <= userRole }
|
||||
if (groupInfo.useRelays)
|
||||
// TODO [relays]: for now owners can only set observer/member in channels.
|
||||
// Restore the full Owner-excluded picker when moderator/admin promotion is supported:
|
||||
// GroupMemberRole.selectableRoles.filter { it <= userRole && it != GroupMemberRole.Owner }
|
||||
listOf(GroupMemberRole.Observer, GroupMemberRole.Member)
|
||||
else
|
||||
GroupMemberRole.selectableRoles.filter { it <= userRole }
|
||||
}
|
||||
|
||||
fun canBlockForAll(groupInfo: GroupInfo): Boolean {
|
||||
@@ -2696,11 +2703,11 @@ enum class GroupMemberRole(val memberRole: String) {
|
||||
val selectableRoles: List<GroupMemberRole> = listOf(Observer, Member, Moderator, Admin, Owner)
|
||||
}
|
||||
|
||||
val text: String get() = when (this) {
|
||||
fun text(isChannel: Boolean): String = when (this) {
|
||||
Relay -> generalGetString(MR.strings.group_member_role_relay)
|
||||
Observer -> generalGetString(MR.strings.group_member_role_observer)
|
||||
Observer -> generalGetString(if (isChannel) MR.strings.group_member_role_observer_channel else MR.strings.group_member_role_observer)
|
||||
Author -> generalGetString(MR.strings.group_member_role_author)
|
||||
Member -> generalGetString(MR.strings.group_member_role_member)
|
||||
Member -> generalGetString(if (isChannel) MR.strings.group_member_role_member_channel else MR.strings.group_member_role_member)
|
||||
Moderator -> generalGetString(MR.strings.group_member_role_moderator)
|
||||
Admin -> generalGetString(MR.strings.group_member_role_admin)
|
||||
Owner -> generalGetString(MR.strings.group_member_role_owner)
|
||||
@@ -5094,13 +5101,13 @@ sealed class RcvGroupEvent() {
|
||||
is MemberAccepted -> String.format(generalGetString(MR.strings.rcv_group_event_member_accepted), profile.profileViewName)
|
||||
is UserAccepted -> generalGetString(MR.strings.rcv_group_event_user_accepted)
|
||||
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 MemberRole -> String.format(generalGetString(MR.strings.rcv_group_event_changed_member_role), profile.profileViewName, role.text(isChannel = isChannel))
|
||||
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 UserRole -> String.format(generalGetString(MR.strings.rcv_group_event_changed_your_role), role.text(isChannel = isChannel))
|
||||
is MemberDeleted -> String.format(generalGetString(MR.strings.rcv_group_event_member_deleted), profile.profileViewName)
|
||||
is UserDeleted -> generalGetString(MR.strings.rcv_group_event_user_deleted)
|
||||
is GroupDeleted -> generalGetString(if (isChannel) MR.strings.rcv_channel_event_channel_deleted else MR.strings.rcv_group_event_group_deleted)
|
||||
@@ -5139,8 +5146,8 @@ sealed class SndGroupEvent() {
|
||||
val text: String get() = text(isChannel = false)
|
||||
|
||||
fun text(isChannel: Boolean): String = 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 MemberRole -> String.format(generalGetString(MR.strings.snd_group_event_changed_member_role), profile.profileViewName, role.text(isChannel = isChannel))
|
||||
is UserRole -> String.format(generalGetString(MR.strings.snd_group_event_changed_role_for_yourself), role.text(isChannel = isChannel))
|
||||
is MemberBlocked -> if (blocked) {
|
||||
String.format(generalGetString(MR.strings.snd_group_event_member_blocked), profile.profileViewName)
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -2035,7 +2035,7 @@ fun BoxScope.ChatItemsList(
|
||||
val tailRendered = style is ShapeStyle.Bubble && style.tailVisible
|
||||
|
||||
Text(
|
||||
member.memberRole.text,
|
||||
member.memberRole.text(isChannel = chatInfo.isChannel),
|
||||
Modifier.padding(start = DEFAULT_PADDING_HALF * 1.5f, end = DEFAULT_PADDING_HALF + if (tailRendered) msgTailWidthDp else 0.dp),
|
||||
fontSize = 13.5.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
|
||||
+1
-1
@@ -228,7 +228,7 @@ private fun RoleSelectionRow(groupInfo: GroupInfo, selectedRole: MutableState<Gr
|
||||
) {
|
||||
val values = GroupMemberRole.selectableRoles
|
||||
.filter { it <= groupInfo.membership.memberRole }
|
||||
.map { it to it.text }
|
||||
.map { it to it.text(isChannel = groupInfo.isChannel) }
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(MR.strings.new_member_role),
|
||||
values,
|
||||
|
||||
+5
-5
@@ -46,7 +46,7 @@ fun ChannelMembersView(
|
||||
val subscriberCount = groupInfo.groupSummary.publicMemberCount ?: (members.size + 1).toLong()
|
||||
SectionView(title = subscriberCountStr(subscriberCount)) {
|
||||
SectionItemView(minHeight = 54.dp, padding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
ChannelMemberRow(groupInfo.membership, user = true, showRole = true)
|
||||
ChannelMemberRow(groupInfo.membership, user = true, showRole = true, isChannel = groupInfo.isChannel)
|
||||
}
|
||||
members.forEachIndexed { index, member ->
|
||||
Divider()
|
||||
@@ -55,7 +55,7 @@ fun ChannelMembersView(
|
||||
minHeight = 54.dp,
|
||||
padding = PaddingValues(horizontal = DEFAULT_PADDING)
|
||||
) {
|
||||
ChannelMemberRow(member, user = false, showRole = member.memberRole >= GroupMemberRole.Owner)
|
||||
ChannelMemberRow(member, user = false, showRole = member.memberRole >= GroupMemberRole.Owner, isChannel = groupInfo.isChannel)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ fun ChannelMembersView(
|
||||
minHeight = 54.dp,
|
||||
padding = PaddingValues(horizontal = DEFAULT_PADDING)
|
||||
) {
|
||||
ChannelMemberRow(member, user = false, showRole = false)
|
||||
ChannelMemberRow(member, user = false, showRole = false, isChannel = groupInfo.isChannel)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ fun ChannelMembersView(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ChannelMemberRow(member: GroupMember, user: Boolean, showRole: Boolean) {
|
||||
private fun ChannelMemberRow(member: GroupMember, user: Boolean, showRole: Boolean, isChannel: Boolean) {
|
||||
Row(
|
||||
Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
@@ -112,7 +112,7 @@ private fun ChannelMemberRow(member: GroupMember, user: Boolean, showRole: Boole
|
||||
}
|
||||
if (showRole) {
|
||||
Text(
|
||||
member.memberRole.text,
|
||||
member.memberRole.text(isChannel = isChannel),
|
||||
color = MaterialTheme.colors.secondary
|
||||
)
|
||||
}
|
||||
|
||||
+4
-4
@@ -731,7 +731,7 @@ fun ModalData.GroupChatInfoLayout(
|
||||
}
|
||||
}
|
||||
SectionItemView(minHeight = 54.dp, padding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
MemberRow(groupInfo.membership, user = true)
|
||||
MemberRow(groupInfo.membership, user = true, isChannel = groupInfo.isChannel)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -765,7 +765,7 @@ fun ModalData.GroupChatInfoLayout(
|
||||
val selectionOffset by animateDpAsState(if (selectedItems.value != null) 20.dp + 22.dp * fontSizeMultiplier else 0.dp)
|
||||
DropDownMenuForMember(chat.remoteHostId, member, groupInfo, selectedItems, showMenu)
|
||||
Box(Modifier.padding(start = selectionOffset)) {
|
||||
MemberRow(member)
|
||||
MemberRow(member, isChannel = groupInfo.isChannel)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1057,7 +1057,7 @@ private fun AddMembersButton(titleId: StringResource, tint: Color = MaterialThem
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MemberRow(member: GroupMember, user: Boolean = false, infoPage: Boolean = true, showlocalAliasAndFullName: Boolean = false, selected: Boolean = false) {
|
||||
fun MemberRow(member: GroupMember, user: Boolean = false, infoPage: Boolean = true, showlocalAliasAndFullName: Boolean = false, selected: Boolean = false, isChannel: Boolean = false) {
|
||||
@Composable
|
||||
fun MemberInfo() {
|
||||
if (member.blocked) {
|
||||
@@ -1065,7 +1065,7 @@ fun MemberRow(member: GroupMember, user: Boolean = false, infoPage: Boolean = tr
|
||||
} else {
|
||||
val role = member.memberRole
|
||||
if (role in listOf(GroupMemberRole.Owner, GroupMemberRole.Admin, GroupMemberRole.Moderator, GroupMemberRole.Observer)) {
|
||||
Text(role.text, color = MaterialTheme.colors.secondary)
|
||||
Text(role.text(isChannel = isChannel), color = MaterialTheme.colors.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -308,7 +308,7 @@ private fun RoleSelectionRow(groupInfo: GroupInfo, selectedRole: MutableState<Gr
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
val values = listOf(GroupMemberRole.Member, GroupMemberRole.Observer).map { it to it.text }
|
||||
val values = listOf(GroupMemberRole.Member, GroupMemberRole.Observer).map { it to it.text(isChannel = groupInfo.isChannel) }
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(MR.strings.initial_member_role),
|
||||
values,
|
||||
|
||||
+15
-16
@@ -596,15 +596,11 @@ fun GroupMemberInfoLayout(
|
||||
else if (groupInfo.businessChat == null) MR.strings.info_row_group
|
||||
else MR.strings.info_row_chat
|
||||
InfoRow(stringResource(titleId), groupInfo.displayName)
|
||||
if (!groupInfo.useRelays) {
|
||||
val roles = remember { member.canChangeRoleTo(groupInfo) }
|
||||
if (roles != null) {
|
||||
RoleSelectionRow(roles, newRole, onRoleSelected)
|
||||
} else {
|
||||
InfoRow(stringResource(MR.strings.role_in_group), member.memberRole.text)
|
||||
}
|
||||
val roles = remember { member.canChangeRoleTo(groupInfo) }
|
||||
if (roles != null) {
|
||||
RoleSelectionRow(roles, newRole, onRoleSelected, groupInfo.isChannel)
|
||||
} else {
|
||||
InfoRow(stringResource(MR.strings.role_in_group), member.memberRole.text)
|
||||
InfoRow(stringResource(MR.strings.role_in_group), member.memberRole.text(isChannel = groupInfo.isChannel))
|
||||
}
|
||||
val relayLink = member.relayLink
|
||||
if (relayLink != null) {
|
||||
@@ -888,14 +884,15 @@ fun ConnectViaAddressButton(onClick: () -> Unit) {
|
||||
private fun RoleSelectionRow(
|
||||
roles: List<GroupMemberRole>,
|
||||
selectedRole: MutableState<GroupMemberRole>,
|
||||
onSelected: (GroupMemberRole) -> Unit
|
||||
onSelected: (GroupMemberRole) -> Unit,
|
||||
isChannel: Boolean
|
||||
) {
|
||||
Row(
|
||||
Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
val values = remember { roles.map { it to it.text } }
|
||||
val values = remember { roles.map { it to it.text(isChannel = isChannel) } }
|
||||
ExposedDropDownSettingRow(
|
||||
generalGetString(MR.strings.change_role),
|
||||
values,
|
||||
@@ -956,12 +953,14 @@ fun updateMemberRoleDialog(
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.change_member_role_question),
|
||||
text = if (memberCurrent) {
|
||||
if (groupInfo.businessChat == null)
|
||||
String.format(generalGetString(MR.strings.member_role_will_be_changed_with_notification), newRole.text)
|
||||
if (groupInfo.isChannel)
|
||||
String.format(generalGetString(MR.strings.member_role_will_be_changed_with_notification_channel), newRole.text(isChannel = groupInfo.isChannel))
|
||||
else if (groupInfo.businessChat == null)
|
||||
String.format(generalGetString(MR.strings.member_role_will_be_changed_with_notification), newRole.text(isChannel = groupInfo.isChannel))
|
||||
else
|
||||
String.format(generalGetString(MR.strings.member_role_will_be_changed_with_notification_chat), newRole.text)
|
||||
String.format(generalGetString(MR.strings.member_role_will_be_changed_with_notification_chat), newRole.text(isChannel = groupInfo.isChannel))
|
||||
} else
|
||||
String.format(generalGetString(MR.strings.member_role_will_be_changed_with_invitation), newRole.text),
|
||||
String.format(generalGetString(MR.strings.member_role_will_be_changed_with_invitation), newRole.text(isChannel = groupInfo.isChannel)),
|
||||
confirmText = generalGetString(MR.strings.change_verb),
|
||||
onDismiss = onDismiss,
|
||||
onConfirm = onConfirm,
|
||||
@@ -977,9 +976,9 @@ fun updateMembersRoleDialog(
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.change_member_role_question),
|
||||
text = if (groupInfo.businessChat == null)
|
||||
String.format(generalGetString(MR.strings.member_role_will_be_changed_with_notification), newRole.text)
|
||||
String.format(generalGetString(MR.strings.member_role_will_be_changed_with_notification), newRole.text(isChannel = groupInfo.isChannel))
|
||||
else
|
||||
String.format(generalGetString(MR.strings.member_role_will_be_changed_with_notification_chat), newRole.text),
|
||||
String.format(generalGetString(MR.strings.member_role_will_be_changed_with_notification_chat), newRole.text(isChannel = groupInfo.isChannel)),
|
||||
confirmText = generalGetString(MR.strings.change_verb),
|
||||
onConfirm = onConfirm,
|
||||
)
|
||||
|
||||
+3
-3
@@ -150,7 +150,7 @@ private fun ModalData.MemberSupportViewLayout(
|
||||
) {
|
||||
Box(contentAlignment = Alignment.CenterStart) {
|
||||
DropDownMenuForSupportChat(chat.remoteHostId, member, groupInfo, showMenu)
|
||||
SupportChatRow(member)
|
||||
SupportChatRow(member, isChannel = groupInfo.isChannel)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,7 +163,7 @@ private fun ModalData.MemberSupportViewLayout(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SupportChatRow(member: GroupMember) {
|
||||
fun SupportChatRow(member: GroupMember, isChannel: Boolean) {
|
||||
fun memberStatus(): String {
|
||||
return if (member.activeConn?.connStatus is ConnStatus.Failed) {
|
||||
generalGetString(MR.strings.member_info_member_failed)
|
||||
@@ -174,7 +174,7 @@ fun SupportChatRow(member: GroupMember) {
|
||||
} else if (member.memberPending) {
|
||||
member.memberStatus.text
|
||||
} else {
|
||||
member.memberRole.text
|
||||
member.memberRole.text(isChannel = isChannel)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1850,8 +1850,10 @@
|
||||
|
||||
<!-- GroupMemberRole -->
|
||||
<string name="group_member_role_observer">observer</string>
|
||||
<string name="group_member_role_observer_channel">subscriber</string>
|
||||
<string name="group_member_role_author">author</string>
|
||||
<string name="group_member_role_member">member</string>
|
||||
<string name="group_member_role_member_channel">contributor</string>
|
||||
<string name="group_member_role_moderator">moderator</string>
|
||||
<string name="group_member_role_admin">admin</string>
|
||||
<string name="group_member_role_owner">owner</string>
|
||||
@@ -2043,9 +2045,10 @@
|
||||
<string name="change_role">Change role</string>
|
||||
<string name="change_verb">Change</string>
|
||||
<string name="switch_verb">Switch</string>
|
||||
<string name="change_member_role_question">Change group role?</string>
|
||||
<string name="change_member_role_question">Change role?</string>
|
||||
<string name="member_role_will_be_changed_with_notification">The role will be changed to "%s". Everyone in the group will be notified.</string>
|
||||
<string name="member_role_will_be_changed_with_notification_chat">The role will be changed to "%s". Everyone in the chat will be notified.</string>
|
||||
<string name="member_role_will_be_changed_with_notification_channel">The role will be changed to "%s". Everyone in the channel will be notified.</string>
|
||||
<string name="member_role_will_be_changed_with_invitation">The role will be changed to "%s". The member will receive a new invitation.</string>
|
||||
<string name="connect_via_member_address_alert_title">Connect directly?</string>
|
||||
<string name="connect_via_member_address_alert_desc">Сonnection request will be sent to this group member.</string>
|
||||
|
||||
Reference in New Issue
Block a user