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) {
|
||||
if (info.account == acc->getName()) {
|
||||
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);
|
||||
|
@ -32,6 +32,7 @@ const QHash<int, QByteArray> 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<QString, Q
|
||||
}
|
||||
|
||||
Shared::Message* msg = *itr;
|
||||
QVector<int> 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<QString, Q
|
||||
}
|
||||
|
||||
if (functor.hasIdBeenModified()) {
|
||||
|
||||
changeRoles.push_back(MessageRoles::Id);
|
||||
}
|
||||
|
||||
//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)
|
||||
@ -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<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
|
||||
Shared::Message* msg = static_cast<Shared::Message*>(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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<int> detectChanges(const Shared::Message& msg, const QMap<QString, QVariant>& 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;
|
||||
|
@ -29,6 +29,14 @@
|
||||
constexpr int maxMessageHeight = 10000;
|
||||
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):
|
||||
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<int>& 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);
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <QAbstractItemView>
|
||||
|
||||
#include <deque>
|
||||
#include <set>
|
||||
|
||||
#include <ui/models/messagefeed.h>
|
||||
|
||||
@ -77,6 +78,8 @@ private:
|
||||
bool specialModel;
|
||||
bool clearWidgetsMode;
|
||||
|
||||
static const std::set<int> geometryChangingRoles;
|
||||
|
||||
};
|
||||
|
||||
#endif //FEEDVIEW_H
|
||||
|
@ -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<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();
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user