From 3f09b8f838d78bd7029a82868d1e8edaa5c957b7 Mon Sep 17 00:00:00 2001 From: Blue Date: Wed, 22 Sep 2021 01:17:43 +0300 Subject: [PATCH] Date dividers between messages from different dates --- CMakeLists.txt | 10 ++++ shared/global.cpp | 2 +- ui/widgets/messageline/feedview.cpp | 62 +++++++++++++++++++++- ui/widgets/messageline/feedview.h | 3 ++ ui/widgets/messageline/messagedelegate.cpp | 5 +- 5 files changed, 78 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b9349d9..b978c33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,16 @@ option(WITH_KIO "Build KIO support module" ON) # Dependencies ## Qt find_package(Qt5 COMPONENTS Widgets DBus Gui Xml Network Core REQUIRED) +find_package(Boost COMPONENTS) + +target_include_directories(squawk PRIVATE ${Boost_INCLUDE_DIRS}) +target_include_directories(squawk PRIVATE ${Qt5_INCLUDE_DIRS}) +target_include_directories(squawk PRIVATE ${Qt5Widgets_INCLUDE_DIRS}) +target_include_directories(squawk PRIVATE ${Qt5DBus_INCLUDE_DIRS}) +target_include_directories(squawk PRIVATE ${Qt5Gui_INCLUDE_DIRS}) +target_include_directories(squawk PRIVATE ${Qt5Xml_INCLUDE_DIRS}) +target_include_directories(squawk PRIVATE ${Qt5Network_INCLUDE_DIRS}) +target_include_directories(squawk PRIVATE ${Qt5Core_INCLUDE_DIRS}) ## QXmpp if (SYSTEM_QXMPP) diff --git a/shared/global.cpp b/shared/global.cpp index 67e74d1..d6f2169 100644 --- a/shared/global.cpp +++ b/shared/global.cpp @@ -95,7 +95,7 @@ Shared::Global::Global(): } instance = this; - + #ifdef WITH_KIO openFileManagerWindowJob.load(); if (openFileManagerWindowJob.isLoaded()) { diff --git a/ui/widgets/messageline/feedview.cpp b/ui/widgets/messageline/feedview.cpp index 6d8c180..7bdfb9e 100644 --- a/ui/widgets/messageline/feedview.cpp +++ b/ui/widgets/messageline/feedview.cpp @@ -29,6 +29,7 @@ constexpr int maxMessageHeight = 10000; constexpr int approximateSingleMessageHeight = 20; constexpr int progressSize = 70; +constexpr int dateDeviderMargin = 10; const std::set FeedView::geometryChangingRoles = { Models::MessageFeed::Attach, @@ -46,7 +47,9 @@ FeedView::FeedView(QWidget* parent): specialModel(false), clearWidgetsMode(false), modelState(Models::MessageFeed::complete), - progress() + progress(), + dividerFont(), + dividerMetrics(dividerFont) { horizontalScrollBar()->setRange(0, 0); verticalScrollBar()->setSingleStep(approximateSingleMessageHeight); @@ -56,6 +59,15 @@ FeedView::FeedView(QWidget* parent): progress.setParent(viewport()); progress.resize(progressSize, progressSize); + + dividerFont = getFont(); + dividerFont.setBold(true); + float ndps = dividerFont.pointSizeF(); + if (ndps != -1) { + dividerFont.setPointSizeF(ndps * 1.2); + } else { + dividerFont.setPointSize(dividerFont.pointSize() + 2); + } } FeedView::~FeedView() @@ -187,8 +199,16 @@ void FeedView::updateGeometries() hints.clear(); uint32_t previousOffset = 0; + QDateTime lastDate; for (int i = 0, size = m->rowCount(); i < size; ++i) { QModelIndex index = m->index(i, 0, rootIndex()); + QDateTime currentDate = index.data(Models::MessageFeed::Date).toDateTime(); + if (i > 0) { + if (currentDate.daysTo(lastDate) > 0) { + previousOffset += dividerMetrics.height() + dateDeviderMargin * 2; + } + } + lastDate = currentDate; int height = itemDelegate(index)->sizeHint(option, index).height(); hints.emplace_back(Hint({ false, @@ -222,8 +242,16 @@ bool FeedView::tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewIt { uint32_t previousOffset = 0; bool success = true; + QDateTime lastDate; for (int i = 0, size = m->rowCount(); i < size; ++i) { QModelIndex index = m->index(i, 0, rootIndex()); + QDateTime currentDate = index.data(Models::MessageFeed::Date).toDateTime(); + if (i > 0) { + if (currentDate.daysTo(lastDate) > 0) { + previousOffset += dateDeviderMargin * 2 + dividerMetrics.height(); + } + } + lastDate = currentDate; int height = itemDelegate(index)->sizeHint(option, index).height(); if (previousOffset + height > totalHeight) { @@ -266,6 +294,7 @@ void FeedView::paintEvent(QPaintEvent* event) toRener.emplace_back(m->index(i, 0, rootIndex())); } if (y1 > relativeY1) { + inZone = false; break; } } @@ -282,11 +311,32 @@ void FeedView::paintEvent(QPaintEvent* event) } } + QDateTime lastDate; + bool first = true; for (const QModelIndex& index : toRener) { + QDateTime currentDate = index.data(Models::MessageFeed::Date).toDateTime(); option.rect = visualRect(index); + if (first) { + int ind = index.row() - 1; + if (ind > 0) { + QDateTime underDate = m->index(ind, 0, rootIndex()).data(Models::MessageFeed::Date).toDateTime(); + if (currentDate.daysTo(underDate) > 0) { + drawDateDevider(option.rect.bottom(), underDate, painter); + } + } + first = false; + } bool mouseOver = option.rect.contains(cursor) && vp->rect().contains(cursor); option.state.setFlag(QStyle::State_MouseOver, mouseOver); itemDelegate(index)->paint(&painter, option, index); + + if (!lastDate.isNull() && currentDate.daysTo(lastDate) > 0) { + drawDateDevider(option.rect.bottom(), lastDate, painter); + } + lastDate = currentDate; + } + if (!lastDate.isNull() && inZone) { //if after drawing all messages there is still space + drawDateDevider(option.rect.bottom(), lastDate, painter); } if (clearWidgetsMode && specialDelegate) { @@ -300,6 +350,16 @@ void FeedView::paintEvent(QPaintEvent* event) } } +void FeedView::drawDateDevider(int top, const QDateTime& date, QPainter& painter) +{ + int divisionHeight = dateDeviderMargin * 2 + dividerMetrics.height(); + QRect r(QPoint(0, top), QSize(viewport()->width(), divisionHeight)); + painter.save(); + painter.setFont(dividerFont); + painter.drawText(r, Qt::AlignCenter, date.toString("d MMMM")); + painter.restore(); +} + void FeedView::verticalScrollbarValueChanged(int value) { vo = verticalScrollBar()->maximum() - value; diff --git a/ui/widgets/messageline/feedview.h b/ui/widgets/messageline/feedview.h index b20276c..5e08946 100644 --- a/ui/widgets/messageline/feedview.h +++ b/ui/widgets/messageline/feedview.h @@ -73,6 +73,7 @@ protected: private: bool tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewItem& option, const QAbstractItemModel* model, uint32_t totalHeight); void positionProgress(); + void drawDateDevider(int top, const QDateTime& date, QPainter& painter); private: struct Hint { @@ -87,6 +88,8 @@ private: bool clearWidgetsMode; Models::MessageFeed::SyncState modelState; Progress progress; + QFont dividerFont; + QFontMetrics dividerMetrics; static const std::set geometryChangingRoles; diff --git a/ui/widgets/messageline/messagedelegate.cpp b/ui/widgets/messageline/messagedelegate.cpp index 8728ba3..649230e 100644 --- a/ui/widgets/messageline/messagedelegate.cpp +++ b/ui/widgets/messageline/messagedelegate.cpp @@ -130,12 +130,13 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio } messageSize.rheight() += nickMetrics.lineSpacing(); messageSize.rheight() += dateMetrics.height(); + QString dateString = data.date.toLocalTime().toString("hh:mm"); if (messageSize.width() < opt.rect.width()) { QSize senderSize = nickMetrics.boundingRect(messageRect, 0, data.sender).size(); if (senderSize.width() > messageSize.width()) { messageSize.setWidth(senderSize.width()); } - QSize dateSize = dateMetrics.boundingRect(messageRect, 0, data.date.toLocalTime().toString()).size(); + QSize dateSize = dateMetrics.boundingRect(messageRect, 0, dateString).size(); int addition = 0; if (data.correction.corrected) { @@ -211,7 +212,7 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio QColor q = painter->pen().color(); q.setAlpha(180); painter->setPen(q); - painter->drawText(opt.rect, opt.displayAlignment, data.date.toLocalTime().toString(), &rect); + painter->drawText(opt.rect, opt.displayAlignment, dateString, &rect); int currentY = opt.rect.y(); if (data.sentByMe) { QLabel* statusIcon = getStatusIcon(data);