diff --git a/src/message.cpp b/src/message.cpp index 6b342631..8d210f37 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -1,526 +1,540 @@ /* Copyright (c) 2017-2018 Montel Laurent 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. */ #include "message.h" #include "ruqola_debug.h" #include #include #include Message::Message() { } void Message::parseMessage(const QJsonObject &o) { const QString roomId = o.value(QLatin1String("rid")).toString(); //t ? I can't find it. const QString type = o.value(QLatin1String("t")).toString(); mMessageId = o.value(QLatin1String("_id")).toString(); mRoomId = roomId; mText = o.value(QLatin1String("msg")).toString(); mTimeStamp = (qint64)o.value(QLatin1String("ts")).toObject().value(QLatin1String("$date")).toDouble(); mUsername = o.value(QLatin1String("u")).toObject().value(QLatin1String("username")).toString(); mUserId = o.value(QLatin1String("u")).toObject().value(QLatin1String("_id")).toString(); mUpdatedAt = o.value(QLatin1String("_updatedAt")).toObject().value(QLatin1String("$date")).toDouble(); mEditedAt = o.value(QLatin1String("editedAt")).toObject().value(QLatin1String("$date")).toDouble(); mEditedByUsername = o.value(QLatin1String("editedBy")).toObject().value(QLatin1String("username")).toString(); mEditedByUserId = o.value(QLatin1String("editedBy")).toObject().value(QLatin1String("userID")).toString(); mAlias = o.value(QLatin1String("alias")).toString(); mAvatar = o.value(QLatin1String("avatar")).toString(); mGroupable = o.value(QLatin1String("groupable")).toBool(); mParseUrls = o.value(QLatin1String("parseUrls")).toBool(); //TODO add starred ! mMessageType = Message::MessageType::NormalText; if (!type.isEmpty()) { mSystemMessageType = type; mMessageType = System; } parseMentions(o.value(QLatin1String("mentions")).toArray()); parseAttachment(o.value(QLatin1String("attachments")).toArray()); parseUrls(o.value(QLatin1String("urls")).toArray()); } void Message::parseMentions(const QJsonArray &mentions) { mMentions.clear(); for (int i = 0; i < mentions.size(); i++) { const QJsonObject mention = mentions.at(i).toObject(); mMentions.insert(mention.value(QLatin1String("username")).toString(), mention.value(QLatin1String("_id")).toString()); } } void Message::parseUrls(const QJsonArray &urls) { mUrls.clear(); if (!urls.isEmpty()) { qCDebug(RUQOLA_LOG) << " void Message::urls(const QJsonObject &attachements)"< Message::mentions() const { return mMentions; } void Message::setMentions(const QMap &mentions) { mMentions = mentions; } void Message::parseAttachment(const QJsonArray &attachments) { mAttachements.clear(); if (!attachments.isEmpty()) { qCDebug(RUQOLA_LOG) << " void Message::parseAttachment(const QJsonObject &attachements)"< Message::attachements() const { return mAttachements; } void Message::setAttachements(const QVector &attachements) { mAttachements = attachements; } QVector Message::urls() const { return mUrls; } void Message::setUrls(const QVector &urls) { mUrls = urls; } QString Message::alias() const { return mAlias; } void Message::setAlias(const QString &alias) { mAlias = alias; } QString Message::editedByUserId() const { return mEditedByUserId; } void Message::setEditedByUserId(const QString &editedByUserId) { mEditedByUserId = editedByUserId; } QString Message::editedByUsername() const { return mEditedByUsername; } void Message::setEditedByUsername(const QString &editedByUsername) { mEditedByUsername = editedByUsername; } qint64 Message::editedAt() const { return mEditedAt; } void Message::setEditedAt(const qint64 &editedAt) { mEditedAt = editedAt; } qint64 Message::updatedAt() const { return mUpdatedAt; } void Message::setUpdatedAt(const qint64 &updatedAt) { mUpdatedAt = updatedAt; } QString Message::userId() const { return mUserId; } void Message::setUserId(const QString &userId) { mUserId = userId; } QString Message::username() const { return mUsername; } void Message::setUsername(const QString &username) { mUsername = username; } qint64 Message::timeStamp() const { return mTimeStamp; } void Message::setTimeStamp(const qint64 &timeStamp) { mTimeStamp = timeStamp; } QString Message::text() const { return mText; } void Message::setText(const QString &text) { mText = text; } QString Message::messageId() const { return mMessageId; } void Message::setMessageId(const QString &messageId) { mMessageId = messageId; } QString Message::roomId() const { return mRoomId; } void Message::setRoomId(const QString &roomId) { mRoomId = roomId; } QString Message::avatar() const { return mAvatar; } void Message::setAvatar(const QString &avatar) { mAvatar = avatar; } bool Message::parseUrls() const { return mParseUrls; } void Message::setParseUrls(bool parseUrls) { mParseUrls = parseUrls; } bool Message::groupable() const { return mGroupable; } void Message::setGroupable(bool groupable) { mGroupable = groupable; } Message Message::fromJSon(const QJsonObject &o) { Message message; message.mMessageId = o[QStringLiteral("messageID")].toString(); message.mRoomId = o[QStringLiteral("roomID")].toString(); message.mText = o[QStringLiteral("message")].toString(); message.mTimeStamp = (qint64)o[QStringLiteral("timestamp")].toDouble(); message.mUsername = o[QStringLiteral("username")].toString(); message.mUserId = o[QStringLiteral("userID")].toString(); message.mUpdatedAt = (qint64)o[QStringLiteral("updatedAt")].toDouble(); message.mEditedAt = (qint64)o[QStringLiteral("editedAt")].toDouble(); message.mEditedByUsername = o[QStringLiteral("editedByUsername")].toString(); message.mEditedByUserId = o[QStringLiteral("editedByUserID")].toString(); message.mAlias = o[QStringLiteral("alias")].toString(); message.mAvatar = o[QStringLiteral("avatar")].toString(); message.mGroupable = o[QStringLiteral("groupable")].toBool(); message.mParseUrls = o[QStringLiteral("parseUrls")].toBool(); message.mSystemMessageType = o[QStringLiteral("type")].toString(); message.mMessageType = o[QStringLiteral("messageType")].toVariant().value(); const QJsonArray attachmentsArray = o.value(QLatin1String("attachments")).toArray(); for (int i = 0; i < attachmentsArray.count(); ++i) { const QJsonObject attachment = attachmentsArray.at(i).toObject(); const MessageAttachment att = MessageAttachment::fromJSon(attachment); if (!att.isEmpty()) { message.mAttachements.append(att); } } const QJsonArray urlsArray = o.value(QLatin1String("urls")).toArray(); for (int i = 0; i < urlsArray.count(); ++i) { const QJsonObject urlObj = urlsArray.at(i).toObject(); const MessageUrl url = MessageUrl::fromJSon(urlObj); if (!url.isEmpty()) { message.mUrls.append(url); } } const QJsonArray mentionsArray = o.value(QLatin1String("mentions")).toArray(); for (int i = 0; i < mentionsArray.count(); ++i) { const QJsonObject mention = mentionsArray.at(i).toObject(); qCDebug(RUQOLA_LOG) << " mention"<(message.mMessageType)); //Attachments if (!message.mAttachements.isEmpty()) { QJsonArray array; const int nbAttachment{ message.mAttachements.count() }; for (int i = 0; i < nbAttachment; ++i) { array.append(MessageAttachment::serialize(message.mAttachements.at(i))); } o[QStringLiteral("attachments")] = array; } //Urls if (!message.mUrls.isEmpty()) { QJsonArray array; const int nbUrls{ message.mUrls.count() }; for (int i = 0; i < nbUrls; ++i) { array.append(MessageUrl::serialize(message.mUrls.at(i))); } o[QStringLiteral("urls")] = array; } d.setObject(o); return d.toBinaryData(); } QDebug operator <<(QDebug d, const Message &t) { d << "mMessageId : " << t.messageId(); d << "mText: " << t.text(); d << "mTimeStamp: " << t.timeStamp(); d << "mUsername: " << t.username(); d << "mUserId: " << t.userId(); d << "mUpdatedAt: " << t.updatedAt(); d << "mEditedAt: " << t.editedAt(); d << "mEditedByUsername: " << t.editedByUsername(); d << "mEditedByUserId: " << t.editedByUserId(); d << "mAlias: " << t.alias(); d << "mSystemMessageType: " << t.systemMessageType(); d << "mRoomId: " << t.roomId(); d << "mAvatar: " << t.avatar(); d << "mGroupable: " << t.groupable(); d << "mParseUrls: " << t.parseUrls(); + d << "mStarred: " << t.starred(); for (int i = 0; i < t.attachements().count(); ++i) { d << "Attachment :" << t.attachements().at(i); } for (int i = 0; i < t.urls().count(); ++i) { d << "Urls :" << t.urls().at(i); } d << "Mentions :" << t.mentions(); d << "mMessageType: " << t.messageType(); return d; } diff --git a/src/message.h b/src/message.h index 7f2e9422..d655e601 100644 --- a/src/message.h +++ b/src/message.h @@ -1,189 +1,195 @@ /* Copyright (c) 2017-2018 Montel Laurent 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. */ #ifndef MESSAGE_H #define MESSAGE_H #include "libruqola_private_export.h" #include "messageattachment.h" #include "messageurl.h" #include #include #include #include class LIBRUQOLACORE_TESTS_EXPORT Message { Q_GADGET public: Message(); enum MessageType { System, NormalText, File, Video, Audio, Image }; Q_ENUM(MessageType) QString roomId() const; void setRoomId(const QString &roomId); bool groupable() const; void setGroupable(bool groupable); bool parseUrls() const; void setParseUrls(bool parseUrls); QString avatar() const; void setAvatar(const QString &avatar); /** * @brief Constructs Message object from QJsonObject * * @param source The Json containing message attributes * @return Message object, The message constructed from Json */ static Message fromJSon(const QJsonObject &source); /** * @brief Constructs QBytearray from Message object * * @param message The Message object * @return QByteArray, The Json containing message attributes */ static QByteArray serialize(const Message &message); void parseMessage(const QJsonObject &o); bool operator==(const Message &other) const; Message &operator=(const Message &other); // To be used in sorted insert: timestamp bool operator<(const Message &other) const; QString messageId() const; void setMessageId(const QString &messageId); QString text() const; void setText(const QString &text); qint64 timeStamp() const; void setTimeStamp(const qint64 &timeStamp); QString username() const; void setUsername(const QString &username); QString userId() const; void setUserId(const QString &userId); qint64 updatedAt() const; void setUpdatedAt(const qint64 &updatedAt); qint64 editedAt() const; void setEditedAt(const qint64 &editedAt); QString editedByUsername() const; void setEditedByUsername(const QString &editedByUsername); QString editedByUserId() const; void setEditedByUserId(const QString &editedByUserId); QString imageUrl() const; void setImageUrl(const QString &imageUrl); QString alias() const; void setAlias(const QString &alias); QString systemMessageType() const; void setSystemMessageType(const QString &systemMessageType); MessageType messageType() const; void setMessageType(const MessageType &messageType); QVector attachements() const; void setAttachements(const QVector &attachements); QVector urls() const; void setUrls(const QVector &urls); QMap mentions() const; void setMentions(const QMap &mentions); + bool starred() const; + void setStarred(bool starred); + private: void parseMentions(const QJsonArray &mentions); void parseAttachment(const QJsonArray &attachments); void parseUrls(const QJsonArray &urls); //Message Object Fields QVector mAttachements; //Message urls object QVector mUrls; //Mentions QMap mMentions; // _id QString mMessageId; // msg QString mText; // u QString mUsername; QString mUserId; // editedBy QString mEditedByUsername; QString mEditedByUserId; // alias QString mAlias; QString mSystemMessageType; // rid QString mRoomId; // avatar QString mAvatar; // ts qint64 mTimeStamp = -1; // _updatedAt qint64 mUpdatedAt = -1; // editedAt qint64 mEditedAt = -1; MessageType mMessageType = MessageType::NormalText; // groupable bool mGroupable = false; // parseUrls bool mParseUrls = false; + + //Starred + bool mStarred = false; }; Q_DECLARE_METATYPE(Message) LIBRUQOLACORE_EXPORT QDebug operator <<(QDebug d, const Message &t); #endif // MESSAGE_H diff --git a/src/messagemodel.cpp b/src/messagemodel.cpp index 3853f26d..4bd254f4 100644 --- a/src/messagemodel.cpp +++ b/src/messagemodel.cpp @@ -1,268 +1,271 @@ /* * Copyright 2016 Riccardo Iaconelli * * 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 . * */ #include #include #include #include #include #include #include #include "messagemodel.h" #include "ruqolaserverconfig.h" #include "message.h" #include "ruqola_debug.h" #include "utils.h" #include "rocketchataccount.h" #include "texthighlighter.h" #include "textconverter.h" #include "loadrecenthistorymanager.h" #include #include #include //TODO reactivate when we will able to load message between cache and official server. //#define STORE_MESSAGE 1 MessageModel::MessageModel(const QString &roomID, RocketChatAccount *account, QObject *parent) : QAbstractListModel(parent) , mRoomID(roomID) , mRocketChatAccount(account) { mTextConverter = new TextConverter; mLoadRecentHistoryManager = new LoadRecentHistoryManager; qCDebug(RUQOLA_LOG) << "Creating message Model"; #ifdef STORE_MESSAGE if (mRocketChatAccount) { const QString cachePath = mRocketChatAccount->settings()->cacheBasePath(); if (cachePath.isEmpty()) { qCWarning(RUQOLA_LOG) << " Cache Path is not defined"; return; } QDir cacheDir(cachePath + QStringLiteral("/rooms_cache")); // load cache if (QFile::exists(cacheDir.absoluteFilePath(roomID)) && !roomID.isEmpty()) { QFile f(cacheDir.absoluteFilePath(roomID)); if (f.open(QIODevice::ReadOnly)) { QDataStream in(&f); while (!f.atEnd()) { char *byteArray; quint32 length; in.readBytes(byteArray, length); const QByteArray arr = QByteArray::fromRawData(byteArray, length); Message m = Message::fromJSon(QJsonDocument::fromBinaryData(arr).object()); addMessage(m); } } } } #endif } MessageModel::~MessageModel() { #ifdef STORE_MESSAGE if (mRocketChatAccount) { const QString cachePath = mRocketChatAccount->settings()->cacheBasePath(); if (cachePath.isEmpty()) { qCWarning(RUQOLA_LOG) << " Cache Path is not defined"; return; } QDir cacheDir(cachePath + QStringLiteral("/rooms_cache")); qCDebug(RUQOLA_LOG) << "Caching to..." << cacheDir.path(); if (!cacheDir.exists(cacheDir.path())) { cacheDir.mkpath(cacheDir.path()); } QFile f(cacheDir.absoluteFilePath(mRoomID)); if (f.open(QIODevice::WriteOnly)) { QDataStream out(&f); for (const Message &m : qAsConst(mAllMessages)) { const QByteArray ms = Message::serialize(m); out.writeBytes(ms, ms.size()); } } } #endif delete mTextConverter; delete mLoadRecentHistoryManager; } QHash MessageModel::roleNames() const { QHash roles; roles[MessageText] = "messageText"; roles[Username] = "username"; roles[Timestamp] = "timestamp"; roles[UserId] = "userID"; roles[SystemMessageType] = "type"; roles[MessageId] = "messageID"; roles[RoomId] = "roomID"; roles[UpdatedAt] = "updatedAt"; roles[EditedAt] = "editedAt"; roles[EditedByUserName] = "editedByUsername"; roles[EditedByUserId] = "editedByUserID"; roles[Alias] = "alias"; roles[Avatar] = "avatar"; roles[Groupable] = "groupable"; roles[MessageType] = "messagetype"; roles[Attachments] = "attachments"; roles[Urls] = "urls"; roles[Date] = "date"; roles[CanEditingMessage] = "canEditingMessage"; + roles[Starred] = "starred"; return roles; } qint64 MessageModel::lastTimestamp() const { if (!mAllMessages.isEmpty()) { //qCDebug(RUQOLA_LOG) << "returning timestamp" << mAllMessages.last().timeStamp(); return mAllMessages.first().timeStamp(); } else { return 0; } } int MessageModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return mAllMessages.size(); } void MessageModel::addMessage(const Message &message) { auto it = std::upper_bound(mAllMessages.begin(), mAllMessages.end(), message, [](const Message &lhs, const Message &rhs) -> bool { return lhs.timeStamp() < rhs.timeStamp(); } ); //When we have 1 element. if (mAllMessages.count() == 1 && (*mAllMessages.begin()).messageId() == message.messageId()) { (*mAllMessages.begin()) = message; const QModelIndex index = createIndex(0, 0); qCDebug(RUQOLA_LOG) << "Update Message"; Q_EMIT dataChanged(index, index); } else if (((it) != mAllMessages.begin() && (*(it - 1)).messageId() == message.messageId())) { qCDebug(RUQOLA_LOG) << "Update Message"; (*(it-1)) = message; const QModelIndex index = createIndex(it - 1 - mAllMessages.begin(), 0); Q_EMIT dataChanged(index, index); } else { const int pos = it - mAllMessages.begin(); beginInsertRows(QModelIndex(), pos, pos); mAllMessages.insert(it, message); endInsertRows(); } } QVariant MessageModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { qCWarning(RUQOLA_LOG) << "ERROR: invalid index"; return {}; } int idx = index.row(); switch (role) { case MessageModel::Username: return mAllMessages.at(idx).username(); case MessageModel::MessageText: return convertMessageText(mAllMessages.at(idx).text(), mAllMessages.at(idx).mentions()); case MessageModel::Timestamp: return mAllMessages.at(idx).timeStamp(); case MessageModel::UserId: return mAllMessages.at(idx).userId(); case MessageModel::SystemMessageType: return mAllMessages.at(idx).systemMessageType(); case MessageModel::MessageId: return mAllMessages.at(idx).messageId(); case MessageModel::Alias: return mAllMessages.at(idx).alias(); case MessageModel::MessageType: return mAllMessages.at(idx).messageType(); case MessageModel::Avatar: return mAllMessages.at(idx).avatar(); case MessageModel::EditedAt: return mAllMessages.at(idx).editedAt(); case MessageModel::EditedByUserName: return mAllMessages.at(idx).editedByUsername(); case MessageModel::Attachments: { QVariantList lst; lst.reserve(mAllMessages.at(idx).attachements().count()); for (const MessageAttachment &att : mAllMessages.at(idx).attachements()) { lst.append(QVariant::fromValue(att)); } return lst; } case MessageModel::Urls: { QVariantList lst; lst.reserve(mAllMessages.at(idx).urls().count()); for (const MessageUrl &url : mAllMessages.at(idx).urls()) { lst.append(QVariant::fromValue(url)); } return lst; } case MessageModel::Date: if (idx > 0) { QDateTime previewDate; previewDate.setMSecsSinceEpoch(mAllMessages.at(idx - 1).timeStamp()); QDateTime currentDate; currentDate.setMSecsSinceEpoch(mAllMessages.at(idx).timeStamp()); if (previewDate.date() != currentDate.date()) { return currentDate.date().toString(); } } return QString(); case MessageModel::CanEditingMessage: return (mAllMessages.at(idx).timeStamp() + mRocketChatAccount->ruqolaServerConfig()->blockEditingMessageInMinutes() * 60 * 1000) > QDateTime::currentMSecsSinceEpoch(); + case MessageModel::Starred: + return mAllMessages.at(idx).starred(); } return QString(); } QString MessageModel::convertMessageText(const QString &str, const QMap &mentions) const { return mTextConverter->convertMessageText(str, mentions); } void MessageModel::deleteMessage(const QString &messageId) { for (int i = 0; i < mAllMessages.count(); ++i) { if (mAllMessages.at(i).messageId() == messageId) { beginRemoveRows(QModelIndex(), i, i); mAllMessages.remove(i); endRemoveRows(); break; } } } qint64 MessageModel::generateNewStartTimeStamp(qint64 lastTimeStamp) { return mLoadRecentHistoryManager->generateNewStartTimeStamp(lastTimeStamp); } diff --git a/src/messagemodel.h b/src/messagemodel.h index 85fb8bd0..98ce19f4 100644 --- a/src/messagemodel.h +++ b/src/messagemodel.h @@ -1,106 +1,107 @@ /* * Copyright 2016 Riccardo Iaconelli * * 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 . * */ #ifndef MESSAGEMODEL_H #define MESSAGEMODEL_H #include "libruqola_private_export.h" #include "message.h" #include #include #include #include class RocketChatAccount; class TextConverter; class LoadRecentHistoryManager; class LIBRUQOLACORE_EXPORT MessageModel : public QAbstractListModel { Q_OBJECT public: enum MessageRoles { Username = Qt::UserRole + 1, MessageText, Timestamp, UserId, SystemMessageType, MessageId, RoomId, UpdatedAt, EditedAt, EditedByUserName, EditedByUserId, Alias, Avatar, Groupable, ParseUrls, MessageType, Attachments, Urls, Date, CanEditingMessage, + Starred }; Q_ENUM(MessageRoles) explicit MessageModel(const QString &roomID = QStringLiteral("no_room"), RocketChatAccount *account = nullptr, QObject *parent = nullptr); virtual ~MessageModel(); /** * @brief Adds a message to QVector m_allMessages * * @param message The message to be added */ void addMessage(const Message &message); /** * @brief returns number of messages in QVector m_allMessages * * @param parent, it is void * @return int, The number of messages in QVector mAllMessages */ int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; /** * @brief Returns last timestamp of last message in QVector mAllMessages * * @return qint64 The last timestamp */ qint64 lastTimestamp() const; void deleteMessage(const QString &messageId); qint64 generateNewStartTimeStamp(qint64 lastTimeStamp); protected: QHash roleNames() const override; private: QString convertMessageText(const QString &str, const QMap &mentions) const; const QString mRoomID; QVector mAllMessages; RocketChatAccount *mRocketChatAccount = nullptr; TextConverter *mTextConverter = nullptr; LoadRecentHistoryManager *mLoadRecentHistoryManager = nullptr; }; #endif diff --git a/src/qml/ActiveChat.qml b/src/qml/ActiveChat.qml index 9ae0fcf3..d5b8d14f 100644 --- a/src/qml/ActiveChat.qml +++ b/src/qml/ActiveChat.qml @@ -1,98 +1,100 @@ /* Copyright (c) 2017-2018 Montel Laurent 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 1.4 import QtQuick.Layouts 1.1 import org.kde.kirigami 2.1 as Kirigami ListView { id: activeChat signal openDirectChannel(string userName) signal jitsiCallConfActivated() signal deleteMessage(string messageId) signal downloadAttachment(string url) signal editMessage(string messageId) signal replyMessage(string messageId) signal setFavoriteMessage(string messageId) signal displayImage(url imageUrl, string title) property QtObject rcAccount property string roomId: "" spacing: Kirigami.Units.smallSpacing onCountChanged: { positionViewAtIndex(count - 1, ListView.Beginning) } Component.onCompleted: positionViewAtIndex(count - 1, ListView.End) visible: count > 0 onDragEnded : { if (roomId !== "") { rcAccount.loadHistory(roomId) } } delegate: FancyMessageDelegate { anchors.left: parent.left anchors.right: parent.right anchors.rightMargin: Kirigami.Units.largeSpacing anchors.leftMargin: Kirigami.Units.largeSpacing i_messageText: messageText i_username: username i_aliasname: alias i_systemMessageType: type i_timestamp: timestamp i_messageID: messageID i_messageType: messagetype i_avatar: avatar == "" ? rcAccount.avatarUrl(userID) : avatar i_urls: urls i_attachments: attachments i_date: date i_own_username: rcAccount.userName i_can_editing_message: canEditingMessage + i_starred: starred + onOpenDirectChannel: { activeChat.openDirectChannel(userName) } onJitsiCallConfActivated: { activeChat.jitsiCallConfActivated() } onDeleteMessage: { activeChat.deleteMessage(messageId) } onDownloadAttachment: { activeChat.downloadAttachment(url) } onEditMessage: { activeChat.editMessage(messageId) } onReplyMessage: { activeChat.replyMessage(messageId) } onSetFavoriteMessage: { activeChat.setFavoriteMessage(messageId) } onDisplayImage: { activeChat.displayImage(imageUrl, title) } } } diff --git a/src/qml/FancyMessageDelegate.qml b/src/qml/FancyMessageDelegate.qml index 6bd52909..1437cdc4 100644 --- a/src/qml/FancyMessageDelegate.qml +++ b/src/qml/FancyMessageDelegate.qml @@ -1,207 +1,210 @@ /* * Copyright 2016 Riccardo Iaconelli * Copyright (c) 2017-2018 Montel Laurent * * 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 KDE.Ruqola.RuqolaUtils 1.0 import KDE.Ruqola.Message 1.0 import QtQuick.Controls 2.2 import org.kde.kirigami 2.1 as Kirigami import KDE.Ruqola.ExtraColors 1.0 import QtQuick.Layouts 1.1 import KDE.Ruqola.RocketChatAccount 1.0 import KDE.Ruqola.DebugCategory 1.0 Rectangle { id: messageMain property string i_messageID property string i_messageText property string i_username property bool i_systemMessage property string i_systemMessageType property string i_avatar property string i_aliasname property var i_timestamp property var i_messageType property var i_urls property var i_attachments property string i_date property string i_own_username property bool i_can_editing_message + property bool i_starred color: RuqolaSingleton.backgroundColor implicitHeight: 4*Kirigami.Units.smallSpacing + loaded.item.implicitHeight implicitWidth: 150 signal openDirectChannel(string userName) signal jitsiCallConfActivated() signal deleteMessage(string messageId) signal downloadAttachment(string url) signal editMessage(string messageId) signal replyMessage(string messageId) signal setFavoriteMessage(string messageId) signal displayImage(url imageUrl, string title) Loader { id: loaded anchors.fill: parent Component.onCompleted: { if (i_messageType === Message.System) { if (i_systemMessageType === "jitsi_call_started") { console.log(RuqolaDebugCategorySingleton.category, "Jitsi"); 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, rcAccount: appid.rocketChatAccount } ) } else { console.log(RuqolaDebugCategorySingleton.category, "System Message"); 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 } ) } } else if (i_messageType === Message.NormalText || i_messageType === Message.File) { console.log(RuqolaDebugCategorySingleton.category, "User Message"); setSource("messages/UserMessage.qml", { i_messageText: i_messageText, i_username: i_username, i_aliasname: i_aliasname, i_timestamp: i_timestamp, i_messageID: i_messageID, i_avatar: i_avatar, i_urls: i_urls, i_attachments: i_attachments, i_date: i_date, i_own_username: i_own_username, rcAccount: appid.rocketChatAccount, - i_can_editing_message: i_can_editing_message + i_can_editing_message: i_can_editing_message, + i_starred: i_starred + } ) } else if (i_messageType === Message.Audio) { console.log(RuqolaDebugCategorySingleton.category, "Audio"); setSource("messages/AttachmentMessageAudio.qml", { i_messageText: i_messageText, i_username: i_username, i_aliasname: i_aliasname, i_timestamp: i_timestamp, i_messageID: i_messageID, i_avatar: i_avatar, i_urls: i_urls, i_attachments: i_attachments, i_date: i_date, rcAccount: appid.rocketChatAccount }) } else if (i_messageType === Message.Video) { console.log(RuqolaDebugCategorySingleton.category, "Video"); setSource("messages/AttachmentMessageVideo.qml", { i_messageText: i_messageText, i_username: i_username, i_aliasname: i_aliasname, i_timestamp: i_timestamp, i_messageID: i_messageID, i_avatar: i_avatar, i_urls: i_urls, i_attachments: i_attachments, i_date: i_date, rcAccount: appid.rocketChatAccount }) } else if (i_messageType === Message.Image) { console.log(RuqolaDebugCategorySingleton.category, "Image"); setSource("messages/AttachmentMessageImage.qml", { i_messageText: i_messageText, i_username: i_username, i_aliasname: i_aliasname, i_timestamp: i_timestamp, i_messageID: i_messageID, i_avatar: i_avatar, i_urls: i_urls, i_attachments: i_attachments, i_date: i_date, rcAccount: appid.rocketChatAccount }) } else { console.log(RuqolaDebugCategorySingleton.category, "Unknown message type: " + i_messageType) } } } Connections { target: loaded.item onLinkActivated: { if (link.startsWith("ruqola:/room/")) { appid.rocketChatAccount.openChannel(RuqolaUtils.extractRoomUserFromUrl(link)); } else if (link.startsWith("ruqola:/user/")) { messageMain.openDirectChannel(RuqolaUtils.extractRoomUserFromUrl(link)) } else { RuqolaUtils.openUrl(link); } } onJitsiCallConfActivated: { messageMain.jitsiCallConfActivated() } onDeleteMessage: { messageMain.deleteMessage(messageId) } onDownloadAttachment: { messageMain.downloadAttachment(url) } onEditMessage: { messageMain.editMessage(messageId) } onReplyMessage: { messageMain.replyMessage(messageId) } onSetFavoriteMessage: { messageMain.setFavoriteMessage(messageId) } onDisplayImage: { messageMain.displayImage(imageUrl, title) } } } diff --git a/src/qml/messages/MessageMenu.qml b/src/qml/messages/MessageMenu.qml index e8a3d2ab..6bb926d1 100644 --- a/src/qml/messages/MessageMenu.qml +++ b/src/qml/messages/MessageMenu.qml @@ -1,72 +1,80 @@ /* Copyright (c) 2017-2018 Montel Laurent 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 org.kde.kirigami 2.1 as Kirigami import QtQuick.Controls 2.2 as QQC2 import QtQuick.Layouts 1.1 import KDE.Ruqola.DebugCategory 1.0 QQC2.Menu { id: menu property bool can_editing_message + property bool starred + + function updateFavoriteLabelText() + { + return (i_starred === true) ? i18n("Remove as Favorite") : i18n("Set as Favorite") + } QQC2.MenuItem { id: editMessageItem contentItem: QQC2.Label { text: i18n("Edit") } onTriggered: { messageMain.editMessage(i_messageID); console.log(RuqolaDebugCategorySingleton.category, "Edit", i_messageID, i_messageText); console.log(RuqolaDebugCategorySingleton.category, "User", i_own_username, i_username); } } QQC2.MenuItem { contentItem: QQC2.Label { text: i18n("Reply") } onTriggered: { console.log(RuqolaDebugCategorySingleton.category, "Reply to", i_messageID); messageMain.replyMessage(i_messageID); } } QQC2.MenuItem { contentItem: QQC2.Label { - text: i18n("Set as Favorite") + id: favoriteLabel + text: updateFavoriteLabelText() } onTriggered: { console.log(RuqolaDebugCategorySingleton.category, "Set as favorite", i_messageID); messageMain.setFavoriteMessage(i_messageID); } } QQC2.MenuItem { visible: i_username === i_own_username contentItem: QQC2.Label { text: i18n("Delete") } onTriggered: { messageMain.deleteMessage(i_messageID); } } onAboutToShow: { editMessageItem.visible = (i_username === i_own_username) && rcAccount.allowEditingMessages() && can_editing_message + favoriteLabel.text = updateFavoriteLabelText() } } diff --git a/src/qml/messages/UserMessage.qml b/src/qml/messages/UserMessage.qml index 4f8bddca..d76d2567 100644 --- a/src/qml/messages/UserMessage.qml +++ b/src/qml/messages/UserMessage.qml @@ -1,138 +1,140 @@ /* * Copyright 2016 Riccardo Iaconelli * Copyright (c) 2017-2018 Montel Laurent * * 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.1 as Kirigami import QtQuick.Controls 2.2 as QQC2 import QtQuick.Layouts 1.1 import KDE.Ruqola.RuqolaUtils 1.0 import KDE.Ruqola.ExtraColors 1.0 import KDE.Ruqola.DebugCategory 1.0 import "../js/message.js" as MessageScript; MessageBase { property string i_messageID property var i_urls property var i_attachments property string i_own_username property bool i_can_editing_message + property bool i_starred id: messageMain Layout.alignment: Qt.AlignTop MessageMenu { id: menu can_editing_message: i_can_editing_message + starred: i_starred } RowLayout { AvatarImage { id: avatarRect avatarurl: i_avatar aliasname: i_aliasname username: i_username } ColumnLayout { Layout.fillHeight: true Kirigami.Heading { id: usernameLabel level: 5 font.bold: true text: i_aliasname + ' @' + i_username anchors.right: parent.right anchors.left: parent.left height: avatarRect.height MouseArea { anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { console.log(RuqolaDebugCategorySingleton.category, "clicked"); if (mouse.button === Qt.RightButton) { menu.x = mouse.x menu.y = mouse.y menu.open(); } } } } Column { id: fullTextColumn Layout.fillWidth: true Text { width: parent.width id: textLabel renderType: Text.NativeRendering textFormat: Text.RichText text: MessageScript.markdownme(i_messageText) wrapMode: QQC2.Label.Wrap onLinkActivated: messageMain.linkActivated(link) } Column { id: urlColumn width: parent.width Repeater { id: repeaterUrl model: i_urls Text { width: urlColumn.width text: model.modelData.description === "" ? MessageScript.markdownme(RuqolaUtils.markdownToRichText(model.modelData.url)) : MessageScript.markdownme(RuqolaUtils.markdownToRichText(model.modelData.description)) wrapMode: QQC2.Label.Wrap renderType: Text.NativeRendering textFormat: Text.RichText onLinkActivated: messageMain.linkActivated(link) } } Repeater { id: repearterAttachments model: i_attachments Text { width: urlColumn.width text: model.modelData.title wrapMode: QQC2.Label.Wrap anchors.leftMargin: Kirigami.Units.smallSpacing anchors.rightMargin: Kirigami.Units.smallSpacing } } } } } TimestampText { id: timestampText timestamp: i_timestamp } } }