Improve working with unread bar.

This commit is contained in:
John Preston 2020-02-20 19:25:31 +04:00
parent ee3e9af63a
commit 49c4d35afa
3 changed files with 89 additions and 116 deletions

View File

@ -1590,22 +1590,22 @@ void History::addToSharedMedia(
}
void History::calculateFirstUnreadMessage() {
if (_firstUnreadView || !_inboxReadBefore) {
if (!_inboxReadBefore) {
return;
}
for (auto i = blocks.cend(); i != blocks.cbegin();) {
--i;
const auto &messages = (*i)->messages;
for (auto j = messages.cend(); j != messages.cbegin();) {
--j;
const auto view = j->get();
const auto item = view->data();
_firstUnreadView = nullptr;
if (!unreadCount()) {
return;
}
for (const auto &block : ranges::view::reverse(blocks)) {
for (const auto &message : ranges::view::reverse(block->messages)) {
const auto item = message->data();
if (!IsServerMsgId(item->id)) {
continue;
} else if (!item->out() || !_firstUnreadView) {
} else if (!item->out()) {
if (item->id >= *_inboxReadBefore) {
_firstUnreadView = view;
_firstUnreadView = message.get();
} else {
return;
}
@ -1798,10 +1798,8 @@ void History::setUnreadCount(int newUnreadCount) {
if (const auto last = msgIdForRead()) {
setInboxReadTill(last);
}
} else {
if (!_firstUnreadView && !_unreadBarView && loadedAtBottom()) {
calculateFirstUnreadMessage();
}
} else if (!_firstUnreadView && !_unreadBarView && loadedAtBottom()) {
calculateFirstUnreadMessage();
}
Notify::peerUpdatedDelayed(
peer,

View File

@ -1551,10 +1551,7 @@ void HistoryWidget::fastShowAtEnd(not_null<History*> history) {
}
clearAllLoadRequests();
setMsgId(ShowAtUnreadMsgId);
_historyInited = false;
if (_history->isReadyFor(_showAtMsgId)) {
historyLoaded();
} else {
@ -1637,7 +1634,7 @@ void HistoryWidget::showHistory(
if (_peer->id == peerId && !reload) {
updateForwarding();
bool canShowNow = _history->isReadyFor(showAtMsgId);
const auto canShowNow = _history->isReadyFor(showAtMsgId);
if (!canShowNow) {
delayedShowAt(showAtMsgId);
} else {
@ -1659,10 +1656,8 @@ void HistoryWidget::showHistory(
setMsgId(showAtMsgId);
if (_historyInited) {
countHistoryShowFrom();
destroyUnreadBar();
auto item = getItemFromHistoryOrMigrated(_showAtMsgId);
const auto item = getItemFromHistoryOrMigrated(
_showAtMsgId);
animatedScrollToY(countInitialScrollTop(), item);
} else {
historyLoaded();
@ -1712,7 +1707,7 @@ void HistoryWidget::showHistory(
_history->showAtMsgId = _showAtMsgId;
destroyUnreadBar();
destroyUnreadBarOnClose();
destroyPinnedBar();
_membersDropdown.destroy();
_scrollToAnimation.stop();
@ -1822,7 +1817,9 @@ void HistoryWidget::showHistory(
_updateHistoryItems.stop();
pinnedMsgVisibilityUpdated();
if (_history->scrollTopItem || (_migrated && _migrated->scrollTopItem) || _history->isReadyFor(_showAtMsgId)) {
if (_history->scrollTopItem
|| (_migrated && _migrated->scrollTopItem)
|| _history->isReadyFor(_showAtMsgId)) {
historyLoaded();
} else {
firstLoadMessages();
@ -2236,8 +2233,22 @@ void HistoryWidget::destroyUnreadBar() {
if (_migrated) _migrated->destroyUnreadBar();
}
void HistoryWidget::destroyUnreadBarOnClose() {
if (!_history || !_historyInited) {
return;
} else if (_scroll->scrollTop() == _scroll->scrollTopMax()) {
destroyUnreadBar();
return;
}
const auto top = unreadBarTop();
if (top && *top < _scroll->scrollTop()) {
destroyUnreadBar();
return;
}
}
void HistoryWidget::unreadMessageAdded(not_null<HistoryItem*> item) {
if (_history != item->history()) {
if (_history != item->history() || !_historyInited) {
return;
}
@ -2442,15 +2453,12 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
}
setMsgId(_delayedShowAtMsgId);
_historyInited = false;
historyLoaded();
}
}
void HistoryWidget::historyLoaded() {
countHistoryShowFrom();
destroyUnreadBar();
_historyInited = false;
doneShow();
}
@ -2478,7 +2486,9 @@ void HistoryWidget::checkHistoryActivation() {
}
void HistoryWidget::firstLoadMessages() {
if (!_history || _firstLoadRequest) return;
if (!_history || _firstLoadRequest) {
return;
}
auto from = _peer;
auto offsetId = 0;
@ -2535,13 +2545,18 @@ void HistoryWidget::firstLoadMessages() {
}
void HistoryWidget::loadMessages() {
if (!_history || _preloadRequest) return;
if (!_history || _preloadRequest) {
return;
}
if (_history->isEmpty() && _migrated && _migrated->isEmpty()) {
return firstLoadMessages();
}
auto loadMigrated = _migrated && (_history->isEmpty() || _history->loadedAtTop() || (!_migrated->isEmpty() && !_migrated->loadedAtBottom()));
auto loadMigrated = _migrated
&& (_history->isEmpty()
|| _history->loadedAtTop()
|| (!_migrated->isEmpty() && !_migrated->loadedAtBottom()));
auto from = loadMigrated ? _migrated : _history;
if (from->loadedAtTop()) {
return;
@ -2572,7 +2587,9 @@ void HistoryWidget::loadMessages() {
}
void HistoryWidget::loadMessagesDown() {
if (!_history || _preloadDownRequest) return;
if (!_history || _preloadDownRequest) {
return;
}
if (_history->isEmpty() && _migrated && _migrated->isEmpty()) {
return firstLoadMessages();
@ -4949,9 +4966,11 @@ int HistoryWidget::countInitialScrollTop() {
auto result = ScrollMax;
if (_history->scrollTopItem || (_migrated && _migrated->scrollTopItem)) {
result = _list->historyScrollTop();
} else if (_showAtMsgId && (_showAtMsgId > 0 || -_showAtMsgId < ServerMaxMsgId)) {
auto item = getItemFromHistoryOrMigrated(_showAtMsgId);
auto itemTop = _list->itemTop(item);
} else if (_showAtMsgId
&& (IsServerMsgId(_showAtMsgId)
|| IsServerMsgId(-_showAtMsgId))) {
const auto item = getItemFromHistoryOrMigrated(_showAtMsgId);
const auto itemTop = _list->itemTop(item);
if (itemTop < 0) {
setMsgId(0);
return countInitialScrollTop();
@ -4971,8 +4990,14 @@ int HistoryWidget::countInitialScrollTop() {
}
int HistoryWidget::countAutomaticScrollTop() {
Expects(_history != nullptr);
Expects(_list != nullptr);
auto result = ScrollMax;
if (const auto unread = firstUnreadMessage()) {
if (!_historyInited) {
_history->calculateFirstUnreadMessage();
}
if (const auto unread = _history->firstUnreadMessage()) {
result = _list->itemTop(unread);
const auto possibleUnreadBarTop = _scroll->scrollTopMax()
+ HistoryView::UnreadBar::height()
@ -5037,10 +5062,10 @@ void HistoryWidget::updateHistoryGeometry(
if (newScrollHeight <= 0) {
return;
}
auto wasScrollTop = _scroll->scrollTop();
auto wasScrollTopMax = _scroll->scrollTopMax();
auto wasAtBottom = wasScrollTop + 1 > wasScrollTopMax;
auto needResize = (_scroll->width() != width()) || (_scroll->height() != newScrollHeight);
const auto wasScrollTop = _scroll->scrollTop();
const auto wasAtBottom = (wasScrollTop == _scroll->scrollTopMax());
const auto needResize = (_scroll->width() != width())
|| (_scroll->height() != newScrollHeight);
if (needResize) {
_scroll->resize(width(), newScrollHeight);
// on initial updateListSize we didn't put the _scroll->scrollTop correctly yet
@ -5069,52 +5094,30 @@ void HistoryWidget::updateHistoryGeometry(
updateListSize();
_updateHistoryGeometryRequired = false;
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());
if (change.type == ScrollChangeAdd) {
toY += change.value;
} else if (change.type == ScrollChangeNoJumpToBottom) {
toY = wasScrollTop;
} else if (_addToScroll) {
toY += _addToScroll;
_addToScroll = 0;
}
toY = snap(toY, 0, _scroll->scrollTopMax());
if (_scroll->scrollTop() == toY) {
visibleAreaUpdated();
} else {
synteticScrollToY(toY);
}
return;
}
auto newScrollTop = 0;
if (initial) {
newScrollTop = countInitialScrollTop();
_historyInited = true;
_scrollToAnimation.stop();
} else if (wasAtBottom && !loadedDown) {
newScrollTop = countAutomaticScrollTop();
} else {
newScrollTop = std::min(
_list->historyScrollTop(),
_scroll->scrollTopMax());
if (change.type == ScrollChangeAdd) {
newScrollTop += change.value;
} else if (change.type == ScrollChangeNoJumpToBottom) {
newScrollTop = wasScrollTop;
} else if (const auto add = base::take(_addToScroll)) {
newScrollTop += add;
}
}
const auto newScrollTop = initial
? countInitialScrollTop()
: countAutomaticScrollTop();
if (_scroll->scrollTop() == newScrollTop) {
const auto toY = std::clamp(newScrollTop, 0, _scroll->scrollTopMax());
if (_scroll->scrollTop() == toY) {
visibleAreaUpdated();
} else {
synteticScrollToY(newScrollTop);
synteticScrollToY(toY);
}
}
@ -5137,15 +5140,13 @@ bool HistoryWidget::hasPendingResizedItems() const {
}
std::optional<int> HistoryWidget::unreadBarTop() const {
auto getUnreadBar = [this]() -> HistoryView::Element* {
const auto bar = [&]() -> HistoryView::Element* {
if (const auto bar = _migrated ? _migrated->unreadBar() : nullptr) {
return bar;
} else if (const auto bar = _history->unreadBar()) {
return bar;
}
return nullptr;
};
if (const auto bar = getUnreadBar()) {
return _history->unreadBar();
}();
if (bar) {
const auto result = _list->itemTop(bar)
+ HistoryView::UnreadBar::marginTop();
if (bar->Has<HistoryView::DateBadge>()) {
@ -5156,15 +5157,6 @@ std::optional<int> HistoryWidget::unreadBarTop() const {
return std::nullopt;
}
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) {
_list->messagesReceived(peer, messages);
if (!_firstLoadRequest) {
@ -5180,21 +5172,6 @@ void HistoryWidget::addMessagesToBack(PeerData *peer, const QVector<MTPMessage>
}
}
void HistoryWidget::countHistoryShowFrom() {
if (_migrated
&& _showAtMsgId == ShowAtUnreadMsgId
&& _migrated->unreadCount()) {
_migrated->calculateFirstUnreadMessage();
}
if ((_migrated && _migrated->firstUnreadMessage())
|| (_showAtMsgId != ShowAtUnreadMsgId)
|| !_history->unreadCount()) {
_history->unsetFirstUnreadMessage();
} else {
_history->calculateFirstUnreadMessage();
}
}
void HistoryWidget::updateBotKeyboard(History *h, bool force) {
if (h && h != _history && h != _migrated) {
return;
@ -5311,7 +5288,7 @@ void HistoryWidget::updateHistoryDownPosition() {
void HistoryWidget::updateHistoryDownVisibility() {
if (_a_show.animating()) return;
auto haveUnreadBelowBottom = [&](History *history) {
const auto haveUnreadBelowBottom = [&](History *history) {
if (!_list || !history || history->unreadCount() <= 0) {
return false;
}
@ -5322,7 +5299,7 @@ void HistoryWidget::updateHistoryDownVisibility() {
const auto top = _list->itemTop(unread);
return (top >= _scroll->scrollTop() + _scroll->height());
};
auto historyDownIsVisible = [&] {
const auto historyDownIsVisible = [&] {
if (!_list || _firstLoadRequest) {
return false;
}

View File

@ -557,6 +557,7 @@ private:
// destroys _history and _migrated unread bars
void destroyUnreadBar();
void destroyUnreadBarOnClose();
void saveEditMsg();
void saveEditMsgDone(History *history, const MTPUpdates &updates, mtpRequestId req);
@ -583,15 +584,12 @@ private:
std::optional<int> unreadBarTop() const;
int itemTopForHighlight(not_null<HistoryView::Element*> view) const;
void scrollToCurrentVoiceMessage(FullMsgId fromId, FullMsgId toId);
HistoryView::Element *firstUnreadMessage() const;
// Scroll to current y without updating the _lastUserScrolled time.
// Used to distinguish between user scrolls and syntetic scrolls.
// This one is syntetic.
void synteticScrollToY(int y);
void countHistoryShowFrom();
void writeDrafts(Data::Draft **localDraft, Data::Draft **editDraft);
void writeDrafts(History *history);
void setFieldText(