From d936c0302d5f23c422822406a21a140402606b7f Mon Sep 17 00:00:00 2001 From: blue Date: Fri, 23 Apr 2021 01:41:32 +0300 Subject: [PATCH] bug with downloads in group chats, status icons in messages, visuals, feedView optimisations --- core/handlers/messagehandler.cpp | 2 +- ui/models/messagefeed.cpp | 63 ++++++++++++++++++++++++++++++-- ui/models/messagefeed.h | 3 ++ ui/utils/feedview.cpp | 18 ++++++++- ui/utils/feedview.h | 3 ++ ui/utils/messagedelegate.cpp | 44 +++++++++++++++++----- 6 files changed, 116 insertions(+), 17 deletions(-) diff --git a/core/handlers/messagehandler.cpp b/core/handlers/messagehandler.cpp index 51282eb..7644982 100644 --- a/core/handlers/messagehandler.cpp +++ b/core/handlers/messagehandler.cpp @@ -369,7 +369,7 @@ void Core::MessageHandler::onDownloadFileComplete(const std::listgetName()) { - Contact* cnt = acc->rh->getContact(info.jid); + RosterItem* cnt = acc->rh->getRosterItem(info.jid); if (cnt != 0) { if (cnt->changeMessage(info.messageId, cData)) { emit acc->changeMessage(info.jid, info.messageId, cData); diff --git a/ui/models/messagefeed.cpp b/ui/models/messagefeed.cpp index 2345816..a591657 100644 --- a/ui/models/messagefeed.cpp +++ b/ui/models/messagefeed.cpp @@ -32,6 +32,7 @@ const QHash Models::MessageFeed::roles = { {Avatar, "avatar"}, {Attach, "attach"}, {Id, "id"}, + {Error, "error"}, {Bulk, "bulk"} }; @@ -85,6 +86,7 @@ void Models::MessageFeed::changeMessage(const QString& id, const QMap changeRoles = detectChanges(*msg, data); QModelIndex index = modelIndexByTime(id, msg->getTime()); Shared::Message::Change functor(data); bool success = indexById.modify(itr, functor); @@ -94,7 +96,7 @@ void Models::MessageFeed::changeMessage(const QString& id, const QMap Models::MessageFeed::detectChanges(const Shared::Message& msg, const QMap& data) const +{ + QVector roles; + Shared::Message::State state = msg.getState(); + QMap::const_iterator itr = data.find("state"); + if (itr != data.end() && static_cast(itr.value().toUInt()) != state) { + roles.push_back(MessageRoles::DeliveryState); + } + + itr = data.find("outOfBandUrl"); + bool att = false; + if (itr != data.end() && itr.value().toString() != msg.getOutOfBandUrl()) { + roles.push_back(MessageRoles::Attach); + att = true; + } + + if (!att) { + itr = data.find("attachPath"); + if (itr != data.end() && itr.value().toString() != msg.getAttachPath()) { + roles.push_back(MessageRoles::Attach); + } + } + + if (state == Shared::Message::State::error) { + itr = data.find("errorText"); + if (itr != data.end()) { + roles.push_back(MessageRoles::Error); + } + } + + itr = data.find("body"); + if (itr != data.end()) { + QMap::const_iterator dItr = data.find("stamp"); + QDateTime correctionDate; + if (dItr != data.end()) { + correctionDate = dItr.value().toDateTime(); + } else { + correctionDate = QDateTime::currentDateTimeUtc(); //in case there is no information about time of this correction it's applied + } + if (!msg.getEdited() || msg.getLastModified() < correctionDate) { + roles.push_back(MessageRoles::Text); + roles.push_back(MessageRoles::Correction); + } + } + + return roles; } void Models::MessageFeed::removeMessage(const QString& id) @@ -187,12 +237,17 @@ QVariant Models::MessageFeed::data(const QModelIndex& index, int role) const case Id: answer.setValue(msg->getId()); break; + break; + case Error: + answer.setValue(msg->getErrorText()); + break; case Bulk: { FeedItem item; item.id = msg->getId(); item.sentByMe = sentByMe(*msg); item.date = msg->getTime(); item.state = msg->getState(); + item.error = msg->getErrorText(); item.correction = msg->getEdited(); QString body = msg->getBody(); @@ -340,7 +395,7 @@ void Models::MessageFeed::downloadAttachment(const QString& messageId) std::pair progressPair = downloads.insert(std::make_pair(messageId, 0)); if (progressPair.second) { //Only to take action if we weren't already downloading it Shared::Message* msg = static_cast(ind.internalPointer()); - emit dataChanged(ind, ind); + emit dataChanged(ind, ind, {MessageRoles::Attach}); emit fileDownloadRequest(msg->getOutOfBandUrl()); } else { qDebug() << "Attachment download for message with id" << messageId << "is already in progress, skipping"; @@ -368,7 +423,7 @@ void Models::MessageFeed::fileProgress(const QString& messageId, qreal value, bo if (itr != pr->end()) { itr->second = value; QModelIndex ind = modelIndexById(messageId); - emit dataChanged(ind, ind); + emit dataChanged(ind, ind); //the type of the attach didn't change, so, there is no need to relayout, there is no role in event } } diff --git a/ui/models/messagefeed.h b/ui/models/messagefeed.h index e8fb712..f5b27b2 100644 --- a/ui/models/messagefeed.h +++ b/ui/models/messagefeed.h @@ -73,6 +73,7 @@ protected: Attachment fillAttach(const Shared::Message& msg) const; QModelIndex modelIndexById(const QString& id) const; QModelIndex modelIndexByTime(const QString& id, const QDateTime& time) const; + QVector detectChanges(const Shared::Message& msg, const QMap& data) const; public: enum MessageRoles { @@ -85,6 +86,7 @@ public: Avatar, Attach, Id, + Error, Bulk }; @@ -161,6 +163,7 @@ struct FeedItem { QString text; QString sender; QString avatar; + QString error; bool sentByMe; bool correction; QDateTime date; diff --git a/ui/utils/feedview.cpp b/ui/utils/feedview.cpp index 7155d95..3f3b4b7 100644 --- a/ui/utils/feedview.cpp +++ b/ui/utils/feedview.cpp @@ -29,6 +29,14 @@ constexpr int maxMessageHeight = 10000; constexpr int approximateSingleMessageHeight = 20; +const std::set FeedView::geometryChangingRoles = { + Models::MessageFeed::Attach, + Models::MessageFeed::Text, + Models::MessageFeed::Id, + Models::MessageFeed::Error + +}; + FeedView::FeedView(QWidget* parent): QAbstractItemView(parent), hints(), @@ -115,8 +123,14 @@ void FeedView::rowsInserted(const QModelIndex& parent, int start, int end) void FeedView::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector& roles) { - //TODO make optimisations! There are some roles but not all that change geometry! - updateGeometries(); + if (specialDelegate) { + for (int role : roles) { + if (geometryChangingRoles.count(role) != 0) { + updateGeometries(); //to recalculate layout only if there are some geometry changing modifications + break; + } + } + } QAbstractItemView::dataChanged(topLeft, bottomRight, roles); } diff --git a/ui/utils/feedview.h b/ui/utils/feedview.h index a0b9252..05e3025 100644 --- a/ui/utils/feedview.h +++ b/ui/utils/feedview.h @@ -22,6 +22,7 @@ #include #include +#include #include @@ -77,6 +78,8 @@ private: bool specialModel; bool clearWidgetsMode; + static const std::set geometryChangingRoles; + }; #endif //FEEDVIEW_H diff --git a/ui/utils/messagedelegate.cpp b/ui/utils/messagedelegate.cpp index 6d53141..02aca8f 100644 --- a/ui/utils/messagedelegate.cpp +++ b/ui/utils/messagedelegate.cpp @@ -26,6 +26,8 @@ constexpr int avatarHeight = 50; constexpr int margin = 6; +constexpr int textMargin = 2; +constexpr int statusIconSize = 16; MessageDelegate::MessageDelegate(QObject* parent): QStyledItemDelegate(parent), @@ -115,7 +117,7 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio painter->setFont(nickFont); painter->drawText(opt.rect, opt.displayAlignment, data.sender, &rect); - opt.rect.adjust(0, rect.height(), 0, 0); + opt.rect.adjust(0, rect.height() + textMargin, 0, 0); painter->save(); switch (data.attach.state) { case Models::none: @@ -139,16 +141,28 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio } painter->restore(); + int messageLeft = 10000; //TODO if (data.text.size() > 0) { painter->setFont(bodyFont); painter->drawText(opt.rect, opt.displayAlignment | Qt::TextWordWrap, data.text, &rect); - opt.rect.adjust(0, rect.height(), 0, 0); + opt.rect.adjust(0, rect.height() + textMargin, 0, 0); + messageLeft = rect.x(); } painter->setFont(dateFont); QColor q = painter->pen().color(); q.setAlpha(180); painter->setPen(q); painter->drawText(opt.rect, opt.displayAlignment, data.date.toLocalTime().toString(), &rect); + if (data.sentByMe) { + if (messageLeft > rect.x() - statusIconSize - margin) { + messageLeft = rect.x() - statusIconSize - margin; + } + QIcon q(Shared::icon(Shared::messageStateThemeIcons[static_cast(data.state)])); + if (data.state == Shared::Message::State::error) { + //TODO handle error tooltip + } + painter->drawPixmap(messageLeft, opt.rect.y(), q.pixmap(statusIconSize, statusIconSize)); + } painter->restore(); @@ -168,6 +182,7 @@ QSize MessageDelegate::sizeHint(const QStyleOptionViewItem& option, const QModel QSize messageSize(0, 0); if (body.size() > 0) { messageSize = bodyMetrics.boundingRect(messageRect, Qt::TextWordWrap, body).size(); + messageSize.rheight() += textMargin; } switch (attach.state) { @@ -175,14 +190,14 @@ QSize MessageDelegate::sizeHint(const QStyleOptionViewItem& option, const QModel break; case Models::uploading: case Models::downloading: - messageSize.rheight() += barHeight; + messageSize.rheight() += barHeight + textMargin; break; case Models::remote: case Models::local: - messageSize.rheight() += buttonHeight; + messageSize.rheight() += buttonHeight + textMargin; break; case Models::ready: - messageSize.rheight() += calculateAttachSize(attach.localPath, messageRect).height(); + messageSize.rheight() += calculateAttachSize(attach.localPath, messageRect).height() + textMargin; break; case Models::errorDownload: case Models::errorUpload: @@ -190,7 +205,8 @@ QSize MessageDelegate::sizeHint(const QStyleOptionViewItem& option, const QModel } messageSize.rheight() += nickMetrics.lineSpacing(); - messageSize.rheight() += dateMetrics.height(); + messageSize.rheight() += textMargin; + messageSize.rheight() += dateMetrics.height() > statusIconSize ? dateMetrics.height() : statusIconSize; if (messageSize.height() < avatarHeight) { messageSize.setHeight(avatarHeight); @@ -208,10 +224,18 @@ void MessageDelegate::initializeFonts(const QFont& font) dateFont = font; nickFont.setBold(true); + + float ndps = nickFont.pointSizeF(); + if (ndps != -1) { + nickFont.setPointSizeF(ndps * 1.2); + } else { + nickFont.setPointSize(nickFont.pointSize() + 2); + } + dateFont.setItalic(true); float dps = dateFont.pointSizeF(); if (dps != -1) { - dateFont.setPointSizeF(dps * 0.7); + dateFont.setPointSizeF(dps * 0.8); } else { dateFont.setPointSize(dateFont.pointSize() - 2); } @@ -243,7 +267,7 @@ void MessageDelegate::paintButton(QPushButton* btn, QPainter* painter, bool sent btn->move(start); btn->show(); - option.rect.adjust(0, buttonHeight, 0, 0); + option.rect.adjust(0, buttonHeight + textMargin, 0, 0); } void MessageDelegate::paintBar(QProgressBar* bar, QPainter* painter, bool sentByMe, QStyleOptionViewItem& option) const @@ -262,7 +286,7 @@ void MessageDelegate::paintBar(QProgressBar* bar, QPainter* painter, bool sentBy painter->translate(start); bar->render(painter, QPoint(), QRegion(), QWidget::DrawChildren); - option.rect.adjust(0, barHeight, 0, 0); + option.rect.adjust(0, barHeight + textMargin, 0, 0); } void MessageDelegate::paintPreview(const Models::FeedItem& data, QPainter* painter, QStyleOptionViewItem& option) const @@ -281,7 +305,7 @@ void MessageDelegate::paintPreview(const Models::FeedItem& data, QPainter* paint QImage img(data.attach.localPath); painter->drawImage(QRect(start, size), img); - option.rect.adjust(0, size.height(), 0, 0); + option.rect.adjust(0, size.height() + textMargin, 0, 0); } }