From ef22fb348dab00df8b032a47c4bfc050f52349fe Mon Sep 17 00:00:00 2001 From: Pascal Precht Date: Tue, 18 Aug 2020 17:31:54 +0200 Subject: [PATCH] feat: allow users to mute and unmute channels Closes #152 --- src/app/chat/view.nim | 26 +++++- src/app/chat/views/channels_list.nim | 9 +- src/signals/messages.nim | 6 +- src/status/chat.nim | 8 +- src/status/chat/chat.nim | 1 + src/status/libstatus/chat.nim | 8 +- .../Chat/ContactsColumn/Channel.qml | 3 +- .../Chat/ContactsColumn/ChannelList.qml | 86 +++++++++++++++---- 8 files changed, 123 insertions(+), 24 deletions(-) diff --git a/src/app/chat/view.nim b/src/app/chat/view.nim index d0c0d83a1c..8216c03e33 100644 --- a/src/app/chat/view.nim +++ b/src/app/chat/view.nim @@ -248,7 +248,8 @@ QtObject: if self.channelOpenTime.getOrDefault(msg.chatId, high(int64)) < msg.timestamp.parseFloat.fromUnixFloat.toUnix: if msg.chatId != self.activeChannel.id: let channel = self.chats.getChannelById(msg.chatId) - self.messageNotificationPushed(msg.chatId, msg.text, msg.messageType, channel.chatType.int, msg.timestamp, msg.identicon, msg.alias) + if not channel.muted: + self.messageNotificationPushed(msg.chatId, msg.text, msg.messageType, channel.chatType.int, msg.timestamp, msg.identicon, msg.alias) else: self.newMessagePushed() @@ -416,3 +417,26 @@ QtObject: QtProperty[bool] isOnline: read = isConnected notify = onlineStatusChanged + + proc muteChannel*(self: ChatsView, channelIndex: int) {.slot.} = + if (self.chats.chats.len == 0): return + let selectedChannel = self.chats.getChannel(channelIndex) + if (selectedChannel == nil): return + self.status.chat.muteChat(selectedChannel.id) + selectedChannel.muted = true + self.chats.updateChat(selectedChannel, false) + + proc unmuteChannel*(self: ChatsView, channelIndex: int) {.slot.} = + if (self.chats.chats.len == 0): return + let selectedChannel = self.chats.getChannel(channelIndex) + if (selectedChannel == nil): return + self.status.chat.unmuteChat(selectedChannel.id) + selectedChannel.muted = false + self.chats.updateChat(selectedChannel, false) + + proc channelIsMuted*(self: ChatsView, channelIndex: int): bool {.slot.} = + if (self.chats.chats.len == 0): return false + let selectedChannel = self.chats.getChannel(channelIndex) + if (selectedChannel == nil): return false + result = selectedChannel.muted + diff --git a/src/app/chat/views/channels_list.nim b/src/app/chat/views/channels_list.nim index 0d435f2cd4..af8b69d746 100644 --- a/src/app/chat/views/channels_list.nim +++ b/src/app/chat/views/channels_list.nim @@ -15,6 +15,7 @@ type Color = UserRole + 7 HasMentions = UserRole + 8 ContentType = UserRole + 9 + Muted = UserRole + 10 QtObject: type @@ -66,6 +67,7 @@ QtObject: of ChannelsRoles.ChatType: result = newQVariant(chatItem.chatType.int) of ChannelsRoles.Color: result = newQVariant(chatItem.color) of ChannelsRoles.HasMentions: result = newQVariant(chatItem.hasMentions) + of ChannelsRoles.Muted: result = newQVariant(chatItem.muted.bool) method roleNames(self: ChannelsList): Table[int, string] = { @@ -77,7 +79,8 @@ QtObject: ChannelsRoles.ChatType.int: "chatType", ChannelsRoles.Color.int: "color", ChannelsRoles.HasMentions.int: "hasMentions", - ChannelsRoles.ContentType.int: "contentType" + ChannelsRoles.ContentType.int: "contentType", + ChannelsRoles.Muted.int: "muted" }.toTable proc addChatItemToList*(self: ChannelsList, channel: Chat): int = @@ -137,7 +140,7 @@ QtObject: else: self.chats[0] = channel - self.dataChanged(topLeft, bottomRight, @[ChannelsRoles.Name.int, ChannelsRoles.ContentType.int, ChannelsRoles.LastMessage.int, ChannelsRoles.Timestamp.int, ChannelsRoles.UnreadMessages.int, ChannelsRoles.Identicon.int, ChannelsRoles.ChatType.int, ChannelsRoles.Color.int, ChannelsRoles.HasMentions.int]) + self.dataChanged(topLeft, bottomRight, @[ChannelsRoles.Name.int, ChannelsRoles.ContentType.int, ChannelsRoles.LastMessage.int, ChannelsRoles.Timestamp.int, ChannelsRoles.UnreadMessages.int, ChannelsRoles.Identicon.int, ChannelsRoles.ChatType.int, ChannelsRoles.Color.int, ChannelsRoles.HasMentions.int, ChannelsRoles.Muted.int]) proc clearUnreadMessagesCount*(self: ChannelsList, channel: var Chat) = let idx = self.chats.findIndexById(channel.id) @@ -149,7 +152,7 @@ QtObject: channel.hasMentions = false self.chats[idx] = channel - self.dataChanged(topLeft, bottomRight, @[ChannelsRoles.Name.int, ChannelsRoles.ContentType.int, ChannelsRoles.LastMessage.int, ChannelsRoles.Timestamp.int, ChannelsRoles.UnreadMessages.int, ChannelsRoles.Identicon.int, ChannelsRoles.ChatType.int, ChannelsRoles.Color.int, ChannelsRoles.HasMentions.int]) + self.dataChanged(topLeft, bottomRight, @[ChannelsRoles.Name.int, ChannelsRoles.ContentType.int, ChannelsRoles.LastMessage.int, ChannelsRoles.Timestamp.int, ChannelsRoles.UnreadMessages.int, ChannelsRoles.Identicon.int, ChannelsRoles.ChatType.int, ChannelsRoles.Color.int, ChannelsRoles.HasMentions.int, ChannelsRoles.Muted.int]) proc renderInline(self: ChannelsList, elem: TextItem): string = case elem.textType: diff --git a/src/signals/messages.nim b/src/signals/messages.nim index 8872111fc3..f245c369a5 100644 --- a/src/signals/messages.nim +++ b/src/signals/messages.nim @@ -107,9 +107,13 @@ proc toChat*(jsonChat: JsonNode): Chat = lastClockValue: jsonChat{"lastClockValue"}.getBiggestInt, deletedAtClockValue: jsonChat{"deletedAtClockValue"}.getBiggestInt, unviewedMessagesCount: jsonChat{"unviewedMessagesCount"}.getInt, - hasMentions: false + hasMentions: false, + muted: false ) + if jsonChat.hasKey("muted") and jsonChat["muted"].kind != JNull: + result.muted = jsonChat["muted"].getBool + if jsonChat["lastMessage"].kind != JNull: result.lastMessage = jsonChat{"lastMessage"}.toMessage diff --git a/src/status/chat.nim b/src/status/chat.nim index 8289bdb00e..2497a8c6f7 100644 --- a/src/status/chat.nim +++ b/src/status/chat.nim @@ -304,4 +304,10 @@ proc makeAdmin*(self: ChatModel, chatId: string, pubKey: string) = self.emitUpdate(response) proc resendMessage*(self: ChatModel, messageId: string) = - discard status_chat.reSendChatMessage(messageId) \ No newline at end of file + discard status_chat.reSendChatMessage(messageId) + +proc muteChat*(self: ChatModel, chatId: string) = + discard status_chat.muteChat(chatId) + +proc unmuteChat*(self: ChatModel, chatId: string) = + discard status_chat.unmuteChat(chatId) diff --git a/src/status/chat/chat.nim b/src/status/chat/chat.nim index e87cd294ad..4af6ee44a4 100644 --- a/src/status/chat/chat.nim +++ b/src/status/chat/chat.nim @@ -66,6 +66,7 @@ type Chat* = ref object members*: seq[ChatMember] membershipUpdateEvents*: seq[ChatMembershipEvent] hasMentions*: bool + muted*: bool proc `$`*(self: Chat): string = result = fmt"Chat(id:{self.id}, name:{self.name}, active:{self.isActive}, type:{self.chatType})" diff --git a/src/status/libstatus/chat.nim b/src/status/libstatus/chat.nim index 728153d9fa..457b439244 100644 --- a/src/status/libstatus/chat.nim +++ b/src/status/libstatus/chat.nim @@ -145,4 +145,10 @@ proc updateOutgoingMessageStatus*(messageId: string, status: string): string = # TODO: handle errors proc reSendChatMessage*(messageId: string): string = - result = callPrivateRPC("reSendChatMessage".prefix, %*[messageId]) \ No newline at end of file + result = callPrivateRPC("reSendChatMessage".prefix, %*[messageId]) + +proc muteChat*(chatId: string): string = + result = callPrivateRPC("muteChat".prefix, %*[chatId]) + +proc unmuteChat*(chatId: string): string = + result = callPrivateRPC("unmuteChat".prefix, %*[chatId]) diff --git a/ui/app/AppLayouts/Chat/ContactsColumn/Channel.qml b/ui/app/AppLayouts/Chat/ContactsColumn/Channel.qml index 7c13aaf2ae..4587720658 100644 --- a/ui/app/AppLayouts/Chat/ContactsColumn/Channel.qml +++ b/ui/app/AppLayouts/Chat/ContactsColumn/Channel.qml @@ -15,6 +15,7 @@ Rectangle { property string searchStr: "" property bool isCompact: appSettings.compactMode property int contentType: 1 + property bool muted: false id: wrapper color: ListView.isCurrentItem ? Style.current.secondaryBackground : Style.current.transparent @@ -33,7 +34,7 @@ Rectangle { anchors.fill: parent onClicked: { if (mouse.button & Qt.RightButton) { - channelContextMenu.openMenu(index) + channelContextMenu.openMenu(index, muted) return; } chatsModel.setActiveChannelByIndex(index) diff --git a/ui/app/AppLayouts/Chat/ContactsColumn/ChannelList.qml b/ui/app/AppLayouts/Chat/ContactsColumn/ChannelList.qml index c6e3877fd5..36efa6fb6f 100644 --- a/ui/app/AppLayouts/Chat/ContactsColumn/ChannelList.qml +++ b/ui/app/AppLayouts/Chat/ContactsColumn/ChannelList.qml @@ -25,6 +25,7 @@ ScrollView { model: chatsModel.chats delegate: Channel { name: model.name + muted: model.muted lastMessage: model.lastMessage timestamp: model.timestamp chatType: model.chatType @@ -52,15 +53,16 @@ ScrollView { PopupMenu { property int channelIndex + property bool channelMuted id: channelContextMenu width: 175 subMenuIcons: [ - { - source: Qt.resolvedUrl("../../../img/bell.svg"), - width: 16, - height: 16 - }, + /* { */ + /* source: Qt.resolvedUrl("../../../img/bell.svg"), */ + /* width: 16, */ + /* height: 16 */ + /* }, */ { source: Qt.resolvedUrl("../../../img/fetch.svg"), width: 16, @@ -68,8 +70,9 @@ ScrollView { } ] - function openMenu(channelIndex) { + function openMenu(channelIndex, muted) { channelContextMenu.channelIndex = channelIndex + channelContextMenu.channelMuted = muted channelContextMenu.popup() } @@ -83,17 +86,68 @@ ScrollView { Separator {} - PopupMenu { - hasArrow: false - title: qsTr("Mute Chat") - - // TODO implement mute chat in Model and call it here - Action { text: qsTr("15 minutes"); icon.width: 0; } - Action { text: qsTr("1 hour"); icon.width: 0; } - Action { text: qsTr("8 hours"); icon.width: 0; } - Action { text: qsTr("24 hours"); icon.width: 0; } - Action { text: qsTr("Until I turn it back on"); icon.width: 0; } + Action { + text: channelContextMenu.channelMuted ? + qsTr("Unmute chat") : + qsTr("Mute chat") + icon.source: "../../../img/bell.svg" + icon.width: 16 + icon.height: 16 + onTriggered: { + if (chatsModel.channelIsMuted(channelContextMenu.channelIndex)) { + chatsModel.unmuteChannel(channelContextMenu.channelIndex) + return + } + chatsModel.muteChannel(channelContextMenu.channelIndex) + } } + + /* PopupMenu { */ + /* hasArrow: false */ + /* title: qstr("Mute chat") */ + + /* // TODO implement mute chat in Model and call it here */ + /* Action { */ + /* text: qsTr("15 minutes"); */ + /* icon.width: 0; */ + /* onTriggered: { */ + /* chatsModel.muteChannel(channelContextMenu.channelIndex, Constants.muteChat15Minutes) */ + /* } */ + /* } */ + /* Action { */ + /* text: qsTr("1 hour"); */ + /* icon.width: 0; */ + /* onTriggered: { */ + /* chatsModel.muteChannel(channelContextMenu.channelIndex, Constants.muteChatOneHour) */ + /* } */ + /* } */ + /* Action { */ + /* text: qsTr("8 hours"); */ + /* icon.width: 0; */ + /* onTriggered: { */ + /* chatsModel.muteChannel(channelContextMenu.channelIndex, Constants.muteChatEightHours) */ + /* } */ + /* } */ + /* Action { */ + /* text: qsTr("24 hours"); */ + /* icon.width: 0; */ + /* onTriggered: { */ + /* chatsModel.muteChannel(channelContextMenu.channelIndex, Constants.muteChat24Hours) */ + /* } */ + /* } */ + /* Action { */ + /* text: qsTr("Until I turn it back on"); */ + /* icon.width: 0; */ + /* onTriggered: { */ + /* console.log(appSettings.mutedChannels) */ + /* appSettings.mutedChannels.push({ */ + /* name: "Foo" */ + /* }) */ + /* console.log(appSettings.mutedChannels) */ + /* //chatsModel.muteChannel(channelContextMenu.channelIndex, Constants.muteChatUntilUnmuted) */ + /* } */ + /* } */ + /* } */ Action { text: qsTr("Mark as Read") icon.source: "../../../img/check-circle.svg"