Manage unread bar using HistoryView::Element-s.

This commit is contained in:
John Preston 2018-01-21 22:21:08 +03:00
parent 861ab85ca1
commit ebd4651ac2
23 changed files with 590 additions and 417 deletions

View File

@ -1225,6 +1225,9 @@ namespace {
} }
History *historyLoaded(const PeerId &peer) { History *historyLoaded(const PeerId &peer) {
if (!peer) {
return nullptr;
}
return ::histories.find(peer); return ::histories.find(peer);
} }

View File

@ -190,27 +190,33 @@ public:
} }
protected: protected:
void UpdateComponents(uint64 mask = 0) { bool UpdateComponents(uint64 mask = 0) {
if (!_meta()->equals(mask)) { if (_meta()->equals(mask)) {
RuntimeComposerBase tmp(mask); return false;
tmp.swap(*this); }
if (_data != zerodata() && tmp._data != zerodata()) { RuntimeComposerBase result(mask);
auto meta = _meta(), wasmeta = tmp._meta(); result.swap(*this);
for (int i = 0; i < meta->last; ++i) { if (_data != zerodata() && result._data != zerodata()) {
auto offset = meta->offsets[i]; const auto meta = _meta();
auto wasoffset = wasmeta->offsets[i]; const auto wasmeta = result._meta();
if (offset >= sizeof(_meta()) && wasoffset >= sizeof(_meta())) { for (auto i = 0; i != meta->last; ++i) {
RuntimeComponentWraps[i].Move(_dataptrunsafe(offset), tmp._dataptrunsafe(wasoffset)); const auto offset = meta->offsets[i];
const auto wasoffset = wasmeta->offsets[i];
if (offset >= sizeof(_meta())
&& wasoffset >= sizeof(_meta())) {
RuntimeComponentWraps[i].Move(
_dataptrunsafe(offset),
result._dataptrunsafe(wasoffset));
} }
} }
} }
return true;
} }
bool AddComponents(uint64 mask = 0) {
return UpdateComponents(_meta()->maskadd(mask));
} }
void AddComponents(uint64 mask = 0) { bool RemoveComponents(uint64 mask = 0) {
UpdateComponents(_meta()->maskadd(mask)); return UpdateComponents(_meta()->maskremove(mask));
}
void RemoveComponents(uint64 mask = 0) {
UpdateComponents(_meta()->maskremove(mask));
} }
private: private:

View File

@ -222,7 +222,7 @@ InnerWidget::InnerWidget(
Auth().data().viewResizeRequest( Auth().data().viewResizeRequest(
) | rpl::start_with_next([this](auto view) { ) | rpl::start_with_next([this](auto view) {
if (view->delegate() == this) { if (view->delegate() == this) {
updateSize(); resizeItem(view);
} }
}, lifetime()); }, lifetime());
Auth().data().itemViewRefreshRequest( Auth().data().itemViewRefreshRequest(
@ -1618,6 +1618,10 @@ void InnerWidget::repaintItem(const Element *view) {
update(0, itemTop(view), width(), view->height()); update(0, itemTop(view), width(), view->height());
} }
void InnerWidget::resizeItem(not_null<Element*> view) {
updateSize();
}
void InnerWidget::refreshItem(not_null<const Element*> view) { void InnerWidget::refreshItem(not_null<const Element*> view) {
// No need to refresh views in admin log. // No need to refresh views in admin log.
} }

View File

@ -123,6 +123,7 @@ private:
int itemTop(not_null<const Element*> view) const; int itemTop(not_null<const Element*> view) const;
void repaintItem(const Element *view); void repaintItem(const Element *view);
void refreshItem(not_null<const Element*> view); void refreshItem(not_null<const Element*> view);
void resizeItem(not_null<Element*> view);
QPoint mapPointToItem(QPoint point, const Element *view) const; QPoint mapPointToItem(QPoint point, const Element *view) const;
void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false); void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false);

View File

@ -79,13 +79,8 @@ void History::clearLastKeyboard() {
lastKeyboardFrom = 0; lastKeyboardFrom = 0;
} }
bool History::canHaveFromPhotos() const { int History::height() const {
if (peer->isUser() && !peer->isSelf() && !Adaptive::ChatWide()) { return _height;
return false;
} else if (isChannel() && !peer->isMegagroup()) {
return false;
}
return true;
} }
void History::setHasPendingResizedItems() { void History::setHasPendingResizedItems() {
@ -259,9 +254,22 @@ bool History::mySendActionUpdated(SendAction::Type type, bool doing) {
return true; return true;
} }
bool History::paintSendAction(Painter &p, int x, int y, int availableWidth, int outerWidth, style::color color, TimeMs ms) { bool History::paintSendAction(
Painter &p,
int x,
int y,
int availableWidth,
int outerWidth,
style::color color,
TimeMs ms) {
if (_sendActionAnimation) { if (_sendActionAnimation) {
_sendActionAnimation.paint(p, color, x, y + st::normalFont->ascent, outerWidth, ms); _sendActionAnimation.paint(
p,
color,
x,
y + st::normalFont->ascent,
outerWidth,
ms);
auto animationWidth = _sendActionAnimation.width(); auto animationWidth = _sendActionAnimation.width();
x += animationWidth; x += animationWidth;
availableWidth -= animationWidth; availableWidth -= animationWidth;
@ -572,7 +580,11 @@ not_null<History*> Histories::findOrInsert(const PeerId &peerId) {
return i.value(); return i.value();
} }
not_null<History*> Histories::findOrInsert(const PeerId &peerId, int32 unreadCount, int32 maxInboxRead, int32 maxOutboxRead) { not_null<History*> Histories::findOrInsert(
const PeerId &peerId,
int unreadCount,
MsgId maxInboxRead,
MsgId maxOutboxRead) {
auto i = map.constFind(peerId); auto i = map.constFind(peerId);
if (i == map.cend()) { if (i == map.cend()) {
auto history = peerIsChannel(peerId) auto history = peerIsChannel(peerId)
@ -1397,6 +1409,23 @@ void History::clearSendAction(not_null<UserData*> from) {
} }
} }
void History::mainViewRemoved(
not_null<HistoryBlock*> block,
not_null<HistoryView::Element*> view) {
if (lastSentMsg == view->data()) {
lastSentMsg = nullptr;
}
if (_firstUnreadView == view) {
getNextFirstUnreadMessage();
}
if (_unreadBarView == view) {
_unreadBarView = nullptr;
}
if (scrollTopItem == view) {
getNextScrollTopItem(block, view->indexInBlock());
}
}
void History::newItemAdded(not_null<HistoryItem*> item) { void History::newItemAdded(not_null<HistoryItem*> item) {
App::checkImageCacheSize(); App::checkImageCacheSize();
item->indexAsNewItem(); item->indexAsNewItem();
@ -1408,9 +1437,7 @@ void History::newItemAdded(not_null<HistoryItem*> item) {
from->madeAction(itemServerTime.v); from->madeAction(itemServerTime.v);
} }
if (item->out()) { if (item->out()) {
if (unreadBar) { destroyUnreadBar();
unreadBar->destroyUnreadBar();
}
if (!item->unread()) { if (!item->unread()) {
outboxRead(item); outboxRead(item);
} }
@ -1739,18 +1766,23 @@ int History::countUnread(MsgId upTo) {
return result; return result;
} }
void History::updateShowFrom() { void History::calculateFirstUnreadMessage() {
if (showFrom) return; if (_firstUnreadView) {
return;
}
for (auto i = blocks.cend(); i != blocks.cbegin();) { for (auto i = blocks.cend(); i != blocks.cbegin();) {
--i; --i;
const auto &messages = (*i)->messages; const auto &messages = (*i)->messages;
for (auto j = messages.cend(); j != messages.cbegin();) { for (auto j = messages.cend(); j != messages.cbegin();) {
--j; --j;
const auto item = (*j)->data(); const auto view = j->get();
if (item->id > 0 && (!item->out() || !showFrom)) { const auto item = view->data();
if (!IsServerMsgId(item->id)) {
continue;
} else if (!item->out() || !_firstUnreadView) {
if (item->id >= inboxReadBefore) { if (item->id >= inboxReadBefore) {
showFrom = item; _firstUnreadView = view;
} else { } else {
return; return;
} }
@ -1776,7 +1808,7 @@ MsgId History::inboxRead(MsgId upTo) {
} }
} }
showFrom = nullptr; _firstUnreadView = nullptr;
Auth().notifications().clearFromHistory(this); Auth().notifications().clearFromHistory(this);
return upTo; return upTo;
@ -1805,13 +1837,19 @@ HistoryItem *History::lastAvailableMessage() const {
void History::setUnreadCount(int newUnreadCount) { void History::setUnreadCount(int newUnreadCount) {
if (_unreadCount != newUnreadCount) { if (_unreadCount != newUnreadCount) {
if (newUnreadCount == 1) { if (newUnreadCount == 1) {
if (loadedAtBottom()) showFrom = lastAvailableMessage(); if (loadedAtBottom()) {
_firstUnreadView = !isEmpty()
? blocks.back()->messages.back().get()
: nullptr;
}
inboxReadBefore = qMax(inboxReadBefore, msgIdForRead()); inboxReadBefore = qMax(inboxReadBefore, msgIdForRead());
} else if (!newUnreadCount) { } else if (!newUnreadCount) {
showFrom = nullptr; _firstUnreadView = nullptr;
inboxReadBefore = qMax(inboxReadBefore, msgIdForRead() + 1); inboxReadBefore = qMax(inboxReadBefore, msgIdForRead() + 1);
} else { } else {
if (!showFrom && !unreadBar && loadedAtBottom()) updateShowFrom(); if (!_firstUnreadView && !_unreadBarView && loadedAtBottom()) {
calculateFirstUnreadMessage();
}
} }
if (inChatList(Dialogs::Mode::All)) { if (inChatList(Dialogs::Mode::All)) {
App::histories().unreadIncrement(newUnreadCount - _unreadCount, mute()); App::histories().unreadIncrement(newUnreadCount - _unreadCount, mute());
@ -1820,22 +1858,17 @@ void History::setUnreadCount(int newUnreadCount) {
} }
} }
_unreadCount = newUnreadCount; _unreadCount = newUnreadCount;
if (auto main = App::main()) { if (_unreadBarView) {
main->unreadCountChanged(this); const auto count = chatListUnreadCount();
}
if (unreadBar) {
int32 count = _unreadCount;
if (peer->migrateTo()) {
if (History *h = App::historyLoaded(peer->migrateTo()->id)) {
count += h->unreadCount();
}
}
if (count > 0) { if (count > 0) {
unreadBar->setUnreadBarCount(count); _unreadBarView->setUnreadBarCount(count);
} else { } else {
unreadBar->setUnreadBarFreezed(); _unreadBarView->setUnreadBarFreezed();
} }
} }
if (const auto main = App::main()) {
main->unreadCountChanged(this);
}
} }
} }
@ -1858,18 +1891,21 @@ bool History::changeMute(bool newMute) {
return true; return true;
} }
void History::getNextShowFrom(HistoryBlock *block, int i) { void History::getNextFirstUnreadMessage() {
const auto setFromMessage = [&](const auto &message) { Expects(_firstUnreadView != nullptr);
const auto item = message->data();
if (item->id > 0) { const auto block = _firstUnreadView->block();
showFrom = item; const auto index = _firstUnreadView->indexInBlock();
const auto setFromMessage = [&](const auto &view) {
if (IsServerMsgId(view->data()->id)) {
_firstUnreadView = view.get();
return true; return true;
} }
return false; return false;
}; };
if (i >= 0) { if (index >= 0) {
auto l = block->messages.size(); const auto count = int(block->messages.size());
for (++i; i < l; ++i) { for (auto i = index + 1; i != count; ++i) {
const auto &message = block->messages[i]; const auto &message = block->messages[i];
if (setFromMessage(block->messages[i])) { if (setFromMessage(block->messages[i])) {
return; return;
@ -1877,15 +1913,15 @@ void History::getNextShowFrom(HistoryBlock *block, int i) {
} }
} }
for (auto j = block->indexInHistory() + 1, s = int(blocks.size()); j < s; ++j) { const auto count = int(blocks.size());
block = blocks[j].get(); for (auto j = block->indexInHistory() + 1; j != count; ++j) {
for (const auto &message : block->messages) { for (const auto &message : blocks[j]->messages) {
if (setFromMessage(message)) { if (setFromMessage(message)) {
return; return;
} }
} }
} }
showFrom = nullptr; _firstUnreadView = nullptr;
} }
QDateTime History::adjustChatListDate() const { QDateTime History::adjustChatListDate() const {
@ -1976,26 +2012,44 @@ void History::getNextScrollTopItem(HistoryBlock *block, int32 i) {
} }
void History::addUnreadBar() { void History::addUnreadBar() {
if (unreadBar || !showFrom || !showFrom->mainView() || !unreadCount()) { if (_unreadBarView || !_firstUnreadView || !unreadCount()) {
return; return;
} }
if (const auto count = chatListUnreadCount()) {
int32 count = unreadCount(); _unreadBarView = _firstUnreadView;
if (peer->migrateTo()) { _unreadBarView->setUnreadBarCount(count);
if (History *h = App::historyLoaded(peer->migrateTo()->id)) {
count += h->unreadCount();
} }
} }
showFrom->setUnreadBarCount(count);
unreadBar = showFrom;
}
void History::destroyUnreadBar() { void History::destroyUnreadBar() {
if (unreadBar) { if (const auto view = base::take(_unreadBarView)) {
unreadBar->destroyUnreadBar(); view->destroyUnreadBar();
} }
} }
bool History::hasNotFreezedUnreadBar() const {
if (_firstUnreadView) {
if (const auto view = _unreadBarView) {
if (const auto bar = view->Get<HistoryView::UnreadBar>()) {
return !bar->freezed;
}
}
}
return false;
}
void History::unsetFirstUnreadMessage() {
_firstUnreadView = nullptr;
}
HistoryView::Element *History::unreadBar() const {
return _unreadBarView;
}
HistoryView::Element *History::firstUnreadMessage() const {
return _firstUnreadView;
}
not_null<HistoryItem*> History::addNewInTheMiddle( not_null<HistoryItem*> History::addNewInTheMiddle(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
int blockIndex, int blockIndex,
@ -2028,10 +2082,16 @@ not_null<HistoryItem*> History::addNewInTheMiddle(
int History::chatListUnreadCount() const { int History::chatListUnreadCount() const {
const auto result = unreadCount(); const auto result = unreadCount();
const auto addFromId = [&] {
if (const auto from = peer->migrateFrom()) { if (const auto from = peer->migrateFrom()) {
if (const auto migrated = App::historyLoaded(from)) { return from->id;
return result + migrated->unreadCount(); } else if (const auto to = peer->migrateTo()) {
return to->id;
} }
return PeerId(0);
}();
if (const auto migrated = App::historyLoaded(addFromId)) {
return result + migrated->unreadCount();
} }
return result; return result;
} }
@ -2108,10 +2168,10 @@ bool History::isReadyFor(MsgId msgId) {
return loadedAtBottom(); return loadedAtBottom();
} }
if (msgId == ShowAtUnreadMsgId) { if (msgId == ShowAtUnreadMsgId) {
if (peer->migrateFrom()) { // old group history if (const auto migratePeer = peer->migrateFrom()) {
if (History *h = App::historyLoaded(peer->migrateFrom()->id)) { if (const auto migrated = App::historyLoaded(migratePeer)) {
if (h->unreadCount()) { if (migrated->unreadCount()) {
return h->isReadyFor(msgId); return migrated->isReadyFor(msgId);
} }
} }
} }
@ -2136,15 +2196,17 @@ void History::getReadyFor(MsgId msgId) {
} }
return; return;
} }
if (msgId == ShowAtUnreadMsgId && peer->migrateFrom()) { if (msgId == ShowAtUnreadMsgId) {
if (auto h = App::historyLoaded(peer->migrateFrom()->id)) { if (const auto migratePeer = peer->migrateFrom()) {
if (h->unreadCount()) { if (const auto migrated = App::historyLoaded(migratePeer)) {
if (migrated->unreadCount()) {
clear(true); clear(true);
h->getReadyFor(msgId); migrated->getReadyFor(msgId);
return; return;
} }
} }
} }
}
if (!isReadyFor(msgId)) { if (!isReadyFor(msgId)) {
clear(true); clear(true);
@ -2194,7 +2256,7 @@ bool History::needUpdateInChatList() const {
} }
void History::fixLastMessage(bool wasAtBottom) { void History::fixLastMessage(bool wasAtBottom) {
setLastMessage(wasAtBottom ? lastAvailableMessage() : 0); setLastMessage(wasAtBottom ? lastAvailableMessage() : nullptr);
} }
MsgId History::minMsgId() const { MsgId History::minMsgId() const {
@ -2227,22 +2289,21 @@ MsgId History::msgIdForRead() const {
return result; return result;
} }
int History::resizeGetHeight(int newWidth) { void History::resizeToWidth(int newWidth) {
const auto resizeAllItems = (width != newWidth); const auto resizeAllItems = (_width != newWidth);
if (!resizeAllItems && !hasPendingResizedItems()) { if (!resizeAllItems && !hasPendingResizedItems()) {
return height; return;
} }
_flags &= ~(Flag::f_has_pending_resized_items); _flags &= ~(Flag::f_has_pending_resized_items);
width = newWidth; _width = newWidth;
int y = 0; int y = 0;
for (const auto &block : blocks) { for (const auto &block : blocks) {
block->setY(y); block->setY(y);
y += block->resizeGetHeight(newWidth, resizeAllItems); y += block->resizeGetHeight(newWidth, resizeAllItems);
} }
height = y; _height = y;
return height;
} }
ChannelHistory *History::asChannelHistory() { ChannelHistory *History::asChannelHistory() {
@ -2295,11 +2356,11 @@ bool History::removeOrphanMediaGroupPart() {
} }
void History::clear(bool leaveItems) { void History::clear(bool leaveItems) {
if (unreadBar) { if (_unreadBarView) {
unreadBar = nullptr; _unreadBarView = nullptr;
} }
if (showFrom) { if (_firstUnreadView) {
showFrom = nullptr; _firstUnreadView = nullptr;
} }
if (lastSentMsg) { if (lastSentMsg) {
lastSentMsg = nullptr; lastSentMsg = nullptr;
@ -2475,22 +2536,11 @@ void HistoryBlock::clear(bool leaveItems) {
void HistoryBlock::remove(not_null<Element*> view) { void HistoryBlock::remove(not_null<Element*> view) {
Expects(view->block() == this); Expects(view->block() == this);
const auto item = view->data(); _history->mainViewRemoved(this, view);
auto blockIndex = indexInHistory();
auto itemIndex = view->indexInBlock();
if (_history->showFrom == item) {
_history->getNextShowFrom(this, itemIndex);
}
if (_history->lastSentMsg == item) {
_history->lastSentMsg = nullptr;
}
if (_history->unreadBar == item) {
_history->unreadBar = nullptr;
}
if (_history->scrollTopItem && _history->scrollTopItem->data() == item) {
_history->getNextScrollTopItem(this, itemIndex);
}
const auto blockIndex = indexInHistory();
const auto itemIndex = view->indexInBlock();
const auto item = view->data();
item->clearMainView(); item->clearMainView();
messages.erase(messages.begin() + itemIndex); messages.erase(messages.begin() + itemIndex);
for (auto i = itemIndex, l = int(messages.size()); i < l; ++i) { for (auto i = itemIndex, l = int(messages.size()); i < l; ++i) {

View File

@ -47,7 +47,11 @@ public:
History *find(const PeerId &peerId); History *find(const PeerId &peerId);
not_null<History*> findOrInsert(const PeerId &peerId); not_null<History*> findOrInsert(const PeerId &peerId);
not_null<History*> findOrInsert(const PeerId &peerId, int32 unreadCount, int32 maxInboxRead, int32 maxOutboxRead); not_null<History*> findOrInsert(
const PeerId &peerId,
int unreadCount,
MsgId maxInboxRead,
MsgId maxOutboxRead);
void clear(); void clear();
void remove(const PeerId &peer); void remove(const PeerId &peer);
@ -153,8 +157,6 @@ public:
void applyGroupAdminChanges(const base::flat_map<UserId, bool> &changes); void applyGroupAdminChanges(const base::flat_map<UserId, bool> &changes);
virtual ~History();
HistoryItem *addNewMessage(const MTPMessage &msg, NewMessageType type); HistoryItem *addNewMessage(const MTPMessage &msg, NewMessageType type);
HistoryItem *addToHistory(const MTPMessage &msg); HistoryItem *addToHistory(const MTPMessage &msg);
not_null<HistoryItem*> addNewService(MsgId msgId, QDateTime date, const QString &text, MTPDmessage::Flags flags = 0, bool newMsg = true); not_null<HistoryItem*> addNewService(MsgId msgId, QDateTime date, const QString &text, MTPDmessage::Flags flags = 0, bool newMsg = true);
@ -176,14 +178,11 @@ public:
void newItemAdded(not_null<HistoryItem*> item); void newItemAdded(not_null<HistoryItem*> item);
int countUnread(MsgId upTo); int countUnread(MsgId upTo);
void updateShowFrom();
MsgId inboxRead(MsgId upTo); MsgId inboxRead(MsgId upTo);
MsgId inboxRead(HistoryItem *wasRead); MsgId inboxRead(HistoryItem *wasRead);
MsgId outboxRead(MsgId upTo); MsgId outboxRead(MsgId upTo);
MsgId outboxRead(HistoryItem *wasRead); MsgId outboxRead(HistoryItem *wasRead);
HistoryItem *lastAvailableMessage() const;
int unreadCount() const { int unreadCount() const {
return _unreadCount; return _unreadCount;
} }
@ -192,9 +191,13 @@ public:
return _mute; return _mute;
} }
bool changeMute(bool newMute); bool changeMute(bool newMute);
void getNextShowFrom(HistoryBlock *block, int i);
void addUnreadBar(); void addUnreadBar();
void destroyUnreadBar(); void destroyUnreadBar();
bool hasNotFreezedUnreadBar() const;
HistoryView::Element *unreadBar() const;
void calculateFirstUnreadMessage();
void unsetFirstUnreadMessage();
HistoryView::Element *firstUnreadMessage() const;
void clearNotifications(); void clearNotifications();
bool loadedAtBottom() const; // last message is in the list bool loadedAtBottom() const; // last message is in the list
@ -210,7 +213,7 @@ public:
MsgId maxMsgId() const; MsgId maxMsgId() const;
MsgId msgIdForRead() const; MsgId msgIdForRead() const;
int resizeGetHeight(int newWidth); void resizeToWidth(int newWidth);
void removeNotification(HistoryItem *item) { void removeNotification(HistoryItem *item) {
if (!notifies.isEmpty()) { if (!notifies.isEmpty()) {
@ -254,10 +257,6 @@ public:
void clearLastKeyboard(); void clearLastKeyboard();
// optimization for userpics displayed on the left
// if this returns false there is no need to even try to handle them
bool canHaveFromPhotos() const;
int getUnreadMentionsLoadedCount() const { int getUnreadMentionsLoadedCount() const {
return _unreadMentions.size(); return _unreadMentions.size();
} }
@ -278,25 +277,6 @@ public:
void eraseFromUnreadMentions(MsgId msgId); void eraseFromUnreadMentions(MsgId msgId);
void addUnreadMentionsSlice(const MTPmessages_Messages &result); void addUnreadMentionsSlice(const MTPmessages_Messages &result);
std::deque<std::unique_ptr<HistoryBlock>> blocks;
int width = 0;
int height = 0;
int32 msgCount = 0;
MsgId inboxReadBefore = 1;
MsgId outboxReadBefore = 1;
HistoryItem *showFrom = nullptr;
HistoryItem *unreadBar = nullptr;
not_null<PeerData*> peer;
bool oldLoaded = false;
bool newLoaded = true;
HistoryItem *lastMsg = nullptr;
HistoryItem *lastSentMsg = nullptr;
typedef QList<HistoryItem*> NotifyQueue;
NotifyQueue notifies;
Data::Draft *localDraft() const { Data::Draft *localDraft() const {
return _localDraft.get(); return _localDraft.get();
} }
@ -340,9 +320,33 @@ public:
int y, int y,
int size) const override; int size) const override;
// some fields below are a property of a currently displayed instance of this void forgetScrollState() {
// conversation history not a property of the conversation history itself scrollTopItem = nullptr;
public: }
// find the correct scrollTopItem and scrollTopOffset using given top
// of the displayed window relative to the history start coordinate
void countScrollState(int top);
virtual ~History();
// Still public data.
std::deque<std::unique_ptr<HistoryBlock>> blocks;
int height() const;
int32 msgCount = 0;
MsgId inboxReadBefore = 1;
MsgId outboxReadBefore = 1;
not_null<PeerData*> peer;
bool oldLoaded = false;
bool newLoaded = true;
HistoryItem *lastMsg = nullptr;
HistoryItem *lastSentMsg = nullptr;
typedef QList<HistoryItem*> NotifyQueue;
NotifyQueue notifies;
// we save the last showAtMsgId to restore the state when switching // we save the last showAtMsgId to restore the state when switching
// between different conversation histories // between different conversation histories
MsgId showAtMsgId = ShowAtUnreadMsgId; MsgId showAtMsgId = ShowAtUnreadMsgId;
@ -352,25 +356,7 @@ public:
// resulting scrollTop = top(scrollTopItem) + scrollTopOffset // resulting scrollTop = top(scrollTopItem) + scrollTopOffset
HistoryView::Element *scrollTopItem = nullptr; HistoryView::Element *scrollTopItem = nullptr;
int scrollTopOffset = 0; int scrollTopOffset = 0;
void forgetScrollState() {
scrollTopItem = nullptr;
}
// find the correct scrollTopItem and scrollTopOffset using given top
// of the displayed window relative to the history start coord
void countScrollState(int top);
protected:
// when this item is destroyed scrollTopItem just points to the next one
// and scrollTopOffset remains the same
// if we are at the bottom of the window scrollTopItem == nullptr and
// scrollTopOffset is undefined
void getNextScrollTopItem(HistoryBlock *block, int32 i);
// helper method for countScrollState(int top)
void countScrollTopItem(int top);
public:
bool lastKeyboardInited = false; bool lastKeyboardInited = false;
bool lastKeyboardUsed = false; bool lastKeyboardUsed = false;
MsgId lastKeyboardId = 0; MsgId lastKeyboardId = 0;
@ -382,11 +368,18 @@ public:
Text cloudDraftTextCache; Text cloudDraftTextCache;
protected: protected:
// when this item is destroyed scrollTopItem just points to the next one
// and scrollTopOffset remains the same
// if we are at the bottom of the window scrollTopItem == nullptr and
// scrollTopOffset is undefined
void getNextScrollTopItem(HistoryBlock *block, int32 i);
// helper method for countScrollState(int top)
void countScrollTopItem(int top);
void clearOnDestroy(); void clearOnDestroy();
HistoryItem *addNewToLastBlock(const MTPMessage &msg, NewMessageType type); HistoryItem *addNewToLastBlock(const MTPMessage &msg, NewMessageType type);
friend class HistoryBlock;
// this method just removes a block from the blocks list // this method just removes a block from the blocks list
// when the last item from this block was detached and // when the last item from this block was detached and
// calls the required previousItemChanged() // calls the required previousItemChanged()
@ -425,6 +418,20 @@ protected:
} }
private: private:
friend class HistoryBlock;
enum class Flag {
f_has_pending_resized_items = (1 << 0),
};
using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) {
return true;
};
void mainViewRemoved(
not_null<HistoryBlock*> block,
not_null<HistoryView::Element*> view);
QDateTime adjustChatListDate() const override; QDateTime adjustChatListDate() const override;
void removeDialog() override; void removeDialog() override;
void changedInChatListHook(Dialogs::Mode list, bool added) override; void changedInChatListHook(Dialogs::Mode list, bool added) override;
@ -451,15 +458,20 @@ private:
void addItemsToLists(const std::vector<not_null<HistoryItem*>> &items); void addItemsToLists(const std::vector<not_null<HistoryItem*>> &items);
void clearSendAction(not_null<UserData*> from); void clearSendAction(not_null<UserData*> from);
enum class Flag { HistoryItem *lastAvailableMessage() const;
f_has_pending_resized_items = (1 << 0), void getNextFirstUnreadMessage();
};
using Flags = base::flags<Flag>; // Creates if necessary a new block for adding item.
friend inline constexpr auto is_flag_type(Flag) { return true; }; // Depending on isBuildingFrontBlock() gets front or back block.
HistoryBlock *prepareBlockForAddingItem();
Flags _flags = 0; Flags _flags = 0;
bool _mute = false; bool _mute = false;
int _unreadCount = 0; int _unreadCount = 0;
int _width = 0;
int _height = 0;
HistoryView::Element *_unreadBarView = nullptr;
HistoryView::Element *_firstUnreadView = nullptr;
base::optional<int> _unreadMentionsCount; base::optional<int> _unreadMentionsCount;
base::flat_set<MsgId> _unreadMentions; base::flat_set<MsgId> _unreadMentions;
@ -473,10 +485,6 @@ private:
}; };
std::unique_ptr<BuildingBlock> _buildingFrontBlock; std::unique_ptr<BuildingBlock> _buildingFrontBlock;
// Creates if necessary a new block for adding item.
// Depending on isBuildingFrontBlock() gets front or back block.
HistoryBlock *prepareBlockForAddingItem();
std::unique_ptr<Data::Draft> _localDraft, _cloudDraft; std::unique_ptr<Data::Draft> _localDraft, _cloudDraft;
std::unique_ptr<Data::Draft> _editDraft; std::unique_ptr<Data::Draft> _editDraft;
MessageIdsList _forwardDraft; MessageIdsList _forwardDraft;

View File

@ -217,7 +217,7 @@ void HistoryInner::enumerateItemsInHistory(History *history, int historytop, Met
if (historytop < 0 || history->isEmpty()) { if (historytop < 0 || history->isEmpty()) {
return; return;
} }
if (_visibleAreaBottom <= historytop || historytop + history->height <= _visibleAreaTop) { if (_visibleAreaBottom <= historytop || historytop + history->height() <= _visibleAreaTop) {
return; return;
} }
@ -302,9 +302,18 @@ void HistoryInner::enumerateItemsInHistory(History *history, int historytop, Met
} }
} }
bool HistoryInner::canHaveFromUserpics() const {
if (_peer->isUser() && !_peer->isSelf() && !Adaptive::ChatWide()) {
return false;
} else if (_peer->isChannel() && !_peer->isMegagroup()) {
return false;
}
return true;
}
template <typename Method> template <typename Method>
void HistoryInner::enumerateUserpics(Method method) { void HistoryInner::enumerateUserpics(Method method) {
if ((!_history || !_history->canHaveFromPhotos()) && (!_migrated || !_migrated->canHaveFromPhotos())) { if (!canHaveFromUserpics()) {
return; return;
} }
@ -620,7 +629,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
p, p,
st::historyPhotoLeft, st::historyPhotoLeft,
userpicTop, userpicTop,
message->history()->width, width(),
st::msgPhotoSize); st::msgPhotoSize);
} }
return true; return true;
@ -635,6 +644,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
//// if item top is before this value always show date as a floating date //// if item top is before this value always show date as a floating date
//int showFloatingBefore = height() - 2 * (_visibleAreaBottom - _visibleAreaTop) - dateHeight; //int showFloatingBefore = height() - 2 * (_visibleAreaBottom - _visibleAreaTop) - dateHeight;
auto scrollDateOpacity = _scrollDateOpacity.current(ms, _scrollDateShown ? 1. : 0.); auto scrollDateOpacity = _scrollDateOpacity.current(ms, _scrollDateShown ? 1. : 0.);
enumerateDates([&](not_null<Element*> view, int itemtop, int dateTop) { enumerateDates([&](not_null<Element*> view, int itemtop, int dateTop) {
// stop the enumeration if the date is above the painted rect // stop the enumeration if the date is above the painted rect
@ -661,16 +671,17 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
auto opacity = (dateInPlace/* || noFloatingDate*/) ? 1. : scrollDateOpacity; auto opacity = (dateInPlace/* || noFloatingDate*/) ? 1. : scrollDateOpacity;
if (opacity > 0.) { if (opacity > 0.) {
p.setOpacity(opacity); p.setOpacity(opacity);
int dateY = /*noFloatingDate ? itemtop :*/ (dateTop - st::msgServiceMargin.top()); const auto dateY = false // noFloatingDate
int width = item->history()->width; ? itemtop
: (dateTop - st::msgServiceMargin.top());
if (const auto date = item->Get<HistoryMessageDate>()) { if (const auto date = item->Get<HistoryMessageDate>()) {
date->paint(p, dateY, width); date->paint(p, dateY, _contentWidth);
} else { } else {
HistoryView::ServiceMessagePainter::paintDate( HistoryView::ServiceMessagePainter::paintDate(
p, p,
item->date, item->date,
dateY, dateY,
width); _contentWidth);
} }
} }
} }
@ -1825,15 +1836,17 @@ void HistoryInner::keyPressEvent(QKeyEvent *e) {
} }
void HistoryInner::recountHistoryGeometry() { void HistoryInner::recountHistoryGeometry() {
int visibleHeight = _scroll->height(); _contentWidth = _scroll->width();
const auto visibleHeight = _scroll->height();
int oldHistoryPaddingTop = qMax(visibleHeight - historyHeight() - st::historyPaddingBottom, 0); int oldHistoryPaddingTop = qMax(visibleHeight - historyHeight() - st::historyPaddingBottom, 0);
if (_botAbout && !_botAbout->info->text.isEmpty()) { if (_botAbout && !_botAbout->info->text.isEmpty()) {
accumulate_max(oldHistoryPaddingTop, st::msgMargin.top() + st::msgMargin.bottom() + st::msgPadding.top() + st::msgPadding.bottom() + st::msgNameFont->height + st::botDescSkip + _botAbout->height); accumulate_max(oldHistoryPaddingTop, st::msgMargin.top() + st::msgMargin.bottom() + st::msgPadding.top() + st::msgPadding.bottom() + st::msgNameFont->height + st::botDescSkip + _botAbout->height);
} }
_history->resizeGetHeight(_scroll->width()); _history->resizeToWidth(_contentWidth);
if (_migrated) { if (_migrated) {
_migrated->resizeGetHeight(_scroll->width()); _migrated->resizeToWidth(_contentWidth);
} }
// with migrated history we perhaps do not need to display first _history message // with migrated history we perhaps do not need to display first _history message
@ -2339,7 +2352,7 @@ void HistoryInner::onUpdateSelected() {
} }
dateWidth += st::msgServicePadding.left() + st::msgServicePadding.right(); dateWidth += st::msgServicePadding.left() + st::msgServicePadding.right();
auto dateLeft = st::msgServiceMargin.left(); auto dateLeft = st::msgServiceMargin.left();
auto maxwidth = item->history()->width; auto maxwidth = _contentWidth;
if (Adaptive::ChatWide()) { if (Adaptive::ChatWide()) {
maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left())); maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
} }
@ -2549,9 +2562,9 @@ void HistoryInner::updateDragSelection(Element *dragSelFrom, Element *dragSelTo,
int HistoryInner::historyHeight() const { int HistoryInner::historyHeight() const {
int result = 0; int result = 0;
if (!_history || _history->isEmpty()) { if (!_history || _history->isEmpty()) {
result += _migrated ? _migrated->height : 0; result += _migrated ? _migrated->height() : 0;
} else { } else {
result += _history->height - _historySkipHeight + (_migrated ? _migrated->height : 0); result += _history->height() - _historySkipHeight + (_migrated ? _migrated->height() : 0);
} }
return result; return result;
} }
@ -2574,7 +2587,7 @@ int HistoryInner::migratedTop() const {
int HistoryInner::historyTop() const { int HistoryInner::historyTop() const {
int mig = migratedTop(); int mig = migratedTop();
return (_history && !_history->isEmpty()) ? (mig >= 0 ? (mig + _migrated->height - _historySkipHeight) : _historyPaddingTop) : -1; return (_history && !_history->isEmpty()) ? (mig >= 0 ? (mig + _migrated->height() - _historySkipHeight) : _historyPaddingTop) : -1;
} }
int HistoryInner::historyDrawTop() const { int HistoryInner::historyDrawTop() const {

View File

@ -181,6 +181,7 @@ private:
template <typename Method> template <typename Method>
void enumerateDates(Method method); void enumerateDates(Method method);
bool canHaveFromUserpics() const;
void mouseActionStart(const QPoint &screenPos, Qt::MouseButton button); void mouseActionStart(const QPoint &screenPos, Qt::MouseButton button);
void mouseActionUpdate(const QPoint &screenPos); void mouseActionUpdate(const QPoint &screenPos);
void mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button); void mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button);
@ -276,6 +277,7 @@ private:
not_null<PeerData*> _peer; not_null<PeerData*> _peer;
not_null<History*> _history; not_null<History*> _history;
History *_migrated = nullptr; History *_migrated = nullptr;
int _contentWidth = 0;
int _historyPaddingTop = 0; int _historyPaddingTop = 0;
// with migrated history we perhaps do not need to display first _history message // with migrated history we perhaps do not need to display first _history message

View File

@ -577,47 +577,6 @@ bool HistoryItem::unread() const {
return (_flags & MTPDmessage_ClientFlag::f_clientside_unread); return (_flags & MTPDmessage_ClientFlag::f_clientside_unread);
} }
void HistoryItem::destroyUnreadBar() {
if (Has<HistoryMessageUnreadBar>()) {
Assert(!isLogEntry());
RemoveComponents(HistoryMessageUnreadBar::Bit());
Auth().data().requestItemResize(this);
if (_history->unreadBar == this) {
_history->unreadBar = nullptr;
}
// #TODO recount attach to previous
}
}
void HistoryItem::setUnreadBarCount(int count) {
Expects(!isLogEntry());
if (count > 0) {
if (!Has<HistoryMessageUnreadBar>()) {
AddComponents(HistoryMessageUnreadBar::Bit());
Auth().data().requestItemResize(this);
// #TODO recount attach to previous
}
const auto bar = Get<HistoryMessageUnreadBar>();
if (bar->_freezed) {
return;
}
bar->init(count);
Auth().data().requestItemRepaint(this);
} else {
destroyUnreadBar();
}
}
void HistoryItem::setUnreadBarFreezed() {
Expects(!isLogEntry());
if (const auto bar = Get<HistoryMessageUnreadBar>()) {
bar->_freezed = true;
}
}
MessageGroupId HistoryItem::groupId() const { MessageGroupId HistoryItem::groupId() const {
return _groupId; return _groupId;
} }

View File

@ -244,17 +244,6 @@ public:
QString authorOriginal() const; QString authorOriginal() const;
MsgId idOriginal() const; MsgId idOriginal() const;
// count > 0 - creates the unread bar if necessary and
// sets unread messages count if bar is not freezed yet
// count <= 0 - destroys the unread bar
void setUnreadBarCount(int count);
void destroyUnreadBar();
// marks the unread bar as freezed so that unread
// messages count will not change for this bar
// when the new messages arrive in this chat history
void setUnreadBarFreezed();
int displayedDateHeight() const; int displayedDateHeight() const;
bool displayDate() const; bool displayDate() const;

View File

@ -798,36 +798,6 @@ void HistoryMessageReplyMarkup::create(
} }
} }
void HistoryMessageUnreadBar::init(int count) {
if (_freezed) return;
_text = lng_unread_bar(lt_count, count);
_width = st::semiboldFont->width(_text);
}
int HistoryMessageUnreadBar::height() {
return st::historyUnreadBarHeight + st::historyUnreadBarMargin;
}
int HistoryMessageUnreadBar::marginTop() {
return st::lineWidth + st::historyUnreadBarMargin;
}
void HistoryMessageUnreadBar::paint(Painter &p, int y, int w) const {
p.fillRect(0, y + marginTop(), w, height() - marginTop() - st::lineWidth, st::historyUnreadBarBg);
p.fillRect(0, y + height() - st::lineWidth, w, st::lineWidth, st::historyUnreadBarBorder);
p.setFont(st::historyUnreadBarFont);
p.setPen(st::historyUnreadBarFg);
int left = st::msgServiceMargin.left();
int maxwidth = w;
if (Adaptive::ChatWide()) {
maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
}
w = maxwidth;
p.drawText((w - _width) / 2, y + marginTop() + (st::historyUnreadBarHeight - 2 * st::lineWidth - st::historyUnreadBarFont->height) / 2 + st::historyUnreadBarFont->ascent, _text);
}
void HistoryMessageDate::init(const QDateTime &date) { void HistoryMessageDate::init(const QDateTime &date) {
_text = langDayOfMonthFull(date.date()); _text = langDayOfMonthFull(date.date());
_width = st::msgServiceFont->width(_text); _width = st::msgServiceFont->width(_text);

View File

@ -335,29 +335,6 @@ struct HistoryMessageDate : public RuntimeComponent<HistoryMessageDate, HistoryI
int _width = 0; int _width = 0;
}; };
// Any HistoryItem can have this Component for
// displaying the unread messages bar above the message.
struct HistoryMessageUnreadBar : public RuntimeComponent<HistoryMessageUnreadBar, HistoryItem> {
void init(int count);
static int height();
static int marginTop();
void paint(Painter &p, int y, int w) const;
QString _text;
int _width = 0;
// If unread bar is freezed the new messages do not
// increment the counter displayed by this bar.
//
// It happens when we've opened the conversation and
// we've seen the bar and new messages are marked as read
// as soon as they are added to the chat history.
bool _freezed = false;
};
// Special type of Component for the channel actions log. // Special type of Component for the channel actions log.
struct HistoryMessageLogEntryOriginal struct HistoryMessageLogEntryOriginal
: public RuntimeComponent<HistoryMessageLogEntryOriginal, HistoryItem> { : public RuntimeComponent<HistoryMessageLogEntryOriginal, HistoryItem> {

View File

@ -2363,9 +2363,8 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM
} else if (!inWebPage) { } else if (!inWebPage) {
auto fullRight = paintx + usex + usew; auto fullRight = paintx + usex + usew;
auto fullBottom = painty + painth; auto fullBottom = painty + painth;
auto maxRight = item->history()->width - st::msgMargin.left(); auto maxRight = _parent->width() - st::msgMargin.left();
// #TODO view media if (_parent->hasFromPhoto()) {
if (item->history()->canHaveFromPhotos()) {
maxRight -= st::msgMargin.right(); maxRight -= st::msgMargin.right();
} else { } else {
maxRight -= st::msgMargin.left(); maxRight -= st::msgMargin.left();
@ -2505,9 +2504,8 @@ HistoryTextState HistoryGif::getState(QPoint point, HistoryStateRequest request)
if (isRound || _caption.isEmpty()) { if (isRound || _caption.isEmpty()) {
auto fullRight = usex + paintx + usew; auto fullRight = usex + paintx + usew;
auto fullBottom = painty + painth; auto fullBottom = painty + painth;
// #TODO view media auto maxRight = _parent->width() - st::msgMargin.left();
auto maxRight = _parent->data()->history()->width - st::msgMargin.left(); if (_parent->hasFromPhoto()) {
if (_parent->data()->history()->canHaveFromPhotos()) {
maxRight -= st::msgMargin.right(); maxRight -= st::msgMargin.right();
} else { } else {
maxRight -= st::msgMargin.left(); maxRight -= st::msgMargin.left();

View File

@ -2204,6 +2204,13 @@ void HistoryWidget::destroyUnreadBar() {
void HistoryWidget::newUnreadMsg(History *history, HistoryItem *item) { void HistoryWidget::newUnreadMsg(History *history, HistoryItem *item) {
if (_history == history) { if (_history == history) {
// If we get here in non-resized state we can't rely on results of
// doWeReadServerHistory() and mark chat as read.
// If we receive N messages being not at bottom:
// - on first message we set unreadcount += 1, firstUnreadMessage.
// - on second we get wrong doWeReadServerHistory() and read both.
Auth().data().sendHistoryChangeNotifications();
if (_scroll->scrollTop() + 1 > _scroll->scrollTopMax()) { if (_scroll->scrollTop() + 1 > _scroll->scrollTopMax()) {
destroyUnreadBar(); destroyUnreadBar();
} }
@ -2229,10 +2236,12 @@ void HistoryWidget::historyToDown(History *history) {
} }
} }
void HistoryWidget::unreadCountChanged(History *history) { void HistoryWidget::unreadCountChanged(not_null<History*> history) {
if (history == _history || history == _migrated) { if (history == _history || history == _migrated) {
updateHistoryDownVisibility(); updateHistoryDownVisibility();
_historyDown->setUnreadCount(_history->unreadCount() + (_migrated ? _migrated->unreadCount() : 0)); _historyDown->setUnreadCount(
_history->unreadCount()
+ (_migrated ? _migrated->unreadCount() : 0));
} }
} }
@ -2452,16 +2461,15 @@ bool HistoryWidget::doWeReadServerHistory() const {
int scrollTop = _scroll->scrollTop(); int scrollTop = _scroll->scrollTop();
if (scrollTop + 1 > _scroll->scrollTopMax()) return true; if (scrollTop + 1 > _scroll->scrollTopMax()) return true;
auto showFrom = (_migrated && _migrated->showFrom) ? _migrated->showFrom : (_history ? _history->showFrom : nullptr); if (const auto unread = firstUnreadMessage()) {
if (showFrom && showFrom->mainView()) { const auto scrollBottom = scrollTop + _scroll->height();
int scrollBottom = scrollTop + _scroll->height(); if (scrollBottom > _list->itemTop(unread)) {
if (scrollBottom > _list->itemTop(showFrom)) return true;
}
}
if (historyHasNotFreezedUnreadBar(_history)) {
return true; return true;
} }
if (historyHasNotFreezedUnreadBar(_migrated)) { }
}
if (_history->hasNotFreezedUnreadBar()
|| (_migrated && _migrated->hasNotFreezedUnreadBar())) {
return true; return true;
} }
return false; return false;
@ -2473,15 +2481,6 @@ bool HistoryWidget::doWeReadMentions() const {
return true; return true;
} }
bool HistoryWidget::historyHasNotFreezedUnreadBar(History *history) const {
if (history && history->showFrom && history->showFrom->mainView() && history->unreadBar) {
if (auto unreadBar = history->unreadBar->Get<HistoryMessageUnreadBar>()) {
return !unreadBar->_freezed;
}
}
return false;
}
void HistoryWidget::firstLoadMessages() { void HistoryWidget::firstLoadMessages() {
if (!_history || _firstLoadRequest) return; if (!_history || _firstLoadRequest) return;
@ -2707,10 +2706,12 @@ void HistoryWidget::visibleAreaUpdated() {
auto scrollBottom = scrollTop + _scroll->height(); auto scrollBottom = scrollTop + _scroll->height();
_list->visibleAreaUpdated(scrollTop, scrollBottom); _list->visibleAreaUpdated(scrollTop, scrollBottom);
if (_history->loadedAtBottom() && (_history->unreadCount() > 0 || (_migrated && _migrated->unreadCount() > 0))) { if (_history->loadedAtBottom() && (_history->unreadCount() > 0 || (_migrated && _migrated->unreadCount() > 0))) {
auto showFrom = (_migrated && _migrated->showFrom) ? _migrated->showFrom : (_history ? _history->showFrom : nullptr); const auto unread = firstUnreadMessage();
auto showFromVisible = (showFrom && showFrom->mainView() && scrollBottom > _list->itemTop(showFrom)); const auto unreadVisible = unread
auto atBottom = (scrollTop >= _scroll->scrollTopMax()); && (scrollBottom > _list->itemTop(unread));
if ((showFromVisible || atBottom) && App::wnd()->doWeReadServerHistory()) { const auto atBottom = (scrollTop >= _scroll->scrollTopMax());
if ((unreadVisible || atBottom)
&& App::wnd()->doWeReadServerHistory()) {
Auth().api().readServerHistory(_history); Auth().api().readServerHistory(_history);
} }
} }
@ -4694,8 +4695,8 @@ int HistoryWidget::countInitialScrollTop() {
result = itemTopForHighlight(view); result = itemTopForHighlight(view);
enqueueMessageHighlight(view); enqueueMessageHighlight(view);
} }
} else if (_history->unreadBar || (_migrated && _migrated->unreadBar)) { } else if (const auto top = unreadBarTop()) {
result = unreadBarTop(); result = *top;
} else { } else {
return countAutomaticScrollTop(); return countAutomaticScrollTop();
} }
@ -4704,28 +4705,18 @@ int HistoryWidget::countInitialScrollTop() {
int HistoryWidget::countAutomaticScrollTop() { int HistoryWidget::countAutomaticScrollTop() {
auto result = ScrollMax; auto result = ScrollMax;
if (_migrated && _migrated->showFrom) { if (const auto unread = firstUnreadMessage()) {
result = _list->itemTop(_migrated->showFrom); result = _list->itemTop(unread);
if (result < _scroll->scrollTopMax() + HistoryMessageUnreadBar::height() - HistoryMessageUnreadBar::marginTop()) { const auto possibleUnreadBarTop = _scroll->scrollTopMax()
_migrated->addUnreadBar(); + HistoryView::UnreadBar::height()
- HistoryView::UnreadBar::marginTop();
if (result < possibleUnreadBarTop) {
const auto history = unread->data()->history();
history->addUnreadBar();
if (hasPendingResizedItems()) { if (hasPendingResizedItems()) {
updateListSize(); updateListSize();
} }
if (_migrated->unreadBar) { if (history->unreadBar() != nullptr) {
setMsgId(ShowAtUnreadMsgId);
result = countInitialScrollTop();
App::wnd()->checkHistoryActivation();
return result;
}
}
} else if (_history->showFrom) {
result = _list->itemTop(_history->showFrom);
if (result < _scroll->scrollTopMax() + HistoryMessageUnreadBar::height() - HistoryMessageUnreadBar::marginTop()) {
_history->addUnreadBar();
if (hasPendingResizedItems()) {
updateListSize();
}
if (_history->unreadBar) {
setMsgId(ShowAtUnreadMsgId); setMsgId(ShowAtUnreadMsgId);
result = countInitialScrollTop(); result = countInitialScrollTop();
App::wnd()->checkHistoryActivation(); App::wnd()->checkHistoryActivation();
@ -4792,7 +4783,23 @@ void HistoryWidget::updateHistoryGeometry(bool initial, bool loadedDown, const S
updateListSize(); updateListSize();
_updateHistoryGeometryRequired = false; _updateHistoryGeometryRequired = false;
if ((!initial && !wasAtBottom) || (loadedDown && (!_history->showFrom || _history->unreadBar || _history->loadedAtBottom()) && (!_migrated || !_migrated->showFrom || _migrated->unreadBar || _history->loadedAtBottom()))) { if ((!initial && !wasAtBottom)
|| (loadedDown
&& (!_history->firstUnreadMessage()
|| _history->unreadBar()
|| _history->loadedAtBottom())
&& (!_migrated
|| !_migrated->firstUnreadMessage()
|| _migrated->unreadBar()
|| _history->loadedAtBottom()))) {
const auto historyScrollTop = _list->historyScrollTop();
if (!wasAtBottom && historyScrollTop == ScrollMax) {
// History scroll top was not inited yet.
// If we're showing locally unread messages, we get here
// from destroyUnreadBar() before we have time to scroll
// to good initial position, like top of an unread bar.
return;
}
auto toY = qMin(_list->historyScrollTop(), _scroll->scrollTopMax()); auto toY = qMin(_list->historyScrollTop(), _scroll->scrollTopMax());
if (change.type == ScrollChangeAdd) { if (change.type == ScrollChangeAdd) {
toY += change.value; toY += change.value;
@ -4815,7 +4822,9 @@ void HistoryWidget::updateHistoryGeometry(bool initial, bool loadedDown, const S
_historyInited = true; _historyInited = true;
_scrollToAnimation.finish(); _scrollToAnimation.finish();
} }
auto newScrollTop = initial ? countInitialScrollTop() : countAutomaticScrollTop(); auto newScrollTop = initial
? countInitialScrollTop()
: countAutomaticScrollTop();
if (_scroll->scrollTop() == newScrollTop) { if (_scroll->scrollTop() == newScrollTop) {
visibleAreaUpdated(); visibleAreaUpdated();
} else { } else {
@ -4841,25 +4850,33 @@ bool HistoryWidget::hasPendingResizedItems() const {
|| (_migrated && _migrated->hasPendingResizedItems()); || (_migrated && _migrated->hasPendingResizedItems());
} }
int HistoryWidget::unreadBarTop() const { base::optional<int> HistoryWidget::unreadBarTop() const {
auto getUnreadBar = [this]() -> HistoryItem* { auto getUnreadBar = [this]() -> HistoryView::Element* {
if (_migrated && _migrated->unreadBar) { if (const auto bar = _migrated ? _migrated->unreadBar() : nullptr) {
return _migrated->unreadBar; return bar;
} } else if (const auto bar = _history->unreadBar()) {
if (_history->unreadBar) { return bar;
return _history->unreadBar;
} }
return nullptr; return nullptr;
}; };
if (const auto bar = getUnreadBar()) { if (const auto bar = getUnreadBar()) {
auto result = _list->itemTop(bar) const auto result = _list->itemTop(bar)
+ HistoryMessageUnreadBar::marginTop(); + HistoryView::UnreadBar::marginTop();
if (bar->Has<HistoryMessageDate>()) { if (bar->data()->Has<HistoryMessageDate>()) {
result += bar->Get<HistoryMessageDate>()->height(); return result + bar->data()->Get<HistoryMessageDate>()->height();
} }
return result; return result;
} }
return -1; return base::none;
}
HistoryView::Element *HistoryWidget::firstUnreadMessage() const {
if (_migrated) {
if (const auto result = _migrated->firstUnreadMessage()) {
return result;
}
}
return _history ? _history->firstUnreadMessage() : nullptr;
} }
void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector<MTPMessage> &messages) { void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector<MTPMessage> &messages) {
@ -4879,14 +4896,18 @@ void HistoryWidget::addMessagesToBack(PeerData *peer, const QVector<MTPMessage>
} }
void HistoryWidget::countHistoryShowFrom() { void HistoryWidget::countHistoryShowFrom() {
if (_migrated && _showAtMsgId == ShowAtUnreadMsgId && _migrated->unreadCount()) { if (_migrated
_migrated->updateShowFrom(); && _showAtMsgId == ShowAtUnreadMsgId
&& _migrated->unreadCount()) {
_migrated->calculateFirstUnreadMessage();
} }
if ((_migrated && _migrated->showFrom) || _showAtMsgId != ShowAtUnreadMsgId || !_history->unreadCount()) { if ((_migrated && _migrated->firstUnreadMessage())
_history->showFrom = nullptr; || (_showAtMsgId != ShowAtUnreadMsgId)
return; || !_history->unreadCount()) {
_history->unsetFirstUnreadMessage();
} else {
_history->calculateFirstUnreadMessage();
} }
_history->updateShowFrom();
} }
void HistoryWidget::updateBotKeyboard(History *h, bool force) { void HistoryWidget::updateBotKeyboard(History *h, bool force) {
@ -4989,26 +5010,30 @@ void HistoryWidget::updateHistoryDownPosition() {
void HistoryWidget::updateHistoryDownVisibility() { void HistoryWidget::updateHistoryDownVisibility() {
if (_a_show.animating()) return; if (_a_show.animating()) return;
auto haveUnreadBelowBottom = [this](History *history) { auto haveUnreadBelowBottom = [&](History *history) {
if (!_list || !history || history->unreadCount() <= 0) { if (!_list || !history || history->unreadCount() <= 0) {
return false; return false;
} }
if (!history->showFrom || !history->showFrom->mainView()) { const auto unread = history->firstUnreadMessage();
if (!unread) {
return false; return false;
} }
return (_list->itemTop(history->showFrom) >= _scroll->scrollTop() + _scroll->height()); const auto top = _list->itemTop(unread);
return (top >= _scroll->scrollTop() + _scroll->height());
}; };
auto historyDownIsVisible = [this, &haveUnreadBelowBottom] { auto historyDownIsVisible = [&] {
if (!_history || _firstLoadRequest) { if (!_list || _firstLoadRequest) {
return false; return false;
} }
if (!_history->loadedAtBottom() || _replyReturn) { if (!_history->loadedAtBottom() || _replyReturn) {
return true; return true;
} }
if (_scroll->scrollTop() + st::historyToDownShownAfter < _scroll->scrollTopMax()) { const auto top = _scroll->scrollTop() + st::historyToDownShownAfter;
if (top < _scroll->scrollTopMax()) {
return true; return true;
} }
if (haveUnreadBelowBottom(_history) || haveUnreadBelowBottom(_migrated)) { if (haveUnreadBelowBottom(_history)
|| haveUnreadBelowBottom(_migrated)) {
return true; return true;
} }
return false; return false;
@ -5338,7 +5363,8 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() {
updatePinnedBar(); updatePinnedBar();
result = true; result = true;
if (_scroll->scrollTop() != unreadBarTop()) { const auto barTop = unreadBarTop();
if (!barTop || _scroll->scrollTop() != *barTop) {
synteticScrollToY(_scroll->scrollTop() + st::historyReplyHeight); synteticScrollToY(_scroll->scrollTop() + st::historyReplyHeight);
} }
} else if (_pinnedBar->msgId != pinnedId) { } else if (_pinnedBar->msgId != pinnedId) {
@ -5356,7 +5382,8 @@ bool HistoryWidget::pinnedMsgVisibilityUpdated() {
} else if (_pinnedBar) { } else if (_pinnedBar) {
destroyPinnedBar(); destroyPinnedBar();
result = true; result = true;
if (_scroll->scrollTop() != unreadBarTop()) { const auto barTop = unreadBarTop();
if (!barTop || _scroll->scrollTop() != *barTop) {
synteticScrollToY(_scroll->scrollTop() - st::historyReplyHeight); synteticScrollToY(_scroll->scrollTop() - st::historyReplyHeight);
} }
updateControlsGeometry(); updateControlsGeometry();

View File

@ -203,7 +203,7 @@ public:
void newUnreadMsg(History *history, HistoryItem *item); void newUnreadMsg(History *history, HistoryItem *item);
void historyToDown(History *history); void historyToDown(History *history);
void unreadCountChanged(History *history); void unreadCountChanged(not_null<History*> history);
QRect historyRect() const; QRect historyRect() const;
void pushTabbedSelectorToThirdSection( void pushTabbedSelectorToThirdSection(
@ -534,7 +534,6 @@ private:
void updateTabbedSelectorToggleTooltipGeometry(); void updateTabbedSelectorToggleTooltipGeometry();
void checkTabbedSelectorToggleTooltip(); void checkTabbedSelectorToggleTooltip();
bool historyHasNotFreezedUnreadBar(History *history) const;
bool canWriteMessage() const; bool canWriteMessage() const;
bool isRestrictedWrite() const; bool isRestrictedWrite() const;
void orderWidgets(); void orderWidgets();
@ -670,9 +669,10 @@ private:
// Counts scrollTop for placing the scroll right at the unread // Counts scrollTop for placing the scroll right at the unread
// messages bar, choosing from _history and _migrated unreadBar. // messages bar, choosing from _history and _migrated unreadBar.
int unreadBarTop() const; base::optional<int> unreadBarTop() const;
int itemTopForHighlight(not_null<HistoryView::Element*> view) const; int itemTopForHighlight(not_null<HistoryView::Element*> view) const;
void scrollToCurrentVoiceMessage(FullMsgId fromId, FullMsgId toId); void scrollToCurrentVoiceMessage(FullMsgId fromId, FullMsgId toId);
HistoryView::Element *firstUnreadMessage() const;
// Scroll to current y without updating the _lastUserScrolled time. // Scroll to current y without updating the _lastUserScrolled time.
// Used to distinguish between user scrolls and syntetic scrolls. // Used to distinguish between user scrolls and syntetic scrolls.

View File

@ -15,8 +15,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_groups.h" #include "data/data_groups.h"
#include "data/data_media_types.h" #include "data/data_media_types.h"
#include "lang/lang_keys.h"
#include "auth_session.h" #include "auth_session.h"
#include "layout.h" #include "layout.h"
#include "styles/style_history.h"
namespace HistoryView { namespace HistoryView {
namespace { namespace {
@ -54,6 +56,60 @@ TextSelection ShiftItemSelection(
return ShiftItemSelection(selection, byText.length()); return ShiftItemSelection(selection, byText.length());
} }
void UnreadBar::init(int count) {
if (freezed) {
return;
}
text = lng_unread_bar(lt_count, count);
width = st::semiboldFont->width(text);
}
int UnreadBar::height() {
return st::historyUnreadBarHeight + st::historyUnreadBarMargin;
}
int UnreadBar::marginTop() {
return st::lineWidth + st::historyUnreadBarMargin;
}
void UnreadBar::paint(Painter &p, int y, int w) const {
const auto bottom = y + height();
y += marginTop();
p.fillRect(
0,
y,
w,
height() - marginTop() - st::lineWidth,
st::historyUnreadBarBg);
p.fillRect(
0,
bottom - st::lineWidth,
w,
st::lineWidth,
st::historyUnreadBarBorder);
p.setFont(st::historyUnreadBarFont);
p.setPen(st::historyUnreadBarFg);
int left = st::msgServiceMargin.left();
int maxwidth = w;
if (Adaptive::ChatWide()) {
maxwidth = qMin(
maxwidth,
st::msgMaxWidth
+ 2 * st::msgPhotoSkip
+ 2 * st::msgMargin.left());
}
w = maxwidth;
const auto skip = st::historyUnreadBarHeight
- 2 * st::lineWidth
- st::historyUnreadBarFont->height;
p.drawText(
(w - width) / 2,
y + (skip / 2) + st::historyUnreadBarFont->ascent,
text);
}
Element::Element( Element::Element(
not_null<ElementDelegate*> delegate, not_null<ElementDelegate*> delegate,
not_null<HistoryItem*> data) not_null<HistoryItem*> data)
@ -99,8 +155,8 @@ int Element::marginTop() const {
} }
} }
result += item->displayedDateHeight(); result += item->displayedDateHeight();
if (const auto unreadbar = item->Get<HistoryMessageUnreadBar>()) { if (const auto bar = Get<UnreadBar>()) {
result += unreadbar->height(); result += bar->height();
} }
return result; return result;
} }
@ -198,7 +254,7 @@ void Element::refreshDataId() {
bool Element::computeIsAttachToPrevious(not_null<Element*> previous) { bool Element::computeIsAttachToPrevious(not_null<Element*> previous) {
const auto item = data(); const auto item = data();
if (!item->Has<HistoryMessageDate>() && !item->Has<HistoryMessageUnreadBar>()) { if (!item->Has<HistoryMessageDate>() && !Has<UnreadBar>()) {
const auto prev = previous->data(); const auto prev = previous->data();
const auto possible = !item->serviceMsg() && !prev->serviceMsg() const auto possible = !item->serviceMsg() && !prev->serviceMsg()
&& !item->isEmpty() && !prev->isEmpty() && !item->isEmpty() && !prev->isEmpty()
@ -217,6 +273,42 @@ bool Element::computeIsAttachToPrevious(not_null<Element*> previous) {
return false; return false;
} }
void Element::destroyUnreadBar() {
if (!Has<UnreadBar>()) {
return;
}
RemoveComponents(UnreadBar::Bit());
Auth().data().requestViewResize(this);
if (data()->mainView() == this) {
recountAttachToPreviousInBlocks();
}
}
void Element::setUnreadBarCount(int count) {
Expects(count > 0);
const auto changed = AddComponents(UnreadBar::Bit());
const auto bar = Get<UnreadBar>();
if (bar->freezed) {
return;
}
bar->init(count);
if (changed) {
if (data()->mainView() == this) {
recountAttachToPreviousInBlocks();
}
Auth().data().requestViewResize(this);
} else {
Auth().data().requestViewRepaint(this);
}
}
void Element::setUnreadBarFreezed() {
if (const auto bar = Get<UnreadBar>()) {
bar->freezed = true;
}
}
void Element::recountAttachToPreviousInBlocks() { void Element::recountAttachToPreviousInBlocks() {
auto attachToPrevious = false; auto attachToPrevious = false;
if (const auto previous = previousInBlocks()) { if (const auto previous = previousInBlocks()) {

View File

@ -55,6 +55,29 @@ TextSelection ShiftItemSelection(
TextSelection selection, TextSelection selection,
const Text &byText); const Text &byText);
// Any HistoryView::Element can have this Component for
// displaying the unread messages bar above the message.
struct UnreadBar : public RuntimeComponent<UnreadBar, Element> {
void init(int count);
static int height();
static int marginTop();
void paint(Painter &p, int y, int w) const;
QString text;
int width = 0;
// If unread bar is freezed the new messages do not
// increment the counter displayed by this bar.
//
// It happens when we've opened the conversation and
// we've seen the bar and new messages are marked as read
// as soon as they are added to the chat history.
bool freezed = false;
};
class Element class Element
: public Object : public Object
, public RuntimeComposer<Element> , public RuntimeComposer<Element>
@ -110,6 +133,16 @@ public:
bool computeIsAttachToPrevious(not_null<Element*> previous); bool computeIsAttachToPrevious(not_null<Element*> previous);
// count > 0 - creates the unread bar if necessary and
// sets unread messages count if bar is not freezed yet
void setUnreadBarCount(int count);
void destroyUnreadBar();
// marks the unread bar as freezed so that unread
// messages count will not change for this bar
// when the new messages arrive in this chat history
void setUnreadBarFreezed();
virtual void draw( virtual void draw(
Painter &p, Painter &p,
QRect clip, QRect clip,
@ -195,7 +228,7 @@ private:
void recountDisplayDateInBlocks(); void recountDisplayDateInBlocks();
// This should be called only from previousInBlocksChanged() or when // This should be called only from previousInBlocksChanged() or when
// HistoryMessageDate or HistoryMessageUnreadBar bit is changed in the Composer mask // HistoryMessageDate or UnreadBar bit is changed in the Composer mask
// then the result should be cached in a client side flag MTPDmessage_ClientFlag::f_attach_to_previous. // then the result should be cached in a client side flag MTPDmessage_ClientFlag::f_attach_to_previous.
void recountAttachToPreviousInBlocks(); void recountAttachToPreviousInBlocks();

View File

@ -231,7 +231,7 @@ ListWidget::ListWidget(
Auth().data().viewResizeRequest( Auth().data().viewResizeRequest(
) | rpl::start_with_next([this](auto view) { ) | rpl::start_with_next([this](auto view) {
if (view->delegate() == this) { if (view->delegate() == this) {
updateSize(); resizeItem(view);
} }
}, lifetime()); }, lifetime());
Auth().data().itemViewRefreshRequest( Auth().data().itemViewRefreshRequest(
@ -572,24 +572,7 @@ void ListWidget::updateItemsGeometry() {
} }
return count; return count;
}(); }();
if (first < count) { refreshAttachmentsFromTill(first, count);
auto view = _items[first].get();
for (auto i = first + 1; i != count; ++i) {
const auto next = _items[i].get();
if (next->isHiddenByGroup()) {
next->setDisplayDate(false);
} else {
const auto viewDate = view->data()->date;
const auto nextDate = next->data()->date;
next->setDisplayDate(nextDate.date() != viewDate.date());
auto attached = next->computeIsAttachToPrevious(view);
next->setAttachToPrevious(attached);
view->setAttachToNext(attached);
view = next;
}
}
}
updateSize();
} }
void ListWidget::updateSize() { void ListWidget::updateSize() {
@ -1452,6 +1435,61 @@ void ListWidget::repaintItem(const Element *view) {
update(0, itemTop(view), width(), view->height()); update(0, itemTop(view), width(), view->height());
} }
void ListWidget::resizeItem(not_null<Element*> view) {
const auto index = ranges::find(_items, view) - begin(_items);
if (index < int(_items.size())) {
refreshAttachmentsAtIndex(index);
}
}
void ListWidget::refreshAttachmentsAtIndex(int index) {
Expects(index >= 0 && index < _items.size());
const auto from = [&] {
if (index > 0) {
for (auto i = index - 1; i != 0; --i) {
if (!_items[i]->isHiddenByGroup()) {
return i;
}
}
}
return index;
}();
const auto till = [&] {
for (auto i = index + 1, count = int(_items.size()); i != count; ) {
if (!_items[i]->isHiddenByGroup()) {
return i + 1;
}
}
return index + 1;
}();
refreshAttachmentsFromTill(from, till);
}
void ListWidget::refreshAttachmentsFromTill(int from, int till) {
Expects(from >= 0 && from <= till && till <= int(_items.size()));
if (from == till) {
return;
}
auto view = _items[from].get();
for (auto i = from + 1; i != till; ++i) {
const auto next = _items[i].get();
if (next->isHiddenByGroup()) {
next->setDisplayDate(false);
} else {
const auto viewDate = view->data()->date;
const auto nextDate = next->data()->date;
next->setDisplayDate(nextDate.date() != viewDate.date());
auto attached = next->computeIsAttachToPrevious(view);
next->setAttachToPrevious(attached);
view->setAttachToNext(attached);
view = next;
}
}
updateSize();
}
void ListWidget::refreshItem(not_null<const Element*> view) { void ListWidget::refreshItem(not_null<const Element*> view) {
const auto i = ranges::find(_items, view); const auto i = ranges::find(_items, view);
const auto index = i - begin(_items); const auto index = i - begin(_items);
@ -1467,7 +1505,7 @@ void ListWidget::refreshItem(not_null<const Element*> view) {
viewReplaced(view, i->second.get()); viewReplaced(view, i->second.get());
updateItemsGeometry(); refreshAttachmentsAtIndex(index);
} }
} }

View File

@ -165,6 +165,7 @@ private:
void performDrag(); void performDrag();
int itemTop(not_null<const Element*> view) const; int itemTop(not_null<const Element*> view) const;
void repaintItem(const Element *view); void repaintItem(const Element *view);
void resizeItem(not_null<Element*> view);
void refreshItem(not_null<const Element*> view); void refreshItem(not_null<const Element*> view);
void itemRemoved(not_null<const HistoryItem*> item); void itemRemoved(not_null<const HistoryItem*> item);
QPoint mapPointToItem(QPoint point, const Element *view) const; QPoint mapPointToItem(QPoint point, const Element *view) const;
@ -194,6 +195,8 @@ private:
void updateVisibleTopItem(); void updateVisibleTopItem();
void updateItemsGeometry(); void updateItemsGeometry();
void updateSize(); void updateSize();
void refreshAttachmentsFromTill(int from, int till);
void refreshAttachmentsAtIndex(int index);
void toggleScrollDateShown(); void toggleScrollDateShown();
void repaintScrollDateCallback(); void repaintScrollDateCallback();

View File

@ -360,14 +360,14 @@ void Message::draw(
} }
auto dateh = 0; auto dateh = 0;
if (auto date = item->Get<HistoryMessageDate>()) { if (const auto date = item->Get<HistoryMessageDate>()) {
dateh = date->height(); dateh = date->height();
} }
if (auto unreadbar = item->Get<HistoryMessageUnreadBar>()) { if (const auto bar = Get<UnreadBar>()) {
auto unreadbarh = unreadbar->height(); auto unreadbarh = bar->height();
if (clip.intersects(QRect(0, dateh, width(), unreadbarh))) { if (clip.intersects(QRect(0, dateh, width(), unreadbarh))) {
p.translate(0, dateh); p.translate(0, dateh);
unreadbar->paint(p, 0, width()); bar->paint(p, 0, width());
p.translate(0, -dateh); p.translate(0, -dateh);
} }
} }

View File

@ -315,8 +315,8 @@ QSize Service::performCountCurrentSize(int newWidth) {
const auto media = this->media(); const auto media = this->media();
auto newHeight = item->displayedDateHeight(); auto newHeight = item->displayedDateHeight();
if (auto unreadbar = item->Get<HistoryMessageUnreadBar>()) { if (const auto bar = Get<UnreadBar>()) {
newHeight += unreadbar->height(); newHeight += bar->height();
} }
if (item->_text.isEmpty()) { if (item->_text.isEmpty()) {
@ -382,10 +382,10 @@ void Service::draw(
clip.translate(0, -dateh); clip.translate(0, -dateh);
height -= dateh; height -= dateh;
} }
if (auto unreadbar = item->Get<HistoryMessageUnreadBar>()) { if (const auto bar = Get<UnreadBar>()) {
unreadbarh = unreadbar->height(); unreadbarh = bar->height();
if (clip.intersects(QRect(0, 0, width(), unreadbarh))) { if (clip.intersects(QRect(0, 0, width(), unreadbarh))) {
unreadbar->paint(p, 0, width()); bar->paint(p, 0, width());
} }
p.translate(0, unreadbarh); p.translate(0, unreadbarh);
clip.translate(0, -unreadbarh); clip.translate(0, -unreadbarh);
@ -405,7 +405,7 @@ void Service::draw(
auto dt = (animms > st::activeFadeInDuration) ? (1. - (animms - st::activeFadeInDuration) / float64(st::activeFadeOutDuration)) : (animms / float64(st::activeFadeInDuration)); auto dt = (animms > st::activeFadeInDuration) ? (1. - (animms - st::activeFadeInDuration) / float64(st::activeFadeOutDuration)) : (animms / float64(st::activeFadeInDuration));
auto o = p.opacity(); auto o = p.opacity();
p.setOpacity(o * dt); p.setOpacity(o * dt);
p.fillRect(0, skiptop, item->history()->width, fillheight, st::defaultTextPalette.selectOverlay); p.fillRect(0, skiptop, width(), fillheight, st::defaultTextPalette.selectOverlay);
p.setOpacity(o); p.setOpacity(o);
} }
} }
@ -448,8 +448,8 @@ bool Service::hasPoint(QPoint point) const {
if (auto dateh = item->displayedDateHeight()) { if (auto dateh = item->displayedDateHeight()) {
g.setTop(g.top() + dateh); g.setTop(g.top() + dateh);
} }
if (auto unreadbar = item->Get<HistoryMessageUnreadBar>()) { if (const auto bar = Get<UnreadBar>()) {
g.setTop(g.top() + unreadbar->height()); g.setTop(g.top() + bar->height());
} }
if (media) { if (media) {
g.setHeight(g.height() - (st::msgServiceMargin.top() + media->height())); g.setHeight(g.height() - (st::msgServiceMargin.top() + media->height()));
@ -472,8 +472,8 @@ HistoryTextState Service::getState(QPoint point, HistoryStateRequest request) co
point.setY(point.y() - dateh); point.setY(point.y() - dateh);
g.setHeight(g.height() - dateh); g.setHeight(g.height() - dateh);
} }
if (auto unreadbar = item->Get<HistoryMessageUnreadBar>()) { if (const auto bar = Get<UnreadBar>()) {
auto unreadbarh = unreadbar->height(); auto unreadbarh = bar->height();
point.setY(point.y() - unreadbarh); point.setY(point.y() - unreadbarh);
g.setHeight(g.height() - unreadbarh); g.setHeight(g.height() - unreadbarh);
} }

View File

@ -1516,7 +1516,7 @@ void MainWidget::saveRecentHashtags(const QString &text) {
} }
} }
void MainWidget::unreadCountChanged(History *history) { void MainWidget::unreadCountChanged(not_null<History*> history) {
_history->unreadCountChanged(history); _history->unreadCountChanged(history);
} }

View File

@ -242,7 +242,7 @@ public:
void sendMessage(const MessageToSend &message); void sendMessage(const MessageToSend &message);
void saveRecentHashtags(const QString &text); void saveRecentHashtags(const QString &text);
void unreadCountChanged(History *history); void unreadCountChanged(not_null<History*> history);
TimeMs highlightStartTime(not_null<const HistoryItem*> item) const; TimeMs highlightStartTime(not_null<const HistoryItem*> item) const;