mirror of https://github.com/procxx/kepka.git
Track local messages, restore on history jump.
This commit is contained in:
parent
04bf24288a
commit
0005e0a3ce
|
@ -1797,7 +1797,7 @@ void ApiWrap::requestSelfParticipant(not_null<ChannelData*> channel) {
|
|||
channel->inviteDate = inviteDate;
|
||||
if (const auto history = _session->data().historyLoaded(channel)) {
|
||||
if (history->lastMessageKnown()) {
|
||||
history->checkJoinedMessage(true);
|
||||
history->checkLocalMessages();
|
||||
history->owner().sendHistoryChangeNotifications();
|
||||
} else {
|
||||
requestDialogEntry(history);
|
||||
|
|
|
@ -131,6 +131,9 @@ void History::setHasPendingResizedItems() {
|
|||
}
|
||||
|
||||
void History::itemRemoved(not_null<HistoryItem*> item) {
|
||||
if (item == _joinedMessage) {
|
||||
_joinedMessage = nullptr;
|
||||
}
|
||||
item->removeMainView();
|
||||
if (lastMessage() == item) {
|
||||
_lastMessage = std::nullopt;
|
||||
|
@ -142,6 +145,9 @@ void History::itemRemoved(not_null<HistoryItem*> item) {
|
|||
}
|
||||
checkChatListMessageRemoved(item);
|
||||
itemVanished(item);
|
||||
if (IsClientMsgId(item->id)) {
|
||||
unregisterLocalMessage(item);
|
||||
}
|
||||
if (const auto chat = peer->asChat()) {
|
||||
if (const auto to = chat->getMigrateToChannel()) {
|
||||
if (const auto history = owner().historyLoaded(to)) {
|
||||
|
@ -679,7 +685,7 @@ void History::checkForLoadedAtTop(not_null<HistoryItem*> added) {
|
|||
} else if (peer->isChannel()) {
|
||||
if (added->id == 1) {
|
||||
_loadedAtTop = true;
|
||||
checkJoinedMessage();
|
||||
checkLocalMessages();
|
||||
addEdgesToSharedMedia();
|
||||
}
|
||||
}
|
||||
|
@ -1208,9 +1214,8 @@ void History::clearSendAction(not_null<UserData*> from) {
|
|||
void History::mainViewRemoved(
|
||||
not_null<HistoryBlock*> block,
|
||||
not_null<HistoryView::Element*> view) {
|
||||
if (_joinedMessage == view->data()) {
|
||||
_joinedMessage = nullptr;
|
||||
}
|
||||
Expects(_joinedMessage != view->data());
|
||||
|
||||
if (_firstUnreadView == view) {
|
||||
getNextFirstUnreadMessage();
|
||||
}
|
||||
|
@ -1253,6 +1258,14 @@ void History::newItemAdded(not_null<HistoryItem*> item) {
|
|||
}
|
||||
}
|
||||
|
||||
void History::registerLocalMessage(not_null<HistoryItem*> item) {
|
||||
_localMessages.emplace(item);
|
||||
}
|
||||
|
||||
void History::unregisterLocalMessage(not_null<HistoryItem*> item) {
|
||||
_localMessages.remove(item);
|
||||
}
|
||||
|
||||
HistoryBlock *History::prepareBlockForAddingItem() {
|
||||
if (isBuildingFrontBlock()) {
|
||||
if (_buildingFrontBlock->block) {
|
||||
|
@ -1318,7 +1331,7 @@ void History::addEdgesToSharedMedia() {
|
|||
void History::addOlderSlice(const QVector<MTPMessage> &slice) {
|
||||
if (slice.isEmpty()) {
|
||||
_loadedAtTop = true;
|
||||
checkJoinedMessage();
|
||||
checkLocalMessages();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1340,7 +1353,7 @@ void History::addOlderSlice(const QVector<MTPMessage> &slice) {
|
|||
addEdgesToSharedMedia();
|
||||
}
|
||||
|
||||
checkJoinedMessage();
|
||||
checkLocalMessages();
|
||||
checkLastMessage();
|
||||
}
|
||||
|
||||
|
@ -1372,7 +1385,7 @@ void History::addNewerSlice(const QVector<MTPMessage> &slice) {
|
|||
checkAddAllToUnreadMentions();
|
||||
}
|
||||
|
||||
checkJoinedMessage();
|
||||
checkLocalMessages();
|
||||
checkLastMessage();
|
||||
}
|
||||
|
||||
|
@ -2195,7 +2208,8 @@ void History::getReadyFor(MsgId msgId) {
|
|||
migrated->clear(ClearType::Unload);
|
||||
}
|
||||
}
|
||||
if (msgId == ShowAtTheEndMsgId) {
|
||||
if ((msgId == ShowAtTheEndMsgId)
|
||||
|| (msgId == ShowAtUnreadMsgId && !unreadCount())) {
|
||||
_loadedAtBottom = true;
|
||||
}
|
||||
}
|
||||
|
@ -2562,7 +2576,7 @@ void History::dialogEntryApplied() {
|
|||
if (const auto from = owner().userLoaded(inviter)) {
|
||||
clear(ClearType::Unload);
|
||||
addNewerSlice(QVector<MTPMessage>());
|
||||
insertJoinedMessage(true);
|
||||
insertJoinedMessage();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2578,7 +2592,7 @@ void History::dialogEntryApplied() {
|
|||
&& chatListTimeId() <= channel->inviteDate
|
||||
&& channel->amIn()) {
|
||||
if (const auto from = owner().userLoaded(inviter)) {
|
||||
insertJoinedMessage(true);
|
||||
insertJoinedMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2791,7 +2805,7 @@ MsgRange History::rangeForDifferenceRequest() const {
|
|||
return MsgRange();
|
||||
}
|
||||
|
||||
HistoryService *History::insertJoinedMessage(bool unread) {
|
||||
HistoryService *History::insertJoinedMessage() {
|
||||
if (!isChannel()
|
||||
|| _joinedMessage
|
||||
|| !peer->asChannel()->amIn()
|
||||
|
@ -2807,109 +2821,79 @@ HistoryService *History::insertJoinedMessage(bool unread) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
MTPDmessage::Flags flags = 0;
|
||||
if (inviter->id == session().userPeerId()) {
|
||||
unread = false;
|
||||
//} else if (unread) {
|
||||
// flags |= MTPDmessage::Flag::f_unread;
|
||||
if (peer->isMegagroup()
|
||||
&& peer->migrateFrom()
|
||||
&& !blocks.empty()
|
||||
&& blocks.front()->messages.front()->data()->id == 1) {
|
||||
peer->asChannel()->mgInfo->joinedMessageFound = true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto flags = MTPDmessage::Flags();
|
||||
const auto inviteDate = peer->asChannel()->inviteDate;
|
||||
_joinedMessage = GenerateJoinedMessage(this, inviteDate, inviter, flags);
|
||||
insertLocalMessage(_joinedMessage);
|
||||
return _joinedMessage;
|
||||
}
|
||||
|
||||
void History::insertLocalMessage(not_null<HistoryItem*> item) {
|
||||
Expects(item->mainView() == nullptr);
|
||||
|
||||
if (isEmpty()) {
|
||||
_joinedMessage = GenerateJoinedMessage(
|
||||
this,
|
||||
inviteDate,
|
||||
inviter,
|
||||
flags);
|
||||
addNewItem(_joinedMessage, unread);
|
||||
return _joinedMessage;
|
||||
addNewItem(item, false);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto itemDate = item->date();
|
||||
for (auto blockIndex = blocks.size(); blockIndex > 0;) {
|
||||
const auto &block = blocks[--blockIndex];
|
||||
for (auto itemIndex = block->messages.size(); itemIndex > 0;) {
|
||||
const auto item = block->messages[--itemIndex]->data();
|
||||
|
||||
// Due to a server bug sometimes inviteDate is less (before) than the
|
||||
// first message in the megagroup (message about migration), let us
|
||||
// ignore that and think, that the inviteDate is always greater-or-equal.
|
||||
if ((item->id == 1)
|
||||
&& peer->isMegagroup()
|
||||
&& peer->migrateFrom()) {
|
||||
peer->asChannel()->mgInfo->joinedMessageFound = true;
|
||||
return nullptr;
|
||||
}
|
||||
if (item->date() <= inviteDate) {
|
||||
if (block->messages[--itemIndex]->data()->date() <= itemDate) {
|
||||
++itemIndex;
|
||||
_joinedMessage = GenerateJoinedMessage(
|
||||
this,
|
||||
inviteDate,
|
||||
inviter,
|
||||
flags);
|
||||
addNewInTheMiddle(_joinedMessage, blockIndex, itemIndex);
|
||||
addNewInTheMiddle(item, blockIndex, itemIndex);
|
||||
const auto lastDate = chatListTimeId();
|
||||
if (!lastDate || inviteDate >= lastDate) {
|
||||
setLastMessage(_joinedMessage);
|
||||
if (unread) {
|
||||
newItemAdded(_joinedMessage);
|
||||
}
|
||||
if (!lastDate || itemDate >= lastDate) {
|
||||
setLastMessage(item);
|
||||
}
|
||||
return _joinedMessage;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startBuildingFrontBlock();
|
||||
_joinedMessage = GenerateJoinedMessage(
|
||||
this,
|
||||
inviteDate,
|
||||
inviter,
|
||||
flags);
|
||||
addItemToBlock(_joinedMessage);
|
||||
addItemToBlock(item);
|
||||
finishBuildingFrontBlock();
|
||||
|
||||
return _joinedMessage;
|
||||
}
|
||||
|
||||
void History::checkJoinedMessage(bool createUnread) {
|
||||
if (!isChannel() || _joinedMessage || peer->asChannel()->inviter <= 0) {
|
||||
void History::checkLocalMessages() {
|
||||
if (isEmpty() && (!loadedAtTop() || !loadedAtBottom())) {
|
||||
return;
|
||||
}
|
||||
if (isEmpty()) {
|
||||
if (loadedAtTop() && loadedAtBottom()) {
|
||||
if (insertJoinedMessage(createUnread)) {
|
||||
if (_joinedMessage->mainView()) {
|
||||
setLastMessage(_joinedMessage);
|
||||
}
|
||||
}
|
||||
return;
|
||||
const auto firstDate = loadedAtTop()
|
||||
? 0
|
||||
: blocks.front()->messages.front()->data()->date();
|
||||
const auto lastDate = loadedAtBottom()
|
||||
? std::numeric_limits<TimeId>::max()
|
||||
: blocks.back()->messages.back()->data()->date();
|
||||
const auto goodDate = [&](TimeId date) {
|
||||
return (date >= firstDate && date < lastDate);
|
||||
};
|
||||
for (const auto &item : _localMessages) {
|
||||
if (!item->mainView() && goodDate(item->date())) {
|
||||
insertLocalMessage(item);
|
||||
}
|
||||
}
|
||||
|
||||
const auto inviteDate = peer->asChannel()->inviteDate;
|
||||
auto firstDate = TimeId(0);
|
||||
auto lastDate = TimeId(0);
|
||||
if (!blocks.empty()) {
|
||||
firstDate = blocks.front()->messages.front()->data()->date();
|
||||
lastDate = blocks.back()->messages.back()->data()->date();
|
||||
}
|
||||
if (firstDate
|
||||
&& lastDate
|
||||
&& (firstDate <= inviteDate || loadedAtTop())
|
||||
&& (lastDate > inviteDate || loadedAtBottom())) {
|
||||
const auto willBeLastMsg = (inviteDate >= lastDate);
|
||||
if (insertJoinedMessage(createUnread && willBeLastMsg)
|
||||
&& willBeLastMsg) {
|
||||
if (_joinedMessage->mainView()) {
|
||||
setLastMessage(_joinedMessage);
|
||||
}
|
||||
}
|
||||
if (isChannel()
|
||||
&& !_joinedMessage
|
||||
&& (peer->asChannel()->inviter > 0)
|
||||
&& goodDate(peer->asChannel()->inviteDate)) {
|
||||
insertJoinedMessage();
|
||||
}
|
||||
}
|
||||
|
||||
void History::removeJoinedMessage() {
|
||||
if (_joinedMessage) {
|
||||
base::take(_joinedMessage)->destroy();
|
||||
_joinedMessage->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3025,7 +3009,7 @@ QVector<MsgId> History::collectMessagesFromUserToDelete(
|
|||
void History::clear(ClearType type) {
|
||||
_unreadBarView = nullptr;
|
||||
_firstUnreadView = nullptr;
|
||||
_joinedMessage = nullptr;
|
||||
removeJoinedMessage();
|
||||
|
||||
forgetScrollState();
|
||||
if (type == ClearType::Unload) {
|
||||
|
@ -3035,6 +3019,7 @@ void History::clear(ClearType type) {
|
|||
_loadedAtTop = _loadedAtBottom = false;
|
||||
} else {
|
||||
_notifications.clear();
|
||||
_localMessages.clear();
|
||||
owner().notifyHistoryCleared(this);
|
||||
if (unreadCountKnown()) {
|
||||
setUnreadCount(0);
|
||||
|
|
|
@ -70,8 +70,7 @@ public:
|
|||
not_null<History*> migrateToOrMe() const;
|
||||
History *migrateFrom() const;
|
||||
MsgRange rangeForDifferenceRequest() const;
|
||||
HistoryService *insertJoinedMessage(bool unread);
|
||||
void checkJoinedMessage(bool createUnread = false);
|
||||
void checkLocalMessages();
|
||||
void removeJoinedMessage();
|
||||
|
||||
bool isEmpty() const;
|
||||
|
@ -154,6 +153,9 @@ public:
|
|||
|
||||
void newItemAdded(not_null<HistoryItem*> item);
|
||||
|
||||
void registerLocalMessage(not_null<HistoryItem*> item);
|
||||
void unregisterLocalMessage(not_null<HistoryItem*> item);
|
||||
|
||||
MsgId readInbox();
|
||||
void applyInboxReadUpdate(
|
||||
FolderId folderId,
|
||||
|
@ -470,6 +472,9 @@ private:
|
|||
|
||||
void createLocalDraftFromCloud();
|
||||
|
||||
HistoryService *insertJoinedMessage();
|
||||
void insertLocalMessage(not_null<HistoryItem*> item);
|
||||
|
||||
void setFolderPointer(Data::Folder *folder);
|
||||
|
||||
Flags _flags = 0;
|
||||
|
@ -490,6 +495,7 @@ private:
|
|||
std::optional<int> _unreadMentionsCount;
|
||||
base::flat_set<MsgId> _unreadMentions;
|
||||
std::optional<HistoryItem*> _lastMessage;
|
||||
base::flat_set<not_null<HistoryItem*>> _localMessages;
|
||||
|
||||
// This almost always is equal to _lastMessage. The only difference is
|
||||
// for a group that migrated to a supergroup. Then _lastMessage can
|
||||
|
|
|
@ -172,6 +172,9 @@ HistoryItem::HistoryItem(
|
|||
, _from(from ? history->owner().user(from) : history->peer)
|
||||
, _flags(flags)
|
||||
, _date(date) {
|
||||
if (IsClientMsgId(id)) {
|
||||
_history->registerLocalMessage(this);
|
||||
}
|
||||
}
|
||||
|
||||
TimeId HistoryItem::date() const {
|
||||
|
@ -432,9 +435,14 @@ void HistoryItem::indexAsNewItem() {
|
|||
}
|
||||
|
||||
void HistoryItem::setRealId(MsgId newId) {
|
||||
Expects(!IsServerMsgId(id));
|
||||
Expects(_flags & MTPDmessage_ClientFlag::f_sending);
|
||||
Expects(IsClientMsgId(id));
|
||||
|
||||
const auto oldId = std::exchange(id, newId);
|
||||
_flags &= ~MTPDmessage_ClientFlag::f_sending;
|
||||
if (IsServerMsgId(id)) {
|
||||
_history->unregisterLocalMessage(this);
|
||||
}
|
||||
_history->owner().notifyItemIdChange({ this, oldId });
|
||||
|
||||
// We don't call Notify::replyMarkupUpdated(this) and update keyboard
|
||||
|
|
|
@ -223,7 +223,6 @@ void FastShareMessage(not_null<HistoryItem*> item) {
|
|||
MTP_vector<MTPint>(msgIds),
|
||||
MTP_vector<MTPlong>(generateRandom()),
|
||||
peer->input);
|
||||
auto callback = doneCallback;
|
||||
history->sendRequestId = MTP::send(
|
||||
request,
|
||||
rpcDone(base::duplicate(doneCallback)),
|
||||
|
@ -262,7 +261,7 @@ Fn<void(ChannelData*, MsgId)> HistoryDependentItemCallback(
|
|||
}
|
||||
|
||||
MTPDmessage::Flags NewMessageFlags(not_null<PeerData*> peer) {
|
||||
MTPDmessage::Flags result = 0;
|
||||
MTPDmessage::Flags result = MTPDmessage_ClientFlag::f_sending | 0;
|
||||
if (!peer->isSelf()) {
|
||||
result |= MTPDmessage::Flag::f_out;
|
||||
//if (p->isChat() || (p->isUser() && !p->asUser()->botInfo)) {
|
||||
|
|
|
@ -787,7 +787,7 @@ HistoryService::PreparedText GenerateJoinedText(
|
|||
return { tr::lng_action_you_joined(tr::now) };
|
||||
}
|
||||
|
||||
HistoryService *GenerateJoinedMessage(
|
||||
not_null<HistoryService*> GenerateJoinedMessage(
|
||||
not_null<History*> history,
|
||||
TimeId inviteDate,
|
||||
not_null<UserData*> inviter,
|
||||
|
|
|
@ -150,7 +150,7 @@ private:
|
|||
|
||||
};
|
||||
|
||||
HistoryService *GenerateJoinedMessage(
|
||||
not_null<HistoryService*> GenerateJoinedMessage(
|
||||
not_null<History*> history,
|
||||
TimeId inviteDate,
|
||||
not_null<UserData*> inviter,
|
||||
|
|
|
@ -4310,7 +4310,9 @@ void HistoryWidget::sendFileConfirmed(
|
|||
file->edit = isEditing;
|
||||
session().uploader().upload(newId, file);
|
||||
|
||||
const auto itemToEdit = isEditing ? session().data().message(newId) : nullptr;
|
||||
const auto itemToEdit = isEditing
|
||||
? session().data().message(newId)
|
||||
: nullptr;
|
||||
|
||||
const auto history = session().data().history(file->to.peer);
|
||||
const auto peer = history->peer;
|
||||
|
@ -4338,7 +4340,7 @@ void HistoryWidget::sendFileConfirmed(
|
|||
}
|
||||
}
|
||||
|
||||
auto flags = NewMessageFlags(peer)
|
||||
auto flags = (isEditing ? MTPDmessage::Flags() : NewMessageFlags(peer))
|
||||
| MTPDmessage::Flag::f_entities
|
||||
| MTPDmessage::Flag::f_media;
|
||||
if (file->to.replyTo) {
|
||||
|
@ -5547,8 +5549,8 @@ bool HistoryWidget::sendExistingPhoto(
|
|||
options.generateLocal = true;
|
||||
session().api().sendAction(options);
|
||||
|
||||
uint64 randomId = rand_value<uint64>();
|
||||
FullMsgId newId(_channel, clientMsgId());
|
||||
const auto randomId = rand_value<uint64>();
|
||||
const auto newId = FullMsgId(_channel, clientMsgId());
|
||||
|
||||
auto flags = NewMessageFlags(_peer) | MTPDmessage::Flag::f_media;
|
||||
auto sendFlags = MTPmessages_SendMedia::Flags(0);
|
||||
|
|
|
@ -41,36 +41,27 @@ enum class MTPDmessage_ClientFlag : uint32 {
|
|||
// message is a group / channel create or migrate service message
|
||||
f_is_group_essential = (1U << 29),
|
||||
|
||||
//// message needs initDimensions() + resize() + paint()
|
||||
//f_pending_init_dimensions = (1U << 28),
|
||||
|
||||
//// message needs resize() + paint()
|
||||
//f_pending_resize = (1U << 27),
|
||||
|
||||
//// message needs paint()
|
||||
//f_pending_paint = (1U << 26),
|
||||
|
||||
//// message is attached to previous one when displaying the history
|
||||
//f_attach_to_previous = (1U << 25),
|
||||
|
||||
// message's edited media is generated on the client
|
||||
// and should not update media from server
|
||||
f_is_local_update_media = (1U << 24),
|
||||
f_is_local_update_media = (1U << 28),
|
||||
|
||||
// message was sent from inline bot, need to re-set media when sent
|
||||
f_from_inline_bot = (1U << 23),
|
||||
f_from_inline_bot = (1U << 27),
|
||||
|
||||
// message has a switch inline keyboard button, need to return to inline
|
||||
f_has_switch_inline_button = (1U << 22),
|
||||
f_has_switch_inline_button = (1U << 26),
|
||||
|
||||
// message is generated on the client side and should be unread
|
||||
f_clientside_unread = (1U << 21),
|
||||
f_clientside_unread = (1U << 25),
|
||||
|
||||
// message has an admin badge in supergroup
|
||||
f_has_admin_badge = (1U << 20),
|
||||
f_has_admin_badge = (1U << 24),
|
||||
|
||||
// message is an outgoing message that is being sent
|
||||
f_sending = (1U << 23),
|
||||
|
||||
// update this when adding new client side flags
|
||||
MIN_FIELD = (1U << 20),
|
||||
MIN_FIELD = (1U << 23),
|
||||
};
|
||||
DEFINE_MTP_CLIENT_FLAGS(MTPDmessage)
|
||||
|
||||
|
|
Loading…
Reference in New Issue