Date dividers between messages from different dates

This commit is contained in:
Blue 2021-09-22 01:17:43 +03:00
parent 5f925217fc
commit 3f09b8f838
Signed by untrusted user: blue
GPG Key ID: 9B203B252A63EE38
5 changed files with 78 additions and 4 deletions

View File

@ -22,6 +22,16 @@ option(WITH_KIO "Build KIO support module" ON)
# Dependencies # Dependencies
## Qt ## Qt
find_package(Qt5 COMPONENTS Widgets DBus Gui Xml Network Core REQUIRED) 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 ## QXmpp
if (SYSTEM_QXMPP) if (SYSTEM_QXMPP)

View File

@ -95,7 +95,7 @@ Shared::Global::Global():
} }
instance = this; instance = this;
#ifdef WITH_KIO #ifdef WITH_KIO
openFileManagerWindowJob.load(); openFileManagerWindowJob.load();
if (openFileManagerWindowJob.isLoaded()) { if (openFileManagerWindowJob.isLoaded()) {

View File

@ -29,6 +29,7 @@
constexpr int maxMessageHeight = 10000; constexpr int maxMessageHeight = 10000;
constexpr int approximateSingleMessageHeight = 20; constexpr int approximateSingleMessageHeight = 20;
constexpr int progressSize = 70; constexpr int progressSize = 70;
constexpr int dateDeviderMargin = 10;
const std::set<int> FeedView::geometryChangingRoles = { const std::set<int> FeedView::geometryChangingRoles = {
Models::MessageFeed::Attach, Models::MessageFeed::Attach,
@ -46,7 +47,9 @@ FeedView::FeedView(QWidget* parent):
specialModel(false), specialModel(false),
clearWidgetsMode(false), clearWidgetsMode(false),
modelState(Models::MessageFeed::complete), modelState(Models::MessageFeed::complete),
progress() progress(),
dividerFont(),
dividerMetrics(dividerFont)
{ {
horizontalScrollBar()->setRange(0, 0); horizontalScrollBar()->setRange(0, 0);
verticalScrollBar()->setSingleStep(approximateSingleMessageHeight); verticalScrollBar()->setSingleStep(approximateSingleMessageHeight);
@ -56,6 +59,15 @@ FeedView::FeedView(QWidget* parent):
progress.setParent(viewport()); progress.setParent(viewport());
progress.resize(progressSize, progressSize); 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() FeedView::~FeedView()
@ -187,8 +199,16 @@ void FeedView::updateGeometries()
hints.clear(); hints.clear();
uint32_t previousOffset = 0; uint32_t previousOffset = 0;
QDateTime lastDate;
for (int i = 0, size = m->rowCount(); i < size; ++i) { for (int i = 0, size = m->rowCount(); i < size; ++i) {
QModelIndex index = m->index(i, 0, rootIndex()); 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(); int height = itemDelegate(index)->sizeHint(option, index).height();
hints.emplace_back(Hint({ hints.emplace_back(Hint({
false, false,
@ -222,8 +242,16 @@ bool FeedView::tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewIt
{ {
uint32_t previousOffset = 0; uint32_t previousOffset = 0;
bool success = true; bool success = true;
QDateTime lastDate;
for (int i = 0, size = m->rowCount(); i < size; ++i) { for (int i = 0, size = m->rowCount(); i < size; ++i) {
QModelIndex index = m->index(i, 0, rootIndex()); 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(); int height = itemDelegate(index)->sizeHint(option, index).height();
if (previousOffset + height > totalHeight) { if (previousOffset + height > totalHeight) {
@ -266,6 +294,7 @@ void FeedView::paintEvent(QPaintEvent* event)
toRener.emplace_back(m->index(i, 0, rootIndex())); toRener.emplace_back(m->index(i, 0, rootIndex()));
} }
if (y1 > relativeY1) { if (y1 > relativeY1) {
inZone = false;
break; break;
} }
} }
@ -282,11 +311,32 @@ void FeedView::paintEvent(QPaintEvent* event)
} }
} }
QDateTime lastDate;
bool first = true;
for (const QModelIndex& index : toRener) { for (const QModelIndex& index : toRener) {
QDateTime currentDate = index.data(Models::MessageFeed::Date).toDateTime();
option.rect = visualRect(index); 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); bool mouseOver = option.rect.contains(cursor) && vp->rect().contains(cursor);
option.state.setFlag(QStyle::State_MouseOver, mouseOver); option.state.setFlag(QStyle::State_MouseOver, mouseOver);
itemDelegate(index)->paint(&painter, option, index); 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) { 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) void FeedView::verticalScrollbarValueChanged(int value)
{ {
vo = verticalScrollBar()->maximum() - value; vo = verticalScrollBar()->maximum() - value;

View File

@ -73,6 +73,7 @@ protected:
private: private:
bool tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewItem& option, const QAbstractItemModel* model, uint32_t totalHeight); bool tryToCalculateGeometriesWithNoScrollbars(const QStyleOptionViewItem& option, const QAbstractItemModel* model, uint32_t totalHeight);
void positionProgress(); void positionProgress();
void drawDateDevider(int top, const QDateTime& date, QPainter& painter);
private: private:
struct Hint { struct Hint {
@ -87,6 +88,8 @@ private:
bool clearWidgetsMode; bool clearWidgetsMode;
Models::MessageFeed::SyncState modelState; Models::MessageFeed::SyncState modelState;
Progress progress; Progress progress;
QFont dividerFont;
QFontMetrics dividerMetrics;
static const std::set<int> geometryChangingRoles; static const std::set<int> geometryChangingRoles;

View File

@ -130,12 +130,13 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio
} }
messageSize.rheight() += nickMetrics.lineSpacing(); messageSize.rheight() += nickMetrics.lineSpacing();
messageSize.rheight() += dateMetrics.height(); messageSize.rheight() += dateMetrics.height();
QString dateString = data.date.toLocalTime().toString("hh:mm");
if (messageSize.width() < opt.rect.width()) { if (messageSize.width() < opt.rect.width()) {
QSize senderSize = nickMetrics.boundingRect(messageRect, 0, data.sender).size(); QSize senderSize = nickMetrics.boundingRect(messageRect, 0, data.sender).size();
if (senderSize.width() > messageSize.width()) { if (senderSize.width() > messageSize.width()) {
messageSize.setWidth(senderSize.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; int addition = 0;
if (data.correction.corrected) { if (data.correction.corrected) {
@ -211,7 +212,7 @@ void MessageDelegate::paint(QPainter* painter, const QStyleOptionViewItem& optio
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, dateString, &rect);
int currentY = opt.rect.y(); int currentY = opt.rect.y();
if (data.sentByMe) { if (data.sentByMe) {
QLabel* statusIcon = getStatusIcon(data); QLabel* statusIcon = getStatusIcon(data);