diff --git a/src/apps/qml/qml/ActiveChat.qml b/src/apps/qml/qml/ActiveChat.qml index 5a5cd3f5..827a78a8 100644 --- a/src/apps/qml/qml/ActiveChat.qml +++ b/src/apps/qml/qml/ActiveChat.qml @@ -1,260 +1,263 @@ /* Copyright (c) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License or ( at your option ) version 3 or, at the discretion of KDE e.V. ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.9 import QtQuick.Controls 2.5 as QQC2 import org.kde.kirigami 2.7 as Kirigami import "messages" ListView { id: activeChat clip: true cacheBuffer: height > 0 ? height : 0 // full height, so page-up/page-down is smooth function scrollPageUp() { var y = contentY - originY; if (y === 0) { // we're already at the top => try to request more history activeChat.moreHistoryRequested() } var newY = Math.max(y - height, 0); activeChat.contentY = newY + originY; } function scrollPageDown() { var y = contentY - originY; var newY = Math.min(contentY - originY + height, contentHeight - height); activeChat.contentY = newY + originY; } signal openDirectChannel(string userName) signal openChannel(string channel) signal jitsiCallConfActivated() signal deleteMessage(string messageId) signal reportMessage(string messageId) signal downloadAttachment(string url) signal editMessage(string messageId, string messageStr) signal copyMessage(string messageId, string messageStr) signal replyMessage(string messageId) signal setFavoriteMessage(string messageId, bool starred) signal displayImage(url imageUrl, string title, bool isAnimatedImage) signal deleteReaction(string messageId, string emoji) signal addReaction(string messageId, string emoji) signal ignoreUser(string userId, bool ignored) signal pinMessage(string messageId, bool pinned) signal createDiscussion(string messageId, string originalMessage) signal openDiscussion(string discussionRoomId) signal openThread(string threadMessageId, string threadPreviewText) signal replyInThread(string messageId) signal showUserInfo(string userId) signal showOriginalOrTranslatedMessage(string messageId, bool showOriginal) signal showDisplayAttachment(string messageId, bool displayAttachment) signal moreHistoryRequested() property QtObject rcAccount + property string roomId: "" property bool enableEditingMode: false property bool wasAtYEnd: true property bool useMenuMessage: true spacing: 0//Kirigami.Units.smallSpacing highlightRangeMode: ListView.ApplyRange preferredHighlightBegin: currentItem === null ? parent.height : parent.height - currentItem.height preferredHighlightEnd: parent.height Keys.onPressed: { if (event.key === Qt.Key_PageUp || event.key === Qt.Key_PageDown) { if (event.key === Qt.Key_PageUp) { activeChat.scrollPageUp(); } else { activeChat.scrollPageDown(); } event.accepted = true; } } onMovementEnded: { if (activeChat.atYBeginning) { activeChat.moreHistoryRequested() } } onAtYEndChanged: { // Remember if we were at the bottom, for when onContentHeight is called if (wasAtYEnd != atYEnd) { wasAtYEnd = atYEnd; } } onContentHeightChanged: { // This is supposed to be emitted only when messages are added or removed. // TODO: Apparently it is also emitted when just scrolling up and down, too... Why? // I guess because items are loaded on demand, and implicitHeight depends on loaded.item.implicitHeight? //console.log("height=" + contentHeight + " using wasAtYEnd=" + wasAtYEnd + " changingRooms=" + changingRooms); if (contentHeight > 0 && (wasAtYEnd)) { positionViewAtEnd(); } } Component.onCompleted: positionViewAtEnd() Connections { target: appid.rocketChatAccount onSwitchedRooms: { positionViewAtEnd(); } } visible: count > 0 delegate: FancyMessageDelegate { width: activeChat.width i_originalMessage: originalMessage i_messageText: messageConverted i_username: username i_usernameurl: usernameurl i_aliasname: alias i_systemMessageType: type i_timestamp: timestamp i_messageID: messageID i_messageType: messagetype - i_avatar: avatar == "" ? rcAccount.avatarUrl(userID) : avatar + i_avatar: avatar == "" ? activeChat.rcAccount.avatarUrl(userID) : avatar i_urls: urls i_attachments: attachments i_reactions: reactions i_roles: roles i_date: date - i_own_username: rcAccount.userName + i_own_username: activeChat.rcAccount.userName i_can_edit_message: canEditMessage i_starred: starred i_pinned: pinned i_editedByUserName: editedByUsername i_user_ignored: userIsIgnored i_dcount: discussionCount i_drid: discussionRoomId i_tcount: threadCount i_threadPreview: threadMessagePreview i_tmid: threadMessageId i_groupable: groupable i_useMenuMessage: useMenuMessage i_showTranslatedMessage: showTranslatedMessage + rcAccount: activeChat.rcAccount + onOpenChannel: { activeChat.openChannel(channel) } onPinMessage: { activeChat.pinMessage(messageId, pinned) } onOpenDirectChannel: { if (rcAccount.userName !== userName) { activeChat.openDirectChannel(userName) } } onJitsiCallConfActivated: { activeChat.jitsiCallConfActivated() } onDeleteMessage: { activeChat.deleteMessage(messageId) } onReportMessage: { activeChat.reportMessage(messageId) } onDownloadAttachment: { activeChat.downloadAttachment(url) } onEditMessage: { activeChat.editMessage(messageId, messageStr) } onCopyMessage: { activeChat.copyMessage(messageId, messageStr) } onReplyMessage: { activeChat.replyMessage(messageId) } onSetFavoriteMessage: { activeChat.setFavoriteMessage(messageId, starred) } onDisplayImage: { activeChat.displayImage(imageUrl, title, isAnimatedImage) } onDeleteReaction: { activeChat.deleteReaction(messageId, emoji) } onAddReaction: { activeChat.addReaction(messageId, emoji) } onIgnoreUser: { activeChat.ignoreUser(userID, ignored) } onCreateDiscussion: { activeChat.createDiscussion(messageId, originalMessage) } onOpenDiscussion: { activeChat.openDiscussion(discussionRoomId) } onOpenThread: { activeChat.openThread(threadMessageId, threadPreviewText) } onReplyInThread: { activeChat.replyInThread(messageId) } onShowUserInfo: { activeChat.showUserInfo(userID) } onShowOriginalOrTranslatedMessage: { activeChat.showOriginalOrTranslatedMessage(messageId, showOriginal) } onShowDisplayAttachment: { activeChat.showDisplayAttachment(messageId, displayAttachment) //TODO } } // always show the scrollbar, also to tell whether we're really looking at the bottom of the list right away QQC2.ScrollBar.vertical: QQC2.ScrollBar { id: __verticalScrollBar policy: QQC2.ScrollBar.AlwaysOn } // FIXME: Disabled this code path since it easily crashes the QML engine when switching quickly between rooms. // // See backtrace below // #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50 // #1 0x00007ffff45fa899 in __GI_abort () at abort.c:79 // #2 0x00007ffff4c13cd6 in qt_message_fatal (context=..., message=...) at /home/kfunk/devel/src/qt5.12/qtbase/src/corelib/global/qlogging.cpp:1907 // #3 0x00007ffff4c0fe40 in QMessageLogger::fatal (this=0x7fffffffb420, msg=0x7ffff4fb9ec8 "ASSERT: \"%s\" in file %s, line %d") at /home/kfunk/devel/src/qt5.12/qtbase/src/corelib/global/qlogging.cpp:888 // #4 0x00007ffff4c0698c in qt_assert (assertion=0x7ffff6f33000 "index >=0 && index < count(group)", file=0x7ffff6f32fb0 "/home/kfunk/devel/src/qt5.12/qtdeclarative/src/qml/util/qqmllistcompositor.cpp", line=365) at /home/kfunk/devel/src/qt5.12/qtbase/src/corelib/global/qglobal.cpp:3212 // #5 0x00007ffff6aa9872 in QQmlListCompositor::find (this=0x61700009f8e0, group=QQmlListCompositor::Default, index=99) at /home/kfunk/devel/src/qt5.12/qtdeclarative/src/qml/util/qqmllistcompositor.cpp:365 // #6 0x00007ffff6ea5159 in QQmlDelegateModelPrivate::stringValue (this=0x61700009f800, group=QQmlListCompositor::Default, index=99, name=...) at /home/kfunk/devel/src/qt5.12/qtdeclarative/src/qml/types/qqmldelegatemodel.cpp:1132 // #7 0x00007ffff6ea544e in QQmlDelegateModel::stringValue (this=0x60300090af00, index=99, name=...) at /home/kfunk/devel/src/qt5.12/qtdeclarative/src/qml/types/qqmldelegatemodel.cpp:1155 // #8 0x00007ffff75c5867 in QQuickListViewPrivate::updateSections (this=0x61d0001ed280) at /home/kfunk/devel/src/qt5.12/qtdeclarative/src/quick/items/qquicklistview.cpp:1205 // ... // // section { // delegate: NewDateLabel { // date: section // width: activeChat.width // } // property: "date" // labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart // } } diff --git a/src/apps/qml/qml/FancyMessageDelegate.qml b/src/apps/qml/qml/FancyMessageDelegate.qml index 940cc21e..5816d23e 100644 --- a/src/apps/qml/qml/FancyMessageDelegate.qml +++ b/src/apps/qml/qml/FancyMessageDelegate.qml @@ -1,348 +1,167 @@ /* * Copyright 2016 Riccardo Iaconelli * Copyright (c) 2017-2020 Laurent Montel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ import QtQuick 2.9 import QtQuick.Controls 2.5 import org.kde.kirigami 2.7 as Kirigami import QtQuick.Layouts 1.12 import Ruqola 1.0 -Rectangle { +import "messages/" - id: messageMain +Rectangle { + id: root property string i_messageID property string i_originalMessage property string i_messageText property string i_username property string i_usernameurl property bool i_systemMessage property string i_systemMessageType property string i_avatar property string i_aliasname property string i_editedByUserName property string i_timestamp property var i_messageType property var i_urls property var i_attachments property var i_reactions property string i_roles property string i_date property string i_own_username property bool i_can_edit_message property bool i_starred property bool i_user_ignored property bool i_pinned property int i_dcount property string i_drid property string i_tmid property string i_threadPreview property int i_tcount property bool i_groupable property bool i_useMenuMessage property bool i_showTranslatedMessage - + property QtObject rcAccount color: RuqolaSingleton.backgroundColor - implicitHeight: 2*Kirigami.Units.smallSpacing + loaded.item.implicitHeight + implicitHeight: loaded.item ? 2*Kirigami.Units.smallSpacing + loaded.item.implicitHeight : 0 implicitWidth: 150 - + signal openDirectChannel(string userName) signal openChannel(string channel) + signal linkActivated(string link) signal jitsiCallConfActivated() signal deleteMessage(string messageId) signal reportMessage(string messageId) - signal downloadAttachment(string url) - signal editMessage(string messageId, string messageStr) signal copyMessage(string messageId, string messageStr) + signal editMessage(string messageId, string messageStr) signal replyMessage(string messageId) signal setFavoriteMessage(string messageId, bool starred) + signal downloadAttachment(string url) signal displayImage(url imageUrl, string title, bool isAnimatedImage) signal deleteReaction(string messageId, string emoji) signal addReaction(string messageId, string emoji) signal ignoreUser(bool ignored) signal pinMessage(string messageId, bool pinned) signal createDiscussion(string messageId, string originalMessage) signal openDiscussion(string discussionRoomId) signal openThread(string threadMessageId, string threadPreviewText) signal replyInThread(string messageId) signal showUserInfo() signal showOriginalOrTranslatedMessage(string messageId, bool showOriginal) signal showDisplayAttachment(string messageId, bool displayAttachment) + + Component { + id: jitsiMessageComponent + JitsiVideoMessage { messageMain: root } + } + Component { + id: systemMessageComponent + SystemMessage { messageMain: root } + } + Component { + id: userMessageComponent + UserMessage { messageMain: root } + } + Component { + id: attachmentMessageAudioComponent + AttachmentMessageAudio { messageMain: root } + } + Component { + id: attachmentMessageVideoComponent + AttachmentMessageVideo { messageMain: root } + } + Component { + id: attachmentMessageImageComponent + AttachmentMessageImage { messageMain: root } + } + Loader { id: loaded anchors { fill: parent margins: Kirigami.Units.largeSpacing } - Component.onCompleted: { + function getComponent() { if (i_messageType === Message.System) { if (i_systemMessageType === "jitsi_call_started") { - setSource("messages/JitsiVideoMessage.qml", - { - i_messageText: i_messageText, - i_username: i_username, - i_aliasname: i_aliasname, - i_timestamp: i_timestamp, - i_systemMessageType: i_systemMessageType, - i_messageID: i_messageID, - i_avatar: i_avatar, - i_date: i_date, - i_useMenuMessage: i_useMenuMessage, - i_showTranslatedMessage: i_showTranslatedMessage, - rcAccount: appid.rocketChatAccount - } - ) + return jitsiMessageComponent; } else { - setSource("messages/SystemMessage.qml", - { - i_messageText: i_messageText, - i_username: i_username, - i_aliasname: i_aliasname, - i_timestamp: i_timestamp, - i_systemMessageType: i_systemMessageType, - i_messageID: i_messageID, - i_date: i_date, - rcAccount: appid.rocketChatAccount, - i_dcount: i_dcount, - i_drid: i_drid, - i_tcount: i_tcount, - i_useMenuMessage: i_useMenuMessage, - i_showTranslatedMessage: i_showTranslatedMessage, - i_groupable: i_groupable, - i_tmid: i_tmid - } - ) + return systemMessageComponent; } } else if (i_messageType === Message.NormalText || i_messageType === Message.File) { - setSource("messages/UserMessage.qml", - { - i_originalMessage: i_originalMessage, - i_messageText: i_messageText, - i_username: i_username, - i_usernameurl: i_usernameurl, - i_aliasname: i_aliasname, - i_timestamp: i_timestamp, - i_messageID: i_messageID, - i_avatar: i_avatar, - i_urls: i_urls, - i_reactions: i_reactions, - i_roles: i_roles, - i_attachments: i_attachments, - i_date: i_date, - i_own_username: i_own_username, - rcAccount: appid.rocketChatAccount, - i_can_edit_message: i_can_edit_message, - i_editedByUserName: i_editedByUserName, - i_starred: i_starred, - i_pinned: i_pinned, - i_user_ignored : i_user_ignored, - i_dcount: i_dcount, - i_drid: i_drid, - i_tcount: i_tcount, - i_groupable: i_groupable, - i_tmid: i_tmid, - i_useMenuMessage: i_useMenuMessage, - i_showTranslatedMessage: i_showTranslatedMessage, - i_threadPreview: i_threadPreview - - } - ) + return userMessageComponent; } else if (i_messageType === Message.Audio) { - setSource("messages/AttachmentMessageAudio.qml", - { - i_messageText: i_messageText, - i_username: i_username, - i_usernameurl: i_usernameurl, - i_aliasname: i_aliasname, - i_timestamp: i_timestamp, - i_messageID: i_messageID, - i_avatar: i_avatar, - i_reactions: i_reactions, - i_roles: i_roles, - i_urls: i_urls, - i_attachments: i_attachments, - i_date: i_date, - i_editedByUserName: i_editedByUserName, - rcAccount: appid.rocketChatAccount, - i_editedByUserName: i_editedByUserName, - i_starred: i_starred, - i_pinned: i_pinned, - i_dcount: i_dcount, - i_drid: i_drid, - i_tcount: i_tcount, - i_groupable: i_groupable, - i_useMenuMessage: i_useMenuMessage, - i_showTranslatedMessage: i_showTranslatedMessage, - i_tmid: i_tmid - }) + return attachmentMessageAudioComponent; } else if (i_messageType === Message.Video) { - setSource("messages/AttachmentMessageVideo.qml", - { - i_messageText: i_messageText, - i_username: i_username, - i_usernameurl: i_usernameurl, - i_aliasname: i_aliasname, - i_timestamp: i_timestamp, - i_messageID: i_messageID, - i_avatar: i_avatar, - i_reactions: i_reactions, - i_roles: i_roles, - i_urls: i_urls, - i_attachments: i_attachments, - i_date: i_date, - i_editedByUserName: i_editedByUserName, - rcAccount: appid.rocketChatAccount, - i_editedByUserName: i_editedByUserName, - i_starred: i_starred, - i_pinned: i_pinned, - i_dcount: i_dcount, - i_drid: i_drid, - i_tcount: i_tcount, - i_groupable: i_groupable, - i_useMenuMessage: i_useMenuMessage, - i_showTranslatedMessage: i_showTranslatedMessage, - i_tmid: i_tmid - }) + return attachmentMessageVideoComponent; } else if (i_messageType === Message.Image) { - setSource("messages/AttachmentMessageImage.qml", - { - i_messageText: i_messageText, - i_username: i_username, - i_usernameurl: i_usernameurl, - i_aliasname: i_aliasname, - i_timestamp: i_timestamp, - i_messageID: i_messageID, - i_avatar: i_avatar, - i_reactions: i_reactions, - i_roles: i_roles, - i_urls: i_urls, - i_attachments: i_attachments, - i_date: i_date, - i_editedByUserName: i_editedByUserName, - rcAccount: appid.rocketChatAccount, - i_editedByUserName: i_editedByUserName, - i_starred: i_starred, - i_pinned: i_pinned, - i_dcount: i_dcount, - i_drid: i_drid, - i_tcount: i_tcount, - i_useMenuMessage: i_useMenuMessage, - i_groupable: i_groupable, - i_showTranslatedMessage: i_showTranslatedMessage, - i_tmid: i_tmid - }) - - } else { - console.log(RuqolaDebugCategorySingleton.category, "Unknown message type: " + i_messageType) + return attachmentMessageImageComponent; } + console.warning(RuqolaDebugCategorySingleton.category, "Unknown message type: " + i_messageType) + return null; } + + sourceComponent: getComponent() } - Connections { - target: loaded.item - onLinkActivated: { - var username = RuqolaUtils.extractRoomUserFromUrl(link); - if (link.startsWith("ruqola:/room/")) { - messageMain.openChannel(username) - } else if (link.startsWith("ruqola:/user/")) { - if (username !== appid.rocketChatAccount.userName) { - messageMain.openDirectChannel(username) - } - } else { - RuqolaUtils.openUrl(link); + + onLinkActivated: { + var username = RuqolaUtils.extractRoomUserFromUrl(link); + if (link.startsWith("ruqola:/room/")) { + messageMain.openChannel(username) + } else if (link.startsWith("ruqola:/user/")) { + if (username !== appid.rocketChatAccount.userName) { + messageMain.openDirectChannel(username) } + } else { + RuqolaUtils.openUrl(link); } - onJitsiCallConfActivated: { - messageMain.jitsiCallConfActivated() - } - onPinMessage: { - messageMain.pinMessage(messageId, pinned) - } - onReportMessage: { - messageMain.reportMessage(messageId) - } - onDeleteMessage: { - messageMain.deleteMessage(messageId) - } - onDownloadAttachment: { - messageMain.downloadAttachment(url) - } - onEditMessage: { - //console.log(RuqolaDebugCategorySingleton.category, "i_messageText " + i_messageText); - messageMain.editMessage(messageId, messageStr) - } - onCopyMessage: { - //console.log(RuqolaDebugCategorySingleton.category, "i_messageText " + i_messageText); - messageMain.copyMessage(messageId, messageStr) - } - onReplyMessage: { - messageMain.replyMessage(messageId) - } - onSetFavoriteMessage: { - messageMain.setFavoriteMessage(messageId, starred) - } - onDisplayImage: { - messageMain.displayImage(imageUrl, title, isAnimatedImage) - } - onDeleteReaction: { - messageMain.deleteReaction(messageId, emoji) - } - onAddReaction: { - messageMain.addReaction(messageId, emoji) - } - onIgnoreUser: { - messageMain.ignoreUser(ignored) - } - onCreateDiscussion: { - messageMain.createDiscussion(messageId, originalMessage) - } - onOpenDiscussion: { - messageMain.openDiscussion(discussionRoomId) - } - onOpenThread: { - messageMain.openThread(threadMessageId, threadPreviewText) - } - onReplyInThread: { - //console.log(RuqolaDebugCategorySingleton.category, "onReplyInThread: " + messageId) - messageMain.replyInThread(messageId) - } - onShowUserInfo: { - messageMain.showUserInfo() - } - onShowOriginalOrTranslatedMessage: { - messageMain.showOriginalOrTranslatedMessage(messageId, showOriginal) - console.log("onShowOriginalOrTranslatedMessage: " + messageId) - } - onShowDisplayAttachment: { - messageMain.showDisplayAttachment(messageId, displayAttachment) - //TODO - } - } } diff --git a/src/apps/qml/qml/messages/AttachmentMessageAudio.qml b/src/apps/qml/qml/messages/AttachmentMessageAudio.qml index 4affb7b2..fd9c9049 100644 --- a/src/apps/qml/qml/messages/AttachmentMessageAudio.qml +++ b/src/apps/qml/qml/messages/AttachmentMessageAudio.qml @@ -1,165 +1,164 @@ /* Copyright (c) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License or ( at your option ) version 3 or, at the discretion of KDE e.V. ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.9 import QtMultimedia 5.8 import QtQuick.Controls 2.5 as QQC2 import org.kde.kirigami 2.7 as Kirigami import QtQuick.Layouts 1.12 import Ruqola 1.0 import "../js/convert.js" as ConvertScript; import "../common" MessageBase { - id: attachmentAudio - + id: root RowLayout { AvatarImage { id: avatarRect avatarurl: i_avatar aliasname: i_aliasname username: i_username onShowUserInfo: { //TODO } } Repeater { id: repearterAttachments model: i_attachments MediaPlayer { id: audioPlayer autoPlay: false onPaused: { playerButton.source = "media-playback-start" } onPlaying: { playerButton.source = "media-playback-pause" } onStopped: { playerButton.source = "media-playback-start" playerSlider.value=0 } onPositionChanged: { playerSlider.sync = true playerSlider.value = audioPlayer.position / audioPlayer.duration playerSlider.sync = false timeLabel.text = ConvertScript.convertTimeString(audioPlayer.position) + "/" + ConvertScript.convertTimeString(audioPlayer.duration) } source: rcAccount.attachmentUrl(model.modelData.link) } ColumnLayout { Layout.fillWidth: true QQC2.Label { //TODO remove duplicate code text: model.modelData.title === "" ? "" : i18n("File Uploaded: %1", model.modelData.title) textFormat: Text.PlainText visible: model.modelData.title !== "" wrapMode: QQC2.Label.Wrap anchors.leftMargin: Kirigami.Units.smallSpacing anchors.rightMargin: Kirigami.Units.smallSpacing } RowLayout { Kirigami.Icon { id: playerButton source: "media-playback-start" width: height height: Kirigami.Units.iconSizes.huge MouseArea { anchors.fill: parent onClicked: { console.log(RuqolaDebugCategorySingleton.category, "Click on download audio file"); if (repearterAttachments.audioPlayer.source !== "") { if (repearterAttachments.audioPlayer.playbackState === MediaPlayer.PlayingState) { repearterAttachments.audioPlayer.pause() playerButton.source = "media-playback-start" } else { repearterAttachments.audioPlayer.play() playerButton.source = "media-playback-pause" } } else { console.log(RuqolaDebugCategorySingleton.category, "Audio file no found"); } } } } QQC2.Slider { id: playerSlider Layout.fillWidth: true property bool sync: false onValueChanged: { if (!sync) { audioPlayer.seek(value * audioPlayer.duration) } } } QQC2.Label { id: timeLabel //TODO display real value text: "00:00/00:00" } DownloadButton { id: download onDownloadButtonClicked: { messageMain.downloadAttachment(model.modelData.link) } } } QQC2.Label { text: model.modelData.description visible: model.modelData.description !== "" wrapMode: QQC2.Label.Wrap anchors.leftMargin: Kirigami.Units.smallSpacing anchors.rightMargin: Kirigami.Units.smallSpacing } } } RowLayout { RepeaterReactions { id: repearterReactions model: i_reactions onAddReaction: { messageMain.addReaction(i_messageID, emoji) } onDeleteReaction: { - attachmentAudio.deleteReaction(i_messageID, emoji) + messageMain.deleteReaction(i_messageID, emoji) } } } TimestampText { id: timestampText timestamp: i_timestamp } } } diff --git a/src/apps/qml/qml/messages/AttachmentMessageImage.qml b/src/apps/qml/qml/messages/AttachmentMessageImage.qml index 21b7a871..c8c5e0e5 100644 --- a/src/apps/qml/qml/messages/AttachmentMessageImage.qml +++ b/src/apps/qml/qml/messages/AttachmentMessageImage.qml @@ -1,255 +1,255 @@ /* Copyright (c) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License or ( at your option ) version 3 or, at the discretion of KDE e.V. ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.9 import QtQuick.Controls 2.5 as QQC2 import org.kde.kirigami 2.7 as Kirigami import Ruqola 1.0 import QtQuick.Layouts 1.12 import "../common" MessageBase { - id: messageMain + id: root Loader { id: messageMenuLoader active: false property var posX property var posY sourceComponent :MessageMenu { id: menu x: messageMenuLoader.posX y: messageMenuLoader.posY can_edit_message: i_can_edit_message starred: i_starred Component.onCompleted: { open() } onAboutToHide: { messageMenuLoader.active = false } } } RowLayout { AvatarImage { id: avatarRect avatarurl: i_avatar aliasname: i_aliasname username: i_username onShowUserInfo: { //TODO } } ColumnLayout { QQC2.Label { id: usernameLabel Layout.alignment: Qt.AlignLeft font.bold: true text: i_aliasname + ' ' + i_usernameurl + (i_editedByUserName === "" ? "" : " " + i18n("(edited by %1)", i_editedByUserName)) height: avatarRect.height onLinkActivated: messageMain.linkActivated(link) MouseArea { anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { if (i_useMenuMessage) { if (mouse.button === Qt.RightButton) { messageMenuLoader.posX = mouse.x messageMenuLoader.posY = mouse.y if (messageMenuLoader.active) messageMenuLoader.active = false else messageMenuLoader.active = true } } } } visible: !i_groupable } Repeater { id: repearterAttachments model: i_attachments Row { spacing: Kirigami.Units.smallSpacing Column { QQC2.Label { id: imageTitle text: model.modelData.title === "" ? "" : model.modelData.imageTitle visible: model.modelData.title !== "" wrapMode: QQC2.Label.NoWrap anchors.leftMargin: Kirigami.Units.smallSpacing anchors.rightMargin: Kirigami.Units.smallSpacing textFormat: Text.RichText onLinkActivated: { messageMain.displayImage(imageUrl.source, model.modelData.title, model.modelData.isAnimatedImage) } MouseArea { anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { if (mouse.button === Qt.RightButton) { messageMenuLoader.posX = mouse.x messageMenuLoader.posY = mouse.y if (messageMenuLoader.active) messageMenuLoader.active = false else messageMenuLoader.active = true } } } } Image { id: imageUrl visible: model.modelData.isAnimatedImage readonly property int imageHeight: model.modelData.imageHeight === -1 ? 200 : Math.min(200, model.modelData.imageHeight) source: rcAccount.attachmentUrl(model.modelData.link) asynchronous: true fillMode: Image.PreserveAspectFit //Don't use really imageWidth otherwise it will be too big width: 200 //model.modelData.imageWidth === -1 ? 200 : model.modelData.imageWidth height: 0 sourceSize.width: 200 sourceSize.height: 200 onStatusChanged: { if(status == Image.Error){ console.log(RuqolaDebugCategorySingleton.category, "Image load error! Trying to reload. " + source) } } MouseArea { anchors.fill: parent onClicked: { if(status === Image.Error) { console.log(RuqolaDebugCategorySingleton.category, "Image not loaded."); } else { messageMain.displayImage(imageUrl.source, imageTitle.text, model.modelData.isAnimatedImage) } } } } AnimatedImage { id: imageAnimatedUrl visible: model.modelData.isAnimatedImage readonly property int imageHeight: model.modelData.imageHeight === -1 ? 200 : Math.min(200, model.modelData.imageHeight) source: rcAccount.attachmentUrl(model.modelData.link) asynchronous: true fillMode: Image.PreserveAspectFit //Don't use really imageWidth otherwise it will be too big width: 200 //model.modelData.imageWidth === -1 ? 200 : model.modelData.imageWidth height: 0 onStatusChanged: { if(status == Image.Error){ console.log(RuqolaDebugCategorySingleton.category, "Image load error! Trying to reload. " + source) } } onHeightChanged: { playing = height > 0; } MouseArea { anchors.fill: parent onClicked: { if(status === Image.Error) { console.log(RuqolaDebugCategorySingleton.category, "Image not loaded."); } else { messageMain.displayImage(imageAnimatedUrl.source, imageTitle.text, model.modelData.isAnimatedImage) } } } } QQC2.Label { text: model.modelData.description wrapMode: QQC2.Label.Wrap anchors.leftMargin: Kirigami.Units.smallSpacing anchors.rightMargin: Kirigami.Units.smallSpacing visible: model.modelData.description !== "" MouseArea { anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { if (mouse.button === Qt.RightButton) { menu.x = mouse.x menu.y = mouse.y menu.open(); } } } } } ShowHideButton { targetAnimation: model.modelData.isAnimatedImage ? imageAnimatedUrl : imageUrl defaultHeight: model.modelData.isAnimatedImage ? imageAnimatedUrl.imageHeight : Url.imageHeight onHiddenChanged: { messageMain.showDisplayAttachment(i_messageID, state) } } DownloadButton { id: download onDownloadButtonClicked: { messageMain.downloadAttachment(model.modelData.link) } } Connections { target: rcAccount onFileDownloaded: { //console.log(RuqolaDebugCategorySingleton.category, " IMAGE SUPPORT: " + filePath + " cacheImageUrl :" + cacheImageUrl + " model.modelData.link: " + model.modelData.link) if (filePath === model.modelData.link) { console.log(RuqolaDebugCategorySingleton.category, "Image updated: " + cacheImageUrl) imageUrl.source = cacheImageUrl; imageAnimatedUrl.source = cacheImageUrl; } } } } } RowLayout { RepeaterReactions { id: repearterReactions model: i_reactions onAddReaction: { messageMain.addReaction(i_messageID, emoji) } onDeleteReaction: { messageMain.deleteReaction(i_messageID, emoji) } } } } Item { Layout.fillWidth: true } TimestampText { id: timestampText timestamp: i_timestamp } } } diff --git a/src/apps/qml/qml/messages/JitsiVideoMessage.qml b/src/apps/qml/qml/messages/JitsiVideoMessage.qml index 5ceff42c..4d7d6b83 100644 --- a/src/apps/qml/qml/messages/JitsiVideoMessage.qml +++ b/src/apps/qml/qml/messages/JitsiVideoMessage.qml @@ -1,91 +1,91 @@ /* * Copyright (C) 2017-2020 Laurent Montel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ import QtQuick 2.9 import QtQuick.Controls 2.5 as QQC2 import org.kde.kirigami 2.7 as Kirigami import QtQuick.Layouts 1.12 import "../js/message.js" as MessageScript; import "../common" MessageBase { - id: messageMain + id: root RowLayout { AvatarImage { id: avatarRect avatarurl: i_avatar aliasname: i_aliasname username: i_username onShowUserInfo: { //TODO } } Item { Layout.fillWidth: true } Rectangle { Layout.alignment: Qt.AlignCenter width: textLabel.implicitWidth + 6*Kirigami.Units.smallSpacing height: textLabel.height color: Kirigami.Theme.disabledTextColor radius: 4*Kirigami.Units.smallSpacing QQC2.Label { id: textLabel color: Kirigami.Theme.textColor opacity: 1 anchors.centerIn: parent anchors.leftMargin: Kirigami.Units.smallSpacing anchors.rightMargin: Kirigami.Units.smallSpacing width: Math.min(implicitWidth, parent.width - Kirigami.Units.largeSpacing) text: i18n("Click To Join to Video") wrapMode: QQC2.Label.Wrap MouseArea { anchors.fill: parent onClicked: { messageMain.jitsiCallConfActivated() } } } } Item { Layout.fillWidth: true } TimestampText { id: timestampText timestamp: i_timestamp } } } diff --git a/src/apps/qml/qml/messages/MessageBase.qml b/src/apps/qml/qml/messages/MessageBase.qml index 3f22a878..42778baf 100644 --- a/src/apps/qml/qml/messages/MessageBase.qml +++ b/src/apps/qml/qml/messages/MessageBase.qml @@ -1,75 +1,29 @@ /* Copyright (c) 2017-2020 Laurent Montel This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License or ( at your option ) version 3 or, at the discretion of KDE e.V. ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.9 import QtQuick.Layouts 1.12 -ColumnLayout { - signal linkActivated(string link) - signal jitsiCallConfActivated() - signal deleteMessage(string messageId) - signal reportMessage(string messageId) - signal copyMessage(string messageId, string messageStr) - signal editMessage(string messageId, string messageStr) - signal replyMessage(string messageId) - signal setFavoriteMessage(string messageId, bool starred) - signal downloadAttachment(string url) - signal displayImage(url imageUrl, string title, bool isAnimatedImage) - signal deleteReaction(string messageId, string emoji) - signal addReaction(string messageId, string emoji) - signal ignoreUser(bool ignored) - signal pinMessage(string messageId, bool pinned) - signal createDiscussion(string messageId, string originalMessage) - signal openDiscussion(string discussionRoomId) - signal openThread(string threadMessageId, string threadPreviewText) - signal replyInThread(string messageId) - signal showUserInfo() - signal showOriginalOrTranslatedMessage(string messageId, bool showOriginal) - signal showDisplayAttachment(string messageId, bool displayAttachment) - - property string i_date - property string i_username - property string i_usernameurl - property string i_aliasname - property string i_avatar - property string i_timestamp - property string i_messageText - property string i_originalMessage - property var i_urls - property var i_attachments - property var i_reactions - property string i_roles - property string i_editedByUserName - property bool i_starred - property bool i_can_edit_message - property bool i_user_ignored - property bool i_pinned - property int i_dcount - property string i_drid - property int i_tcount - property string i_tmid - property bool i_groupable - property string i_threadPreview - property bool i_useMenuMessage - property bool i_showTranslatedMessage +ColumnLayout { + id: main - property QtObject rcAccount + property var messageMain: undefined } diff --git a/src/apps/qml/qml/messages/SystemMessage.qml b/src/apps/qml/qml/messages/SystemMessage.qml index 78aba133..e39ff9fc 100644 --- a/src/apps/qml/qml/messages/SystemMessage.qml +++ b/src/apps/qml/qml/messages/SystemMessage.qml @@ -1,73 +1,73 @@ /* * Copyright 2016 Riccardo Iaconelli * Copyright (c) 2017-2020 Laurent Montel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ import QtQuick 2.9 import org.kde.kirigami 2.7 as Kirigami import QtQuick.Controls 2.5 as QQC2 import QtQuick.Layouts 1.12 import Ruqola 1.0 MessageBase { - id: messageMain + id: root property string i_systemMessageType RowLayout { ColumnLayout { //Layout.fillHeight: true QQC2.Label { id: textLabel Layout.fillWidth: true color: Kirigami.Theme.disabledTextColor opacity: 1 width: parent.width //Layout.alignment: Qt.AlignLeft //anchors.centerIn: parent anchors.leftMargin: Kirigami.Units.smallSpacing anchors.rightMargin: Kirigami.Units.smallSpacing text: i_messageText wrapMode: QQC2.Label.Wrap font.italic: true } DiscussionLabel { id: discussionLabel onOpenDiscussion: { messageMain.openDiscussion(i_drid) console.log(RuqolaDebugCategorySingleton.category, "Click to go to sub room: " + i_drid) } } } Item { Layout.fillWidth: true } TimestampText { id: timestampText timestamp: i_timestamp } } } diff --git a/src/apps/qml/qml/messages/UserMessage.qml b/src/apps/qml/qml/messages/UserMessage.qml index 5b574712..1c586518 100644 --- a/src/apps/qml/qml/messages/UserMessage.qml +++ b/src/apps/qml/qml/messages/UserMessage.qml @@ -1,295 +1,291 @@ /* * Copyright 2016 Riccardo Iaconelli * Copyright (c) 2017-2020 Laurent Montel * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ import QtQuick 2.9 import org.kde.kirigami 2.7 as Kirigami import QtQuick.Controls 2.5 as QQC2 import QtQuick.Layouts 1.12 import Ruqola 1.0 import "../common" -MessageBase { - property string i_messageID - property var i_urls - property var i_attachments - property string i_own_username +MessageBase { + id: root - id: messageMain Layout.alignment: Qt.AlignTop Loader { id: messageMenuLoader active: false property var posX property var posY sourceComponent: MessageMenu { id: menu x: messageMenuLoader.posX y: messageMenuLoader.posY can_edit_message: i_can_edit_message user_ignored : i_user_ignored starred: i_starred pinned_message: i_pinned showTranslatedMessage: i_showTranslatedMessage Component.onCompleted: { open() } onAboutToHide: { messageMenuLoader.active = false; } } } RowLayout { AvatarImage { id: avatarRect avatarurl: i_avatar aliasname: i_aliasname username: i_username onShowUserInfo: { messageMain.showUserInfo(i_own_username) } visible: !i_groupable } ColumnLayout { Layout.fillHeight: true spacing: Kirigami.Units.smallSpacing / 2 // reduce spacing a little RowLayout { QQC2.Label { id: usernameLabel Layout.alignment: Qt.AlignLeft font.bold: true text: i_aliasname + ' ' + i_usernameurl + (i_editedByUserName === "" ? "" : " " + i18n("(edited by %1)", i_editedByUserName)) height: avatarRect.height onLinkActivated: messageMain.linkActivated(link) MouseArea { anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { if (i_useMenuMessage) { if (mouse.button === Qt.RightButton) { messageMenuLoader.posX = mouse.x messageMenuLoader.posY = mouse.y if (messageMenuLoader.active) messageMenuLoader.active = false else messageMenuLoader.active = true } } } } visible: !i_groupable } Kirigami.Icon { id: rolesInfo property var opacityDefaultValue: 0.5 source: "documentinfo" width: height height: 18 visible: i_roles.length > 0 opacity: opacityDefaultValue MouseArea { hoverEnabled: true anchors.fill: parent onEntered: { rolesInfo.opacity = 1.0 } onExited: { rolesInfo.opacity = rolesInfo.opacityDefaultValue } QQC2.ToolTip { id: tooltipRoleInfo text: i_roles } } } } ColumnLayout { id: fullTextColumn Layout.fillWidth: true QQC2.Label { id: threadPreview Layout.fillWidth: true visible: i_threadPreview.length > 0 textFormat: Text.RichText color: "red" //Convert to kirigami color font.pointSize: textLabel.font.pointSize - 1 text: i_threadPreview wrapMode: QQC2.Label.Wrap MouseArea { anchors.fill: parent acceptedButtons: Qt.RightButton | Qt.LeftButton onClicked: { //console.log("open thread " + i_tmid) messageMain.openThread(i_tmid, i_threadPreview) } } } QQC2.Label { id: textLabel Layout.fillWidth: true textFormat: Text.RichText text: i_messageText wrapMode: QQC2.Label.Wrap onLinkActivated: messageMain.linkActivated(link) MouseArea { anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { if (i_useMenuMessage) { if (mouse.button === Qt.RightButton) { messageMenuLoader.posX = mouse.x messageMenuLoader.posY = mouse.y if (messageMenuLoader.active) messageMenuLoader.active = false else messageMenuLoader.active = true } } } } } ColumnLayout { id: urlColumn Layout.fillWidth: true //TODO //Reactivate when we have a parsed url ! //see info about bugs // Repeater { // id: repeaterUrl // model: i_urls // Text { // //Display it only if url != text otherwise it's not necessary // visible: model.modelData.url !== i_originalMessage // width: urlColumn.width // text: model.modelData.description === "" ? // RuqolaUtils.markdownToRichText(model.modelData.url) : // RuqolaUtils.markdownToRichText(model.modelData.description) // wrapMode: QQC2.Label.Wrap // textFormat: Text.RichText // onLinkActivated: messageMain.linkActivated(link) // } // } RowLayout { Layout.fillWidth: true RepeaterReactions { id: repearterReactions model: i_reactions onAddReaction: { messageMain.addReaction(i_messageID, emoji) } onDeleteReaction: { messageMain.deleteReaction(i_messageID, emoji) } } } Repeater { id: repearterAttachments model: i_attachments Column { Text { visible: model.modelData.authorName !== "" width: urlColumn.width text: model.modelData.authorName wrapMode: QQC2.Label.Wrap anchors.leftMargin: Kirigami.Units.smallSpacing anchors.rightMargin: Kirigami.Units.smallSpacing } Row { QQC2.Label { id: attachmentTitle textFormat: Text.RichText visible: model.modelData.title !== "" width: urlColumn.width text: model.modelData.displayTitle wrapMode: QQC2.Label.Wrap anchors.leftMargin: Kirigami.Units.smallSpacing anchors.rightMargin: Kirigami.Units.smallSpacing onLinkActivated: { messageMain.linkActivated(link) } } DownloadButton { id: downloadButton visible: model.modelData.canDownloadAttachment onDownloadButtonClicked: { messageMain.downloadAttachment(model.modelData.link) } } Item { Layout.fillWidth: true } } QQC2.Label { visible: model.modelData.description !== "" width: urlColumn.width text: model.modelData.description wrapMode: QQC2.Label.Wrap anchors.leftMargin: Kirigami.Units.smallSpacing anchors.rightMargin: Kirigami.Units.smallSpacing } } } } } ThreadLabel { Layout.fillWidth: true onOpenThread: { console.log(RuqolaDebugCategorySingleton.category, " OPen thread " + i_messageID) messageMain.openThread(i_messageID, i_messageText) } } } ReactionsPopup { visible: i_useMenuMessage onInsertReaction: { messageMain.addReaction(i_messageID, emoji) } } TimestampText { id: timestampText timestamp: i_timestamp visible: !i_groupable } } }