diff --git a/src/app/chat/view.nim b/src/app/chat/view.nim index 54853d8624..0910442ca2 100644 --- a/src/app/chat/view.nim +++ b/src/app/chat/view.nim @@ -108,6 +108,10 @@ QtObject: self.status.chat.resendMessage(messageId) self.messageList[chatId].resetTimeOut(messageId) + proc sendImage*(self: ChatsView, imagePath: string) {.slot.} = + let image = replace(imagePath, "file://", "") + self.status.chat.sendImage(self.activeChannel.id, image) + proc activeChannelChanged*(self: ChatsView) {.signal.} proc userNameOrAlias*(self: ChatsView, pubKey: string): string {.slot.} = diff --git a/src/status/chat.nim b/src/status/chat.nim index 58f62749c8..efcad1299d 100644 --- a/src/status/chat.nim +++ b/src/status/chat.nim @@ -218,6 +218,13 @@ proc sendMessage*(self: ChatModel, chatId: string, msg: string, replyTo: string for msg in messages: self.events.emit("sendingMessage", MessageArgs(id: msg.id, channel: msg.chatId)) +proc sendImage*(self: ChatModel, chatId: string, image: string) = + var response = status_chat.sendImageMessage(chatId, image) + var (chats, messages) = self.processChatUpdate(parseJson(response)) + self.events.emit("chatUpdate", ChatUpdateArgs(messages: messages, chats: chats, contacts: @[])) + for msg in messages: + self.events.emit("sendingMessage", MessageArgs(id: msg.id, channel: msg.chatId)) + proc addStickerToRecent*(self: ChatModel, sticker: Sticker, save: bool = false) = self.recentStickers.insert(sticker, 0) self.recentStickers = self.recentStickers.deduplicate() diff --git a/src/status/libstatus/chat.nim b/src/status/libstatus/chat.nim index 5147ff41f9..5e9b8c837e 100644 --- a/src/status/libstatus/chat.nim +++ b/src/status/libstatus/chat.nim @@ -83,6 +83,16 @@ proc sendChatMessage*(chatId: string, msg: string, replyTo: string): string = } ]) +proc sendImageMessage*(chatId: string, image: string): string = + callPrivateRPC("sendChatMessage".prefix, %* [ + { + "chatId": chatId, + "contentType": ContentType.Image.int, + "imagePath": image, + "text": "Update to latest version to see a nice image here!" + } + ]) + proc sendStickerMessage*(chatId: string, sticker: Sticker): string = callPrivateRPC("sendChatMessage".prefix, %* [ { diff --git a/ui/app/AppLayouts/Chat/ChatColumn.qml b/ui/app/AppLayouts/Chat/ChatColumn.qml index fc9a76335f..a002d01eaa 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn.qml @@ -10,7 +10,12 @@ import "./data" StackLayout { id: chatColumnLayout property int chatGroupsListViewCount: 0 + property bool isReply: false + property bool isImage: false + + property bool isExtendedInput: isReply || isImage + property var appSettings property bool isConnected: false Layout.fillHeight: true @@ -19,6 +24,25 @@ StackLayout { currentIndex: chatsModel.activeChannelIndex > -1 && chatGroupsListViewCount > 0 ? 0 : 1 + function showReplyArea(){ + isReply = true; + isImage = false; + replyAreaContainer.setup() + } + + function showImageArea(imagePath){ + isImage = true; + isReply = false; + sendImageArea.image = imagePath[0]; + } + + function hideExtendedArea(){ + isImage = false; + isReply = false; + replyAreaContainer.setup(); + sendImageArea.image = ""; + } + ColumnLayout { spacing: 0 @@ -130,10 +154,7 @@ StackLayout { Action { //% "Reply to" text: qsTrId("reply-to") - onTriggered: { - isReply = true; - replyAreaContainer.setup() - } + onTriggered: showReplyArea() } } @@ -166,7 +187,7 @@ StackLayout { Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom Layout.fillWidth: true Layout.preferredWidth: parent.width - height: !isReply ? 70 : 140 + height: !isExtendedInput ? 70 : 140 Layout.preferredHeight: height SuggestionBox { @@ -205,10 +226,27 @@ StackLayout { visible: isReply } + SendImageArea { + id: sendImageArea + visible: isImage + } + ChatInput { id: chatInput height: 40 - anchors.top: !isReply ? inputArea.top : replyAreaContainer.bottom + anchors.top: { + if(!isExtendedInput){ + return inputArea.top; + } + + if(isReply){ + return replyAreaContainer.bottom; + } + + if(isImage){ + return sendImageArea.bottom; + } + } anchors.topMargin: 4 anchors.left: parent.left anchors.right: parent.right diff --git a/ui/app/AppLayouts/Chat/ChatColumn/ChatButtons.qml b/ui/app/AppLayouts/Chat/ChatColumn/ChatButtons.qml index 379af5d333..f3fc43ab41 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/ChatButtons.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/ChatButtons.qml @@ -15,7 +15,7 @@ Item { Button { id: chatSendBtn - visible: txtData.length > 0 + visible: txtData.length > 0 || chatColumn.isImage width: 30 height: 30 text: "" @@ -23,8 +23,15 @@ Item { anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right onClicked: { - chatsModel.sendMessage(txtData.text, chatColumn.isReply ? SelectedMessage.messageId : "") - txtData.text = "" + if(chatColumn.isImage){ + chatsModel.sendImage(sendImageArea.image); + chatColumn.hideExtendedArea(); + } + + if(txtData.text.trim() > 0){ + chatsModel.sendMessage(txtData.text, chatColumn.isReply ? SelectedMessage.messageId : "") + txtData.text = ""; + } } background: Rectangle { color: parent.enabled ? Style.current.blue : Style.current.grey @@ -45,7 +52,11 @@ Item { id: emojiIconContainer width: emojiIcon.width + chatButtonsContainer.iconPadding * 2 height: emojiIcon.height + chatButtonsContainer.iconPadding * 2 - anchors.right: txtData.length == 0 ? stickerIconContainer.left : chatSendBtn.left + anchors.right: { + if(stickerIconContainer.visible) return stickerIconContainer.left; + if(imageIconContainer.visible) return imageIconContainer.left; + return chatSendBtn.left; + } anchors.rightMargin: Style.current.padding - chatButtonsContainer.iconPadding * 2 anchors.verticalCenter: parent.verticalCenter radius: Style.current.radius @@ -91,11 +102,11 @@ Item { property bool hovered: false id: stickerIconContainer - visible: txtData.length == 0 + visible: !chatColumn.isExtendedInput && txtData.length == 0 width: emojiIcon.width + chatButtonsContainer.iconPadding * 2 height: emojiIcon.height + chatButtonsContainer.iconPadding * 2 - anchors.right: parent.right - anchors.rightMargin: Style.current.padding - chatButtonsContainer.iconPadding + anchors.right: imageIconContainer.visible ? imageIconContainer.left : parent.right + anchors.rightMargin: Style.current.padding - chatButtonsContainer.iconPadding * (imageIconContainer.visible ? 2 : 1) anchors.verticalCenter: parent.verticalCenter radius: Style.current.radius color: hovered ? Style.current.lightBlue : Style.current.transparent @@ -136,6 +147,50 @@ Item { } } + Rectangle { + property bool hovered: false + visible: !chatColumn.isExtendedInput && (chatsModel.activeChannel.chatType === Constants.chatTypePrivateGroupChat || chatsModel.activeChannel.chatType === Constants.chatTypeOneToOne) + id: imageIconContainer + width: emojiIcon.width + chatButtonsContainer.iconPadding * 2 + height: emojiIcon.height + chatButtonsContainer.iconPadding * 2 + anchors.right: chatSendBtn.visible ? chatSendBtn.left : parent.right + anchors.rightMargin: Style.current.padding - chatButtonsContainer.iconPadding + anchors.verticalCenter: parent.verticalCenter + radius: Style.current.radius + color: hovered ? Style.current.lightBlue : Style.current.transparent + + Image { + id: imageIcon + width: 20 + height: 20 + fillMode: Image.PreserveAspectFit + source: "../../../img/images_icon.svg" + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + + } + ColorOverlay { + anchors.fill: imageIcon + source: imageIcon + color: imageIconContainer.hovered ? Style.current.blue : Style.current.transparent + } + + MouseArea { + cursorShape: Qt.PointingHandCursor + anchors.fill: parent + hoverEnabled: true + onEntered: { + imageIconContainer.hovered = true + } + onExited: { + imageIconContainer.hovered = false + } + onClicked: { + imageDialog.open(); + } + } + } + StickersPopup { id: stickersPopup width: 360 diff --git a/ui/app/AppLayouts/Chat/ChatColumn/ChatInput.qml b/ui/app/AppLayouts/Chat/ChatColumn/ChatInput.qml index da924a7eee..d44e0fbd45 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/ChatInput.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/ChatInput.qml @@ -2,6 +2,7 @@ import QtQuick 2.13 import QtQuick.Controls 2.13 import QtQuick.Layouts 1.13 import QtMultimedia 5.13 +import QtQuick.Dialogs 1.0 import "../components" import "../../../../shared" import "../../../../imports" @@ -34,6 +35,10 @@ Rectangle { function onEnter(event){ if (event.modifiers === Qt.NoModifier && (event.key === Qt.Key_Enter || event.key === Qt.Key_Return)) { + if(chatColumn.isImage){ + chatsModel.sendImage(sendImageArea.image); + chatColumn.hideExtendedArea(); + } if(txtData.text.trim().length > 0){ let msg = interpretMessage(txtData.text.trim()) @@ -46,6 +51,22 @@ Rectangle { } } + FileDialog { + id: imageDialog + title: qsTr("Please choose an image") + folder: shortcuts.pictures + nameFilters: [ + qsTr("Image files (*.jpg *.jpeg *.png)") + ] + onAccepted: { + chatColumn.showImageArea(imageDialog.fileUrls); + txtData.forceActiveFocus(); + } + onRejected: { + chatColumn.hideExtendedArea(); + } + } + ScrollView { id: scrollView anchors.bottom: parent.bottom diff --git a/ui/app/AppLayouts/Chat/ChatColumn/Message.qml b/ui/app/AppLayouts/Chat/ChatColumn/Message.qml index fd1a2514ee..73075bb71a 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/Message.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/Message.qml @@ -9,7 +9,7 @@ Item { property string userName: "Jotaro Kujo" property string message: "That's right. We're friends... Of justice, that is." property string plainText: "That's right. We're friends... Of justice, that is." - property string identicon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=" + property string identicon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQAQMAAAC6caSPAAAABlBMVEXMzMz////TjRV2AAAAAWJLR0QB/wIt3gAAACpJREFUGBntwYEAAAAAw6D7Uw/gCtUAAAAAAAAAAAAAAAAAAAAAAAAAgBNPsAABAjKCqQAAAABJRU5ErkJggg==" property bool isCurrentUser: false property string timestamp: "1234567" property string sticker: "Qme8vJtyrEHxABcSVGPF95PtozDgUyfr1xGjePmFdZgk9v" diff --git a/ui/app/AppLayouts/Chat/ChatColumn/ReplyArea.qml b/ui/app/AppLayouts/Chat/ChatColumn/ReplyArea.qml index cef39079e8..dec4ee37a6 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/ReplyArea.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/ReplyArea.qml @@ -63,8 +63,7 @@ Rectangle { closeButton.color = Style.current.grey } onClicked: { - reset(); - chatColumn.isReply = false; + chatColumn.hideExtendedArea() } } } diff --git a/ui/app/AppLayouts/Chat/ChatColumn/SendImageArea.qml b/ui/app/AppLayouts/Chat/ChatColumn/SendImageArea.qml new file mode 100644 index 0000000000..df35012583 --- /dev/null +++ b/ui/app/AppLayouts/Chat/ChatColumn/SendImageArea.qml @@ -0,0 +1,69 @@ +import QtQuick 2.13 +import QtQuick.Controls 2.13 +import QtQuick.Layouts 1.13 +import "../../../../imports" +import "../../../../shared" +import "./" + +Rectangle { + id: sendImageArea + height: 70 + + property string image: "" + + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + color: "#00000000" + + Rectangle { + id: closeButton + height: 32 + width: 32 + anchors.top: parent.top + anchors.topMargin: Style.current.padding + anchors.rightMargin: Style.current.padding + anchors.right: parent.right + radius: 8 + + SVGImage { + id: closeModalImg + source: "../../../../shared/img/close.svg" + width: 25 + height: 25 + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + } + + MouseArea { + id: closeImageArea + cursorShape: Qt.PointingHandCursor + anchors.fill: parent + hoverEnabled: true + onExited: { + closeButton.color = Style.current.white + } + onEntered: { + closeButton.color = Style.current.grey + } + onClicked: { + chatColumn.hideExtendedArea(); + } + } + } + + Image { + id: chatImage + width: 36 + height: 36 + anchors.topMargin: 20 + anchors.left: parent.left + anchors.leftMargin: Style.current.padding + anchors.top: parent.top + fillMode: Image.PreserveAspectFit + source: image + mipmap: true + smooth: false + antialiasing: true + } +} \ No newline at end of file diff --git a/ui/app/img/images_icon.svg b/ui/app/img/images_icon.svg new file mode 100644 index 0000000000..5bbaa3b64e --- /dev/null +++ b/ui/app/img/images_icon.svg @@ -0,0 +1,4 @@ + + + +