From d6a061a5171482bc469141c3997d1b032eacbb0a Mon Sep 17 00:00:00 2001 From: Michal Iskierko Date: Thu, 11 Aug 2022 12:58:09 +0200 Subject: [PATCH] feat(@desktop/chat): Add setting image in group chat Image and cropping information are sent to status-go. Issue #6466 --- .../chat_content/messages/io_interface.nim | 3 +++ .../chat_section/chat_content/messages/module.nim | 4 ++++ .../chat_section/chat_content/messages/view.nim | 3 +++ .../main/chat_section/chat_content/module.nim | 2 +- .../modules/main/chat_section/chat_content/view.nim | 3 ++- src/app/modules/main/chat_section/controller.nim | 4 ++-- src/app/modules/main/chat_section/io_interface.nim | 2 +- src/app/modules/main/chat_section/module.nim | 6 ++++-- src/app_service/service/chat/dto/chat.nim | 8 +++++++- src/app_service/service/chat/service.nim | 10 ++++++---- src/backend/chat.nim | 6 ++++-- ui/app/AppLayouts/Chat/popups/GroupInfoPopup.qml | 13 +++++++++++-- ui/app/AppLayouts/Chat/popups/RenameGroupPopup.qml | 11 ++++++----- ui/app/AppLayouts/Chat/stores/MessageStore.qml | 7 +++++++ ui/app/AppLayouts/Chat/views/ChatContentView.qml | 1 + .../AppLayouts/Chat/views/ChatContextMenuView.qml | 3 ++- .../AppLayouts/Chat/views/CommunityColumnView.qml | 2 +- .../AppLayouts/Chat/views/CommunitySettingsView.qml | 4 ++-- ui/app/AppLayouts/Chat/views/ContactsColumnView.qml | 1 + ui/imports/shared/views/chat/MessageView.qml | 8 +++++++- ui/imports/utils/Utils.qml | 5 +++++ 21 files changed, 80 insertions(+), 26 deletions(-) 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 7d1bd4f58c..acdbb08955 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 @@ -86,6 +86,9 @@ method getChatType*(self: AccessInterface): int {.base.} = method getChatColor*(self: AccessInterface): string {.base.} = raise newException(ValueError, "No implementation available") +method getChatIcon*(self: AccessInterface): string {.base.} = + raise newException(ValueError, "No implementation available") + method amIChatAdmin*(self: AccessInterface): bool {.base.} = 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 9a62810b48..b985a28c29 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 @@ -379,6 +379,10 @@ method getChatColor*(self: Module): string = let chatDto = self.controller.getChatDetails() return chatDto.color +method getChatIcon*(self: Module): string = + let chatDto = self.controller.getChatDetails() + return chatDto.icon + method amIChatAdmin*(self: Module): bool = if(not self.controller.belongsToCommunity()): let chatDto = self.controller.getChatDetails() diff --git a/src/app/modules/main/chat_section/chat_content/messages/view.nim b/src/app/modules/main/chat_section/chat_content/messages/view.nim index 5350b49f93..97206c60fc 100644 --- a/src/app/modules/main/chat_section/chat_content/messages/view.nim +++ b/src/app/modules/main/chat_section/chat_content/messages/view.nim @@ -68,6 +68,9 @@ QtObject: proc getChatColor*(self: View): string {.slot.} = return self.delegate.getChatColor() + proc getChatIcon*(self: View): string {.slot.} = + return self.delegate.getChatIcon() + proc amIChatAdmin*(self: View): bool {.slot.} = return self.delegate.amIChatAdmin() 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 ce9f6b5a16..248f25c1d0 100644 --- a/src/app/modules/main/chat_section/chat_content/module.nim +++ b/src/app/modules/main/chat_section/chat_content/module.nim @@ -338,7 +338,7 @@ method onNotificationsUpdated*(self: Module, hasUnreadMessages: bool, notificati self.view.updateChatDetailsNotifications(hasUnreadMessages, notificationCount) method onChatEdited*(self: Module, chatDto: ChatDto) = - self.view.updateChatDetails(chatDto.name, chatDto.description, chatDto.emoji, chatDto.color, chatDto.chatType == ChatType.OneToOne) + self.view.updateChatDetails(chatDto.name, chatDto.description, chatDto.emoji, chatDto.color, chatDto.icon, chatDto.chatType == ChatType.OneToOne) self.messagesModule.updateChatIdentifier() method onChatRenamed*(self: Module, newName: string) = 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 4e4aef257e..70b02a0584 100644 --- a/src/app/modules/main/chat_section/chat_content/view.nim +++ b/src/app/modules/main/chat_section/chat_content/view.nim @@ -122,12 +122,13 @@ QtObject: proc amIChatAdmin*(self: View): bool {.slot.} = return self.delegate.amIChatAdmin() - proc updateChatDetails*(self: View, name, description, emoji, color: string, ignoreName: bool) = + proc updateChatDetails*(self: View, name, description, emoji, color, icon: string, ignoreName: bool) = if not ignoreName: self.chatDetails.setName(name) self.chatDetails.setDescription(description) self.chatDetails.setEmoji(emoji) self.chatDetails.setColor(color) + self.chatDetails.setIcon(icon) self.chatDetailsChanged() proc updateChatDetailsName*(self: View, name: string) = diff --git a/src/app/modules/main/chat_section/controller.nim b/src/app/modules/main/chat_section/controller.nim index eb59667dc9..2e654c08d7 100644 --- a/src/app/modules/main/chat_section/controller.nim +++ b/src/app/modules/main/chat_section/controller.nim @@ -345,9 +345,9 @@ proc renameGroupChat*(self: Controller, chatId: string, newName: string) = let communityId = if self.isCommunitySection: self.sectionId else: "" self.chatService.renameGroupChat(communityId, chatId, newName) -proc updateGroupChatDetails*(self: Controller, chatId: string, newGroupName: string, newGroupColor: string, newGroupImage: string) = +proc updateGroupChatDetails*(self: Controller, chatId: string, newGroupName: string, newGroupColor: string, newGroupImageJson: string) = let communityId = if self.isCommunitySection: self.sectionId else: "" - self.chatService.updateGroupChatDetails(communityId, chatId, newGroupName, newGroupColor, newGroupImage) + self.chatService.updateGroupChatDetails(communityId, chatId, newGroupName, newGroupColor, newGroupImageJson) proc makeAdmin*(self: Controller, communityID: string, chatId: string, pubKey: string) = self.chatService.makeAdmin(communityID, chatId, pubKey) diff --git a/src/app/modules/main/chat_section/io_interface.nim b/src/app/modules/main/chat_section/io_interface.nim index abf47a8c45..a899df85b3 100644 --- a/src/app/modules/main/chat_section/io_interface.nim +++ b/src/app/modules/main/chat_section/io_interface.nim @@ -115,7 +115,7 @@ method onCommunityChannelDeletedOrChatLeft*(self: AccessInterface, chatId: strin method onChatRenamed*(self: AccessInterface, chatId: string, newName: string) {.base.} = raise newException(ValueError, "No implementation available") -method onGroupChatDetailsUpdated*(self: AccessInterface, chatId: string, newName: string, newColor: string, newImage: string) {.base.} = +method onGroupChatDetailsUpdated*(self: AccessInterface, chatId: string, newName: string, newColor: string, newImageJson: string) {.base.} = raise newException(ValueError, "No implementation available") method onCommunityChannelEdited*(self: AccessInterface, chat: ChatDto) {.base.} = diff --git a/src/app/modules/main/chat_section/module.nim b/src/app/modules/main/chat_section/module.nim index d41596e5c3..be7a9b7896 100644 --- a/src/app/modules/main/chat_section/module.nim +++ b/src/app/modules/main/chat_section/module.nim @@ -146,6 +146,8 @@ proc buildChatSectionUI( blocked = contactDetails.details.isBlocked() colorHash = self.controller.getColorHash(chatDto.id) colorId = self.controller.getColorId(chatDto.id) + elif(chatDto.chatType == ChatType.PrivateGroupChat): + chatImage = chatDto.icon # for group chats only member.admin should be checked, # because channelGroup.admin is alway true @@ -726,8 +728,8 @@ method removeMembersFromGroupChat*(self: Module, communityID: string, chatId: st method renameGroupChat*(self: Module, chatId: string, newName: string) = self.controller.renameGroupChat(chatId, newName) -method updateGroupChatDetails*(self: Module, chatId: string, newGroupName: string, newGroupColor: string, newGroupImage: string) = - self.controller.updateGroupChatDetails(chatId, newGroupName, newGroupColor, newGroupImage) +method updateGroupChatDetails*(self: Module, chatId: string, newGroupName: string, newGroupColor: string, newGroupImageJson: string) = + self.controller.updateGroupChatDetails(chatId, newGroupName, newGroupColor, newGroupImageJson) method makeAdmin*(self: Module, communityID: string, chatId: string, pubKey: string) = self.controller.makeAdmin(communityID, chatId, pubKey) diff --git a/src/app_service/service/chat/dto/chat.nim b/src/app_service/service/chat/dto/chat.nim index baafd9fef3..59b7c0e540 100644 --- a/src/app_service/service/chat/dto/chat.nim +++ b/src/app_service/service/chat/dto/chat.nim @@ -207,7 +207,6 @@ proc toChatDto*(jsonObj: JsonNode): ChatDto = discard jsonObj.getProp("unviewedMentionsCount", result.unviewedMentionsCount) discard jsonObj.getProp("canPost", result.canPost) discard jsonObj.getProp("alias", result.alias) - discard jsonObj.getProp("identicon", result.icon) discard jsonObj.getProp("muted", result.muted) discard jsonObj.getProp("categoryId", result.categoryId) if (result.categoryId == ""): @@ -231,6 +230,13 @@ proc toChatDto*(jsonObj: JsonNode): ChatDto = (chatTypeInt >= ord(low(ChatType)) or chatTypeInt <= ord(high(ChatType)))): result.chatType = ChatType(chatTypeInt) + var chatImage: string + discard jsonObj.getProp("image", chatImage) + if (result.chatType == ChatType.PrivateGroupChat and len(chatImage) > 0): + result.icon = chatImage + else: + discard jsonObj.getProp("identicon", result.icon) + var membersObj: JsonNode if(jsonObj.getProp("members", membersObj)): if(membersObj.kind == JArray): diff --git a/src/app_service/service/chat/service.nim b/src/app_service/service/chat/service.nim index 03983e4665..ecd8778990 100644 --- a/src/app_service/service/chat/service.nim +++ b/src/app_service/service/chat/service.nim @@ -509,21 +509,23 @@ QtObject: except Exception as e: error "error while renaming group chat: ", msg = e.msg - proc updateGroupChatDetails*(self: Service, communityID: string, chatID: string, name: string, color: string, image: string) = + proc updateGroupChatDetails*(self: Service, communityID: string, chatID: string, name: string, color: string, imageJson: string) = try: - let response = status_chat.editChat(communityID, chatID, name, color, image) + let response = status_chat.editChat(communityID, chatID, name, color, imageJson) if (not response.error.isNil): let msg = response.error.message & " chatId=" & chatId error "error while editing group chat details", msg return + let resultedChat = response.result.toChatDto() + var chat = self.chats[chatID] chat.name = name chat.color = color - # TODO set image + chat.icon = resultedChat.icon self.updateOrAddChat(chat) - self.events.emit(SIGNAL_GROUP_CHAT_DETAILS_UPDATED, ChatUpdateDetailsArgs(id: chatID, newName: name, newColor: color, newImage: image)) + self.events.emit(SIGNAL_GROUP_CHAT_DETAILS_UPDATED, ChatUpdateDetailsArgs(id: chatID, newName: name, newColor: color, newImage: resultedChat.icon)) except Exception as e: error "error while updating group chat: ", msg = e.msg diff --git a/src/backend/chat.nim b/src/backend/chat.nim index e1f29589d6..35c06252e6 100644 --- a/src/backend/chat.nim +++ b/src/backend/chat.nim @@ -1,6 +1,7 @@ import json, sequtils, sugar, strutils import core, utils import response_type +import interpret/cropped_image export response_type @@ -134,6 +135,7 @@ proc getLinkPreviewData*(link: string): RpcResponse[JsonNode] {.raises: [Excepti proc getMembers*(communityId, chatId: string): RpcResponse[JsonNode] {.raises: [Exception].} = result = callPrivateRPC("chat_getMembers", %* [communityId, chatId]) -proc editChat*(communityID: string, chatID: string, name: string, color: string, image: string): RpcResponse[JsonNode] {.raises: [Exception].} = - let payload = %* [communityID, chatID, name, color, image] +proc editChat*(communityID: string, chatID: string, name: string, color: string, imageJson: string): RpcResponse[JsonNode] {.raises: [Exception].} = + let croppedImage = newCroppedImage(imageJson) + let payload = %* [communityID, chatID, name, color, croppedImage] return core.callPrivateRPC("chat_editChat", payload) diff --git a/ui/app/AppLayouts/Chat/popups/GroupInfoPopup.qml b/ui/app/AppLayouts/Chat/popups/GroupInfoPopup.qml index 02d259405e..033705a902 100644 --- a/ui/app/AppLayouts/Chat/popups/GroupInfoPopup.qml +++ b/ui/app/AppLayouts/Chat/popups/GroupInfoPopup.qml @@ -66,11 +66,19 @@ StatusModal { } } header.editable: !addMembers && popup.isAdmin - header.icon.isLetterIdenticon: true + header.icon.isLetterIdenticon: { + if (popup.chatDetails && popup.chatDetails.icon !== "") { + return false + } + return true + } header.icon.name: popup.chatDetails ? popup.chatDetails.name : "" header.icon.background.color: popup.chatDetails ? popup.chatDetails.color : "transparent" + header.image.source: popup.chatDetails ? popup.chatDetails.icon : "" - onEditButtonClicked: renameGroupPopup.open() + onEditButtonClicked: { + renameGroupPopup.open() + } onClosed: { chatSectionModule.clearMyContacts() @@ -284,6 +292,7 @@ StatusModal { id: renameGroupPopup activeGroupName: popup.chatDetails ? popup.chatDetails.name : "" activeGroupColor: popup.chatDetails ? popup.chatDetails.color: "" + activeGroupImageData: popup.chatDetails ? popup.chatDetails.icon: "" onUpdateGroupChatDetails: { popup.chatSectionModule.updateGroupChatDetails(popup.chatSectionModule.activeItem.id, groupName, groupColor, groupImage) popup.header.title = groupName diff --git a/ui/app/AppLayouts/Chat/popups/RenameGroupPopup.qml b/ui/app/AppLayouts/Chat/popups/RenameGroupPopup.qml index 0e0117ee5d..d6a8afca05 100644 --- a/ui/app/AppLayouts/Chat/popups/RenameGroupPopup.qml +++ b/ui/app/AppLayouts/Chat/popups/RenameGroupPopup.qml @@ -43,9 +43,7 @@ StatusDialog { colorSelectionGrid.selectedColorIndex = i } - // TODO next phase - // imageEditor.dataImage: root.activeGroupImageData - + imageEditor.dataImage = activeGroupImageData } ColumnLayout { @@ -142,9 +140,12 @@ StatusDialog { id: saveBtn text: qsTr("Save changes") enabled: groupName.text.trim().length > 0 && - ((groupName.text != root.activeGroupName) || (root.activeGroupColor != colorSelectionGrid.selectedColor)) + ((groupName.text != root.activeGroupName) || + (root.activeGroupColor != colorSelectionGrid.selectedColor) || + (String(imageEditor.source).length > 0)) onClicked : { - updateGroupChatDetails(groupName.text, colorSelectionGrid.selectedColor, ""/*imageEditor.dataImage*/) + updateGroupChatDetails(groupName.text, colorSelectionGrid.selectedColor, + Utils.getImageAndCropInfoJson(imageEditor.source, imageEditor.cropRect)) } } } diff --git a/ui/app/AppLayouts/Chat/stores/MessageStore.qml b/ui/app/AppLayouts/Chat/stores/MessageStore.qml index ac4d3f404f..5cdd1f17f5 100644 --- a/ui/app/AppLayouts/Chat/stores/MessageStore.qml +++ b/ui/app/AppLayouts/Chat/stores/MessageStore.qml @@ -93,6 +93,13 @@ QtObject { return messageModule.getChatColor() } + function getChatIcon () { + if(!messageModule) + return "" + + return messageModule.getChatIcon() + } + function amIChatAdmin () { if(!messageModule) return false diff --git a/ui/app/AppLayouts/Chat/views/ChatContentView.qml b/ui/app/AppLayouts/Chat/views/ChatContentView.qml index 592e4cdd4c..4af6f1b581 100644 --- a/ui/app/AppLayouts/Chat/views/ChatContentView.qml +++ b/ui/app/AppLayouts/Chat/views/ChatContentView.qml @@ -209,6 +209,7 @@ ColumnLayout { chatDescription = chatContentModule.chatDetails.description chatEmoji = chatContentModule.chatDetails.emoji chatColor = chatContentModule.chatDetails.color + chatIcon = chatContentModule.chatDetails.icon chatType = chatContentModule.chatDetails.type chatMuted = chatContentModule.chatDetails.muted channelPosition = chatContentModule.chatDetails.position diff --git a/ui/app/AppLayouts/Chat/views/ChatContextMenuView.qml b/ui/app/AppLayouts/Chat/views/ChatContextMenuView.qml index 69b6d3694f..22adf1bb6c 100644 --- a/ui/app/AppLayouts/Chat/views/ChatContextMenuView.qml +++ b/ui/app/AppLayouts/Chat/views/ChatContextMenuView.qml @@ -92,7 +92,8 @@ StatusPopupMenu { onTriggered: { Global.openPopup(renameGroupPopupComponent, { activeGroupName: root.chatName, - activeGroupColor: root.chatColor + activeGroupColor: root.chatColor, + activeGroupImageData: root.chatIcon }); } } diff --git a/ui/app/AppLayouts/Chat/views/CommunityColumnView.qml b/ui/app/AppLayouts/Chat/views/CommunityColumnView.qml index e3867389ec..33ec715319 100644 --- a/ui/app/AppLayouts/Chat/views/CommunityColumnView.qml +++ b/ui/app/AppLayouts/Chat/views/CommunityColumnView.qml @@ -313,7 +313,7 @@ Item { chatId = obj.itemId chatName = obj.name chatDescription = obj.description - + chatIcon = obj.icon chatEmoji = obj.emoji chatColor = obj.color chatType = obj.type diff --git a/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml b/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml index 4c1e7a04e0..98d5ce40fb 100644 --- a/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml +++ b/ui/app/AppLayouts/Chat/views/CommunitySettingsView.qml @@ -156,8 +156,8 @@ StatusAppTwoPanelLayout { item.options.requestToJoinEnabled ? Constants.communityChatOnRequestAccess : Constants.communityChatPublicAccess, item.color.toString().toUpperCase(), item.selectedTags, - JSON.stringify({imagePath: String(item.logoImagePath).replace("file://", ""), cropRect: item.logoCropRect}), - JSON.stringify({imagePath: String(item.bannerPath).replace("file://", ""), cropRect: item.bannerCropRect}), + Utils.getImageAndCropInfoJson(item.logoImagePath, item.logoCropRect), + Utils.getImageAndCropInfoJson(item.bannerPath, item.bannerCropRect), item.options.archiveSupportEnabled, item.options.pinMessagesEnabled ) diff --git a/ui/app/AppLayouts/Chat/views/ContactsColumnView.qml b/ui/app/AppLayouts/Chat/views/ContactsColumnView.qml index a7ff702217..ab0f56856d 100644 --- a/ui/app/AppLayouts/Chat/views/ContactsColumnView.qml +++ b/ui/app/AppLayouts/Chat/views/ContactsColumnView.qml @@ -184,6 +184,7 @@ Item { chatDescription = obj.description chatEmoji = obj.emoji chatColor = obj.color + chatIcon = obj.icon chatType = obj.type chatMuted = obj.muted } diff --git a/ui/imports/shared/views/chat/MessageView.qml b/ui/imports/shared/views/chat/MessageView.qml index 301d21edec..a7891f3942 100644 --- a/ui/imports/shared/views/chat/MessageView.qml +++ b/ui/imports/shared/views/chat/MessageView.qml @@ -298,7 +298,13 @@ Loader { chatColor: root.messageStore.getChatColor() chatEmoji: root.channelEmoji amIChatAdmin: root.messageStore.amIChatAdmin() - chatIcon: root.senderIconToShow + chatIcon: { + if ((root.messageStore.getChatType() === Constants.chatType.privateGroupChat) && + root.messageStore.getChatIcon() !== "") { + return root.messageStore.getChatIcon() + } + return root.senderIconToShow + } } } diff --git a/ui/imports/utils/Utils.qml b/ui/imports/utils/Utils.qml index a703db216b..d1f1731e90 100644 --- a/ui/imports/utils/Utils.qml +++ b/ui/imports/utils/Utils.qml @@ -697,6 +697,11 @@ QtObject { return msg.includes("account already exists") } + // See also: backend/interpret/cropped_image.nim + function getImageAndCropInfoJson(imgPath, cropRect) { + return JSON.stringify({imagePath: String(imgPath).replace("file://", ""), cropRect: cropRect}) + } + // Leave this function at the bottom of the file as QT Creator messes up the code color after this function isPunct(c) { return /(!|\@|#|\$|%|\^|&|\*|\(|\)|_|\+|\||-|=|\\|{|}|[|]|"|;|'|<|>|\?|,|\.|\/)/.test(c)