diff --git a/src/app/modules/main/activity_center/module.nim b/src/app/modules/main/activity_center/module.nim index 6f63201a96..72ebff70de 100644 --- a/src/app/modules/main/activity_center/module.nim +++ b/src/app/modules/main/activity_center/module.nim @@ -75,6 +75,13 @@ proc createMessageItemFromDto(self: Module, message: MessageDto, chatDetails: Ch let contactDetails = self.controller.getContactDetails(message.`from`) let communityChats = self.controller.getCommunityById(chatDetails.communityId).chats + var quotedMessageAuthorDetails = ContactDetails() + if message.quotedMessage.`from` != "": + if(message.`from` == message.quotedMessage.`from`): + quotedMessageAuthorDetails = contactDetails + else: + quotedMessageAuthorDetails = self.controller.getContactDetails(message.quotedMessage.`from`) + return msg_item_qobj.newMessageItem(msg_item.initItem( message.id, chatDetails.communityId, # we don't received community id via `activityCenterNotifications` api call @@ -83,6 +90,7 @@ proc createMessageItemFromDto(self: Module, message: MessageDto, chatDetails: Ch contactDetails.defaultDisplayName, contactDetails.optionalName, contactDetails.icon, + contactDetails.colorHash, contactDetails.isCurrentUser, contactDetails.details.added, message.outgoingStatus, @@ -112,6 +120,7 @@ proc createMessageItemFromDto(self: Module, message: MessageDto, chatDetails: Ch message.quotedMessage.contentType, message.quotedMessage.deleted, message.quotedMessage.discordMessage, + quotedMessageAuthorDetails )) method convertToItems*( 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 63ad0b580c..a09700ce5c 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 @@ -86,6 +86,7 @@ proc createFetchMoreMessagesItem(self: Module): Item = senderDisplayName = "", senderOptionalName = "", senderIcon = "", + senderColorHash = "", amISender = false, senderIsAdded = false, outgoingStatus = "", @@ -115,6 +116,7 @@ proc createFetchMoreMessagesItem(self: Module): Item = quotedMessageContentType = -1, quotedMessageDeleted = false, quotedMessageDiscordMessage = DiscordMessage(), + quotedMessageAuthorDetails = ContactDetails() ) proc createChatIdentifierItem(self: Module): Item = @@ -122,11 +124,13 @@ proc createChatIdentifierItem(self: Module): Item = var chatName = chatDto.name var smallImage = "" var chatIcon = "" + var senderColorHash = "" var senderIsAdded = false if(chatDto.chatType == ChatType.OneToOne): let sender = self.controller.getContactDetails(chatDto.id) senderIsAdded = sender.details.added (chatName, smallImage, chatIcon) = self.controller.getOneToOneChatNameAndImage() + senderColorHash = sender.colorHash result = initItem( CHAT_IDENTIFIER_MESSAGE_ID, @@ -136,6 +140,7 @@ proc createChatIdentifierItem(self: Module): Item = senderDisplayName = chatName, senderOptionalName = "", senderIcon = chatIcon, + senderColorHash = senderColorHash, amISender = false, senderIsAdded, outgoingStatus = "", @@ -165,6 +170,7 @@ proc createChatIdentifierItem(self: Module): Item = quotedMessageContentType = -1, quotedMessageDeleted = false, quotedMessageDiscordMessage = DiscordMessage(), + quotedMessageAuthorDetails = ContactDetails() ) proc checkIfMessageLoadedAndScrollToItIfItIs(self: Module) = @@ -199,11 +205,17 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se # Now we just skip deleted messages if message.deleted or message.deletedForMe: continue - - let sender = self.controller.getContactDetails(message.`from`) let chatDetails = self.controller.getChatDetails() let communityChats = self.controller.getCommunityById(chatDetails.communityId).chats + let sender = self.controller.getContactDetails(message.`from`) + var quotedMessageAuthorDetails = ContactDetails() + if message.quotedMessage.`from` != "": + if(message.`from` == message.quotedMessage.`from`): + quotedMessageAuthorDetails = sender + else: + quotedMessageAuthorDetails = self.controller.getContactDetails(message.quotedMessage.`from`) + let renderedMessageText = self.controller.getRenderedText(message.parsedText, communityChats) var transactionContract = message.transactionParameters.contract var transactionValue = message.transactionParameters.value @@ -220,6 +232,7 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se sender.defaultDisplayName, sender.optionalName, sender.icon, + sender.colorHash, (isCurrentUser and message.contentType.ContentType != ContentType.DiscordMessage), sender.details.added, message.outgoingStatus, @@ -256,6 +269,7 @@ method newMessagesLoaded*(self: Module, messages: seq[MessageDto], reactions: se message.quotedMessage.contentType, message.quotedMessage.deleted, message.quotedMessage.discordMessage, + quotedMessageAuthorDetails ) for r in reactions: @@ -305,6 +319,12 @@ method messagesAdded*(self: Module, messages: seq[MessageDto]) = let sender = self.controller.getContactDetails(message.`from`) let chatDetails = self.controller.getChatDetails() let communityChats = self.controller.getCommunityById(chatDetails.communityId).chats + var quotedMessageAuthorDetails = ContactDetails() + if message.quotedMessage.`from` != "": + if(message.`from` == message.quotedMessage.`from`): + quotedMessageAuthorDetails = sender + else: + quotedMessageAuthorDetails = self.controller.getContactDetails(message.quotedMessage.`from`) let renderedMessageText = self.controller.getRenderedText(message.parsedText, communityChats) @@ -333,6 +353,7 @@ method messagesAdded*(self: Module, messages: seq[MessageDto]) = sender.defaultDisplayName, sender.optionalName, sender.icon, + sender.colorHash, (isCurrentUser and message.contentType.ContentType != ContentType.DiscordMessage), sender.details.added, message.outgoingStatus, @@ -369,6 +390,7 @@ method messagesAdded*(self: Module, messages: seq[MessageDto]) = message.quotedMessage.contentType, message.quotedMessage.deleted, message.quotedMessage.discordMessage, + quotedMessageAuthorDetails, ) items.add(item) @@ -499,9 +521,12 @@ method updateContactDetails*(self: Module, contactId: string) = item.senderDisplayName = updatedContact.defaultDisplayName item.senderOptionalName = updatedContact.optionalName item.senderIcon = updatedContact.icon + item.senderColorHash = updatedContact.colorHash item.senderIsAdded = updatedContact.details.added item.senderTrustStatus = updatedContact.details.trustStatus item.senderEnsVerified = updatedContact.details.ensVerified + if(item.quotedMessageAuthorDetails.details.id == contactId): + item.quotedMessageAuthorDetails = updatedContact if(item.messageContainsMentions): let (message, _, err) = self.controller.getMessageDetails(item.id) if(err.len == 0): @@ -615,6 +640,13 @@ method getMessageById*(self: Module, messageId: string): message_item.Item = let communityChats = self.controller.getCommunityById(chatDetails.communityId).chats let renderedMessageText = self.controller.getRenderedText(message.parsedText, communityChats) + var quotedMessageAuthorDetails = ContactDetails() + if message.quotedMessage.`from` != "": + if(message.`from` == message.quotedMessage.`from`): + quotedMessageAuthorDetails = sender + else: + quotedMessageAuthorDetails = self.controller.getContactDetails(message.quotedMessage.`from`) + var transactionContract = message.transactionParameters.contract var transactionValue = message.transactionParameters.value var isCurrentUser = sender.isCurrentUser @@ -630,6 +662,7 @@ method getMessageById*(self: Module, messageId: string): message_item.Item = sender.defaultDisplayName, sender.optionalName, sender.icon, + sender.colorHash, (isCurrentUser and message.contentType.ContentType != ContentType.DiscordMessage), sender.details.added, message.outgoingStatus, @@ -665,7 +698,8 @@ method getMessageById*(self: Module, messageId: string): message_item.Item = self.controller.getRenderedText(message.quotedMessage.parsedText, communityChats), message.quotedMessage.contentType, message.quotedMessage.deleted, - message.quotedMessage.discordMessage + message.quotedMessage.discordMessage, + quotedMessageAuthorDetails, ) return item return nil 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 0482f7c927..8392dabcf5 100644 --- a/src/app/modules/main/chat_section/chat_content/module.nim +++ b/src/app/modules/main/chat_section/chat_content/module.nim @@ -157,6 +157,12 @@ proc buildPinnedMessageItem(self: Module, messageId: string, actionInitiatedBy: let contactDetails = self.controller.getContactDetails(message.`from`) let chatDetails = self.controller.getChatDetails() let communityChats = self.controller.getCommunityById(chatDetails.communityId).chats + var quotedMessageAuthorDetails = ContactDetails() + if message.quotedMessage.`from` != "": + if(message.`from` == message.quotedMessage.`from`): + quotedMessageAuthorDetails = contactDetails + else: + quotedMessageAuthorDetails = self.controller.getContactDetails(message.quotedMessage.`from`) var transactionContract = message.transactionParameters.contract var transactionValue = message.transactionParameters.value @@ -173,6 +179,7 @@ proc buildPinnedMessageItem(self: Module, messageId: string, actionInitiatedBy: contactDetails.defaultDisplayName, contactDetails.optionalName, contactDetails.icon, + contactDetails.colorHash, isCurrentUser, contactDetails.details.added, message.outgoingStatus, @@ -209,6 +216,7 @@ proc buildPinnedMessageItem(self: Module, messageId: string, actionInitiatedBy: message.quotedMessage.contentType, message.quotedMessage.deleted, message.quotedMessage.discordMessage, + quotedMessageAuthorDetails ) item.pinned = true item.pinnedBy = actionInitiatedBy diff --git a/src/app/modules/main/chat_section/chat_content/users/module.nim b/src/app/modules/main/chat_section/chat_content/users/module.nim index 97fed75bd4..e02cb60304 100644 --- a/src/app/modules/main/chat_section/chat_content/users/module.nim +++ b/src/app/modules/main/chat_section/chat_content/users/module.nim @@ -81,6 +81,7 @@ method onNewMessagesLoaded*(self: Module, messages: seq[MessageDto]) = alias = contactDetails.details.alias, icon = contactDetails.icon, colorId = contactDetails.colorId, + colorHash = contactDetails.colorHash, onlineStatus = status, isContact = contactDetails.details.isContact, isVerified = contactDetails.details.isContactVerified(), @@ -153,6 +154,7 @@ method addChatMember*(self: Module, member: ChatMember) = alias = contactDetails.details.alias, icon = contactDetails.icon, colorId = contactDetails.colorId, + colorHash = contactDetails.colorHash, onlineStatus = status, isContact = contactDetails.details.isContact, isVerified = contactDetails.details.isContactVerified(), diff --git a/src/app/modules/main/communities/module.nim b/src/app/modules/main/communities/module.nim index ee1e6bc28b..04d7c3d75d 100644 --- a/src/app/modules/main/communities/module.nim +++ b/src/app/modules/main/communities/module.nim @@ -93,6 +93,7 @@ proc createMemberItem(self: Module, memberId, requestId: string): MemberItem = alias = contactDetails.details.alias, icon = contactDetails.icon, colorId = contactDetails.colorId, + colorHash = contactDetails.colorHash, onlineStatus = toOnlineStatus(self.controller.getStatusForContactWithId(memberId).statusType), isContact = contactDetails.details.isContact, isVerified = contactDetails.details.isContactVerified(), diff --git a/src/app/modules/main/module.nim b/src/app/modules/main/module.nim index 8edcbd080f..771995bdbf 100644 --- a/src/app/modules/main/module.nim +++ b/src/app/modules/main/module.nim @@ -267,6 +267,7 @@ proc createChannelGroupItem[T](self: Module[T], c: ChannelGroupDto): SectionItem alias = contactDetails.details.alias, icon = contactDetails.icon, colorId = contactDetails.colorId, + colorHash = contactDetails.colorHash, onlineStatus = toOnlineStatus(self.controller.getStatusForContactWithId(member.id).statusType), isContact = contactDetails.details.isContact, isVerified = contactDetails.details.isContactVerified(), @@ -292,6 +293,7 @@ proc createChannelGroupItem[T](self: Module[T], c: ChannelGroupDto): SectionItem alias = contactDetails.details.alias, icon = contactDetails.icon, colorId = contactDetails.colorId, + colorHash = contactDetails.colorHash, onlineStatus = toOnlineStatus(self.controller.getStatusForContactWithId(bannedMemberId).statusType), isContact = contactDetails.details.isContact, isVerified = contactDetails.details.isContactVerified() @@ -307,6 +309,7 @@ proc createChannelGroupItem[T](self: Module[T], c: ChannelGroupDto): SectionItem alias = contactDetails.details.alias, icon = contactDetails.icon, colorId = contactDetails.colorId, + colorHash = contactDetails.colorHash, onlineStatus = toOnlineStatus(self.controller.getStatusForContactWithId(requestDto.publicKey).statusType), isContact = contactDetails.details.isContact, isVerified = contactDetails.details.isContactVerified(), @@ -323,6 +326,7 @@ proc createChannelGroupItem[T](self: Module[T], c: ChannelGroupDto): SectionItem alias = contactDetails.details.alias, icon = contactDetails.icon, colorId = contactDetails.colorId, + colorHash = contactDetails.colorHash, onlineStatus = toOnlineStatus(self.controller.getStatusForContactWithId(requestDto.publicKey).statusType), isContact = contactDetails.details.isContact, isVerified = contactDetails.details.isContactVerified(), diff --git a/src/app/modules/shared_models/message_item.nim b/src/app/modules/shared_models/message_item.nim index a0f24f6ab4..338e36d212 100644 --- a/src/app/modules/shared_models/message_item.nim +++ b/src/app/modules/shared_models/message_item.nim @@ -1,6 +1,6 @@ import json, strformat, strutils import ../../../app_service/common/types -import ../../../app_service/service/contacts/dto/contacts +import ../../../app_service/service/contacts/dto/contact_details import ../../../app_service/service/message/dto/message export types.ContentType @@ -17,6 +17,7 @@ type amISender: bool senderIsAdded: bool senderIcon: string + senderColorHash: string seen: bool outgoingStatus: string messageText: string @@ -52,8 +53,7 @@ type quotedMessageDeleted: bool quotedMessageAuthorDisplayName: string quotedMessageAuthorAvatar: string - # This is only used to update the author's details when author's details change - quotedMessageFromIterator: int + quotedMessageAuthorDetails: ContactDetails proc initItem*( id, @@ -63,6 +63,7 @@ proc initItem*( senderDisplayName, senderOptionalName, senderIcon: string, + senderColorHash: string, amISender: bool, senderIsAdded: bool, outgoingStatus, @@ -92,6 +93,7 @@ proc initItem*( quotedMessageContentType: int, quotedMessageDeleted: bool, quotedMessageDiscordMessage: DiscordMessage, + quotedMessageAuthorDetails: ContactDetails, ): Item = result = Item() result.id = id @@ -103,6 +105,7 @@ proc initItem*( result.amISender = amISender result.senderIsAdded = senderIsAdded result.senderIcon = senderIcon + result.senderColorHash = senderColorHash result.seen = seen result.outgoingStatus = outgoingStatus result.messageText = if contentType == ContentType.Image : "" else: text @@ -135,13 +138,16 @@ proc initItem*( result.quotedMessageParsedText = quotedMessageParsedText result.quotedMessageContentType = quotedMessageContentType result.quotedMessageDeleted = quotedMessageDeleted - result.quotedMessageFromIterator = 0 + result.quotedMessageAuthorDetails = quotedMessageAuthorDetails if quotedMessageContentType == ContentType.DiscordMessage.int: result.quotedMessageAuthorDisplayName = quotedMessageDiscordMessage.author.name result.quotedMessageAuthorAvatar = quotedMessageDiscordMessage.author.localUrl if result.quotedMessageAuthorAvatar == "": result.quotedMessageAuthorAvatar = quotedMessageDiscordMessage.author.avatarUrl + else: + result.quotedMessageAuthorDisplayName = quotedMessageAuthorDetails.details.displayName + result.quotedMessageAuthorAvatar = quotedMessageAuthorDetails.details.image.thumbnail if contentType == ContentType.DiscordMessage: @@ -172,6 +178,7 @@ proc initNewMessagesMarkerItem*(clock, timestamp: int64): Item = senderDisplayName = "", senderOptionalName = "", senderIcon = "", + senderColorHash = "", amISender = false, senderIsAdded = false, outgoingStatus = "", @@ -201,6 +208,7 @@ proc initNewMessagesMarkerItem*(clock, timestamp: int64): Item = quotedMessageContentType = -1, quotedMessageDeleted = false, quotedMessageDiscordMessage = DiscordMessage(), + quotedMessageAuthorDetails = ContactDetails(), ) proc `$`*(self: Item): string = @@ -265,6 +273,12 @@ proc senderIcon*(self: Item): string {.inline.} = proc `senderIcon=`*(self: Item, value: string) {.inline.} = self.senderIcon = value +proc senderColorHash*(self: Item): string {.inline.} = + self.senderColorHash + +proc `senderColorHash=`*(self: Item, value: string) {.inline.} = + self.senderColorHash = value + proc amISender*(self: Item): bool {.inline.} = self.amISender @@ -403,6 +417,7 @@ proc toJsonNode*(self: Item): JsonNode = "amISender": self.amISender, "senderIsAdded": self.senderIsAdded, "senderIcon": self.senderIcon, + "senderColorHash": self.senderColorHash, "seen": self.seen, "outgoingStatus": self.outgoingStatus, "messageText": self.messageText, @@ -491,11 +506,6 @@ proc quotedMessageDeleted*(self: Item): bool {.inline.} = proc `quotedMessageDeleted=`*(self: Item, value: bool) {.inline.} = self.quotedMessageDeleted = value -proc quotedMessageFromIterator*(self: Item): int {.inline.} = - self.quotedMessageFromIterator -proc `quotedMessageFromIterator=`*(self: Item, value: int) {.inline.} = - self.quotedMessageFromIterator = value - proc quotedMessageAuthorDisplayName*(self: Item): string {.inline.} = self.quotedMessageAuthorDisplayName @@ -507,3 +517,8 @@ proc quotedMessageAuthorAvatar*(self: Item): string {.inline.} = proc `quotedMessageAuthorAvatar=`*(self: Item, value: string) {.inline.} = self.quotedMessageAuthorAvatar = value + +proc quotedMessageAuthorDetails*(self: Item): ContactDetails {.inline.} = + self.quotedMessageAuthorDetails +proc `quotedMessageAuthorDetails=`*(self: Item, value: ContactDetails) {.inline.} = + self.quotedMessageAuthorDetails = value diff --git a/src/app/modules/shared_models/message_item_qobject.nim b/src/app/modules/shared_models/message_item_qobject.nim index f1a2f809c0..5abb60f8c3 100644 --- a/src/app/modules/shared_models/message_item_qobject.nim +++ b/src/app/modules/shared_models/message_item_qobject.nim @@ -93,6 +93,10 @@ QtObject: QtProperty[string] senderIcon: read = senderIcon + proc senderColorHash*(self: MessageItem): string {.slot.} = result = ?.self.messageItem.senderColorHash + QtProperty[string] senderColorHash: + read = senderColorHash + proc seen*(self: MessageItem): bool {.slot.} = result = ?.self.messageItem.seen QtProperty[bool] seen: read = seen diff --git a/src/app/modules/shared_models/message_model.nim b/src/app/modules/shared_models/message_model.nim index 418eba5751..084c78304c 100644 --- a/src/app/modules/shared_models/message_model.nim +++ b/src/app/modules/shared_models/message_model.nim @@ -3,19 +3,24 @@ import NimQml, Tables, json, sets, algorithm, sequtils, strutils, strformat, sug import message_item, message_reaction_item, message_transaction_parameters_item import ../../../app_service/service/message/dto/message# as message_dto +import ../../../app_service/service/contacts/dto/contact_details type ModelRole {.pure.} = enum Id = UserRole + 1 PrevMsgTimestamp PrevMsgIndex + PrevMsgSenderId + PrevMsgContentType NextMsgIndex + NextMsgTimestamp CommunityId ResponseToMessageWithId SenderId SenderDisplayName SenderOptionalName SenderIcon + SenderColorHash AmISender SenderIsAdded Seen @@ -50,9 +55,12 @@ type QuotedMessageParsedText QuotedMessageContentType QuotedMessageDeleted - QuotedMessageFromIterator + QuotedMessageAuthorName QuotedMessageAuthorDisplayName - QuotedMessageAuthorAvatar + QuotedMessageAuthorThumbnailImage + QuotedMessageAuthorEnsVerified + QuotedMessageAuthorIsContact + QuotedMessageAuthorColorHash QtObject: type @@ -103,13 +111,17 @@ QtObject: ModelRole.Id.int:"id", ModelRole.PrevMsgTimestamp.int: "prevMsgTimestamp", ModelRole.PrevMsgIndex.int:"prevMsgIndex", + ModelRole.PrevMsgSenderId.int:"prevMsgSenderId", + ModelRole.PrevMsgContentType.int:"prevMsgContentType", ModelRole.NextMsgIndex.int:"nextMsgIndex", + ModelRole.NextMsgTimestamp.int:"nextMsgTimestamp", ModelRole.CommunityId.int:"communityId", ModelRole.ResponseToMessageWithId.int:"responseToMessageWithId", ModelRole.SenderId.int:"senderId", ModelRole.SenderDisplayName.int:"senderDisplayName", ModelRole.SenderOptionalName.int:"senderOptionalName", ModelRole.SenderIcon.int:"senderIcon", + ModelRole.SenderColorHash.int:"senderColorHash", ModelRole.AmISender.int:"amISender", ModelRole.SenderIsAdded.int:"senderIsAdded", ModelRole.Seen.int:"seen", @@ -139,13 +151,16 @@ QtObject: ModelRole.SenderEnsVerified.int: "senderEnsVerified", ModelRole.MessageAttachments.int: "messageAttachments", ModelRole.QuotedMessageFrom.int: "quotedMessageFrom", - ModelRole.QuotedMessageFromIterator.int: "quotedMessageFromIterator", ModelRole.QuotedMessageText.int: "quotedMessageText", ModelRole.QuotedMessageParsedText.int: "quotedMessageParsedText", ModelRole.QuotedMessageContentType.int: "quotedMessageContentType", ModelRole.QuotedMessageDeleted.int: "quotedMessageDeleted", + ModelRole.QuotedMessageAuthorName.int: "quotedMessageAuthorName", ModelRole.QuotedMessageAuthorDisplayName.int: "quotedMessageAuthorDisplayName", - ModelRole.QuotedMessageAuthorAvatar.int: "quotedMessageAuthorAvatar", + ModelRole.QuotedMessageAuthorThumbnailImage.int: "quotedMessageAuthorThumbnailImage", + ModelRole.QuotedMessageAuthorEnsVerified.int: "quotedMessageAuthorEnsVerified", + ModelRole.QuotedMessageAuthorIsContact.int: "quotedMessageAuthorIsContact", + ModelRole.QuotedMessageAuthorColorHash.int: "quotedMessageAuthorColorHash", }.toTable method data(self: Model, index: QModelIndex, role: int): QVariant = @@ -161,16 +176,34 @@ QtObject: case enumRole: of ModelRole.Id: result = newQVariant(item.id) - of PrevMsgTimestamp: + of ModelRole.PrevMsgTimestamp: if (index.row + 1 < self.items.len): let prevItem = self.items[index.row + 1] result = newQVariant(prevItem.timestamp) else: result = newQVariant(0) + of ModelRole.PrevMsgSenderId: + if (index.row + 1 < self.items.len): + let prevItem = self.items[index.row + 1] + result = newQVariant(prevItem.senderId) + else: + result = newQVariant("") + of ModelRole.PrevMsgContentType: + if (index.row + 1 < self.items.len): + let prevItem = self.items[index.row + 1] + result = newQVariant(prevItem.contentType.int) + else: + result = newQVariant(ContentType.Unknown.int) of ModelRole.PrevMsgIndex: result = newQVariant(index.row + 1) of ModelRole.NextMsgIndex: result = newQVariant(index.row - 1) + of ModelRole.NextMsgTimestamp: + if (index.row - 1 >= 0 and index.row - 1 < self.items.len): + let nextItem = self.items[index.row - 1] + result = newQVariant(nextItem.timestamp) + else: + result = newQVariant(0) of ModelRole.CommunityId: result = newQVariant(item.communityId) of ModelRole.ResponseToMessageWithId: @@ -185,6 +218,8 @@ QtObject: result = newQVariant(item.senderOptionalName) of ModelRole.SenderIcon: result = newQVariant(item.senderIcon) + of ModelRole.SenderColorHash: + result = newQVariant(item.senderColorHash) of ModelRole.AmISender: result = newQVariant(item.amISender) of ModelRole.SenderIsAdded: @@ -199,8 +234,6 @@ QtObject: result = newQVariant(item.mentioned) of ModelRole.QuotedMessageFrom: result = newQVariant(item.quotedMessageFrom) - of ModelRole.QuotedMessageFromIterator: - result = newQVariant(item.quotedMessageFromIterator) of ModelRole.QuotedMessageText: result = newQVariant(item.quotedMessageText) of ModelRole.QuotedMessageParsedText: @@ -209,10 +242,18 @@ QtObject: result = newQVariant(item.quotedMessageContentType) of ModelRole.QuotedMessageDeleted: result = newQVariant(item.quotedMessageDeleted) + of ModelRole.QuotedMessageAuthorName: + result = newQVariant(item.quotedMessageAuthorDetails.details.name) of ModelRole.QuotedMessageAuthorDisplayName: result = newQVariant(item.quotedMessageAuthorDisplayName) - of ModelRole.QuotedMessageAuthorAvatar: + of ModelRole.QuotedMessageAuthorThumbnailImage: result = newQVariant(item.quotedMessageAuthorAvatar) + of ModelRole.QuotedMessageAuthorEnsVerified: + result = newQVariant(item.quotedMessageAuthorDetails.details.ensVerified) + of ModelRole.QuotedMessageAuthorIsContact: + result = newQVariant(item.quotedMessageAuthorDetails.details.isContact()) + of ModelRole.QuotedMessageAuthorColorHash: + result = newQVariant(item.quotedMessageAuthorDetails.colorHash) of ModelRole.MessageText: result = newQVariant(item.messageText) of ModelRole.UnparsedText: @@ -310,7 +351,7 @@ QtObject: self.dataChanged(index, index, @[ ModelRole.QuotedMessageFrom.int, ModelRole.QuotedMessageAuthorDisplayName.int, - ModelRole.QuotedMessageAuthorAvatar.int, + ModelRole.QuotedMessageAuthorThumbnailImage.int, ModelRole.QuotedMessageText.int, ModelRole.QuotedMessageParsedText.int, ModelRole.QuotedMessageContentType.int, @@ -372,11 +413,18 @@ QtObject: item.quotedMessageParsedText = "" item.quotedMessageFrom = "" item.quotedMessageDeleted = true + item.quotedMessageAuthorDetails = ContactDetails() self.dataChanged(ind, ind, @[ ModelRole.QuotedMessageFrom.int, ModelRole.QuotedMessageParsedText.int, ModelRole.QuotedMessageContentType.int, ModelRole.QuotedMessageDeleted.int, + ModelRole.QuotedMessageAuthorName.int, + ModelRole.QuotedMessageAuthorDisplayName.int, + ModelRole.QuotedMessageAuthorThumbnailImage.int, + ModelRole.QuotedMessageAuthorEnsVerified.int, + ModelRole.QuotedMessageAuthorIsContact.int, + ModelRole.QuotedMessageAuthorColorHash.int ]) proc removeItem*(self: Model, messageId: string) = @@ -494,6 +542,7 @@ QtObject: roles = @[ModelRole.SenderDisplayName.int, ModelRole.SenderOptionalName.int, ModelRole.SenderIcon.int, + ModelRole.SenderColorHash.int, ModelRole.SenderIsAdded.int, ModelRole.SenderTrustStatus.int, ModelRole.SenderEnsVerified.int] @@ -503,10 +552,12 @@ QtObject: roles.add(@[ModelRole.MessageText.int, ModelRole.UnparsedText.int, ModelRole.MessageContainsMentions.int]) if (self.items[i].quotedMessageFrom == contactId): - # If there is a quoted message whom the author changed, increase the iterator to force - # the view to re-fetch the author's details - self.items[i].quotedMessageFromIterator = self.items[i].quotedMessageFromIterator + 1 - roles.add(ModelRole.QuotedMessageFromIterator.int) + roles.add(@[ModelRole.QuotedMessageAuthorName.int, + ModelRole.QuotedMessageAuthorDisplayName.int, + ModelRole.QuotedMessageAuthorThumbnailImage.int, + ModelRole.QuotedMessageAuthorEnsVerified.int, + ModelRole.QuotedMessageAuthorIsContact.int, + ModelRole.QuotedMessageAuthorColorHash.int]) if(roles.len > 0): let index = self.createIndex(i, 0, nil) diff --git a/src/app_service/service/contacts/dto/contact_details.nim b/src/app_service/service/contacts/dto/contact_details.nim index 52aeb6a403..2432ccd429 100644 --- a/src/app_service/service/contacts/dto/contact_details.nim +++ b/src/app_service/service/contacts/dto/contact_details.nim @@ -11,4 +11,5 @@ type icon*: string isCurrentUser*: bool colorId*: int + colorHash*: string details*: ContactsDto diff --git a/src/app_service/service/contacts/service.nim b/src/app_service/service/contacts/service.nim index 402b99dd02..12d7de878f 100644 --- a/src/app_service/service/contacts/service.nim +++ b/src/app_service/service/contacts/service.nim @@ -565,6 +565,8 @@ QtObject: result.colorId = procs_from_visual_identity_service.colorIdOf(pubKey) result.isCurrentUser = pubKey == singletonInstance.userProfile.getPubKey() result.details = contactDto + if not contactDto.ensVerified: + result.colorHash = procs_from_visual_identity_service.getColorHashAsJson(pubKey) proc markUntrustworthy*(self: Service, publicKey: string) = let response = status_contacts.markUntrustworthy(publicKey) diff --git a/test/nim/message_model_test.nim b/test/nim/message_model_test.nim index 127171e20b..bbf96290d0 100644 --- a/test/nim/message_model_test.nim +++ b/test/nim/message_model_test.nim @@ -1,7 +1,7 @@ import unittest import ../../../src/app_service/common/types -import ../../../src/app_service/service/contacts/dto/contacts +import ../../../src/app_service/service/contacts/dto/contact_details import ../../../src/app_service/service/message/dto/message import ../../../src/app/modules/shared_models/message_model @@ -17,6 +17,7 @@ proc createTestMessageItem(id: string, clock: int64): Item = senderDisplayName = "", senderOptionalName = "", senderIcon = "", + senderColorHash = "", amISender = false, senderIsAdded = false, outgoingStatus = "", @@ -46,6 +47,7 @@ proc createTestMessageItem(id: string, clock: int64): Item = quotedMessageContentType = -1, quotedMessageDeleted = false, quotedMessageDiscordMessage = DiscordMessage(), + quotedMessageAuthorDetails = ContactDetails(), ) let message0_chatIdentifier = createTestMessageItem("chat-identifier", -2) diff --git a/ui/StatusQ/src/StatusQ/Controls/StatusIdenticonRing.qml b/ui/StatusQ/src/StatusQ/Controls/StatusIdenticonRing.qml index f582d37f99..1da0416baf 100644 --- a/ui/StatusQ/src/StatusQ/Controls/StatusIdenticonRing.qml +++ b/ui/StatusQ/src/StatusQ/Controls/StatusIdenticonRing.qml @@ -62,7 +62,7 @@ Item { ringPxSize: 1.5 } - visible: settings && settings.ringSpecModel !== undefined + visible: settings && typeof settings.normalizedRingSpecModel !== "undefined" Loader { anchors.fill: parent @@ -79,23 +79,23 @@ Item { } function getSegmentsCount() { - if (typeof settings.ringSpecModel.rowCount !== "undefined") { - return settings.ringSpecModel.rowCount() + if (typeof settings.normalizedRingSpecModel.rowCount !== "undefined") { + return settings.normalizedRingSpecModel.rowCount() } - if (typeof settings.ringSpecModel.count !== "undefined") { - return settings.ringSpecModel.count + if (typeof settings.normalizedRingSpecModel.count !== "undefined") { + return settings.normalizedRingSpecModel.count } - return settings.ringSpecModel.length + return settings.normalizedRingSpecModel.length } function getSegment(i) { - if (typeof settings.ringSpecModel.rowCount !== "undefined") { + if (typeof settings.normalizedRingSpecModel.rowCount !== "undefined") { return abstactItemModelWrapper.itemAt(i) } - if (typeof settings.ringSpecModel.count !== "undefined") { - return settings.ringSpecModel.get(i) + if (typeof settings.normalizedRingSpecModel.count !== "undefined") { + return settings.normalizedRingSpecModel.get(i) } - return settings.ringSpecModel[i] + return settings.normalizedRingSpecModel[i] } function totalRingUnits() { @@ -109,7 +109,7 @@ Item { Repeater { id: abstactItemModelWrapper - model: typeof settings.ringSpecModel.rowCount !== "undefined" ? settings.ringSpecModel : null + model: typeof settings.normalizedRingSpecModel.rowCount !== "undefined" ? settings.normalizedRingSpecModel : null delegate: Item { readonly property int segmentLength: model.segmentLength readonly property int colorId: model.colorId @@ -126,7 +126,7 @@ Item { let arcPos = settings.initalAngleRad context.reset() - if(settings.ringSpecModel) { + if(settings.normalizedRingSpecModel) { for (let i=0; i < segmentsCount; i++) { const segment = getSegment(i) printArcSegment(context, @@ -144,7 +144,7 @@ Item { Connections { target: root.settings - function onRingSpecModelChanged() { + function onNormalizedRingSpecModelChanged() { requestPaint() } } diff --git a/ui/StatusQ/src/StatusQ/Core/StatusIdenticonRingSettings.qml b/ui/StatusQ/src/StatusQ/Core/StatusIdenticonRingSettings.qml index 2bfd863a21..5c042b0ba3 100644 --- a/ui/StatusQ/src/StatusQ/Core/StatusIdenticonRingSettings.qml +++ b/ui/StatusQ/src/StatusQ/Core/StatusIdenticonRingSettings.qml @@ -64,4 +64,21 @@ QtObject { This property provides the pixels size of the ring line. */ property real ringPxSize + + readonly property var normalizedRingSpecModel: { + if (typeof ringSpecModel !== "string") { + return ringSpecModel + } + + if(!ringSpecModel) { + return undefined + } + + try { + return JSON.parse(ringSpecModel) + } catch (e) { + console.log("StatusIdenticonRingSettings: ringSpecModel is not a valid JSON string") + return undefined + } + } } diff --git a/ui/app/AppLayouts/Chat/panels/UserListPanel.qml b/ui/app/AppLayouts/Chat/panels/UserListPanel.qml index 8e04c9c4b6..649dd3cb61 100644 --- a/ui/app/AppLayouts/Chat/panels/UserListPanel.qml +++ b/ui/app/AppLayouts/Chat/panels/UserListPanel.qml @@ -88,7 +88,7 @@ Item { asset.isLetterIdenticon: (asset.name === "") asset.color: Utils.colorForColorId(model.colorId) status: model.onlineStatus - ringSettings.ringSpecModel: Utils.getColorHashAsJson(model.pubKey, ensVerified) // FIXME: use model.colorHash + ringSettings.ringSpecModel: model.colorHash onClicked: { if (mouse.button === Qt.RightButton) { // Set parent, X & Y positions for the messageContextMenu diff --git a/ui/app/AppLayouts/Chat/panels/communities/CommunityMembersTabPanel.qml b/ui/app/AppLayouts/Chat/panels/communities/CommunityMembersTabPanel.qml index b2ead5d5c3..9ece522a3a 100644 --- a/ui/app/AppLayouts/Chat/panels/communities/CommunityMembersTabPanel.qml +++ b/ui/app/AppLayouts/Chat/panels/communities/CommunityMembersTabPanel.qml @@ -138,7 +138,7 @@ Item { asset.isLetterIdenticon: !model.icon asset.width: 40 asset.height: 40 - ringSettings.ringSpecModel: Utils.getColorHashAsJson(model.pubKey, !!model.ensName) + ringSettings.ringSpecModel: model.colorHash statusListItemIcon.badge.visible: (root.panelType === CommunityMembersTabPanel.TabType.AllMembers) onClicked: root.userProfileClicked(model.pubKey) diff --git a/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml b/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml index de2253a35c..bb9d488a8d 100644 --- a/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml +++ b/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml @@ -73,6 +73,7 @@ StatusDialog { senderIsEnsVerified: model.senderEnsVerified senderIsAdded: model.senderIsAdded senderIcon: model.senderIcon + senderColorHash: model.senderColorHash senderTrustStatus: model.senderTrustStatus amISender: model.amISender messageText: model.messageText @@ -84,6 +85,16 @@ StatusDialog { messagePinnedBy: model.pinnedBy linkUrls: model.links transactionParams: model.transactionParameters + quotedMessageText: model.quotedMessageParsedText + quotedMessageFrom: model.quotedMessageFrom + quotedMessageContentType: model.quotedMessageContentType + quotedMessageDeleted: model.quotedMessageDeleted + quotedMessageAuthorDetailsName: model.quotedMessageAuthorName + quotedMessageAuthorDetailsDisplayName: model.quotedMessageAuthorDisplayName + quotedMessageAuthorDetailsThumbnailImage: model.quotedMessageAuthorThumbnailImage + quotedMessageAuthorDetailsEnsVerified: model.quotedMessageAuthorEnsVerified + quotedMessageAuthorDetailsIsContact: model.quotedMessageAuthorIsContact + quotedMessageAuthorDetailsColorHash: model.quotedMessageAuthorColorHash // This is possible since we have all data loaded before we load qml. // When we fetch messages to fulfill a gap we have to set them at once. diff --git a/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml b/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml index 6828a5dbb0..3cd36f279e 100644 --- a/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml +++ b/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml @@ -262,6 +262,7 @@ Item { senderOptionalName: model.senderOptionalName senderIsEnsVerified: model.senderEnsVerified senderIcon: model.senderIcon + senderColorHash: model.senderColorHash senderIsAdded: model.senderIsAdded senderTrustStatus: model.senderTrustStatus amISender: model.amISender @@ -287,22 +288,28 @@ Item { quotedMessageText: model.quotedMessageParsedText quotedMessageFrom: model.quotedMessageFrom quotedMessageContentType: model.quotedMessageContentType - quotedMessageFromIterator: model.quotedMessageFromIterator quotedMessageDeleted: model.quotedMessageDeleted - + quotedMessageAuthorDetailsName: model.quotedMessageAuthorName + quotedMessageAuthorDetailsDisplayName: model.quotedMessageAuthorDisplayName + quotedMessageAuthorDetailsThumbnailImage: model.quotedMessageAuthorThumbnailImage + quotedMessageAuthorDetailsEnsVerified: model.quotedMessageAuthorEnsVerified + quotedMessageAuthorDetailsIsContact: model.quotedMessageAuthorIsContact + quotedMessageAuthorDetailsColorHash: model.quotedMessageAuthorColorHash + gapFrom: model.gapFrom gapTo: model.gapTo - // This is possible since we have all data loaded before we load qml. - // When we fetch messages to fulfill a gap we have to set them at once. - // Also one important thing here is that messages are set in descending order - // in terms of `timestamp` of a message, that means a message with the most - // recent time is added at index 0. - prevMessageIndex: model.prevMsgIndex - prevMessageAsJsonObj: messageStore.getMessageByIndexAsJson(model.prevMsgIndex) - prevMsgTimestamp: model.prevMsgTimestamp - nextMessageIndex: model.nextMsgIndex - nextMessageAsJsonObj: messageStore.getMessageByIndexAsJson(model.nextMsgIndex) + // This is possible since we have all data loaded before we load qml. + // When we fetch messages to fulfill a gap we have to set them at once. + // Also one important thing here is that messages are set in descending order + // in terms of `timestamp` of a message, that means a message with the most + // recent time is added at index 0. + prevMessageIndex: prevMsgIndex + prevMessageTimestamp: prevMsgTimestamp + prevMessageSenderId: prevMsgSenderId + prevMessageContentType: prevMsgContentType + nextMessageIndex: nextMsgIndex + nextMessageTimestamp: nextMsgTimestamp onOpenStickerPackPopup: { root.openStickerPackPopup(stickerPackId); diff --git a/ui/imports/shared/views/chat/MessageView.qml b/ui/imports/shared/views/chat/MessageView.qml index 0c3017e3dc..86635631a2 100644 --- a/ui/imports/shared/views/chat/MessageView.qml +++ b/ui/imports/shared/views/chat/MessageView.qml @@ -42,6 +42,8 @@ Loader { property string senderOptionalName: "" property bool senderIsEnsVerified: false property string senderIcon: "" + //TODO: provide the sender color hash from nim model in case of ContactVerificationRequest, OngoingContactVerificationRequest or PinnedMessagesPopupremove + property var senderColorHash: senderId != "" ? Utils.getColorHashAsJson(senderId, senderIsEnsVerified) : "" property bool amISender: false property bool amIChatAdmin: messageStore && messageStore.amIChatAdmin property bool senderIsAdded: false @@ -66,7 +68,12 @@ Loader { property int quotedMessageContentType: Constants.messageContentType.messageType property int quotedMessageFromIterator: -1 property bool quotedMessageDeleted: false - property var quotedMessageAuthorDetails: quotedMessageFromIterator >= 0 && Utils.getContactDetailsAsJson(quotedMessageFrom, false) + property string quotedMessageAuthorDetailsName: "" + property string quotedMessageAuthorDetailsDisplayName: "" + property string quotedMessageAuthorDetailsThumbnailImage: "" + property bool quotedMessageAuthorDetailsEnsVerified: false + property bool quotedMessageAuthorDetailsIsContact: false + property var quotedMessageAuthorDetailsColorHash // External behavior changers property bool isInPinnedPopup: false // The pinned popup limits the number of buttons shown @@ -77,26 +84,18 @@ Loader { property int gapTo: 0 property int prevMessageIndex: -1 + property int prevMessageContentType: prevMessageAsJsonObj ? prevMessageAsJsonObj.contentType : Constants.messageContentType.unknownContentType + property double prevMessageTimestamp: prevMessageAsJsonObj ? prevMessageAsJsonObj.timestamp : 0 + property string prevMessageSenderId: prevMessageAsJsonObj ? prevMessageAsJsonObj.senderId : "" property var prevMessageAsJsonObj property int nextMessageIndex: -1 + property int nextMessageTimestamp: nextMessageAsJsonObj ? nextMessageAsJsonObj.timestamp : 0 property var nextMessageAsJsonObj property bool editModeOn: false property bool isEdited: false - property string authorPrevMsg: { - if(!prevMessageAsJsonObj || - // The system message for private groups appear as created by the group host, but it shouldn't - prevMessageAsJsonObj.contentType === Constants.messageContentType.systemMessagePrivateGroupType) { - return "" - } - - return prevMessageAsJsonObj.senderId - } - property double prevMsgTimestamp: prevMessageAsJsonObj ? prevMessageAsJsonObj.timestamp : 0 - property double nextMsgTimestamp: nextMessageAsJsonObj ? nextMessageAsJsonObj.timestamp : 0 - - property bool shouldRepeatHeader: d.getShouldRepeatHeader(messageTimestamp, prevMsgTimestamp, messageOutgoingStatus) + property bool shouldRepeatHeader: d.getShouldRepeatHeader(messageTimestamp, prevMessageTimestamp, messageOutgoingStatus) property bool hasMention: false @@ -166,8 +165,8 @@ Loader { } messageContextMenu.messageSenderId = quotedMessageFrom messageContextMenu.selectedUserPublicKey = quotedMessageFrom - messageContextMenu.selectedUserDisplayName = quotedMessageAuthorDetails.displayName - messageContextMenu.selectedUserIcon = quotedMessageAuthorDetails.thumbnailImage + messageContextMenu.selectedUserDisplayName = quotedMessageAuthorDetailsDisplayName + messageContextMenu.selectedUserIcon = quotedMessageAuthorDetailsThumbnailImage } messageContextMenu.parent = sender; @@ -283,7 +282,7 @@ Loader { id: fetchMoreMessagesButtonComponent FetchMoreMessagesButton { nextMessageIndex: root.nextMessageIndex - nextMsgTimestamp: root.nextMsgTimestamp + nextMsgTimestamp: root.nextMessageTimestamp onTimerTriggered: { messageStore.requestMoreMessages(); } @@ -357,7 +356,7 @@ Loader { Layout.topMargin: 16 Layout.bottomMargin: 16 messageTimestamp: root.messageTimestamp - previousMessageTimestamp: root.prevMessageIndex === -1 ? 0 : root.prevMsgTimestamp + previousMessageTimestamp: root.prevMessageIndex === -1 ? 0 : root.prevMessageTimestamp visible: text !== "" } @@ -456,8 +455,8 @@ Loader { resendError: root.resendError reactionsModel: root.reactionsModel - showHeader: root.senderId !== root.authorPrevMsg || - root.shouldRepeatHeader || dateGroupLabel.visible || isAReply + showHeader: root.shouldRepeatHeader || dateGroupLabel.visible || isAReply || + (root.prevMessageContentType !== Constants.messageContentType.systemMessagePrivateGroupType && root.senderId !== root.prevMessageSenderId) isActiveMessage: d.isMessageActive topPadding: showHeader ? Style.current.halfPadding : 2 bottomPadding: showHeader && nextMessageHasHeader() ? Style.current.halfPadding : 2 @@ -605,7 +604,7 @@ Loader { assetSettings.isImage: root.isDiscordMessage || root.senderIcon.startsWith("data") pubkey: root.senderId colorId: Utils.colorIdForPubkey(root.senderId) - colorHash: Utils.getColorHashAsJson(root.senderId, root.senderIsEnsVerified) + colorHash: root.senderColorHash showRing: !root.isDiscordMessage && !root.senderIsEnsVerified } } @@ -637,19 +636,19 @@ Loader { amISender: root.quotedMessageFrom === userProfile.pubKey sender.id: root.quotedMessageFrom - sender.isContact: quotedMessageAuthorDetails.isContact - sender.displayName: root.quotedMessageContentType === Constants.messageContentType.discordMessageType ? quotedMessageAuthorDisplayName : quotedMessageAuthorDetails.displayName - sender.isEnsVerified: quotedMessageAuthorDetails.ensVerified - sender.secondaryName: quotedMessageAuthorDetails.name || "" + sender.isContact: quotedMessageAuthorDetailsIsContact + sender.displayName: quotedMessageAuthorDetailsDisplayName + sender.isEnsVerified: quotedMessageAuthorDetailsEnsVerified + sender.secondaryName: quotedMessageAuthorDetailsName || "" sender.profileImage { width: 20 height: 20 - name: root.quotedMessageContentType === Constants.messageContentType.discordMessageType ? quotedMessageAuthorAvatar : quotedMessageAuthorDetails.thumbnailImage - assetSettings.isImage: quotedMessageAuthorDetails.thumbnailImage !== "" || quotedMessageAuthorAvatar != "" + name: quotedMessageAuthorDetailsThumbnailImage + assetSettings.isImage: quotedMessageAuthorDetailsThumbnailImage showRing: (root.quotedMessageContentType !== Constants.messageContentType.discordMessageType) && !sender.isEnsVerified pubkey: sender.id colorId: Utils.colorIdForPubkey(sender.id) - colorHash: Utils.getColorHashAsJson(sender.id, sender.isEnsVerified) + colorHash: quotedMessageAuthorDetailsColorHash } }