Improve history items management.

Encapsulate HistoryBlock::y and HistoryBlock::height.
This commit is contained in:
John Preston 2017-05-12 16:53:08 +03:00
parent 3f2bed8a92
commit d581e00299
7 changed files with 199 additions and 170 deletions

View File

@ -312,9 +312,6 @@ enum {
DialogsFirstLoad = 20, // first dialogs part size requested DialogsFirstLoad = 20, // first dialogs part size requested
DialogsPerPage = 500, // next dialogs part size DialogsPerPage = 500, // next dialogs part size
MessagesFirstLoad = 30, // first history part size requested
MessagesPerPage = 50, // next history part size
FileLoaderQueueStopTimeout = 5000, FileLoaderQueueStopTimeout = 5000,
UseBigFilesFrom = 10 * 1024 * 1024, // mtp big files methods used for files greater than 10mb UseBigFilesFrom = 10 * 1024 * 1024, // mtp big files methods used for files greater than 10mb

View File

@ -36,19 +36,20 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
namespace { namespace {
constexpr int kStatusShowClientsideTyping = 6000; constexpr auto kStatusShowClientsideTyping = 6000;
constexpr int kStatusShowClientsideRecordVideo = 6000; constexpr auto kStatusShowClientsideRecordVideo = 6000;
constexpr int kStatusShowClientsideUploadVideo = 6000; constexpr auto kStatusShowClientsideUploadVideo = 6000;
constexpr int kStatusShowClientsideRecordVoice = 6000; constexpr auto kStatusShowClientsideRecordVoice = 6000;
constexpr int kStatusShowClientsideUploadVoice = 6000; constexpr auto kStatusShowClientsideUploadVoice = 6000;
constexpr int kStatusShowClientsideRecordRound = 6000; constexpr auto kStatusShowClientsideRecordRound = 6000;
constexpr int kStatusShowClientsideUploadRound = 6000; constexpr auto kStatusShowClientsideUploadRound = 6000;
constexpr int kStatusShowClientsideUploadPhoto = 6000; constexpr auto kStatusShowClientsideUploadPhoto = 6000;
constexpr int kStatusShowClientsideUploadFile = 6000; constexpr auto kStatusShowClientsideUploadFile = 6000;
constexpr int kStatusShowClientsideChooseLocation = 6000; constexpr auto kStatusShowClientsideChooseLocation = 6000;
constexpr int kStatusShowClientsideChooseContact = 6000; constexpr auto kStatusShowClientsideChooseContact = 6000;
constexpr int kStatusShowClientsidePlayGame = 10000; constexpr auto kStatusShowClientsidePlayGame = 10000;
constexpr int kSetMyActionForMs = 10000; constexpr auto kSetMyActionForMs = 10000;
constexpr auto kNewBlockEachMessage = 50;
auto GlobalPinnedIndex = 0; auto GlobalPinnedIndex = 0;
@ -357,11 +358,12 @@ bool History::updateSendActionNeedsAnimating(TimeMs ms, bool force) {
} }
void ChannelHistory::getRangeDifference() { void ChannelHistory::getRangeDifference() {
auto fromId = MsgId(0), toId = MsgId(0); auto fromId = MsgId(0);
auto toId = MsgId(0);
for (auto blockIndex = 0, blocksCount = blocks.size(); blockIndex < blocksCount; ++blockIndex) { for (auto blockIndex = 0, blocksCount = blocks.size(); blockIndex < blocksCount; ++blockIndex) {
auto block = blocks.at(blockIndex); auto block = blocks[blockIndex];
for (auto itemIndex = 0, itemsCount = block->items.size(); itemIndex < itemsCount; ++itemIndex) { for (auto itemIndex = 0, itemsCount = block->items.size(); itemIndex < itemsCount; ++itemIndex) {
auto item = block->items.at(itemIndex); auto item = block->items[itemIndex];
if (item->id > 0) { if (item->id > 0) {
fromId = item->id; fromId = item->id;
break; break;
@ -372,9 +374,9 @@ void ChannelHistory::getRangeDifference() {
if (!fromId) return; if (!fromId) return;
for (auto blockIndex = blocks.size(); blockIndex > 0;) { for (auto blockIndex = blocks.size(); blockIndex > 0;) {
auto block = blocks.at(--blockIndex); auto block = blocks[--blockIndex];
for (auto itemIndex = block->items.size(); itemIndex > 0;) { for (auto itemIndex = block->items.size(); itemIndex > 0;) {
auto item = block->items.at(--itemIndex); auto item = block->items[--itemIndex];
if (item->id > 0) { if (item->id > 0) {
toId = item->id; toId = item->id;
break; break;
@ -428,9 +430,9 @@ HistoryJoined *ChannelHistory::insertJoinedMessage(bool unread) {
} }
for (auto blockIndex = blocks.size(); blockIndex > 0;) { for (auto blockIndex = blocks.size(); blockIndex > 0;) {
auto block = blocks.at(--blockIndex); auto block = blocks[--blockIndex];
for (auto itemIndex = block->items.size(); itemIndex > 0;) { for (auto itemIndex = block->items.size(); itemIndex > 0;) {
auto item = block->items.at(--itemIndex); auto item = block->items[--itemIndex];
// Due to a server bug sometimes inviteDate is less (before) than the // Due to a server bug sometimes inviteDate is less (before) than the
// first message in the megagroup (message about migration), let us // first message in the megagroup (message about migration), let us
@ -498,10 +500,10 @@ void ChannelHistory::checkJoinedMessage(bool createUnread) {
void ChannelHistory::checkMaxReadMessageDate() { void ChannelHistory::checkMaxReadMessageDate() {
if (_maxReadMessageDate.isValid()) return; if (_maxReadMessageDate.isValid()) return;
for (int blockIndex = blocks.size(); blockIndex > 0;) { for (auto blockIndex = blocks.size(); blockIndex > 0;) {
HistoryBlock *block = blocks.at(--blockIndex); auto block = blocks[--blockIndex];
for (int itemIndex = block->items.size(); itemIndex > 0;) { for (auto itemIndex = block->items.size(); itemIndex > 0;) {
HistoryItem *item = block->items.at(--itemIndex); auto item = block->items[--itemIndex];
if (!item->unread()) { if (!item->unread()) {
_maxReadMessageDate = item->date; _maxReadMessageDate = item->date;
if (item->isGroupMigrate() && isMegagroup() && peer->migrateFrom()) { if (item->isGroupMigrate() && isMegagroup() && peer->migrateFrom()) {
@ -1105,7 +1107,7 @@ void History::eraseFromOverview(MediaOverviewType type, MsgId msgId) {
} }
HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) { HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) {
t_assert(!isBuildingFrontBlock()); Expects(!isBuildingFrontBlock());
addItemToBlock(adding); addItemToBlock(adding);
setLastMessage(adding); setLastMessage(adding);
@ -1237,12 +1239,12 @@ HistoryBlock *History::prepareBlockForAddingItem() {
result->setIndexInHistory(0); result->setIndexInHistory(0);
blocks.push_front(result); blocks.push_front(result);
for (int i = 1, l = blocks.size(); i < l; ++i) { for (int i = 1, l = blocks.size(); i < l; ++i) {
blocks.at(i)->setIndexInHistory(i); blocks[i]->setIndexInHistory(i);
} }
return result; return result;
} }
bool addNewBlock = blocks.isEmpty() || (blocks.back()->items.size() >= MessagesPerPage); auto addNewBlock = blocks.isEmpty() || (blocks.back()->items.size() >= kNewBlockEachMessage);
if (!addNewBlock) { if (!addNewBlock) {
return blocks.back(); return blocks.back();
} }
@ -1251,13 +1253,13 @@ HistoryBlock *History::prepareBlockForAddingItem() {
result->setIndexInHistory(blocks.size()); result->setIndexInHistory(blocks.size());
blocks.push_back(result); blocks.push_back(result);
result->items.reserve(MessagesPerPage); result->items.reserve(kNewBlockEachMessage);
return result; return result;
}; };
void History::addItemToBlock(HistoryItem *item) { void History::addItemToBlock(HistoryItem *item) {
t_assert(item != nullptr); Expects(item != nullptr);
t_assert(item->detached()); Expects(item->detached());
auto block = prepareBlockForAddingItem(); auto block = prepareBlockForAddingItem();
@ -1311,7 +1313,7 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice) {
// lastParticipants are displayed in Profile as members list. // lastParticipants are displayed in Profile as members list.
markupSenders = &peer->asChannel()->mgInfo->markupSenders; markupSenders = &peer->asChannel()->mgInfo->markupSenders;
} }
for (int32 i = block->items.size(); i > 0; --i) { for (auto i = block->items.size(); i > 0; --i) {
auto item = block->items[i - 1]; auto item = block->items[i - 1];
mask |= item->addToOverview(AddToOverviewFront); mask |= item->addToOverview(AddToOverviewFront);
if (item->from()->id) { if (item->from()->id) {
@ -1593,14 +1595,14 @@ void History::getNextShowFrom(HistoryBlock *block, int i) {
auto l = block->items.size(); auto l = block->items.size();
for (++i; i < l; ++i) { for (++i; i < l; ++i) {
if (block->items[i]->id > 0) { if (block->items[i]->id > 0) {
showFrom = block->items.at(i); showFrom = block->items[i];
return; return;
} }
} }
} }
for (auto j = block->indexInHistory() + 1, s = blocks.size(); j < s; ++j) { for (auto j = block->indexInHistory() + 1, s = blocks.size(); j < s; ++j) {
block = blocks.at(j); block = blocks[j];
for_const (auto item, block->items) { for_const (auto item, block->items) {
if (item->id > 0) { if (item->id > 0) {
showFrom = item; showFrom = item;
@ -1614,7 +1616,7 @@ void History::getNextShowFrom(HistoryBlock *block, int i) {
void History::countScrollState(int top) { void History::countScrollState(int top) {
countScrollTopItem(top); countScrollTopItem(top);
if (scrollTopItem) { if (scrollTopItem) {
scrollTopOffset = (top - scrollTopItem->block()->y - scrollTopItem->y); scrollTopOffset = (top - scrollTopItem->block()->y() - scrollTopItem->y());
} }
} }
@ -1628,22 +1630,22 @@ void History::countScrollTopItem(int top) {
if (scrollTopItem && !scrollTopItem->detached()) { if (scrollTopItem && !scrollTopItem->detached()) {
itemIndex = scrollTopItem->indexInBlock(); itemIndex = scrollTopItem->indexInBlock();
blockIndex = scrollTopItem->block()->indexInHistory(); blockIndex = scrollTopItem->block()->indexInHistory();
itemTop = blocks.at(blockIndex)->y + scrollTopItem->y; itemTop = blocks[blockIndex]->y() + scrollTopItem->y();
} }
if (itemTop > top) { if (itemTop > top) {
// go backward through history while we don't find an item that starts above // go backward through history while we don't find an item that starts above
do { do {
HistoryBlock *block = blocks.at(blockIndex); auto block = blocks[blockIndex];
for (--itemIndex; itemIndex >= 0; --itemIndex) { for (--itemIndex; itemIndex >= 0; --itemIndex) {
HistoryItem *item = block->items.at(itemIndex); auto item = block->items[itemIndex];
itemTop = block->y + item->y; itemTop = block->y() + item->y();
if (itemTop <= top) { if (itemTop <= top) {
scrollTopItem = item; scrollTopItem = item;
return; return;
} }
} }
if (--blockIndex >= 0) { if (--blockIndex >= 0) {
itemIndex = blocks.at(blockIndex)->items.size(); itemIndex = blocks[blockIndex]->items.size();
} else { } else {
break; break;
} }
@ -1653,16 +1655,16 @@ void History::countScrollTopItem(int top) {
} else { } else {
// go forward through history while we don't find the last item that starts above // go forward through history while we don't find the last item that starts above
for (int blocksCount = blocks.size(); blockIndex < blocksCount; ++blockIndex) { for (int blocksCount = blocks.size(); blockIndex < blocksCount; ++blockIndex) {
HistoryBlock *block = blocks.at(blockIndex); auto block = blocks[blockIndex];
for (int itemsCount = block->items.size(); itemIndex < itemsCount; ++itemIndex) { for (int itemsCount = block->items.size(); itemIndex < itemsCount; ++itemIndex) {
HistoryItem *item = block->items.at(itemIndex); auto item = block->items[itemIndex];
itemTop = block->y + item->y; itemTop = block->y() + item->y();
if (itemTop > top) { if (itemTop > top) {
t_assert(itemIndex > 0 || blockIndex > 0); t_assert(itemIndex > 0 || blockIndex > 0);
if (itemIndex > 0) { if (itemIndex > 0) {
scrollTopItem = block->items.at(itemIndex - 1); scrollTopItem = block->items[itemIndex - 1];
} else { } else {
scrollTopItem = blocks.at(blockIndex - 1)->items.back(); scrollTopItem = blocks[blockIndex - 1]->items.back();
} }
return; return;
} }
@ -1676,12 +1678,12 @@ void History::countScrollTopItem(int top) {
void History::getNextScrollTopItem(HistoryBlock *block, int32 i) { void History::getNextScrollTopItem(HistoryBlock *block, int32 i) {
++i; ++i;
if (i > 0 && i < block->items.size()) { if (i > 0 && i < block->items.size()) {
scrollTopItem = block->items.at(i); scrollTopItem = block->items[i];
return; return;
} }
int j = block->indexInHistory() + 1; int j = block->indexInHistory() + 1;
if (j > 0 && j < blocks.size()) { if (j > 0 && j < blocks.size()) {
scrollTopItem = blocks.at(j)->items.front(); scrollTopItem = blocks[j]->items.front();
return; return;
} }
scrollTopItem = nullptr; scrollTopItem = nullptr;
@ -1707,12 +1709,12 @@ void History::destroyUnreadBar() {
} }
HistoryItem *History::addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex, int32 itemIndex) { HistoryItem *History::addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex, int32 itemIndex) {
t_assert(blockIndex >= 0); Expects(blockIndex >= 0);
t_assert(blockIndex < blocks.size()); Expects(blockIndex < blocks.size());
t_assert(itemIndex >= 0); Expects(itemIndex >= 0);
t_assert(itemIndex <= blocks[blockIndex]->items.size()); Expects(itemIndex <= blocks[blockIndex]->items.size());
auto block = blocks.at(blockIndex); auto block = blocks[blockIndex];
newItem->attachToBlock(block, itemIndex); newItem->attachToBlock(block, itemIndex);
block->items.insert(itemIndex, newItem); block->items.insert(itemIndex, newItem);
@ -1747,7 +1749,7 @@ HistoryBlock *History::finishBuildingFrontBlock() {
if (block) { if (block) {
if (blocks.size() > 1) { if (blocks.size() > 1) {
auto last = block->items.back(); // ... item, item, item, last ], [ first, item, item ... auto last = block->items.back(); // ... item, item, item, last ], [ first, item, item ...
auto first = blocks.at(1)->items.front(); auto first = blocks[1]->items.front();
// we've added a new front block, so previous item for // we've added a new front block, so previous item for
// the old first item of a first block was changed // the old first item of a first block was changed
@ -1942,8 +1944,8 @@ int History::resizeGetHeight(int newWidth) {
width = newWidth; width = newWidth;
int y = 0; int y = 0;
for_const (HistoryBlock *block, blocks) { for_const (auto block, blocks) {
block->y = y; block->setY(y);
y += block->resizeGetHeight(newWidth, resizeAllItems); y += block->resizeGetHeight(newWidth, resizeAllItems);
} }
height = y; height = y;
@ -2179,11 +2181,11 @@ void History::overviewSliceDone(int32 overviewIndex, const MTPmessages_Messages
} }
void History::changeMsgId(MsgId oldId, MsgId newId) { void History::changeMsgId(MsgId oldId, MsgId newId) {
for (int32 i = 0; i < OverviewCount; ++i) { for (auto i = 0; i < OverviewCount; ++i) {
auto j = overviewIds[i].find(oldId); auto j = overviewIds[i].find(oldId);
if (j != overviewIds[i].cend()) { if (j != overviewIds[i].cend()) {
overviewIds[i].erase(j); overviewIds[i].erase(j);
int32 index = overview[i].indexOf(oldId); auto index = overview[i].indexOf(oldId);
if (overviewIds[i].constFind(newId) == overviewIds[i].cend()) { if (overviewIds[i].constFind(newId) == overviewIds[i].cend()) {
overviewIds[i].insert(newId); overviewIds[i].insert(newId);
if (index >= 0) { if (index >= 0) {
@ -2199,7 +2201,7 @@ void History::changeMsgId(MsgId oldId, MsgId newId) {
} }
void History::removeBlock(HistoryBlock *block) { void History::removeBlock(HistoryBlock *block) {
t_assert(block->items.isEmpty()); Expects(block->items.isEmpty());
if (_buildingFrontBlock && block == _buildingFrontBlock->block) { if (_buildingFrontBlock && block == _buildingFrontBlock->block) {
_buildingFrontBlock->block = nullptr; _buildingFrontBlock->block = nullptr;
@ -2209,9 +2211,9 @@ void History::removeBlock(HistoryBlock *block) {
blocks.removeAt(index); blocks.removeAt(index);
if (index < blocks.size()) { if (index < blocks.size()) {
for (int i = index, l = blocks.size(); i < l; ++i) { for (int i = index, l = blocks.size(); i < l; ++i) {
blocks.at(i)->setIndexInHistory(i); blocks[i]->setIndexInHistory(i);
} }
blocks.at(index)->items.front()->previousItemChanged(); blocks[index]->items.front()->previousItemChanged();
} else if (!blocks.empty() && !blocks.back()->items.empty()) { } else if (!blocks.empty() && !blocks.back()->items.empty()) {
blocks.back()->items.back()->nextItemChanged(); blocks.back()->items.back()->nextItemChanged();
} }
@ -2222,65 +2224,64 @@ History::~History() {
} }
int HistoryBlock::resizeGetHeight(int newWidth, bool resizeAllItems) { int HistoryBlock::resizeGetHeight(int newWidth, bool resizeAllItems) {
int y = 0; auto y = 0;
for_const (HistoryItem *item, items) { for_const (auto item, items) {
item->y = y; item->setY(y);
if (resizeAllItems || item->pendingResize()) { if (resizeAllItems || item->pendingResize()) {
y += item->resizeGetHeight(newWidth); y += item->resizeGetHeight(newWidth);
} else { } else {
y += item->height(); y += item->height();
} }
} }
height = y; _height = y;
return height; return _height;
} }
void HistoryBlock::clear(bool leaveItems) { void HistoryBlock::clear(bool leaveItems) {
Items lst; auto itemsList = base::take(items);
std::swap(lst, items);
if (leaveItems) { if (leaveItems) {
for_const (HistoryItem *item, lst) { for_const (auto item, itemsList) {
item->detachFast(); item->detachFast();
} }
} else { } else {
for_const (HistoryItem *item, lst) { for_const (auto item, itemsList) {
delete item; delete item;
} }
} }
} }
void HistoryBlock::removeItem(HistoryItem *item) { void HistoryBlock::removeItem(HistoryItem *item) {
t_assert(item->block() == this); Expects(item->block() == this);
int blockIndex = indexInHistory(); auto blockIndex = indexInHistory();
int itemIndex = item->indexInBlock(); auto itemIndex = item->indexInBlock();
if (history->showFrom == item) { if (_history->showFrom == item) {
history->getNextShowFrom(this, itemIndex); _history->getNextShowFrom(this, itemIndex);
} }
if (history->lastSentMsg == item) { if (_history->lastSentMsg == item) {
history->lastSentMsg = nullptr; _history->lastSentMsg = nullptr;
} }
if (history->unreadBar == item) { if (_history->unreadBar == item) {
history->unreadBar = nullptr; _history->unreadBar = nullptr;
} }
if (history->scrollTopItem == item) { if (_history->scrollTopItem == item) {
history->getNextScrollTopItem(this, itemIndex); _history->getNextScrollTopItem(this, itemIndex);
} }
item->detachFast(); item->detachFast();
items.remove(itemIndex); items.remove(itemIndex);
for (int i = itemIndex, l = items.size(); i < l; ++i) { for (auto i = itemIndex, l = items.size(); i < l; ++i) {
items.at(i)->setIndexInBlock(i); items[i]->setIndexInBlock(i);
} }
if (items.isEmpty()) { if (items.isEmpty()) {
history->removeBlock(this); _history->removeBlock(this);
} else if (itemIndex < items.size()) { } else if (itemIndex < items.size()) {
items.at(itemIndex)->previousItemChanged(); items[itemIndex]->previousItemChanged();
} else if (blockIndex + 1 < history->blocks.size()) { } else if (blockIndex + 1 < _history->blocks.size()) {
history->blocks.at(blockIndex + 1)->items.front()->previousItemChanged(); _history->blocks[blockIndex + 1]->items.front()->previousItemChanged();
} else if (!history->blocks.empty() && !history->blocks.back()->items.empty()) { } else if (!_history->blocks.empty() && !_history->blocks.back()->items.empty()) {
history->blocks.back()->items.back()->nextItemChanged(); _history->blocks.back()->items.back()->nextItemChanged();
} }
if (items.isEmpty()) { if (items.isEmpty()) {

View File

@ -622,14 +622,13 @@ private:
class HistoryBlock { class HistoryBlock {
public: public:
HistoryBlock(History *hist) : history(hist), _indexInHistory(-1) { HistoryBlock(gsl::not_null<History*> history) : _history(history) {
} }
HistoryBlock(const HistoryBlock &) = delete; HistoryBlock(const HistoryBlock &) = delete;
HistoryBlock &operator=(const HistoryBlock &) = delete; HistoryBlock &operator=(const HistoryBlock &) = delete;
typedef QVector<HistoryItem*> Items; QVector<HistoryItem*> items;
Items items;
void clear(bool leaveItems = false); void clear(bool leaveItems = false);
~HistoryBlock() { ~HistoryBlock() {
@ -638,31 +637,45 @@ public:
void removeItem(HistoryItem *item); void removeItem(HistoryItem *item);
int resizeGetHeight(int newWidth, bool resizeAllItems); int resizeGetHeight(int newWidth, bool resizeAllItems);
int y = 0; int y() const {
int height = 0; return _y;
History *history; }
void setY(int y) {
_y = y;
}
int height() const {
return _height;
}
gsl::not_null<History*> history() const {
return _history;
}
HistoryBlock *previousBlock() const { HistoryBlock *previousBlock() const {
t_assert(_indexInHistory >= 0); Expects(_indexInHistory >= 0);
return (_indexInHistory > 0) ? history->blocks.at(_indexInHistory - 1) : nullptr; return (_indexInHistory > 0) ? _history->blocks.at(_indexInHistory - 1) : nullptr;
} }
HistoryBlock *nextBlock() const { HistoryBlock *nextBlock() const {
t_assert(_indexInHistory >= 0); Expects(_indexInHistory >= 0);
return (_indexInHistory + 1 < history->blocks.size()) ? history->blocks.at(_indexInHistory + 1) : nullptr; return (_indexInHistory + 1 < _history->blocks.size()) ? _history->blocks.at(_indexInHistory + 1) : nullptr;
} }
void setIndexInHistory(int index) { void setIndexInHistory(int index) {
_indexInHistory = index; _indexInHistory = index;
} }
int indexInHistory() const { int indexInHistory() const {
t_assert(_indexInHistory >= 0); Expects(_indexInHistory >= 0);
t_assert(history->blocks.at(_indexInHistory) == this); Expects(_indexInHistory < _history->blocks.size());
Expects(_history->blocks[_indexInHistory] == this);
return _indexInHistory; return _indexInHistory;
} }
protected: protected:
int _indexInHistory; const gsl::not_null<History*> _history;
int _y = 0;
int _height = 0;
int _indexInHistory = -1;
}; };

View File

@ -152,7 +152,7 @@ int binarySearchBlocksOrItems(const T &list, int edge) {
auto start = 0, end = static_cast<int>(list.size()); auto start = 0, end = static_cast<int>(list.size());
while (end - start > 1) { while (end - start > 1) {
auto middle = (start + end) / 2; auto middle = (start + end) / 2;
auto top = list[middle]->y; auto top = list[middle]->y();
auto chooseLeft = (TopToBottom ? (top <= edge) : (top < edge)); auto chooseLeft = (TopToBottom ? (top <= edge) : (top < edge));
if (chooseLeft) { if (chooseLeft) {
start = middle; start = middle;
@ -182,14 +182,14 @@ void HistoryInner::enumerateItemsInHistory(History *history, int historytop, Met
// binary search for itemIndex of the first item that is not completely below the visible area // binary search for itemIndex of the first item that is not completely below the visible area
auto block = history->blocks.at(blockIndex); auto block = history->blocks.at(blockIndex);
auto blocktop = historytop + block->y; auto blocktop = historytop + block->y();
auto blockbottom = blocktop + block->height; auto blockbottom = blocktop + block->height();
auto itemIndex = binarySearchBlocksOrItems<TopToBottom>(block->items, searchEdge - blocktop); auto itemIndex = binarySearchBlocksOrItems<TopToBottom>(block->items, searchEdge - blocktop);
while (true) { while (true) {
while (true) { while (true) {
auto item = block->items.at(itemIndex); auto item = block->items.at(itemIndex);
auto itemtop = blocktop + item->y; auto itemtop = blocktop + item->y();
auto itembottom = itemtop + item->height(); auto itembottom = itemtop + item->height();
// binary search should've skipped all the items that are above / below the visible area // binary search should've skipped all the items that are above / below the visible area
@ -205,7 +205,7 @@ void HistoryInner::enumerateItemsInHistory(History *history, int historytop, Met
debugValue("blockIndex", blockIndex); debugValue("blockIndex", blockIndex);
debugValue("history->blocks.size()", history->blocks.size()); debugValue("history->blocks.size()", history->blocks.size());
debugValue("blocktop", blocktop); debugValue("blocktop", blocktop);
debugValue("block->height", block->height); debugValue("block->height", block->height());
debugValue("itemIndex", itemIndex); debugValue("itemIndex", itemIndex);
debugValue("block->items.size()", block->items.size()); debugValue("block->items.size()", block->items.size());
debugValue("itemtop", itemtop); debugValue("itemtop", itemtop);
@ -214,10 +214,10 @@ void HistoryInner::enumerateItemsInHistory(History *history, int historytop, Met
debugValue("_visibleAreaTop", _visibleAreaTop); debugValue("_visibleAreaTop", _visibleAreaTop);
debugValue("_visibleAreaBottom", _visibleAreaBottom); debugValue("_visibleAreaBottom", _visibleAreaBottom);
for (int i = 0; i != qMin(history->blocks.size(), 5); ++i) { for (int i = 0; i != qMin(history->blocks.size(), 5); ++i) {
debugValue("y[" + QString::number(i) + "]", history->blocks[i]->y); debugValue("y[" + QString::number(i) + "]", history->blocks[i]->y());
debugValue("h[" + QString::number(i) + "]", history->blocks[i]->height); debugValue("h[" + QString::number(i) + "]", history->blocks[i]->height());
for (int j = 0; j != qMin(history->blocks[i]->items.size(), 5); ++j) { for (int j = 0; j != qMin(history->blocks[i]->items.size(), 5); ++j) {
debugValue("y[" + QString::number(i) + "][" + QString::number(j) + "]", history->blocks[i]->items[j]->y); debugValue("y[" + QString::number(i) + "][" + QString::number(j) + "]", history->blocks[i]->items[j]->y());
debugValue("h[" + QString::number(i) + "][" + QString::number(j) + "]", history->blocks[i]->items[j]->height()); debugValue("h[" + QString::number(i) + "][" + QString::number(j) + "]", history->blocks[i]->items[j]->height());
} }
} }
@ -225,8 +225,8 @@ void HistoryInner::enumerateItemsInHistory(History *history, int historytop, Met
auto y = 0; auto y = 0;
for (int i = 0; i != history->blocks.size(); ++i) { for (int i = 0; i != history->blocks.size(); ++i) {
auto innery = 0; auto innery = 0;
if (history->blocks[i]->y != y) { if (history->blocks[i]->y() != y) {
debugInfo.append("bad_block_y" + QString::number(i) + ":" + QString::number(history->blocks[i]->y) + "!=" + QString::number(y)); debugInfo.append("bad_block_y" + QString::number(i) + ":" + QString::number(history->blocks[i]->y()) + "!=" + QString::number(y));
return false; return false;
} }
for (int j = 0; j != history->blocks[i]->items.size(); ++j) { for (int j = 0; j != history->blocks[i]->items.size(); ++j) {
@ -235,14 +235,14 @@ void HistoryInner::enumerateItemsInHistory(History *history, int historytop, Met
} else if (history->blocks[i]->items[j]->pendingResize()) { } else if (history->blocks[i]->items[j]->pendingResize()) {
debugInfo.append("pending_resize" + QString::number(i) + "," + QString::number(j)); debugInfo.append("pending_resize" + QString::number(i) + "," + QString::number(j));
} }
if (history->blocks[i]->items[j]->y != innery) { if (history->blocks[i]->items[j]->y() != innery) {
debugInfo.append("bad_item_y" + QString::number(i) + "," + QString::number(j) + ":" + QString::number(history->blocks[i]->items[j]->y) + "!=" + QString::number(innery)); debugInfo.append("bad_item_y" + QString::number(i) + "," + QString::number(j) + ":" + QString::number(history->blocks[i]->items[j]->y()) + "!=" + QString::number(innery));
return false; return false;
} }
innery += history->blocks[i]->items[j]->height(); innery += history->blocks[i]->items[j]->height();
} }
if (history->blocks[i]->height != innery) { if (history->blocks[i]->height() != innery) {
debugInfo.append("bad_block_height" + QString::number(i) + ":" + QString::number(history->blocks[i]->height) + "!=" + QString::number(innery)); debugInfo.append("bad_block_height" + QString::number(i) + ":" + QString::number(history->blocks[i]->height()) + "!=" + QString::number(innery));
return false; return false;
} }
y += innery; y += innery;
@ -305,9 +305,9 @@ void HistoryInner::enumerateItemsInHistory(History *history, int historytop, Met
return; return;
} }
} }
block = history->blocks.at(blockIndex); block = history->blocks[blockIndex];
blocktop = historytop + block->y; blocktop = historytop + block->y();
blockbottom = blocktop + block->height; blockbottom = blocktop + block->height();
if (TopToBottom) { if (TopToBottom) {
itemIndex = 0; itemIndex = 0;
} else { } else {
@ -472,14 +472,16 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
seltoy += _dragSelTo->height(); seltoy += _dragSelTo->height();
} }
int32 mtop = migratedTop(), htop = historyTop(), hdrawtop = historyDrawTop(); auto mtop = migratedTop();
auto htop = historyTop();
auto hdrawtop = historyDrawTop();
if (mtop >= 0) { if (mtop >= 0) {
int32 iBlock = (_curHistory == _migrated ? _curBlock : (_migrated->blocks.size() - 1)); auto iBlock = (_curHistory == _migrated ? _curBlock : (_migrated->blocks.size() - 1));
HistoryBlock *block = _migrated->blocks[iBlock]; auto block = _migrated->blocks[iBlock];
int32 iItem = (_curHistory == _migrated ? _curItem : (block->items.size() - 1)); auto iItem = (_curHistory == _migrated ? _curItem : (block->items.size() - 1));
HistoryItem *item = block->items[iItem]; auto item = block->items[iItem];
int32 y = mtop + block->y + item->y; auto y = mtop + block->y() + item->y();
p.save(); p.save();
p.translate(0, y); p.translate(0, y);
if (r.y() < y + item->height()) while (y < drawToY) { if (r.y() < y + item->height()) while (y < drawToY) {
@ -518,17 +520,17 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
p.restore(); p.restore();
} }
if (htop >= 0) { if (htop >= 0) {
int32 iBlock = (_curHistory == _history ? _curBlock : 0); auto iBlock = (_curHistory == _history ? _curBlock : 0);
HistoryBlock *block = _history->blocks[iBlock]; auto block = _history->blocks[iBlock];
int32 iItem = (_curHistory == _history ? _curItem : 0); auto iItem = (_curHistory == _history ? _curItem : 0);
HistoryItem *item = block->items[iItem]; auto item = block->items[iItem];
QRect historyRect = r.intersected(QRect(0, hdrawtop, width(), r.top() + r.height())); auto historyRect = r.intersected(QRect(0, hdrawtop, width(), r.top() + r.height()));
int32 y = htop + block->y + item->y; auto y = htop + block->y() + item->y();
p.save(); p.save();
p.translate(0, y); p.translate(0, y);
while (y < drawToY) { while (y < drawToY) {
int32 h = item->height(); auto h = item->height();
if (historyRect.y() < y + h && hdrawtop < y + h) { if (historyRect.y() < y + h && hdrawtop < y + h) {
TextSelection sel; TextSelection sel;
if (y >= selfromy && y < seltoy) { if (y >= selfromy && y < seltoy) {
@ -1902,23 +1904,23 @@ void HistoryInner::adjustCurrent(int32 y, History *history) const {
_curBlock = history->blocks.size() - 1; _curBlock = history->blocks.size() - 1;
_curItem = 0; _curItem = 0;
} }
while (history->blocks.at(_curBlock)->y > y && _curBlock > 0) { while (history->blocks[_curBlock]->y() > y && _curBlock > 0) {
--_curBlock; --_curBlock;
_curItem = 0; _curItem = 0;
} }
while (history->blocks.at(_curBlock)->y + history->blocks.at(_curBlock)->height <= y && _curBlock + 1 < history->blocks.size()) { while (history->blocks[_curBlock]->y() + history->blocks[_curBlock]->height() <= y && _curBlock + 1 < history->blocks.size()) {
++_curBlock; ++_curBlock;
_curItem = 0; _curItem = 0;
} }
HistoryBlock *block = history->blocks.at(_curBlock); auto block = history->blocks[_curBlock];
if (_curItem >= block->items.size()) { if (_curItem >= block->items.size()) {
_curItem = block->items.size() - 1; _curItem = block->items.size() - 1;
} }
int by = block->y; auto by = block->y();
while (block->items.at(_curItem)->y + by > y && _curItem > 0) { while (block->items[_curItem]->y() + by > y && _curItem > 0) {
--_curItem; --_curItem;
} }
while (block->items.at(_curItem)->y + block->items.at(_curItem)->height() + by <= y && _curItem + 1 < block->items.size()) { while (block->items[_curItem]->y() + block->items[_curItem]->height() + by <= y && _curItem + 1 < block->items.size()) {
++_curItem; ++_curItem;
} }
} }
@ -2300,14 +2302,15 @@ int HistoryInner::historyHeight() const {
} }
int HistoryInner::historyScrollTop() const { int HistoryInner::historyScrollTop() const {
int htop = historyTop(), mtop = migratedTop(); auto htop = historyTop();
auto mtop = migratedTop();
if (htop >= 0 && _history->scrollTopItem) { if (htop >= 0 && _history->scrollTopItem) {
t_assert(!_history->scrollTopItem->detached()); t_assert(!_history->scrollTopItem->detached());
return htop + _history->scrollTopItem->block()->y + _history->scrollTopItem->y + _history->scrollTopOffset; return htop + _history->scrollTopItem->block()->y() + _history->scrollTopItem->y() + _history->scrollTopOffset;
} }
if (mtop >= 0 && _migrated->scrollTopItem) { if (mtop >= 0 && _migrated->scrollTopItem) {
t_assert(!_migrated->scrollTopItem->detached()); t_assert(!_migrated->scrollTopItem->detached());
return mtop + _migrated->scrollTopItem->block()->y + _migrated->scrollTopItem->y + _migrated->scrollTopOffset; return mtop + _migrated->scrollTopItem->block()->y() + _migrated->scrollTopItem->y() + _migrated->scrollTopOffset;
} }
return ScrollMax; return ScrollMax;
} }
@ -2331,7 +2334,7 @@ int HistoryInner::itemTop(const HistoryItem *item) const { // -1 if should not b
if (item->detached()) return -1; if (item->detached()) return -1;
int top = (item->history() == _history) ? historyTop() : (item->history() == _migrated ? migratedTop() : -2); int top = (item->history() == _history) ? historyTop() : (item->history() == _migrated ? migratedTop() : -2);
return (top < 0) ? top : (top + item->y + item->block()->y); return (top < 0) ? top : (top + item->y() + item->block()->y());
} }
void HistoryInner::notifyIsBotChanged() { void HistoryInner::notifyIsBotChanged() {

View File

@ -578,7 +578,6 @@ TextSelection shiftSelection(TextSelection selection, const Text &byText) {
} // namespace internal } // namespace internal
HistoryItem::HistoryItem(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime msgDate, int32 from) : HistoryElement() HistoryItem::HistoryItem(History *history, MsgId msgId, MTPDmessage::Flags flags, QDateTime msgDate, int32 from) : HistoryElement()
, y(0)
, id(msgId) , id(msgId)
, date(msgDate) , date(msgDate)
, _from(from ? App::user(from) : history->peer) , _from(from ? App::user(from) : history->peer)

View File

@ -156,8 +156,8 @@ struct HistoryMessageReply : public RuntimeComponent<HistoryMessageReply> {
} }
~HistoryMessageReply() { ~HistoryMessageReply() {
// clearData() should be called by holder // clearData() should be called by holder
t_assert(replyToMsg == nullptr); Expects(replyToMsg == nullptr);
t_assert(_replyToVia == nullptr); Expects(_replyToVia == nullptr);
} }
bool updateData(HistoryMessage *holder, bool force = false); bool updateData(HistoryMessage *holder, bool force = false);
@ -438,7 +438,7 @@ public:
return get(); return get();
} }
HistoryMedia &operator*() const { HistoryMedia &operator*() const {
t_assert(!isNull()); Expects(!isNull());
return *get(); return *get();
} }
explicit operator bool() const { explicit operator bool() const {
@ -522,10 +522,10 @@ public:
return !_block; return !_block;
} }
void attachToBlock(HistoryBlock *block, int index) { void attachToBlock(HistoryBlock *block, int index) {
t_assert(_block == nullptr); Expects(_block == nullptr);
t_assert(_indexInBlock < 0); Expects(_indexInBlock < 0);
t_assert(block != nullptr); Expects(block != nullptr);
t_assert(index >= 0); Expects(index >= 0);
_block = block; _block = block;
_indexInBlock = index; _indexInBlock = index;
@ -534,8 +534,8 @@ public:
} }
} }
void setIndexInBlock(int index) { void setIndexInBlock(int index) {
t_assert(_block != nullptr); Expects(_block != nullptr);
t_assert(index >= 0); Expects(index >= 0);
_indexInBlock = index; _indexInBlock = index;
} }
@ -575,7 +575,7 @@ public:
return (_flags & MTPDmessage::Flag::f_reply_markup); return (_flags & MTPDmessage::Flag::f_reply_markup);
} }
MTPDreplyKeyboardMarkup::Flags replyKeyboardFlags() const { MTPDreplyKeyboardMarkup::Flags replyKeyboardFlags() const {
t_assert(definesReplyKeyboard()); Expects(definesReplyKeyboard());
if (auto markup = Get<HistoryMessageReplyMarkup>()) { if (auto markup = Get<HistoryMessageReplyMarkup>()) {
return markup->flags; return markup->flags;
} }
@ -701,7 +701,12 @@ public:
} }
QString directLink() const; QString directLink() const;
int32 y; int y() const {
return _y;
}
void setY(int y) {
_y = y;
}
MsgId id; MsgId id;
QDateTime date; QDateTime date;
@ -951,6 +956,9 @@ protected:
HistoryMediaPtr _media; HistoryMediaPtr _media;
private:
int _y = 0;
}; };
// make all the constructors in HistoryItem children protected // make all the constructors in HistoryItem children protected

View File

@ -75,6 +75,9 @@ namespace {
constexpr auto kStickersUpdateTimeout = 3600000; // update not more than once in an hour constexpr auto kStickersUpdateTimeout = 3600000; // update not more than once in an hour
constexpr auto kSaveTabbedSelectorSectionTimeout = 1000; constexpr auto kSaveTabbedSelectorSectionTimeout = 1000;
constexpr auto kMessagesPerPageFirst = 30;
constexpr auto kMessagesPerPage = 50;
constexpr auto kPreloadHeightsCount = 3; // when 3 screens to scroll left make a preload request
ApiWrap::RequestMessageDataCallback replyEditMessageDataCallback() { ApiWrap::RequestMessageDataCallback replyEditMessageDataCallback() {
return [](ChannelData *channel, MsgId msgId) { return [](ChannelData *channel, MsgId msgId) {
@ -2255,7 +2258,7 @@ bool HistoryWidget::messagesFailed(const RPCError &error, mtpRequestId requestId
if (MTP::isDefaultHandledError(error)) return false; if (MTP::isDefaultHandledError(error)) return false;
if (error.type() == qstr("CHANNEL_PRIVATE") || error.type() == qstr("CHANNEL_PUBLIC_GROUP_NA") || error.type() == qstr("USER_BANNED_IN_CHANNEL")) { if (error.type() == qstr("CHANNEL_PRIVATE") || error.type() == qstr("CHANNEL_PUBLIC_GROUP_NA") || error.type() == qstr("USER_BANNED_IN_CHANNEL")) {
PeerData *was = _peer; auto was = _peer;
App::main()->showBackFromStack(); App::main()->showBackFromStack();
Ui::show(Box<InformBox>(lang((was && was->isMegagroup()) ? lng_group_not_accessible : lng_channel_not_accessible))); Ui::show(Box<InformBox>(lang((was && was->isMegagroup()) ? lng_group_not_accessible : lng_channel_not_accessible)));
return true; return true;
@ -2437,8 +2440,10 @@ bool HistoryWidget::historyHasNotFreezedUnreadBar(History *history) const {
void HistoryWidget::firstLoadMessages() { void HistoryWidget::firstLoadMessages() {
if (!_history || _firstLoadRequest) return; if (!_history || _firstLoadRequest) return;
PeerData *from = _peer; auto from = _peer;
int32 offset_id = 0, offset = 0, loadCount = MessagesPerPage; auto offset_id = 0;
auto offset = 0;
auto loadCount = kMessagesPerPage;
if (_showAtMsgId == ShowAtUnreadMsgId) { if (_showAtMsgId == ShowAtUnreadMsgId) {
if (_migrated && _migrated->unreadCount()) { if (_migrated && _migrated->unreadCount()) {
_history->getReadyFor(_showAtMsgId); _history->getReadyFor(_showAtMsgId);
@ -2454,7 +2459,7 @@ void HistoryWidget::firstLoadMessages() {
} }
} else if (_showAtMsgId == ShowAtTheEndMsgId) { } else if (_showAtMsgId == ShowAtTheEndMsgId) {
_history->getReadyFor(_showAtMsgId); _history->getReadyFor(_showAtMsgId);
loadCount = MessagesFirstLoad; loadCount = kMessagesPerPageFirst;
} else if (_showAtMsgId > 0) { } else if (_showAtMsgId > 0) {
_history->getReadyFor(_showAtMsgId); _history->getReadyFor(_showAtMsgId);
offset = -loadCount / 2; offset = -loadCount / 2;
@ -2486,8 +2491,9 @@ void HistoryWidget::loadMessages() {
return; return;
} }
MsgId offset_id = from->minMsgId(); auto offset_id = from->minMsgId();
int32 offset = 0, loadCount = offset_id ? MessagesPerPage : MessagesFirstLoad; auto offset = 0;
auto loadCount = offset_id ? kMessagesPerPage : kMessagesPerPageFirst;
_preloadRequest = MTP::send(MTPmessages_GetHistory(from->peer->input, MTP_int(offset_id), MTP_int(0), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from->peer), rpcFail(&HistoryWidget::messagesFailed)); _preloadRequest = MTP::send(MTPmessages_GetHistory(from->peer->input, MTP_int(offset_id), MTP_int(0), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from->peer), rpcFail(&HistoryWidget::messagesFailed));
} }
@ -2505,9 +2511,9 @@ void HistoryWidget::loadMessagesDown() {
return; return;
} }
int32 loadCount = MessagesPerPage, offset = -loadCount; auto loadCount = kMessagesPerPage;
auto offset = -loadCount;
MsgId offset_id = from->maxMsgId(); auto offset_id = from->maxMsgId();
if (!offset_id) { if (!offset_id) {
if (loadMigrated || !_migrated) return; if (loadMigrated || !_migrated) return;
++offset_id; ++offset_id;
@ -2523,8 +2529,10 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) {
clearDelayedShowAt(); clearDelayedShowAt();
_delayedShowAtMsgId = showAtMsgId; _delayedShowAtMsgId = showAtMsgId;
PeerData *from = _peer; auto from = _peer;
int32 offset_id = 0, offset = 0, loadCount = MessagesPerPage; auto offset_id = 0;
auto offset = 0;
auto loadCount = kMessagesPerPage;
if (_delayedShowAtMsgId == ShowAtUnreadMsgId) { if (_delayedShowAtMsgId == ShowAtUnreadMsgId) {
if (_migrated && _migrated->unreadCount()) { if (_migrated && _migrated->unreadCount()) {
from = _migrated->peer; from = _migrated->peer;
@ -2534,10 +2542,10 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) {
offset = -loadCount / 2; offset = -loadCount / 2;
offset_id = _history->inboxReadBefore; offset_id = _history->inboxReadBefore;
} else { } else {
loadCount = MessagesFirstLoad; loadCount = kMessagesPerPageFirst;
} }
} else if (_delayedShowAtMsgId == ShowAtTheEndMsgId) { } else if (_delayedShowAtMsgId == ShowAtTheEndMsgId) {
loadCount = MessagesFirstLoad; loadCount = kMessagesPerPageFirst;
} else if (_delayedShowAtMsgId > 0) { } else if (_delayedShowAtMsgId > 0) {
offset = -loadCount / 2; offset = -loadCount / 2;
offset_id = _delayedShowAtMsgId; offset_id = _delayedShowAtMsgId;
@ -2578,11 +2586,11 @@ void HistoryWidget::preloadHistoryIfNeeded() {
updateHistoryDownVisibility(); updateHistoryDownVisibility();
int st = _scroll->scrollTop(), stm = _scroll->scrollTopMax(), sh = _scroll->height(); int st = _scroll->scrollTop(), stm = _scroll->scrollTopMax(), sh = _scroll->height();
if (st + PreloadHeightsCount * sh > stm) { if (st + kPreloadHeightsCount * sh >= stm) {
loadMessagesDown(); loadMessagesDown();
} }
if (st < PreloadHeightsCount * sh) { if (st <= kPreloadHeightsCount * sh) {
loadMessages(); loadMessages();
} }