mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 18:21:42 -05:00
Creating HistoryBlock only before adding an item to it.
Now invariants always should be kept true, including indexInBlock, indexInHistory and !block->items.isEmpty() Need to backport UniquePointer from other branch.
This commit is contained in:
parent
8f06244895
commit
fed715c1f4
2 changed files with 204 additions and 132 deletions
|
@ -577,14 +577,8 @@ void ChannelHistory::addNewGroup(const MTPMessageGroup &group) {
|
|||
|
||||
if (onlyImportant()) {
|
||||
if (newLoaded) {
|
||||
HistoryBlock *block = blocks.isEmpty() ? pushBackNewBlock() : blocks.back();
|
||||
HistoryItem *prev = block->items.isEmpty() ? nullptr : block->items.back();
|
||||
|
||||
prev = addMessageGroupAfterPrevToBlock(d, prev, block);
|
||||
if (block->items.isEmpty()) {
|
||||
blocks.pop_back();
|
||||
delete block;
|
||||
}
|
||||
t_assert(!isBuildingFrontBlock());
|
||||
addMessageGroup(d);
|
||||
}
|
||||
} else {
|
||||
setNotLoadedAtBottom();
|
||||
|
@ -641,14 +635,12 @@ HistoryJoined *ChannelHistory::insertJoinedMessage(bool unread) {
|
|||
}
|
||||
}
|
||||
|
||||
// adding new item to new block
|
||||
HistoryBlock *block = pushFrontNewBlock();
|
||||
startBuildingFrontBlock();
|
||||
|
||||
_joinedMessage = HistoryJoined::create(this, inviteDate, inviter, flags);
|
||||
addItemToBlock(_joinedMessage, block);
|
||||
addItemToBlock(_joinedMessage);
|
||||
|
||||
t_assert(blocks.size() > 1);
|
||||
blocks.at(1)->items.front()->previousItemChanged();
|
||||
finishBuildingFrontBlock();
|
||||
|
||||
return _joinedMessage;
|
||||
}
|
||||
|
@ -757,15 +749,15 @@ HistoryItem *ChannelHistory::addNewToBlocks(const MTPMessage &msg, NewMessageTyp
|
|||
}
|
||||
|
||||
if (!isImportant && onlyImportant()) {
|
||||
HistoryItem *item = addToHistory(msg), *prev = isEmpty() ? nullptr : blocks.back()->items.back();
|
||||
HistoryItem *item = addToHistory(msg);
|
||||
|
||||
t_assert(!isBuildingFrontBlock());
|
||||
addMessageGroup([item, this](HistoryItem *previous) -> HistoryItem* { // create(..)
|
||||
return HistoryGroup::create(this, item, previous ? previous->date : item->date);
|
||||
}, [item](HistoryGroup *existing) { // unite(..)
|
||||
existing->uniteWith(item);
|
||||
});
|
||||
|
||||
if (prev && prev->type() == HistoryItemGroup) {
|
||||
static_cast<HistoryGroup*>(prev)->uniteWith(item);
|
||||
} else {
|
||||
QDateTime date = prev ? prev->date : item->date;
|
||||
HistoryBlock *block = prev ? prev->block() : pushBackNewBlock();
|
||||
addItemToBlock(HistoryGroup::create(this, item, date), block);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
|
@ -821,22 +813,15 @@ void ChannelHistory::switchMode() {
|
|||
|
||||
clear(true);
|
||||
|
||||
t_assert(!isBuildingFrontBlock());
|
||||
|
||||
newLoaded = _otherNewLoaded;
|
||||
oldLoaded = _otherOldLoaded;
|
||||
if (int count = _otherList.size()) {
|
||||
blocks.reserve(qCeil(count / float64(MessagesPerPage)));
|
||||
|
||||
blocks.reserve((count / MessagesPerPage) + 1);
|
||||
for (int i = 0; i < count;) {
|
||||
HistoryBlock *block = pushBackNewBlock();
|
||||
|
||||
int willAddToBlock = qMin(int(MessagesPerPage), count - i);
|
||||
block->items.reserve(willAddToBlock);
|
||||
for (int till = i + willAddToBlock; i < till; ++i) {
|
||||
t_assert(_otherList.at(i)->detached());
|
||||
addItemToBlock(_otherList.at(i), block);
|
||||
}
|
||||
|
||||
t_assert(!block->items.isEmpty());
|
||||
t_assert(_otherList.at(i)->detached());
|
||||
addItemToBlock(_otherList.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1550,16 +1535,10 @@ void History::eraseFromOverview(MediaOverviewType type, MsgId msgId) {
|
|||
}
|
||||
|
||||
HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) {
|
||||
t_assert(adding != nullptr);
|
||||
t_assert(adding->detached());
|
||||
t_assert(!isBuildingFrontBlock());
|
||||
addItemToBlock(adding);
|
||||
|
||||
HistoryBlock *block = blocks.isEmpty() ? pushBackNewBlock() : blocks.back();
|
||||
|
||||
adding->attachToBlock(block, block->items.size());
|
||||
block->items.push_back(adding);
|
||||
adding->previousItemChanged();
|
||||
setLastMessage(adding);
|
||||
|
||||
if (newMsg) {
|
||||
newItemAdded(adding);
|
||||
}
|
||||
|
@ -1671,19 +1650,50 @@ void History::newItemAdded(HistoryItem *item) {
|
|||
}
|
||||
}
|
||||
|
||||
HistoryItem *History::addItemToBlock(HistoryItem *item, HistoryBlock *block) {
|
||||
HistoryBlock *History::prepareBlockForAddingItem() {
|
||||
if (isBuildingFrontBlock()) {
|
||||
if (_frontBlock->block) {
|
||||
return _frontBlock->block;
|
||||
}
|
||||
|
||||
HistoryBlock *result = _frontBlock->block = new HistoryBlock(this);
|
||||
if (_frontBlock->expectedItemsCount > 0) {
|
||||
result->items.reserve(_frontBlock->expectedItemsCount + 1);
|
||||
}
|
||||
result->setIndexInHistory(0);
|
||||
blocks.push_front(result);
|
||||
for (int i = 1, l = blocks.size(); i < l; ++i) {
|
||||
blocks.at(i)->setIndexInHistory(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool addNewBlock = blocks.isEmpty() || (blocks.back()->items.size() >= MessagesPerPage);
|
||||
if (!addNewBlock) {
|
||||
return blocks.back();
|
||||
}
|
||||
|
||||
HistoryBlock *result = new HistoryBlock(this);
|
||||
result->setIndexInHistory(blocks.size());
|
||||
blocks.push_back(result);
|
||||
|
||||
result->items.reserve(MessagesPerPage);
|
||||
return result;
|
||||
};
|
||||
|
||||
void History::addItemToBlock(HistoryItem *item) {
|
||||
t_assert(item != nullptr);
|
||||
t_assert(item->detached());
|
||||
|
||||
HistoryBlock *block = prepareBlockForAddingItem();
|
||||
|
||||
item->attachToBlock(block, block->items.size());
|
||||
block->items.push_back(item);
|
||||
item->previousItemChanged();
|
||||
return item;
|
||||
}
|
||||
|
||||
HistoryItem *History::addMessageGroupAfterPrevToBlock(const MTPDmessageGroup &group, HistoryItem *prev, HistoryBlock *block) {
|
||||
if (prev && prev->type() == HistoryItemGroup) {
|
||||
static_cast<HistoryGroup*>(prev)->uniteWith(group.vmin_id.v, group.vmax_id.v, group.vcount.v);
|
||||
return prev;
|
||||
if (isBuildingFrontBlock() && _frontBlock->expectedItemsCount > 0) {
|
||||
--_frontBlock->expectedItemsCount;
|
||||
}
|
||||
return addItemToBlock(HistoryGroup::create(this, group, prev ? prev->date : date(group.vdate)), block);
|
||||
}
|
||||
|
||||
void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPMessageGroup> *collapsed) {
|
||||
|
@ -1700,10 +1710,8 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
|
|||
|
||||
const MTPMessageGroup *groupsBegin = (isChannel() && collapsed) ? collapsed->constData() : 0, *groupsIt = groupsBegin, *groupsEnd = (isChannel() && collapsed) ? (groupsBegin + collapsed->size()) : 0;
|
||||
|
||||
HistoryItem *prev = nullptr;
|
||||
HistoryBlock *block = pushFrontNewBlock();
|
||||
startBuildingFrontBlock(slice.size() + (collapsed ? collapsed->size() : 0));
|
||||
|
||||
block->items.reserve(slice.size() + (collapsed ? collapsed->size() : 0));
|
||||
for (auto i = slice.cend(), e = slice.cbegin(); i != e;) {
|
||||
--i;
|
||||
HistoryItem *adding = createItem(*i, false, true);
|
||||
|
@ -1714,23 +1722,21 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
|
|||
const MTPDmessageGroup &group(groupsIt->c_messageGroup());
|
||||
if (group.vmin_id.v >= adding->id) break;
|
||||
|
||||
prev = addMessageGroupAfterPrevToBlock(group, prev, block);
|
||||
addMessageGroup(group);
|
||||
}
|
||||
|
||||
prev = addItemToBlock(adding, block);
|
||||
addItemToBlock(adding);
|
||||
}
|
||||
for (; groupsIt != groupsEnd; ++groupsIt) {
|
||||
if (groupsIt->type() != mtpc_messageGroup) continue;
|
||||
const MTPDmessageGroup &group(groupsIt->c_messageGroup());
|
||||
|
||||
prev = addMessageGroupAfterPrevToBlock(group, prev, block);
|
||||
addMessageGroup(group);
|
||||
}
|
||||
|
||||
if (block->items.isEmpty()) {
|
||||
blocks.pop_front();
|
||||
delete block;
|
||||
block = nullptr;
|
||||
|
||||
HistoryBlock *block = finishBuildingFrontBlock();
|
||||
if (!block) {
|
||||
// If no items were added it means we've loaded everything old.
|
||||
oldLoaded = true;
|
||||
} else if (loadedAtBottom()) { // add photos to overview and authors to lastAuthors / lastParticipants
|
||||
bool channel = isChannel();
|
||||
|
@ -1808,28 +1814,6 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
|
|||
}
|
||||
}
|
||||
|
||||
// some checks if there was some message history already
|
||||
if (block && blocks.size() > 1) {
|
||||
HistoryItem *last = block->items.back(); // ... item, item, item, last ], [ first, item, item ...
|
||||
HistoryItem *first = blocks.at(1)->items.front();
|
||||
|
||||
// we've added a new front block, so previous item for
|
||||
// the old first item of a first block was changed
|
||||
first->previousItemChanged();
|
||||
|
||||
// we've added a new front block, now we check if both
|
||||
// last message of the first block and first message of
|
||||
// the second block are groups, if they are - unite them
|
||||
if (first->type() == HistoryItemGroup && last->type() == HistoryItemGroup) {
|
||||
static_cast<HistoryGroup*>(first)->uniteWith(static_cast<HistoryGroup*>(last));
|
||||
last->destroy();
|
||||
|
||||
// last->destroy() could've destroyed this new block
|
||||
// so we can't rely on this pointer any more
|
||||
block = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (isChannel()) {
|
||||
asChannelHistory()->checkJoinedMessage();
|
||||
asChannelHistory()->checkMaxReadMessageDate();
|
||||
|
@ -1845,14 +1829,11 @@ void History::addNewerSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
|
|||
if (!lastMsg) setLastMessage(lastImportantMessage());
|
||||
}
|
||||
|
||||
t_assert(!isBuildingFrontBlock());
|
||||
if (!slice.isEmpty() || (isChannel() && collapsed && !collapsed->isEmpty())) {
|
||||
const MTPMessageGroup *groupsBegin = (isChannel() && collapsed) ? collapsed->constData() : 0, *groupsIt = groupsBegin, *groupsEnd = (isChannel() && collapsed) ? (groupsBegin + collapsed->size()) : 0;
|
||||
|
||||
HistoryItem *prev = blocks.isEmpty() ? nullptr : blocks.back()->items.back();
|
||||
|
||||
HistoryBlock *block = pushBackNewBlock();
|
||||
|
||||
block->items.reserve(slice.size() + (collapsed ? collapsed->size() : 0));
|
||||
bool atLeastOneAdded = false;
|
||||
for (auto i = slice.cend(), e = slice.cbegin(); i != e;) {
|
||||
--i;
|
||||
HistoryItem *adding = createItem(*i, false, true);
|
||||
|
@ -1863,25 +1844,22 @@ void History::addNewerSlice(const QVector<MTPMessage> &slice, const QVector<MTPM
|
|||
const MTPDmessageGroup &group(groupsIt->c_messageGroup());
|
||||
if (group.vmin_id.v >= adding->id) break;
|
||||
|
||||
prev = addMessageGroupAfterPrevToBlock(group, prev, block);
|
||||
addMessageGroup(group);
|
||||
}
|
||||
|
||||
prev = addItemToBlock(adding, block);
|
||||
addItemToBlock(adding);
|
||||
atLeastOneAdded = true;
|
||||
}
|
||||
for (; groupsIt != groupsEnd; ++groupsIt) {
|
||||
if (groupsIt->type() != mtpc_messageGroup) continue;
|
||||
const MTPDmessageGroup &group(groupsIt->c_messageGroup());
|
||||
|
||||
prev = addMessageGroupAfterPrevToBlock(group, prev, block);
|
||||
addMessageGroup(group);
|
||||
}
|
||||
|
||||
if (block->items.isEmpty()) {
|
||||
if (!atLeastOneAdded) {
|
||||
newLoaded = true;
|
||||
setLastMessage(lastImportantMessage());
|
||||
|
||||
blocks.pop_back();
|
||||
delete block;
|
||||
block = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2181,21 +2159,76 @@ HistoryItem *History::addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex,
|
|||
return newItem;
|
||||
}
|
||||
|
||||
HistoryBlock *History::pushBackNewBlock() {
|
||||
HistoryBlock *result = new HistoryBlock(this);
|
||||
result->setIndexInHistory(blocks.size());
|
||||
blocks.push_back(result);
|
||||
return result;
|
||||
template <typename CreateGroup, typename UniteGroup>
|
||||
void History::addMessageGroup(CreateGroup create, UniteGroup unite) {
|
||||
HistoryItem *previous = nullptr;
|
||||
if (isBuildingFrontBlock()) {
|
||||
if (_frontBlock->block) {
|
||||
previous = _frontBlock->block->items.back();
|
||||
}
|
||||
} else {
|
||||
if (!blocks.isEmpty()) {
|
||||
previous = blocks.back()->items.back();
|
||||
}
|
||||
}
|
||||
|
||||
if (previous && previous->type() == HistoryItemGroup) {
|
||||
unite(static_cast<HistoryGroup*>(previous));
|
||||
return;
|
||||
}
|
||||
|
||||
HistoryGroup *result = create(previous);
|
||||
if (isBuildingFrontBlock()) {
|
||||
addItemToBuildingFrontBlock(result);
|
||||
} else {
|
||||
addItemToBackBlock(result);
|
||||
}
|
||||
}
|
||||
|
||||
HistoryBlock *History::pushFrontNewBlock() {
|
||||
HistoryBlock *result = new HistoryBlock(this);
|
||||
result->setIndexInHistory(0);
|
||||
blocks.push_front(result);
|
||||
for (int i = 1, l = blocks.size(); i < l; ++i) {
|
||||
blocks.at(i)->setIndexInHistory(i);
|
||||
void History::addMessageGroup(const MTPDmessageGroup &group) {
|
||||
addMessageGroup([&group, this](HistoryItem *previous) -> HistoryItem* { // create(..)
|
||||
return HistoryGroup::create(this, group, previous ? previous->date : date(group.vdate));
|
||||
}, [&group](HistoryGroup *existing) { // unite(..)
|
||||
existing->uniteWith(group.vmin_id.v, group.vmax_id.v, group.vcount.v);
|
||||
});
|
||||
}
|
||||
|
||||
void History::startBuildingFrontBlock(int expectedItemsCount) {
|
||||
t_assert(!isBuildingFrontBlock());
|
||||
t_assert(expectedItemsCount > 0);
|
||||
|
||||
_frontBlock.reset(new BuildingBlock());
|
||||
_frontBlock->expectedItemsCount = expectedItemsCount;
|
||||
}
|
||||
|
||||
HistoryBlock *History::finishBuildingFrontBlock() {
|
||||
t_assert(isBuildingFrontBlock());
|
||||
|
||||
// Some checks if there was some message history already
|
||||
HistoryBlock *block = _frontBlock->block;
|
||||
if (block && blocks.size() > 1) {
|
||||
HistoryItem *last = block->items.back(); // ... item, item, item, last ], [ first, item, item ...
|
||||
HistoryItem *first = blocks.at(1)->items.front();
|
||||
|
||||
// we've added a new front block, so previous item for
|
||||
// the old first item of a first block was changed
|
||||
first->previousItemChanged();
|
||||
|
||||
// we've added a new front block, now we check if both
|
||||
// last message of the first block and first message of
|
||||
// the second block are groups, if they are - unite them
|
||||
if (first->type() == HistoryItemGroup && last->type() == HistoryItemGroup) {
|
||||
static_cast<HistoryGroup*>(first)->uniteWith(static_cast<HistoryGroup*>(last));
|
||||
last->destroy();
|
||||
|
||||
// last->destroy() could've destroyed this new block
|
||||
// so we can't rely on this pointer any more
|
||||
block = _frontBlock->block;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
_frontBlock.clear();
|
||||
return block;
|
||||
}
|
||||
|
||||
void History::clearNotifications() {
|
||||
|
@ -2572,6 +2605,10 @@ void History::changeMsgId(MsgId oldId, MsgId newId) {
|
|||
void History::removeBlock(HistoryBlock *block) {
|
||||
t_assert(block->items.isEmpty());
|
||||
|
||||
if (_frontBlock && block == _frontBlock->block) {
|
||||
_frontBlock->block = nullptr;
|
||||
}
|
||||
|
||||
int index = block->indexInHistory();
|
||||
blocks.removeAt(index);
|
||||
for (int i = index, l = blocks.size(); i < l; ++i) {
|
||||
|
|
|
@ -470,19 +470,64 @@ protected:
|
|||
void clearOnDestroy();
|
||||
HistoryItem *addNewToLastBlock(const MTPMessage &msg, NewMessageType type);
|
||||
|
||||
friend class HistoryBlock;
|
||||
|
||||
// this method just removes a block from the blocks list
|
||||
// when the last item from this block was detached and
|
||||
// calls the required previousItemChanged()
|
||||
void removeBlock(HistoryBlock *block);
|
||||
|
||||
void clearBlocks(bool leaveItems);
|
||||
|
||||
HistoryItem *createItem(const MTPMessage &msg, bool applyServiceAction, bool detachExistingItem);
|
||||
HistoryItem *createItemForwarded(MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *msg);
|
||||
HistoryItem *createItemDocument(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption);
|
||||
HistoryItem *createItemPhoto(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption);
|
||||
|
||||
HistoryItem *addNewItem(HistoryItem *adding, bool newMsg);
|
||||
HistoryItem *addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex, int32 itemIndex);
|
||||
|
||||
// All this methods add a new item to the first or last block
|
||||
// depending on if we are in isBuildingFronBlock() state.
|
||||
// The last block is created on the go if it is needed.
|
||||
|
||||
// If the previous item is a message group the new group is
|
||||
// not created but is just united with the previous one.
|
||||
// create(HistoryItem *previous) should return a new HistoryGroup*
|
||||
// unite(HistoryGroup *existing) should unite a new group with an existing
|
||||
template <typename CreateGroup, typename UniteGroup>
|
||||
void addMessageGroup(CreateGroup create, UniteGroup unite);
|
||||
void addMessageGroup(const MTPDmessageGroup &group);
|
||||
|
||||
// Adds the item to the back or front block, depending on
|
||||
// isBuildingFrontBlock(), creating the block if necessary.
|
||||
void addItemToBlock(HistoryItem *item);
|
||||
|
||||
// Usually all new items are added to the last block.
|
||||
// Only when we scroll up and add a new slice to the
|
||||
// front we want to create a new front block.
|
||||
void startBuildingFrontBlock(int expectedItemsCount = 1);
|
||||
HistoryBlock *finishBuildingFrontBlock(); // Returns the built block or nullptr if nothing was added.
|
||||
bool isBuildingFrontBlock() const {
|
||||
return !_buildingFrontBlock.isNull();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
enum Flag {
|
||||
enum class Flag {
|
||||
f_has_pending_resized_items = (1 << 0),
|
||||
f_pending_resize = (1 << 1),
|
||||
f_pending_resize = (1 << 1),
|
||||
};
|
||||
Q_DECLARE_FLAGS(Flags, Flag);
|
||||
Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, Flags::enum_type f2) Q_DECL_NOTHROW {
|
||||
Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, Flags::enum_type f2) noexcept {
|
||||
return QFlags<Flags::enum_type>(f1) | f2;
|
||||
}
|
||||
Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, QFlags<Flags::enum_type> f2) Q_DECL_NOTHROW {
|
||||
Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator|(Flags::enum_type f1, QFlags<Flags::enum_type> f2) noexcept {
|
||||
return f2 | f1;
|
||||
}
|
||||
Q_DECL_CONSTEXPR friend inline QFlags<Flags::enum_type> operator~(Flags::enum_type f) noexcept {
|
||||
return ~QFlags<Flags::enum_type>(f);
|
||||
}
|
||||
Flags _flags;
|
||||
|
||||
ChatListLinksMap _chatListLinks;
|
||||
|
@ -497,28 +542,18 @@ private:
|
|||
MediaOverviewIds overviewIds[OverviewCount];
|
||||
int32 overviewCountData[OverviewCount]; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded
|
||||
|
||||
friend class HistoryBlock;
|
||||
friend class ChannelHistory;
|
||||
// A pointer to the block that is currently being built.
|
||||
// We hold this pointer so we can destroy it while building
|
||||
// and then create a new one if it is necessary.
|
||||
struct BuildingBlock {
|
||||
int expectedItemsCount = 0; // optimization for block->items.reserve() call
|
||||
HistoryBlock *block = nullptr;
|
||||
};
|
||||
UniquePointer<BuildingBlock> _buildingFrontBlock;
|
||||
|
||||
// this method just removes a block from the blocks list
|
||||
// when the last item from this block was detached and
|
||||
// calls the required previousItemChanged()
|
||||
void removeBlock(HistoryBlock *block);
|
||||
|
||||
void clearBlocks(bool leaveItems);
|
||||
|
||||
HistoryItem *createItem(const MTPMessage &msg, bool applyServiceAction, bool detachExistingItem);
|
||||
HistoryItem *createItemForwarded(MsgId id, MTPDmessage::Flags flags, QDateTime date, int32 from, HistoryMessage *msg);
|
||||
HistoryItem *createItemDocument(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, DocumentData *doc, const QString &caption);
|
||||
HistoryItem *createItemPhoto(MsgId id, MTPDmessage::Flags flags, int32 viaBotId, MsgId replyTo, QDateTime date, int32 from, PhotoData *photo, const QString &caption);
|
||||
|
||||
HistoryItem *addItemToBlock(HistoryItem *item, HistoryBlock *block);
|
||||
HistoryItem *addNewItem(HistoryItem *adding, bool newMsg);
|
||||
HistoryItem *addMessageGroupAfterPrevToBlock(const MTPDmessageGroup &group, HistoryItem *prev, HistoryBlock *block);
|
||||
HistoryItem *addNewInTheMiddle(HistoryItem *newItem, int32 blockIndex, int32 itemIndex);
|
||||
|
||||
HistoryBlock *pushBackNewBlock();
|
||||
HistoryBlock *pushFrontNewBlock();
|
||||
// Creates if necessary a new block for adding item.
|
||||
// Depending on isBuildingFrontBlock() gets front or back block.
|
||||
HistoryBlock *prepareBlockForAddingItem();
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue