2
0
mirror of https://github.com/kotatogram/kotatogram-desktop synced 2025-08-31 14:45:14 +00:00

Display unread reactions badge in chats list.

This commit is contained in:
John Preston
2022-01-27 15:55:34 +03:00
parent e9c79886d2
commit 8f33d5903d
23 changed files with 377 additions and 307 deletions

View File

@@ -848,10 +848,6 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
mouseActionUpdate();
}
const auto guard = gsl::finally([&] {
_userpicsCache.clear();
});
Painter p(this);
auto clip = e->rect();
@@ -872,7 +868,6 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
const auto now = crl::now();
const auto historyDisplayedEmpty = _history->isDisplayedEmpty()
&& (!_migrated || _migrated->isDisplayedEmpty());
bool noHistoryDisplayed = historyDisplayedEmpty;
if (_botAbout && !_botAbout->info->text.isEmpty() && _botAbout->height > 0) {
const auto st = context.st;
const auto stm = &st->messageStyle(false, false);
@@ -899,254 +894,251 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
_emptyPainter = nullptr;
}
_reactionsManager->startEffectsCollection();
if (!noHistoryDisplayed) {
auto readMentions = base::flat_set<not_null<HistoryItem*>>();
const auto mtop = migratedTop();
const auto htop = historyTop();
if (historyDisplayedEmpty || (mtop < 0 && htop < 0)) {
return;
}
adjustCurrent(clip.top());
auto drawToY = clip.y() + clip.height();
auto selfromy = itemTop(_dragSelFrom);
auto seltoy = itemTop(_dragSelTo);
if (selfromy < 0 || seltoy < 0) {
selfromy = seltoy = -1;
} else {
seltoy += _dragSelTo->height();
auto readTill = (HistoryItem*)nullptr;
auto readContents = base::flat_set<not_null<HistoryItem*>>();
const auto guard = gsl::finally([&] {
if (readTill && _widget->doWeReadServerHistory()) {
session().data().histories().readInboxTill(readTill);
}
if (!readContents.empty() && _widget->doWeReadMentions()) {
session().api().markContentsRead(readContents);
}
_userpicsCache.clear();
});
auto mtop = migratedTop();
auto htop = historyTop();
auto hdrawtop = historyDrawTop();
if (mtop >= 0) {
auto iBlock = (_curHistory == _migrated ? _curBlock : (_migrated->blocks.size() - 1));
auto block = _migrated->blocks[iBlock].get();
auto iItem = (_curHistory == _migrated ? _curItem : (block->messages.size() - 1));
auto view = block->messages[iItem].get();
auto item = view->data();
const auto processPainted = [&](
not_null<Element*> view,
int top,
int height) {
const auto item = view->data();
const auto isSponsored = item->isSponsored();
const auto isUnread = !item->out()
&& item->unread()
&& (item->history() == _history);
const auto withReaction = item->hasUnreadReaction();
const auto yShown = [&](int y) {
return (_visibleAreaBottom >= y && _visibleAreaTop <= y);
};
const auto markShown = isSponsored
? view->markSponsoredViewed(_visibleAreaBottom - top)
: withReaction
? yShown(top + context.reactionInfo->position.y())
: isUnread
? yShown(top + height)
: yShown(top + height / 2);
if (markShown) {
if (isSponsored) {
session().data().sponsoredMessages().view(
item->fullId());
} else if (isUnread) {
readTill = item;
}
if (item->hasViews()) {
session().api().views().scheduleIncrement(item);
}
if (withReaction) {
readContents.insert(item);
} else if (item->isUnreadMention()
&& !item->isUnreadMedia()) {
readContents.insert(item);
_widget->enqueueMessageHighlight(view);
}
}
session().data().reactions().poll(item, now);
_reactionsManager->recordCurrentReactionEffect(
item->fullId(),
QPoint(0, top));
};
auto top = mtop + block->y() + view->y();
context.translate(0, -top);
p.translate(0, top);
if (context.clip.y() < view->height()) while (top < drawToY) {
context.reactionEffects
= _reactionsManager->currentReactionEffect();
adjustCurrent(clip.top());
const auto drawToY = clip.y() + clip.height();
auto selfromy = itemTop(_dragSelFrom);
auto seltoy = itemTop(_dragSelTo);
if (selfromy < 0 || seltoy < 0) {
selfromy = seltoy = -1;
} else {
seltoy += _dragSelTo->height();
}
const auto hdrawtop = historyDrawTop();
if (mtop >= 0) {
auto iBlock = (_curHistory == _migrated ? _curBlock : (_migrated->blocks.size() - 1));
auto block = _migrated->blocks[iBlock].get();
auto iItem = (_curHistory == _migrated ? _curItem : (block->messages.size() - 1));
auto view = block->messages[iItem].get();
auto top = mtop + block->y() + view->y();
context.translate(0, -top);
p.translate(0, top);
if (context.clip.y() < view->height()) while (top < drawToY) {
const auto height = view->height();
context.reactionInfo
= _reactionsManager->currentReactionPaintInfo();
context.outbg = view->hasOutLayout();
context.selection = itemRenderSelection(
view,
selfromy - mtop,
seltoy - mtop);
view->draw(p, context);
processPainted(view, top, height);
top += height;
context.translate(0, -height);
p.translate(0, height);
++iItem;
if (iItem == block->messages.size()) {
iItem = 0;
++iBlock;
if (iBlock == _migrated->blocks.size()) {
break;
}
block = _migrated->blocks[iBlock].get();
}
view = block->messages[iItem].get();
}
context.translate(0, top);
p.translate(0, -top);
}
if (htop >= 0) {
auto iBlock = (_curHistory == _history ? _curBlock : 0);
auto block = _history->blocks[iBlock].get();
auto iItem = (_curHistory == _history ? _curItem : 0);
auto view = block->messages[iItem].get();
auto top = htop + block->y() + view->y();
context.clip = clip.intersected(
QRect(0, hdrawtop, width(), clip.top() + clip.height()));
context.translate(0, -top);
p.translate(0, top);
while (top < drawToY) {
const auto height = view->height();
if (context.clip.y() < height && hdrawtop < top + height) {
context.reactionInfo
= _reactionsManager->currentReactionPaintInfo();
context.outbg = view->hasOutLayout();
context.selection = itemRenderSelection(
view,
selfromy - mtop,
seltoy - mtop);
selfromy - htop,
seltoy - htop);
view->draw(p, context);
_reactionsManager->recordCurrentReactionEffect(
item->fullId(),
QPoint(0, top));
const auto height = view->height();
const auto middle = top + height / 2;
if (_visibleAreaBottom >= middle
&& _visibleAreaTop <= middle) {
if (item->hasViews()) {
session().api().views().scheduleIncrement(item);
}
if (item->isUnreadMention() && !item->isUnreadMedia()) {
readMentions.insert(item);
_widget->enqueueMessageHighlight(view);
}
session().data().reactions().poll(item, now);
}
top += height;
context.translate(0, -height);
p.translate(0, height);
++iItem;
if (iItem == block->messages.size()) {
iItem = 0;
++iBlock;
if (iBlock == _migrated->blocks.size()) {
break;
}
block = _migrated->blocks[iBlock].get();
}
view = block->messages[iItem].get();
item = view->data();
processPainted(view, top, height);
}
context.translate(0, top);
p.translate(0, -top);
}
if (htop >= 0) {
auto iBlock = (_curHistory == _history ? _curBlock : 0);
auto block = _history->blocks[iBlock].get();
auto iItem = (_curHistory == _history ? _curItem : 0);
auto view = block->messages[iItem].get();
auto item = view->data();
auto readTill = (HistoryItem*)nullptr;
auto top = htop + block->y() + view->y();
context.clip = clip.intersected(
QRect(0, hdrawtop, width(), clip.top() + clip.height()));
context.translate(0, -top);
p.translate(0, top);
while (top < drawToY) {
const auto height = view->height();
if (context.clip.y() < height && hdrawtop < top + height) {
context.reactionEffects
= _reactionsManager->currentReactionEffect();
context.outbg = view->hasOutLayout();
context.selection = itemRenderSelection(
view,
selfromy - htop,
seltoy - htop);
view->draw(p, context);
_reactionsManager->recordCurrentReactionEffect(
item->fullId(),
QPoint(0, top));
top += height;
context.translate(0, -height);
p.translate(0, height);
const auto middle = top + height / 2;
const auto bottom = top + height;
if (_visibleAreaBottom >= bottom) {
if (!item->out() && item->unread()) {
readTill = item;
}
}
if (item->isSponsored()
&& view->markSponsoredViewed(
_visibleAreaBottom - top)) {
session().data().sponsoredMessages().view(
item->fullId());
}
if (_visibleAreaBottom >= middle
&& _visibleAreaTop <= middle) {
if (item->hasViews()) {
session().api().views().scheduleIncrement(item);
}
if (item->isUnreadMention()
&& !item->isUnreadMedia()) {
readMentions.insert(item);
_widget->enqueueMessageHighlight(view);
}
}
session().data().reactions().poll(item, now);
++iItem;
if (iItem == block->messages.size()) {
iItem = 0;
++iBlock;
if (iBlock == _history->blocks.size()) {
break;
}
top += height;
context.translate(0, -height);
p.translate(0, height);
++iItem;
if (iItem == block->messages.size()) {
iItem = 0;
++iBlock;
if (iBlock == _history->blocks.size()) {
break;
}
block = _history->blocks[iBlock].get();
}
view = block->messages[iItem].get();
item = view->data();
}
context.translate(0, top);
p.translate(0, -top);
if (readTill && _widget->doWeReadServerHistory()) {
session().data().histories().readInboxTill(readTill);
block = _history->blocks[iBlock].get();
}
view = block->messages[iItem].get();
}
if (!readMentions.empty() && _widget->doWeReadMentions()) {
session().api().markContentsRead(readMentions);
}
if (mtop >= 0 || htop >= 0) {
enumerateUserpics([&](not_null<Element*> view, int userpicTop) {
// stop the enumeration if the userpic is below the painted rect
if (userpicTop >= clip.top() + clip.height()) {
return false;
}
// paint the userpic if it intersects the painted rect
if (userpicTop + st::msgPhotoSize > clip.top()) {
if (const auto from = view->data()->displayFrom()) {
from->paintUserpicLeft(
p,
_userpics[from],
st::historyPhotoLeft,
userpicTop,
width(),
st::msgPhotoSize);
} else if (const auto info = view->data()->hiddenSenderInfo()) {
info->userpic.paint(
p,
st::historyPhotoLeft,
userpicTop,
width(),
st::msgPhotoSize);
} else {
Unexpected("Corrupt forwarded information in message.");
}
}
return true;
});
int dateHeight = st::msgServicePadding.bottom() + st::msgServiceFont->height + st::msgServicePadding.top();
//QDate lastDate;
//if (!_history->isEmpty()) {
// lastDate = _history->blocks.back()->messages.back()->data()->date.date();
//}
//// if item top is before this value always show date as a floating date
//int showFloatingBefore = height() - 2 * (_visibleAreaBottom - _visibleAreaTop) - dateHeight;
auto scrollDateOpacity = _scrollDateOpacity.value(_scrollDateShown ? 1. : 0.);
enumerateDates([&](not_null<Element*> view, int itemtop, int dateTop) {
// stop the enumeration if the date is above the painted rect
if (dateTop + dateHeight <= clip.top()) {
return false;
}
const auto displayDate = view->displayDate();
auto dateInPlace = displayDate;
if (dateInPlace) {
const auto correctDateTop = itemtop + st::msgServiceMargin.top();
dateInPlace = (dateTop < correctDateTop + dateHeight);
}
//bool noFloatingDate = (item->date.date() == lastDate && displayDate);
//if (noFloatingDate) {
// if (itemtop < showFloatingBefore) {
// noFloatingDate = false;
// }
//}
// paint the date if it intersects the painted rect
if (dateTop < clip.top() + clip.height()) {
auto opacity = (dateInPlace/* || noFloatingDate*/) ? 1. : scrollDateOpacity;
if (opacity > 0.) {
p.setOpacity(opacity);
const auto dateY = false // noFloatingDate
? itemtop
: (dateTop - st::msgServiceMargin.top());
if (const auto date = view->Get<HistoryView::DateBadge>()) {
date->paint(p, context.st, dateY, _contentWidth, _isChatWide);
} else {
HistoryView::ServiceMessagePainter::PaintDate(
p,
context.st,
view->dateTime(),
dateY,
_contentWidth,
_isChatWide);
}
}
}
return true;
});
p.setOpacity(1.);
_reactionsManager->paint(p, context);
p.translate(0, _historyPaddingTop);
_emojiInteractions->paint(p);
}
context.translate(0, top);
p.translate(0, -top);
}
enumerateUserpics([&](not_null<Element*> view, int userpicTop) {
// stop the enumeration if the userpic is below the painted rect
if (userpicTop >= clip.top() + clip.height()) {
return false;
}
// paint the userpic if it intersects the painted rect
if (userpicTop + st::msgPhotoSize > clip.top()) {
if (const auto from = view->data()->displayFrom()) {
from->paintUserpicLeft(
p,
_userpics[from],
st::historyPhotoLeft,
userpicTop,
width(),
st::msgPhotoSize);
} else if (const auto info = view->data()->hiddenSenderInfo()) {
info->userpic.paint(
p,
st::historyPhotoLeft,
userpicTop,
width(),
st::msgPhotoSize);
} else {
Unexpected("Corrupt forwarded information in message.");
}
}
return true;
});
const auto dateHeight = st::msgServicePadding.bottom()
+ st::msgServiceFont->height
+ st::msgServicePadding.top();
//QDate lastDate;
//if (!_history->isEmpty()) {
// lastDate = _history->blocks.back()->messages.back()->data()->date.date();
//}
//// if item top is before this value always show date as a floating date
//int showFloatingBefore = height() - 2 * (_visibleAreaBottom - _visibleAreaTop) - dateHeight;
auto scrollDateOpacity = _scrollDateOpacity.value(_scrollDateShown ? 1. : 0.);
enumerateDates([&](not_null<Element*> view, int itemtop, int dateTop) {
// stop the enumeration if the date is above the painted rect
if (dateTop + dateHeight <= clip.top()) {
return false;
}
const auto displayDate = view->displayDate();
auto dateInPlace = displayDate;
if (dateInPlace) {
const auto correctDateTop = itemtop + st::msgServiceMargin.top();
dateInPlace = (dateTop < correctDateTop + dateHeight);
}
//bool noFloatingDate = (item->date.date() == lastDate && displayDate);
//if (noFloatingDate) {
// if (itemtop < showFloatingBefore) {
// noFloatingDate = false;
// }
//}
// paint the date if it intersects the painted rect
if (dateTop < clip.top() + clip.height()) {
auto opacity = (dateInPlace/* || noFloatingDate*/) ? 1. : scrollDateOpacity;
if (opacity > 0.) {
p.setOpacity(opacity);
const auto dateY = false // noFloatingDate
? itemtop
: (dateTop - st::msgServiceMargin.top());
if (const auto date = view->Get<HistoryView::DateBadge>()) {
date->paint(p, context.st, dateY, _contentWidth, _isChatWide);
} else {
HistoryView::ServiceMessagePainter::PaintDate(
p,
context.st,
view->dateTime(),
dateY,
_contentWidth,
_isChatWide);
}
}
}
return true;
});
p.setOpacity(1.);
_reactionsManager->paint(p, context);
p.translate(0, _historyPaddingTop);
_emojiInteractions->paint(p);
}
bool HistoryInner::eventHook(QEvent *e) {