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

View File

@ -622,14 +622,13 @@ private:
class HistoryBlock {
public:
HistoryBlock(History *hist) : history(hist), _indexInHistory(-1) {
HistoryBlock(gsl::not_null<History*> history) : _history(history) {
}
HistoryBlock(const HistoryBlock &) = delete;
HistoryBlock &operator=(const HistoryBlock &) = delete;
typedef QVector<HistoryItem*> Items;
Items items;
QVector<HistoryItem*> items;
void clear(bool leaveItems = false);
~HistoryBlock() {
@ -638,31 +637,45 @@ public:
void removeItem(HistoryItem *item);
int resizeGetHeight(int newWidth, bool resizeAllItems);
int y = 0;
int height = 0;
History *history;
int y() const {
return _y;
}
void setY(int y) {
_y = y;
}
int height() const {
return _height;
}
gsl::not_null<History*> history() const {
return _history;
}
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 {
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) {
_indexInHistory = index;
}
int indexInHistory() const {
t_assert(_indexInHistory >= 0);
t_assert(history->blocks.at(_indexInHistory) == this);
Expects(_indexInHistory >= 0);
Expects(_indexInHistory < _history->blocks.size());
Expects(_history->blocks[_indexInHistory] == this);
return _indexInHistory;
}
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());
while (end - start > 1) {
auto middle = (start + end) / 2;
auto top = list[middle]->y;
auto top = list[middle]->y();
auto chooseLeft = (TopToBottom ? (top <= edge) : (top < edge));
if (chooseLeft) {
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
auto block = history->blocks.at(blockIndex);
auto blocktop = historytop + block->y;
auto blockbottom = blocktop + block->height;
auto blocktop = historytop + block->y();
auto blockbottom = blocktop + block->height();
auto itemIndex = binarySearchBlocksOrItems<TopToBottom>(block->items, searchEdge - blocktop);
while (true) {
while (true) {
auto item = block->items.at(itemIndex);
auto itemtop = blocktop + item->y;
auto itemtop = blocktop + item->y();
auto itembottom = itemtop + item->height();
// 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("history->blocks.size()", history->blocks.size());
debugValue("blocktop", blocktop);
debugValue("block->height", block->height);
debugValue("block->height", block->height());
debugValue("itemIndex", itemIndex);
debugValue("block->items.size()", block->items.size());
debugValue("itemtop", itemtop);
@ -214,10 +214,10 @@ void HistoryInner::enumerateItemsInHistory(History *history, int historytop, Met
debugValue("_visibleAreaTop", _visibleAreaTop);
debugValue("_visibleAreaBottom", _visibleAreaBottom);
for (int i = 0; i != qMin(history->blocks.size(), 5); ++i) {
debugValue("y[" + QString::number(i) + "]", history->blocks[i]->y);
debugValue("h[" + QString::number(i) + "]", history->blocks[i]->height);
debugValue("y[" + QString::number(i) + "]", history->blocks[i]->y());
debugValue("h[" + QString::number(i) + "]", history->blocks[i]->height());
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());
}
}
@ -225,8 +225,8 @@ void HistoryInner::enumerateItemsInHistory(History *history, int historytop, Met
auto y = 0;
for (int i = 0; i != history->blocks.size(); ++i) {
auto innery = 0;
if (history->blocks[i]->y != y) {
debugInfo.append("bad_block_y" + QString::number(i) + ":" + QString::number(history->blocks[i]->y) + "!=" + QString::number(y));
if (history->blocks[i]->y() != y) {
debugInfo.append("bad_block_y" + QString::number(i) + ":" + QString::number(history->blocks[i]->y()) + "!=" + QString::number(y));
return false;
}
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()) {
debugInfo.append("pending_resize" + QString::number(i) + "," + QString::number(j));
}
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));
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));
return false;
}
innery += history->blocks[i]->items[j]->height();
}
if (history->blocks[i]->height != innery) {
debugInfo.append("bad_block_height" + QString::number(i) + ":" + QString::number(history->blocks[i]->height) + "!=" + QString::number(innery));
if (history->blocks[i]->height() != innery) {
debugInfo.append("bad_block_height" + QString::number(i) + ":" + QString::number(history->blocks[i]->height()) + "!=" + QString::number(innery));
return false;
}
y += innery;
@ -305,9 +305,9 @@ void HistoryInner::enumerateItemsInHistory(History *history, int historytop, Met
return;
}
}
block = history->blocks.at(blockIndex);
blocktop = historytop + block->y;
blockbottom = blocktop + block->height;
block = history->blocks[blockIndex];
blocktop = historytop + block->y();
blockbottom = blocktop + block->height();
if (TopToBottom) {
itemIndex = 0;
} else {
@ -472,14 +472,16 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
seltoy += _dragSelTo->height();
}
int32 mtop = migratedTop(), htop = historyTop(), hdrawtop = historyDrawTop();
auto mtop = migratedTop();
auto htop = historyTop();
auto hdrawtop = historyDrawTop();
if (mtop >= 0) {
int32 iBlock = (_curHistory == _migrated ? _curBlock : (_migrated->blocks.size() - 1));
HistoryBlock *block = _migrated->blocks[iBlock];
int32 iItem = (_curHistory == _migrated ? _curItem : (block->items.size() - 1));
HistoryItem *item = block->items[iItem];
auto iBlock = (_curHistory == _migrated ? _curBlock : (_migrated->blocks.size() - 1));
auto block = _migrated->blocks[iBlock];
auto iItem = (_curHistory == _migrated ? _curItem : (block->items.size() - 1));
auto item = block->items[iItem];
int32 y = mtop + block->y + item->y;
auto y = mtop + block->y() + item->y();
p.save();
p.translate(0, y);
if (r.y() < y + item->height()) while (y < drawToY) {
@ -518,17 +520,17 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
p.restore();
}
if (htop >= 0) {
int32 iBlock = (_curHistory == _history ? _curBlock : 0);
HistoryBlock *block = _history->blocks[iBlock];
int32 iItem = (_curHistory == _history ? _curItem : 0);
HistoryItem *item = block->items[iItem];
auto iBlock = (_curHistory == _history ? _curBlock : 0);
auto block = _history->blocks[iBlock];
auto iItem = (_curHistory == _history ? _curItem : 0);
auto item = block->items[iItem];
QRect historyRect = r.intersected(QRect(0, hdrawtop, width(), r.top() + r.height()));
int32 y = htop + block->y + item->y;
auto historyRect = r.intersected(QRect(0, hdrawtop, width(), r.top() + r.height()));
auto y = htop + block->y() + item->y();
p.save();
p.translate(0, y);
while (y < drawToY) {
int32 h = item->height();
auto h = item->height();
if (historyRect.y() < y + h && hdrawtop < y + h) {
TextSelection sel;
if (y >= selfromy && y < seltoy) {
@ -1902,23 +1904,23 @@ void HistoryInner::adjustCurrent(int32 y, History *history) const {
_curBlock = history->blocks.size() - 1;
_curItem = 0;
}
while (history->blocks.at(_curBlock)->y > y && _curBlock > 0) {
while (history->blocks[_curBlock]->y() > y && _curBlock > 0) {
--_curBlock;
_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;
_curItem = 0;
}
HistoryBlock *block = history->blocks.at(_curBlock);
auto block = history->blocks[_curBlock];
if (_curItem >= block->items.size()) {
_curItem = block->items.size() - 1;
}
int by = block->y;
while (block->items.at(_curItem)->y + by > y && _curItem > 0) {
auto by = block->y();
while (block->items[_curItem]->y() + by > y && _curItem > 0) {
--_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;
}
}
@ -2300,14 +2302,15 @@ int HistoryInner::historyHeight() const {
}
int HistoryInner::historyScrollTop() const {
int htop = historyTop(), mtop = migratedTop();
auto htop = historyTop();
auto mtop = migratedTop();
if (htop >= 0 && _history->scrollTopItem) {
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) {
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;
}
@ -2331,7 +2334,7 @@ int HistoryInner::itemTop(const HistoryItem *item) const { // -1 if should not b
if (item->detached()) return -1;
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() {

View File

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

View File

@ -156,8 +156,8 @@ struct HistoryMessageReply : public RuntimeComponent<HistoryMessageReply> {
}
~HistoryMessageReply() {
// clearData() should be called by holder
t_assert(replyToMsg == nullptr);
t_assert(_replyToVia == nullptr);
Expects(replyToMsg == nullptr);
Expects(_replyToVia == nullptr);
}
bool updateData(HistoryMessage *holder, bool force = false);
@ -438,7 +438,7 @@ public:
return get();
}
HistoryMedia &operator*() const {
t_assert(!isNull());
Expects(!isNull());
return *get();
}
explicit operator bool() const {
@ -522,10 +522,10 @@ public:
return !_block;
}
void attachToBlock(HistoryBlock *block, int index) {
t_assert(_block == nullptr);
t_assert(_indexInBlock < 0);
t_assert(block != nullptr);
t_assert(index >= 0);
Expects(_block == nullptr);
Expects(_indexInBlock < 0);
Expects(block != nullptr);
Expects(index >= 0);
_block = block;
_indexInBlock = index;
@ -534,8 +534,8 @@ public:
}
}
void setIndexInBlock(int index) {
t_assert(_block != nullptr);
t_assert(index >= 0);
Expects(_block != nullptr);
Expects(index >= 0);
_indexInBlock = index;
}
@ -575,7 +575,7 @@ public:
return (_flags & MTPDmessage::Flag::f_reply_markup);
}
MTPDreplyKeyboardMarkup::Flags replyKeyboardFlags() const {
t_assert(definesReplyKeyboard());
Expects(definesReplyKeyboard());
if (auto markup = Get<HistoryMessageReplyMarkup>()) {
return markup->flags;
}
@ -701,7 +701,12 @@ public:
}
QString directLink() const;
int32 y;
int y() const {
return _y;
}
void setY(int y) {
_y = y;
}
MsgId id;
QDateTime date;
@ -951,6 +956,9 @@ protected:
HistoryMediaPtr _media;
private:
int _y = 0;
};
// 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 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() {
return [](ChannelData *channel, MsgId msgId) {
@ -2255,7 +2258,7 @@ bool HistoryWidget::messagesFailed(const RPCError &error, mtpRequestId requestId
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")) {
PeerData *was = _peer;
auto was = _peer;
App::main()->showBackFromStack();
Ui::show(Box<InformBox>(lang((was && was->isMegagroup()) ? lng_group_not_accessible : lng_channel_not_accessible)));
return true;
@ -2437,8 +2440,10 @@ bool HistoryWidget::historyHasNotFreezedUnreadBar(History *history) const {
void HistoryWidget::firstLoadMessages() {
if (!_history || _firstLoadRequest) return;
PeerData *from = _peer;
int32 offset_id = 0, offset = 0, loadCount = MessagesPerPage;
auto from = _peer;
auto offset_id = 0;
auto offset = 0;
auto loadCount = kMessagesPerPage;
if (_showAtMsgId == ShowAtUnreadMsgId) {
if (_migrated && _migrated->unreadCount()) {
_history->getReadyFor(_showAtMsgId);
@ -2454,7 +2459,7 @@ void HistoryWidget::firstLoadMessages() {
}
} else if (_showAtMsgId == ShowAtTheEndMsgId) {
_history->getReadyFor(_showAtMsgId);
loadCount = MessagesFirstLoad;
loadCount = kMessagesPerPageFirst;
} else if (_showAtMsgId > 0) {
_history->getReadyFor(_showAtMsgId);
offset = -loadCount / 2;
@ -2486,8 +2491,9 @@ void HistoryWidget::loadMessages() {
return;
}
MsgId offset_id = from->minMsgId();
int32 offset = 0, loadCount = offset_id ? MessagesPerPage : MessagesFirstLoad;
auto offset_id = from->minMsgId();
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));
}
@ -2505,9 +2511,9 @@ void HistoryWidget::loadMessagesDown() {
return;
}
int32 loadCount = MessagesPerPage, offset = -loadCount;
MsgId offset_id = from->maxMsgId();
auto loadCount = kMessagesPerPage;
auto offset = -loadCount;
auto offset_id = from->maxMsgId();
if (!offset_id) {
if (loadMigrated || !_migrated) return;
++offset_id;
@ -2523,8 +2529,10 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) {
clearDelayedShowAt();
_delayedShowAtMsgId = showAtMsgId;
PeerData *from = _peer;
int32 offset_id = 0, offset = 0, loadCount = MessagesPerPage;
auto from = _peer;
auto offset_id = 0;
auto offset = 0;
auto loadCount = kMessagesPerPage;
if (_delayedShowAtMsgId == ShowAtUnreadMsgId) {
if (_migrated && _migrated->unreadCount()) {
from = _migrated->peer;
@ -2534,10 +2542,10 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) {
offset = -loadCount / 2;
offset_id = _history->inboxReadBefore;
} else {
loadCount = MessagesFirstLoad;
loadCount = kMessagesPerPageFirst;
}
} else if (_delayedShowAtMsgId == ShowAtTheEndMsgId) {
loadCount = MessagesFirstLoad;
loadCount = kMessagesPerPageFirst;
} else if (_delayedShowAtMsgId > 0) {
offset = -loadCount / 2;
offset_id = _delayedShowAtMsgId;
@ -2578,11 +2586,11 @@ void HistoryWidget::preloadHistoryIfNeeded() {
updateHistoryDownVisibility();
int st = _scroll->scrollTop(), stm = _scroll->scrollTopMax(), sh = _scroll->height();
if (st + PreloadHeightsCount * sh > stm) {
if (st + kPreloadHeightsCount * sh >= stm) {
loadMessagesDown();
}
if (st < PreloadHeightsCount * sh) {
if (st <= kPreloadHeightsCount * sh) {
loadMessages();
}