From e822c37716fdf518dcef09332cb8af3315d25ef6 Mon Sep 17 00:00:00 2001 From: Patryk Osmaczko Date: Tue, 11 Apr 2023 22:28:24 +0200 Subject: [PATCH] feat(chat): implement marking specific messages as seen iterates: #9069 --- .../chat_section/chat_content/controller.nim | 3 ++ .../chat_content/io_interface.nim | 3 ++ .../chat_content/messages/controller.nim | 5 ++- .../chat_content/messages/io_interface.nim | 3 ++ .../chat_content/messages/module.nim | 3 ++ .../main/chat_section/chat_content/module.nim | 3 ++ .../main/chat_section/chat_content/view.nim | 3 ++ .../modules/main/chat_section/controller.nim | 8 ++--- .../main/chat_section/io_interface.nim | 2 +- src/app/modules/main/chat_section/module.nim | 7 ++-- .../modules/shared_models/message_model.nim | 15 ++++++++ src/app_service/service/chat/service.nim | 12 +++++++ .../service/message/async_tasks.nim | 11 ++++-- src/app_service/service/message/service.nim | 20 +++++++++-- test/nim/message_model_test.nim | 35 +++++++++++++++++++ 15 files changed, 119 insertions(+), 14 deletions(-) diff --git a/src/app/modules/main/chat_section/chat_content/controller.nim b/src/app/modules/main/chat_section/chat_content/controller.nim index 79ec20be9b..352fc87849 100644 --- a/src/app/modules/main/chat_section/chat_content/controller.nim +++ b/src/app/modules/main/chat_section/chat_content/controller.nim @@ -224,6 +224,9 @@ proc unblockChat*(self: Controller) = proc markAllMessagesRead*(self: Controller) = self.messageService.markAllMessagesRead(self.chatId) +proc markMessageRead*(self: Controller, msgID: string) = + self.messageService.markCertainMessagesRead(self.chatId, @[msgID]) + proc clearChatHistory*(self: Controller) = self.chatService.clearChatHistory(self.chatId) diff --git a/src/app/modules/main/chat_section/chat_content/io_interface.nim b/src/app/modules/main/chat_section/chat_content/io_interface.nim index 76f7419e80..0b6cb7b929 100644 --- a/src/app/modules/main/chat_section/chat_content/io_interface.nim +++ b/src/app/modules/main/chat_section/chat_content/io_interface.nim @@ -101,6 +101,9 @@ method unblockChat*(self: AccessInterface) {.base.} = method markAllMessagesRead*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") +method markMessageRead*(self: AccessInterface, msgID: string) {.base.} = + raise newException(ValueError, "No implementation available") + method clearChatHistory*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/chat_section/chat_content/messages/controller.nim b/src/app/modules/main/chat_section/chat_content/messages/controller.nim index 38505bda00..84e17ca266 100644 --- a/src/app/modules/main/chat_section/chat_content/messages/controller.nim +++ b/src/app/modules/main/chat_section/chat_content/messages/controller.nim @@ -132,7 +132,10 @@ proc init*(self: Controller) = let args = MessagesMarkedAsReadArgs(e) if(self.chatId != args.chatId): return - self.delegate.markAllMessagesRead() + if(args.allMessagesMarked): + self.delegate.markAllMessagesRead() + else: + self.delegate.markMessagesAsRead(args.messagesIds) self.events.on(SIGNAL_CONTACT_NICKNAME_CHANGED) do(e: Args): var args = ContactArgs(e) diff --git a/src/app/modules/main/chat_section/chat_content/messages/io_interface.nim b/src/app/modules/main/chat_section/chat_content/messages/io_interface.nim index bcad3266e4..56ff9bb4a4 100644 --- a/src/app/modules/main/chat_section/chat_content/messages/io_interface.nim +++ b/src/app/modules/main/chat_section/chat_content/messages/io_interface.nim @@ -164,6 +164,9 @@ method resetAndScrollToNewMessagesMarker*(self: AccessInterface) = method markAllMessagesRead*(self: AccessInterface) = raise newException(ValueError, "No implementation available") +method markMessagesAsRead*(self: AccessInterface, messages: seq[string]) = + raise newException(ValueError, "No implementation available") + method updateCommunityDetails*(self: AccessInterface, community: CommunityDto) = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/main/chat_section/chat_content/messages/module.nim b/src/app/modules/main/chat_section/chat_content/messages/module.nim index 931a0ff346..b689bf1145 100644 --- a/src/app/modules/main/chat_section/chat_content/messages/module.nim +++ b/src/app/modules/main/chat_section/chat_content/messages/module.nim @@ -712,6 +712,9 @@ method removeNewMessagesMarker*(self: Module) = method markAllMessagesRead*(self: Module) = self.view.model().markAllAsSeen() +method markMessagesAsRead*(self: Module, messages: seq[string]) = + self.view.model().markAsSeen(messages) + method updateCommunityDetails*(self: Module, community: CommunityDto) = self.view.setAmIChatAdmin(community.admin) self.view.setIsPinMessageAllowedForMembers(community.adminSettings.pinMessageAllMembersEnabled) diff --git a/src/app/modules/main/chat_section/chat_content/module.nim b/src/app/modules/main/chat_section/chat_content/module.nim index a97503667c..9ec5bf1ec7 100644 --- a/src/app/modules/main/chat_section/chat_content/module.nim +++ b/src/app/modules/main/chat_section/chat_content/module.nim @@ -274,6 +274,9 @@ method unblockChat*(self: Module) = method markAllMessagesRead*(self: Module) = self.controller.markAllMessagesRead() +method markMessageRead*(self: Module, msgID: string) = + self.controller.markMessageRead(msgID) + method clearChatHistory*(self: Module) = self.controller.clearChatHistory() diff --git a/src/app/modules/main/chat_section/chat_content/view.nim b/src/app/modules/main/chat_section/chat_content/view.nim index c881c2dc43..4f1becaf8c 100644 --- a/src/app/modules/main/chat_section/chat_content/view.nim +++ b/src/app/modules/main/chat_section/chat_content/view.nim @@ -86,6 +86,9 @@ QtObject: proc markAllMessagesRead*(self: View) {.slot.} = self.delegate.markAllMessagesRead() + proc markMessageRead*(self: View, msgID: string) {.slot.} = + self.delegate.markMessageRead(msgID) + proc clearChatHistory*(self: View) {.slot.} = self.delegate.clearChatHistory() diff --git a/src/app/modules/main/chat_section/controller.nim b/src/app/modules/main/chat_section/controller.nim index b8635f6d50..409c2b1f0d 100644 --- a/src/app/modules/main/chat_section/controller.nim +++ b/src/app/modules/main/chat_section/controller.nim @@ -147,14 +147,12 @@ proc init*(self: Controller) = self.events.on(message_service.SIGNAL_MESSAGES_MARKED_AS_READ) do(e: Args): let args = message_service.MessagesMarkedAsReadArgs(e) # update chat entity in chat service - var chat = self.chatService.getChatById(args.chatId) + let chat = self.chatService.getChatById(args.chatId) if ((self.isCommunitySection and chat.communityId != self.sectionId) or (not self.isCommunitySection and chat.communityId != "")): return - chat.unviewedMessagesCount = 0 - chat.unviewedMentionsCount = 0 - self.chatService.updateOrAddChat(chat) - self.delegate.onMarkAllMessagesRead(args.chatId) + self.chatService.updateUnreadMessagesAndMentions(args.chatId, args.allMessagesMarked, args.messagesCount, args.messagesWithMentionsCount) + self.delegate.updateUnreadMessagesAndMentions(args.chatId) self.events.on(chat_service.SIGNAL_CHAT_LEFT) do(e: Args): let args = chat_service.ChatArgs(e) diff --git a/src/app/modules/main/chat_section/io_interface.nim b/src/app/modules/main/chat_section/io_interface.nim index 7c769439e9..1334b66001 100644 --- a/src/app/modules/main/chat_section/io_interface.nim +++ b/src/app/modules/main/chat_section/io_interface.nim @@ -111,7 +111,7 @@ method onChatMuted*(self: AccessInterface, chatId: string) {.base.} = method onChatUnmuted*(self: AccessInterface, chatId: string) {.base.} = raise newException(ValueError, "No implementation available") -method onMarkAllMessagesRead*(self: AccessInterface, chatId: string) {.base.} = +method updateUnreadMessagesAndMentions*(self: AccessInterface, chatId: string) {.base.} = raise newException(ValueError, "No implementation available") method onContactAdded*(self: AccessInterface, publicKey: string) {.base.} = diff --git a/src/app/modules/main/chat_section/module.nim b/src/app/modules/main/chat_section/module.nim index e1dc1af69c..7cea981575 100644 --- a/src/app/modules/main/chat_section/module.nim +++ b/src/app/modules/main/chat_section/module.nim @@ -827,9 +827,12 @@ method onJoinedCommunity*(self: Module) = method onUserAuthenticated*(self: Module, pin: string, password: string, keyUid: string) = self.controller.requestToJoinCommunityAuthenticated(password) -method onMarkAllMessagesRead*(self: Module, chatId: string) = - self.updateBadgeNotifications(chatId, hasUnreadMessages=false, unviewedMentionsCount=0) +method updateUnreadMessagesAndMentions*(self: Module, chatId: string) = let chatDetails = self.controller.getChatDetails(chatId) + self.updateBadgeNotifications( + chatId=chatId, + hasUnreadMessages=chatDetails.unviewedMessagesCount > 0, + unviewedMentionsCount=chatDetails.unviewedMentionsCount) if chatDetails.categoryId != "": let hasUnreadMessages = self.controller.chatsWithCategoryHaveUnreadMessages(chatDetails.communityId, chatDetails.categoryId) self.view.chatsModel().setCategoryHasUnreadMessages(chatDetails.categoryId, hasUnreadMessages) diff --git a/src/app/modules/shared_models/message_model.nim b/src/app/modules/shared_models/message_model.nim index b3ec9a0685..103d302916 100644 --- a/src/app/modules/shared_models/message_model.nim +++ b/src/app/modules/shared_models/message_model.nim @@ -713,6 +713,21 @@ QtObject: let index = self.createIndex(i, 0, nil) self.dataChanged(index, index, @[ModelRole.Seen.int]) + proc markAsSeen*(self: Model, messages: seq[string]) = + var messagesSet = toHashSet(messages) + + for i in 0 ..< self.items.len: + let currentItemID = self.items[i].id + + if messagesSet.contains(currentItemID): + self.items[i].seen = true + let index = self.createIndex(i, 0, nil) + self.dataChanged(index, index, @[ModelRole.Seen.int]) + messagesSet.excl(currentItemID) + + if messagesSet.len == 0: + return + proc updateAlbumIfExists*(self: Model, albumId: string, messageImage: string, messageId: string): bool = for i in 0 ..< self.items.len: let item = self.items[i] diff --git a/src/app_service/service/chat/service.nim b/src/app_service/service/chat/service.nim index 729080c529..39d63cf6df 100644 --- a/src/app_service/service/chat/service.nim +++ b/src/app_service/service/chat/service.nim @@ -725,3 +725,15 @@ QtObject: result.add(member) except Exception as e: error "error while getting members", msg = e.msg, communityID, chatId + + proc updateUnreadMessagesAndMentions*(self: Service, chatID: string, markAllAsRead: bool, markAsReadCount: int, markAsReadMentionsCount: int) = + var chat = self.getChatById(chatID) + if chat.id == "": + return + if markAllAsRead: + chat.unviewedMessagesCount = 0 + chat.unviewedMentionsCount = 0 + else: + chat.unviewedMessagesCount = max(0, chat.unviewedMessagesCount - markAsReadCount) + chat.unviewedMentionsCount = max(0, chat.unviewedMentionsCount - markAsReadMentionsCount) + self.updateOrAddChat(chat) diff --git a/src/app_service/service/message/async_tasks.nim b/src/app_service/service/message/async_tasks.nim index ff09e9e36c..c4a899db3c 100644 --- a/src/app_service/service/message/async_tasks.nim +++ b/src/app_service/service/message/async_tasks.nim @@ -142,16 +142,21 @@ const asyncMarkCertainMessagesReadTask: Task = proc(argEncoded: string) {.gcsafe let response = status_go.markCertainMessagesFromChatWithIdAsRead(arg.chatId, arg.messagesIds) - var numberOfAffectedMessages: int - discard response.result.getProp("count", numberOfAffectedMessages) + var count: int + discard response.result.getProp("count", count) + + var countWithMentions: int + discard response.result.getProp("countWithMentions", countWithMentions) var error = "" - if(numberOfAffectedMessages == 0): + if(count == 0): error = "no message has updated" let responseJson = %*{ "chatId": arg.chatId, "messagesIds": arg.messagesIds, + "count": count, + "countWithMentions": countWithMentions, "error": error } arg.finish(responseJson) diff --git a/src/app_service/service/message/service.nim b/src/app_service/service/message/service.nim index b5135f8ed9..763af97401 100644 --- a/src/app_service/service/message/service.nim +++ b/src/app_service/service/message/service.nim @@ -88,6 +88,8 @@ type chatId*: string allMessagesMarked*: bool messagesIds*: seq[string] + messagesCount*: int + messagesWithMentionsCount*: int MessageAddRemoveReactionArgs* = ref object of Args chatId*: string @@ -640,7 +642,7 @@ QtObject: var error: string discard responseObj.getProp("error", error) if(error.len > 0): - error "error: ", procName="onMarkCertainMessagesRead", errDescription=error + error "error: ", procName="onMarkAllMessagesRead", errDescription=error return var chatId: string @@ -681,7 +683,21 @@ QtObject: for id in messagesIdsArr: messagesIds.add(id.getStr) - let data = MessagesMarkedAsReadArgs(chatId: chatId, allMessagesMarked: false, messagesIds: messagesIds) + var count: int + discard responseObj.getProp("count", count) + + if count < len(messagesIds): + warn "warning: ", procName="onMarkCertainMessagesRead", errDescription="not all messages has been marked as read" + + var countWithMentions: int + discard responseObj.getProp("countWithMentions", countWithMentions) + + let data = MessagesMarkedAsReadArgs( + chatId: chatId, + allMessagesMarked: false, + messagesIds: messagesIds, + messagesCount: count, + messagesWithMentionsCount: countWithMentions) self.events.emit(SIGNAL_MESSAGES_MARKED_AS_READ, data) proc markCertainMessagesRead*(self: Service, chatId: string, messagesIds: seq[string]) = diff --git a/test/nim/message_model_test.nim b/test/nim/message_model_test.nim index c68d567a6b..8d9de95c7d 100644 --- a/test/nim/message_model_test.nim +++ b/test/nim/message_model_test.nim @@ -311,3 +311,38 @@ suite "simulations": check(model.items[5].id == message1.id) check(model.items[6].id == message0_fetchMoreMessages.id) check(model.items[7].id == message0_chatIdentifier.id) + + +suite "mark as seen": + setup: + let model = newModel() + + var msg1 = createTestMessageItem("0xa", 1) + msg1.seen=false + let msg2 = createTestMessageItem("0xb", 2) + msg2.seen=false + let msg3 = createTestMessageItem("0xc", 3) + msg3.seen=true + + model.insertItemsBasedOnClock(@[msg1, msg2, msg3]) + require(model.items.len == 3) + check(model.items[0].seen == true) + check(model.items[1].seen == false) + check(model.items[2].seen == false) + + test "mark all as seen": + model.markAllAsSeen() + check(model.items[0].seen == true) + check(model.items[1].seen == true) + check(model.items[2].seen == true) + + test "mark some as seen": + model.markAsSeen(@["0xa"]) + check(model.items[0].seen == true) + check(model.items[1].seen == false) + check(model.items[2].seen == true) + + model.markAsSeen(@["0xb"]) + check(model.items[0].seen == true) + check(model.items[1].seen == true) + check(model.items[2].seen == true)