From 117ed75d4012e0695ca7acf060c24627b5dcd02a Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Mon, 22 Jun 2026 12:53:05 +0000 Subject: [PATCH] ui: allow to change member role in channel (#7096) --- apps/ios/Shared/Views/Chat/ChatView.swift | 2 +- .../Chat/Group/AddGroupMembersView.swift | 2 +- .../Views/Chat/Group/ChannelMembersView.swift | 2 +- .../Views/Chat/Group/GroupChatInfoView.swift | 2 +- .../Views/Chat/Group/GroupLinkView.swift | 2 +- .../Chat/Group/GroupMemberInfoView.swift | 18 ++++++----- .../Views/Chat/Group/MemberSupportView.swift | 2 +- apps/ios/SimpleXChat/ChatTypes.swift | 28 ++++++++++++----- .../chat/simplex/common/model/ChatModel.kt | 23 +++++++++----- .../simplex/common/views/chat/ChatView.kt | 2 +- .../views/chat/group/AddGroupMembersView.kt | 2 +- .../views/chat/group/ChannelMembersView.kt | 10 +++--- .../views/chat/group/GroupChatInfoView.kt | 8 ++--- .../common/views/chat/group/GroupLinkView.kt | 2 +- .../views/chat/group/GroupMemberInfoView.kt | 31 +++++++++---------- .../views/chat/group/MemberSupportView.kt | 6 ++-- .../commonMain/resources/MR/base/strings.xml | 5 ++- 17 files changed, 85 insertions(+), 62 deletions(-) diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift index 49643745b0..ded0019692 100644 --- a/apps/ios/Shared/Views/Chat/ChatView.swift +++ b/apps/ios/Shared/Views/Chat/ChatView.swift @@ -1999,7 +1999,7 @@ struct ChatView: View { let (name, role) = if ci.meta.showGroupAsSender { (groupInfo.chatViewName, NSLocalizedString("group", comment: "shown on group welcome message")) } else { - (member.chatViewName, member.memberRole.text) + (member.chatViewName, member.memberRole.text(isChannel: groupInfo.isChannel)) } Group { if #available(iOS 16.0, *) { diff --git a/apps/ios/Shared/Views/Chat/Group/AddGroupMembersView.swift b/apps/ios/Shared/Views/Chat/Group/AddGroupMembersView.swift index b59fd51fe8..336b4adfd1 100644 --- a/apps/ios/Shared/Views/Chat/Group/AddGroupMembersView.swift +++ b/apps/ios/Shared/Views/Chat/Group/AddGroupMembersView.swift @@ -183,7 +183,7 @@ struct AddGroupMembersViewCommon: View { private func rolePicker() -> some View { Picker("New member role", selection: $selectedRole) { ForEach(GroupMemberRole.supportedRoles.filter({ $0 <= groupInfo.membership.memberRole })) { role in - Text(role.text) + Text(role.text(isChannel: groupInfo.isChannel)) } } .frame(height: 36) diff --git a/apps/ios/Shared/Views/Chat/Group/ChannelMembersView.swift b/apps/ios/Shared/Views/Chat/Group/ChannelMembersView.swift index 50144e2bc5..44fc302aff 100644 --- a/apps/ios/Shared/Views/Chat/Group/ChannelMembersView.swift +++ b/apps/ios/Shared/Views/Chat/Group/ChannelMembersView.swift @@ -66,7 +66,7 @@ struct ChannelMembersView: View { } Spacer() if showRole { - Text(member.memberRole.text) + Text(member.memberRole.text(isChannel: groupInfo.isChannel)) .foregroundColor(theme.colors.secondary) } } diff --git a/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift b/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift index b62939fd36..5563d79e61 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupChatInfoView.swift @@ -581,7 +581,7 @@ struct GroupChatInfoView: View { } else { let role = member.memberRole if [.owner, .admin, .moderator, .observer].contains(role) { - Text(member.memberRole.text) + Text(member.memberRole.text(isChannel: groupInfo.isChannel)) .foregroundColor(theme.colors.secondary) } } diff --git a/apps/ios/Shared/Views/Chat/Group/GroupLinkView.swift b/apps/ios/Shared/Views/Chat/Group/GroupLinkView.swift index 22253c4808..43d23878f5 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupLinkView.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupLinkView.swift @@ -84,7 +84,7 @@ struct GroupLinkView: View { if !isChannel { Picker("Initial role", selection: $groupLinkMemberRole) { ForEach([GroupMemberRole.member, GroupMemberRole.observer]) { role in - Text(role.text) + Text(role.text(isChannel: isChannel)) } } .frame(height: 36) diff --git a/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift b/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift index 2f37e3d822..c87f97089c 100644 --- a/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift +++ b/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift @@ -178,15 +178,15 @@ struct GroupMemberInfoView: View { let label: LocalizedStringKey = groupInfo.useRelays ? "Channel" : groupInfo.businessChat == nil ? "Group" : "Chat" infoRow(label, groupInfo.displayName) - if !groupInfo.useRelays, let roles = member.canChangeRoleTo(groupInfo: groupInfo) { + if let roles = member.canChangeRoleTo(groupInfo: groupInfo) { Picker("Change role", selection: $newRole) { ForEach(roles) { role in - Text(role.text) + Text(role.text(isChannel: groupInfo.isChannel)) } } .frame(height: 36) } else { - infoRow("Role", member.memberRole.text) + infoRow("Role", member.memberRole.text(isChannel: groupInfo.isChannel)) } if let link = member.relayLink { infoRow("Relay link", String.localizedStringWithFormat(NSLocalizedString("via %@", comment: "relay hostname"), hostFromRelayLink(link))) @@ -727,15 +727,17 @@ struct GroupMemberInfoView: View { private func changeMemberRoleAlert(_ mem: GroupMember) -> Alert { Alert( - title: Text("Change member role?"), + title: Text("Change role?"), message: ( mem.memberCurrent ? ( - groupInfo.businessChat == nil - ? Text("Member role will be changed to \"\(newRole.text)\". All group members will be notified.") - : Text("Member role will be changed to \"\(newRole.text)\". All chat members will be notified.") + groupInfo.isChannel + ? Text("Role will be changed to \"\(newRole.text(isChannel: groupInfo.isChannel))\". All subscribers will be notified.") + : groupInfo.businessChat == nil + ? Text("Role will be changed to \"\(newRole.text(isChannel: groupInfo.isChannel))\". All group members will be notified.") + : Text("Role will be changed to \"\(newRole.text(isChannel: groupInfo.isChannel))\". All chat members will be notified.") ) - : Text("Member role will be changed to \"\(newRole.text)\". The member will receive a new invitation.") + : Text("Role will be changed to \"\(newRole.text(isChannel: groupInfo.isChannel))\". The member will receive a new invitation.") ), primaryButton: .default(Text("Change")) { Task { diff --git a/apps/ios/Shared/Views/Chat/Group/MemberSupportView.swift b/apps/ios/Shared/Views/Chat/Group/MemberSupportView.swift index 0263a39a90..da9d56a699 100644 --- a/apps/ios/Shared/Views/Chat/Group/MemberSupportView.swift +++ b/apps/ios/Shared/Views/Chat/Group/MemberSupportView.swift @@ -205,7 +205,7 @@ struct MemberSupportView: View { } else if member.memberPending { return member.memberStatus.text } else { - return LocalizedStringKey(member.memberRole.text) + return LocalizedStringKey(member.memberRole.text(isChannel: groupInfo.isChannel)) } } diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift index d7478e5c3b..8b186f168d 100644 --- a/apps/ios/SimpleXChat/ChatTypes.swift +++ b/apps/ios/SimpleXChat/ChatTypes.swift @@ -2981,8 +2981,16 @@ public struct GroupMember: Identifiable, Decodable, Hashable { public func canChangeRoleTo(groupInfo: GroupInfo) -> [GroupMemberRole]? { if memberRole == .relay || !canBeRemoved(groupInfo: groupInfo) || memberStatus == .memRemoved || memberStatus == .memLeft || memberPending { return nil } + if groupInfo.useRelays && !groupInfo.isOwner { return nil } let userRole = groupInfo.membership.memberRole - return GroupMemberRole.supportedRoles.filter { $0 <= 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: + // return GroupMemberRole.supportedRoles.filter { $0 <= userRole && $0 != .owner } + return [.observer, .member] + } else { + return GroupMemberRole.supportedRoles.filter { $0 <= userRole } + } } public func canBlockForAll(groupInfo: GroupInfo) -> Bool { @@ -3070,12 +3078,16 @@ public enum GroupMemberRole: String, Identifiable, CaseIterable, Comparable, Cod public static var supportedRoles: [GroupMemberRole] = [.observer, .member, .moderator, .admin, .owner] - public var text: String { + public func text(isChannel: Bool) -> String { switch self { case .relay: return NSLocalizedString("relay", comment: "member role") - case .observer: return NSLocalizedString("observer", comment: "member role") + case .observer: return isChannel + ? NSLocalizedString("subscriber", comment: "member role") + : NSLocalizedString("observer", comment: "member role") case .author: return NSLocalizedString("author", comment: "member role") - case .member: return NSLocalizedString("member", comment: "member role") + case .member: return isChannel + ? NSLocalizedString("contributor", comment: "member role") + : NSLocalizedString("member", comment: "member role") case .moderator: return NSLocalizedString("moderator", comment: "member role") case .admin: return NSLocalizedString("admin", comment: "member role") case .owner: return NSLocalizedString("owner", comment: "member role") @@ -5596,7 +5608,7 @@ public enum RcvGroupEvent: Decodable, Hashable { case .userAccepted: return NSLocalizedString("accepted you", comment: "rcv group event chat item") case .memberLeft: return NSLocalizedString("left", comment: "rcv group event chat item") case let .memberRole(_, profile, role): - return String.localizedStringWithFormat(NSLocalizedString("changed role of %@ to %@", comment: "rcv group event chat item"), profile.profileViewName, role.text) + return String.localizedStringWithFormat(NSLocalizedString("changed role of %@ to %@", comment: "rcv group event chat item"), profile.profileViewName, role.text(isChannel: isChannel)) case let .memberBlocked(_, profile, blocked): if blocked { return String.localizedStringWithFormat(NSLocalizedString("blocked %@", comment: "rcv group event chat item"), profile.profileViewName) @@ -5604,7 +5616,7 @@ public enum RcvGroupEvent: Decodable, Hashable { return String.localizedStringWithFormat(NSLocalizedString("unblocked %@", comment: "rcv group event chat item"), profile.profileViewName) } case let .userRole(role): - return String.localizedStringWithFormat(NSLocalizedString("changed your role to %@", comment: "rcv group event chat item"), role.text) + return String.localizedStringWithFormat(NSLocalizedString("changed your role to %@", comment: "rcv group event chat item"), role.text(isChannel: isChannel)) case let .memberDeleted(_, profile): return String.localizedStringWithFormat(NSLocalizedString("removed %@", comment: "rcv group event chat item"), profile.profileViewName) case .userDeleted: return NSLocalizedString("removed you", comment: "rcv group event chat item") @@ -5650,9 +5662,9 @@ public enum SndGroupEvent: Decodable, Hashable { func text(isChannel: Bool) -> String { switch self { case let .memberRole(_, profile, role): - return String.localizedStringWithFormat(NSLocalizedString("you changed role of %@ to %@", comment: "snd group event chat item"), profile.profileViewName, role.text) + return String.localizedStringWithFormat(NSLocalizedString("you changed role of %@ to %@", comment: "snd group event chat item"), profile.profileViewName, role.text(isChannel: isChannel)) case let .userRole(role): - return String.localizedStringWithFormat(NSLocalizedString("you changed role for yourself to %@", comment: "snd group event chat item"), role.text) + return String.localizedStringWithFormat(NSLocalizedString("you changed role for yourself to %@", comment: "snd group event chat item"), role.text(isChannel: isChannel)) case let .memberBlocked(_, profile, blocked): if blocked { return String.localizedStringWithFormat(NSLocalizedString("you blocked %@", comment: "snd group event chat item"), profile.profileViewName) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt index ecfb58fdb0..c5dd81fec7 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/ChatModel.kt @@ -2617,8 +2617,15 @@ data class GroupMember ( fun canChangeRoleTo(groupInfo: GroupInfo): List? = 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 = 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 { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt index a020f8c1fe..6f7c746691 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt @@ -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, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt index 4717321f63..7223f69f98 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt @@ -228,7 +228,7 @@ private fun RoleSelectionRow(groupInfo: GroupInfo, selectedRole: MutableState 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 ) } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt index b2c25bf06c..2b1c7bcd09 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupChatInfoView.kt @@ -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) } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupLinkView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupLinkView.kt index b68f0efaf5..f6f19e9d72 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupLinkView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupLinkView.kt @@ -308,7 +308,7 @@ private fun RoleSelectionRow(groupInfo: GroupInfo, selectedRole: MutableState Unit) { private fun RoleSelectionRow( roles: List, selectedRole: MutableState, - 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, ) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/MemberSupportView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/MemberSupportView.kt index 7ca277df94..b685d20fb9 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/MemberSupportView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/MemberSupportView.kt @@ -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) } } diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index 4ea07d4608..71c0bf98a4 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -1850,8 +1850,10 @@ observer + subscriber author member + contributor moderator admin owner @@ -2043,9 +2045,10 @@ Change role Change Switch - Change group role? + Change role? The role will be changed to "%s". Everyone in the group will be notified. The role will be changed to "%s". Everyone in the chat will be notified. + The role will be changed to "%s". Everyone in the channel will be notified. The role will be changed to "%s". The member will receive a new invitation. Connect directly? Сonnection request will be sent to this group member.