mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-03-19 18:05:37 +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_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";
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
@ -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(),
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}();
|
}();
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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(
|
||||||
|
@ -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),
|
||||||
|
@ -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) {
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user