Remove supergroup migrate messages.

This commit is contained in:
John Preston 2019-01-15 15:57:45 +04:00
parent c552db04d7
commit 2a0b9a44dd
40 changed files with 695 additions and 481 deletions

View File

@ -899,7 +899,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_action_changed_title_channel" = "Channel name was changed to «{title}»"; "lng_action_changed_title_channel" = "Channel name was changed to «{title}»";
"lng_action_created_chat" = "{from} created group «{title}»"; "lng_action_created_chat" = "{from} created group «{title}»";
"lng_action_created_channel" = "Channel created"; "lng_action_created_channel" = "Channel created";
"lng_action_group_migrate" = "The group was upgraded to a supergroup";
"lng_action_pinned_message" = "{from} pinned «{text}»"; "lng_action_pinned_message" = "{from} pinned «{text}»";
"lng_action_pinned_media" = "{from} pinned {media}"; "lng_action_pinned_media" = "{from} pinned {media}";
"lng_action_pinned_media_photo" = "a photo"; "lng_action_pinned_media_photo" = "a photo";

View File

@ -416,7 +416,7 @@ void ApiWrap::savePinnedOrder() {
const auto &order = _session->data().pinnedDialogsOrder(); const auto &order = _session->data().pinnedDialogsOrder();
auto peers = QVector<MTPInputDialogPeer>(); auto peers = QVector<MTPInputDialogPeer>();
peers.reserve(order.size()); peers.reserve(order.size());
for (const auto &pinned : base::reversed(order)) { for (const auto &pinned : ranges::view::reverse(order)) {
if (const auto history = pinned.history()) { if (const auto history = pinned.history()) {
peers.push_back(MTP_inputDialogPeer(history->peer->input)); peers.push_back(MTP_inputDialogPeer(history->peer->input));
} else if (const auto feed = pinned.feed()) { } else if (const auto feed = pinned.feed()) {
@ -708,7 +708,7 @@ void ApiWrap::requestDialogEntry(
MTP_vector(std::move(peers)) MTP_vector(std::move(peers))
)).done([=](const MTPmessages_PeerDialogs &result) { )).done([=](const MTPmessages_PeerDialogs &result) {
applyPeerDialogs(result); applyPeerDialogs(result);
historyDialogEntryApplied(history); history->dialogEntryApplied();
finalize(); finalize();
}).fail([=](const RPCError &error) { }).fail([=](const RPCError &error) {
finalize(); finalize();
@ -744,7 +744,7 @@ void ApiWrap::requestDialogEntries(
)).done([=](const MTPmessages_PeerDialogs &result) { )).done([=](const MTPmessages_PeerDialogs &result) {
applyPeerDialogs(result); applyPeerDialogs(result);
for (const auto history : histories) { for (const auto history : histories) {
historyDialogEntryApplied(history); history->dialogEntryApplied();
} }
finalize(histories); finalize(histories);
}).fail([=](const RPCError &error) { }).fail([=](const RPCError &error) {
@ -778,89 +778,41 @@ void ApiWrap::applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs) {
_session->data().sendHistoryChangeNotifications(); _session->data().sendHistoryChangeNotifications();
} }
void ApiWrap::historyDialogEntryApplied(not_null<History*> history) {
if (!history->lastMessage()) {
if (const auto chat = history->peer->asChat()) {
if (!chat->haveLeft()) {
Local::addSavedPeer(
history->peer,
ParseDateTime(history->chatsListTimeId()));
}
} 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);
}
return;
}
if (history->chatsListTimeId() != 0 && history->loadedAtBottom()) {
if (const auto channel = history->peer->asChannel()) {
const auto inviter = channel->inviter;
if (inviter != 0
&& history->chatsListTimeId() <= channel->inviteDate
&& channel->amIn()) {
if (const auto from = App::userLoaded(inviter)) {
history->insertJoinedMessage(true);
}
}
}
}
history->updateChatListExistence();
}
void ApiWrap::applyFeedDialogs( void ApiWrap::applyFeedDialogs(
not_null<Data::Feed*> feed, not_null<Data::Feed*> feed,
const MTPmessages_Dialogs &dialogs) { const MTPmessages_Dialogs &dialogs) {
const auto [dialogsList, messagesList] = [&] { if (dialogs.type() == mtpc_messages_dialogsNotModified) {
const auto process = [&](const auto &data) { LOG(("API Error: "
App::feedUsers(data.vusers); "messages.dialogsNotModified in ApiWrap::applyFeedDialogs."));
App::feedChats(data.vchats); return;
return std::make_tuple(&data.vdialogs.v, &data.vmessages.v); }
};
switch (dialogs.type()) {
case mtpc_messages_dialogs:
return process(dialogs.c_messages_dialogs());
case mtpc_messages_dialogsSlice:
LOG(("API Error: "
"Unexpected dialogsSlice in feed dialogs list."));
return process(dialogs.c_messages_dialogsSlice());
}
Unexpected("Type in DialogsWidget::dialogsReceived");
}();
App::feedMsgs(*messagesList, NewMessageLast);
auto channels = std::vector<not_null<ChannelData*>>(); auto channels = std::vector<not_null<ChannelData*>>();
channels.reserve(dialogsList->size()); dialogs.match([&](const MTPDmessages_dialogsNotModified &) {
for (const auto &dialog : *dialogsList) { Unexpected("Type in ApiWrap::applyFeedDialogs.");
switch (dialog.type()) { }, [&](const auto &data) {
case mtpc_dialog: { App::feedUsers(data.vusers);
if (const auto peerId = peerFromMTP(dialog.c_dialog().vpeer)) { App::feedChats(data.vchats);
if (peerIsChannel(peerId)) { App::feedMsgs(data.vmessages.v, NewMessageLast);
const auto history = App::history(peerId); channels.reserve(data.vdialogs.v.size());
history->applyDialog(dialog.c_dialog()); for (const auto &dialog : data.vdialogs.v) {
channels.emplace_back(history->peer->asChannel()); dialog.match([&](const MTPDdialog &data) {
} else { if (const auto peerId = peerFromMTP(data.vpeer)) {
LOG(("API Error: " if (peerIsChannel(peerId)) {
"Unexpected non-channel in feed dialogs list.")); const auto history = App::history(peerId);
history->applyDialog(dialog.c_dialog());
channels.emplace_back(history->peer->asChannel());
} else {
LOG(("API Error: "
"Unexpected peer in feed dialogs list."));
}
} }
} //}, [&](const MTPDdialogFeed &) { // #feed
} break; // LOG(("API Error: "
//case mtpc_dialogFeed: { // #feed // "Unexpected dialogFeed in feed dialogs list."));
// LOG(("API Error: Unexpected dialogFeed in feed dialogs list.")); });
//} break;
default: Unexpected("Type in DialogsInner::dialogsReceived");
} }
} });
feed->setChannels(channels); feed->setChannels(channels);
_session->data().sendHistoryChangeNotifications(); _session->data().sendHistoryChangeNotifications();
@ -878,6 +830,34 @@ void ApiWrap::changeDialogUnreadMark(
)).send(); )).send();
} }
void ApiWrap::requestFakeChatListMessage(
not_null<History*> history) {
if (_fakeChatListRequests.contains(history)) {
return;
}
_fakeChatListRequests.emplace(history);
request(MTPmessages_GetHistory(
history->peer->input,
MTP_int(0), // offset_id
MTP_int(0), // offset_date
MTP_int(0), // add_offset
MTP_int(2), // limit
MTP_int(0), // max_id
MTP_int(0), // min_id
MTP_int(0)
)).done([=](const MTPmessages_Messages &result) {
_fakeChatListRequests.erase(history);
history->setFakeChatListMessageFrom(result);
}).fail([=](const RPCError &error) {
_fakeChatListRequests.erase(history);
history->setFakeChatListMessageFrom(MTP_messages_messages(
MTP_vector<MTPMessage>(0),
MTP_vector<MTPChat>(0),
MTP_vector<MTPUser>(0)));
}).send();
}
void ApiWrap::requestFullPeer(not_null<PeerData*> peer) { void ApiWrap::requestFullPeer(not_null<PeerData*> peer) {
if (_fullPeerRequests.contains(peer)) { if (_fullPeerRequests.contains(peer)) {
return; return;
@ -1768,9 +1748,7 @@ void ApiWrap::deleteAllFromUserSend(
if (offset > 0) { if (offset > 0) {
deleteAllFromUserSend(channel, from); deleteAllFromUserSend(channel, from);
} else if (const auto history = App::historyLoaded(channel)) { } else if (const auto history = App::historyLoaded(channel)) {
if (!history->lastMessageKnown()) { history->requestChatListMessage();
requestDialogEntry(history);
}
} }
}).send(); }).send();
} }
@ -2303,9 +2281,11 @@ int ApiWrap::OnlineTillFromStatus(
void ApiWrap::clearHistory(not_null<PeerData*> peer) { void ApiWrap::clearHistory(not_null<PeerData*> peer) {
auto deleteTillId = MsgId(0); auto deleteTillId = MsgId(0);
if (auto history = App::historyLoaded(peer->id)) { if (const auto history = App::historyLoaded(peer->id)) {
if (const auto last = history->lastMessage()) { if (const auto last = history->lastMessage()) {
deleteTillId = last->id; deleteTillId = last->id;
}
if (const auto last = history->chatListMessage()) {
Local::addSavedPeer(history->peer, ItemDateTime(last)); Local::addSavedPeer(history->peer, ItemDateTime(last));
} }
history->clear(); history->clear();

View File

@ -90,6 +90,7 @@ public:
// const std::vector<not_null<ChannelData*>> &channels); // const std::vector<not_null<ChannelData*>> &channels);
void changeDialogUnreadMark(not_null<History*> history, bool unread); void changeDialogUnreadMark(not_null<History*> history, bool unread);
//void changeDialogUnreadMark(not_null<Data::Feed*> feed, bool unread); // #feed //void changeDialogUnreadMark(not_null<Data::Feed*> feed, bool unread); // #feed
void requestFakeChatListMessage(not_null<History*> history);
void requestFullPeer(not_null<PeerData*> peer); void requestFullPeer(not_null<PeerData*> peer);
void requestPeer(not_null<PeerData*> peer); void requestPeer(not_null<PeerData*> peer);
@ -428,7 +429,6 @@ private:
QVector<MTPInputMessage> collectMessageIds(const MessageDataRequests &requests); QVector<MTPInputMessage> 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 applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs);
void historyDialogEntryApplied(not_null<History*> history);
void applyFeedDialogs( void applyFeedDialogs(
not_null<Data::Feed*> feed, not_null<Data::Feed*> feed,
const MTPmessages_Dialogs &dialogs); const MTPmessages_Dialogs &dialogs);
@ -666,6 +666,7 @@ private:
base::flat_map< base::flat_map<
not_null<History*>, not_null<History*>,
std::vector<Fn<void()>>> _dialogRequests; std::vector<Fn<void()>>> _dialogRequests;
base::flat_set<not_null<History*>> _fakeChatListRequests;
base::flat_map<not_null<History*>, mtpRequestId> _unreadMentionsRequests; base::flat_map<not_null<History*>, mtpRequestId> _unreadMentionsRequests;

View File

@ -380,7 +380,7 @@ namespace App {
if (j != data->cend()) { if (j != data->cend()) {
const auto history = (*j)->history(); const auto history = (*j)->history();
(*j)->destroy(); (*j)->destroy();
if (!history->lastMessageKnown()) { if (!history->chatListMessageKnown()) {
historiesToCheck.emplace(history); historiesToCheck.emplace(history);
} }
} else if (affectedHistory) { } else if (affectedHistory) {
@ -388,7 +388,7 @@ namespace App {
} }
} }
for (const auto history : historiesToCheck) { for (const auto history : historiesToCheck) {
Auth().api().requestDialogEntry(history); history->requestChatListMessage();
} }
} }

View File

@ -24,6 +24,12 @@ inline constexpr size_t array_size(const Type(&)[Size]) {
return Size; return Size;
} }
template <typename Container, typename T>
inline bool contains(const Container &container, const T &value) {
const auto end = std::end(container);
return std::find(std::begin(container), end, value) != end;
}
} // namespace base } // namespace base
template <typename T> template <typename T>

View File

@ -605,25 +605,26 @@ void DeleteMessagesBox::deleteAndClear() {
_deleteConfirmedCallback(); _deleteConfirmedCallback();
} }
QMap<PeerData*, QVector<MTPint>> idsByPeer; base::flat_map<not_null<PeerData*>, QVector<MTPint>> idsByPeer;
for (const auto itemId : _ids) { for (const auto itemId : _ids) {
if (auto item = App::histItemById(itemId)) { if (const auto item = App::histItemById(itemId)) {
auto history = item->history(); const auto history = item->history();
auto wasOnServer = (item->id > 0); const auto wasOnServer = IsServerMsgId(item->id);
auto wasLast = (history->lastMessage() == item); const auto wasLast = (history->lastMessage() == item);
const auto wasInChats = (history->chatListMessage() == 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 && !history->lastMessageKnown()) { } else if (wasLast || wasInChats) {
history->session().api().requestDialogEntry(history); history->requestChatListMessage();
} }
} }
} }
auto forEveryone = _forEveryone ? _forEveryone->checked() : false; const auto revoke = _forEveryone ? _forEveryone->checked() : false;
for (auto i = idsByPeer.cbegin(), e = idsByPeer.cend(); i != e; ++i) { for (const auto &[peer, ids] : idsByPeer) {
App::main()->deleteMessages(i.key(), i.value(), forEveryone); App::main()->deleteMessages(peer, ids, revoke);
} }
Ui::hideLayer(); Ui::hideLayer();
Auth().data().sendHistoryChangeNotifications(); Auth().data().sendHistoryChangeNotifications();

View File

@ -435,7 +435,7 @@ void Options::removeEmptyTail() {
_list, _list,
&Option::hasFocus); &Option::hasFocus);
const auto end = _list.end(); const auto end = _list.end();
auto reversed = ranges::view::reverse(_list); const auto reversed = ranges::view::reverse(_list);
const auto emptyItem = ranges::find_if( const auto emptyItem = ranges::find_if(
reversed, reversed,
ranges::not_fn(&Option::isEmpty)).base(); ranges::not_fn(&Option::isEmpty)).base();

View File

@ -1830,7 +1830,7 @@ void SendFilesBox::updateControlsGeometry() {
_sendPhotos.data(), _sendPhotos.data(),
_sendFiles.data() _sendFiles.data()
}; };
for (auto pointer : base::reversed(pointers)) { for (const auto pointer : ranges::view::reverse(pointers)) {
if (pointer) { if (pointer) {
pointer->moveToLeft( pointer->moveToLeft(
st::boxPhotoPadding.left(), st::boxPhotoPadding.left(),

View File

@ -966,7 +966,7 @@ void ShareBox::Inner::updateFilter(QString filter) {
if (toFilter) { if (toFilter) {
_filtered.reserve(toFilter->size()); _filtered.reserve(toFilter->size());
for (const auto row : *toFilter) { for (const auto row : *toFilter) {
auto &nameWords = row->entry()->chatsListNameWords(); const auto &nameWords = row->entry()->chatListNameWords();
auto nb = nameWords.cbegin(), ne = nameWords.cend(), ni = nb; auto nb = nameWords.cbegin(), ne = nameWords.cend(), ni = nb;
for (fi = fb; fi != fe; ++fi) { for (fi = fb; fi != fe; ++fi) {
auto filterName = *fi; auto filterName = *fi;

View File

@ -36,12 +36,6 @@ inline constexpr D up_cast(T object) {
} }
} }
template <typename Container, typename T>
inline bool contains(const Container &container, const T &value) {
auto end = std::end(container);
return std::find(std::begin(container), end, value) != end;
}
// We need a custom comparator for std::set<std::unique_ptr<T>>::find to work with pointers. // We need a custom comparator for std::set<std::unique_ptr<T>>::find to work with pointers.
// thanks to http://stackoverflow.com/questions/18939882/raw-pointer-lookup-for-sets-of-unique-ptrs // thanks to http://stackoverflow.com/questions/18939882/raw-pointer-lookup-for-sets-of-unique-ptrs
template <typename T> template <typename T>
@ -86,28 +80,6 @@ using set_of_unique_ptr = std::set<std::unique_ptr<T>, base::pointer_comparator<
template <typename T> template <typename T>
using set_of_shared_ptr = std::set<std::shared_ptr<T>, base::pointer_comparator<T>>; using set_of_shared_ptr = std::set<std::shared_ptr<T>, base::pointer_comparator<T>>;
// Thanks https://stackoverflow.com/a/28139075
template <typename Container>
struct reversion_wrapper {
Container &container;
};
template <typename Container>
auto begin(reversion_wrapper<Container> wrapper) {
return std::rbegin(wrapper.container);
}
template <typename Container>
auto end(reversion_wrapper<Container> wrapper) {
return std::rend(wrapper.container);
}
template <typename Container>
reversion_wrapper<Container> reversed(Container &&container) {
return { container };
}
template <typename Value, typename From, typename Till> template <typename Value, typename From, typename Till>
inline bool in_range(Value &&value, From &&from, Till &&till) { inline bool in_range(Value &&value, From &&from, Till &&till) {
return (value >= from) && (value < till); return (value >= from) && (value < till);

View File

@ -31,14 +31,22 @@ namespace Data {
// data.vid.v)); // data.vid.v));
//} //}
Feed::Feed(FeedId id, not_null<Data::Session*> parent) Feed::Feed(not_null<Data::Session*> owner, FeedId id)
: Entry(this) : Entry(this)
, _id(id) , _id(id)
, _parent(parent) , _owner(owner)
, _name(lang(lng_feed_name)) { , _name(lang(lng_feed_name)) {
indexNameParts(); indexNameParts();
} }
Data::Session &Feed::owner() const {
return *_owner;
}
AuthSession &Feed::session() const {
return _owner->session();
}
FeedId Feed::id() const { FeedId Feed::id() const {
return _id; return _id;
} }
@ -74,17 +82,17 @@ 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);
_parent->session().storage().invalidate( session().storage().invalidate(
Storage::FeedMessagesInvalidate(_id)); Storage::FeedMessagesInvalidate(_id));
if (history->lastMessageKnown()) { if (history->chatListMessageKnown()) {
if (const auto last = history->lastMessage()) { if (const auto last = history->chatListMessage()) {
if (justUpdateLastMessage(last)) { if (justUpdateChatListMessage(last)) {
updateChatListEntry(); updateChatListEntry();
} }
} }
} else if (lastMessageKnown()) { } else if (chatListMessageKnown()) {
_parent->session().api().requestDialogEntry(history); history->requestChatListMessage();
} }
if (unreadCountKnown()) { if (unreadCountKnown()) {
if (history->unreadCountKnown()) { if (history->unreadCountKnown()) {
@ -96,7 +104,7 @@ void Feed::registerOne(not_null<ChannelData*> channel) {
unreadCountChanged(count, history->mute() ? count : 0); unreadCountChanged(count, history->mute() ? count : 0);
} }
} else if (!_settingChannels) { } else if (!_settingChannels) {
_parent->session().api().requestDialogEntry(this); session().api().requestDialogEntry(this);
} }
} }
if (invisible && _channels.size() > 1) { if (invisible && _channels.size() > 1) {
@ -107,7 +115,7 @@ void Feed::registerOne(not_null<ChannelData*> channel) {
} else { } else {
history->updateChatListExistence(); history->updateChatListExistence();
} }
_parent->notifyFeedUpdated(this, FeedUpdateFlag::Channels); _owner->notifyFeedUpdated(this, FeedUpdateFlag::Channels);
} }
} }
@ -117,13 +125,13 @@ 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));
_parent->session().storage().remove( session().storage().remove(
Storage::FeedMessagesRemoveAll(_id, channel->bareId())); Storage::FeedMessagesRemoveAll(_id, channel->bareId()));
if (lastMessageKnown()) { if (chatListMessageKnown()) {
if (const auto last = lastMessage()) { if (const auto last = chatListMessage()) {
if (last->history() == history) { if (last->history() == history) {
recountLastMessage(); recountChatListMessage();
} }
} }
} }
@ -133,7 +141,7 @@ void Feed::unregisterOne(not_null<ChannelData*> channel) {
unreadCountChanged(delta, history->mute() ? delta : 0); unreadCountChanged(delta, history->mute() ? delta : 0);
} }
} else { } else {
_parent->session().api().requestDialogEntry(this); session().api().requestDialogEntry(this);
} }
} }
if (visible && _channels.size() < 2) { if (visible && _channels.size() < 2) {
@ -144,14 +152,14 @@ void Feed::unregisterOne(not_null<ChannelData*> channel) {
} else { } else {
history->updateChatListExistence(); history->updateChatListExistence();
} }
_parent->notifyFeedUpdated(this, FeedUpdateFlag::Channels); _owner->notifyFeedUpdated(this, FeedUpdateFlag::Channels);
} }
} }
void Feed::updateLastMessage(not_null<HistoryItem*> item) { void Feed::updateChatListMessage(not_null<HistoryItem*> item) {
if (justUpdateLastMessage(item)) { if (justUpdateChatListMessage(item)) {
if (_lastMessage && *_lastMessage) { if (_chatListMessage && *_chatListMessage) {
setChatsListTimeId((*_lastMessage)->date()); setChatListTimeId((*_chatListMessage)->date());
} }
} }
} }
@ -206,7 +214,7 @@ bool Feed::channelsLoaded() const {
void Feed::setChannelsLoaded(bool loaded) { void Feed::setChannelsLoaded(bool loaded) {
if (_channelsLoaded != loaded) { if (_channelsLoaded != loaded) {
_channelsLoaded = loaded; _channelsLoaded = loaded;
_parent->notifyFeedUpdated(this, FeedUpdateFlag::Channels); _owner->notifyFeedUpdated(this, FeedUpdateFlag::Channels);
} }
} }
@ -249,74 +257,72 @@ void Feed::changeChannelsList(
// We assume the last message was correct before requesting the list. // We assume the last message was correct before requesting the list.
// So we save it and don't allow channels from the list to change it. // So we save it and don't allow channels from the list to change it.
// After that we restore it. // After that we restore it.
const auto oldLastMessage = base::take(_lastMessage); const auto oldChatListMessage = base::take(_chatListMessage);
for (const auto channel : add) { for (const auto channel : add) {
_lastMessage = std::nullopt; _chatListMessage = std::nullopt;
channel->setFeed(this); channel->setFeed(this);
} }
_lastMessage = oldLastMessage; _chatListMessage = oldChatListMessage;
} }
bool Feed::justUpdateLastMessage(not_null<HistoryItem*> item) { bool Feed::justUpdateChatListMessage(not_null<HistoryItem*> item) {
if (!_lastMessage) { if (!_chatListMessage) {
return false; return false;
} else if (*_lastMessage } else if (*_chatListMessage
&& item->position() <= (*_lastMessage)->position()) { && item->position() <= (*_chatListMessage)->position()) {
return false; return false;
} }
_lastMessage = item; _chatListMessage = item;
return true; return true;
} }
void Feed::messageRemoved(not_null<HistoryItem*> item) { void Feed::messageRemoved(not_null<HistoryItem*> item) {
if (lastMessage() == item) { if (chatListMessage() == item) {
recountLastMessage(); recountChatListMessage();
} }
} }
void Feed::historyCleared(not_null<History*> history) { void Feed::historyCleared(not_null<History*> history) {
if (const auto last = lastMessage()) { if (const auto last = chatListMessage()) {
if (last->history() == history) { if (last->history() == history) {
messageRemoved(last); messageRemoved(last);
} }
} }
} }
void Feed::recountLastMessage() { void Feed::requestChatListMessage() {
_lastMessage = std::nullopt; if (!chatListMessageKnown()) {
session().api().requestDialogEntry(this);
}
}
void Feed::recountChatListMessage() {
_chatListMessage = std::nullopt;
for (const auto history : _channels) { for (const auto history : _channels) {
if (!history->lastMessageKnown()) { if (!history->chatListMessageKnown()) {
_parent->session().api().requestDialogEntry(this); requestChatListMessage();
return; return;
} }
} }
setLastMessageFromChannels(); setChatListMessageFromChannels();
} }
void Feed::setLastMessageFromChannels() { void Feed::setChatListMessageFromChannels() {
_lastMessage = nullptr; _chatListMessage = nullptr;
for (const auto history : _channels) { for (const auto history : _channels) {
if (const auto last = history->lastMessage()) { if (const auto last = history->chatListMessage()) {
justUpdateLastMessage(last); justUpdateChatListMessage(last);
} }
} }
updateChatsListDate(); updateChatListDate();
} }
void Feed::updateChatsListDate() { void Feed::updateChatListDate() {
if (_lastMessage && *_lastMessage) { if (_chatListMessage && *_chatListMessage) {
setChatsListTimeId((*_lastMessage)->date()); setChatListTimeId((*_chatListMessage)->date());
} }
} }
HistoryItem *Feed::lastMessage() const {
return _lastMessage ? *_lastMessage : nullptr;
}
bool Feed::lastMessageKnown() const {
return !!_lastMessage;
}
int Feed::unreadCount() const { int Feed::unreadCount() const {
return _unreadCount ? *_unreadCount : 0; return _unreadCount ? *_unreadCount : 0;
} }
@ -341,17 +347,17 @@ bool Feed::unreadCountKnown() const {
// addChannel(channelId.v); // addChannel(channelId.v);
// } // }
// //
// _lastMessage = nullptr; // _chatListMessage = nullptr;
// if (const auto peerId = peerFromMTP(data.vpeer)) { // if (const auto peerId = peerFromMTP(data.vpeer)) {
// if (const auto channelId = peerToChannel(peerId)) { // if (const auto channelId = peerToChannel(peerId)) {
// addChannel(channelId); // addChannel(channelId);
// const auto fullId = FullMsgId(channelId, data.vtop_message.v); // const auto fullId = FullMsgId(channelId, data.vtop_message.v);
// if (const auto item = App::histItemById(fullId)) { // if (const auto item = App::histItemById(fullId)) {
// justUpdateLastMessage(item); // justUpdateChatListMessage(item);
// } // }
// } // }
// } // }
// updateChatsListDate(); // updateChatListDate();
// //
// setUnreadCounts( // setUnreadCounts(
// data.vunread_count.v, // data.vunread_count.v,
@ -493,19 +499,23 @@ bool Feed::chatListMutedBadge() const {
return _unreadCount ? (*_unreadCount <= _unreadMutedCount) : false; return _unreadCount ? (*_unreadCount <= _unreadMutedCount) : false;
} }
HistoryItem *Feed::chatsListItem() const { HistoryItem *Feed::chatListMessage() const {
return lastMessage(); return _chatListMessage ? *_chatListMessage : nullptr;
} }
const QString &Feed::chatsListName() const { bool Feed::chatListMessageKnown() const {
return _chatListMessage.has_value();
}
const QString &Feed::chatListName() const {
return _name; return _name;
} }
const base::flat_set<QString> &Feed::chatsListNameWords() const { const base::flat_set<QString> &Feed::chatListNameWords() const {
return _nameWords; return _nameWords;
} }
const base::flat_set<QChar> &Feed::chatsListFirstLetters() const { const base::flat_set<QChar> &Feed::chatListFirstLetters() const {
return _nameFirstLetters; return _nameFirstLetters;
} }

View File

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_messages.h" #include "data/data_messages.h"
class ChannelData; class ChannelData;
class AuthSession;
namespace Data { namespace Data {
@ -34,13 +35,18 @@ public:
static constexpr auto kId = 1; static constexpr auto kId = 1;
static constexpr auto kChannelsLimit = 1000; static constexpr auto kChannelsLimit = 1000;
Feed(FeedId id, not_null<Data::Session*> parent); Feed(not_null<Data::Session*> owner, FeedId id);
Feed(const Feed &) = delete;
Feed &operator=(const Feed &) = delete;
Data::Session &owner() const;
AuthSession &session() const;
FeedId id() const; FeedId id() const;
void registerOne(not_null<ChannelData*> channel); void registerOne(not_null<ChannelData*> channel);
void unregisterOne(not_null<ChannelData*> channel); void unregisterOne(not_null<ChannelData*> channel);
void updateLastMessage(not_null<HistoryItem*> item); void updateChatListMessage(not_null<HistoryItem*> item);
void messageRemoved(not_null<HistoryItem*> item); void messageRemoved(not_null<HistoryItem*> item);
void historyCleared(not_null<History*> history); void historyCleared(not_null<History*> history);
@ -54,8 +60,6 @@ public:
MessagePosition unreadPosition() const; MessagePosition unreadPosition() const;
rpl::producer<MessagePosition> unreadPositionChanges() const; rpl::producer<MessagePosition> unreadPositionChanges() const;
HistoryItem *lastMessage() const;
bool lastMessageKnown() const;
int unreadCount() const; int unreadCount() const;
bool unreadCountKnown() const; bool unreadCountKnown() const;
@ -65,10 +69,12 @@ public:
int chatListUnreadCount() const override; int chatListUnreadCount() const override;
bool chatListUnreadMark() const override; bool chatListUnreadMark() const override;
bool chatListMutedBadge() const override; bool chatListMutedBadge() const override;
HistoryItem *chatsListItem() const override; HistoryItem *chatListMessage() const override;
const QString &chatsListName() const override; bool chatListMessageKnown() const override;
const base::flat_set<QString> &chatsListNameWords() const override; void requestChatListMessage() override;
const base::flat_set<QChar> &chatsListFirstLetters() const override; const QString &chatListName() const override;
const base::flat_set<QString> &chatListNameWords() const override;
const base::flat_set<QChar> &chatListFirstLetters() const override;
void changedInChatListHook(Dialogs::Mode list, bool added) override; void changedInChatListHook(Dialogs::Mode list, bool added) override;
void loadUserpic() override; void loadUserpic() override;
@ -86,10 +92,10 @@ public:
private: private:
void indexNameParts(); void indexNameParts();
void recountLastMessage(); void recountChatListMessage();
void setLastMessageFromChannels(); void setChatListMessageFromChannels();
bool justUpdateLastMessage(not_null<HistoryItem*> item); bool justUpdateChatListMessage(not_null<HistoryItem*> item);
void updateChatsListDate(); void updateChatListDate();
void changeChannelsList( void changeChannelsList(
const std::vector<not_null<ChannelData*>> &add, const std::vector<not_null<ChannelData*>> &add,
const std::vector<not_null<ChannelData*>> &remove); const std::vector<not_null<ChannelData*>> &remove);
@ -98,7 +104,7 @@ private:
void updateUnreadCounts(PerformUpdate &&performUpdate); void updateUnreadCounts(PerformUpdate &&performUpdate);
FeedId _id = 0; FeedId _id = 0;
not_null<Data::Session*> _parent; not_null<Data::Session*> _owner;
std::vector<not_null<History*>> _channels; std::vector<not_null<History*>> _channels;
bool _settingChannels = false; bool _settingChannels = false;
bool _channelsLoaded = false; bool _channelsLoaded = false;
@ -106,7 +112,7 @@ 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;
std::optional<HistoryItem*> _lastMessage; std::optional<HistoryItem*> _chatListMessage;
rpl::variable<MessagePosition> _unreadPosition; rpl::variable<MessagePosition> _unreadPosition;
std::optional<int> _unreadCount; std::optional<int> _unreadCount;

View File

@ -187,7 +187,7 @@ bool Media::canBeGrouped() const {
return false; return false;
} }
QString Media::chatsListText() const { QString Media::chatListText() const {
auto result = notificationText(); auto result = notificationText();
return result.isEmpty() return result.isEmpty()
? QString() ? QString()
@ -304,7 +304,7 @@ QString MediaPhoto::notificationText() const {
//return WithCaptionNotificationText(lang(lng_in_dlg_album), _caption); //return WithCaptionNotificationText(lang(lng_in_dlg_album), _caption);
} }
QString MediaPhoto::chatsListText() const { QString MediaPhoto::chatListText() const {
return WithCaptionDialogsText( return WithCaptionDialogsText(
lang(lng_in_dlg_photo), lang(lng_in_dlg_photo),
parent()->originalText().text); parent()->originalText().text);
@ -539,9 +539,9 @@ Image *MediaFile::replyPreview() const {
return _document->getReplyPreview(parent()->fullId()); return _document->getReplyPreview(parent()->fullId());
} }
QString MediaFile::chatsListText() const { QString MediaFile::chatListText() const {
if (const auto sticker = _document->sticker()) { if (const auto sticker = _document->sticker()) {
return Media::chatsListText(); return Media::chatListText();
} }
const auto type = [&] { const auto type = [&] {
if (_document->isVideoMessage()) { if (_document->isVideoMessage()) {
@ -861,7 +861,7 @@ LocationData *MediaLocation::location() const {
return _location; return _location;
} }
QString MediaLocation::chatsListText() const { QString MediaLocation::chatListText() const {
return WithCaptionDialogsText(lang(lng_maps_point), _title); return WithCaptionDialogsText(lang(lng_maps_point), _title);
} }
@ -1032,7 +1032,7 @@ Image *MediaWebPage::replyPreview() const {
return nullptr; return nullptr;
} }
QString MediaWebPage::chatsListText() const { QString MediaWebPage::chatListText() const {
return notificationText(); return notificationText();
} }

View File

@ -86,7 +86,7 @@ public:
virtual Image *replyPreview() const; virtual Image *replyPreview() const;
// Returns text with link-start and link-end commands for service-color highlighting. // Returns text with link-start and link-end commands for service-color highlighting.
// Example: "[link1-start]You:[link1-end] [link1-start]Photo,[link1-end] caption text" // Example: "[link1-start]You:[link1-end] [link1-start]Photo,[link1-end] caption text"
virtual QString chatsListText() const; virtual QString chatListText() const;
virtual QString notificationText() const = 0; virtual QString notificationText() const = 0;
virtual QString pinnedTextSubstring() const = 0; virtual QString pinnedTextSubstring() const = 0;
virtual TextWithEntities clipboardText() const = 0; virtual TextWithEntities clipboardText() const = 0;
@ -136,7 +136,7 @@ public:
bool canBeGrouped() const override; bool canBeGrouped() const override;
bool hasReplyPreview() const override; bool hasReplyPreview() const override;
Image *replyPreview() const override; Image *replyPreview() const override;
QString chatsListText() const override; QString chatListText() const override;
QString notificationText() const override; QString notificationText() const override;
QString pinnedTextSubstring() const override; QString pinnedTextSubstring() const override;
TextWithEntities clipboardText() const override; TextWithEntities clipboardText() const override;
@ -171,7 +171,7 @@ public:
bool canBeGrouped() const override; bool canBeGrouped() const override;
bool hasReplyPreview() const override; bool hasReplyPreview() const override;
Image *replyPreview() const override; Image *replyPreview() const override;
QString chatsListText() const override; QString chatListText() const override;
QString notificationText() const override; QString notificationText() const override;
QString pinnedTextSubstring() const override; QString pinnedTextSubstring() const override;
TextWithEntities clipboardText() const override; TextWithEntities clipboardText() const override;
@ -233,7 +233,7 @@ public:
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override; std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
LocationData *location() const override; LocationData *location() const override;
QString chatsListText() const override; QString chatListText() const override;
QString notificationText() const override; QString notificationText() const override;
QString pinnedTextSubstring() const override; QString pinnedTextSubstring() const override;
TextWithEntities clipboardText() const override; TextWithEntities clipboardText() const override;
@ -296,7 +296,7 @@ public:
bool hasReplyPreview() const override; bool hasReplyPreview() const override;
Image *replyPreview() const override; Image *replyPreview() const override;
QString chatsListText() const override; QString chatListText() const override;
QString notificationText() const override; QString notificationText() const override;
QString pinnedTextSubstring() const override; QString pinnedTextSubstring() const override;
TextWithEntities clipboardText() const override; TextWithEntities clipboardText() const override;

View File

@ -2759,7 +2759,7 @@ not_null<Feed*> Session::feed(FeedId id) {
} }
const auto [it, ok] = _feeds.emplace( const auto [it, ok] = _feeds.emplace(
id, id,
std::make_unique<Feed>(id, this)); std::make_unique<Feed>(this, id));
return it->second.get(); return it->second.get();
} }
@ -3038,9 +3038,7 @@ void Session::setProxyPromoted(PeerData *promoted) {
if (_proxyPromoted) { if (_proxyPromoted) {
const auto history = this->history(_proxyPromoted); const auto history = this->history(_proxyPromoted);
history->cacheProxyPromoted(true); history->cacheProxyPromoted(true);
if (!history->lastMessageKnown()) { history->requestChatListMessage();
_session->api().requestDialogEntry(history);
}
Notify::peerUpdatedDelayed( Notify::peerUpdatedDelayed(
_proxyPromoted, _proxyPromoted,
Notify::PeerUpdate::Flag::ChannelPromotedChanged); Notify::PeerUpdate::Flag::ChannelPromotedChanged);

View File

@ -102,7 +102,7 @@ void Entry::setChatListExistence(bool exists) {
} }
TimeId Entry::adjustChatListTimeId() const { TimeId Entry::adjustChatListTimeId() const {
return chatsListTimeId(); return chatListTimeId();
} }
void Entry::changedInChatListHook(Dialogs::Mode list, bool added) { void Entry::changedInChatListHook(Dialogs::Mode list, bool added) {
@ -135,13 +135,13 @@ PositionChange Entry::adjustByPosInChatList(
return { movedFrom, movedTo }; return { movedFrom, movedTo };
} }
void Entry::setChatsListTimeId(TimeId date) { void Entry::setChatListTimeId(TimeId date) {
if (_lastMessageTimeId && _lastMessageTimeId >= date) { if (_timeId && _timeId >= date) {
if (!inChatList(Dialogs::Mode::All)) { if (!inChatList(Dialogs::Mode::All)) {
return; return;
} }
} }
_lastMessageTimeId = date; _timeId = date;
updateChatListSortPosition(); updateChatListSortPosition();
} }

View File

@ -65,7 +65,7 @@ public:
return _sortKeyInChatList; return _sortKeyInChatList;
} }
void updateChatListSortPosition(); void updateChatListSortPosition();
void setChatsListTimeId(TimeId date); void setChatListTimeId(TimeId date);
virtual void updateChatListExistence(); virtual void updateChatListExistence();
bool needUpdateInChatList() const; bool needUpdateInChatList() const;
@ -74,10 +74,12 @@ public:
virtual int chatListUnreadCount() const = 0; virtual int chatListUnreadCount() const = 0;
virtual bool chatListUnreadMark() const = 0; virtual bool chatListUnreadMark() const = 0;
virtual bool chatListMutedBadge() const = 0; virtual bool chatListMutedBadge() const = 0;
virtual HistoryItem *chatsListItem() const = 0; virtual HistoryItem *chatListMessage() const = 0;
virtual const QString &chatsListName() const = 0; virtual bool chatListMessageKnown() const = 0;
virtual const base::flat_set<QString> &chatsListNameWords() const = 0; virtual void requestChatListMessage() = 0;
virtual const base::flat_set<QChar> &chatsListFirstLetters() const = 0; virtual const QString &chatListName() const = 0;
virtual const base::flat_set<QString> &chatListNameWords() const = 0;
virtual const base::flat_set<QChar> &chatListFirstLetters() const = 0;
virtual void loadUserpic() = 0; virtual void loadUserpic() = 0;
virtual void paintUserpic( virtual void paintUserpic(
@ -94,8 +96,8 @@ public:
paintUserpic(p, rtl() ? (w - x - size) : x, y, size); paintUserpic(p, rtl() ? (w - x - size) : x, y, size);
} }
TimeId chatsListTimeId() const { TimeId chatListTimeId() const {
return _lastMessageTimeId; return _timeId;
} }
virtual ~Entry() = default; virtual ~Entry() = default;
@ -118,7 +120,7 @@ private:
uint64 _sortKeyInChatList = 0; uint64 _sortKeyInChatList = 0;
int _pinnedIndex = 0; int _pinnedIndex = 0;
bool _isProxyPromoted = false; bool _isProxyPromoted = false;
TimeId _lastMessageTimeId = 0; TimeId _timeId = 0;
}; };

View File

@ -23,7 +23,7 @@ RowsByLetter IndexedList::addToEnd(Key key) {
RowsByLetter result; RowsByLetter result;
if (!_list.contains(key)) { if (!_list.contains(key)) {
result.emplace(0, _list.addToEnd(key)); result.emplace(0, _list.addToEnd(key));
for (auto ch : key.entry()->chatsListFirstLetters()) { for (const auto ch : key.entry()->chatListFirstLetters()) {
auto j = _index.find(ch); auto j = _index.find(ch);
if (j == _index.cend()) { if (j == _index.cend()) {
j = _index.emplace( j = _index.emplace(
@ -42,7 +42,7 @@ Row *IndexedList::addByName(Key key) {
} }
Row *result = _list.addByName(key); Row *result = _list.addByName(key);
for (auto ch : key.entry()->chatsListFirstLetters()) { for (const auto ch : key.entry()->chatListFirstLetters()) {
auto j = _index.find(ch); auto j = _index.find(ch);
if (j == _index.cend()) { if (j == _index.cend()) {
j = _index.emplace( j = _index.emplace(
@ -68,7 +68,7 @@ void IndexedList::adjustByPos(const RowsByLetter &links) {
void IndexedList::moveToTop(Key key) { void IndexedList::moveToTop(Key key) {
if (_list.moveToTop(key)) { if (_list.moveToTop(key)) {
for (auto ch : key.entry()->chatsListFirstLetters()) { for (const auto ch : key.entry()->chatListFirstLetters()) {
if (auto it = _index.find(ch); it != _index.cend()) { if (auto it = _index.find(ch); it != _index.cend()) {
it->second->moveToTop(key); it->second->moveToTop(key);
} }
@ -123,7 +123,7 @@ void IndexedList::adjustByName(
auto toRemove = oldLetters; auto toRemove = oldLetters;
auto toAdd = base::flat_set<QChar>(); auto toAdd = base::flat_set<QChar>();
for (auto ch : key.entry()->chatsListFirstLetters()) { for (const auto ch : key.entry()->chatListFirstLetters()) {
auto j = toRemove.find(ch); auto j = toRemove.find(ch);
if (j == toRemove.cend()) { if (j == toRemove.cend()) {
toAdd.insert(ch); toAdd.insert(ch);
@ -162,7 +162,7 @@ void IndexedList::adjustNames(
auto toRemove = oldLetters; auto toRemove = oldLetters;
auto toAdd = base::flat_set<QChar>(); auto toAdd = base::flat_set<QChar>();
for (auto ch : key.entry()->chatsListFirstLetters()) { for (const auto ch : key.entry()->chatListFirstLetters()) {
auto j = toRemove.find(ch); auto j = toRemove.find(ch);
if (j == toRemove.cend()) { if (j == toRemove.cend()) {
toAdd.insert(ch); toAdd.insert(ch);
@ -194,7 +194,7 @@ void IndexedList::adjustNames(
void IndexedList::del(Key key, Row *replacedBy) { void IndexedList::del(Key key, Row *replacedBy) {
if (_list.del(key, replacedBy)) { if (_list.del(key, replacedBy)) {
for (auto ch : key.entry()->chatsListFirstLetters()) { for (const auto ch : key.entry()->chatListFirstLetters()) {
if (auto it = _index.find(ch); it != _index.cend()) { if (auto it = _index.find(ch); it != _index.cend()) {
it->second->del(key, replacedBy); it->second->del(key, replacedBy);
} }

View File

@ -1702,7 +1702,7 @@ void DialogsInner::applyFilterUpdate(QString newFilter, bool force) {
+ (toFilterContacts ? toFilterContacts->size() : 0)); + (toFilterContacts ? toFilterContacts->size() : 0));
if (toFilter) { if (toFilter) {
for (const auto row : *toFilter) { for (const auto row : *toFilter) {
const auto &nameWords = row->entry()->chatsListNameWords(); const auto &nameWords = row->entry()->chatListNameWords();
auto nb = nameWords.cbegin(), ne = nameWords.cend(), ni = nb; auto nb = nameWords.cbegin(), ne = nameWords.cend(), ni = nb;
for (fi = fb; fi != fe; ++fi) { for (fi = fb; fi != fe; ++fi) {
auto filterWord = *fi; auto filterWord = *fi;
@ -1722,7 +1722,7 @@ void DialogsInner::applyFilterUpdate(QString newFilter, bool force) {
} }
if (toFilterContacts) { if (toFilterContacts) {
for (const auto row : *toFilterContacts) { for (const auto row : *toFilterContacts) {
const auto &nameWords = row->entry()->chatsListNameWords(); const auto &nameWords = row->entry()->chatListNameWords();
auto nb = nameWords.cbegin(), ne = nameWords.cend(), ni = nb; auto nb = nameWords.cbegin(), ne = nameWords.cend(), ni = nb;
for (fi = fb; fi != fe; ++fi) { for (fi = fb; fi != fe; ++fi) {
auto filterWord = *fi; auto filterWord = *fi;
@ -1875,7 +1875,7 @@ void DialogsInner::applyDialog(const MTPDdialog &dialog) {
history->applyDialog(dialog); history->applyDialog(dialog);
if (!history->useProxyPromotion() && !history->isPinnedDialog()) { if (!history->useProxyPromotion() && !history->isPinnedDialog()) {
const auto date = history->chatsListTimeId(); const auto date = history->chatListTimeId();
if (date != 0) { if (date != 0) {
addSavedPeersAfter(ParseDateTime(date)); addSavedPeersAfter(ParseDateTime(date));
} }
@ -1898,7 +1898,7 @@ void DialogsInner::applyDialog(const MTPDdialog &dialog) {
// feed->applyDialog(dialog); // feed->applyDialog(dialog);
// //
// if (!feed->useProxyPromotion() && !feed->isPinnedDialog()) { // if (!feed->useProxyPromotion() && !feed->isPinnedDialog()) {
// const auto date = feed->chatsListDate(); // const auto date = feed->chatListDate();
// if (!date.isNull()) { // if (!date.isNull()) {
// addSavedPeersAfter(date); // addSavedPeersAfter(date);
// } // }
@ -1913,7 +1913,7 @@ void DialogsInner::addSavedPeersAfter(const QDateTime &date) {
saved.remove(lastDate, lastPeer); saved.remove(lastDate, lastPeer);
const auto history = App::history(lastPeer); const auto history = App::history(lastPeer);
history->setChatsListTimeId(ServerTimeFromParsed(lastDate)); history->setChatListTimeId(ServerTimeFromParsed(lastDate));
_contactsNoDialogs->del(history); _contactsNoDialogs->del(history);
} }
} }
@ -2233,7 +2233,7 @@ void DialogsInner::refreshSearchInChatLabel() {
} }
return peer->name; return peer->name;
} else if (const auto feed = _searchInChat.feed()) { } else if (const auto feed = _searchInChat.feed()) {
return feed->chatsListName(); return feed->chatListName();
} }
return QString(); return QString();
}(); }();

View File

@ -377,7 +377,7 @@ void paintRow(
from->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); from->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
} else { } else {
p.setFont(st::msgNameFont); p.setFont(st::msgNameFont);
auto text = entry->chatsListName(); // TODO feed name with emoji auto text = entry->chatListName(); // TODO feed name with emoji
auto textWidth = st::msgNameFont->width(text); auto textWidth = st::msgNameFont->width(text);
if (textWidth > rectForName.width()) { if (textWidth > rectForName.width()) {
text = st::msgNameFont->elided(text, rectForName.width()); text = st::msgNameFont->elided(text, rectForName.width());
@ -528,7 +528,7 @@ void RowPainter::paint(
const auto unreadCount = entry->chatListUnreadCount(); const auto unreadCount = entry->chatListUnreadCount();
const auto unreadMark = entry->chatListUnreadMark(); const auto unreadMark = entry->chatListUnreadMark();
const auto unreadMuted = entry->chatListMutedBadge(); const auto unreadMuted = entry->chatListMutedBadge();
const auto item = entry->chatsListItem(); const auto item = entry->chatListMessage();
const auto cloudDraft = [&]() -> const Data::Draft*{ const auto cloudDraft = [&]() -> const Data::Draft*{
if (history && (!item || (!unreadCount && !unreadMark))) { if (history && (!item || (!unreadCount && !unreadMark))) {
// Draw item, if there are unread messages. // Draw item, if there are unread messages.

View File

@ -114,15 +114,15 @@ Row *List::adjustByName(Key key) {
if (i == _rowByKey.cend()) return nullptr; if (i == _rowByKey.cend()) return nullptr;
const auto row = i->second; const auto row = i->second;
const auto name = key.entry()->chatsListName(); const auto name = key.entry()->chatListName();
auto change = row; auto change = row;
while (change->_prev while (change->_prev
&& change->_prev->entry()->chatsListName().compare(name, Qt::CaseInsensitive) < 0) { && change->_prev->entry()->chatListName().compare(name, Qt::CaseInsensitive) < 0) {
change = change->_prev; change = change->_prev;
} }
if (!insertBefore(row, change)) { if (!insertBefore(row, change)) {
while (change->_next != _end while (change->_next != _end
&& change->_next->entry()->chatsListName().compare(name, Qt::CaseInsensitive) < 0) { && change->_next->entry()->chatListName().compare(name, Qt::CaseInsensitive) < 0) {
change = change->_next; change = change->_next;
} }
insertAfter(row, change); insertAfter(row, change);
@ -137,14 +137,14 @@ Row *List::addByName(Key key) {
const auto row = addToEnd(key); const auto row = addToEnd(key);
auto change = row; auto change = row;
const auto name = key.entry()->chatsListName(); const auto name = key.entry()->chatListName();
while (change->_prev while (change->_prev
&& change->_prev->entry()->chatsListName().compare(name, Qt::CaseInsensitive) > 0) { && change->_prev->entry()->chatListName().compare(name, Qt::CaseInsensitive) > 0) {
change = change->_prev; change = change->_prev;
} }
if (!insertBefore(row, change)) { if (!insertBefore(row, change)) {
while (change->_next != _end while (change->_next != _end
&& change->_next->entry()->chatsListName().compare(name, Qt::CaseInsensitive) < 0) { && change->_next->entry()->chatListName().compare(name, Qt::CaseInsensitive) < 0) {
change = change->_next; change = change->_next;
} }
insertAfter(row, change); insertAfter(row, change);

View File

@ -716,7 +716,7 @@ int InnerWidget::resizeGetHeight(int newWidth) {
const auto resizeAllItems = (_itemsWidth != newWidth); const auto resizeAllItems = (_itemsWidth != newWidth);
auto newHeight = 0; auto newHeight = 0;
for (auto &item : base::reversed(_items)) { for (const auto &item : ranges::view::reverse(_items)) {
item->setY(newHeight); item->setY(newHeight);
if (item->pendingResize() || resizeAllItems) { if (item->pendingResize() || resizeAllItems) {
newHeight += item->resizeGetHeight(newWidth); newHeight += item->resizeGetHeight(newWidth);

View File

@ -60,9 +60,9 @@ constexpr auto kSkipCloudDraftsFor = TimeId(3);
} // namespace } // namespace
History::History(not_null<Data::Session*> owner, const PeerId &peerId) History::History(not_null<Data::Session*> owner, PeerId peerId)
: Entry(this) : Entry(this)
, peer(App::peer(peerId)) , peer(owner->peer(peerId))
, cloudDraftTextCache(st::dialogsTextWidthMin) , cloudDraftTextCache(st::dialogsTextWidthMin)
, _owner(owner) , _owner(owner)
, _mute(_owner->notifyIsMuted(peer)) , _mute(_owner->notifyIsMuted(peer))
@ -138,15 +138,31 @@ void History::itemRemoved(not_null<HistoryItem*> item) {
setLastMessage(last); setLastMessage(last);
} }
} }
if (const auto channel = peer->asChannel()) { }
if (const auto feed = channel->feed()) { checkChatListMessageRemoved(item);
// Must be after history->lastMessage() is updated. itemVanished(item);
// Otherwise feed last message will be this value again. if (const auto chat = peer->asChat()) {
feed->messageRemoved(item); if (const auto to = chat->getMigrateToChannel()) {
if (const auto history = owner().historyLoaded(to)) {
history->checkChatListMessageRemoved(item);
} }
} }
} }
itemVanished(item); }
void History::checkChatListMessageRemoved(not_null<HistoryItem*> item) {
if (chatListMessage() != item) {
return;
}
_chatListMessage = std::nullopt;
refreshChatListMessage();
if (const auto channel = peer->asChannel()) {
if (const auto feed = channel->feed()) {
// Must be after history->chatListMessage() is updated.
// Otherwise feed last message will be this value again.
feed->messageRemoved(item);
}
}
} }
void History::itemVanished(not_null<HistoryItem*> item) { void History::itemVanished(not_null<HistoryItem*> item) {
@ -1130,7 +1146,7 @@ void History::newItemAdded(not_null<HistoryItem*> item) {
notifies.push_back(item); notifies.push_back(item);
App::main()->newUnreadMsg(this, item); App::main()->newUnreadMsg(this, item);
} }
} else if (!item->isGroupMigrate() || !peer->isMegagroup()) { } else {
inboxRead(item); inboxRead(item);
} }
} }
@ -1285,7 +1301,7 @@ void History::addItemsToLists(
// lastParticipants are displayed in Profile as members list. // lastParticipants are displayed in Profile as members list.
markupSenders = &peer->asChannel()->mgInfo->markupSenders; markupSenders = &peer->asChannel()->mgInfo->markupSenders;
} }
for (const auto item : base::reversed(items)) { for (const auto item : ranges::view::reverse(items)) {
item->addToUnreadMentions(UnreadMentionType::Existing); item->addToUnreadMentions(UnreadMentionType::Existing);
if (item->from()->id) { if (item->from()->id) {
if (lastAuthors) { // chats if (lastAuthors) { // chats
@ -1465,7 +1481,7 @@ void History::inboxRead(not_null<const HistoryItem*> wasRead) {
void History::outboxRead(MsgId upTo) { void History::outboxRead(MsgId upTo) {
setOutboxReadTill(upTo); setOutboxReadTill(upTo);
if (const auto last = lastMessage()) { if (const auto last = chatListMessage()) {
if (last->out() && IsServerMsgId(last->id) && last->id <= upTo) { if (last->out() && IsServerMsgId(last->id) && last->id <= upTo) {
if (const auto main = App::main()) { if (const auto main = App::main()) {
main->repaintDialogRow({ this, last->fullId() }); main->repaintDialogRow({ this, last->fullId() });
@ -1701,7 +1717,7 @@ std::shared_ptr<AdminLog::LocalIdManager> History::adminLogIdManager() {
} }
TimeId History::adjustChatListTimeId() const { TimeId History::adjustChatListTimeId() const {
const auto result = chatsListTimeId(); const auto result = chatListTimeId();
if (const auto draft = cloudDraft()) { if (const auto draft = cloudDraft()) {
if (!Data::draftIsNull(draft) && !session().supportMode()) { if (!Data::draftIsNull(draft) && !session().supportMode()) {
return std::max(result, draft->date); return std::max(result, draft->date);
@ -1889,19 +1905,23 @@ bool History::chatListMutedBadge() const {
return mute(); return mute();
} }
HistoryItem *History::chatsListItem() const { HistoryItem *History::chatListMessage() const {
return lastMessage(); return _chatListMessage.value_or(nullptr);
} }
const QString &History::chatsListName() const { bool History::chatListMessageKnown() const {
return _chatListMessage.has_value();
}
const QString &History::chatListName() const {
return peer->name; return peer->name;
} }
const base::flat_set<QString> &History::chatsListNameWords() const { const base::flat_set<QString> &History::chatListNameWords() const {
return peer->nameWords(); return peer->nameWords();
} }
const base::flat_set<QChar> &History::chatsListFirstLetters() const { const base::flat_set<QChar> &History::chatListFirstLetters() const {
return peer->nameFirstLetters(); return peer->nameFirstLetters();
} }
@ -2050,40 +2070,194 @@ void History::markFullyLoaded() {
} }
void History::setLastMessage(HistoryItem *item) { void History::setLastMessage(HistoryItem *item) {
if (item) { if (_lastMessage && *_lastMessage == item) {
if (_lastMessage) { return;
if (!*_lastMessage) { }
Local::removeSavedPeer(peer); _lastMessage = item;
} else if (!IsServerMsgId((*_lastMessage)->id) _chatListMessage = std::nullopt;
&& (*_lastMessage)->date() > item->date()) { if (!peer->migrateTo()) {
return; // We don't want to request last message for all deactivated chats.
} // This is a heavy request for them, because we need to get last
} // two items by messages.getHistory to skip the migration message.
_lastMessage = item; requestChatListMessage();
if (const auto feed = peer->feed()) {
feed->updateLastMessage(item);
}
setChatsListTimeId(item->date());
} else if (!_lastMessage || *_lastMessage) {
_lastMessage = nullptr;
updateChatListEntry();
} }
} }
void History::refreshChatListMessage() {
const auto known = chatListMessageKnown();
setChatListMessageFromLast();
if (known && !_chatListMessage) {
requestChatListMessage();
}
}
void History::setChatListMessage(HistoryItem *item) {
if (_chatListMessage && *_chatListMessage == item) {
return;
}
if (item) {
if (_chatListMessage) {
if (!*_chatListMessage) {
Local::removeSavedPeer(peer);
} else if (!IsServerMsgId((*_chatListMessage)->id)
&& (*_chatListMessage)->date() > item->date()) {
return;
}
}
_chatListMessage = item;
setChatListTimeId(item->date());
} else if (!_chatListMessage || *_chatListMessage) {
_chatListMessage = nullptr;
updateChatListEntry();
}
if (const auto to = peer->migrateTo()) {
if (const auto history = owner().historyLoaded(to)) {
if (!history->chatListMessageKnown()) {
history->requestChatListMessage();
}
}
}
}
auto History::computeChatListMessageFromLast() const
-> std::optional<HistoryItem*> {
if (!_lastMessage) {
return _lastMessage;
}
// In migrated groups we want to skip essential message
// about migration in the chats list and display the last
// non-migration message from the original legacy group.
const auto last = lastMessage();
if (!last || !last->isGroupEssential() || !last->isEmpty()) {
return _lastMessage;
}
if (const auto chat = peer->asChat()) {
// In chats we try to take the item before the 'last', which
// is the empty-displayed migration message.
if (!loadedAtBottom()) {
// We don't know the tail of the history.
return std::nullopt;
}
const auto before = [&]() -> HistoryItem* {
for (const auto &block : ranges::view::reverse(blocks)) {
const auto &messages = block->messages;
for (const auto &item : ranges::view::reverse(messages)) {
if (item->data() != last) {
return item->data();
}
}
}
return nullptr;
}();
if (before) {
// We found a message that is not the migration one.
return before;
} else if (loadedAtTop()) {
// No other messages in this history.
return _lastMessage;
}
return std::nullopt;
} else if (const auto from = migrateFrom()) {
// In megagroups we just try to use
// the message from the original group.
return from->chatListMessageKnown()
? std::make_optional(from->chatListMessage())
: std::nullopt;
}
return _lastMessage;
}
void History::setChatListMessageFromLast() {
if (const auto good = computeChatListMessageFromLast()) {
setChatListMessage(*good);
} else {
_chatListMessage = std::nullopt;
}
}
void History::requestChatListMessage() {
if (!lastMessageKnown()) {
session().api().requestDialogEntry(this);
return;
} else if (chatListMessageKnown()) {
return;
}
setChatListMessageFromLast();
if (!chatListMessageKnown()) {
setFakeChatListMessage();
}
}
void History::setFakeChatListMessage() {
if (const auto chat = peer->asChat()) {
// In chats we try to take the item before the 'last', which
// is the empty-displayed migration message.
session().api().requestFakeChatListMessage(this);
} else if (const auto from = migrateFrom()) {
// In megagroups we just try to use
// the message from the original group.
from->requestChatListMessage();
}
}
void History::setFakeChatListMessageFrom(const MTPmessages_Messages &data) {
if (!lastMessageKnown()) {
requestChatListMessage();
return;
}
const auto finalize = gsl::finally([&] {
// Make sure that we have chatListMessage when we get out of here.
if (!chatListMessageKnown()) {
setChatListMessage(lastMessage());
}
});
const auto last = lastMessage();
if (!last || !last->isGroupEssential() || !last->isEmpty()) {
// Last message is good enough.
return;
}
const auto other = data.match([&](
const MTPDmessages_messagesNotModified &) {
return static_cast<const MTPMessage*>(nullptr);
}, [&](const auto &data) {
for (const auto &message : data.vmessages.v) {
const auto id = message.match([](const auto &data) {
return data.vid.v;
});
if (id != last->id) {
return &message;
}
}
return static_cast<const MTPMessage*>(nullptr);
});
if (!other) {
// Other (non equal to the last one) message not found.
return;
}
const auto item = owner().addNewMessage(*other, NewMessageExisting);
if (!item || (item->isGroupEssential() && item->isEmpty())) {
// Not better than the last one.
return;
}
setChatListMessage(item);
}
HistoryItem *History::lastMessage() const { HistoryItem *History::lastMessage() const {
return _lastMessage ? (*_lastMessage) : nullptr; return _lastMessage.value_or(nullptr);
} }
bool History::lastMessageKnown() const { bool History::lastMessageKnown() const {
return !!_lastMessage; return _lastMessage.has_value();
} }
void History::updateChatListExistence() { void History::updateChatListExistence() {
Entry::updateChatListExistence(); Entry::updateChatListExistence();
if (!lastMessageKnown() || !unreadCountKnown()) { if (const auto channel = peer->asChannel()) {
if (const auto channel = peer->asChannel()) { if (!channel->feed()) {
if (!channel->feed()) { // After ungrouping from a feed we need to load dialog.
// After ungrouping from a feed we need to load dialog. requestChatListMessage();
if (!unreadCountKnown()) {
session().api().requestDialogEntry(this); session().api().requestDialogEntry(this);
} }
} }
@ -2164,6 +2338,51 @@ void History::applyDialog(const MTPDdialog &data) {
} }
} }
void History::dialogEntryApplied() {
if (!lastMessageKnown()) {
setLastMessage(nullptr);
}
if (!chatListMessageKnown()) {
requestChatListMessage();
return;
}
if (!chatListMessage()) {
if (const auto chat = peer->asChat()) {
if (!chat->haveLeft()) {
Local::addSavedPeer(
peer,
ParseDateTime(chatListTimeId()));
}
} else if (const auto channel = peer->asChannel()) {
const auto inviter = channel->inviter;
if (inviter != 0 && channel->amIn()) {
if (const auto from = App::userLoaded(inviter)) {
unloadBlocks();
addNewerSlice(QVector<MTPMessage>());
insertJoinedMessage(true);
}
}
} else {
App::main()->deleteConversation(peer, false);
}
return;
}
if (chatListTimeId() != 0 && loadedAtBottom()) {
if (const auto channel = peer->asChannel()) {
const auto inviter = channel->inviter;
if (inviter != 0
&& chatListTimeId() <= channel->inviteDate
&& channel->amIn()) {
if (const auto from = App::userLoaded(inviter)) {
insertJoinedMessage(true);
}
}
}
}
updateChatListExistence();
}
bool History::clearUnreadOnClientSide() const { bool History::clearUnreadOnClientSide() const {
if (!session().supportMode()) { if (!session().supportMode()) {
return false; return false;
@ -2253,8 +2472,8 @@ MsgId History::minMsgId() const {
} }
MsgId History::maxMsgId() const { MsgId History::maxMsgId() const {
for (const auto &block : base::reversed(blocks)) { for (const auto &block : ranges::view::reverse(blocks)) {
for (const auto &message : base::reversed(block->messages)) { for (const auto &message : ranges::view::reverse(block->messages)) {
const auto item = message->data(); const auto item = message->data();
if (IsServerMsgId(item->id)) { if (IsServerMsgId(item->id)) {
return item->id; return item->id;
@ -2278,8 +2497,8 @@ HistoryItem *History::lastSentMessage() const {
if (!loadedAtBottom()) { if (!loadedAtBottom()) {
return nullptr; return nullptr;
} }
for (const auto &block : base::reversed(blocks)) { for (const auto &block : ranges::view::reverse(blocks)) {
for (const auto &message : base::reversed(block->messages)) { for (const auto &message : ranges::view::reverse(block->messages)) {
const auto item = message->data(); const auto item = message->data();
// Skip if message is video message or sticker. // Skip if message is video message or sticker.
if (const auto media = item->media()) { if (const auto media = item->media()) {
@ -2336,7 +2555,7 @@ bool History::isMegagroup() const {
} }
not_null<History*> History::migrateToOrMe() const { not_null<History*> History::migrateToOrMe() const {
if (auto to = peer->migrateTo()) { if (const auto to = peer->migrateTo()) {
return App::history(to); return App::history(to);
} }
// We could get it by App::history(peer), but we optimize. // We could get it by App::history(peer), but we optimize.
@ -2344,7 +2563,7 @@ not_null<History*> History::migrateToOrMe() const {
} }
History *History::migrateFrom() const { History *History::migrateFrom() const {
if (auto from = peer->migrateFrom()) { if (const auto from = peer->migrateFrom()) {
return App::history(from); return App::history(from);
} }
return nullptr; return nullptr;
@ -2423,7 +2642,7 @@ HistoryService *History::insertJoinedMessage(bool unread) {
// Due to a server bug sometimes inviteDate is less (before) than the // Due to a server bug sometimes inviteDate is less (before) than the
// first message in the megagroup (message about migration), let us // first message in the megagroup (message about migration), let us
// ignore that and think, that the inviteDate is always greater-or-equal. // ignore that and think, that the inviteDate is always greater-or-equal.
if (item->isGroupMigrate() if ((item->id == 1)
&& peer->isMegagroup() && peer->isMegagroup()
&& peer->migrateFrom()) { && peer->migrateFrom()) {
peer->asChannel()->mgInfo->joinedMessageFound = true; peer->asChannel()->mgInfo->joinedMessageFound = true;
@ -2437,7 +2656,7 @@ HistoryService *History::insertJoinedMessage(bool unread) {
inviter, inviter,
flags); flags);
addNewInTheMiddle(_joinedMessage, blockIndex, itemIndex); addNewInTheMiddle(_joinedMessage, blockIndex, itemIndex);
const auto lastDate = chatsListTimeId(); const auto lastDate = chatListTimeId();
if (!lastDate || inviteDate >= lastDate) { if (!lastDate || inviteDate >= lastDate) {
setLastMessage(_joinedMessage); setLastMessage(_joinedMessage);
if (unread) { if (unread) {
@ -2508,9 +2727,29 @@ bool History::isEmpty() const {
} }
bool History::isDisplayedEmpty() const { bool History::isDisplayedEmpty() const {
return isEmpty() || ((blocks.size() == 1) return findFirstNonEmpty() == nullptr;
&& blocks.front()->messages.size() == 1 }
&& blocks.front()->messages.front()->data()->isEmpty());
auto History::findFirstNonEmpty() const -> Element* {
for (const auto &block : blocks) {
for (const auto &element : block->messages) {
if (!element->data()->isEmpty()) {
return element.get();
}
}
}
return nullptr;
}
auto History::findLastNonEmpty() const -> Element* {
for (const auto &block : ranges::view::reverse(blocks)) {
for (const auto &element : ranges::view::reverse(block->messages)) {
if (!element->data()->isEmpty()) {
return element.get();
}
}
}
return nullptr;
} }
bool History::hasOrphanMediaGroupPart() const { bool History::hasOrphanMediaGroupPart() const {
@ -2624,9 +2863,7 @@ void History::clearUpTill(MsgId availableMinId) {
item->destroy(); item->destroy();
} while (!isEmpty()); } while (!isEmpty());
if (!lastMessageKnown()) { requestChatListMessage();
session().api().requestDialogEntry(this);
}
_owner->sendHistoryChangeNotifications(); _owner->sendHistoryChangeNotifications();
} }

View File

@ -58,7 +58,7 @@ class History final : public Dialogs::Entry {
public: public:
using Element = HistoryView::Element; using Element = HistoryView::Element;
History(not_null<Data::Session*> owner, const PeerId &peerId); History(not_null<Data::Session*> owner, PeerId peerId);
History(const History &) = delete; History(const History &) = delete;
History &operator=(const History &) = delete; History &operator=(const History &) = delete;
@ -77,6 +77,8 @@ public:
bool isEmpty() const; bool isEmpty() const;
bool isDisplayedEmpty() const; bool isDisplayedEmpty() const;
Element *findFirstNonEmpty() const;
Element *findLastNonEmpty() const;
bool hasOrphanMediaGroupPart() const; bool hasOrphanMediaGroupPart() const;
bool removeOrphanMediaGroupPart(); bool removeOrphanMediaGroupPart();
QVector<MsgId> collectMessagesFromUserToDelete( QVector<MsgId> collectMessagesFromUserToDelete(
@ -192,6 +194,7 @@ public:
int unreadCount, int unreadCount,
MsgId maxInboxRead, MsgId maxInboxRead,
MsgId maxOutboxRead); MsgId maxOutboxRead);
void dialogEntryApplied();
MsgId minMsgId() const; MsgId minMsgId() const;
MsgId maxMsgId() const; MsgId maxMsgId() const;
@ -283,10 +286,12 @@ public:
int chatListUnreadCount() const override; int chatListUnreadCount() const override;
bool chatListUnreadMark() const override; bool chatListUnreadMark() const override;
bool chatListMutedBadge() const override; bool chatListMutedBadge() const override;
HistoryItem *chatsListItem() const override; HistoryItem *chatListMessage() const override;
const QString &chatsListName() const override; bool chatListMessageKnown() const override;
const base::flat_set<QString> &chatsListNameWords() const override; void requestChatListMessage() override;
const base::flat_set<QChar> &chatsListFirstLetters() const override; const QString &chatListName() const override;
const base::flat_set<QString> &chatListNameWords() const override;
const base::flat_set<QChar> &chatListFirstLetters() const override;
void loadUserpic() override; void loadUserpic() override;
void paintUserpic( void paintUserpic(
Painter &p, Painter &p,
@ -294,6 +299,9 @@ public:
int y, int y,
int size) const override; int size) const override;
void setFakeChatListMessageFrom(const MTPmessages_Messages &data);
void checkChatListMessageRemoved(not_null<HistoryItem*> item);
void forgetScrollState() { void forgetScrollState() {
scrollTopItem = nullptr; scrollTopItem = nullptr;
} }
@ -411,6 +419,12 @@ private:
void checkLastMessage(); void checkLastMessage();
void setLastMessage(HistoryItem *item); void setLastMessage(HistoryItem *item);
void refreshChatListMessage();
void setChatListMessage(HistoryItem *item);
std::optional<HistoryItem*> computeChatListMessageFromLast() const;
void setChatListMessageFromLast();
void setFakeChatListMessage();
// 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();
@ -449,6 +463,12 @@ private:
std::optional<int> _unreadMentionsCount; std::optional<int> _unreadMentionsCount;
base::flat_set<MsgId> _unreadMentions; base::flat_set<MsgId> _unreadMentions;
std::optional<HistoryItem*> _lastMessage; std::optional<HistoryItem*> _lastMessage;
// This almost always is equal to _lastMessage. The only difference is
// for a group that migrated to a supergroup. Then _lastMessage can
// be a migrate message, but _chatListMessage should be the one before.
std::optional<HistoryItem*> _chatListMessage;
bool _unreadMark = false; bool _unreadMark = false;
// A pointer to the block that is currently being built. // A pointer to the block that is currently being built.

View File

@ -436,10 +436,6 @@ void HistoryInner::enumerateDates(Method method) {
if (itemtop > _visibleAreaTop) { if (itemtop > _visibleAreaTop) {
// Previous item (from the _migrated history) is drawing date now. // Previous item (from the _migrated history) is drawing date now.
return false; return false;
} else if (item == _history->blocks.front()->messages.front()->data() && item->isGroupMigrate()
&& _migrated->blocks.back()->messages.back()->data()->isGroupMigrate()) {
// This item is completely invisible and should be completely ignored.
return false;
} }
} }
@ -1954,17 +1950,19 @@ void HistoryInner::recountHistoryGeometry() {
_migrated->resizeToWidth(_contentWidth); _migrated->resizeToWidth(_contentWidth);
} }
// with migrated history we perhaps do not need to display first _history message // With migrated history we perhaps do not need to display
// (if last _migrated message and first _history message are both isGroupMigrate) // the first _history message date (just skip it by height).
// or at least we don't need to display first _history date (just skip it by height)
_historySkipHeight = 0; _historySkipHeight = 0;
if (_migrated) { if (_migrated
if (!_migrated->isEmpty() && !_history->isEmpty() && _migrated->loadedAtBottom() && _history->loadedAtTop()) { && _migrated->loadedAtBottom()
if (_migrated->blocks.back()->messages.back()->dateTime().date() == _history->blocks.front()->messages.front()->dateTime().date()) { && _history->loadedAtTop()) {
if (_migrated->blocks.back()->messages.back()->data()->isGroupMigrate() && _history->blocks.front()->messages.front()->data()->isGroupMigrate()) { if (const auto first = _history->findFirstNonEmpty()) {
_historySkipHeight += _history->blocks.front()->messages.front()->height(); if (const auto last = _migrated->findLastNonEmpty()) {
} else if (_migrated->height() > _history->blocks.front()->messages.front()->displayedDateHeight()) { if (first->dateTime().date() == last->dateTime().date()) {
_historySkipHeight += _history->blocks.front()->messages.front()->displayedDateHeight(); const auto dateHeight = first->displayedDateHeight();
if (_migrated->height() > dateHeight) {
_historySkipHeight += dateHeight;
}
} }
} }
} }

View File

@ -298,9 +298,8 @@ private:
int _contentWidth = 0; int _contentWidth = 0;
int _historyPaddingTop = 0; int _historyPaddingTop = 0;
// with migrated history we perhaps do not need to display first _history message // With migrated history we perhaps do not need to display
// (if last _migrated message and first _history message are both isGroupMigrate) // the first _history message date (just skip it by height).
// or at least we don't need to display first _history date (just skip it by height)
int _historySkipHeight = 0; int _historySkipHeight = 0;
std::unique_ptr<BotAbout> _botAbout; std::unique_ptr<BotAbout> _botAbout;

View File

@ -176,12 +176,12 @@ TimeId HistoryItem::date() const {
void HistoryItem::finishEdition(int oldKeyboardTop) { void HistoryItem::finishEdition(int oldKeyboardTop) {
_history->owner().requestItemViewRefresh(this); _history->owner().requestItemViewRefresh(this);
invalidateChatsListEntry(); invalidateChatListEntry();
if (const auto group = _history->owner().groups().find(this)) { if (const auto group = _history->owner().groups().find(this)) {
const auto leader = group->items.back(); const auto leader = group->items.back();
if (leader != this) { if (leader != this) {
_history->owner().requestItemViewRefresh(leader); _history->owner().requestItemViewRefresh(leader);
leader->invalidateChatsListEntry(); leader->invalidateChatListEntry();
} }
} }
@ -217,7 +217,7 @@ ReplyKeyboard *HistoryItem::inlineReplyKeyboard() {
return nullptr; return nullptr;
} }
void HistoryItem::invalidateChatsListEntry() { void HistoryItem::invalidateChatListEntry() {
if (const auto main = App::main()) { if (const auto main = App::main()) {
// #TODO feeds search results // #TODO feeds search results
main->repaintDialogRow({ history(), fullId() }); main->repaintDialogRow({ history(), fullId() });
@ -462,7 +462,7 @@ bool HistoryItem::canDelete() const {
} }
auto channel = _history->peer->asChannel(); auto channel = _history->peer->asChannel();
if (!channel) { if (!channel) {
return !(_flags & MTPDmessage_ClientFlag::f_is_group_migrate); return !(_flags & MTPDmessage_ClientFlag::f_is_group_essential);
} }
if (id == 1) { if (id == 1) {
@ -706,7 +706,7 @@ QString HistoryItem::notificationText() const {
QString HistoryItem::inDialogsText(DrawInDialog way) const { QString HistoryItem::inDialogsText(DrawInDialog way) const {
auto getText = [this]() { auto getText = [this]() {
if (_media) { if (_media) {
return _media->chatsListText(); return _media->chatListText();
} else if (!emptyText()) { } else if (!emptyText()) {
return TextUtilities::Clean(_text.originalText()); return TextUtilities::Clean(_text.originalText());
} }

View File

@ -134,8 +134,8 @@ public:
bool hasTextLinks() const { bool hasTextLinks() const {
return _flags & MTPDmessage_ClientFlag::f_has_text_links; return _flags & MTPDmessage_ClientFlag::f_has_text_links;
} }
bool isGroupMigrate() const { bool isGroupEssential() const {
return _flags & MTPDmessage_ClientFlag::f_is_group_migrate; return _flags & MTPDmessage_ClientFlag::f_is_group_essential;
} }
bool hasViews() const { bool hasViews() const {
return _flags & MTPDmessage::Flag::f_views; return _flags & MTPDmessage::Flag::f_views;
@ -294,7 +294,7 @@ protected:
} }
HistoryMessageReplyMarkup *inlineReplyMarkup(); HistoryMessageReplyMarkup *inlineReplyMarkup();
ReplyKeyboard *inlineReplyKeyboard(); ReplyKeyboard *inlineReplyKeyboard();
void invalidateChatsListEntry(); void invalidateChatListEntry();
void setGroupId(MessageGroupId groupId); void setGroupId(MessageGroupId groupId);

View File

@ -36,7 +36,7 @@ constexpr auto kPinnedMessageTextLimit = 16;
void HistoryService::setMessageByAction(const MTPmessageAction &action) { void HistoryService::setMessageByAction(const MTPmessageAction &action) {
auto prepareChatAddUserText = [this](const MTPDmessageActionChatAddUser &action) { auto prepareChatAddUserText = [this](const MTPDmessageActionChatAddUser &action) {
auto result = PreparedText {}; auto result = PreparedText{};
auto &users = action.vusers.v; auto &users = action.vusers.v;
if (users.size() == 1) { if (users.size() == 1) {
auto u = App::user(peerFromUser(users[0])); auto u = App::user(peerFromUser(users[0]));
@ -72,14 +72,14 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
}; };
auto prepareChatJoinedByLink = [this](const MTPDmessageActionChatJoinedByLink &action) { auto prepareChatJoinedByLink = [this](const MTPDmessageActionChatJoinedByLink &action) {
auto result = PreparedText {}; auto result = PreparedText{};
result.links.push_back(fromLink()); result.links.push_back(fromLink());
result.text = lng_action_user_joined_by_link(lt_from, fromLinkText()); result.text = lng_action_user_joined_by_link(lt_from, fromLinkText());
return result; return result;
}; };
auto prepareChatCreate = [this](const MTPDmessageActionChatCreate &action) { auto prepareChatCreate = [this](const MTPDmessageActionChatCreate &action) {
auto result = PreparedText {}; auto result = PreparedText{};
result.links.push_back(fromLink()); result.links.push_back(fromLink());
result.text = lng_action_created_chat(lt_from, fromLinkText(), lt_title, TextUtilities::Clean(qs(action.vtitle))); result.text = lng_action_created_chat(lt_from, fromLinkText(), lt_title, TextUtilities::Clean(qs(action.vtitle)));
return result; return result;
@ -97,7 +97,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
}; };
auto prepareChatDeletePhoto = [this] { auto prepareChatDeletePhoto = [this] {
auto result = PreparedText {}; auto result = PreparedText{};
if (isPost()) { if (isPost()) {
result.text = lang(lng_action_removed_photo_channel); result.text = lang(lng_action_removed_photo_channel);
} else { } else {
@ -108,7 +108,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
}; };
auto prepareChatDeleteUser = [this](const MTPDmessageActionChatDeleteUser &action) { auto prepareChatDeleteUser = [this](const MTPDmessageActionChatDeleteUser &action) {
auto result = PreparedText {}; auto result = PreparedText{};
if (peerFromUser(action.vuser_id) == _from->id) { if (peerFromUser(action.vuser_id) == _from->id) {
result.links.push_back(fromLink()); result.links.push_back(fromLink());
result.text = lng_action_user_left(lt_from, fromLinkText()); result.text = lng_action_user_left(lt_from, fromLinkText());
@ -122,7 +122,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
}; };
auto prepareChatEditPhoto = [this](const MTPDmessageActionChatEditPhoto &action) { auto prepareChatEditPhoto = [this](const MTPDmessageActionChatEditPhoto &action) {
auto result = PreparedText {}; auto result = PreparedText{};
if (isPost()) { if (isPost()) {
result.text = lang(lng_action_changed_photo_channel); result.text = lang(lng_action_changed_photo_channel);
} else { } else {
@ -133,7 +133,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
}; };
auto prepareChatEditTitle = [this](const MTPDmessageActionChatEditTitle &action) { auto prepareChatEditTitle = [this](const MTPDmessageActionChatEditTitle &action) {
auto result = PreparedText {}; auto result = PreparedText{};
if (isPost()) { if (isPost()) {
result.text = lng_action_changed_title_channel(lt_title, TextUtilities::Clean(qs(action.vtitle))); result.text = lng_action_changed_title_channel(lt_title, TextUtilities::Clean(qs(action.vtitle)));
} else { } else {
@ -144,7 +144,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
}; };
auto prepareScreenshotTaken = [this] { auto prepareScreenshotTaken = [this] {
auto result = PreparedText {}; auto result = PreparedText{};
if (out()) { if (out()) {
result.text = lang(lng_action_you_took_screenshot); result.text = lang(lng_action_you_took_screenshot);
} else { } else {
@ -155,7 +155,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
}; };
auto prepareCustomAction = [&](const MTPDmessageActionCustomAction &action) { auto prepareCustomAction = [&](const MTPDmessageActionCustomAction &action) {
auto result = PreparedText {}; auto result = PreparedText{};
result.text = qs(action.vmessage); result.text = qs(action.vmessage);
return result; return result;
}; };
@ -214,69 +214,98 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
return result; return result;
}; };
auto messageText = PreparedText {}; const auto messageText = action.match([&](
const MTPDmessageActionChatAddUser &data) {
switch (action.type()) { return prepareChatAddUserText(data);
case mtpc_messageActionChatAddUser: messageText = prepareChatAddUserText(action.c_messageActionChatAddUser()); break; }, [&](const MTPDmessageActionChatJoinedByLink &data) {
case mtpc_messageActionChatJoinedByLink: messageText = prepareChatJoinedByLink(action.c_messageActionChatJoinedByLink()); break; return prepareChatJoinedByLink(data);
case mtpc_messageActionChatCreate: messageText = prepareChatCreate(action.c_messageActionChatCreate()); break; }, [&](const MTPDmessageActionChatCreate &data) {
case mtpc_messageActionChannelCreate: messageText = prepareChannelCreate(action.c_messageActionChannelCreate()); break; return prepareChatCreate(data);
case mtpc_messageActionHistoryClear: break; // Leave empty text. }, [](const MTPDmessageActionChatMigrateTo &) {
case mtpc_messageActionChatDeletePhoto: messageText = prepareChatDeletePhoto(); break; return PreparedText();
case mtpc_messageActionChatDeleteUser: messageText = prepareChatDeleteUser(action.c_messageActionChatDeleteUser()); break; }, [](const MTPDmessageActionChannelMigrateFrom &) {
case mtpc_messageActionChatEditPhoto: messageText = prepareChatEditPhoto(action.c_messageActionChatEditPhoto()); break; return PreparedText();
case mtpc_messageActionChatEditTitle: messageText = prepareChatEditTitle(action.c_messageActionChatEditTitle()); break; }, [](const MTPDmessageActionHistoryClear &) {
case mtpc_messageActionChatMigrateTo: messageText.text = lang(lng_action_group_migrate); break; return PreparedText();
case mtpc_messageActionChannelMigrateFrom: messageText.text = lang(lng_action_group_migrate); break; }, [&](const MTPDmessageActionChannelCreate &data) {
case mtpc_messageActionPinMessage: messageText = preparePinnedText(); break; return prepareChannelCreate(data);
case mtpc_messageActionGameScore: messageText = prepareGameScoreText(); break; }, [&](const MTPDmessageActionChatDeletePhoto &) {
case mtpc_messageActionPhoneCall: Unexpected("PhoneCall type in HistoryService."); return prepareChatDeletePhoto();
case mtpc_messageActionPaymentSent: messageText = preparePaymentSentText(); break; }, [&](const MTPDmessageActionChatDeleteUser &data) {
case mtpc_messageActionScreenshotTaken: messageText = prepareScreenshotTaken(); break; return prepareChatDeleteUser(data);
case mtpc_messageActionCustomAction: messageText = prepareCustomAction(action.c_messageActionCustomAction()); break; }, [&](const MTPDmessageActionChatEditPhoto &data) {
case mtpc_messageActionBotAllowed: messageText = prepareBotAllowed(action.c_messageActionBotAllowed()); break; return prepareChatEditPhoto(data);
case mtpc_messageActionSecureValuesSent: messageText = prepareSecureValuesSent(action.c_messageActionSecureValuesSent()); break; }, [&](const MTPDmessageActionChatEditTitle &data) {
case mtpc_messageActionContactSignUp: messageText = prepareContactSignUp(); break; return prepareChatEditTitle(data);
default: messageText.text = lang(lng_message_empty); break; }, [&](const MTPDmessageActionPinMessage &) {
} return preparePinnedText();
}, [&](const MTPDmessageActionGameScore &) {
return prepareGameScoreText();
}, [&](const MTPDmessageActionPhoneCall &) -> PreparedText {
Unexpected("PhoneCall type in HistoryService.");
}, [&](const MTPDmessageActionPaymentSent &) {
return preparePaymentSentText();
}, [&](const MTPDmessageActionScreenshotTaken &) {
return prepareScreenshotTaken();
}, [&](const MTPDmessageActionCustomAction &data) {
return prepareCustomAction(data);
}, [&](const MTPDmessageActionBotAllowed &data) {
return prepareBotAllowed(data);
}, [&](const MTPDmessageActionSecureValuesSent &data) {
return prepareSecureValuesSent(data);
}, [&](const MTPDmessageActionContactSignUp &data) {
return prepareContactSignUp();
}, [](const MTPDmessageActionPaymentSentMe &) {
LOG(("API Error: messageActionPaymentSentMe received."));
return PreparedText{ lang(lng_message_empty) };
}, [](const MTPDmessageActionSecureValuesSentMe &) {
LOG(("API Error: messageActionSecureValuesSentMe received."));
return PreparedText{ lang(lng_message_empty) };
}, [](const MTPDmessageActionEmpty &) {
return PreparedText{ lang(lng_message_empty) };
});
setServiceText(messageText); setServiceText(messageText);
// Additional information. // Additional information.
switch (action.type()) { applyAction(action);
case mtpc_messageActionChatAddUser: { }
if (auto channel = history()->peer->asMegagroup()) {
auto &users = action.c_messageActionChatAddUser().vusers; void HistoryService::applyAction(const MTPMessageAction &action) {
for_const (auto &item, users.v) { action.match([&](const MTPDmessageActionChatAddUser &data) {
if (item.v == history()->session().userId()) { if (const auto channel = history()->peer->asMegagroup()) {
const auto selfUserId = history()->session().userId();
for (const auto &item : data.vusers.v) {
if (item.v == selfUserId) {
channel->mgInfo->joinedMessageFound = true; channel->mgInfo->joinedMessageFound = true;
break; break;
} }
} }
} }
} break; }, [&](const MTPDmessageActionChatJoinedByLink &data) {
if (_from->isSelf()) {
case mtpc_messageActionChatJoinedByLink: { if (const auto channel = history()->peer->asMegagroup()) {
if (_from->isSelf() && history()->peer->isMegagroup()) { channel->mgInfo->joinedMessageFound = true;
history()->peer->asChannel()->mgInfo->joinedMessageFound = true; }
} }
} break; }, [&](const MTPDmessageActionChatEditPhoto &data) {
data.vphoto.match([&](const MTPDphoto &photo) {
case mtpc_messageActionChatEditPhoto: {
auto &photo = action.c_messageActionChatEditPhoto().vphoto;
if (photo.type() == mtpc_photo) {
_media = std::make_unique<Data::MediaPhoto>( _media = std::make_unique<Data::MediaPhoto>(
this, this,
history()->peer, history()->peer,
history()->owner().photo(photo.c_photo())); history()->owner().photo(photo));
} }, [](const MTPDphotoEmpty &) {
} break; });
}, [&](const MTPDmessageActionChatCreate &) {
case mtpc_messageActionChatMigrateTo: _flags |= MTPDmessage_ClientFlag::f_is_group_essential;
case mtpc_messageActionChannelMigrateFrom: { }, [&](const MTPDmessageActionChannelCreate &) {
_flags |= MTPDmessage_ClientFlag::f_is_group_migrate; _flags |= MTPDmessage_ClientFlag::f_is_group_essential;
} break; }, [&](const MTPDmessageActionChatMigrateTo &) {
} _flags |= MTPDmessage_ClientFlag::f_is_group_essential;
}, [&](const MTPDmessageActionChannelMigrateFrom &) {
_flags |= MTPDmessage_ClientFlag::f_is_group_essential;
}, [](const auto &) {
});
} }
void HistoryService::setSelfDestruct(HistoryServiceSelfDestruct::Type type, int ttlSeconds) { void HistoryService::setSelfDestruct(HistoryServiceSelfDestruct::Type type, int ttlSeconds) {

View File

@ -137,7 +137,10 @@ private:
void createFromMtp(const MTPDmessage &message); void createFromMtp(const MTPDmessage &message);
void createFromMtp(const MTPDmessageService &message); void createFromMtp(const MTPDmessageService &message);
void setMessageByAction(const MTPmessageAction &action); void setMessageByAction(const MTPmessageAction &action);
void setSelfDestruct(HistoryServiceSelfDestruct::Type type, int ttlSeconds); void setSelfDestruct(
HistoryServiceSelfDestruct::Type type,
int ttlSeconds);
void applyAction(const MTPMessageAction &action);
PreparedText preparePinnedText(); PreparedText preparePinnedText();
PreparedText prepareGameScoreText(); PreparedText prepareGameScoreText();

View File

@ -730,26 +730,6 @@ void HistoryWidget::highlightMessage(MsgId universalMessageId) {
_highlightStart = getms(); _highlightStart = getms();
_highlightedMessageId = universalMessageId; _highlightedMessageId = universalMessageId;
_highlightTimer.callEach(AnimationTimerDelta); _highlightTimer.callEach(AnimationTimerDelta);
adjustHighlightedMessageToMigrated();
}
void HistoryWidget::adjustHighlightedMessageToMigrated() {
if (_history
&& _highlightTimer.isActive()
&& _highlightedMessageId > 0
&& _migrated
&& !_migrated->isEmpty()
&& _migrated->loadedAtBottom()
&& _migrated->blocks.back()->messages.back()->data()->isGroupMigrate()
&& _list->historyTop() != _list->historyDrawTop()) {
auto highlighted = App::histItemById(
_history->channelId(),
_highlightedMessageId);
if (highlighted && highlighted->isGroupMigrate()) {
_highlightedMessageId = -_migrated->blocks.back()->messages.back()->data()->id;
}
}
} }
void HistoryWidget::checkNextHighlight() { void HistoryWidget::checkNextHighlight() {
@ -4902,7 +4882,6 @@ void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector<MTPMessage>
_list->messagesReceived(peer, messages); _list->messagesReceived(peer, messages);
if (!_firstLoadRequest) { if (!_firstLoadRequest) {
updateHistoryGeometry(); updateHistoryGeometry();
adjustHighlightedMessageToMigrated();
updateBotKeyboard(); updateBotKeyboard();
} }
} }
@ -5553,22 +5532,15 @@ void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) {
return; return;
} }
if (item->history() == _migrated) { if (item->history() == _migrated) {
if (item->isGroupMigrate() if (item->serviceMsg()) {
&& !_history->isEmpty() Ui::show(Box<InformBox>(lang(lng_reply_cant)));
&& _history->blocks.front()->messages.front()->data()->isGroupMigrate()
&& _history != _migrated) {
replyToMessage(_history->blocks.front()->messages.front()->data());
} else { } else {
if (item->serviceMsg()) { const auto itemId = item->fullId();
Ui::show(Box<InformBox>(lang(lng_reply_cant))); Ui::show(Box<ConfirmBox>(lang(lng_reply_cant_forward), lang(lng_selected_forward), crl::guard(this, [=] {
} else { App::main()->setForwardDraft(
const auto itemId = item->fullId(); _peer->id,
Ui::show(Box<ConfirmBox>(lang(lng_reply_cant_forward), lang(lng_selected_forward), crl::guard(this, [=] { { 1, itemId });
App::main()->setForwardDraft( })));
_peer->id,
{ 1, itemId });
})));
}
} }
return; return;
} }

View File

@ -387,7 +387,6 @@ private:
void supportShareContact(Support::Contact contact); void supportShareContact(Support::Contact contact);
void highlightMessage(MsgId universalMessageId); void highlightMessage(MsgId universalMessageId);
void adjustHighlightedMessageToMigrated();
void checkNextHighlight(); void checkNextHighlight();
void updateHighlightedMessage(); void updateHighlightedMessage();
void clearHighlightMessages(); void clearHighlightMessages();

View File

@ -310,7 +310,7 @@ void TopBarWidget::paintTopBar(Painter &p, TimeMs ms) {
p.setPen(st::dialogsNameFg); p.setPen(st::dialogsNameFg);
if (const auto feed = _activeChat.feed()) { if (const auto feed = _activeChat.feed()) {
auto text = feed->chatsListName(); // TODO feed name emoji auto text = feed->chatListName(); // TODO feed name emoji
auto textWidth = st::historySavedFont->width(text); auto textWidth = st::historySavedFont->width(text);
if (namewidth < textWidth) { if (namewidth < textWidth) {
text = st::historySavedFont->elided(text, namewidth); text = st::historySavedFont->elided(text, namewidth);

View File

@ -71,7 +71,7 @@ void Cover::initViewers() {
} }
void Cover::refreshNameText() { void Cover::refreshNameText() {
_name->setText(_feed->chatsListName()); _name->setText(_feed->chatListName());
refreshNameGeometry(width()); refreshNameGeometry(width());
} }

View File

@ -731,9 +731,7 @@ void MainWidget::cancelUploadLayer(not_null<HistoryItem*> item) {
if (const auto item = App::histItemById(itemId)) { if (const auto item = App::histItemById(itemId)) {
const auto history = item->history(); const auto history = item->history();
item->destroy(); item->destroy();
if (!history->lastMessageKnown()) { history->requestChatListMessage();
Auth().api().requestDialogEntry(history);
}
Auth().data().sendHistoryChangeNotifications(); Auth().data().sendHistoryChangeNotifications();
} }
Auth().uploader().unpause(); Auth().uploader().unpause();
@ -831,7 +829,7 @@ void MainWidget::deleteHistoryPart(DeleteHistoryRequest request, const MTPmessag
void MainWidget::deleteMessages( void MainWidget::deleteMessages(
not_null<PeerData*> peer, not_null<PeerData*> peer,
const QVector<MTPint> &ids, const QVector<MTPint> &ids,
bool forEveryone) { bool revoke) {
if (const auto channel = peer->asChannel()) { if (const auto channel = peer->asChannel()) {
MTP::send( MTP::send(
MTPchannels_DeleteMessages( MTPchannels_DeleteMessages(
@ -839,13 +837,10 @@ void MainWidget::deleteMessages(
MTP_vector<MTPint>(ids)), MTP_vector<MTPint>(ids)),
rpcDone(&MainWidget::messagesAffected, peer)); rpcDone(&MainWidget::messagesAffected, peer));
} else { } else {
auto flags = MTPmessages_DeleteMessages::Flags(0); using Flag = MTPmessages_DeleteMessages::Flag;
if (forEveryone) {
flags |= MTPmessages_DeleteMessages::Flag::f_revoke;
}
MTP::send( MTP::send(
MTPmessages_DeleteMessages( MTPmessages_DeleteMessages(
MTP_flags(flags), MTP_flags(revoke ? Flag::f_revoke : Flag(0)),
MTP_vector<MTPint>(ids)), MTP_vector<MTPint>(ids)),
rpcDone(&MainWidget::messagesAffected, peer)); rpcDone(&MainWidget::messagesAffected, peer));
} }
@ -1039,9 +1034,7 @@ void MainWidget::messagesAffected(
} }
if (const auto history = App::historyLoaded(peer)) { if (const auto history = App::historyLoaded(peer)) {
if (!history->lastMessageKnown()) { history->requestChatListMessage();
Auth().api().requestDialogEntry(history);
}
} }
} }
@ -4003,9 +3996,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
if (existing && !local->mainView()) { if (existing && !local->mainView()) {
const auto history = local->history(); const auto history = local->history();
local->destroy(); local->destroy();
if (!history->lastMessageKnown()) { history->requestChatListMessage();
Auth().api().requestDialogEntry(history);
}
} else { } else {
if (existing) { if (existing) {
existing->destroy(); existing->destroy();
@ -4477,15 +4468,15 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
Auth().api().requestSelfParticipant(channel); Auth().api().requestSelfParticipant(channel);
} }
if (const auto feed = channel->feed()) { if (const auto feed = channel->feed()) {
if (!feed->lastMessageKnown() feed->requestChatListMessage();
|| !feed->unreadCountKnown()) { if (!feed->unreadCountKnown()) {
Auth().api().requestDialogEntry(feed); feed->session().api().requestDialogEntry(feed);
} }
} else if (channel->amIn()) { } else if (channel->amIn()) {
const auto history = App::history(channel->id); const auto history = App::history(channel->id);
if (!history->lastMessageKnown() history->requestChatListMessage();
|| !history->unreadCountKnown()) { if (!history->unreadCountKnown()) {
Auth().api().requestDialogEntry(history); history->session().api().requestDialogEntry(history);
} }
} }
} }

View File

@ -196,7 +196,7 @@ public:
void deleteMessages( void deleteMessages(
not_null<PeerData*> peer, not_null<PeerData*> peer,
const QVector<MTPint> &ids, const QVector<MTPint> &ids,
bool forEveryone); bool revoke);
void deletedContact(UserData *user, const MTPcontacts_Link &result); void deletedContact(UserData *user, const MTPcontacts_Link &result);
void deleteConversation( void deleteConversation(
not_null<PeerData*> peer, not_null<PeerData*> peer,

View File

@ -409,22 +409,13 @@ void ResolveChannel(
std::optional<MTPMessage> GetMessagesElement( std::optional<MTPMessage> GetMessagesElement(
const MTPmessages_Messages &list) { const MTPmessages_Messages &list) {
const auto get = [](auto &&data) -> std::optional<MTPMessage> { return list.match([&](const MTPDmessages_messagesNotModified &) {
return std::optional<MTPMessage>(std::nullopt);
}, [&](const auto &data) {
return data.vmessages.v.isEmpty() return data.vmessages.v.isEmpty()
? std::nullopt ? std::nullopt
: base::make_optional(data.vmessages.v[0]); : std::make_optional(data.vmessages.v[0]);
}; });
switch (list.type()) {
case mtpc_messages_messages:
return get(list.c_messages_messages());
case mtpc_messages_messagesSlice:
return get(list.c_messages_messagesSlice());
case mtpc_messages_channelMessages:
return get(list.c_messages_channelMessages());
case mtpc_messages_messagesNotModified:
return std::nullopt;
default: Unexpected("Type of messages.Messages (GetMessagesElement)");
}
} }
void StartDedicatedLoader( void StartDedicatedLoader(

View File

@ -38,8 +38,8 @@ enum class MTPDmessage_ClientFlag : uint32 {
// message has links for "shared links" indexing // message has links for "shared links" indexing
f_has_text_links = (1U << 30), f_has_text_links = (1U << 30),
// message is a group migrate (group -> supergroup) service message // message is a group / channel create or migrate service message
f_is_group_migrate = (1U << 29), f_is_group_essential = (1U << 29),
//// message needs initDimensions() + resize() + paint() //// message needs initDimensions() + resize() + paint()
//f_pending_init_dimensions = (1U << 28), //f_pending_init_dimensions = (1U << 28),

View File

@ -643,7 +643,7 @@ bool PanelEditDocument::validate() {
error = firsttop.y(); error = firsttop.y();
} }
auto first = QPointer<PanelDetailsRow>(); auto first = QPointer<PanelDetailsRow>();
for (const auto [i, field] : base::reversed(_details)) { for (const auto [i, field] : ranges::view::reverse(_details)) {
const auto &row = _scheme.rows[i]; const auto &row = _scheme.rows[i];
if (row.valueClass == Scheme::ValueClass::Additional if (row.valueClass == Scheme::ValueClass::Additional
&& !_additionalShown) { && !_additionalShown) {

View File

@ -407,14 +407,14 @@ void Controller::showJumpToDate(Dialogs::Key chat, QDate requestedDate) {
return history->blocks.front()->messages.front()->dateTime().date(); return history->blocks.front()->messages.front()->dateTime().date();
} }
} }
} else if (history->chatsListTimeId() != 0) { } else if (history->chatListTimeId() != 0) {
return ParseDateTime(history->chatsListTimeId()).date(); return ParseDateTime(history->chatListTimeId()).date();
} }
} else if (const auto feed = chat.feed()) { } else if (const auto feed = chat.feed()) {
/*if (chatScrollPosition(feed)) { // #TODO feeds save position /*if (chatScrollPosition(feed)) { // #TODO feeds save position
} else */if (feed->chatsListTimeId() != 0) { } else */if (feed->chatListTimeId() != 0) {
return ParseDateTime(feed->chatsListTimeId()).date(); return ParseDateTime(feed->chatListTimeId()).date();
} }
} }
return QDate::currentDate(); return QDate::currentDate();
@ -424,12 +424,12 @@ void Controller::showJumpToDate(Dialogs::Key chat, QDate requestedDate) {
if (const auto channel = history->peer->migrateTo()) { if (const auto channel = history->peer->migrateTo()) {
history = App::historyLoaded(channel); history = App::historyLoaded(channel);
} }
if (history && history->chatsListTimeId() != 0) { if (history && history->chatListTimeId() != 0) {
return ParseDateTime(history->chatsListTimeId()).date(); return ParseDateTime(history->chatListTimeId()).date();
} }
} else if (const auto feed = chat.feed()) { } else if (const auto feed = chat.feed()) {
if (feed->chatsListTimeId() != 0) { if (feed->chatListTimeId() != 0) {
return ParseDateTime(feed->chatsListTimeId()).date(); return ParseDateTime(feed->chatListTimeId()).date();
} }
} }
return QDate::currentDate(); return QDate::currentDate();