Better chats list entries management.

Make unread counts and last message base::optional<>.
Remove ChannelHistory.
This commit is contained in:
John Preston 2018-01-31 20:10:29 +03:00
parent edcaccba1f
commit a7f67c4bc9
22 changed files with 1329 additions and 1146 deletions

View File

@ -1420,6 +1420,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_feed_group" = "Group in feed"; "lng_feed_group" = "Group in feed";
"lng_feed_ungroup" = "Ungroup from feed"; "lng_feed_ungroup" = "Ungroup from feed";
"lng_feed_channel_added" = "Channel added to your feed.";
"lng_feed_channel_removed" = "Channel removed from your feed.";
"lng_info_feed_title" = "Feed Info"; "lng_info_feed_title" = "Feed Info";

View File

@ -172,9 +172,10 @@ void ApiWrap::savePinnedOrder() {
void ApiWrap::toggleChannelGrouping( void ApiWrap::toggleChannelGrouping(
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
bool group) { bool group,
base::lambda<void()> callback) {
if (const auto already = _channelGroupingRequests.take(channel)) { if (const auto already = _channelGroupingRequests.take(channel)) {
request(*already).cancel(); request(already->first).cancel();
} }
const auto feedId = Data::Feed::kId; const auto feedId = Data::Feed::kId;
const auto flags = group const auto flags = group
@ -185,15 +186,18 @@ void ApiWrap::toggleChannelGrouping(
channel->inputChannel, channel->inputChannel,
MTP_int(feedId) MTP_int(feedId)
)).done([=](const MTPBool &result) { )).done([=](const MTPBool &result) {
_channelGroupingRequests.remove(channel);
if (group) { if (group) {
channel->setFeed(Auth().data().feed(feedId)); channel->setFeed(Auth().data().feed(feedId));
} else { } else {
channel->clearFeed(); channel->clearFeed();
} }
if (const auto data = _channelGroupingRequests.take(channel)) {
data->second();
}
}).fail([=](const RPCError &error) { }).fail([=](const RPCError &error) {
_channelGroupingRequests.remove(channel); _channelGroupingRequests.remove(channel);
}).send(); }).send();
_channelGroupingRequests.emplace(channel, requestId, callback);
} }
void ApiWrap::sendMessageFail(const RPCError &error) { void ApiWrap::sendMessageFail(const RPCError &error) {
@ -362,6 +366,124 @@ void ApiWrap::requestContacts() {
}).send(); }).send();
} }
void ApiWrap::requestDialogEntry(not_null<Data::Feed*> feed) {
if (_dialogFeedRequests.contains(feed)) {
return;
}
_dialogFeedRequests.emplace(feed);
auto peers = QVector<MTPInputDialogPeer>(
1,
MTP_inputDialogPeerFeed(MTP_int(feed->id())));
if (feed->channelsLoaded()) {
const auto &channels = feed->channels();
peers.reserve(channels.size() + 1);
for (const auto history : feed->channels()) {
peers.push_back(MTP_inputDialogPeer(history->peer->input));
}
} else {
request(MTPmessages_GetDialogs(
MTP_flags(MTPmessages_GetDialogs::Flag::f_feed_id),
MTP_int(feed->id()),
MTP_int(0), // offset_date
MTP_int(0), // offset_id
MTP_inputPeerEmpty(), // offset_peer
MTP_int(Data::Feed::kChannelsLimit)
)).done([=](const MTPmessages_Dialogs &result) {
// applyFeedChannels(result);
}).send();
}
request(MTPmessages_GetPeerDialogs(
MTP_vector(std::move(peers))
)).done([=](const MTPmessages_PeerDialogs &result) {
applyPeerDialogs(result);
_dialogFeedRequests.remove(feed);
}).fail([=](const RPCError &error) {
_dialogFeedRequests.remove(feed);
}).send();
}
void ApiWrap::requestDialogEntry(not_null<History*> history) {
if (_dialogRequests.contains(history)) {
return;
}
_dialogRequests.emplace(history);
auto peers = QVector<MTPInputDialogPeer>(
1,
MTP_inputDialogPeer(history->peer->input));
request(MTPmessages_GetPeerDialogs(
MTP_vector(std::move(peers))
)).done([=](const MTPmessages_PeerDialogs &result) {
applyPeerDialogs(result);
if (history->lastMessage()) {
if (!history->chatsListDate().isNull()
&& history->loadedAtBottom()) {
if (const auto channel = history->peer->asChannel()) {
const auto inviter = channel->inviter;
if (inviter != 0
&& history->chatsListDate() <= channel->inviteDate
&& channel->amIn()) {
if (const auto from = App::userLoaded(inviter)) {
history->insertJoinedMessage(true);
}
}
}
}
history->updateChatListExistence();
} else {
if (const auto chat = history->peer->asChat()) {
if (!chat->haveLeft()) {
Local::addSavedPeer(
history->peer,
history->chatsListDate());
}
} else if (const auto channel = history->peer->asChannel()) {
const auto inviter = channel->inviter;
if (inviter != 0 && channel->amIn()) {
if (const auto from = App::userLoaded(inviter)) {
history->unloadBlocks();
history->addNewerSlice(QVector<MTPMessage>());
history->insertJoinedMessage(
true);
}
}
} else {
App::main()->deleteConversation(history->peer, false);
}
}
_dialogRequests.remove(history);
}).fail([=](const RPCError &error) {
_dialogRequests.remove(history);
}).send();
}
void ApiWrap::applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs) {
Expects(dialogs.type() == mtpc_messages_peerDialogs);
const auto &data = dialogs.c_messages_peerDialogs();
App::feedUsers(data.vusers);
App::feedChats(data.vchats);
App::feedMsgs(data.vmessages, NewMessageLast);
for (const auto &dialog : data.vdialogs.v) {
switch (dialog.type()) {
case mtpc_dialog: {
const auto &fields = dialog.c_dialog();
if (const auto peerId = peerFromMTP(fields.vpeer)) {
App::history(peerId)->applyDialog(fields);
}
} break;
case mtpc_dialogFeed: {
const auto &fields = dialog.c_dialogFeed();
const auto feed = Auth().data().feed(fields.vfeed_id.v);
feed->applyDialog(fields);
} break;
}
}
_session->data().sendHistoryChangeNotifications();
}
void ApiWrap::requestFullPeer(PeerData *peer) { void ApiWrap::requestFullPeer(PeerData *peer) {
if (!peer || _fullPeerRequests.contains(peer)) return; if (!peer || _fullPeerRequests.contains(peer)) return;
@ -464,7 +586,7 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt
if (auto h = App::historyLoaded(cfrom->id)) { if (auto h = App::historyLoaded(cfrom->id)) {
if (auto hto = App::historyLoaded(channel->id)) { if (auto hto = App::historyLoaded(channel->id)) {
if (!h->isEmpty()) { if (!h->isEmpty()) {
h->clear(true); h->unloadBlocks();
} }
if (hto->inChatList(Dialogs::Mode::All) && h->inChatList(Dialogs::Mode::All)) { if (hto->inChatList(Dialogs::Mode::All) && h->inChatList(Dialogs::Mode::All)) {
App::main()->removeDialog(h); App::main()->removeDialog(h);
@ -495,14 +617,12 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt
channel->setRestrictedCount(f.has_banned_count() ? f.vbanned_count.v : 0); channel->setRestrictedCount(f.has_banned_count() ? f.vbanned_count.v : 0);
channel->setKickedCount(f.has_kicked_count() ? f.vkicked_count.v : 0); channel->setKickedCount(f.has_kicked_count() ? f.vkicked_count.v : 0);
channel->setInviteLink((f.vexported_invite.type() == mtpc_chatInviteExported) ? qs(f.vexported_invite.c_chatInviteExported().vlink) : QString()); channel->setInviteLink((f.vexported_invite.type() == mtpc_chatInviteExported) ? qs(f.vexported_invite.c_chatInviteExported().vlink) : QString());
if (auto h = App::historyLoaded(channel->id)) { if (const auto history = App::historyLoaded(channel->id)) {
if (h->inboxReadBefore < f.vread_inbox_max_id.v + 1) { history->applyDialogFields(
h->setUnreadCount(f.vunread_count.v); f.vunread_count.v,
h->inboxReadBefore = f.vread_inbox_max_id.v + 1; f.vread_inbox_max_id.v,
} f.vread_outbox_max_id.v);
accumulate_max(h->outboxReadBefore, f.vread_outbox_max_id.v + 1);
} }
ranges::overload([] {}, [](int a) {});
if (f.has_pinned_msg_id()) { if (f.has_pinned_msg_id()) {
channel->setPinnedMessageId(f.vpinned_msg_id.v); channel->setPinnedMessageId(f.vpinned_msg_id.v);
} else { } else {
@ -1063,7 +1183,9 @@ void ApiWrap::unblockParticipant(
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
not_null<UserData*> user) { not_null<UserData*> user) {
const auto kick = KickRequest(channel, user); const auto kick = KickRequest(channel, user);
if (_kickRequests.contains(kick)) return; if (_kickRequests.contains(kick)) {
return;
}
const auto requestId = request(MTPchannels_EditBanned( const auto requestId = request(MTPchannels_EditBanned(
channel->inputChannel, channel->inputChannel,
@ -1085,6 +1207,43 @@ void ApiWrap::unblockParticipant(
_kickRequests.emplace(kick, requestId); _kickRequests.emplace(kick, requestId);
} }
void ApiWrap::deleteAllFromUser(
not_null<ChannelData*> channel,
not_null<UserData*> from) {
const auto history = App::historyLoaded(channel->id);
const auto ids = history
? history->collectMessagesFromUserToDelete(from)
: QVector<MsgId>();
const auto channelId = peerToChannel(channel->id);
for (const auto msgId : ids) {
if (const auto item = App::histItemById(channelId, msgId)) {
item->destroy();
}
}
Auth().data().sendHistoryChangeNotifications();
deleteAllFromUserSend(channel, from);
}
void ApiWrap::deleteAllFromUserSend(
not_null<ChannelData*> channel,
not_null<UserData*> from) {
request(MTPchannels_DeleteUserHistory(
channel->inputChannel,
from->inputUser
)).done([=](const MTPmessages_AffectedHistory &result) {
const auto offset = applyAffectedHistory(channel, result);
if (offset > 0) {
deleteAllFromUserSend(channel, from);
} else if (const auto history = App::historyLoaded(channel)) {
if (!history->lastMessageKnown()) {
Auth().api().requestDialogEntry(history);
}
}
}).send();
}
void ApiWrap::requestChannelMembersForAdd( void ApiWrap::requestChannelMembersForAdd(
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
base::lambda<void(const MTPchannels_ChannelParticipants&)> callback) { base::lambda<void(const MTPchannels_ChannelParticipants&)> callback) {
@ -1505,23 +1664,23 @@ int ApiWrap::onlineTillFromStatus(const MTPUserStatus &status, int currentOnline
} }
void ApiWrap::clearHistory(not_null<PeerData*> peer) { void ApiWrap::clearHistory(not_null<PeerData*> peer) {
auto lastMsgId = MsgId(0); auto deleteTillId = MsgId(0);
if (auto history = App::historyLoaded(peer->id)) { if (auto history = App::historyLoaded(peer->id)) {
if (history->lastMsg) { if (const auto last = history->lastMessage()) {
lastMsgId = history->lastMsg->id; deleteTillId = last->id;
Local::addSavedPeer(history->peer, history->lastMsg->date); Local::addSavedPeer(history->peer, last->date);
} }
history->clear(); history->clear();
history->newLoaded = history->oldLoaded = true; history->newLoaded = history->oldLoaded = true;
} }
if (auto channel = peer->asChannel()) { if (const auto channel = peer->asChannel()) {
if (auto migrated = peer->migrateFrom()) { if (const auto migrated = peer->migrateFrom()) {
clearHistory(migrated); clearHistory(migrated);
} }
if (IsServerMsgId(lastMsgId)) { if (IsServerMsgId(deleteTillId)) {
request(MTPchannels_DeleteHistory( request(MTPchannels_DeleteHistory(
channel->inputChannel, channel->inputChannel,
MTP_int(lastMsgId) MTP_int(deleteTillId)
)).send(); )).send();
} }
} else { } else {
@ -1530,7 +1689,7 @@ void ApiWrap::clearHistory(not_null<PeerData*> peer) {
peer->input, peer->input,
MTP_int(0) MTP_int(0)
)).done([=](const MTPmessages_AffectedHistory &result) { )).done([=](const MTPmessages_AffectedHistory &result) {
auto offset = applyAffectedHistory(peer, result); const auto offset = applyAffectedHistory(peer, result);
if (offset > 0) { if (offset > 0) {
clearHistory(peer); clearHistory(peer);
} }
@ -1775,6 +1934,94 @@ void ApiWrap::requestParticipantsCountDelayed(
[this, channel] { channel->updateFullForced(); }); [this, channel] { channel->updateFullForced(); });
} }
void ApiWrap::requestChannelRangeDifference(not_null<History*> history) {
Expects(history->isChannel());
const auto channel = history->peer->asChannel();
if (const auto requestId = _rangeDifferenceRequests.take(channel)) {
request(*requestId).cancel();
}
const auto range = history->rangeForDifferenceRequest();
if (!(range.from < range.till) || !channel->pts()) {
return;
}
MTP_LOG(0, ("getChannelDifference { good - "
"after channelDifferenceTooLong was received, "
"validating history part }%1").arg(cTestMode() ? " TESTMODE" : ""));
channelRangeDifferenceSend(channel, range, channel->pts());
}
void ApiWrap::channelRangeDifferenceSend(
not_null<ChannelData*> channel,
MsgRange range,
int32 pts) {
Expects(range.from < range.till);
const auto limit = range.till - range.from;
const auto filter = MTP_channelMessagesFilter(
MTP_flags(0),
MTP_vector<MTPMessageRange>(1, MTP_messageRange(
MTP_int(range.from),
MTP_int(range.till - 1))));
const auto requestId = request(MTPupdates_GetChannelDifference(
MTP_flags(MTPupdates_GetChannelDifference::Flag::f_force),
channel->inputChannel,
filter,
MTP_int(pts),
MTP_int(limit)
)).done([=](const MTPupdates_ChannelDifference &result) {
_rangeDifferenceRequests.remove(channel);
channelRangeDifferenceDone(channel, range, result);
}).fail([=](const RPCError &error) {
_rangeDifferenceRequests.remove(channel);
}).send();
_rangeDifferenceRequests.emplace(channel, requestId);
}
void ApiWrap::channelRangeDifferenceDone(
not_null<ChannelData*> channel,
MsgRange range,
const MTPupdates_ChannelDifference &result) {
auto nextRequestPts = int32(0);
auto isFinal = true;
switch (result.type()) {
case mtpc_updates_channelDifferenceEmpty: {
const auto &d = result.c_updates_channelDifferenceEmpty();
nextRequestPts = d.vpts.v;
isFinal = d.is_final();
} break;
case mtpc_updates_channelDifferenceTooLong: {
const auto &d = result.c_updates_channelDifferenceTooLong();
App::feedUsers(d.vusers);
App::feedChats(d.vchats);
nextRequestPts = d.vpts.v;
isFinal = d.is_final();
} break;
case mtpc_updates_channelDifference: {
const auto &d = result.c_updates_channelDifference();
App::main()->feedChannelDifference(d);
nextRequestPts = d.vpts.v;
isFinal = d.is_final();
} break;
}
if (!isFinal) {
MTP_LOG(0, ("getChannelDifference { "
"good - after not final channelDifference was received, "
"validating history part }%1"
).arg(cTestMode() ? " TESTMODE" : ""));
channelRangeDifferenceSend(channel, range, nextRequestPts);
}
}
void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId req) { void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId req) {
const QVector<MTPMessage> *v = 0; const QVector<MTPMessage> *v = 0;
switch (msgs.type()) { switch (msgs.type()) {
@ -3438,7 +3685,11 @@ void ApiWrap::readServerHistory(not_null<History*> history) {
void ApiWrap::readServerHistoryForce(not_null<History*> history) { void ApiWrap::readServerHistoryForce(not_null<History*> history) {
const auto peer = history->peer; const auto peer = history->peer;
const auto upTo = history->inboxRead(0); const auto upTo = history->readInbox();
if (!upTo) {
return;
}
if (const auto channel = peer->asChannel()) { if (const auto channel = peer->asChannel()) {
if (!channel->amIn()) { if (!channel->amIn()) {
return; // no read request for channels that I didn't join return; // no read request for channels that I didn't join

View File

@ -56,7 +56,10 @@ public:
void applyUpdates(const MTPUpdates &updates, uint64 sentMessageRandomId = 0); void applyUpdates(const MTPUpdates &updates, uint64 sentMessageRandomId = 0);
void savePinnedOrder(); void savePinnedOrder();
void toggleChannelGrouping(not_null<ChannelData*> channel, bool group); void toggleChannelGrouping(
not_null<ChannelData*> channel,
bool group,
base::lambda<void()> callback);
using RequestMessageDataCallback = base::lambda<void(ChannelData*, MsgId)>; using RequestMessageDataCallback = base::lambda<void(ChannelData*, MsgId)>;
void requestMessageData( void requestMessageData(
@ -65,6 +68,8 @@ public:
RequestMessageDataCallback callback); RequestMessageDataCallback callback);
void requestContacts(); void requestContacts();
void requestDialogEntry(not_null<Data::Feed*> feed);
void requestDialogEntry(not_null<History*> history);
void requestFullPeer(PeerData *peer); void requestFullPeer(PeerData *peer);
void requestPeer(PeerData *peer); void requestPeer(PeerData *peer);
@ -73,6 +78,7 @@ public:
void requestBots(not_null<ChannelData*> channel); void requestBots(not_null<ChannelData*> channel);
void requestAdmins(not_null<ChannelData*> channel); void requestAdmins(not_null<ChannelData*> channel);
void requestParticipantsCountDelayed(not_null<ChannelData*> channel); void requestParticipantsCountDelayed(not_null<ChannelData*> channel);
void requestChannelRangeDifference(not_null<History*> history);
void requestChangelog( void requestChangelog(
const QString &sinceVersion, const QString &sinceVersion,
@ -96,6 +102,9 @@ public:
void unblockParticipant( void unblockParticipant(
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
not_null<UserData*> user); not_null<UserData*> user);
void deleteAllFromUser(
not_null<ChannelData*> channel,
not_null<UserData*> from);
void requestWebPageDelayed(WebPageData *page); void requestWebPageDelayed(WebPageData *page);
void clearWebPageRequest(WebPageData *page); void clearWebPageRequest(WebPageData *page);
@ -269,6 +278,7 @@ private:
QVector<MTPint> collectMessageIds(const MessageDataRequests &requests); QVector<MTPint> collectMessageIds(const MessageDataRequests &requests);
MessageDataRequests *messageDataRequests(ChannelData *channel, bool onlyExisting = false); MessageDataRequests *messageDataRequests(ChannelData *channel, bool onlyExisting = false);
void applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs);
void gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mtpRequestId req); void gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mtpRequestId req);
void gotUserFull(UserData *user, const MTPUserFull &result, mtpRequestId req); void gotUserFull(UserData *user, const MTPUserFull &result, mtpRequestId req);
@ -285,10 +295,24 @@ private:
int availableCount, int availableCount,
const QVector<MTPChannelParticipant> &list); const QVector<MTPChannelParticipant> &list);
void resolveWebPages(); void resolveWebPages();
void gotWebPages(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req); void gotWebPages(
ChannelData *channel,
const MTPmessages_Messages &result,
mtpRequestId req);
void gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result); void gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result);
PeerData *notifySettingReceived(MTPInputNotifyPeer peer, const MTPPeerNotifySettings &settings); void channelRangeDifferenceSend(
not_null<ChannelData*> channel,
MsgRange range,
int32 pts);
void channelRangeDifferenceDone(
not_null<ChannelData*> channel,
MsgRange range,
const MTPupdates_ChannelDifference &result);
PeerData *notifySettingReceived(
MTPInputNotifyPeer peer,
const MTPPeerNotifySettings &settings);
void stickerSetDisenabled(mtpRequestId requestId); void stickerSetDisenabled(mtpRequestId requestId);
void stickersSaveOrder(); void stickersSaveOrder();
@ -347,6 +371,11 @@ private:
void applyAffectedMessages( void applyAffectedMessages(
not_null<PeerData*> peer, not_null<PeerData*> peer,
const MTPmessages_AffectedMessages &result); const MTPmessages_AffectedMessages &result);
void deleteAllFromUserSend(
not_null<ChannelData*> channel,
not_null<UserData*> from);
void sendMessageFail(const RPCError &error); void sendMessageFail(const RPCError &error);
void uploadAlbumMedia( void uploadAlbumMedia(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
@ -391,7 +420,7 @@ private:
const MTPchannels_ChannelParticipants&)> _channelMembersForAddCallback; const MTPchannels_ChannelParticipants&)> _channelMembersForAddCallback;
base::flat_map< base::flat_map<
not_null<ChannelData*>, not_null<ChannelData*>,
mtpRequestId> _channelGroupingRequests; std::pair<mtpRequestId,base::lambda<void()>>> _channelGroupingRequests;
using KickRequest = std::pair< using KickRequest = std::pair<
not_null<ChannelData*>, not_null<ChannelData*>,
@ -400,6 +429,10 @@ private:
QMap<ChannelData*, mtpRequestId> _selfParticipantRequests; QMap<ChannelData*, mtpRequestId> _selfParticipantRequests;
base::flat_map<
not_null<ChannelData*>,
mtpRequestId> _rangeDifferenceRequests;
QMap<WebPageData*, mtpRequestId> _webPagesPending; QMap<WebPageData*, mtpRequestId> _webPagesPending;
base::Timer _webPagesTimer; base::Timer _webPagesTimer;
@ -432,6 +465,8 @@ private:
mtpRequestId _contactsRequestId = 0; mtpRequestId _contactsRequestId = 0;
mtpRequestId _contactsStatusesRequestId = 0; mtpRequestId _contactsStatusesRequestId = 0;
base::flat_set<not_null<Data::Feed*>> _dialogFeedRequests;
base::flat_set<not_null<History*>> _dialogRequests;
base::flat_map<not_null<History*>, mtpRequestId> _unreadMentionsRequests; base::flat_map<not_null<History*>, mtpRequestId> _unreadMentionsRequests;

View File

@ -459,7 +459,7 @@ namespace {
if (auto h = App::historyLoaded(cdata->id)) { if (auto h = App::historyLoaded(cdata->id)) {
if (auto hto = App::historyLoaded(channel->id)) { if (auto hto = App::historyLoaded(channel->id)) {
if (!h->isEmpty()) { if (!h->isEmpty()) {
h->clear(true); h->unloadBlocks();
} }
if (hto->inChatList(Dialogs::Mode::All) && h->inChatList(Dialogs::Mode::All)) { if (hto->inChatList(Dialogs::Mode::All) && h->inChatList(Dialogs::Mode::All)) {
App::main()->removeDialog(h); App::main()->removeDialog(h);
@ -1019,7 +1019,7 @@ namespace {
} }
void feedInboxRead(const PeerId &peer, MsgId upTo) { void feedInboxRead(const PeerId &peer, MsgId upTo) {
if (auto history = App::historyLoaded(peer)) { if (const auto history = App::historyLoaded(peer)) {
history->inboxRead(upTo); history->inboxRead(upTo);
} }
} }
@ -1027,17 +1027,8 @@ namespace {
void feedOutboxRead(const PeerId &peer, MsgId upTo, TimeId when) { void feedOutboxRead(const PeerId &peer, MsgId upTo, TimeId when) {
if (auto history = App::historyLoaded(peer)) { if (auto history = App::historyLoaded(peer)) {
history->outboxRead(upTo); history->outboxRead(upTo);
if (history->lastMsg if (const auto user = history->peer->asUser()) {
&& history->lastMsg->out() user->madeAction(when);
&& history->lastMsg->id <= upTo) {
if (const auto main = App::main()) {
main->repaintDialogRow(history, history->lastMsg->id);
}
}
history->updateChatListEntry();
if (history->peer->isUser()) {
history->peer->asUser()->madeAction(when);
} }
} }
} }
@ -1055,37 +1046,31 @@ namespace {
return &(*i); return &(*i);
} }
void feedWereDeleted(ChannelId channelId, const QVector<MTPint> &msgsIds) { void feedWereDeleted(
ChannelId channelId,
const QVector<MTPint> &msgsIds) {
const auto data = fetchMsgsData(channelId, false); const auto data = fetchMsgsData(channelId, false);
if (!data) return; if (!data) return;
const auto channelHistory = (channelId != NoChannel) const auto affectedHistory = (channelId != NoChannel)
? App::history(peerFromChannel(channelId))->asChannelHistory() ? App::history(peerFromChannel(channelId)).get()
: nullptr; : nullptr;
base::flat_set<not_null<History*>> historiesToCheck; auto historiesToCheck = base::flat_set<not_null<History*>>();
for (const auto msgId : msgsIds) { for (const auto msgId : msgsIds) {
auto j = data->constFind(msgId.v); auto j = data->constFind(msgId.v);
if (j != data->cend()) { if (j != data->cend()) {
const auto h = (*j)->history(); const auto history = (*j)->history();
(*j)->destroy(); (*j)->destroy();
if (!h->lastMsg) { if (!history->lastMessageKnown()) {
historiesToCheck.emplace(h); historiesToCheck.emplace(history);
}
} else {
if (channelHistory) {
if (channelHistory->unreadCount() > 0
&& msgId.v >= channelHistory->inboxReadBefore) {
channelHistory->setUnreadCount(
channelHistory->unreadCount() - 1);
}
} }
} else if (affectedHistory) {
affectedHistory->unknownMessageDeleted(msgId.v);
} }
} }
if (main()) { for (const auto history : historiesToCheck) {
for (const auto history : historiesToCheck) { Auth().api().requestDialogEntry(history);
main()->checkPeerHistory(history->peer);
}
} }
} }
@ -1222,10 +1207,6 @@ namespace {
return ::histories.findOrInsert(peer); return ::histories.findOrInsert(peer);
} }
not_null<History*> historyFromDialog(const PeerId &peer, int32 unreadCnt, int32 maxInboxRead, int32 maxOutboxRead) {
return ::histories.findOrInsert(peer, unreadCnt, maxInboxRead, maxOutboxRead);
}
History *historyLoaded(const PeerId &peer) { History *historyLoaded(const PeerId &peer) {
if (!peer) { if (!peer) {
return nullptr; return nullptr;

View File

@ -148,7 +148,6 @@ namespace App {
Histories &histories(); Histories &histories();
not_null<History*> history(const PeerId &peer); not_null<History*> history(const PeerId &peer);
not_null<History*> historyFromDialog(const PeerId &peer, int32 unreadCnt, int32 maxInboxRead, int32 maxOutboxRead);
History *historyLoaded(const PeerId &peer); History *historyLoaded(const PeerId &peer);
HistoryItem *histItemById(ChannelId channelId, MsgId itemId); HistoryItem *histItemById(ChannelId channelId, MsgId itemId);
inline not_null<History*> history(const PeerData *peer) { inline not_null<History*> history(const PeerData *peer) {

View File

@ -568,7 +568,7 @@ void DeleteMessagesBox::deleteAndClear() {
MTP_vector<MTPint>(1, MTP_int(_ids[0].msg)))); MTP_vector<MTPint>(1, MTP_int(_ids[0].msg))));
} }
if (_deleteAll && _deleteAll->checked()) { if (_deleteAll && _deleteAll->checked()) {
App::main()->deleteAllFromUser( Auth().api().deleteAllFromUser(
_moderateInChannel, _moderateInChannel,
_moderateFrom); _moderateFrom);
} }
@ -583,13 +583,13 @@ void DeleteMessagesBox::deleteAndClear() {
if (auto item = App::histItemById(itemId)) { if (auto item = App::histItemById(itemId)) {
auto history = item->history(); auto history = item->history();
auto wasOnServer = (item->id > 0); auto wasOnServer = (item->id > 0);
auto wasLast = (history->lastMsg == item); auto wasLast = (history->lastMessage() == item);
item->destroy(); item->destroy();
if (wasOnServer) { if (wasOnServer) {
idsByPeer[history->peer].push_back(MTP_int(itemId.msg)); idsByPeer[history->peer].push_back(MTP_int(itemId.msg));
} else if (wasLast) { } else if (wasLast) {
App::main()->checkPeerHistory(history->peer); Auth().api().requestDialogEntry(history);
} }
} }
} }

View File

@ -372,6 +372,7 @@ std::unique_ptr<PeerListRow> ContactsBoxController::createSearchRow(not_null<Pee
} }
void ContactsBoxController::rowClicked(not_null<PeerListRow*> row) { void ContactsBoxController::rowClicked(not_null<PeerListRow*> row) {
Auth().api().requestDialogEntry(App::history(row->peer()));
Ui::showPeerHistory(row->peer(), ShowAtUnreadMsgId); Ui::showPeerHistory(row->peer(), ShowAtUnreadMsgId);
} }

View File

@ -72,8 +72,10 @@ void Feed::registerOne(not_null<ChannelData*> channel) {
if (!base::contains(_channels, history)) { if (!base::contains(_channels, history)) {
const auto invisible = (_channels.size() < 2); const auto invisible = (_channels.size() < 2);
_channels.push_back(history); _channels.push_back(history);
if (history->lastMsg) { if (history->lastMessageKnown()) {
updateLastMessage(history->lastMsg); recountLastMessage();
} else if (_channelsLoaded) {
_parent->session().api().requestDialogEntry(history);
} }
_parent->session().storage().remove( _parent->session().storage().remove(
Storage::FeedMessagesInvalidate(_id)); Storage::FeedMessagesInvalidate(_id));
@ -96,8 +98,10 @@ void Feed::unregisterOne(not_null<ChannelData*> channel) {
if (i != end(_channels)) { if (i != end(_channels)) {
const auto visible = (_channels.size() > 1); const auto visible = (_channels.size() > 1);
_channels.erase(i, end(_channels)); _channels.erase(i, end(_channels));
if (_lastMessage && _lastMessage->history() == history) { if (const auto last = lastMessage()) {
messageRemoved(_lastMessage); if (last->history() == history) {
recountLastMessage();
}
} }
_parent->session().storage().remove( _parent->session().storage().remove(
Storage::FeedMessagesRemoveAll(_id, channel->bareId())); Storage::FeedMessagesRemoveAll(_id, channel->bareId()));
@ -115,8 +119,10 @@ void Feed::unregisterOne(not_null<ChannelData*> channel) {
} }
void Feed::updateLastMessage(not_null<HistoryItem*> item) { void Feed::updateLastMessage(not_null<HistoryItem*> item) {
if (justSetLastMessage(item)) { if (justUpdateLastMessage(item)) {
setChatsListDate(_lastMessage->date); if (_lastMessage && *_lastMessage) {
setChatsListDate((*_lastMessage)->date);
}
} }
} }
@ -207,8 +213,11 @@ void Feed::setChannels(std::vector<not_null<ChannelData*>> channels) {
_parent->notifyFeedUpdated(this, FeedUpdateFlag::Channels); _parent->notifyFeedUpdated(this, FeedUpdateFlag::Channels);
} }
bool Feed::justSetLastMessage(not_null<HistoryItem*> item) { bool Feed::justUpdateLastMessage(not_null<HistoryItem*> item) {
if (_lastMessage && item->position() <= _lastMessage->position()) { if (!_lastMessage) {
return false;
} else if (*_lastMessage
&& item->position() <= (*_lastMessage)->position()) {
return false; return false;
} }
_lastMessage = item; _lastMessage = item;
@ -216,36 +225,106 @@ bool Feed::justSetLastMessage(not_null<HistoryItem*> item) {
} }
void Feed::messageRemoved(not_null<HistoryItem*> item) { void Feed::messageRemoved(not_null<HistoryItem*> item) {
if (_lastMessage == item) { if (lastMessage() == item) {
_lastMessage = base::none;
recountLastMessage(); recountLastMessage();
} }
} }
void Feed::historyCleared(not_null<History*> history) { void Feed::historyCleared(not_null<History*> history) {
if (_lastMessage->history() == history) { if (const auto last = lastMessage()) {
recountLastMessage(); if (last->history() == history) {
messageRemoved(last);
}
} }
} }
void Feed::recountLastMessage() { void Feed::recountLastMessage() {
_lastMessage = nullptr;
for (const auto history : _channels) { for (const auto history : _channels) {
if (const auto last = history->lastMsg) { if (!history->lastMessageKnown()) {
justSetLastMessage(last); return;
} }
} }
if (_lastMessage) { _lastMessage = nullptr;
setChatsListDate(_lastMessage->date); for (const auto history : _channels) {
if (const auto last = history->lastMessage()) {
justUpdateLastMessage(last);
}
}
updateChatsListDate();
}
void Feed::updateChatsListDate() {
if (_lastMessage && *_lastMessage) {
setChatsListDate((*_lastMessage)->date);
} }
} }
void Feed::setUnreadCounts(int unreadCount, int unreadMutedCount) { HistoryItem *Feed::lastMessage() const {
_unreadCount = unreadCount; return _lastMessage ? *_lastMessage : nullptr;
}
bool Feed::lastMessageKnown() const {
return !!_lastMessage;
}
void Feed::applyDialog(const MTPDdialogFeed &data) {
const auto addChannel = [&](ChannelId channelId) {
if (const auto channel = App::channelLoaded(channelId)) {
channel->setFeed(this);
}
};
for (const auto &channelId : data.vfeed_other_channels.v) {
addChannel(channelId.v);
}
_lastMessage = nullptr;
if (const auto peerId = peerFromMTP(data.vpeer)) {
if (const auto channelId = peerToChannel(peerId)) {
addChannel(channelId);
const auto fullId = FullMsgId(channelId, data.vtop_message.v);
if (const auto item = App::histItemById(fullId)) {
justUpdateLastMessage(item);
}
}
}
updateChatsListDate();
setUnreadCounts(
data.vunread_count.v,
data.vunread_muted_count.v);
if (data.has_read_max_position()) {
setUnreadPosition(FeedPositionFromMTP(data.vread_max_position));
}
}
void Feed::setUnreadCounts(int unreadNonMutedCount, int unreadMutedCount) {
_unreadCount = unreadNonMutedCount + unreadMutedCount;
_unreadMutedCount = unreadMutedCount; _unreadMutedCount = unreadMutedCount;
} }
void Feed::setUnreadPosition(const MessagePosition &position) { void Feed::setUnreadPosition(const MessagePosition &position) {
_unreadPosition = position; if (_unreadPosition.current() < position) {
_unreadPosition = position;
}
}
void Feed::unreadCountChanged(
base::optional<int> unreadCountDelta,
int mutedCountDelta) {
if (!_unreadCount) {
return;
}
if (unreadCountDelta) {
*_unreadCount = std::max(*_unreadCount + *unreadCountDelta, 0);
_unreadMutedCount = snap(
_unreadMutedCount + mutedCountDelta,
0,
*_unreadCount);
updateChatListEntry();
} else {
_parent->session().api().requestDialogEntry(this);
}
} }
MessagePosition Feed::unreadPosition() const { MessagePosition Feed::unreadPosition() const {
@ -265,15 +344,15 @@ bool Feed::shouldBeInChatList() const {
} }
int Feed::chatListUnreadCount() const { int Feed::chatListUnreadCount() const {
return _unreadCount; return _unreadCount ? *_unreadCount : 0;
} }
bool Feed::chatListMutedBadge() const { bool Feed::chatListMutedBadge() const {
return _unreadCount <= _unreadMutedCount; return _unreadCount ? (*_unreadCount <= _unreadMutedCount) : false;
} }
HistoryItem *Feed::chatsListItem() const { HistoryItem *Feed::chatsListItem() const {
return _lastMessage; return lastMessage();
} }
const QString &Feed::chatsListName() const { const QString &Feed::chatsListName() const {

View File

@ -32,6 +32,7 @@ MessagePosition FeedPositionFromMTP(const MTPFeedPosition &position);
class Feed : public Dialogs::Entry { class Feed : public Dialogs::Entry {
public: public:
static constexpr auto kId = 1; static constexpr auto kId = 1;
static constexpr auto kChannelsLimit = 1000;
Feed(FeedId id, not_null<Data::Session*> parent); Feed(FeedId id, not_null<Data::Session*> parent);
@ -43,11 +44,18 @@ public:
void messageRemoved(not_null<HistoryItem*> item); void messageRemoved(not_null<HistoryItem*> item);
void historyCleared(not_null<History*> history); void historyCleared(not_null<History*> history);
void setUnreadCounts(int unreadCount, int unreadMutedCount); void applyDialog(const MTPDdialogFeed &data);
void setUnreadCounts(int unreadNonMutedCount, int unreadMutedCount);
void setUnreadPosition(const MessagePosition &position); void setUnreadPosition(const MessagePosition &position);
void unreadCountChanged(
base::optional<int> unreadCountDelta,
int mutedCountDelta);
MessagePosition unreadPosition() const; MessagePosition unreadPosition() const;
rpl::producer<MessagePosition> unreadPositionChanges() const; rpl::producer<MessagePosition> unreadPositionChanges() const;
HistoryItem *lastMessage() const;
bool lastMessageKnown() const;
bool toImportant() const override; bool toImportant() const override;
bool shouldBeInChatList() const override; bool shouldBeInChatList() const override;
int chatListUnreadCount() const override; int chatListUnreadCount() const override;
@ -73,7 +81,8 @@ public:
private: private:
void indexNameParts(); void indexNameParts();
void recountLastMessage(); void recountLastMessage();
bool justSetLastMessage(not_null<HistoryItem*> item); bool justUpdateLastMessage(not_null<HistoryItem*> item);
void updateChatsListDate();
FeedId _id = 0; FeedId _id = 0;
not_null<Data::Session*> _parent; not_null<Data::Session*> _parent;
@ -83,10 +92,10 @@ private:
QString _name; QString _name;
base::flat_set<QString> _nameWords; base::flat_set<QString> _nameWords;
base::flat_set<QChar> _nameFirstLetters; base::flat_set<QChar> _nameFirstLetters;
HistoryItem *_lastMessage = nullptr; base::optional<HistoryItem*> _lastMessage;
rpl::variable<MessagePosition> _unreadPosition; rpl::variable<MessagePosition> _unreadPosition;
int _unreadCount = 0; base::optional<int> _unreadCount;
int _unreadMutedCount = 0; int _unreadMutedCount = 0;
}; };

View File

@ -849,13 +849,22 @@ void ChannelData::setAvailableMinId(MsgId availableMinId) {
if (auto history = App::historyLoaded(this)) { if (auto history = App::historyLoaded(this)) {
history->clearUpTill(availableMinId); history->clearUpTill(availableMinId);
} }
if (_pinnedMessageId <= _availableMinId) {
_pinnedMessageId = MsgId(0);
Notify::peerUpdatedDelayed(
this,
Notify::PeerUpdate::Flag::ChannelPinnedChanged);
}
} }
} }
void ChannelData::setPinnedMessageId(MsgId messageId) { void ChannelData::setPinnedMessageId(MsgId messageId) {
messageId = (messageId > _availableMinId) ? messageId : MsgId(0);
if (_pinnedMessageId != messageId) { if (_pinnedMessageId != messageId) {
_pinnedMessageId = messageId; _pinnedMessageId = messageId;
Notify::peerUpdatedDelayed(this, Notify::PeerUpdate::Flag::ChannelPinnedChanged); Notify::peerUpdatedDelayed(
this,
Notify::PeerUpdate::Flag::ChannelPinnedChanged);
} }
} }

View File

@ -1726,76 +1726,32 @@ void DialogsInner::applyDialog(const MTPDdialog &dialog) {
return; return;
} }
const auto history = App::historyFromDialog( const auto history = App::history(peerId);
peerId, history->applyDialog(dialog);
dialog.vunread_count.v,
dialog.vread_inbox_max_id.v,
dialog.vread_outbox_max_id.v);
history->setUnreadMentionsCount(dialog.vunread_mentions_count.v);
const auto peer = history->peer;
if (const auto channel = peer->asChannel()) {
if (dialog.has_pts()) {
channel->ptsReceived(dialog.vpts.v);
}
if (!channel->amCreator()) {
const auto topMsgId = FullMsgId(
peerToChannel(channel->id),
dialog.vtop_message.v);
if (const auto topMsg = App::histItemById(topMsgId)) {
if (topMsg->date <= date(channel->date)) {
Auth().api().requestSelfParticipant(channel);
}
}
}
}
App::main()->applyNotifySetting(
MTP_notifyPeer(dialog.vpeer),
dialog.vnotify_settings,
history);
if (!history->isPinnedDialog() && !history->chatsListDate().isNull()) { if (!history->isPinnedDialog() && !history->chatsListDate().isNull()) {
addSavedPeersAfter(history->chatsListDate()); addSavedPeersAfter(history->chatsListDate());
} }
_contactsNoDialogs->del(history); _contactsNoDialogs->del(history);
if (peer->migrateFrom()) { if (const auto from = history->peer->migrateFrom()) {
if (const auto historyFrom = App::historyLoaded(peer->migrateFrom())) { if (const auto historyFrom = App::historyLoaded(from)) {
removeDialog(historyFrom); removeDialog(historyFrom);
} }
} else if (peer->migrateTo() && peer->migrateTo()->amIn()) { } else if (const auto to = history->peer->migrateTo()) {
removeDialog(history); if (to->amIn()) {
} removeDialog(history);
}
if (dialog.has_draft() && dialog.vdraft.type() == mtpc_draftMessage) {
const auto &draft = dialog.vdraft.c_draftMessage();
Data::applyPeerCloudDraft(peerId, draft);
} }
} }
void DialogsInner::applyFeedDialog(const MTPDdialogFeed &dialog) { void DialogsInner::applyFeedDialog(const MTPDdialogFeed &dialog) {
const auto peerId = peerFromMTP(dialog.vpeer);
const auto feedId = dialog.vfeed_id.v; const auto feedId = dialog.vfeed_id.v;
const auto feed = Auth().data().feed(feedId); const auto feed = Auth().data().feed(feedId);
const auto addChannel = [&](ChannelId channelId) { feed->applyDialog(dialog);
if (const auto channel = App::channelLoaded(channelId)) {
channel->setFeed(feed);
}
};
if (peerId && peerIsChannel(peerId)) {
addChannel(peerToChannel(peerId));
}
for (const auto &channelId : dialog.vfeed_other_channels.v) {
addChannel(channelId.v);
}
feed->setUnreadCounts(
dialog.vunread_count.v,
dialog.vunread_muted_count.v);
if (!feed->isPinnedDialog() && !feed->chatsListDate().isNull()) { if (!feed->isPinnedDialog() && !feed->chatsListDate().isNull()) {
addSavedPeersAfter(feed->chatsListDate()); addSavedPeersAfter(feed->chatsListDate());
} }
if (dialog.has_read_max_position()) {
feed->setUnreadPosition(
Data::FeedPositionFromMTP(dialog.vread_max_position));
}
} }
void DialogsInner::addSavedPeersAfter(const QDateTime &date) { void DialogsInner::addSavedPeersAfter(const QDateTime &date) {

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/flags.h" #include "base/flags.h"
class History; class History;
class ChannelHistory;
class HistoryBlock; class HistoryBlock;
class HistoryItem; class HistoryItem;
class HistoryMessage; class HistoryMessage;
@ -50,12 +49,7 @@ enum NewMessageType : char {
class Histories { class Histories {
public: public:
using Map = QHash<PeerId, History*>; Histories();
Map map;
Histories() : _a_typings(animation(this, &Histories::step_typings)) {
_selfDestructTimer.setCallback([this] { checkSelfDestructItems(); });
}
void registerSendAction( void registerSendAction(
not_null<History*> history, not_null<History*> history,
@ -64,20 +58,16 @@ public:
TimeId when); TimeId when);
void step_typings(TimeMs ms, bool timer); void step_typings(TimeMs ms, bool timer);
History *find(const PeerId &peerId); History *find(PeerId peerId) const;
not_null<History*> findOrInsert(const PeerId &peerId); not_null<History*> findOrInsert(PeerId peerId);
not_null<History*> findOrInsert(
const PeerId &peerId,
int unreadCount,
MsgId maxInboxRead,
MsgId maxOutboxRead);
void clear(); void clear();
void remove(const PeerId &peer); void remove(const PeerId &peer);
HistoryItem *addNewMessage(const MTPMessage &msg, NewMessageType type); HistoryItem *addNewMessage(const MTPMessage &msg, NewMessageType type);
typedef QMap<History*, TimeMs> TypingHistories; // when typing in this history started // When typing in this history started.
typedef QMap<History*, TimeMs> TypingHistories;
TypingHistories typing; TypingHistories typing;
BasicAnimation _a_typings; BasicAnimation _a_typings;
@ -114,6 +104,8 @@ public:
private: private:
void checkSelfDestructItems(); void checkSelfDestructItems();
std::unordered_map<PeerId, std::unique_ptr<History>> _map;
int _unreadFull = 0; int _unreadFull = 0;
int _unreadMuted = 0; int _unreadMuted = 0;
base::Observable<SendActionAnimationUpdate> _sendActionAnimationUpdated; base::Observable<SendActionAnimationUpdate> _sendActionAnimationUpdated;
@ -136,29 +128,24 @@ public:
History(const History &) = delete; History(const History &) = delete;
History &operator=(const History &) = delete; History &operator=(const History &) = delete;
ChannelId channelId() const { ChannelId channelId() const;
return peerToChannel(peer->id); bool isChannel() const;
} bool isMegagroup() const;
bool isChannel() const {
return peerIsChannel(peer->id);
}
bool isMegagroup() const {
return peer->isMegagroup();
}
ChannelHistory *asChannelHistory();
const ChannelHistory *asChannelHistory() const;
not_null<History*> migrateToOrMe() const; not_null<History*> migrateToOrMe() const;
History *migrateFrom() const; History *migrateFrom() const;
MsgRange rangeForDifferenceRequest() const;
HistoryService *insertJoinedMessage(bool unread);
void checkJoinedMessage(bool createUnread = false);
bool isEmpty() const { bool isEmpty() const;
return blocks.empty();
}
bool isDisplayedEmpty() const; bool isDisplayedEmpty() const;
bool hasOrphanMediaGroupPart() const; bool hasOrphanMediaGroupPart() const;
bool removeOrphanMediaGroupPart(); bool removeOrphanMediaGroupPart();
QVector<MsgId> collectMessagesFromUserToDelete(
not_null<UserData*> user) const;
void clear(bool leaveItems = false); void clear();
void unloadBlocks();
void clearUpTill(MsgId availableMinId); void clearUpTill(MsgId availableMinId);
void applyGroupAdminChanges(const base::flat_map<UserId, bool> &changes); void applyGroupAdminChanges(const base::flat_map<UserId, bool> &changes);
@ -184,18 +171,17 @@ public:
void newItemAdded(not_null<HistoryItem*> item); void newItemAdded(not_null<HistoryItem*> item);
int countUnread(MsgId upTo); int countUnread(MsgId upTo);
MsgId inboxRead(MsgId upTo); MsgId readInbox();
MsgId inboxRead(HistoryItem *wasRead); void inboxRead(MsgId upTo);
MsgId outboxRead(MsgId upTo); void inboxRead(not_null<const HistoryItem*> wasRead);
MsgId outboxRead(HistoryItem *wasRead); void outboxRead(MsgId upTo);
void outboxRead(not_null<const HistoryItem*> wasRead);
bool isServerSideUnread(not_null<const HistoryItem*> item) const;
MsgId loadAroundId() const;
int unreadCount() const { int unreadCount() const;
return _unreadCount;
}
void setUnreadCount(int newUnreadCount); void setUnreadCount(int newUnreadCount);
bool mute() const { bool mute() const;
return _mute;
}
bool changeMute(bool newMute); bool changeMute(bool newMute);
void addUnreadBar(); void addUnreadBar();
void destroyUnreadBar(); void destroyUnreadBar();
@ -212,46 +198,34 @@ public:
bool isReadyFor(MsgId msgId); // has messages for showing history at msgId bool isReadyFor(MsgId msgId); // has messages for showing history at msgId
void getReadyFor(MsgId msgId); void getReadyFor(MsgId msgId);
void setLastMessage(HistoryItem *msg); HistoryItem *lastMessage() const;
void fixLastMessage(bool wasAtBottom); bool lastMessageKnown() const;
void unknownMessageDeleted(MsgId messageId);
void applyDialogTopMessage(MsgId topMessageId);
void applyDialog(const MTPDdialog &data);
void applyDialogFields(
int unreadCount,
MsgId maxInboxRead,
MsgId maxOutboxRead);
MsgId minMsgId() const; MsgId minMsgId() const;
MsgId maxMsgId() const; MsgId maxMsgId() const;
MsgId msgIdForRead() const; MsgId msgIdForRead() const;
void resizeToWidth(int newWidth); void resizeToWidth(int newWidth);
int height() const;
void removeNotification(HistoryItem *item) { void itemRemoved(not_null<HistoryItem*> item);
if (!notifies.isEmpty()) { void itemVanished(not_null<HistoryItem*> item);
for (auto i = notifies.begin(), e = notifies.end(); i != e; ++i) {
if ((*i) == item) {
notifies.erase(i);
break;
}
}
}
}
HistoryItem *currentNotification() {
return notifies.isEmpty() ? 0 : notifies.front();
}
bool hasNotification() const {
return !notifies.isEmpty();
}
void skipNotification() {
if (!notifies.isEmpty()) {
notifies.pop_front();
}
}
void popNotification(HistoryItem *item) {
if (!notifies.isEmpty() && notifies.back() == item) notifies.pop_back();
}
bool hasPendingResizedItems() const { HistoryItem *currentNotification();
return _flags & Flag::f_has_pending_resized_items; bool hasNotification() const;
} void skipNotification();
void popNotification(HistoryItem *item);
bool hasPendingResizedItems() const;
void setHasPendingResizedItems(); void setHasPendingResizedItems();
void paintDialog(Painter &p, int32 w, bool sel) const;
bool mySendActionUpdated(SendAction::Type type, bool doing); bool mySendActionUpdated(SendAction::Type type, bool doing);
bool paintSendAction(Painter &p, int x, int y, int availableWidth, int outerWidth, style::color color, TimeMs ms); bool paintSendAction(Painter &p, int x, int y, int availableWidth, int outerWidth, style::color color, TimeMs ms);
@ -345,15 +319,9 @@ public:
// Still public data. // Still public data.
std::deque<std::unique_ptr<HistoryBlock>> blocks; std::deque<std::unique_ptr<HistoryBlock>> blocks;
int height() const;
int32 msgCount = 0;
MsgId inboxReadBefore = 1;
MsgId outboxReadBefore = 1;
not_null<PeerData*> peer; not_null<PeerData*> peer;
bool oldLoaded = false; bool oldLoaded = false;
bool newLoaded = true; bool newLoaded = true;
HistoryItem *lastMsg = nullptr;
HistoryItem *lastSentMsg = nullptr; HistoryItem *lastSentMsg = nullptr;
typedef QList<HistoryItem*> NotifyQueue; typedef QList<HistoryItem*> NotifyQueue;
@ -379,7 +347,17 @@ public:
Text cloudDraftTextCache; Text cloudDraftTextCache;
protected: private:
friend class HistoryBlock;
enum class Flag {
f_has_pending_resized_items = (1 << 0),
};
using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) {
return true;
};
// when this item is destroyed scrollTopItem just points to the next one // when this item is destroyed scrollTopItem just points to the next one
// and scrollTopOffset remains the same // and scrollTopOffset remains the same
// if we are at the bottom of the window scrollTopItem == nullptr and // if we are at the bottom of the window scrollTopItem == nullptr and
@ -389,7 +367,6 @@ protected:
// helper method for countScrollState(int top) // helper method for countScrollState(int top)
void countScrollTopItem(int top); void countScrollTopItem(int top);
void clearOnDestroy();
HistoryItem *addNewToLastBlock(const MTPMessage &msg, NewMessageType type); HistoryItem *addNewToLastBlock(const MTPMessage &msg, NewMessageType type);
// this method just removes a block from the blocks list // this method just removes a block from the blocks list
@ -429,25 +406,18 @@ protected:
return _buildingFrontBlock != nullptr; return _buildingFrontBlock != nullptr;
} }
private:
friend class HistoryBlock;
enum class Flag {
f_has_pending_resized_items = (1 << 0),
};
using Flags = base::flags<Flag>;
friend inline constexpr auto is_flag_type(Flag) {
return true;
};
void mainViewRemoved( void mainViewRemoved(
not_null<HistoryBlock*> block, not_null<HistoryBlock*> block,
not_null<Element*> view); not_null<Element*> view);
void removeNotification(not_null<HistoryItem*> item);
QDateTime adjustChatListDate() const override; QDateTime adjustChatListDate() const override;
void changedInChatListHook(Dialogs::Mode list, bool added) override; void changedInChatListHook(Dialogs::Mode list, bool added) override;
void changedChatListPinHook() override; void changedChatListPinHook() override;
void setInboxReadTill(MsgId upTo);
void setOutboxReadTill(MsgId upTo);
void applyMessageChanges( void applyMessageChanges(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
const MTPMessage &original); const MTPMessage &original);
@ -455,14 +425,13 @@ private:
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
const MTPDmessageService &data); const MTPDmessageService &data);
// After adding a new history slice check the lastMsg and newLoaded. // After adding a new history slice check the lastMessage and newLoaded.
void checkLastMsg(); void checkLastMessage();
void setLastMessage(HistoryItem *item);
// Add all items to the unread mentions if we were not loaded at bottom and now are. // Add all items to the unread mentions if we were not loaded at bottom and now are.
void checkAddAllToUnreadMentions(); void checkAddAllToUnreadMentions();
template <int kSharedMediaTypeCount>
void addToSharedMedia(std::vector<MsgId> (&medias)[kSharedMediaTypeCount], bool force);
void addToSharedMedia(const std::vector<not_null<HistoryItem*>> &items); void addToSharedMedia(const std::vector<not_null<HistoryItem*>> &items);
void addEdgesToSharedMedia(); void addEdgesToSharedMedia();
@ -480,14 +449,18 @@ private:
Flags _flags = 0; Flags _flags = 0;
bool _mute = false; bool _mute = false;
int _unreadCount = 0;
int _width = 0; int _width = 0;
int _height = 0; int _height = 0;
Element *_unreadBarView = nullptr; Element *_unreadBarView = nullptr;
Element *_firstUnreadView = nullptr; Element *_firstUnreadView = nullptr;
HistoryService *_joinedMessage = nullptr;
base::optional<MsgId> _inboxReadBefore;
base::optional<MsgId> _outboxReadBefore;
base::optional<int> _unreadCount;
base::optional<int> _unreadMentionsCount; base::optional<int> _unreadMentionsCount;
base::flat_set<MsgId> _unreadMentions; base::flat_set<MsgId> _unreadMentions;
base::optional<HistoryItem*> _lastMessage;
// A pointer to the block that is currently being built. // A pointer to the block that is currently being built.
// We hold this pointer so we can destroy it while building // We hold this pointer so we can destroy it while building
@ -517,37 +490,6 @@ private:
}; };
class ChannelHistory : public History {
public:
using History::History;
void messageDetached(not_null<HistoryItem*> message);
void getRangeDifference();
void getRangeDifferenceNext(int32 pts);
HistoryService *insertJoinedMessage(bool unread);
void checkJoinedMessage(bool createUnread = false);
const QDateTime &maxReadMessageDate();
~ChannelHistory();
private:
friend class History;
void checkMaxReadMessageDate();
void cleared(bool leaveItems);
QDateTime _maxReadMessageDate;
HistoryService *_joinedMessage = nullptr;
MsgId _rangeDifferenceFromId, _rangeDifferenceToId;
int32 _rangeDifferencePts;
mtpRequestId _rangeDifferenceRequestId;
};
class HistoryBlock { class HistoryBlock {
public: public:
using Element = HistoryView::Element; using Element = HistoryView::Element;
@ -559,7 +501,6 @@ public:
std::vector<std::unique_ptr<Element>> messages; std::vector<std::unique_ptr<Element>> messages;
void clear(bool leaveItems = false);
void remove(not_null<Element*> view); void remove(not_null<Element*> view);
void refreshView(not_null<Element*> view); void refreshView(not_null<Element*> view);

View File

@ -178,11 +178,15 @@ HistoryInner::HistoryInner(
}, lifetime()); }, lifetime());
} }
void HistoryInner::messagesReceived(PeerData *peer, const QVector<MTPMessage> &messages) { void HistoryInner::messagesReceived(
PeerData *peer,
const QVector<MTPMessage> &messages) {
if (_history && _history->peer == peer) { if (_history && _history->peer == peer) {
_history->addOlderSlice(messages); _history->addOlderSlice(messages);
} else if (_migrated && _migrated->peer == peer) { } else if (_migrated && _migrated->peer == peer) {
bool newLoaded = (_migrated && _migrated->isEmpty() && !_history->isEmpty()); const auto newLoaded = _migrated
&& _migrated->isEmpty()
&& !_history->isEmpty();
_migrated->addOlderSlice(messages); _migrated->addOlderSlice(messages);
if (newLoaded) { if (newLoaded) {
_migrated->addNewerSlice(QVector<MTPMessage>()); _migrated->addNewerSlice(QVector<MTPMessage>());

View File

@ -148,19 +148,7 @@ void HistoryItem::invalidateChatsListEntry() {
void HistoryItem::finishEditionToEmpty() { void HistoryItem::finishEditionToEmpty() {
finishEdition(-1); finishEdition(-1);
_history->itemVanished(this);
_history->removeNotification(this);
if (auto channel = history()->peer->asChannel()) {
if (channel->pinnedMessageId() == id) {
channel->clearPinnedMessage();
}
}
if (history()->lastKeyboardId == id) {
history()->clearLastKeyboard();
}
if ((!out() || isPost()) && unread() && history()->unreadCount() > 0) {
history()->setUnreadCount(history()->unreadCount() - 1);
}
} }
bool HistoryItem::isMediaUnread() const { bool HistoryItem::isMediaUnread() const {
@ -244,7 +232,7 @@ void HistoryItem::destroy() {
if (isLogEntry()) { if (isLogEntry()) {
Assert(!mainView()); Assert(!mainView());
} else { } else {
// All this must be done for all items manually in History::clear(false)! // All this must be done for all items manually in History::clear()!
eraseFromUnreadMentions(); eraseFromUnreadMentions();
if (IsServerMsgId(id)) { if (IsServerMsgId(id)) {
if (const auto types = sharedMediaTypes()) { if (const auto types = sharedMediaTypes()) {
@ -256,32 +244,7 @@ void HistoryItem::destroy() {
} else { } else {
Auth().api().cancelLocalItem(this); Auth().api().cancelLocalItem(this);
} }
_history->itemRemoved(this);
const auto wasAtBottom = history->loadedAtBottom();
history->removeNotification(this);
removeMainView();
if (history->lastMsg == this) {
history->fixLastMessage(wasAtBottom);
}
if (history->lastKeyboardId == id) {
history->clearLastKeyboard();
}
if ((!out() || isPost()) && unread() && history->unreadCount() > 0) {
history->setUnreadCount(history->unreadCount() - 1);
}
if (const auto channel = history->peer->asChannel()) {
if (channel->pinnedMessageId() == id) {
channel->clearPinnedMessage();
}
if (const auto feed = channel->feed()) {
// Must be after histroy->lastMsg is cleared.
// Otherwise feed last message will be this value again.
feed->messageRemoved(this);
// #TODO feeds unread
}
}
} }
delete this; delete this;
} }
@ -295,9 +258,6 @@ void HistoryItem::refreshMainView() {
void HistoryItem::removeMainView() { void HistoryItem::removeMainView() {
if (const auto view = mainView()) { if (const auto view = mainView()) {
if (const auto channelHistory = _history->asChannelHistory()) {
channelHistory->messageDetached(this);
}
Auth().data().notifyHistoryChangeDelayed(_history); Auth().data().notifyHistoryChangeDelayed(_history);
view->removeFromBlock(); view->removeFromBlock();
} }
@ -551,11 +511,11 @@ bool HistoryItem::unread() const {
return false; return false;
} }
if (id > 0) { if (IsServerMsgId(id)) {
if (id < history()->outboxReadBefore) { if (!history()->isServerSideUnread(this)) {
return false; return false;
} }
if (auto user = history()->peer->asUser()) { if (const auto user = history()->peer->asUser()) {
if (user->botInfo) { if (user->botInfo) {
return false; return false;
} }
@ -568,8 +528,8 @@ bool HistoryItem::unread() const {
return true; return true;
} }
if (id > 0) { if (IsServerMsgId(id)) {
if (id < history()->inboxReadBefore) { if (!history()->isServerSideUnread(this)) {
return false; return false;
} }
return true; return true;
@ -587,24 +547,6 @@ bool HistoryItem::isEmpty() const {
&& !Has<HistoryMessageLogEntryOriginal>(); && !Has<HistoryMessageLogEntryOriginal>();
} }
HistoryItem *HistoryItem::previousItem() const {
if (const auto view = mainView()) {
if (const auto previous = view->previousInBlocks()) {
return previous->data();
}
}
return nullptr;
}
HistoryItem *HistoryItem::nextItem() const {
if (const auto view = mainView()) {
if (const auto next = view->nextInBlocks()) {
return next->data();
}
}
return nullptr;
}
QString HistoryItem::notificationText() const { QString HistoryItem::notificationText() const {
auto getText = [this]() { auto getText = [this]() {
if (_media) { if (_media) {

View File

@ -254,9 +254,6 @@ public:
MessageGroupId groupId() const; MessageGroupId groupId() const;
HistoryItem *previousItem() const;
HistoryItem *nextItem() const;
virtual std::unique_ptr<HistoryView::Element> createView( virtual std::unique_ptr<HistoryView::Element> createView(
not_null<HistoryView::ElementDelegate*> delegate) = 0; not_null<HistoryView::ElementDelegate*> delegate) = 0;

View File

@ -2256,9 +2256,7 @@ void HistoryWidget::historyToDown(History *history) {
void HistoryWidget::unreadCountChanged(not_null<History*> history) { void HistoryWidget::unreadCountChanged(not_null<History*> history) {
if (history == _history || history == _migrated) { if (history == _history || history == _migrated) {
updateHistoryDownVisibility(); updateHistoryDownVisibility();
_historyDown->setUnreadCount( _historyDown->setUnreadCount(_history->chatListUnreadCount());
_history->unreadCount()
+ (_migrated ? _migrated->unreadCount() : 0));
} }
} }
@ -2402,9 +2400,9 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
if (_history->loadedAtBottom() && App::wnd()) App::wnd()->checkHistoryActivation(); if (_history->loadedAtBottom() && App::wnd()) App::wnd()->checkHistoryActivation();
} else if (_firstLoadRequest == requestId) { } else if (_firstLoadRequest == requestId) {
if (toMigrated) { if (toMigrated) {
_history->clear(true); _history->unloadBlocks();
} else if (_migrated) { } else if (_migrated) {
_migrated->clear(true); _migrated->unloadBlocks();
} }
addMessagesToFront(peer, *histList); addMessagesToFront(peer, *histList);
_firstLoadRequest = 0; _firstLoadRequest = 0;
@ -2421,9 +2419,9 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
historyLoaded(); historyLoaded();
} else if (_delayedShowAtRequest == requestId) { } else if (_delayedShowAtRequest == requestId) {
if (toMigrated) { if (toMigrated) {
_history->clear(true); _history->unloadBlocks();
} else if (_migrated) { } else if (_migrated) {
_migrated->clear(true); _migrated->unloadBlocks();
} }
_delayedShowAtRequest = 0; _delayedShowAtRequest = 0;
@ -2506,15 +2504,15 @@ void HistoryWidget::firstLoadMessages() {
auto offset = 0; auto offset = 0;
auto loadCount = kMessagesPerPage; auto loadCount = kMessagesPerPage;
if (_showAtMsgId == ShowAtUnreadMsgId) { if (_showAtMsgId == ShowAtUnreadMsgId) {
if (_migrated && _migrated->unreadCount()) { if (const auto around = _migrated ? _migrated->loadAroundId() : 0) {
_history->getReadyFor(_showAtMsgId); _history->getReadyFor(_showAtMsgId);
from = _migrated->peer; from = _migrated->peer;
offset = -loadCount / 2; offset = -loadCount / 2;
offsetId = _migrated->inboxReadBefore; offsetId = around;
} else if (_history->unreadCount()) { } else if (const auto around = _history->loadAroundId()) {
_history->getReadyFor(_showAtMsgId); _history->getReadyFor(_showAtMsgId);
offset = -loadCount / 2; offset = -loadCount / 2;
offsetId = _history->inboxReadBefore; offsetId = around;
} else { } else {
_history->getReadyFor(ShowAtTheEndMsgId); _history->getReadyFor(ShowAtTheEndMsgId);
} }
@ -2651,13 +2649,13 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) {
auto offset = 0; auto offset = 0;
auto loadCount = kMessagesPerPage; auto loadCount = kMessagesPerPage;
if (_delayedShowAtMsgId == ShowAtUnreadMsgId) { if (_delayedShowAtMsgId == ShowAtUnreadMsgId) {
if (_migrated && _migrated->unreadCount()) { if (const auto around = _migrated ? _migrated->loadAroundId() : 0) {
from = _migrated->peer; from = _migrated->peer;
offset = -loadCount / 2; offset = -loadCount / 2;
offsetId = _migrated->inboxReadBefore; offsetId = around;
} else if (_history->unreadCount()) { } else if (const auto around = _history->loadAroundId()) {
offset = -loadCount / 2; offset = -loadCount / 2;
offsetId = _history->inboxReadBefore; offsetId = around;
} else { } else {
loadCount = kMessagesPerPageFirst; loadCount = kMessagesPerPageFirst;
} }
@ -3630,8 +3628,17 @@ bool HistoryWidget::inlineBotResolveFail(QString name, const RPCError &error) {
} }
bool HistoryWidget::isBotStart() const { bool HistoryWidget::isBotStart() const {
if (!_peer || !_peer->isUser() || !_peer->asUser()->botInfo || !_canSendMessages) return false; const auto user = _peer ? _peer->asUser() : nullptr;
return !_peer->asUser()->botInfo->startToken.isEmpty() || (_history->isEmpty() && !_history->lastMsg); if (!user
|| !user->botInfo
|| !_canSendMessages) {
return false;
} else if (!user->botInfo->startToken.isEmpty()) {
return true;
} else if (_history->isEmpty() && !_history->lastMessage()) {
return true;
}
return false;
} }
bool HistoryWidget::isBlocked() const { bool HistoryWidget::isBlocked() const {
@ -5126,14 +5133,7 @@ void HistoryWidget::keyPressEvent(QKeyEvent *e) {
if (!(e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier))) { if (!(e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier))) {
_scroll->keyPressEvent(e); _scroll->keyPressEvent(e);
} else if ((e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier)) == Qt::ControlModifier) { } else if ((e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier)) == Qt::ControlModifier) {
if (_history && _history->lastMsg && !_editMsgId) { replyToNextMessage();
if (const auto item = App::histItemById(_history->channelId(), _replyToId)) {
if (const auto next = item->nextItem()) {
Ui::showPeerHistory(_peer, next->id);
replyToMessage(next);
}
}
}
} }
} else if (e->key() == Qt::Key_Up) { } else if (e->key() == Qt::Key_Up) {
if (!(e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier))) { if (!(e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier))) {
@ -5145,17 +5145,7 @@ void HistoryWidget::keyPressEvent(QKeyEvent *e) {
} }
_scroll->keyPressEvent(e); _scroll->keyPressEvent(e);
} else if ((e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier)) == Qt::ControlModifier) { } else if ((e->modifiers() & (Qt::ShiftModifier | Qt::MetaModifier | Qt::ControlModifier)) == Qt::ControlModifier) {
if (_history && _history->lastMsg && !_editMsgId) { replyToPreviousMessage();
if (const auto item = App::histItemById(_history->channelId(), _replyToId)) {
if (const auto previous = item->previousItem()) {
Ui::showPeerHistory(_peer, previous->id);
replyToMessage(previous);
}
} else if (const auto previous = _history->lastMsg) {
Ui::showPeerHistory(_peer, previous->id);
replyToMessage(previous);
}
}
} }
} else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
onListEnterPressed(); onListEnterPressed();
@ -5164,6 +5154,45 @@ void HistoryWidget::keyPressEvent(QKeyEvent *e) {
} }
} }
void HistoryWidget::replyToPreviousMessage() {
if (!_history || _editMsgId) {
return;
}
const auto fullId = FullMsgId(
_history->channelId(),
_replyToId);
if (const auto item = App::histItemById(fullId)) {
if (const auto view = item->mainView()) {
if (const auto previousView = view->previousInBlocks()) {
const auto previous = previousView->data();
Ui::showPeerHistoryAtItem(previous);
replyToMessage(previous);
}
}
} else if (const auto previous = _history->lastMessage()) {
Ui::showPeerHistoryAtItem(previous);
replyToMessage(previous);
}
}
void HistoryWidget::replyToNextMessage() {
if (!_history || _editMsgId) {
return;
}
const auto fullId = FullMsgId(
_history->channelId(),
_replyToId);
if (const auto item = App::histItemById(fullId)) {
if (const auto view = item->mainView()) {
if (const auto nextView = view->nextInBlocks()) {
const auto next = nextView->data();
Ui::showPeerHistoryAtItem(next);
replyToMessage(next);
}
}
}
}
void HistoryWidget::onFieldTabbed() { void HistoryWidget::onFieldTabbed() {
if (!_fieldAutocomplete->isHidden()) { if (!_fieldAutocomplete->isHidden()) {
_fieldAutocomplete->chooseSelected(FieldAutocomplete::ChooseMethod::ByTab); _fieldAutocomplete->chooseSelected(FieldAutocomplete::ChooseMethod::ByTab);

View File

@ -538,6 +538,8 @@ private:
void applyInlineBotQuery(UserData *bot, const QString &query); void applyInlineBotQuery(UserData *bot, const QString &query);
void cancelReplyAfterMediaSend(bool lastKeyboardUsed); void cancelReplyAfterMediaSend(bool lastKeyboardUsed);
void replyToPreviousMessage();
void replyToNextMessage();
void hideSelectorControlsAnimated(); void hideSelectorControlsAnimated();
int countMembersDropdownHeightMax() const; int countMembersDropdownHeightMax() const;

View File

@ -611,6 +611,9 @@ void Element::clickHandlerPressedChanged(
} }
Element::~Element() { Element::~Element() {
if (_data->mainView() == this) {
_data->clearMainView();
}
Auth().data().unregisterItemView(this); Auth().data().unregisterItemView(this);
} }

View File

@ -887,21 +887,27 @@ void MainWidget::deleteLayer(FullMsgId itemId) {
void MainWidget::cancelUploadLayer(not_null<HistoryItem*> item) { void MainWidget::cancelUploadLayer(not_null<HistoryItem*> item) {
const auto itemId = item->fullId(); const auto itemId = item->fullId();
Auth().uploader().pause(itemId); Auth().uploader().pause(itemId);
Ui::show(Box<ConfirmBox>(lang(lng_selected_cancel_sure_this), lang(lng_selected_upload_stop), lang(lng_continue), base::lambda_guarded(this, [=] { const auto stopUpload = [=] {
Ui::hideLayer(); Ui::hideLayer();
if (const auto item = App::histItemById(itemId)) { if (const auto item = App::histItemById(itemId)) {
const auto history = item->history(); const auto history = item->history();
const auto wasLast = (history->lastMsg == item);
item->destroy(); item->destroy();
if (wasLast && !history->lastMsg) { if (!history->lastMessageKnown()) {
checkPeerHistory(history->peer); Auth().api().requestDialogEntry(history);
} }
Auth().data().sendHistoryChangeNotifications(); Auth().data().sendHistoryChangeNotifications();
} }
Auth().uploader().unpause(); Auth().uploader().unpause();
}), base::lambda_guarded(this, [] { };
const auto continueUpload = [=] {
Auth().uploader().unpause(); Auth().uploader().unpause();
}))); };
Ui::show(Box<ConfirmBox>(
lang(lng_selected_cancel_sure_this),
lang(lng_selected_upload_stop),
lang(lng_continue),
stopUpload,
continueUpload));
} }
void MainWidget::deletePhotoLayer(PhotoData *photo) { void MainWidget::deletePhotoLayer(PhotoData *photo) {
@ -1041,12 +1047,11 @@ void MainWidget::deleteConversation(
if (const auto history = App::historyLoaded(peer->id)) { if (const auto history = App::historyLoaded(peer->id)) {
Auth().data().setPinnedDialog(history, false); Auth().data().setPinnedDialog(history, false);
removeDialog(history); removeDialog(history);
if (peer->isMegagroup() && peer->asChannel()->mgInfo->migrateFromPtr) { if (const auto channel = peer->asMegagroup()) {
if (auto migrated = App::historyLoaded(peer->asChannel()->mgInfo->migrateFromPtr->id)) { channel->addFlags(MTPDchannel::Flag::f_left);
if (migrated->lastMsg) { // return initial dialog if (const auto from = channel->mgInfo->migrateFromPtr) {
migrated->setLastMessage(migrated->lastMsg); if (const auto migrated = App::historyLoaded(from)) {
} else { migrated->updateChatListExistence();
checkPeerHistory(migrated->peer);
} }
} }
} }
@ -1059,7 +1064,12 @@ void MainWidget::deleteConversation(
} }
if (deleteHistory) { if (deleteHistory) {
DeleteHistoryRequest request = { peer, false }; DeleteHistoryRequest request = { peer, false };
MTP::send(MTPmessages_DeleteHistory(MTP_flags(0), peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, request)); MTP::send(
MTPmessages_DeleteHistory(
MTP_flags(0),
peer->input,
MTP_int(0)),
rpcDone(&MainWidget::deleteHistoryPart, request));
} }
} }
@ -1068,47 +1078,6 @@ void MainWidget::deleteAndExit(ChatData *chat) {
MTP::send(MTPmessages_DeleteChatUser(chat->inputChat, App::self()->inputUser), rpcDone(&MainWidget::deleteHistoryAfterLeave, peer), rpcFail(&MainWidget::leaveChatFailed, peer)); MTP::send(MTPmessages_DeleteChatUser(chat->inputChat, App::self()->inputUser), rpcDone(&MainWidget::deleteHistoryAfterLeave, peer), rpcFail(&MainWidget::leaveChatFailed, peer));
} }
void MainWidget::deleteAllFromUser(ChannelData *channel, UserData *from) {
Assert(channel != nullptr && from != nullptr);
QVector<MsgId> toDestroy;
if (auto history = App::historyLoaded(channel->id)) {
for (const auto &block : history->blocks) {
for (const auto &message : block->messages) {
const auto item = message->data();
if (item->from() == from && item->canDelete()) {
toDestroy.push_back(item->id);
}
}
}
for_const (auto &msgId, toDestroy) {
if (auto item = App::histItemById(peerToChannel(channel->id), msgId)) {
item->destroy();
}
}
}
MTP::send(
MTPchannels_DeleteUserHistory(
channel->inputChannel,
from->inputUser),
rpcDone(&MainWidget::deleteAllFromUserPart, { channel, from }));
Auth().data().sendHistoryChangeNotifications();
}
void MainWidget::deleteAllFromUserPart(DeleteAllFromUserParams params, const MTPmessages_AffectedHistory &result) {
auto &d = result.c_messages_affectedHistory();
params.channel->ptsUpdateAndApply(d.vpts.v, d.vpts_count.v);
auto offset = d.voffset.v;
if (offset > 0) {
MTP::send(MTPchannels_DeleteUserHistory(params.channel->inputChannel, params.from->inputUser), rpcDone(&MainWidget::deleteAllFromUserPart, params));
} else if (auto h = App::historyLoaded(params.channel)) {
if (!h->lastMsg) {
checkPeerHistory(params.channel);
}
}
}
void MainWidget::addParticipants( void MainWidget::addParticipants(
not_null<PeerData*> chatOrChannel, not_null<PeerData*> chatOrChannel,
const std::vector<not_null<UserData*>> &users) { const std::vector<not_null<UserData*>> &users) {
@ -1194,99 +1163,6 @@ bool MainWidget::addParticipantsFail(
return false; return false;
} }
void MainWidget::checkPeerHistory(PeerData *peer) {
auto offsetId = 0;
auto offsetDate = 0;
auto addOffset = 0;
auto limit = 1;
auto maxId = 0;
auto minId = 0;
auto historyHash = 0;
MTP::send(
MTPmessages_GetHistory(
peer->input,
MTP_int(offsetId),
MTP_int(offsetDate),
MTP_int(addOffset),
MTP_int(limit),
MTP_int(maxId),
MTP_int(minId),
MTP_int(historyHash)),
rpcDone(&MainWidget::checkedHistory, peer));
}
void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &result) {
const QVector<MTPMessage> *v = 0;
switch (result.type()) {
case mtpc_messages_messages: {
auto &d(result.c_messages_messages());
App::feedUsers(d.vusers);
App::feedChats(d.vchats);
v = &d.vmessages.v;
} break;
case mtpc_messages_messagesSlice: {
auto &d(result.c_messages_messagesSlice());
App::feedUsers(d.vusers);
App::feedChats(d.vchats);
v = &d.vmessages.v;
} break;
case mtpc_messages_channelMessages: {
auto &d(result.c_messages_channelMessages());
if (peer && peer->isChannel()) {
peer->asChannel()->ptsReceived(d.vpts.v);
} else {
LOG(("API Error: received messages.channelMessages when no channel was passed! (MainWidget::checkedHistory)"));
}
App::feedUsers(d.vusers);
App::feedChats(d.vchats);
v = &d.vmessages.v;
} break;
case mtpc_messages_messagesNotModified: {
LOG(("API Error: received messages.messagesNotModified! (MainWidget::checkedHistory)"));
} break;
}
if (!v || v->isEmpty()) {
if (peer->isChat() && !peer->asChat()->haveLeft()) {
if (const auto history = App::historyLoaded(peer->id)) {
Local::addSavedPeer(peer, history->chatsListDate());
}
} else if (const auto channel = peer->asChannel()) {
if (channel->inviter > 0 && channel->amIn()) {
if (const auto from = App::userLoaded(channel->inviter)) {
const auto history = App::history(peer->id);
history->clear(true);
history->addNewerSlice(QVector<MTPMessage>());
history->asChannelHistory()->insertJoinedMessage(true);
}
}
} else if (const auto history = App::historyLoaded(peer->id)) {
deleteConversation(history->peer, false);
}
} else {
const auto history = App::history(peer->id);
if (!history->lastMsg) {
history->addNewMessage((*v)[0], NewMessageLast);
}
if (!history->chatsListDate().isNull() && history->loadedAtBottom()) {
if (const auto channel = peer->asChannel()) {
if (channel->inviter > 0
&& history->chatsListDate() <= channel->inviteDate
&& channel->amIn()) {
if (const auto from = App::userLoaded(channel->inviter)) {
history->asChannelHistory()->insertJoinedMessage(true);
}
}
}
}
history->updateChatListExistence();
}
Auth().data().sendHistoryChangeNotifications();
}
bool MainWidget::sendMessageFail(const RPCError &error) { bool MainWidget::sendMessageFail(const RPCError &error) {
if (MTP::isDefaultHandledError(error)) return false; if (MTP::isDefaultHandledError(error)) return false;
@ -1562,9 +1438,9 @@ void MainWidget::messagesAffected(
ptsUpdateAndApply(data.vpts.v, data.vpts_count.v); ptsUpdateAndApply(data.vpts.v, data.vpts_count.v);
} }
if (auto h = App::historyLoaded(peer ? peer->id : 0)) { if (const auto history = App::historyLoaded(peer)) {
if (!h->lastMsg) { if (!history->lastMessageKnown()) {
checkPeerHistory(peer); Auth().api().requestDialogEntry(history);
} }
} }
} }
@ -3473,7 +3349,9 @@ void MainWidget::updSetState(int32 pts, int32 date, int32 qts, int32 seq) {
} }
} }
void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_ChannelDifference &diff) { void MainWidget::gotChannelDifference(
ChannelData *channel,
const MTPupdates_ChannelDifference &diff) {
_channelFailDifferenceTimeout.remove(channel); _channelFailDifferenceTimeout.remove(channel);
int32 timeout = 0; int32 timeout = 0;
@ -3491,28 +3369,28 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha
App::feedUsers(d.vusers); App::feedUsers(d.vusers);
App::feedChats(d.vchats); App::feedChats(d.vchats);
auto h = App::historyLoaded(channel->id); auto history = App::historyLoaded(channel->id);
if (h) { if (history) {
h->setNotLoadedAtBottom(); history->setNotLoadedAtBottom();
} }
App::feedMsgs(d.vmessages, NewMessageLast); App::feedMsgs(d.vmessages, NewMessageLast);
if (h) { if (history) {
if (auto item = App::histItemById(peerToChannel(channel->id), d.vtop_message.v)) { history->applyDialogFields(
h->setLastMessage(item); d.vunread_count.v,
} d.vread_inbox_max_id.v,
if (d.vunread_count.v >= h->unreadCount()) { d.vread_outbox_max_id.v);
h->setUnreadCount(d.vunread_count.v); history->applyDialogTopMessage(d.vtop_message.v);
h->inboxReadBefore = d.vread_inbox_max_id.v + 1; history->setUnreadMentionsCount(d.vunread_mentions_count.v);
}
h->setUnreadMentionsCount(d.vunread_mentions_count.v);
if (_history->peer() == channel) { if (_history->peer() == channel) {
_history->updateHistoryDownVisibility(); _history->updateHistoryDownVisibility();
_history->preloadHistoryIfNeeded(); _history->preloadHistoryIfNeeded();
} }
h->asChannelHistory()->getRangeDifference(); Auth().api().requestChannelRangeDifference(history);
} }
if (d.has_timeout()) timeout = d.vtimeout.v; if (d.has_timeout()) {
timeout = d.vtimeout.v;
}
isFinal = d.is_final(); isFinal = d.is_final();
channel->ptsInit(d.vpts.v); channel->ptsInit(d.vpts.v);
} break; } break;
@ -3520,39 +3398,7 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha
case mtpc_updates_channelDifference: { case mtpc_updates_channelDifference: {
auto &d = diff.c_updates_channelDifference(); auto &d = diff.c_updates_channelDifference();
App::feedUsers(d.vusers); feedChannelDifference(d);
App::feedChats(d.vchats);
_handlingChannelDifference = true;
feedMessageIds(d.vother_updates);
// feed messages and groups, copy from App::feedMsgs
auto h = App::history(channel->id);
auto &vmsgs = d.vnew_messages.v;
auto indices = base::flat_map<uint64, int>();
for (auto i = 0, l = vmsgs.size(); i != l; ++i) {
const auto &msg = vmsgs[i];
if (msg.type() == mtpc_message) {
const auto &data = msg.c_message();
if (App::checkEntitiesAndViewsUpdate(data)) { // new message, index my forwarded messages to links _overview, already in blocks
LOG(("Skipping message, because it is already in blocks!"));
continue;
}
}
const auto msgId = idFromMessage(msg);
indices.emplace((uint64(uint32(msgId)) << 32) | uint64(i), i);
}
for (const auto [position, index] : indices) {
const auto &msg = vmsgs[index];
if (channel->id != peerFromMessage(msg)) {
LOG(("API Error: message with invalid peer returned in channelDifference, channelId: %1, peer: %2").arg(peerToChannel(channel->id)).arg(peerFromMessage(msg)));
continue; // wtf
}
h->addNewMessage(msg, NewMessageUnread);
}
feedUpdateVector(d.vother_updates, true);
_handlingChannelDifference = false;
if (d.has_timeout()) timeout = d.vtimeout.v; if (d.has_timeout()) timeout = d.vtimeout.v;
isFinal = d.is_final(); isFinal = d.is_final();
@ -3570,55 +3416,16 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha
} }
} }
void MainWidget::gotRangeDifference( void MainWidget::feedChannelDifference(
ChannelData *channel, const MTPDupdates_channelDifference &data) {
const MTPupdates_ChannelDifference &diff) { App::feedUsers(data.vusers);
int32 nextRequestPts = 0; App::feedChats(data.vchats);
bool isFinal = true;
switch (diff.type()) {
case mtpc_updates_channelDifferenceEmpty: {
auto &d = diff.c_updates_channelDifferenceEmpty();
nextRequestPts = d.vpts.v;
isFinal = d.is_final();
} break;
case mtpc_updates_channelDifferenceTooLong: { _handlingChannelDifference = true;
auto &d = diff.c_updates_channelDifferenceTooLong(); feedMessageIds(data.vother_updates);
App::feedMsgs(data.vnew_messages, NewMessageUnread);
App::feedUsers(d.vusers); feedUpdateVector(data.vother_updates, true);
App::feedChats(d.vchats); _handlingChannelDifference = false;
nextRequestPts = d.vpts.v;
isFinal = d.is_final();
} break;
case mtpc_updates_channelDifference: {
auto &d = diff.c_updates_channelDifference();
App::feedUsers(d.vusers);
App::feedChats(d.vchats);
_handlingChannelDifference = true;
feedMessageIds(d.vother_updates);
App::feedMsgs(d.vnew_messages, NewMessageUnread);
feedUpdateVector(d.vother_updates, true);
_handlingChannelDifference = false;
nextRequestPts = d.vpts.v;
isFinal = d.is_final();
} break;
}
if (!isFinal) {
if (const auto history = App::historyLoaded(channel->id)) {
MTP_LOG(0, ("getChannelDifference { "
"good - after not final channelDifference was received, "
"validating history part }%1"
).arg(cTestMode() ? " TESTMODE" : ""));
history->asChannelHistory()->getRangeDifferenceNext(
nextRequestPts);
}
}
} }
bool MainWidget::failChannelDifference(ChannelData *channel, const RPCError &error) { bool MainWidget::failChannelDifference(ChannelData *channel, const RPCError &error) {
@ -3985,12 +3792,12 @@ void MainWidget::onSelfParticipantUpdated(ChannelData *channel) {
history = App::history(channel); history = App::history(channel);
} }
if (history->isEmpty()) { if (history->isEmpty()) {
checkPeerHistory(channel); Auth().api().requestDialogEntry(history);
} else { } else {
history->asChannelHistory()->checkJoinedMessage(true); history->checkJoinedMessage(true);
} }
} else if (history) { } else if (history) {
history->asChannelHistory()->checkJoinedMessage(); history->checkJoinedMessage();
} }
Auth().data().sendHistoryChangeNotifications(); Auth().data().sendHistoryChangeNotifications();
} }
@ -4768,10 +4575,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
const auto existing = App::histItemById(channel, newId); const auto existing = App::histItemById(channel, newId);
if (existing && !local->mainView()) { if (existing && !local->mainView()) {
const auto history = local->history(); const auto history = local->history();
const auto wasLast = (history->lastMsg == local);
local->destroy(); local->destroy();
if (wasLast && !history->lastMsg) { if (!history->lastMessageKnown()) {
checkPeerHistory(history->peer); Auth().api().requestDialogEntry(history);
} }
} else { } else {
if (existing) { if (existing) {
@ -5211,7 +5017,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
case mtpc_updateChannel: { case mtpc_updateChannel: {
auto &d = update.c_updateChannel(); auto &d = update.c_updateChannel();
if (auto channel = App::channelLoaded(d.vchannel_id.v)) { if (const auto channel = App::channelLoaded(d.vchannel_id.v)) {
channel->inviter = 0; channel->inviter = 0;
if (!channel->amIn()) { if (!channel->amIn()) {
if (const auto history = App::historyLoaded(channel->id)) { if (const auto history = App::historyLoaded(channel->id)) {

View File

@ -215,9 +215,6 @@ public:
not_null<ChannelData*> channel, not_null<ChannelData*> channel,
const RPCError &e); // for multi invite in channels const RPCError &e); // for multi invite in channels
void checkPeerHistory(PeerData *peer);
void checkedHistory(PeerData *peer, const MTPmessages_Messages &result);
bool sendMessageFail(const RPCError &error); bool sendMessageFail(const RPCError &error);
Dialogs::IndexedList *contactsList(); Dialogs::IndexedList *contactsList();
@ -288,8 +285,8 @@ public:
void scheduleViewIncrement(HistoryItem *item); void scheduleViewIncrement(HistoryItem *item);
void gotRangeDifference(ChannelData *channel, const MTPupdates_ChannelDifference &diff);
void onSelfParticipantUpdated(ChannelData *channel); void onSelfParticipantUpdated(ChannelData *channel);
void feedChannelDifference(const MTPDupdates_channelDifference &data);
// Mayde public for ApiWrap, while it is still here. // Mayde public for ApiWrap, while it is still here.
// Better would be for this to be moved to ApiWrap. // Better would be for this to be moved to ApiWrap.
@ -478,7 +475,6 @@ private:
void feedUpdate(const MTPUpdate &update); void feedUpdate(const MTPUpdate &update);
void deleteHistoryPart(DeleteHistoryRequest request, const MTPmessages_AffectedHistory &result); void deleteHistoryPart(DeleteHistoryRequest request, const MTPmessages_AffectedHistory &result);
void deleteAllFromUserPart(DeleteAllFromUserParams params, const MTPmessages_AffectedHistory &result);
void updateReceived(const mtpPrime *from, const mtpPrime *end); void updateReceived(const mtpPrime *from, const mtpPrime *end);
bool updateFail(const RPCError &e); bool updateFail(const RPCError &e);

View File

@ -593,7 +593,15 @@ void PeerMenuAddChannelMembers(not_null<ChannelData*> channel) {
} }
void ToggleChannelGrouping(not_null<ChannelData*> channel, bool group) { void ToggleChannelGrouping(not_null<ChannelData*> channel, bool group) {
Auth().api().toggleChannelGrouping(channel, group); const auto callback = [=] {
Ui::Toast::Show(lang(group
? lng_feed_channel_added
: lng_feed_channel_removed));
};
Auth().api().toggleChannelGrouping(
channel,
group,
callback);
} }
base::lambda<void()> ClearHistoryHandler(not_null<PeerData*> peer) { base::lambda<void()> ClearHistoryHandler(not_null<PeerData*> peer) {