forked from blue/squawk
bug with downloads in group chats, status icons in messages, visuals, feedView optimisations
This commit is contained in:
parent
0e937199b0
commit
d936c0302d
@ -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);
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user