1
0
forked from blue/squawk

bug with downloads in group chats, status icons in messages, visuals, feedView optimisations

This commit is contained in:
Blue 2021-04-23 01:41:32 +03:00
parent 0e937199b0
commit d936c0302d
6 changed files with 116 additions and 17 deletions

View File

@ -369,7 +369,7 @@ void Core::MessageHandler::onDownloadFileComplete(const std::list<Shared::Messag
}; };
for (const Shared::MessageInfo& info : msgs) { for (const Shared::MessageInfo& info : msgs) {
if (info.account == acc->getName()) { if (info.account == acc->getName()) {
Contact* cnt = acc->rh->getContact(info.jid); RosterItem* cnt = acc->rh->getRosterItem(info.jid);
if (cnt != 0) { if (cnt != 0) {
if (cnt->changeMessage(info.messageId, cData)) { if (cnt->changeMessage(info.messageId, cData)) {
emit acc->changeMessage(info.jid, info.messageId, cData); emit acc->changeMessage(info.jid, info.messageId, cData);

View File

@ -32,6 +32,7 @@ const QHash<int, QByteArray> Models::MessageFeed::roles = {
{Avatar, "avatar"}, {Avatar, "avatar"},
{Attach, "attach"}, {Attach, "attach"},
{Id, "id"}, {Id, "id"},
{Error, "error"},
{Bulk, "bulk"} {Bulk, "bulk"}
}; };
@ -85,6 +86,7 @@ void Models::MessageFeed::changeMessage(const QString& id, const QMap<QString, Q
} }
Shared::Message* msg = *itr; Shared::Message* msg = *itr;
QVector<int> changeRoles = detectChanges(*msg, data);
QModelIndex index = modelIndexByTime(id, msg->getTime()); QModelIndex index = modelIndexByTime(id, msg->getTime());
Shared::Message::Change functor(data); Shared::Message::Change functor(data);
bool success = indexById.modify(itr, functor); bool success = indexById.modify(itr, functor);
@ -94,7 +96,7 @@ void Models::MessageFeed::changeMessage(const QString& id, const QMap<QString, Q
} }
if (functor.hasIdBeenModified()) { if (functor.hasIdBeenModified()) {
changeRoles.push_back(MessageRoles::Id);
} }
//change message is a final event in download/upload event train //change message is a final event in download/upload event train
@ -113,7 +115,55 @@ void Models::MessageFeed::changeMessage(const QString& id, const QMap<QString, Q
} }
} }
emit dataChanged(index, index); emit dataChanged(index, index, changeRoles);
}
QVector<int> Models::MessageFeed::detectChanges(const Shared::Message& msg, const QMap<QString, QVariant>& data) const
{
QVector<int> roles;
Shared::Message::State state = msg.getState();
QMap<QString, QVariant>::const_iterator itr = data.find("state");
if (itr != data.end() && static_cast<Shared::Message::State>(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<QString, QVariant>::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) void Models::MessageFeed::removeMessage(const QString& id)
@ -187,12 +237,17 @@ QVariant Models::MessageFeed::data(const QModelIndex& index, int role) const
case Id: case Id:
answer.setValue(msg->getId()); answer.setValue(msg->getId());
break; break;
break;
case Error:
answer.setValue(msg->getErrorText());
break;
case Bulk: { case Bulk: {
FeedItem item; FeedItem item;
item.id = msg->getId(); item.id = msg->getId();
item.sentByMe = sentByMe(*msg); item.sentByMe = sentByMe(*msg);
item.date = msg->getTime(); item.date = msg->getTime();
item.state = msg->getState(); item.state = msg->getState();
item.error = msg->getErrorText();
item.correction = msg->getEdited(); item.correction = msg->getEdited();
QString body = msg->getBody(); QString body = msg->getBody();
@ -340,7 +395,7 @@ void Models::MessageFeed::downloadAttachment(const QString& messageId)
std::pair<Progress::iterator, bool> progressPair = downloads.insert(std::make_pair(messageId, 0)); std::pair<Progress::iterator, bool> progressPair = downloads.insert(std::make_pair(messageId, 0));
if (progressPair.second) { //Only to take action if we weren't already downloading it if (progressPair.second) { //Only to take action if we weren't already downloading it
Shared::Message* msg = static_cast<Shared::Message*>(ind.internalPointer()); Shared::Message* msg = static_cast<Shared::Message*>(ind.internalPointer());
emit dataChanged(ind, ind); emit dataChanged(ind, ind, {MessageRoles::Attach});
emit fileDownloadRequest(msg->getOutOfBandUrl()); emit fileDownloadRequest(msg->getOutOfBandUrl());
} else { } else {
qDebug() << "Attachment download for message with id" << messageId << "is already in progress, skipping"; 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()) { if (itr != pr->end()) {
itr->second = value; itr->second = value;
QModelIndex ind = modelIndexById(messageId); 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
} }
} }

View File

@ -73,6 +73,7 @@ protected:
Attachment fillAttach(const Shared::Message& msg) const; Attachment fillAttach(const Shared::Message& msg) const;
QModelIndex modelIndexById(const QString& id) const; QModelIndex modelIndexById(const QString& id) const;
QModelIndex modelIndexByTime(const QString& id, const QDateTime& time) const; QModelIndex modelIndexByTime(const QString& id, const QDateTime& time) const;
QVector<int> detectChanges(const Shared::Message& msg, const QMap<QString, QVariant>& data) const;
public: public:
enum MessageRoles { enum MessageRoles {
@ -85,6 +86,7 @@ public:
Avatar, Avatar,
Attach, Attach,
Id, Id,
Error,
Bulk Bulk
}; };
@ -161,6 +163,7 @@ struct FeedItem {
QString text; QString text;
QString sender; QString sender;
QString avatar; QString avatar;
QString error;
bool sentByMe; bool sentByMe;
bool correction; bool correction;
QDateTime date; QDateTime date;

View File

@ -29,6 +29,14 @@
constexpr int maxMessageHeight = 10000; constexpr int maxMessageHeight = 10000;
constexpr int approximateSingleMessageHeight = 20; constexpr int approximateSingleMessageHeight = 20;
const std::set<int> FeedView::geometryChangingRoles = {
Models::MessageFeed::Attach,
Models::MessageFeed::Text,
Models::MessageFeed::Id,
Models::MessageFeed::Error
};
FeedView::FeedView(QWidget* parent): FeedView::FeedView(QWidget* parent):
QAbstractItemView(parent), QAbstractItemView(parent),
hints(), 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<int>& roles) void FeedView::dataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector<int>& roles)
{ {
//TODO make optimisations! There are some roles but not all that change geometry! if (specialDelegate) {
updateGeometries(); 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); QAbstractItemView::dataChanged(topLeft, bottomRight, roles);
} }

View File

@ -22,6 +22,7 @@
#include <QAbstractItemView> #include <QAbstractItemView>
#include <deque> #include <deque>
#include <set>
#include <ui/models/messagefeed.h> #include <ui/models/messagefeed.h>
@ -77,6 +78,8 @@ private:
bool specialModel; bool specialModel;
bool clearWidgetsMode; bool clearWidgetsMode;
static const std::set<int> geometryChangingRoles;
}; };
#endif //FEEDVIEW_H #endif //FEEDVIEW_H

View File

@ -26,6 +26,8 @@
constexpr int avatarHeight = 50; constexpr int avatarHeight = 50;
constexpr int margin = 6; constexpr int margin = 6;
constexpr int textMargin = 2;
constexpr int statusIconSize = 16;
MessageDelegate::MessageDelegate(QObject* parent): MessageDelegate::MessageDelegate(QObject* parent):
QStyledItemDelegate(parent), QStyledItemDelegate(parent),
@ -115,7 +117,7 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio
painter->setFont(nickFont); painter->setFont(nickFont);
painter->drawText(opt.rect, opt.displayAlignment, data.sender, &rect); 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(); painter->save();
switch (data.attach.state) { switch (data.attach.state) {
case Models::none: case Models::none:
@ -139,16 +141,28 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio
} }
painter->restore(); painter->restore();
int messageLeft = 10000; //TODO
if (data.text.size() > 0) { if (data.text.size() > 0) {
painter->setFont(bodyFont); painter->setFont(bodyFont);
painter->drawText(opt.rect, opt.displayAlignment | Qt::TextWordWrap, data.text, &rect); 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); painter->setFont(dateFont);
QColor q = painter->pen().color(); QColor q = painter->pen().color();
q.setAlpha(180); q.setAlpha(180);
painter->setPen(q); painter->setPen(q);
painter->drawText(opt.rect, opt.displayAlignment, data.date.toLocalTime().toString(), &rect); 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<uint8_t>(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(); painter->restore();
@ -168,6 +182,7 @@ QSize MessageDelegate::sizeHint(const QStyleOptionViewItem& option, const QModel
QSize messageSize(0, 0); QSize messageSize(0, 0);
if (body.size() > 0) { if (body.size() > 0) {
messageSize = bodyMetrics.boundingRect(messageRect, Qt::TextWordWrap, body).size(); messageSize = bodyMetrics.boundingRect(messageRect, Qt::TextWordWrap, body).size();
messageSize.rheight() += textMargin;
} }
switch (attach.state) { switch (attach.state) {
@ -175,14 +190,14 @@ QSize MessageDelegate::sizeHint(const QStyleOptionViewItem& option, const QModel
break; break;
case Models::uploading: case Models::uploading:
case Models::downloading: case Models::downloading:
messageSize.rheight() += barHeight; messageSize.rheight() += barHeight + textMargin;
break; break;
case Models::remote: case Models::remote:
case Models::local: case Models::local:
messageSize.rheight() += buttonHeight; messageSize.rheight() += buttonHeight + textMargin;
break; break;
case Models::ready: case Models::ready:
messageSize.rheight() += calculateAttachSize(attach.localPath, messageRect).height(); messageSize.rheight() += calculateAttachSize(attach.localPath, messageRect).height() + textMargin;
break; break;
case Models::errorDownload: case Models::errorDownload:
case Models::errorUpload: case Models::errorUpload:
@ -190,7 +205,8 @@ QSize MessageDelegate::sizeHint(const QStyleOptionViewItem& option, const QModel
} }
messageSize.rheight() += nickMetrics.lineSpacing(); messageSize.rheight() += nickMetrics.lineSpacing();
messageSize.rheight() += dateMetrics.height(); messageSize.rheight() += textMargin;
messageSize.rheight() += dateMetrics.height() > statusIconSize ? dateMetrics.height() : statusIconSize;
if (messageSize.height() < avatarHeight) { if (messageSize.height() < avatarHeight) {
messageSize.setHeight(avatarHeight); messageSize.setHeight(avatarHeight);
@ -208,10 +224,18 @@ void MessageDelegate::initializeFonts(const QFont& font)
dateFont = font; dateFont = font;
nickFont.setBold(true); nickFont.setBold(true);
float ndps = nickFont.pointSizeF();
if (ndps != -1) {
nickFont.setPointSizeF(ndps * 1.2);
} else {
nickFont.setPointSize(nickFont.pointSize() + 2);
}
dateFont.setItalic(true); dateFont.setItalic(true);
float dps = dateFont.pointSizeF(); float dps = dateFont.pointSizeF();
if (dps != -1) { if (dps != -1) {
dateFont.setPointSizeF(dps * 0.7); dateFont.setPointSizeF(dps * 0.8);
} else { } else {
dateFont.setPointSize(dateFont.pointSize() - 2); dateFont.setPointSize(dateFont.pointSize() - 2);
} }
@ -243,7 +267,7 @@ void MessageDelegate::paintButton(QPushButton* btn, QPainter* painter, bool sent
btn->move(start); btn->move(start);
btn->show(); 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 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); painter->translate(start);
bar->render(painter, QPoint(), QRegion(), QWidget::DrawChildren); 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 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); QImage img(data.attach.localPath);
painter->drawImage(QRect(start, size), img); painter->drawImage(QRect(start, size), img);
option.rect.adjust(0, size.height(), 0, 0); option.rect.adjust(0, size.height() + textMargin, 0, 0);
} }
} }