mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-19 09:58:52 +00:00
Remove supergroup migrate messages.
This commit is contained in:
parent
c552db04d7
commit
2a0b9a44dd
@ -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_created_chat" = "{from} created group «{title}»";
|
||||
"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_media" = "{from} pinned {media}";
|
||||
"lng_action_pinned_media_photo" = "a photo";
|
||||
|
@ -416,7 +416,7 @@ void ApiWrap::savePinnedOrder() {
|
||||
const auto &order = _session->data().pinnedDialogsOrder();
|
||||
auto peers = QVector<MTPInputDialogPeer>();
|
||||
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()) {
|
||||
peers.push_back(MTP_inputDialogPeer(history->peer->input));
|
||||
} else if (const auto feed = pinned.feed()) {
|
||||
@ -708,7 +708,7 @@ void ApiWrap::requestDialogEntry(
|
||||
MTP_vector(std::move(peers))
|
||||
)).done([=](const MTPmessages_PeerDialogs &result) {
|
||||
applyPeerDialogs(result);
|
||||
historyDialogEntryApplied(history);
|
||||
history->dialogEntryApplied();
|
||||
finalize();
|
||||
}).fail([=](const RPCError &error) {
|
||||
finalize();
|
||||
@ -744,7 +744,7 @@ void ApiWrap::requestDialogEntries(
|
||||
)).done([=](const MTPmessages_PeerDialogs &result) {
|
||||
applyPeerDialogs(result);
|
||||
for (const auto history : histories) {
|
||||
historyDialogEntryApplied(history);
|
||||
history->dialogEntryApplied();
|
||||
}
|
||||
finalize(histories);
|
||||
}).fail([=](const RPCError &error) {
|
||||
@ -778,89 +778,41 @@ void ApiWrap::applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs) {
|
||||
_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(
|
||||
not_null<Data::Feed*> feed,
|
||||
const MTPmessages_Dialogs &dialogs) {
|
||||
const auto [dialogsList, messagesList] = [&] {
|
||||
const auto process = [&](const auto &data) {
|
||||
App::feedUsers(data.vusers);
|
||||
App::feedChats(data.vchats);
|
||||
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);
|
||||
if (dialogs.type() == mtpc_messages_dialogsNotModified) {
|
||||
LOG(("API Error: "
|
||||
"messages.dialogsNotModified in ApiWrap::applyFeedDialogs."));
|
||||
return;
|
||||
}
|
||||
|
||||
auto channels = std::vector<not_null<ChannelData*>>();
|
||||
channels.reserve(dialogsList->size());
|
||||
for (const auto &dialog : *dialogsList) {
|
||||
switch (dialog.type()) {
|
||||
case mtpc_dialog: {
|
||||
if (const auto peerId = peerFromMTP(dialog.c_dialog().vpeer)) {
|
||||
if (peerIsChannel(peerId)) {
|
||||
const auto history = App::history(peerId);
|
||||
history->applyDialog(dialog.c_dialog());
|
||||
channels.emplace_back(history->peer->asChannel());
|
||||
} else {
|
||||
LOG(("API Error: "
|
||||
"Unexpected non-channel in feed dialogs list."));
|
||||
dialogs.match([&](const MTPDmessages_dialogsNotModified &) {
|
||||
Unexpected("Type in ApiWrap::applyFeedDialogs.");
|
||||
}, [&](const auto &data) {
|
||||
App::feedUsers(data.vusers);
|
||||
App::feedChats(data.vchats);
|
||||
App::feedMsgs(data.vmessages.v, NewMessageLast);
|
||||
channels.reserve(data.vdialogs.v.size());
|
||||
for (const auto &dialog : data.vdialogs.v) {
|
||||
dialog.match([&](const MTPDdialog &data) {
|
||||
if (const auto peerId = peerFromMTP(data.vpeer)) {
|
||||
if (peerIsChannel(peerId)) {
|
||||
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."));
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
//case mtpc_dialogFeed: { // #feed
|
||||
// LOG(("API Error: Unexpected dialogFeed in feed dialogs list."));
|
||||
//} break;
|
||||
default: Unexpected("Type in DialogsInner::dialogsReceived");
|
||||
//}, [&](const MTPDdialogFeed &) { // #feed
|
||||
// LOG(("API Error: "
|
||||
// "Unexpected dialogFeed in feed dialogs list."));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
feed->setChannels(channels);
|
||||
_session->data().sendHistoryChangeNotifications();
|
||||
@ -878,6 +830,34 @@ void ApiWrap::changeDialogUnreadMark(
|
||||
)).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) {
|
||||
if (_fullPeerRequests.contains(peer)) {
|
||||
return;
|
||||
@ -1768,9 +1748,7 @@ void ApiWrap::deleteAllFromUserSend(
|
||||
if (offset > 0) {
|
||||
deleteAllFromUserSend(channel, from);
|
||||
} else if (const auto history = App::historyLoaded(channel)) {
|
||||
if (!history->lastMessageKnown()) {
|
||||
requestDialogEntry(history);
|
||||
}
|
||||
history->requestChatListMessage();
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
@ -2303,9 +2281,11 @@ int ApiWrap::OnlineTillFromStatus(
|
||||
|
||||
void ApiWrap::clearHistory(not_null<PeerData*> peer) {
|
||||
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()) {
|
||||
deleteTillId = last->id;
|
||||
}
|
||||
if (const auto last = history->chatListMessage()) {
|
||||
Local::addSavedPeer(history->peer, ItemDateTime(last));
|
||||
}
|
||||
history->clear();
|
||||
|
@ -90,6 +90,7 @@ public:
|
||||
// const std::vector<not_null<ChannelData*>> &channels);
|
||||
void changeDialogUnreadMark(not_null<History*> history, bool unread);
|
||||
//void changeDialogUnreadMark(not_null<Data::Feed*> feed, bool unread); // #feed
|
||||
void requestFakeChatListMessage(not_null<History*> history);
|
||||
|
||||
void requestFullPeer(not_null<PeerData*> peer);
|
||||
void requestPeer(not_null<PeerData*> peer);
|
||||
@ -428,7 +429,6 @@ private:
|
||||
QVector<MTPInputMessage> collectMessageIds(const MessageDataRequests &requests);
|
||||
MessageDataRequests *messageDataRequests(ChannelData *channel, bool onlyExisting = false);
|
||||
void applyPeerDialogs(const MTPmessages_PeerDialogs &dialogs);
|
||||
void historyDialogEntryApplied(not_null<History*> history);
|
||||
void applyFeedDialogs(
|
||||
not_null<Data::Feed*> feed,
|
||||
const MTPmessages_Dialogs &dialogs);
|
||||
@ -666,6 +666,7 @@ private:
|
||||
base::flat_map<
|
||||
not_null<History*>,
|
||||
std::vector<Fn<void()>>> _dialogRequests;
|
||||
base::flat_set<not_null<History*>> _fakeChatListRequests;
|
||||
|
||||
base::flat_map<not_null<History*>, mtpRequestId> _unreadMentionsRequests;
|
||||
|
||||
|
@ -380,7 +380,7 @@ namespace App {
|
||||
if (j != data->cend()) {
|
||||
const auto history = (*j)->history();
|
||||
(*j)->destroy();
|
||||
if (!history->lastMessageKnown()) {
|
||||
if (!history->chatListMessageKnown()) {
|
||||
historiesToCheck.emplace(history);
|
||||
}
|
||||
} else if (affectedHistory) {
|
||||
@ -388,7 +388,7 @@ namespace App {
|
||||
}
|
||||
}
|
||||
for (const auto history : historiesToCheck) {
|
||||
Auth().api().requestDialogEntry(history);
|
||||
history->requestChatListMessage();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,12 @@ inline constexpr size_t array_size(const Type(&)[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
|
||||
|
||||
template <typename T>
|
||||
|
@ -605,25 +605,26 @@ void DeleteMessagesBox::deleteAndClear() {
|
||||
_deleteConfirmedCallback();
|
||||
}
|
||||
|
||||
QMap<PeerData*, QVector<MTPint>> idsByPeer;
|
||||
base::flat_map<not_null<PeerData*>, QVector<MTPint>> idsByPeer;
|
||||
for (const auto itemId : _ids) {
|
||||
if (auto item = App::histItemById(itemId)) {
|
||||
auto history = item->history();
|
||||
auto wasOnServer = (item->id > 0);
|
||||
auto wasLast = (history->lastMessage() == item);
|
||||
if (const auto item = App::histItemById(itemId)) {
|
||||
const auto history = item->history();
|
||||
const auto wasOnServer = IsServerMsgId(item->id);
|
||||
const auto wasLast = (history->lastMessage() == item);
|
||||
const auto wasInChats = (history->chatListMessage() == item);
|
||||
item->destroy();
|
||||
|
||||
if (wasOnServer) {
|
||||
idsByPeer[history->peer].push_back(MTP_int(itemId.msg));
|
||||
} else if (wasLast && !history->lastMessageKnown()) {
|
||||
history->session().api().requestDialogEntry(history);
|
||||
} else if (wasLast || wasInChats) {
|
||||
history->requestChatListMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto forEveryone = _forEveryone ? _forEveryone->checked() : false;
|
||||
for (auto i = idsByPeer.cbegin(), e = idsByPeer.cend(); i != e; ++i) {
|
||||
App::main()->deleteMessages(i.key(), i.value(), forEveryone);
|
||||
const auto revoke = _forEveryone ? _forEveryone->checked() : false;
|
||||
for (const auto &[peer, ids] : idsByPeer) {
|
||||
App::main()->deleteMessages(peer, ids, revoke);
|
||||
}
|
||||
Ui::hideLayer();
|
||||
Auth().data().sendHistoryChangeNotifications();
|
||||
|
@ -435,7 +435,7 @@ void Options::removeEmptyTail() {
|
||||
_list,
|
||||
&Option::hasFocus);
|
||||
const auto end = _list.end();
|
||||
auto reversed = ranges::view::reverse(_list);
|
||||
const auto reversed = ranges::view::reverse(_list);
|
||||
const auto emptyItem = ranges::find_if(
|
||||
reversed,
|
||||
ranges::not_fn(&Option::isEmpty)).base();
|
||||
|
@ -1830,7 +1830,7 @@ void SendFilesBox::updateControlsGeometry() {
|
||||
_sendPhotos.data(),
|
||||
_sendFiles.data()
|
||||
};
|
||||
for (auto pointer : base::reversed(pointers)) {
|
||||
for (const auto pointer : ranges::view::reverse(pointers)) {
|
||||
if (pointer) {
|
||||
pointer->moveToLeft(
|
||||
st::boxPhotoPadding.left(),
|
||||
|
@ -966,7 +966,7 @@ void ShareBox::Inner::updateFilter(QString filter) {
|
||||
if (toFilter) {
|
||||
_filtered.reserve(toFilter->size());
|
||||
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;
|
||||
for (fi = fb; fi != fe; ++fi) {
|
||||
auto filterName = *fi;
|
||||
|
@ -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.
|
||||
// thanks to http://stackoverflow.com/questions/18939882/raw-pointer-lookup-for-sets-of-unique-ptrs
|
||||
template <typename T>
|
||||
@ -86,28 +80,6 @@ using set_of_unique_ptr = std::set<std::unique_ptr<T>, base::pointer_comparator<
|
||||
template <typename 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>
|
||||
inline bool in_range(Value &&value, From &&from, Till &&till) {
|
||||
return (value >= from) && (value < till);
|
||||
|
@ -31,14 +31,22 @@ namespace Data {
|
||||
// data.vid.v));
|
||||
//}
|
||||
|
||||
Feed::Feed(FeedId id, not_null<Data::Session*> parent)
|
||||
Feed::Feed(not_null<Data::Session*> owner, FeedId id)
|
||||
: Entry(this)
|
||||
, _id(id)
|
||||
, _parent(parent)
|
||||
, _owner(owner)
|
||||
, _name(lang(lng_feed_name)) {
|
||||
indexNameParts();
|
||||
}
|
||||
|
||||
Data::Session &Feed::owner() const {
|
||||
return *_owner;
|
||||
}
|
||||
|
||||
AuthSession &Feed::session() const {
|
||||
return _owner->session();
|
||||
}
|
||||
|
||||
FeedId Feed::id() const {
|
||||
return _id;
|
||||
}
|
||||
@ -74,17 +82,17 @@ void Feed::registerOne(not_null<ChannelData*> channel) {
|
||||
if (!base::contains(_channels, history)) {
|
||||
const auto invisible = (_channels.size() < 2);
|
||||
_channels.push_back(history);
|
||||
_parent->session().storage().invalidate(
|
||||
session().storage().invalidate(
|
||||
Storage::FeedMessagesInvalidate(_id));
|
||||
|
||||
if (history->lastMessageKnown()) {
|
||||
if (const auto last = history->lastMessage()) {
|
||||
if (justUpdateLastMessage(last)) {
|
||||
if (history->chatListMessageKnown()) {
|
||||
if (const auto last = history->chatListMessage()) {
|
||||
if (justUpdateChatListMessage(last)) {
|
||||
updateChatListEntry();
|
||||
}
|
||||
}
|
||||
} else if (lastMessageKnown()) {
|
||||
_parent->session().api().requestDialogEntry(history);
|
||||
} else if (chatListMessageKnown()) {
|
||||
history->requestChatListMessage();
|
||||
}
|
||||
if (unreadCountKnown()) {
|
||||
if (history->unreadCountKnown()) {
|
||||
@ -96,7 +104,7 @@ void Feed::registerOne(not_null<ChannelData*> channel) {
|
||||
unreadCountChanged(count, history->mute() ? count : 0);
|
||||
}
|
||||
} else if (!_settingChannels) {
|
||||
_parent->session().api().requestDialogEntry(this);
|
||||
session().api().requestDialogEntry(this);
|
||||
}
|
||||
}
|
||||
if (invisible && _channels.size() > 1) {
|
||||
@ -107,7 +115,7 @@ void Feed::registerOne(not_null<ChannelData*> channel) {
|
||||
} else {
|
||||
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)) {
|
||||
const auto visible = (_channels.size() > 1);
|
||||
_channels.erase(i, end(_channels));
|
||||
_parent->session().storage().remove(
|
||||
session().storage().remove(
|
||||
Storage::FeedMessagesRemoveAll(_id, channel->bareId()));
|
||||
|
||||
if (lastMessageKnown()) {
|
||||
if (const auto last = lastMessage()) {
|
||||
if (chatListMessageKnown()) {
|
||||
if (const auto last = chatListMessage()) {
|
||||
if (last->history() == history) {
|
||||
recountLastMessage();
|
||||
recountChatListMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -133,7 +141,7 @@ void Feed::unregisterOne(not_null<ChannelData*> channel) {
|
||||
unreadCountChanged(delta, history->mute() ? delta : 0);
|
||||
}
|
||||
} else {
|
||||
_parent->session().api().requestDialogEntry(this);
|
||||
session().api().requestDialogEntry(this);
|
||||
}
|
||||
}
|
||||
if (visible && _channels.size() < 2) {
|
||||
@ -144,14 +152,14 @@ void Feed::unregisterOne(not_null<ChannelData*> channel) {
|
||||
} else {
|
||||
history->updateChatListExistence();
|
||||
}
|
||||
_parent->notifyFeedUpdated(this, FeedUpdateFlag::Channels);
|
||||
_owner->notifyFeedUpdated(this, FeedUpdateFlag::Channels);
|
||||
}
|
||||
}
|
||||
|
||||
void Feed::updateLastMessage(not_null<HistoryItem*> item) {
|
||||
if (justUpdateLastMessage(item)) {
|
||||
if (_lastMessage && *_lastMessage) {
|
||||
setChatsListTimeId((*_lastMessage)->date());
|
||||
void Feed::updateChatListMessage(not_null<HistoryItem*> item) {
|
||||
if (justUpdateChatListMessage(item)) {
|
||||
if (_chatListMessage && *_chatListMessage) {
|
||||
setChatListTimeId((*_chatListMessage)->date());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -206,7 +214,7 @@ bool Feed::channelsLoaded() const {
|
||||
void Feed::setChannelsLoaded(bool loaded) {
|
||||
if (_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.
|
||||
// So we save it and don't allow channels from the list to change it.
|
||||
// After that we restore it.
|
||||
const auto oldLastMessage = base::take(_lastMessage);
|
||||
const auto oldChatListMessage = base::take(_chatListMessage);
|
||||
for (const auto channel : add) {
|
||||
_lastMessage = std::nullopt;
|
||||
_chatListMessage = std::nullopt;
|
||||
channel->setFeed(this);
|
||||
}
|
||||
_lastMessage = oldLastMessage;
|
||||
_chatListMessage = oldChatListMessage;
|
||||
}
|
||||
|
||||
bool Feed::justUpdateLastMessage(not_null<HistoryItem*> item) {
|
||||
if (!_lastMessage) {
|
||||
bool Feed::justUpdateChatListMessage(not_null<HistoryItem*> item) {
|
||||
if (!_chatListMessage) {
|
||||
return false;
|
||||
} else if (*_lastMessage
|
||||
&& item->position() <= (*_lastMessage)->position()) {
|
||||
} else if (*_chatListMessage
|
||||
&& item->position() <= (*_chatListMessage)->position()) {
|
||||
return false;
|
||||
}
|
||||
_lastMessage = item;
|
||||
_chatListMessage = item;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Feed::messageRemoved(not_null<HistoryItem*> item) {
|
||||
if (lastMessage() == item) {
|
||||
recountLastMessage();
|
||||
if (chatListMessage() == item) {
|
||||
recountChatListMessage();
|
||||
}
|
||||
}
|
||||
|
||||
void Feed::historyCleared(not_null<History*> history) {
|
||||
if (const auto last = lastMessage()) {
|
||||
if (const auto last = chatListMessage()) {
|
||||
if (last->history() == history) {
|
||||
messageRemoved(last);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Feed::recountLastMessage() {
|
||||
_lastMessage = std::nullopt;
|
||||
void Feed::requestChatListMessage() {
|
||||
if (!chatListMessageKnown()) {
|
||||
session().api().requestDialogEntry(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Feed::recountChatListMessage() {
|
||||
_chatListMessage = std::nullopt;
|
||||
for (const auto history : _channels) {
|
||||
if (!history->lastMessageKnown()) {
|
||||
_parent->session().api().requestDialogEntry(this);
|
||||
if (!history->chatListMessageKnown()) {
|
||||
requestChatListMessage();
|
||||
return;
|
||||
}
|
||||
}
|
||||
setLastMessageFromChannels();
|
||||
setChatListMessageFromChannels();
|
||||
}
|
||||
|
||||
void Feed::setLastMessageFromChannels() {
|
||||
_lastMessage = nullptr;
|
||||
void Feed::setChatListMessageFromChannels() {
|
||||
_chatListMessage = nullptr;
|
||||
for (const auto history : _channels) {
|
||||
if (const auto last = history->lastMessage()) {
|
||||
justUpdateLastMessage(last);
|
||||
if (const auto last = history->chatListMessage()) {
|
||||
justUpdateChatListMessage(last);
|
||||
}
|
||||
}
|
||||
updateChatsListDate();
|
||||
updateChatListDate();
|
||||
}
|
||||
|
||||
void Feed::updateChatsListDate() {
|
||||
if (_lastMessage && *_lastMessage) {
|
||||
setChatsListTimeId((*_lastMessage)->date());
|
||||
void Feed::updateChatListDate() {
|
||||
if (_chatListMessage && *_chatListMessage) {
|
||||
setChatListTimeId((*_chatListMessage)->date());
|
||||
}
|
||||
}
|
||||
|
||||
HistoryItem *Feed::lastMessage() const {
|
||||
return _lastMessage ? *_lastMessage : nullptr;
|
||||
}
|
||||
|
||||
bool Feed::lastMessageKnown() const {
|
||||
return !!_lastMessage;
|
||||
}
|
||||
|
||||
int Feed::unreadCount() const {
|
||||
return _unreadCount ? *_unreadCount : 0;
|
||||
}
|
||||
@ -341,17 +347,17 @@ bool Feed::unreadCountKnown() const {
|
||||
// addChannel(channelId.v);
|
||||
// }
|
||||
//
|
||||
// _lastMessage = nullptr;
|
||||
// _chatListMessage = nullptr;
|
||||
// if (const auto peerId = peerFromMTP(data.vpeer)) {
|
||||
// if (const auto channelId = peerToChannel(peerId)) {
|
||||
// addChannel(channelId);
|
||||
// const auto fullId = FullMsgId(channelId, data.vtop_message.v);
|
||||
// if (const auto item = App::histItemById(fullId)) {
|
||||
// justUpdateLastMessage(item);
|
||||
// justUpdateChatListMessage(item);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// updateChatsListDate();
|
||||
// updateChatListDate();
|
||||
//
|
||||
// setUnreadCounts(
|
||||
// data.vunread_count.v,
|
||||
@ -493,19 +499,23 @@ bool Feed::chatListMutedBadge() const {
|
||||
return _unreadCount ? (*_unreadCount <= _unreadMutedCount) : false;
|
||||
}
|
||||
|
||||
HistoryItem *Feed::chatsListItem() const {
|
||||
return lastMessage();
|
||||
HistoryItem *Feed::chatListMessage() const {
|
||||
return _chatListMessage ? *_chatListMessage : nullptr;
|
||||
}
|
||||
|
||||
const QString &Feed::chatsListName() const {
|
||||
bool Feed::chatListMessageKnown() const {
|
||||
return _chatListMessage.has_value();
|
||||
}
|
||||
|
||||
const QString &Feed::chatListName() const {
|
||||
return _name;
|
||||
}
|
||||
|
||||
const base::flat_set<QString> &Feed::chatsListNameWords() const {
|
||||
const base::flat_set<QString> &Feed::chatListNameWords() const {
|
||||
return _nameWords;
|
||||
}
|
||||
|
||||
const base::flat_set<QChar> &Feed::chatsListFirstLetters() const {
|
||||
const base::flat_set<QChar> &Feed::chatListFirstLetters() const {
|
||||
return _nameFirstLetters;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_messages.h"
|
||||
|
||||
class ChannelData;
|
||||
class AuthSession;
|
||||
|
||||
namespace Data {
|
||||
|
||||
@ -34,13 +35,18 @@ public:
|
||||
static constexpr auto kId = 1;
|
||||
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;
|
||||
void registerOne(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 historyCleared(not_null<History*> history);
|
||||
|
||||
@ -54,8 +60,6 @@ public:
|
||||
MessagePosition unreadPosition() const;
|
||||
rpl::producer<MessagePosition> unreadPositionChanges() const;
|
||||
|
||||
HistoryItem *lastMessage() const;
|
||||
bool lastMessageKnown() const;
|
||||
int unreadCount() const;
|
||||
bool unreadCountKnown() const;
|
||||
|
||||
@ -65,10 +69,12 @@ public:
|
||||
int chatListUnreadCount() const override;
|
||||
bool chatListUnreadMark() const override;
|
||||
bool chatListMutedBadge() const override;
|
||||
HistoryItem *chatsListItem() const override;
|
||||
const QString &chatsListName() const override;
|
||||
const base::flat_set<QString> &chatsListNameWords() const override;
|
||||
const base::flat_set<QChar> &chatsListFirstLetters() const override;
|
||||
HistoryItem *chatListMessage() const override;
|
||||
bool chatListMessageKnown() const override;
|
||||
void requestChatListMessage() 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 loadUserpic() override;
|
||||
@ -86,10 +92,10 @@ public:
|
||||
|
||||
private:
|
||||
void indexNameParts();
|
||||
void recountLastMessage();
|
||||
void setLastMessageFromChannels();
|
||||
bool justUpdateLastMessage(not_null<HistoryItem*> item);
|
||||
void updateChatsListDate();
|
||||
void recountChatListMessage();
|
||||
void setChatListMessageFromChannels();
|
||||
bool justUpdateChatListMessage(not_null<HistoryItem*> item);
|
||||
void updateChatListDate();
|
||||
void changeChannelsList(
|
||||
const std::vector<not_null<ChannelData*>> &add,
|
||||
const std::vector<not_null<ChannelData*>> &remove);
|
||||
@ -98,7 +104,7 @@ private:
|
||||
void updateUnreadCounts(PerformUpdate &&performUpdate);
|
||||
|
||||
FeedId _id = 0;
|
||||
not_null<Data::Session*> _parent;
|
||||
not_null<Data::Session*> _owner;
|
||||
std::vector<not_null<History*>> _channels;
|
||||
bool _settingChannels = false;
|
||||
bool _channelsLoaded = false;
|
||||
@ -106,7 +112,7 @@ private:
|
||||
QString _name;
|
||||
base::flat_set<QString> _nameWords;
|
||||
base::flat_set<QChar> _nameFirstLetters;
|
||||
std::optional<HistoryItem*> _lastMessage;
|
||||
std::optional<HistoryItem*> _chatListMessage;
|
||||
|
||||
rpl::variable<MessagePosition> _unreadPosition;
|
||||
std::optional<int> _unreadCount;
|
||||
|
@ -187,7 +187,7 @@ bool Media::canBeGrouped() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
QString Media::chatsListText() const {
|
||||
QString Media::chatListText() const {
|
||||
auto result = notificationText();
|
||||
return result.isEmpty()
|
||||
? QString()
|
||||
@ -304,7 +304,7 @@ QString MediaPhoto::notificationText() const {
|
||||
//return WithCaptionNotificationText(lang(lng_in_dlg_album), _caption);
|
||||
}
|
||||
|
||||
QString MediaPhoto::chatsListText() const {
|
||||
QString MediaPhoto::chatListText() const {
|
||||
return WithCaptionDialogsText(
|
||||
lang(lng_in_dlg_photo),
|
||||
parent()->originalText().text);
|
||||
@ -539,9 +539,9 @@ Image *MediaFile::replyPreview() const {
|
||||
return _document->getReplyPreview(parent()->fullId());
|
||||
}
|
||||
|
||||
QString MediaFile::chatsListText() const {
|
||||
QString MediaFile::chatListText() const {
|
||||
if (const auto sticker = _document->sticker()) {
|
||||
return Media::chatsListText();
|
||||
return Media::chatListText();
|
||||
}
|
||||
const auto type = [&] {
|
||||
if (_document->isVideoMessage()) {
|
||||
@ -861,7 +861,7 @@ LocationData *MediaLocation::location() const {
|
||||
return _location;
|
||||
}
|
||||
|
||||
QString MediaLocation::chatsListText() const {
|
||||
QString MediaLocation::chatListText() const {
|
||||
return WithCaptionDialogsText(lang(lng_maps_point), _title);
|
||||
}
|
||||
|
||||
@ -1032,7 +1032,7 @@ Image *MediaWebPage::replyPreview() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString MediaWebPage::chatsListText() const {
|
||||
QString MediaWebPage::chatListText() const {
|
||||
return notificationText();
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ public:
|
||||
virtual Image *replyPreview() const;
|
||||
// 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"
|
||||
virtual QString chatsListText() const;
|
||||
virtual QString chatListText() const;
|
||||
virtual QString notificationText() const = 0;
|
||||
virtual QString pinnedTextSubstring() const = 0;
|
||||
virtual TextWithEntities clipboardText() const = 0;
|
||||
@ -136,7 +136,7 @@ public:
|
||||
bool canBeGrouped() const override;
|
||||
bool hasReplyPreview() const override;
|
||||
Image *replyPreview() const override;
|
||||
QString chatsListText() const override;
|
||||
QString chatListText() const override;
|
||||
QString notificationText() const override;
|
||||
QString pinnedTextSubstring() const override;
|
||||
TextWithEntities clipboardText() const override;
|
||||
@ -171,7 +171,7 @@ public:
|
||||
bool canBeGrouped() const override;
|
||||
bool hasReplyPreview() const override;
|
||||
Image *replyPreview() const override;
|
||||
QString chatsListText() const override;
|
||||
QString chatListText() const override;
|
||||
QString notificationText() const override;
|
||||
QString pinnedTextSubstring() const override;
|
||||
TextWithEntities clipboardText() const override;
|
||||
@ -233,7 +233,7 @@ public:
|
||||
std::unique_ptr<Media> clone(not_null<HistoryItem*> parent) override;
|
||||
|
||||
LocationData *location() const override;
|
||||
QString chatsListText() const override;
|
||||
QString chatListText() const override;
|
||||
QString notificationText() const override;
|
||||
QString pinnedTextSubstring() const override;
|
||||
TextWithEntities clipboardText() const override;
|
||||
@ -296,7 +296,7 @@ public:
|
||||
|
||||
bool hasReplyPreview() const override;
|
||||
Image *replyPreview() const override;
|
||||
QString chatsListText() const override;
|
||||
QString chatListText() const override;
|
||||
QString notificationText() const override;
|
||||
QString pinnedTextSubstring() const override;
|
||||
TextWithEntities clipboardText() const override;
|
||||
|
@ -2759,7 +2759,7 @@ not_null<Feed*> Session::feed(FeedId id) {
|
||||
}
|
||||
const auto [it, ok] = _feeds.emplace(
|
||||
id,
|
||||
std::make_unique<Feed>(id, this));
|
||||
std::make_unique<Feed>(this, id));
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
@ -3038,9 +3038,7 @@ void Session::setProxyPromoted(PeerData *promoted) {
|
||||
if (_proxyPromoted) {
|
||||
const auto history = this->history(_proxyPromoted);
|
||||
history->cacheProxyPromoted(true);
|
||||
if (!history->lastMessageKnown()) {
|
||||
_session->api().requestDialogEntry(history);
|
||||
}
|
||||
history->requestChatListMessage();
|
||||
Notify::peerUpdatedDelayed(
|
||||
_proxyPromoted,
|
||||
Notify::PeerUpdate::Flag::ChannelPromotedChanged);
|
||||
|
@ -102,7 +102,7 @@ void Entry::setChatListExistence(bool exists) {
|
||||
}
|
||||
|
||||
TimeId Entry::adjustChatListTimeId() const {
|
||||
return chatsListTimeId();
|
||||
return chatListTimeId();
|
||||
}
|
||||
|
||||
void Entry::changedInChatListHook(Dialogs::Mode list, bool added) {
|
||||
@ -135,13 +135,13 @@ PositionChange Entry::adjustByPosInChatList(
|
||||
return { movedFrom, movedTo };
|
||||
}
|
||||
|
||||
void Entry::setChatsListTimeId(TimeId date) {
|
||||
if (_lastMessageTimeId && _lastMessageTimeId >= date) {
|
||||
void Entry::setChatListTimeId(TimeId date) {
|
||||
if (_timeId && _timeId >= date) {
|
||||
if (!inChatList(Dialogs::Mode::All)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_lastMessageTimeId = date;
|
||||
_timeId = date;
|
||||
updateChatListSortPosition();
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ public:
|
||||
return _sortKeyInChatList;
|
||||
}
|
||||
void updateChatListSortPosition();
|
||||
void setChatsListTimeId(TimeId date);
|
||||
void setChatListTimeId(TimeId date);
|
||||
virtual void updateChatListExistence();
|
||||
bool needUpdateInChatList() const;
|
||||
|
||||
@ -74,10 +74,12 @@ public:
|
||||
virtual int chatListUnreadCount() const = 0;
|
||||
virtual bool chatListUnreadMark() const = 0;
|
||||
virtual bool chatListMutedBadge() const = 0;
|
||||
virtual HistoryItem *chatsListItem() const = 0;
|
||||
virtual const QString &chatsListName() const = 0;
|
||||
virtual const base::flat_set<QString> &chatsListNameWords() const = 0;
|
||||
virtual const base::flat_set<QChar> &chatsListFirstLetters() const = 0;
|
||||
virtual HistoryItem *chatListMessage() const = 0;
|
||||
virtual bool chatListMessageKnown() const = 0;
|
||||
virtual void requestChatListMessage() = 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 paintUserpic(
|
||||
@ -94,8 +96,8 @@ public:
|
||||
paintUserpic(p, rtl() ? (w - x - size) : x, y, size);
|
||||
}
|
||||
|
||||
TimeId chatsListTimeId() const {
|
||||
return _lastMessageTimeId;
|
||||
TimeId chatListTimeId() const {
|
||||
return _timeId;
|
||||
}
|
||||
|
||||
virtual ~Entry() = default;
|
||||
@ -118,7 +120,7 @@ private:
|
||||
uint64 _sortKeyInChatList = 0;
|
||||
int _pinnedIndex = 0;
|
||||
bool _isProxyPromoted = false;
|
||||
TimeId _lastMessageTimeId = 0;
|
||||
TimeId _timeId = 0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -23,7 +23,7 @@ RowsByLetter IndexedList::addToEnd(Key key) {
|
||||
RowsByLetter result;
|
||||
if (!_list.contains(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);
|
||||
if (j == _index.cend()) {
|
||||
j = _index.emplace(
|
||||
@ -42,7 +42,7 @@ Row *IndexedList::addByName(Key key) {
|
||||
}
|
||||
|
||||
Row *result = _list.addByName(key);
|
||||
for (auto ch : key.entry()->chatsListFirstLetters()) {
|
||||
for (const auto ch : key.entry()->chatListFirstLetters()) {
|
||||
auto j = _index.find(ch);
|
||||
if (j == _index.cend()) {
|
||||
j = _index.emplace(
|
||||
@ -68,7 +68,7 @@ void IndexedList::adjustByPos(const RowsByLetter &links) {
|
||||
|
||||
void IndexedList::moveToTop(Key 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()) {
|
||||
it->second->moveToTop(key);
|
||||
}
|
||||
@ -123,7 +123,7 @@ void IndexedList::adjustByName(
|
||||
|
||||
auto toRemove = oldLetters;
|
||||
auto toAdd = base::flat_set<QChar>();
|
||||
for (auto ch : key.entry()->chatsListFirstLetters()) {
|
||||
for (const auto ch : key.entry()->chatListFirstLetters()) {
|
||||
auto j = toRemove.find(ch);
|
||||
if (j == toRemove.cend()) {
|
||||
toAdd.insert(ch);
|
||||
@ -162,7 +162,7 @@ void IndexedList::adjustNames(
|
||||
|
||||
auto toRemove = oldLetters;
|
||||
auto toAdd = base::flat_set<QChar>();
|
||||
for (auto ch : key.entry()->chatsListFirstLetters()) {
|
||||
for (const auto ch : key.entry()->chatListFirstLetters()) {
|
||||
auto j = toRemove.find(ch);
|
||||
if (j == toRemove.cend()) {
|
||||
toAdd.insert(ch);
|
||||
@ -194,7 +194,7 @@ void IndexedList::adjustNames(
|
||||
|
||||
void IndexedList::del(Key key, Row *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()) {
|
||||
it->second->del(key, replacedBy);
|
||||
}
|
||||
|
@ -1702,7 +1702,7 @@ void DialogsInner::applyFilterUpdate(QString newFilter, bool force) {
|
||||
+ (toFilterContacts ? toFilterContacts->size() : 0));
|
||||
if (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;
|
||||
for (fi = fb; fi != fe; ++fi) {
|
||||
auto filterWord = *fi;
|
||||
@ -1722,7 +1722,7 @@ void DialogsInner::applyFilterUpdate(QString newFilter, bool force) {
|
||||
}
|
||||
if (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;
|
||||
for (fi = fb; fi != fe; ++fi) {
|
||||
auto filterWord = *fi;
|
||||
@ -1875,7 +1875,7 @@ void DialogsInner::applyDialog(const MTPDdialog &dialog) {
|
||||
history->applyDialog(dialog);
|
||||
|
||||
if (!history->useProxyPromotion() && !history->isPinnedDialog()) {
|
||||
const auto date = history->chatsListTimeId();
|
||||
const auto date = history->chatListTimeId();
|
||||
if (date != 0) {
|
||||
addSavedPeersAfter(ParseDateTime(date));
|
||||
}
|
||||
@ -1898,7 +1898,7 @@ void DialogsInner::applyDialog(const MTPDdialog &dialog) {
|
||||
// feed->applyDialog(dialog);
|
||||
//
|
||||
// if (!feed->useProxyPromotion() && !feed->isPinnedDialog()) {
|
||||
// const auto date = feed->chatsListDate();
|
||||
// const auto date = feed->chatListDate();
|
||||
// if (!date.isNull()) {
|
||||
// addSavedPeersAfter(date);
|
||||
// }
|
||||
@ -1913,7 +1913,7 @@ void DialogsInner::addSavedPeersAfter(const QDateTime &date) {
|
||||
saved.remove(lastDate, lastPeer);
|
||||
|
||||
const auto history = App::history(lastPeer);
|
||||
history->setChatsListTimeId(ServerTimeFromParsed(lastDate));
|
||||
history->setChatListTimeId(ServerTimeFromParsed(lastDate));
|
||||
_contactsNoDialogs->del(history);
|
||||
}
|
||||
}
|
||||
@ -2233,7 +2233,7 @@ void DialogsInner::refreshSearchInChatLabel() {
|
||||
}
|
||||
return peer->name;
|
||||
} else if (const auto feed = _searchInChat.feed()) {
|
||||
return feed->chatsListName();
|
||||
return feed->chatListName();
|
||||
}
|
||||
return QString();
|
||||
}();
|
||||
|
@ -377,7 +377,7 @@ void paintRow(
|
||||
from->dialogName().drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
|
||||
} else {
|
||||
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);
|
||||
if (textWidth > rectForName.width()) {
|
||||
text = st::msgNameFont->elided(text, rectForName.width());
|
||||
@ -528,7 +528,7 @@ void RowPainter::paint(
|
||||
const auto unreadCount = entry->chatListUnreadCount();
|
||||
const auto unreadMark = entry->chatListUnreadMark();
|
||||
const auto unreadMuted = entry->chatListMutedBadge();
|
||||
const auto item = entry->chatsListItem();
|
||||
const auto item = entry->chatListMessage();
|
||||
const auto cloudDraft = [&]() -> const Data::Draft*{
|
||||
if (history && (!item || (!unreadCount && !unreadMark))) {
|
||||
// Draw item, if there are unread messages.
|
||||
|
@ -114,15 +114,15 @@ Row *List::adjustByName(Key key) {
|
||||
if (i == _rowByKey.cend()) return nullptr;
|
||||
|
||||
const auto row = i->second;
|
||||
const auto name = key.entry()->chatsListName();
|
||||
const auto name = key.entry()->chatListName();
|
||||
auto change = row;
|
||||
while (change->_prev
|
||||
&& change->_prev->entry()->chatsListName().compare(name, Qt::CaseInsensitive) < 0) {
|
||||
&& change->_prev->entry()->chatListName().compare(name, Qt::CaseInsensitive) < 0) {
|
||||
change = change->_prev;
|
||||
}
|
||||
if (!insertBefore(row, change)) {
|
||||
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;
|
||||
}
|
||||
insertAfter(row, change);
|
||||
@ -137,14 +137,14 @@ Row *List::addByName(Key key) {
|
||||
|
||||
const auto row = addToEnd(key);
|
||||
auto change = row;
|
||||
const auto name = key.entry()->chatsListName();
|
||||
const auto name = key.entry()->chatListName();
|
||||
while (change->_prev
|
||||
&& change->_prev->entry()->chatsListName().compare(name, Qt::CaseInsensitive) > 0) {
|
||||
&& change->_prev->entry()->chatListName().compare(name, Qt::CaseInsensitive) > 0) {
|
||||
change = change->_prev;
|
||||
}
|
||||
if (!insertBefore(row, change)) {
|
||||
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;
|
||||
}
|
||||
insertAfter(row, change);
|
||||
|
@ -716,7 +716,7 @@ int InnerWidget::resizeGetHeight(int newWidth) {
|
||||
|
||||
const auto resizeAllItems = (_itemsWidth != newWidth);
|
||||
auto newHeight = 0;
|
||||
for (auto &item : base::reversed(_items)) {
|
||||
for (const auto &item : ranges::view::reverse(_items)) {
|
||||
item->setY(newHeight);
|
||||
if (item->pendingResize() || resizeAllItems) {
|
||||
newHeight += item->resizeGetHeight(newWidth);
|
||||
|
@ -60,9 +60,9 @@ constexpr auto kSkipCloudDraftsFor = TimeId(3);
|
||||
|
||||
} // namespace
|
||||
|
||||
History::History(not_null<Data::Session*> owner, const PeerId &peerId)
|
||||
History::History(not_null<Data::Session*> owner, PeerId peerId)
|
||||
: Entry(this)
|
||||
, peer(App::peer(peerId))
|
||||
, peer(owner->peer(peerId))
|
||||
, cloudDraftTextCache(st::dialogsTextWidthMin)
|
||||
, _owner(owner)
|
||||
, _mute(_owner->notifyIsMuted(peer))
|
||||
@ -138,15 +138,31 @@ void History::itemRemoved(not_null<HistoryItem*> item) {
|
||||
setLastMessage(last);
|
||||
}
|
||||
}
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
if (const auto feed = channel->feed()) {
|
||||
// Must be after history->lastMessage() is updated.
|
||||
// Otherwise feed last message will be this value again.
|
||||
feed->messageRemoved(item);
|
||||
}
|
||||
checkChatListMessageRemoved(item);
|
||||
itemVanished(item);
|
||||
if (const auto chat = peer->asChat()) {
|
||||
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) {
|
||||
@ -1130,7 +1146,7 @@ void History::newItemAdded(not_null<HistoryItem*> item) {
|
||||
notifies.push_back(item);
|
||||
App::main()->newUnreadMsg(this, item);
|
||||
}
|
||||
} else if (!item->isGroupMigrate() || !peer->isMegagroup()) {
|
||||
} else {
|
||||
inboxRead(item);
|
||||
}
|
||||
}
|
||||
@ -1285,7 +1301,7 @@ void History::addItemsToLists(
|
||||
// lastParticipants are displayed in Profile as members list.
|
||||
markupSenders = &peer->asChannel()->mgInfo->markupSenders;
|
||||
}
|
||||
for (const auto item : base::reversed(items)) {
|
||||
for (const auto item : ranges::view::reverse(items)) {
|
||||
item->addToUnreadMentions(UnreadMentionType::Existing);
|
||||
if (item->from()->id) {
|
||||
if (lastAuthors) { // chats
|
||||
@ -1465,7 +1481,7 @@ void History::inboxRead(not_null<const HistoryItem*> wasRead) {
|
||||
|
||||
void History::outboxRead(MsgId upTo) {
|
||||
setOutboxReadTill(upTo);
|
||||
if (const auto last = lastMessage()) {
|
||||
if (const auto last = chatListMessage()) {
|
||||
if (last->out() && IsServerMsgId(last->id) && last->id <= upTo) {
|
||||
if (const auto main = App::main()) {
|
||||
main->repaintDialogRow({ this, last->fullId() });
|
||||
@ -1701,7 +1717,7 @@ std::shared_ptr<AdminLog::LocalIdManager> History::adminLogIdManager() {
|
||||
}
|
||||
|
||||
TimeId History::adjustChatListTimeId() const {
|
||||
const auto result = chatsListTimeId();
|
||||
const auto result = chatListTimeId();
|
||||
if (const auto draft = cloudDraft()) {
|
||||
if (!Data::draftIsNull(draft) && !session().supportMode()) {
|
||||
return std::max(result, draft->date);
|
||||
@ -1889,19 +1905,23 @@ bool History::chatListMutedBadge() const {
|
||||
return mute();
|
||||
}
|
||||
|
||||
HistoryItem *History::chatsListItem() const {
|
||||
return lastMessage();
|
||||
HistoryItem *History::chatListMessage() const {
|
||||
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;
|
||||
}
|
||||
|
||||
const base::flat_set<QString> &History::chatsListNameWords() const {
|
||||
const base::flat_set<QString> &History::chatListNameWords() const {
|
||||
return peer->nameWords();
|
||||
}
|
||||
|
||||
const base::flat_set<QChar> &History::chatsListFirstLetters() const {
|
||||
const base::flat_set<QChar> &History::chatListFirstLetters() const {
|
||||
return peer->nameFirstLetters();
|
||||
}
|
||||
|
||||
@ -2050,40 +2070,194 @@ void History::markFullyLoaded() {
|
||||
}
|
||||
|
||||
void History::setLastMessage(HistoryItem *item) {
|
||||
if (item) {
|
||||
if (_lastMessage) {
|
||||
if (!*_lastMessage) {
|
||||
Local::removeSavedPeer(peer);
|
||||
} else if (!IsServerMsgId((*_lastMessage)->id)
|
||||
&& (*_lastMessage)->date() > item->date()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_lastMessage = item;
|
||||
if (const auto feed = peer->feed()) {
|
||||
feed->updateLastMessage(item);
|
||||
}
|
||||
setChatsListTimeId(item->date());
|
||||
} else if (!_lastMessage || *_lastMessage) {
|
||||
_lastMessage = nullptr;
|
||||
updateChatListEntry();
|
||||
if (_lastMessage && *_lastMessage == item) {
|
||||
return;
|
||||
}
|
||||
_lastMessage = item;
|
||||
_chatListMessage = std::nullopt;
|
||||
if (!peer->migrateTo()) {
|
||||
// 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.
|
||||
requestChatListMessage();
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
return _lastMessage ? (*_lastMessage) : nullptr;
|
||||
return _lastMessage.value_or(nullptr);
|
||||
}
|
||||
|
||||
bool History::lastMessageKnown() const {
|
||||
return !!_lastMessage;
|
||||
return _lastMessage.has_value();
|
||||
}
|
||||
|
||||
void History::updateChatListExistence() {
|
||||
Entry::updateChatListExistence();
|
||||
if (!lastMessageKnown() || !unreadCountKnown()) {
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
if (!channel->feed()) {
|
||||
// After ungrouping from a feed we need to load dialog.
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
if (!channel->feed()) {
|
||||
// After ungrouping from a feed we need to load dialog.
|
||||
requestChatListMessage();
|
||||
if (!unreadCountKnown()) {
|
||||
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 {
|
||||
if (!session().supportMode()) {
|
||||
return false;
|
||||
@ -2253,8 +2472,8 @@ MsgId History::minMsgId() const {
|
||||
}
|
||||
|
||||
MsgId History::maxMsgId() const {
|
||||
for (const auto &block : base::reversed(blocks)) {
|
||||
for (const auto &message : base::reversed(block->messages)) {
|
||||
for (const auto &block : ranges::view::reverse(blocks)) {
|
||||
for (const auto &message : ranges::view::reverse(block->messages)) {
|
||||
const auto item = message->data();
|
||||
if (IsServerMsgId(item->id)) {
|
||||
return item->id;
|
||||
@ -2278,8 +2497,8 @@ HistoryItem *History::lastSentMessage() const {
|
||||
if (!loadedAtBottom()) {
|
||||
return nullptr;
|
||||
}
|
||||
for (const auto &block : base::reversed(blocks)) {
|
||||
for (const auto &message : base::reversed(block->messages)) {
|
||||
for (const auto &block : ranges::view::reverse(blocks)) {
|
||||
for (const auto &message : ranges::view::reverse(block->messages)) {
|
||||
const auto item = message->data();
|
||||
// Skip if message is video message or sticker.
|
||||
if (const auto media = item->media()) {
|
||||
@ -2336,7 +2555,7 @@ bool History::isMegagroup() const {
|
||||
}
|
||||
|
||||
not_null<History*> History::migrateToOrMe() const {
|
||||
if (auto to = peer->migrateTo()) {
|
||||
if (const auto to = peer->migrateTo()) {
|
||||
return App::history(to);
|
||||
}
|
||||
// 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 {
|
||||
if (auto from = peer->migrateFrom()) {
|
||||
if (const auto from = peer->migrateFrom()) {
|
||||
return App::history(from);
|
||||
}
|
||||
return nullptr;
|
||||
@ -2423,7 +2642,7 @@ HistoryService *History::insertJoinedMessage(bool unread) {
|
||||
// Due to a server bug sometimes inviteDate is less (before) than the
|
||||
// first message in the megagroup (message about migration), let us
|
||||
// ignore that and think, that the inviteDate is always greater-or-equal.
|
||||
if (item->isGroupMigrate()
|
||||
if ((item->id == 1)
|
||||
&& peer->isMegagroup()
|
||||
&& peer->migrateFrom()) {
|
||||
peer->asChannel()->mgInfo->joinedMessageFound = true;
|
||||
@ -2437,7 +2656,7 @@ HistoryService *History::insertJoinedMessage(bool unread) {
|
||||
inviter,
|
||||
flags);
|
||||
addNewInTheMiddle(_joinedMessage, blockIndex, itemIndex);
|
||||
const auto lastDate = chatsListTimeId();
|
||||
const auto lastDate = chatListTimeId();
|
||||
if (!lastDate || inviteDate >= lastDate) {
|
||||
setLastMessage(_joinedMessage);
|
||||
if (unread) {
|
||||
@ -2508,9 +2727,29 @@ bool History::isEmpty() const {
|
||||
}
|
||||
|
||||
bool History::isDisplayedEmpty() const {
|
||||
return isEmpty() || ((blocks.size() == 1)
|
||||
&& blocks.front()->messages.size() == 1
|
||||
&& blocks.front()->messages.front()->data()->isEmpty());
|
||||
return findFirstNonEmpty() == nullptr;
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -2624,9 +2863,7 @@ void History::clearUpTill(MsgId availableMinId) {
|
||||
item->destroy();
|
||||
} while (!isEmpty());
|
||||
|
||||
if (!lastMessageKnown()) {
|
||||
session().api().requestDialogEntry(this);
|
||||
}
|
||||
requestChatListMessage();
|
||||
_owner->sendHistoryChangeNotifications();
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ class History final : public Dialogs::Entry {
|
||||
public:
|
||||
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 &operator=(const History &) = delete;
|
||||
|
||||
@ -77,6 +77,8 @@ public:
|
||||
|
||||
bool isEmpty() const;
|
||||
bool isDisplayedEmpty() const;
|
||||
Element *findFirstNonEmpty() const;
|
||||
Element *findLastNonEmpty() const;
|
||||
bool hasOrphanMediaGroupPart() const;
|
||||
bool removeOrphanMediaGroupPart();
|
||||
QVector<MsgId> collectMessagesFromUserToDelete(
|
||||
@ -192,6 +194,7 @@ public:
|
||||
int unreadCount,
|
||||
MsgId maxInboxRead,
|
||||
MsgId maxOutboxRead);
|
||||
void dialogEntryApplied();
|
||||
|
||||
MsgId minMsgId() const;
|
||||
MsgId maxMsgId() const;
|
||||
@ -283,10 +286,12 @@ public:
|
||||
int chatListUnreadCount() const override;
|
||||
bool chatListUnreadMark() const override;
|
||||
bool chatListMutedBadge() const override;
|
||||
HistoryItem *chatsListItem() const override;
|
||||
const QString &chatsListName() const override;
|
||||
const base::flat_set<QString> &chatsListNameWords() const override;
|
||||
const base::flat_set<QChar> &chatsListFirstLetters() const override;
|
||||
HistoryItem *chatListMessage() const override;
|
||||
bool chatListMessageKnown() const override;
|
||||
void requestChatListMessage() 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 paintUserpic(
|
||||
Painter &p,
|
||||
@ -294,6 +299,9 @@ public:
|
||||
int y,
|
||||
int size) const override;
|
||||
|
||||
void setFakeChatListMessageFrom(const MTPmessages_Messages &data);
|
||||
void checkChatListMessageRemoved(not_null<HistoryItem*> item);
|
||||
|
||||
void forgetScrollState() {
|
||||
scrollTopItem = nullptr;
|
||||
}
|
||||
@ -411,6 +419,12 @@ private:
|
||||
void checkLastMessage();
|
||||
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.
|
||||
void checkAddAllToUnreadMentions();
|
||||
|
||||
@ -449,6 +463,12 @@ private:
|
||||
std::optional<int> _unreadMentionsCount;
|
||||
base::flat_set<MsgId> _unreadMentions;
|
||||
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;
|
||||
|
||||
// A pointer to the block that is currently being built.
|
||||
|
@ -436,10 +436,6 @@ void HistoryInner::enumerateDates(Method method) {
|
||||
if (itemtop > _visibleAreaTop) {
|
||||
// Previous item (from the _migrated history) is drawing date now.
|
||||
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);
|
||||
}
|
||||
|
||||
// with migrated history we perhaps do not need to display first _history message
|
||||
// (if last _migrated message and first _history message are both isGroupMigrate)
|
||||
// or at least we don't need to display first _history date (just skip it by height)
|
||||
// With migrated history we perhaps do not need to display
|
||||
// the first _history message date (just skip it by height).
|
||||
_historySkipHeight = 0;
|
||||
if (_migrated) {
|
||||
if (!_migrated->isEmpty() && !_history->isEmpty() && _migrated->loadedAtBottom() && _history->loadedAtTop()) {
|
||||
if (_migrated->blocks.back()->messages.back()->dateTime().date() == _history->blocks.front()->messages.front()->dateTime().date()) {
|
||||
if (_migrated->blocks.back()->messages.back()->data()->isGroupMigrate() && _history->blocks.front()->messages.front()->data()->isGroupMigrate()) {
|
||||
_historySkipHeight += _history->blocks.front()->messages.front()->height();
|
||||
} else if (_migrated->height() > _history->blocks.front()->messages.front()->displayedDateHeight()) {
|
||||
_historySkipHeight += _history->blocks.front()->messages.front()->displayedDateHeight();
|
||||
if (_migrated
|
||||
&& _migrated->loadedAtBottom()
|
||||
&& _history->loadedAtTop()) {
|
||||
if (const auto first = _history->findFirstNonEmpty()) {
|
||||
if (const auto last = _migrated->findLastNonEmpty()) {
|
||||
if (first->dateTime().date() == last->dateTime().date()) {
|
||||
const auto dateHeight = first->displayedDateHeight();
|
||||
if (_migrated->height() > dateHeight) {
|
||||
_historySkipHeight += dateHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -298,9 +298,8 @@ private:
|
||||
int _contentWidth = 0;
|
||||
int _historyPaddingTop = 0;
|
||||
|
||||
// with migrated history we perhaps do not need to display first _history message
|
||||
// (if last _migrated message and first _history message are both isGroupMigrate)
|
||||
// or at least we don't need to display first _history date (just skip it by height)
|
||||
// With migrated history we perhaps do not need to display
|
||||
// the first _history message date (just skip it by height).
|
||||
int _historySkipHeight = 0;
|
||||
|
||||
std::unique_ptr<BotAbout> _botAbout;
|
||||
|
@ -176,12 +176,12 @@ TimeId HistoryItem::date() const {
|
||||
|
||||
void HistoryItem::finishEdition(int oldKeyboardTop) {
|
||||
_history->owner().requestItemViewRefresh(this);
|
||||
invalidateChatsListEntry();
|
||||
invalidateChatListEntry();
|
||||
if (const auto group = _history->owner().groups().find(this)) {
|
||||
const auto leader = group->items.back();
|
||||
if (leader != this) {
|
||||
_history->owner().requestItemViewRefresh(leader);
|
||||
leader->invalidateChatsListEntry();
|
||||
leader->invalidateChatListEntry();
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,7 +217,7 @@ ReplyKeyboard *HistoryItem::inlineReplyKeyboard() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void HistoryItem::invalidateChatsListEntry() {
|
||||
void HistoryItem::invalidateChatListEntry() {
|
||||
if (const auto main = App::main()) {
|
||||
// #TODO feeds search results
|
||||
main->repaintDialogRow({ history(), fullId() });
|
||||
@ -462,7 +462,7 @@ bool HistoryItem::canDelete() const {
|
||||
}
|
||||
auto channel = _history->peer->asChannel();
|
||||
if (!channel) {
|
||||
return !(_flags & MTPDmessage_ClientFlag::f_is_group_migrate);
|
||||
return !(_flags & MTPDmessage_ClientFlag::f_is_group_essential);
|
||||
}
|
||||
|
||||
if (id == 1) {
|
||||
@ -706,7 +706,7 @@ QString HistoryItem::notificationText() const {
|
||||
QString HistoryItem::inDialogsText(DrawInDialog way) const {
|
||||
auto getText = [this]() {
|
||||
if (_media) {
|
||||
return _media->chatsListText();
|
||||
return _media->chatListText();
|
||||
} else if (!emptyText()) {
|
||||
return TextUtilities::Clean(_text.originalText());
|
||||
}
|
||||
|
@ -134,8 +134,8 @@ public:
|
||||
bool hasTextLinks() const {
|
||||
return _flags & MTPDmessage_ClientFlag::f_has_text_links;
|
||||
}
|
||||
bool isGroupMigrate() const {
|
||||
return _flags & MTPDmessage_ClientFlag::f_is_group_migrate;
|
||||
bool isGroupEssential() const {
|
||||
return _flags & MTPDmessage_ClientFlag::f_is_group_essential;
|
||||
}
|
||||
bool hasViews() const {
|
||||
return _flags & MTPDmessage::Flag::f_views;
|
||||
@ -294,7 +294,7 @@ protected:
|
||||
}
|
||||
HistoryMessageReplyMarkup *inlineReplyMarkup();
|
||||
ReplyKeyboard *inlineReplyKeyboard();
|
||||
void invalidateChatsListEntry();
|
||||
void invalidateChatListEntry();
|
||||
|
||||
void setGroupId(MessageGroupId groupId);
|
||||
|
||||
|
@ -36,7 +36,7 @@ constexpr auto kPinnedMessageTextLimit = 16;
|
||||
|
||||
void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
auto prepareChatAddUserText = [this](const MTPDmessageActionChatAddUser &action) {
|
||||
auto result = PreparedText {};
|
||||
auto result = PreparedText{};
|
||||
auto &users = action.vusers.v;
|
||||
if (users.size() == 1) {
|
||||
auto u = App::user(peerFromUser(users[0]));
|
||||
@ -72,14 +72,14 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
};
|
||||
|
||||
auto prepareChatJoinedByLink = [this](const MTPDmessageActionChatJoinedByLink &action) {
|
||||
auto result = PreparedText {};
|
||||
auto result = PreparedText{};
|
||||
result.links.push_back(fromLink());
|
||||
result.text = lng_action_user_joined_by_link(lt_from, fromLinkText());
|
||||
return result;
|
||||
};
|
||||
|
||||
auto prepareChatCreate = [this](const MTPDmessageActionChatCreate &action) {
|
||||
auto result = PreparedText {};
|
||||
auto result = PreparedText{};
|
||||
result.links.push_back(fromLink());
|
||||
result.text = lng_action_created_chat(lt_from, fromLinkText(), lt_title, TextUtilities::Clean(qs(action.vtitle)));
|
||||
return result;
|
||||
@ -97,7 +97,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
};
|
||||
|
||||
auto prepareChatDeletePhoto = [this] {
|
||||
auto result = PreparedText {};
|
||||
auto result = PreparedText{};
|
||||
if (isPost()) {
|
||||
result.text = lang(lng_action_removed_photo_channel);
|
||||
} else {
|
||||
@ -108,7 +108,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
};
|
||||
|
||||
auto prepareChatDeleteUser = [this](const MTPDmessageActionChatDeleteUser &action) {
|
||||
auto result = PreparedText {};
|
||||
auto result = PreparedText{};
|
||||
if (peerFromUser(action.vuser_id) == _from->id) {
|
||||
result.links.push_back(fromLink());
|
||||
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 result = PreparedText {};
|
||||
auto result = PreparedText{};
|
||||
if (isPost()) {
|
||||
result.text = lang(lng_action_changed_photo_channel);
|
||||
} else {
|
||||
@ -133,7 +133,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
};
|
||||
|
||||
auto prepareChatEditTitle = [this](const MTPDmessageActionChatEditTitle &action) {
|
||||
auto result = PreparedText {};
|
||||
auto result = PreparedText{};
|
||||
if (isPost()) {
|
||||
result.text = lng_action_changed_title_channel(lt_title, TextUtilities::Clean(qs(action.vtitle)));
|
||||
} else {
|
||||
@ -144,7 +144,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
};
|
||||
|
||||
auto prepareScreenshotTaken = [this] {
|
||||
auto result = PreparedText {};
|
||||
auto result = PreparedText{};
|
||||
if (out()) {
|
||||
result.text = lang(lng_action_you_took_screenshot);
|
||||
} else {
|
||||
@ -155,7 +155,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
};
|
||||
|
||||
auto prepareCustomAction = [&](const MTPDmessageActionCustomAction &action) {
|
||||
auto result = PreparedText {};
|
||||
auto result = PreparedText{};
|
||||
result.text = qs(action.vmessage);
|
||||
return result;
|
||||
};
|
||||
@ -214,69 +214,98 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
return result;
|
||||
};
|
||||
|
||||
auto messageText = PreparedText {};
|
||||
|
||||
switch (action.type()) {
|
||||
case mtpc_messageActionChatAddUser: messageText = prepareChatAddUserText(action.c_messageActionChatAddUser()); break;
|
||||
case mtpc_messageActionChatJoinedByLink: messageText = prepareChatJoinedByLink(action.c_messageActionChatJoinedByLink()); break;
|
||||
case mtpc_messageActionChatCreate: messageText = prepareChatCreate(action.c_messageActionChatCreate()); break;
|
||||
case mtpc_messageActionChannelCreate: messageText = prepareChannelCreate(action.c_messageActionChannelCreate()); break;
|
||||
case mtpc_messageActionHistoryClear: break; // Leave empty text.
|
||||
case mtpc_messageActionChatDeletePhoto: messageText = prepareChatDeletePhoto(); break;
|
||||
case mtpc_messageActionChatDeleteUser: messageText = prepareChatDeleteUser(action.c_messageActionChatDeleteUser()); break;
|
||||
case mtpc_messageActionChatEditPhoto: messageText = prepareChatEditPhoto(action.c_messageActionChatEditPhoto()); break;
|
||||
case mtpc_messageActionChatEditTitle: messageText = prepareChatEditTitle(action.c_messageActionChatEditTitle()); break;
|
||||
case mtpc_messageActionChatMigrateTo: messageText.text = lang(lng_action_group_migrate); break;
|
||||
case mtpc_messageActionChannelMigrateFrom: messageText.text = lang(lng_action_group_migrate); break;
|
||||
case mtpc_messageActionPinMessage: messageText = preparePinnedText(); break;
|
||||
case mtpc_messageActionGameScore: messageText = prepareGameScoreText(); break;
|
||||
case mtpc_messageActionPhoneCall: Unexpected("PhoneCall type in HistoryService.");
|
||||
case mtpc_messageActionPaymentSent: messageText = preparePaymentSentText(); break;
|
||||
case mtpc_messageActionScreenshotTaken: messageText = prepareScreenshotTaken(); break;
|
||||
case mtpc_messageActionCustomAction: messageText = prepareCustomAction(action.c_messageActionCustomAction()); break;
|
||||
case mtpc_messageActionBotAllowed: messageText = prepareBotAllowed(action.c_messageActionBotAllowed()); break;
|
||||
case mtpc_messageActionSecureValuesSent: messageText = prepareSecureValuesSent(action.c_messageActionSecureValuesSent()); break;
|
||||
case mtpc_messageActionContactSignUp: messageText = prepareContactSignUp(); break;
|
||||
default: messageText.text = lang(lng_message_empty); break;
|
||||
}
|
||||
const auto messageText = action.match([&](
|
||||
const MTPDmessageActionChatAddUser &data) {
|
||||
return prepareChatAddUserText(data);
|
||||
}, [&](const MTPDmessageActionChatJoinedByLink &data) {
|
||||
return prepareChatJoinedByLink(data);
|
||||
}, [&](const MTPDmessageActionChatCreate &data) {
|
||||
return prepareChatCreate(data);
|
||||
}, [](const MTPDmessageActionChatMigrateTo &) {
|
||||
return PreparedText();
|
||||
}, [](const MTPDmessageActionChannelMigrateFrom &) {
|
||||
return PreparedText();
|
||||
}, [](const MTPDmessageActionHistoryClear &) {
|
||||
return PreparedText();
|
||||
}, [&](const MTPDmessageActionChannelCreate &data) {
|
||||
return prepareChannelCreate(data);
|
||||
}, [&](const MTPDmessageActionChatDeletePhoto &) {
|
||||
return prepareChatDeletePhoto();
|
||||
}, [&](const MTPDmessageActionChatDeleteUser &data) {
|
||||
return prepareChatDeleteUser(data);
|
||||
}, [&](const MTPDmessageActionChatEditPhoto &data) {
|
||||
return prepareChatEditPhoto(data);
|
||||
}, [&](const MTPDmessageActionChatEditTitle &data) {
|
||||
return prepareChatEditTitle(data);
|
||||
}, [&](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);
|
||||
|
||||
// Additional information.
|
||||
switch (action.type()) {
|
||||
case mtpc_messageActionChatAddUser: {
|
||||
if (auto channel = history()->peer->asMegagroup()) {
|
||||
auto &users = action.c_messageActionChatAddUser().vusers;
|
||||
for_const (auto &item, users.v) {
|
||||
if (item.v == history()->session().userId()) {
|
||||
applyAction(action);
|
||||
}
|
||||
|
||||
void HistoryService::applyAction(const MTPMessageAction &action) {
|
||||
action.match([&](const MTPDmessageActionChatAddUser &data) {
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_messageActionChatJoinedByLink: {
|
||||
if (_from->isSelf() && history()->peer->isMegagroup()) {
|
||||
history()->peer->asChannel()->mgInfo->joinedMessageFound = true;
|
||||
}, [&](const MTPDmessageActionChatJoinedByLink &data) {
|
||||
if (_from->isSelf()) {
|
||||
if (const auto channel = history()->peer->asMegagroup()) {
|
||||
channel->mgInfo->joinedMessageFound = true;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_messageActionChatEditPhoto: {
|
||||
auto &photo = action.c_messageActionChatEditPhoto().vphoto;
|
||||
if (photo.type() == mtpc_photo) {
|
||||
}, [&](const MTPDmessageActionChatEditPhoto &data) {
|
||||
data.vphoto.match([&](const MTPDphoto &photo) {
|
||||
_media = std::make_unique<Data::MediaPhoto>(
|
||||
this,
|
||||
history()->peer,
|
||||
history()->owner().photo(photo.c_photo()));
|
||||
}
|
||||
} break;
|
||||
|
||||
case mtpc_messageActionChatMigrateTo:
|
||||
case mtpc_messageActionChannelMigrateFrom: {
|
||||
_flags |= MTPDmessage_ClientFlag::f_is_group_migrate;
|
||||
} break;
|
||||
}
|
||||
history()->owner().photo(photo));
|
||||
}, [](const MTPDphotoEmpty &) {
|
||||
});
|
||||
}, [&](const MTPDmessageActionChatCreate &) {
|
||||
_flags |= MTPDmessage_ClientFlag::f_is_group_essential;
|
||||
}, [&](const MTPDmessageActionChannelCreate &) {
|
||||
_flags |= MTPDmessage_ClientFlag::f_is_group_essential;
|
||||
}, [&](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) {
|
||||
|
@ -137,7 +137,10 @@ private:
|
||||
void createFromMtp(const MTPDmessage &message);
|
||||
void createFromMtp(const MTPDmessageService &message);
|
||||
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 prepareGameScoreText();
|
||||
|
@ -730,26 +730,6 @@ void HistoryWidget::highlightMessage(MsgId universalMessageId) {
|
||||
_highlightStart = getms();
|
||||
_highlightedMessageId = universalMessageId;
|
||||
_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() {
|
||||
@ -4902,7 +4882,6 @@ void HistoryWidget::addMessagesToFront(PeerData *peer, const QVector<MTPMessage>
|
||||
_list->messagesReceived(peer, messages);
|
||||
if (!_firstLoadRequest) {
|
||||
updateHistoryGeometry();
|
||||
adjustHighlightedMessageToMigrated();
|
||||
updateBotKeyboard();
|
||||
}
|
||||
}
|
||||
@ -5553,22 +5532,15 @@ void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) {
|
||||
return;
|
||||
}
|
||||
if (item->history() == _migrated) {
|
||||
if (item->isGroupMigrate()
|
||||
&& !_history->isEmpty()
|
||||
&& _history->blocks.front()->messages.front()->data()->isGroupMigrate()
|
||||
&& _history != _migrated) {
|
||||
replyToMessage(_history->blocks.front()->messages.front()->data());
|
||||
if (item->serviceMsg()) {
|
||||
Ui::show(Box<InformBox>(lang(lng_reply_cant)));
|
||||
} else {
|
||||
if (item->serviceMsg()) {
|
||||
Ui::show(Box<InformBox>(lang(lng_reply_cant)));
|
||||
} else {
|
||||
const auto itemId = item->fullId();
|
||||
Ui::show(Box<ConfirmBox>(lang(lng_reply_cant_forward), lang(lng_selected_forward), crl::guard(this, [=] {
|
||||
App::main()->setForwardDraft(
|
||||
_peer->id,
|
||||
{ 1, itemId });
|
||||
})));
|
||||
}
|
||||
const auto itemId = item->fullId();
|
||||
Ui::show(Box<ConfirmBox>(lang(lng_reply_cant_forward), lang(lng_selected_forward), crl::guard(this, [=] {
|
||||
App::main()->setForwardDraft(
|
||||
_peer->id,
|
||||
{ 1, itemId });
|
||||
})));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -387,7 +387,6 @@ private:
|
||||
void supportShareContact(Support::Contact contact);
|
||||
|
||||
void highlightMessage(MsgId universalMessageId);
|
||||
void adjustHighlightedMessageToMigrated();
|
||||
void checkNextHighlight();
|
||||
void updateHighlightedMessage();
|
||||
void clearHighlightMessages();
|
||||
|
@ -310,7 +310,7 @@ void TopBarWidget::paintTopBar(Painter &p, TimeMs ms) {
|
||||
|
||||
p.setPen(st::dialogsNameFg);
|
||||
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);
|
||||
if (namewidth < textWidth) {
|
||||
text = st::historySavedFont->elided(text, namewidth);
|
||||
|
@ -71,7 +71,7 @@ void Cover::initViewers() {
|
||||
}
|
||||
|
||||
void Cover::refreshNameText() {
|
||||
_name->setText(_feed->chatsListName());
|
||||
_name->setText(_feed->chatListName());
|
||||
refreshNameGeometry(width());
|
||||
}
|
||||
|
||||
|
@ -731,9 +731,7 @@ void MainWidget::cancelUploadLayer(not_null<HistoryItem*> item) {
|
||||
if (const auto item = App::histItemById(itemId)) {
|
||||
const auto history = item->history();
|
||||
item->destroy();
|
||||
if (!history->lastMessageKnown()) {
|
||||
Auth().api().requestDialogEntry(history);
|
||||
}
|
||||
history->requestChatListMessage();
|
||||
Auth().data().sendHistoryChangeNotifications();
|
||||
}
|
||||
Auth().uploader().unpause();
|
||||
@ -831,7 +829,7 @@ void MainWidget::deleteHistoryPart(DeleteHistoryRequest request, const MTPmessag
|
||||
void MainWidget::deleteMessages(
|
||||
not_null<PeerData*> peer,
|
||||
const QVector<MTPint> &ids,
|
||||
bool forEveryone) {
|
||||
bool revoke) {
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
MTP::send(
|
||||
MTPchannels_DeleteMessages(
|
||||
@ -839,13 +837,10 @@ void MainWidget::deleteMessages(
|
||||
MTP_vector<MTPint>(ids)),
|
||||
rpcDone(&MainWidget::messagesAffected, peer));
|
||||
} else {
|
||||
auto flags = MTPmessages_DeleteMessages::Flags(0);
|
||||
if (forEveryone) {
|
||||
flags |= MTPmessages_DeleteMessages::Flag::f_revoke;
|
||||
}
|
||||
using Flag = MTPmessages_DeleteMessages::Flag;
|
||||
MTP::send(
|
||||
MTPmessages_DeleteMessages(
|
||||
MTP_flags(flags),
|
||||
MTP_flags(revoke ? Flag::f_revoke : Flag(0)),
|
||||
MTP_vector<MTPint>(ids)),
|
||||
rpcDone(&MainWidget::messagesAffected, peer));
|
||||
}
|
||||
@ -1039,9 +1034,7 @@ void MainWidget::messagesAffected(
|
||||
}
|
||||
|
||||
if (const auto history = App::historyLoaded(peer)) {
|
||||
if (!history->lastMessageKnown()) {
|
||||
Auth().api().requestDialogEntry(history);
|
||||
}
|
||||
history->requestChatListMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@ -4003,9 +3996,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
||||
if (existing && !local->mainView()) {
|
||||
const auto history = local->history();
|
||||
local->destroy();
|
||||
if (!history->lastMessageKnown()) {
|
||||
Auth().api().requestDialogEntry(history);
|
||||
}
|
||||
history->requestChatListMessage();
|
||||
} else {
|
||||
if (existing) {
|
||||
existing->destroy();
|
||||
@ -4477,15 +4468,15 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
|
||||
Auth().api().requestSelfParticipant(channel);
|
||||
}
|
||||
if (const auto feed = channel->feed()) {
|
||||
if (!feed->lastMessageKnown()
|
||||
|| !feed->unreadCountKnown()) {
|
||||
Auth().api().requestDialogEntry(feed);
|
||||
feed->requestChatListMessage();
|
||||
if (!feed->unreadCountKnown()) {
|
||||
feed->session().api().requestDialogEntry(feed);
|
||||
}
|
||||
} else if (channel->amIn()) {
|
||||
const auto history = App::history(channel->id);
|
||||
if (!history->lastMessageKnown()
|
||||
|| !history->unreadCountKnown()) {
|
||||
Auth().api().requestDialogEntry(history);
|
||||
history->requestChatListMessage();
|
||||
if (!history->unreadCountKnown()) {
|
||||
history->session().api().requestDialogEntry(history);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ public:
|
||||
void deleteMessages(
|
||||
not_null<PeerData*> peer,
|
||||
const QVector<MTPint> &ids,
|
||||
bool forEveryone);
|
||||
bool revoke);
|
||||
void deletedContact(UserData *user, const MTPcontacts_Link &result);
|
||||
void deleteConversation(
|
||||
not_null<PeerData*> peer,
|
||||
|
@ -409,22 +409,13 @@ void ResolveChannel(
|
||||
|
||||
std::optional<MTPMessage> GetMessagesElement(
|
||||
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()
|
||||
? std::nullopt
|
||||
: base::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)");
|
||||
}
|
||||
: std::make_optional(data.vmessages.v[0]);
|
||||
});
|
||||
}
|
||||
|
||||
void StartDedicatedLoader(
|
||||
|
@ -38,8 +38,8 @@ enum class MTPDmessage_ClientFlag : uint32 {
|
||||
// message has links for "shared links" indexing
|
||||
f_has_text_links = (1U << 30),
|
||||
|
||||
// message is a group migrate (group -> supergroup) service message
|
||||
f_is_group_migrate = (1U << 29),
|
||||
// message is a group / channel create or migrate service message
|
||||
f_is_group_essential = (1U << 29),
|
||||
|
||||
//// message needs initDimensions() + resize() + paint()
|
||||
//f_pending_init_dimensions = (1U << 28),
|
||||
|
@ -643,7 +643,7 @@ bool PanelEditDocument::validate() {
|
||||
error = firsttop.y();
|
||||
}
|
||||
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];
|
||||
if (row.valueClass == Scheme::ValueClass::Additional
|
||||
&& !_additionalShown) {
|
||||
|
@ -407,14 +407,14 @@ void Controller::showJumpToDate(Dialogs::Key chat, QDate requestedDate) {
|
||||
return history->blocks.front()->messages.front()->dateTime().date();
|
||||
}
|
||||
}
|
||||
} else if (history->chatsListTimeId() != 0) {
|
||||
return ParseDateTime(history->chatsListTimeId()).date();
|
||||
} else if (history->chatListTimeId() != 0) {
|
||||
return ParseDateTime(history->chatListTimeId()).date();
|
||||
}
|
||||
} else if (const auto feed = chat.feed()) {
|
||||
/*if (chatScrollPosition(feed)) { // #TODO feeds save position
|
||||
|
||||
} else */if (feed->chatsListTimeId() != 0) {
|
||||
return ParseDateTime(feed->chatsListTimeId()).date();
|
||||
} else */if (feed->chatListTimeId() != 0) {
|
||||
return ParseDateTime(feed->chatListTimeId()).date();
|
||||
}
|
||||
}
|
||||
return QDate::currentDate();
|
||||
@ -424,12 +424,12 @@ void Controller::showJumpToDate(Dialogs::Key chat, QDate requestedDate) {
|
||||
if (const auto channel = history->peer->migrateTo()) {
|
||||
history = App::historyLoaded(channel);
|
||||
}
|
||||
if (history && history->chatsListTimeId() != 0) {
|
||||
return ParseDateTime(history->chatsListTimeId()).date();
|
||||
if (history && history->chatListTimeId() != 0) {
|
||||
return ParseDateTime(history->chatListTimeId()).date();
|
||||
}
|
||||
} else if (const auto feed = chat.feed()) {
|
||||
if (feed->chatsListTimeId() != 0) {
|
||||
return ParseDateTime(feed->chatsListTimeId()).date();
|
||||
if (feed->chatListTimeId() != 0) {
|
||||
return ParseDateTime(feed->chatListTimeId()).date();
|
||||
}
|
||||
}
|
||||
return QDate::currentDate();
|
||||
|
Loading…
Reference in New Issue
Block a user