feat(community): enable choosing and changing community channel color

Fixes #4953
This commit is contained in:
Jonathan Rainville 2022-03-10 14:28:37 -05:00 committed by Iuri Matias
parent f9c2d20d65
commit aef8d0c4ab
18 changed files with 142 additions and 42 deletions

View File

@ -76,6 +76,9 @@ method `isIdenticon=`*(self: var BaseItem, value: bool) {.inline base.} =
method color*(self: BaseItem): string {.inline base.} = method color*(self: BaseItem): string {.inline base.} =
self.color self.color
method `color=`*(self: var BaseItem, value: string) {.inline base.} =
self.color = value
method emoji*(self: BaseItem): string {.inline base.} = method emoji*(self: BaseItem): string {.inline base.} =
self.emoji self.emoji

View File

@ -328,7 +328,7 @@ method onNotificationsUpdated*(self: Module, hasUnreadMessages: bool, notificati
self.view.updateChatDetailsNotifications(hasUnreadMessages, notificationCount) self.view.updateChatDetailsNotifications(hasUnreadMessages, notificationCount)
method onChatEdited*(self: Module, chatDto: ChatDto) = method onChatEdited*(self: Module, chatDto: ChatDto) =
self.view.updateChatDetails(chatDto.name, chatDto.description, chatDto.emoji) self.view.updateChatDetails(chatDto.name, chatDto.description, chatDto.emoji, chatDto.color)
self.messagesModule.updateChatIdentifier() self.messagesModule.updateChatIdentifier()
method onChatRenamed*(self: Module, newName: string) = method onChatRenamed*(self: Module, newName: string) =

View File

@ -111,10 +111,11 @@ QtObject:
proc amIChatAdmin*(self: View): bool {.slot.} = proc amIChatAdmin*(self: View): bool {.slot.} =
return self.delegate.amIChatAdmin() return self.delegate.amIChatAdmin()
proc updateChatDetails*(self: View, name, description, emoji: string) = proc updateChatDetails*(self: View, name, description, emoji, color: string) =
self.chatDetails.setName(name) self.chatDetails.setName(name)
self.chatDetails.setDescription(description) self.chatDetails.setDescription(description)
self.chatDetails.setEmoji(emoji) self.chatDetails.setEmoji(emoji)
self.chatDetails.setColor(color)
self.chatDetailsChanged() self.chatDetailsChanged()
proc updateChatDetailsName*(self: View, name: string) = proc updateChatDetailsName*(self: View, name: string) =

View File

@ -318,8 +318,10 @@ method createCommunityChannel*(
name: string, name: string,
description: string, description: string,
emoji: string, emoji: string,
color: string,
categoryId: string) = categoryId: string) =
self.communityService.createCommunityChannel(self.sectionId, name, description, emoji, categoryId) self.communityService.createCommunityChannel(self.sectionId, name, description, emoji, color,
categoryId)
method editCommunityChannel*( method editCommunityChannel*(
self: Controller, self: Controller,
@ -327,6 +329,7 @@ method editCommunityChannel*(
name: string, name: string,
description: string, description: string,
emoji: string, emoji: string,
color: string,
categoryId: string, categoryId: string,
position: int) = position: int) =
self.communityService.editCommunityChannel( self.communityService.editCommunityChannel(
@ -335,6 +338,7 @@ method editCommunityChannel*(
name, name,
description, description,
emoji, emoji,
color,
categoryId, categoryId,
position) position)

View File

@ -119,10 +119,12 @@ method acceptRequestToJoinCommunity*(self: AccessInterface, requestId: string) {
method declineRequestToJoinCommunity*(self: AccessInterface, requestId: string) {.base.} = method declineRequestToJoinCommunity*(self: AccessInterface, requestId: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method createCommunityChannel*(self: AccessInterface, name: string, description: string, emoji: string, categoryId: string) {.base.} = method createCommunityChannel*(self: AccessInterface, name: string, description: string,
emoji: string, color: string, categoryId: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method editCommunityChannel*(self: AccessInterface, channelId: string, name: string, description: string, emoji: string, categoryId: string, position: int) {.base.} = method editCommunityChannel*(self: AccessInterface, channelId: string, name: string,
description: string, emoji: string, color: string, categoryId: string, position: int) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method createCommunityCategory*(self: AccessInterface, name: string, channels: seq[string]) {.base.} = method createCommunityCategory*(self: AccessInterface, name: string, channels: seq[string]) {.base.} =

View File

@ -272,16 +272,17 @@ QtObject:
self.dataChanged(index, index, @[ModelRole.Name.int]) self.dataChanged(index, index, @[ModelRole.Name.int])
return return
proc updateItemDetails*(self: Model, id, name, description, emoji: string) = proc updateItemDetails*(self: Model, id, name, description, emoji, color: string) =
## This updates only first level items, it doesn't update subitems, since subitems cannot have custom icon. ## This updates only first level items, it doesn't update subitems, since subitems cannot have custom icon.
for i in 0 ..< self.items.len: for i in 0 ..< self.items.len:
if(self.items[i].id == id): if(self.items[i].id == id):
self.items[i].BaseItem.name = name self.items[i].BaseItem.name = name
self.items[i].BaseItem.description = description self.items[i].BaseItem.description = description
self.items[i].BaseItem.emoji = emoji self.items[i].BaseItem.emoji = emoji
self.items[i].BaseItem.color = color
let index = self.createIndex(i, 0, nil) let index = self.createIndex(i, 0, nil)
self.dataChanged(index, index, self.dataChanged(index, index,
@[ModelRole.Name.int, ModelRole.Description.int, ModelRole.Emoji.int]) @[ModelRole.Name.int, ModelRole.Description.int, ModelRole.Emoji.int, ModelRole.Color.int])
return return
proc updateNotificationsForItemOrSubItemById*(self: Model, id: string, hasUnreadMessages: bool, proc updateNotificationsForItemOrSubItemById*(self: Model, id: string, hasUnreadMessages: bool,

View File

@ -552,7 +552,8 @@ method onCommunityChannelDeletedOrChatLeft*(self: Module, chatId: string) =
method onCommunityChannelEdited*(self: Module, chat: ChatDto) = method onCommunityChannelEdited*(self: Module, chat: ChatDto) =
if(not self.chatContentModules.contains(chat.id)): if(not self.chatContentModules.contains(chat.id)):
return return
self.view.chatsModel().updateItemDetails(chat.id, chat.name, chat.description, chat.emoji) self.view.chatsModel().updateItemDetails(chat.id, chat.name, chat.description, chat.emoji,
chat.color)
method createOneToOneChat*(self: Module, communityID: string, chatId: string, ensName: string) = method createOneToOneChat*(self: Module, communityID: string, chatId: string, ensName: string) =
if(self.controller.isCommunity()): if(self.controller.isCommunity()):
@ -694,12 +695,13 @@ method acceptRequestToJoinCommunity*(self: Module, requestId: string) =
method declineRequestToJoinCommunity*(self: Module, requestId: string) = method declineRequestToJoinCommunity*(self: Module, requestId: string) =
self.controller.declineRequestToJoinCommunity(requestId) self.controller.declineRequestToJoinCommunity(requestId)
method createCommunityChannel*(self: Module, name, description, emoji, categoryId: string) = method createCommunityChannel*(self: Module, name, description, emoji, color, categoryId: string) =
self.controller.createCommunityChannel(name, description, emoji, categoryId) self.controller.createCommunityChannel(name, description, emoji, color, categoryId)
method editCommunityChannel*(self: Module, channelId, name, description, emoji, categoryId: string, method editCommunityChannel*(self: Module, channelId, name, description, emoji, color,
position: int) = categoryId: string, position: int) =
self.controller.editCommunityChannel(channelId, name, description, emoji, categoryId, position) self.controller.editCommunityChannel(channelId, name, description, emoji, color, categoryId,
position)
method createCommunityCategory*(self: Module, name: string, channels: seq[string]) = method createCommunityCategory*(self: Module, name: string, channels: seq[string]) =
self.controller.createCommunityCategory(name, channels) self.controller.createCommunityCategory(name, channels)

View File

@ -94,10 +94,12 @@ method acceptRequestToJoinCommunity*(self: AccessInterface, requestId: string) {
method declineRequestToJoinCommunity*(self: AccessInterface, requestId: string) {.base.} = method declineRequestToJoinCommunity*(self: AccessInterface, requestId: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method createCommunityChannel*(self: AccessInterface, name: string, description: string, emoji: string, categoryId: string) {.base.} = method createCommunityChannel*(self: AccessInterface, name: string, description: string,
emoji: string, color: string, categoryId: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method editCommunityChannel*(self: AccessInterface, channelId, name, description, emoji, categoryId: string, position: int) {.base.} = method editCommunityChannel*(self: AccessInterface, channelId, name, description, emoji, color,
categoryId: string, position: int) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method leaveCommunity*(self: AccessInterface) {.base.} = method leaveCommunity*(self: AccessInterface) {.base.} =

View File

@ -213,9 +213,10 @@ QtObject:
name: string, name: string,
description: string, description: string,
emoji: string, emoji: string,
color: string,
categoryId: string categoryId: string
) {.slot.} = ) {.slot.} =
self.delegate.createCommunityChannel(name, description, emoji, categoryId) self.delegate.createCommunityChannel(name, description, emoji, color, categoryId)
proc editCommunityChannel*( proc editCommunityChannel*(
self: View, self: View,
@ -223,6 +224,7 @@ QtObject:
name: string, name: string,
description: string, description: string,
emoji: string, emoji: string,
color: string,
categoryId: string, categoryId: string,
position: int position: int
) {.slot.} = ) {.slot.} =
@ -231,6 +233,7 @@ QtObject:
name, name,
description, description,
emoji, emoji,
color,
categoryId, categoryId,
position position
) )

View File

@ -581,9 +581,11 @@ QtObject:
name: string, name: string,
description: string, description: string,
emoji: string, emoji: string,
color: string,
categoryId: string) = categoryId: string) =
try: try:
let response = status_go.createCommunityChannel(communityId, name, description, emoji, categoryId) let response = status_go.createCommunityChannel(communityId, name, description, emoji, color,
categoryId)
if not response.error.isNil: if not response.error.isNil:
let error = Json.decode($response.error, RpcError) let error = Json.decode($response.error, RpcError)
@ -611,6 +613,7 @@ QtObject:
name: string, name: string,
description: string, description: string,
emoji: string, emoji: string,
color: string,
categoryId: string, categoryId: string,
position: int) = position: int) =
try: try:
@ -620,6 +623,7 @@ QtObject:
name, name,
description, description,
emoji, emoji,
color,
categoryId, categoryId,
position) position)

View File

@ -85,6 +85,7 @@ proc createCommunityChannel*(
name: string, name: string,
description: string, description: string,
emoji: string, emoji: string,
color: string,
categoryId: string categoryId: string
): RpcResponse[JsonNode] {.raises: [Exception].} = ): RpcResponse[JsonNode] {.raises: [Exception].} =
result = callPrivateRPC("createCommunityChat".prefix, %*[ result = callPrivateRPC("createCommunityChat".prefix, %*[
@ -96,8 +97,8 @@ proc createCommunityChannel*(
"identity": { "identity": {
"display_name": name, "display_name": name,
"description": description, "description": description,
"emoji": emoji#, "emoji": emoji,
# "color": color# "color": color
}, },
"category_id": categoryId "category_id": categoryId
}]) }])
@ -108,6 +109,7 @@ proc editCommunityChannel*(
name: string, name: string,
description: string, description: string,
emoji: string, emoji: string,
color: string,
categoryId: string, categoryId: string,
position: int position: int
): RpcResponse[JsonNode] {.raises: [Exception].} = ): RpcResponse[JsonNode] {.raises: [Exception].} =
@ -121,8 +123,8 @@ proc editCommunityChannel*(
"identity": { "identity": {
"display_name": name, "display_name": name,
"description": description, "description": description,
"emoji": emoji#, "emoji": emoji,
# "color": color "color": color
}, },
"category_id": categoryId, "category_id": categoryId,
"position": position "position": position

View File

@ -20,15 +20,20 @@ StatusModal {
property string channelName: "" property string channelName: ""
property string channelDescription: "" property string channelDescription: ""
property string channelEmoji: "" property string channelEmoji: ""
property string channelColor: ""
property bool emojiPopupOpened: false property bool emojiPopupOpened: false
property var emojiPopup: null property var emojiPopup: null
readonly property string emojiRegexStr: 'alt="(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])"' readonly property string emojiRegexStr: 'alt="(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])"'
readonly property var communityColorValidator: Utils.Validate.NoEmpty
| Utils.Validate.TextHexColor
readonly property int maxChannelNameLength: 30 readonly property int maxChannelNameLength: 30
readonly property int maxChannelDescLength: 140 readonly property int maxChannelDescLength: 140
signal createCommunityChannel(string chName, string chDescription, string chEmoji, string chCategoryId) signal createCommunityChannel(string chName, string chDescription, string chEmoji,
signal editCommunityChannel(string chName, string chDescription, string chEmoji, string chCategoryId) string chColor, string chCategoryId)
signal editCommunityChannel(string chName, string chDescription, string chEmoji, string chColor,
string chCategoryId)
//% "New channel" //% "New channel"
header.title: qsTrId("create-channel-title") header.title: qsTrId("create-channel-title")
@ -61,7 +66,9 @@ StatusModal {
function isFormValid() { function isFormValid() {
return (scrollView.channelName.valid && return (scrollView.channelName.valid &&
scrollView.channelDescription.valid) scrollView.channelDescription.valid) &&
Utils.validateAndReturnError(scrollView.channelColorDialog.color.toString().toUpperCase(),
communityColorValidator) === ""
} }
contentItem: ScrollView { contentItem: ScrollView {
@ -72,6 +79,7 @@ StatusModal {
property alias channelName: nameInput property alias channelName: nameInput
property alias channelDescription: descriptionTextArea property alias channelDescription: descriptionTextArea
property alias channelColorDialog: colorDialog
property alias channelEmoji: emojiText property alias channelEmoji: emojiText
contentHeight: content.height contentHeight: content.height
@ -91,8 +99,9 @@ StatusModal {
StatusInput { StatusInput {
id: nameInput id: nameInput
label: qsTr("Channel name")
charLimit: popup.maxChannelNameLength charLimit: popup.maxChannelNameLength
input.placeholderText: qsTr("Channel name") input.placeholderText: qsTr("Name the channel")
input.onTextChanged: { input.onTextChanged: {
input.text = Utils.convertSpacesToDashesAndUpperToLowerCase(input.text); input.text = Utils.convertSpacesToDashesAndUpperToLowerCase(input.text);
input.cursorPosition = input.text.length input.cursorPosition = input.text.length
@ -104,9 +113,63 @@ StatusModal {
}] }]
} }
StatusModalDivider { Item {
topPadding: 8 id: spacer1
bottomPadding: 8 height: 16
width: parent.width
}
StatusBaseText {
text: qsTr("Channel colour")
font.pixelSize: 15
color: Theme.palette.directColor1
anchors.left: parent.left
anchors.leftMargin: 16
}
Item {
anchors.horizontalCenter: parent.horizontalCenter
height: colorSelectorButton.height + 16
width: parent.width - 32
StatusPickerButton {
id: colorSelectorButton
property string validationError: ""
bgColor: colorDialog.colorSelected ?
colorDialog.color : Theme.palette.baseColor2
// TODO adjust text color depending on the background color to make it readable
// contentColor: colorDialog.colorSelected ? Theme.palette.indirectColor1 : Theme.palette.baseColor1
text: colorDialog.colorSelected ?
colorDialog.color.toString().toUpperCase() :
//% "Pick a color"
qsTrId("pick-a-color")
onClicked: colorDialog.open();
onTextChanged: {
if (colorDialog.colorSelected) {
validationError = Utils.validateAndReturnError(text, communityColorValidator)
}
}
ColorDialog {
id: colorDialog
property bool colorSelected: popup.isEdit && popup.channelColor
color: popup.isEdit && popup.channelColor ? popup.channelColor :
Theme.palette.primaryColor1
onAccepted: colorSelected = true
}
}
StatusBaseText {
text: colorSelectorButton.validationError
visible: !!text
color: Theme.palette.dangerColor1
anchors.top: colorSelectorButton.bottom
anchors.topMargin: 4
anchors.right: colorSelectorButton.right
}
} }
StatusInput { StatusInput {
@ -245,14 +308,17 @@ StatusModal {
emoji = found[1] emoji = found[1]
} }
if (!isEdit) { if (!isEdit) {
//popup.contentItem.communityColor.color.toString().toUpperCase()
popup.createCommunityChannel(Utils.filterXSS(popup.contentItem.channelName.input.text), popup.createCommunityChannel(Utils.filterXSS(popup.contentItem.channelName.input.text),
Utils.filterXSS(popup.contentItem.channelDescription.input.text), Utils.filterXSS(popup.contentItem.channelDescription.input.text),
emoji, emoji,
popup.contentItem.channelColorDialog.color.toString().toUpperCase(),
popup.categoryId) popup.categoryId)
} else { } else {
popup.editCommunityChannel(Utils.filterXSS(popup.contentItem.channelName.input.text), popup.editCommunityChannel(Utils.filterXSS(popup.contentItem.channelName.input.text),
Utils.filterXSS(popup.contentItem.channelDescription.input.text), Utils.filterXSS(popup.contentItem.channelDescription.input.text),
emoji, emoji,
popup.contentItem.channelColorDialog.color.toString().toUpperCase(),
popup.categoryId) popup.categoryId)
} }

View File

@ -21,8 +21,7 @@ StatusModal {
property var store property var store
property var communitySectionModule property var communitySectionModule
property bool isEdit: false property bool isEdit: false
// Not Refactored Yet property QtObject community: null
property QtObject community: null //popup.store.chatsModelInst.communities.activeCommunity
property var onSave: () => {} property var onSave: () => {}
readonly property int maxCommunityNameLength: 30 readonly property int maxCommunityNameLength: 30
readonly property int maxCommunityDescLength: 140 readonly property int maxCommunityDescLength: 140

View File

@ -189,19 +189,20 @@ QtObject {
chatCommunitySectionModule.removeUserFromCommunity(pubKey); chatCommunitySectionModule.removeUserFromCommunity(pubKey);
} }
function createCommunityChannel(channelName, channelDescription, channelEmoji, categoryId) { function createCommunityChannel(channelName, channelDescription, channelEmoji, channelColor,
chatCommunitySectionModule.createCommunityChannel(channelName, channelDescription, channelEmoji, categoryId); categoryId) {
chatCommunitySectionModule.createCommunityChannel(channelName, channelDescription,
channelEmoji, channelColor, categoryId);
} }
function editCommunityChannel(chatId, newName, newDescription, newEmoji, newCategory, channelPosition) { function editCommunityChannel(chatId, newName, newDescription, newEmoji, newColor,
// TODO: pass the private value when private channels newCategory, channelPosition) {
// are implemented
//privateSwitch.checked)
chatCommunitySectionModule.editCommunityChannel( chatCommunitySectionModule.editCommunityChannel(
chatId, chatId,
newName, newName,
newDescription, newDescription,
newEmoji, newEmoji,
newColor,
newCategory, newCategory,
channelPosition channelPosition
) )

View File

@ -177,6 +177,7 @@ ColumnLayout {
chatName = chatContentModule.chatDetails.name chatName = chatContentModule.chatDetails.name
chatDescription = chatContentModule.chatDetails.description chatDescription = chatContentModule.chatDetails.description
chatEmoji = chatContentModule.chatDetails.emoji chatEmoji = chatContentModule.chatDetails.emoji
chatColor = chatContentModule.chatDetails.color
chatType = chatContentModule.chatDetails.type chatType = chatContentModule.chatDetails.type
chatMuted = chatContentModule.chatDetails.muted chatMuted = chatContentModule.chatDetails.muted
channelPosition = chatContentModule.chatDetails.position channelPosition = chatContentModule.chatDetails.position
@ -249,6 +250,7 @@ ColumnLayout {
newName, newName,
newDescription, newDescription,
newEmoji, newEmoji,
newColor,
newCategory, newCategory,
channelPosition // TODO change this to the signal once it is modifiable channelPosition // TODO change this to the signal once it is modifiable
) )

View File

@ -20,6 +20,7 @@ StatusPopupMenu {
property string chatName: "" property string chatName: ""
property string chatDescription: "" property string chatDescription: ""
property string chatEmoji: "" property string chatEmoji: ""
property string chatColor: ""
property string chatIcon: "" property string chatIcon: ""
property int chatType: -1 property int chatType: -1
property bool chatMuted: false property bool chatMuted: false
@ -39,8 +40,8 @@ StatusPopupMenu {
signal leaveChat(string chatId) signal leaveChat(string chatId)
signal leaveGroup(string chatId) signal leaveGroup(string chatId)
signal createCommunityChannel(string chatId, string newName, string newDescription, string newEmoji) signal createCommunityChannel(string chatId, string newName, string newDescription, string newEmoji, string newColor)
signal editCommunityChannel(string chatId, string newName, string newDescription, string newEmoji, string newCategory) signal editCommunityChannel(string chatId, string newName, string newDescription, string newEmoji, string newColor, string newCategory)
signal fetchMoreMessages(int timeFrame) signal fetchMoreMessages(int timeFrame)
signal addRemoveGroupMember() signal addRemoveGroupMember()
@ -190,6 +191,7 @@ StatusPopupMenu {
channelName: root.chatName, channelName: root.chatName,
channelDescription: root.chatDescription, channelDescription: root.chatDescription,
channelEmoji: root.chatEmoji, channelEmoji: root.chatEmoji,
channelColor: root.chatColor,
categoryId: root.chatCategoryId categoryId: root.chatCategoryId
}); });
} }
@ -202,10 +204,11 @@ StatusPopupMenu {
isEdit: true isEdit: true
emojiPopup: root.emojiPopup emojiPopup: root.emojiPopup
onCreateCommunityChannel: { onCreateCommunityChannel: {
root.createCommunityChannel(root.chatId, chName, chDescription, chEmoji); root.createCommunityChannel(root.chatId, chName, chDescription, chEmoji, chColor);
} }
onEditCommunityChannel: { onEditCommunityChannel: {
root.editCommunityChannel(root.chatId, chName, chDescription, chEmoji, chCategoryId); root.editCommunityChannel(root.chatId, chName, chDescription, chEmoji, chColor,
chCategoryId);
} }
onClosed: { onClosed: {
destroy() destroy()

View File

@ -277,6 +277,7 @@ Item {
chatDescription = obj.description chatDescription = obj.description
chatEmoji = obj.emoji chatEmoji = obj.emoji
chatColor = obj.color
chatType = obj.type chatType = obj.type
chatMuted = obj.muted chatMuted = obj.muted
channelPosition = obj.position channelPosition = obj.position
@ -332,6 +333,7 @@ Item {
newName, newName,
newDescription, newDescription,
newEmoji, newEmoji,
newColor,
newCategory, newCategory,
channelPosition // TODO change this to the signal once it is modifiable channelPosition // TODO change this to the signal once it is modifiable
) )
@ -405,8 +407,10 @@ Item {
CreateChannelPopup { CreateChannelPopup {
anchors.centerIn: parent anchors.centerIn: parent
emojiPopup: root.emojiPopup emojiPopup: root.emojiPopup
onCreateCommunityChannel: function (chName, chDescription, chEmoji, chCategoryId) { onCreateCommunityChannel: function (chName, chDescription, chEmoji, chColor,
root.store.createCommunityChannel(chName, chDescription, chEmoji, chCategoryId) chCategoryId) {
root.store.createCommunityChannel(chName, chDescription, chEmoji, chColor,
chCategoryId)
} }
onClosed: { onClosed: {
destroy() destroy()

View File

@ -184,6 +184,7 @@ Item {
chatName = obj.name chatName = obj.name
chatDescription = obj.description chatDescription = obj.description
chatEmoji = obj.emoji chatEmoji = obj.emoji
chatColor = obj.color
chatType = obj.type chatType = obj.type
chatMuted = obj.muted chatMuted = obj.muted
} }