fix(activity_center): Mark as read does not clear @ symbol in chat

Mark all mention notifications as read is fixed. Also mark as read one by one notification removes "@" from the appropriate channel along with the marking as read last mention notification for that channel. hasMention field which was bool is switched with mentionsCount field which is int, so we have evidention how many mentions were for each channel.

Fixes: #2788
This commit is contained in:
Sale Djenic 2021-07-01 21:44:51 +02:00 committed by Iuri Matias
parent 20b3f29422
commit 7fbccec227
12 changed files with 219 additions and 57 deletions

View File

@ -18,7 +18,9 @@ proc handleChatEvents(self: ChatController) =
self.view.pushPinnedMessages(MsgsLoadedArgs(e).messages)
self.status.events.on("activityCenterNotificationsLoaded") do(e:Args):
self.view.pushActivityCenterNotifications(ActivityCenterNotificationsArgs(e).activityCenterNotifications)
let notifications = ActivityCenterNotificationsArgs(e).activityCenterNotifications
self.view.pushActivityCenterNotifications(notifications)
self.view.communities.updateNotifications(notifications)
self.status.events.on("contactUpdate") do(e: Args):
var evArgs = ContactUpdateArgs(e)
@ -56,6 +58,7 @@ proc handleChatEvents(self: ChatController) =
self.view.addPinnedMessages(evArgs.pinnedMessages)
if (evArgs.activityCenterNotifications.len > 0):
self.view.addActivityCenterNotification(evArgs.activityCenterNotifications)
self.view.communities.updateNotifications(evArgs.activityCenterNotifications)
self.status.events.on("channelUpdate") do(e: Args):
var evArgs = ChatUpdateArgs(e)
@ -139,6 +142,12 @@ proc handleChatEvents(self: ChatController) =
else:
self.view.stickers.resetBuyAttempt(tx.data.parseInt)
self.status.events.on("markNotificationsAsRead") do(e:Args):
let markAsReadProps = MarkAsReadNotificationProperties(e)
#Notifying communities about this change.
self.view.communities.markNotificationsAsRead(markAsReadProps)
proc handleMailserverEvents(self: ChatController) =
let mailserverWorker = self.status.tasks.marathon[MailserverWorker().name]
# TODO: test mailserver topics when joining chat

View File

@ -128,35 +128,36 @@ QtObject:
let topLeft = self.createIndex(0, 0, nil)
let bottomRight = self.createIndex(self.activityCenterNotifications.len - 1, 0, nil)
self.dataChanged(topLeft, bottomRight, @[NotifRoles.Read.int])
proc reduceUnreadCount(self: ActivityNotificationList, numberNotifs: int) =
self.nbUnreadNotifications = self.nbUnreadNotifications - numberNotifs
if (self.nbUnreadNotifications < 0):
self.nbUnreadNotifications = 0
self.unreadCountChanged()
proc markActivityCenterNotificationsRead(self: ActivityNotificationList, idsJson: string): string {.slot.} =
let ids = map(parseJson(idsJson).getElems(), proc(x:JsonNode):string = x.getStr())
proc markActivityCenterNotificationRead(self: ActivityNotificationList, notificationId: string,
communityId: string, channelId: string, nType: int): void {.slot.} =
let error = self.status.chat.markActivityCenterNotificationsRead(ids)
let notificationType = ActivityCenterNotificationType(nType)
let markAsReadProps = MarkAsReadNotificationProperties(communityId: communityId,
channelId: channelId, notificationTypes: @[notificationType])
let error = self.status.chat.markActivityCenterNotificationRead(notificationId, markAsReadProps)
if (error != ""):
return error
self.reduceUnreadCount(ids.len)
return
self.nbUnreadNotifications = self.nbUnreadNotifications - 1
if (self.nbUnreadNotifications < 0):
self.nbUnreadNotifications = 0
self.unreadCountChanged()
var i = 0
for activityCenterNotification in self.activityCenterNotifications:
for id in ids:
if (activityCenterNotification.id == id):
activityCenterNotification.read = true
let topLeft = self.createIndex(i, 0, nil)
let bottomRight = self.createIndex(i, 0, nil)
self.dataChanged(topLeft, bottomRight, @[NotifRoles.Read.int])
break
i = i + 1
proc markActivityCenterNotificationRead(self: ActivityNotificationList, id: string): string {.slot.} =
self.markActivityCenterNotificationsRead(fmt"[""{id}""]")
for acnViewItem in self.activityCenterNotifications:
if (acnViewItem.id == notificationId):
acnViewItem.read = true
let index = self.createIndex(i, 0, nil)
self.dataChanged(index, index, @[NotifRoles.Read.int])
i.inc
proc removeNotifications(self: ActivityNotificationList, ids: seq[string]) =
var i = 0

View File

@ -91,10 +91,11 @@ QtObject:
discard self.status.chat.markAllChannelMessagesRead(selectedChannel.id)
proc clearUnreadIfNeeded*(self: ChannelView, channel: var Chat) =
if (not channel.isNil and (channel.unviewedMessagesCount > 0 or channel.hasMentions)):
if (not channel.isNil and (channel.unviewedMessagesCount > 0 or channel.mentionsCount > 0)):
var response = self.status.chat.markAllChannelMessagesRead(channel.id)
if not response.hasKey("error"):
self.chats.clearUnreadMessagesCount(channel)
self.chats.clearUnreadMessages(channel.id)
self.chats.clearAllMentionsFromChannelWithId(channel.id)
proc userNameOrAlias(self: ChannelView, pubKey: string): string =
if self.status.chat.contacts.hasKey(pubKey):

View File

@ -14,7 +14,7 @@ type
Identicon = UserRole + 5
ChatType = UserRole + 6
Color = UserRole + 7
HasMentions = UserRole + 8
MentionsCount = UserRole + 8
ContentType = UserRole + 9
Muted = UserRole + 10
Id = UserRole + 11
@ -74,7 +74,7 @@ QtObject:
of ChannelsRoles.Identicon: result = newQVariant(chatItem.identicon)
of ChannelsRoles.ChatType: result = newQVariant(chatItem.chatType.int)
of ChannelsRoles.Color: result = newQVariant(chatItem.color)
of ChannelsRoles.HasMentions: result = newQVariant(chatItem.hasMentions)
of ChannelsRoles.MentionsCount: result = newQVariant(chatItem.mentionsCount.int)
of ChannelsRoles.Muted: result = newQVariant(chatItem.muted.bool)
of ChannelsRoles.Id: result = newQVariant($chatItem.id)
of ChannelsRoles.CategoryId: result = newQVariant(chatItem.categoryId)
@ -89,7 +89,7 @@ QtObject:
ChannelsRoles.Identicon.int: "identicon",
ChannelsRoles.ChatType.int: "chatType",
ChannelsRoles.Color.int: "color",
ChannelsRoles.HasMentions.int: "hasMentions",
ChannelsRoles.MentionsCount.int: "mentionsCount",
ChannelsRoles.ContentType.int: "contentType",
ChannelsRoles.Muted.int: "muted",
ChannelsRoles.Id.int: "id",
@ -160,19 +160,53 @@ QtObject:
self.chats[idx] = channel
self.dataChanged(topLeft, bottomRight, @[ChannelsRoles.Name.int, ChannelsRoles.Description.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])
self.dataChanged(topLeft, bottomRight, @[ChannelsRoles.Name.int, ChannelsRoles.Description.int, ChannelsRoles.ContentType.int, ChannelsRoles.LastMessage.int, ChannelsRoles.Timestamp.int, ChannelsRoles.UnreadMessages.int, ChannelsRoles.Identicon.int, ChannelsRoles.ChatType.int, ChannelsRoles.Color.int, ChannelsRoles.MentionsCount.int, ChannelsRoles.Muted.int])
proc clearUnreadMessagesCount*(self: ChannelsList, channel: var Chat) =
let idx = self.chats.findIndexById(channel.id)
if idx == -1: return
proc clearUnreadMessages*(self: ChannelsList, channelId: string) =
let idx = self.chats.findIndexById(channelId)
if idx == -1:
return
let topLeft = self.createIndex(0, 0, nil)
let bottomRight = self.createIndex(self.chats.len, 0, nil)
channel.unviewedMessagesCount = 0
channel.hasMentions = false
self.chats[idx] = channel
let index = self.createIndex(idx, 0, nil)
self.chats[idx].unviewedMessagesCount = 0
self.dataChanged(topLeft, bottomRight, @[ChannelsRoles.Name.int, ChannelsRoles.Description.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])
self.dataChanged(index, index, @[ChannelsRoles.UnreadMessages.int])
proc clearAllMentionsFromChannelWithId*(self: ChannelsList, channelId: string) =
let idx = self.chats.findIndexById(channelId)
if idx == -1:
return
let index = self.createIndex(idx, 0, nil)
self.chats[idx].mentionsCount = 0
self.dataChanged(index, index, @[ChannelsRoles.MentionsCount.int])
proc clearAllMentionsFromAllChannels*(self: ChannelsList) =
for c in self.chats:
self.clearAllMentionsFromChannelWithId(c.id)
proc decrementMentions*(self: ChannelsList, channelId: string) =
let idx = self.chats.findIndexById(channelId)
if idx == -1:
return
let index = self.createIndex(idx, 0, nil)
self.chats[idx].mentionsCount.dec
self.dataChanged(index, index, @[ChannelsRoles.MentionsCount.int])
proc incrementMentions*(self: ChannelsList, channelId: string) : bool =
result = false
let idx = self.chats.findIndexById(channelId)
if idx == -1:
return
let index = self.createIndex(idx, 0, nil)
self.chats[idx].mentionsCount.inc
result = true
self.dataChanged(index, index, @[ChannelsRoles.MentionsCount.int])
proc renderInline(self: ChannelsList, elem: TextItem): string =
case elem.textType:

View File

@ -138,10 +138,10 @@ QtObject:
read = isTimelineChat
proc hasMentions*(self: ChatItemView): bool {.slot.} = result = ?.self.chatItem.hasMentions
proc mentionsCount*(self: ChatItemView): int {.slot.} = result = ?.self.chatItem.mentionsCount
QtProperty[bool] hasMentions:
read = hasMentions
QtProperty[int] mentionsCount:
read = mentionsCount
proc canPost*(self: ChatItemView): bool {.slot.} = result = ?.self.chatItem.canPost

View File

@ -1,6 +1,7 @@
import NimQml, json, sequtils, chronicles, strutils, strformat
import ../../../status/status
import ../../../status/chat/chat
import ./channels_list
import ./community_list
import ./community_item
import ./community_membership_request_list
@ -57,6 +58,7 @@ QtObject:
# canPost and categoryId are not available in the newChat so we need to check what we had before
newChat.canPost = community.chats[i].canPost
newChat.categoryId = community.chats[i].categoryId
newChat.mentionsCount = community.chats[i].mentionsCount
community.chats[i] = newChat
found = true
i = i + 1
@ -428,13 +430,66 @@ QtObject:
if community.muted:
chat.muted = true
return chat
proc setCommunityMuted*(self: CommunitiesView, communityId: string, muted: bool) {.slot.} =
self.status.chat.setCommunityMuted(communityId, muted)
if (communityId == self.activeCommunity.communityItem.id):
self.activeCommunity.setMuted(muted)
var community = self.joinedCommunityList.getCommunityById(communityId)
community.muted = muted
self.joinedCommunityList.replaceCommunity(community)
proc markNotificationsAsRead*(self: CommunitiesView, markAsReadProps: MarkAsReadNotificationProperties) =
if(markAsReadProps.communityId.len == 0 and markAsReadProps.channelId.len == 0):
# Remove all notifications from all communities and their channels for set types.
for t in markAsReadProps.notificationTypes:
case t:
of ActivityCenterNotificationType.NewOneToOne:
debug "Clear all one to one notifications"
of ActivityCenterNotificationType.NewPrivateGroupChat:
debug "Clear all private group chat notifications"
of ActivityCenterNotificationType.Mention:
self.activeCommunity.chats.clearAllMentionsFromAllChannels()
for c in self.joinedCommunityList.communities:
# We don't need to update channels from the currently active community.
let clearChannels = c.id != self.activeCommunity.communityItem.id
self.joinedCommunityList.clearAllMentions(c.id, clearChannels)
of ActivityCenterNotificationType.Reply:
debug "Clear all reply notifications"
else:
debug "Unknown notifications"
else:
# Remove single notification from the channel (channelId) of community (communityId) for set types.
for t in markAsReadProps.notificationTypes:
case t:
of ActivityCenterNotificationType.NewOneToOne:
debug "Clear one to one notification"
of ActivityCenterNotificationType.NewPrivateGroupChat:
debug "Clear private group chat notification"
of ActivityCenterNotificationType.Mention:
if (markAsReadProps.communityId == self.activeCommunity.communityItem.id):
self.activeCommunity.chats.decrementMentions(markAsReadProps.channelId)
else:
for c in self.joinedCommunityList.communities:
# We don't need to update channels from the currently active community.
if (c.id != self.activeCommunity.communityItem.id):
self.joinedCommunityList.decrementMentions(c.id, markAsReadProps.channelId)
of ActivityCenterNotificationType.Reply:
debug "Clear reply notification"
else:
debug "Unknown notification"
proc updateNotifications*(self: CommunitiesView, notifications: seq[ActivityCenterNotification]) =
for n in notifications:
if (not n.read):
case n.notificationType:
of ActivityCenterNotificationType.NewOneToOne:
debug "Update one to one notification"
of ActivityCenterNotificationType.NewPrivateGroupChat:
debug "Update private group chat notification"
of ActivityCenterNotificationType.Mention:
let incremented = self.activeCommunity.chats.incrementMentions(n.chatId)
if (not incremented):
self.joinedCommunityList.incrementMentions(n.chatId)
of ActivityCenterNotificationType.Reply:
debug "Update reply notification"
else:
debug "Unknown notification"

View File

@ -208,3 +208,48 @@ QtObject:
community.categories.delete(idx)
let index = self.communities.findIndexById(communityId)
self.communities[index] = community
proc clearUnreadMessages*(self: CommunityList, communityId: string, clearFromChannels : bool) =
let idx = self.communities.findIndexById(communityId)
if (idx == -1):
return
if (clearFromChannels):
# Clear unread messages for each channel in community.
for c in self.communities[idx].chats:
c.unviewedMessagesCount = 0
let index = self.createIndex(idx, 0, nil)
self.communities[idx].unviewedMessagesCount = 0
self.dataChanged(index, index, @[CommunityRoles.UnviewedMessagesCount.int])
proc clearAllMentions*(self: CommunityList, communityId: string, clearFromChannels : bool) =
let idx = self.communities.findIndexById(communityId)
if (idx == -1):
return
if (clearFromChannels):
# Clear mentions for each chat in community. No need to emit dataChanged
# as mentins are not exposed to qml using roles from this model.
for c in self.communities[idx].chats:
c.mentionsCount = 0
# If we decide in one moment to expose mention role we should do that here.
proc decrementMentions*(self: CommunityList, communityId: string, channelId : string) =
let comIndex = self.communities.findIndexById(communityId)
if (comIndex == -1):
return
let chatIndex = self.communities[comIndex].chats.findIndexById(channelId)
if (chatIndex == -1):
return
self.communities[comIndex].chats[chatIndex].mentionsCount.dec
proc incrementMentions*(self: CommunityList, channelId : string) =
for c in self.communities:
let chatIndex = c.chats.findIndexById(channelId)
if (chatIndex != -1):
c.chats[chatIndex].mentionsCount.inc

View File

@ -67,6 +67,11 @@ type
id*: string
channel*: string
MarkAsReadNotificationProperties* = ref object of Args
communityId*: string
channelId*: string
notificationTypes*: seq[ActivityCenterNotificationType]
include chat/utils
proc newChatModel*(events: EventEmitter): ChatModel =
@ -534,13 +539,25 @@ proc markAllActivityCenterNotificationsRead*(self: ChatModel): string =
except Exception as e:
error "Error marking all as read", msg = e.msg
result = e.msg
# This proc should accept ActivityCenterNotificationType in order to clear all notifications
# per type, that's why we have this part here. If we add all types to notificationsType that
# means that we need to clear all notifications for all types.
var types : seq[ActivityCenterNotificationType]
for t in ActivityCenterNotificationType:
types.add(t)
proc markActivityCenterNotificationsRead*(self: ChatModel, ids: seq[string]): string =
self.events.emit("markNotificationsAsRead", MarkAsReadNotificationProperties(notificationTypes: types))
proc markActivityCenterNotificationRead*(self: ChatModel, notificationId: string,
markAsReadProps: MarkAsReadNotificationProperties): string =
try:
status_chat.markActivityCenterNotificationsRead(ids)
status_chat.markActivityCenterNotificationsRead(@[notificationId])
except Exception as e:
error "Error marking as read", msg = e.msg
result = e.msg
self.events.emit("markNotificationsAsRead", markAsReadProps)
proc acceptActivityCenterNotifications*(self: ChatModel, ids: seq[string]): string =
try:

View File

@ -83,7 +83,7 @@ type Chat* = ref object
lastMessage*: Message
members*: seq[ChatMember]
membershipUpdateEvents*: seq[ChatMembershipEvent]
hasMentions*: bool
mentionsCount*: int
muted*: bool
canPost*: bool
ensName*: string

View File

@ -49,7 +49,7 @@ proc fromEvent*(event: JsonNode): Signal =
for jsonChat in event["event"]["chats"]:
var chat = jsonChat.toChat
if chatsWithMentions.contains(chat.id):
chat.hasMentions = true
chat.mentionsCount.inc
signal.chats.add(chat)
if event["event"]{"installations"} != nil:
@ -135,7 +135,7 @@ proc newChat*(id: string, chatType: ChatType): Chat =
lastClockValue: 0,
deletedAtClockValue: 0,
unviewedMessagesCount: 0,
hasMentions: false,
mentionsCount: 0,
members: @[]
)
@ -165,7 +165,7 @@ proc toChat*(jsonChat: JsonNode): Chat =
lastClockValue: jsonChat{"lastClockValue"}.getBiggestInt,
deletedAtClockValue: jsonChat{"deletedAtClockValue"}.getBiggestInt,
unviewedMessagesCount: jsonChat{"unviewedMessagesCount"}.getInt,
hasMentions: false,
mentionsCount: 0,
muted: false,
ensName: "",
joined: 0,

View File

@ -13,7 +13,7 @@ Item {
property string timestamp: "1605212622434"
property string unviewedMessagesCount: "2"
property string identicon
property bool hasMentions: false
property int mentionsCount: 0
property int chatType: Constants.chatTypePublic
property int realChatType: {
if (chatType === Constants.chatTypeCommunity) {
@ -163,10 +163,10 @@ Item {
anchors.bottomMargin: !isCompact ? Style.current.smallPadding : 0
anchors.verticalCenter: !isCompact ? undefined : parent.verticalCenter
color: Style.current.blue
visible: (unviewedMessagesCount > 0) || wrapper.hasMentions
visible: (unviewedMessagesCount > 0) || wrapper.mentionsCount > 0
StyledText {
id: contactNumberChats
text: wrapper.hasMentions ? '@' : (wrapper.unviewedMessagesCount < 100 ? wrapper.unviewedMessagesCount : "99+")
text: wrapper.mentionsCount > 0 ? '@' : (wrapper.unviewedMessagesCount < 100 ? wrapper.unviewedMessagesCount : "99+")
font.pixelSize: 12
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter

View File

@ -37,7 +37,7 @@ Item {
chatType: model.chatType
identicon: model.identicon
unviewedMessagesCount: model.unviewedMessagesCount
hasMentions: model.hasMentions
mentionsCount: model.mentionsCount
contentType: model.contentType
searchStr: channelListContent.searchStr
categoryId: model.categoryId