mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-08-07 20:26:25 +00:00
Merge tag 'v7.0.4' into dev
This commit is contained in:
@@ -49,6 +49,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/components/sponsored_messages.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "data/data_ai_compose_tones.h"
|
||||
#include "data/data_bot_app.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_group_call.h"
|
||||
@@ -59,10 +60,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_download_manager.h"
|
||||
#include "data/data_web_page.h"
|
||||
#include "iv/iv_rich_page.h"
|
||||
#include "data/data_game.h"
|
||||
#include "data/data_poll.h"
|
||||
#include "data/data_replies_list.h"
|
||||
#include "data/data_chat_filters.h"
|
||||
#include "dialogs/dialogs_entry.h"
|
||||
#include "dialogs/dialogs_row.h"
|
||||
#include "base/options.h"
|
||||
#include "data/data_send_action.h"
|
||||
#include "data/data_message_reactions.h"
|
||||
#include "data/data_emoji_statuses.h"
|
||||
@@ -97,6 +102,7 @@ namespace Data {
|
||||
namespace {
|
||||
|
||||
constexpr auto kNextForUpgradeGiftTimeout = 5 * crl::time(1000);
|
||||
constexpr auto kMaxServiceNotificationMessageSize = 4096;
|
||||
|
||||
using ViewElement = HistoryView::Element;
|
||||
|
||||
@@ -249,6 +255,7 @@ Session::Session(not_null<Main::Session*> session)
|
||||
, _pollsClosingTimer([=] { checkPollsClosings(); })
|
||||
, _watchForOfflineTimer([=] { checkLocalUsersWentOffline(); })
|
||||
, _groups(this)
|
||||
, _aiComposeTones(std::make_unique<AiComposeTones>(session))
|
||||
, _chatsFilters(std::make_unique<ChatFilters>(this))
|
||||
, _cloudThemes(std::make_unique<CloudThemes>(session))
|
||||
, _sendActionManager(std::make_unique<SendActionManager>())
|
||||
@@ -288,6 +295,12 @@ Session::Session(not_null<Main::Session*> session)
|
||||
notifyUnreadBadgeChanged();
|
||||
}, _lifetime);
|
||||
|
||||
base::options::lookup<bool>(
|
||||
Dialogs::kOptionDialogsUnreadOnTop
|
||||
).changes() | rpl::on_next([=] {
|
||||
refreshChatListUnreadOnTop();
|
||||
}, _lifetime);
|
||||
|
||||
_chatsFilters->changed(
|
||||
) | rpl::on_next([=] {
|
||||
const auto enabled = _chatsFilters->has();
|
||||
@@ -407,6 +420,8 @@ void Session::subscribeForTopicRepliesLists() {
|
||||
}
|
||||
|
||||
void Session::clear() {
|
||||
_sessionDataAboutToBeCleared.fire({});
|
||||
|
||||
// Optimization: clear notifications before destroying items.
|
||||
Core::App().notifications().clearFromSession(_session);
|
||||
|
||||
@@ -442,12 +457,21 @@ void Session::clear() {
|
||||
_shortcutMessages = nullptr;
|
||||
_session->scheduledMessages().clear();
|
||||
_session->sponsoredMessages().clear();
|
||||
|
||||
// Items are gone now, so HistoryMessageReply::resolvedStory raw
|
||||
// pointers no longer linger. Tear stories down here so their
|
||||
// shared_ptr<GroupCall> drops while Main::Session::_data still
|
||||
// holds a live pointer to us; otherwise the GroupCall destructor
|
||||
// would run inside ~Data::Session and find data() returning a
|
||||
// null reference (the parent unique_ptr resets its stored pointer
|
||||
// before invoking the deleter).
|
||||
_stories->clear();
|
||||
|
||||
_dependentMessages.clear();
|
||||
base::take(_messages);
|
||||
base::take(_nonChannelMessages);
|
||||
_messageByRandomId.clear();
|
||||
_sentMessagesData.clear();
|
||||
cSetRecentInlineBots(RecentInlineBots());
|
||||
cSetRecentStickers(RecentStickerPack());
|
||||
HistoryView::Element::ClearGlobal();
|
||||
_contactsNoChatsList.clear();
|
||||
@@ -602,6 +626,8 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
||||
info->hasMainApp = data.is_bot_has_main_app();
|
||||
info->userCreatesTopics = data.is_bot_forum_can_manage_topics();
|
||||
info->canManageBots = data.is_bot_can_manage_bots();
|
||||
info->supportsGuestChat = data.is_bot_guestchat();
|
||||
info->supportsGuard = data.is_bot_guard();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -671,6 +697,8 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
||||
result->setFlags((result->flags() & ~flagsMask) | flagsSet);
|
||||
result->setBotVerifyDetailsIcon(
|
||||
data.vbot_verification_icon().value_or_empty());
|
||||
result->setLinkedCommunityId(
|
||||
data.vlinked_community_id().value_or_empty());
|
||||
if (!minimal) {
|
||||
if (storiesState) {
|
||||
result->setStoriesState(storiesState->hasVideoStream
|
||||
@@ -836,6 +864,10 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
||||
return peer(peerFromChannel(data.vid().v));
|
||||
}, [&](const MTPDchannelForbidden &data) {
|
||||
return peer(peerFromChannel(data.vid().v));
|
||||
}, [&](const MTPDcommunity &data) {
|
||||
return peer(peerFromChannel(data.vid().v));
|
||||
}, [&](const MTPDcommunityForbidden &data) {
|
||||
return peer(peerFromChannel(data.vid().v));
|
||||
});
|
||||
auto minimal = false;
|
||||
|
||||
@@ -1100,6 +1132,8 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
||||
applyMonoforumLinkedId(
|
||||
channel,
|
||||
data.vlinked_monoforum_id().value_or_empty());
|
||||
channel->setLinkedCommunityId(
|
||||
data.vlinked_community_id().value_or_empty());
|
||||
|
||||
if (wasInChannel != channel->amIn()) {
|
||||
flags |= UpdateFlag::ChannelAmIn;
|
||||
@@ -1164,6 +1198,84 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
|
||||
|| canAddMembers != channel->canAddMembers()) {
|
||||
flags |= UpdateFlag::Rights;
|
||||
}
|
||||
}, [&](const MTPDcommunity &data) {
|
||||
const auto channel = result->asChannel();
|
||||
|
||||
minimal = data.is_min();
|
||||
if (minimal && !result->isLoaded()) {
|
||||
LOG(("API Warning: not loaded minimal community applied."));
|
||||
}
|
||||
|
||||
if (const auto accessHash = data.vaccess_hash()) {
|
||||
if (!minimal || !channel->accessHash()) {
|
||||
channel->setAccessHash(accessHash->v);
|
||||
}
|
||||
}
|
||||
if (const auto rights = data.vdefault_banned_rights()) {
|
||||
channel->setDefaultRestrictions(
|
||||
ChatRestrictionsInfo(*rights).flags);
|
||||
} else {
|
||||
channel->setDefaultRestrictions(ChatRestrictions());
|
||||
}
|
||||
if (!minimal) {
|
||||
const auto wasLoaded = result->isLoaded();
|
||||
const auto hadRights = channel->hasAdminRights();
|
||||
if (const auto rights = data.vadmin_rights()) {
|
||||
channel->setAdminRights(ChatAdminRightsInfo(*rights).flags);
|
||||
} else if (channel->hasAdminRights()) {
|
||||
channel->setAdminRights(ChatAdminRights());
|
||||
}
|
||||
channel->date = data.vdate().v;
|
||||
if (wasLoaded
|
||||
&& !hadRights
|
||||
&& channel->hasAdminRights()
|
||||
&& !data.is_creator()) {
|
||||
_communityAdminPromotions.fire(
|
||||
not_null<ChannelData*>(channel));
|
||||
}
|
||||
}
|
||||
channel->setName(qs(data.vtitle()), QString());
|
||||
channel->setPhoto(data.vphoto());
|
||||
|
||||
using Flag = ChannelDataFlag;
|
||||
const auto collapsed = data.is_collapsed_in_dialogs();
|
||||
const auto flagsMask = Flag::Community
|
||||
| Flag::Forbidden
|
||||
| (!minimal
|
||||
? (Flag::Left | Flag::Creator | Flag::CommunityCollapsed)
|
||||
: Flag());
|
||||
const auto flagsSet = Flag::Community
|
||||
| (!minimal
|
||||
? ((data.is_left() ? Flag::Left : Flag())
|
||||
| (data.is_creator() ? Flag::Creator : Flag())
|
||||
| (collapsed ? Flag::CommunityCollapsed : Flag()))
|
||||
: Flag());
|
||||
channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
|
||||
}, [&](const MTPDcommunityForbidden &data) {
|
||||
const auto channel = result->asChannel();
|
||||
|
||||
using Flag = ChannelDataFlag;
|
||||
const auto flagsMask = Flag::Community
|
||||
| Flag::CommunityCollapsed
|
||||
| Flag::Forbidden;
|
||||
const auto flagsSet = Flag::Community | Flag::Forbidden;
|
||||
channel->setFlags((channel->flags() & ~flagsMask) | flagsSet);
|
||||
|
||||
if (channel->hasAdminRights()) {
|
||||
channel->setAdminRights(ChatAdminRights());
|
||||
}
|
||||
if (channel->hasRestrictions()) {
|
||||
channel->setRestrictions(ChatRestrictionsInfo());
|
||||
}
|
||||
|
||||
channel->setName(qs(data.vtitle()), QString());
|
||||
|
||||
if (const auto accessHash = data.vaccess_hash()) {
|
||||
channel->setAccessHash(accessHash->v);
|
||||
}
|
||||
channel->setPhoto(MTP_chatPhotoEmpty());
|
||||
channel->date = 0;
|
||||
channel->setMembersCount(0);
|
||||
}, [](const MTPDchatEmpty &) {
|
||||
});
|
||||
|
||||
@@ -1832,16 +1944,19 @@ void Session::documentLoadFail(
|
||||
|
||||
void Session::photoLoadProgress(not_null<PhotoData*> photo) {
|
||||
requestPhotoViewRepaint(photo);
|
||||
_photoLoadProgress.fire_copy(photo);
|
||||
}
|
||||
|
||||
void Session::photoLoadDone(not_null<PhotoData*> photo) {
|
||||
notifyPhotoLayoutChanged(photo);
|
||||
_photoLoadProgress.fire_copy(photo);
|
||||
}
|
||||
|
||||
void Session::photoLoadFail(
|
||||
not_null<PhotoData*> photo,
|
||||
bool started) {
|
||||
notifyPhotoLayoutChanged(photo);
|
||||
_photoLoadProgress.fire_copy(photo);
|
||||
}
|
||||
|
||||
void Session::markMediaRead(not_null<const DocumentData*> document) {
|
||||
@@ -2106,6 +2221,14 @@ rpl::producer<not_null<HistoryItem*>> Session::itemDataChanges() const {
|
||||
return _itemDataChanges.events();
|
||||
}
|
||||
|
||||
void Session::notifyReactionsRemoved(ReactionsRemoved update) {
|
||||
_reactionsRemoved.fire(std::move(update));
|
||||
}
|
||||
|
||||
rpl::producer<ReactionsRemoved> Session::reactionsRemoved() const {
|
||||
return _reactionsRemoved.events();
|
||||
}
|
||||
|
||||
void Session::requestItemTextRefresh(not_null<HistoryItem*> item) {
|
||||
const auto call = [&](not_null<HistoryItem*> item) {
|
||||
enumerateItemViews(item, [&](not_null<ViewElement*> view) {
|
||||
@@ -2189,6 +2312,30 @@ rpl::producer<not_null<const HistoryItem*>> Session::itemRemoved(
|
||||
});
|
||||
}
|
||||
|
||||
rpl::producer<> Session::sessionDataAboutToBeCleared() const {
|
||||
return _sessionDataAboutToBeCleared.events();
|
||||
}
|
||||
|
||||
void Session::notifyItemsAboutToBeDestroyed(
|
||||
const std::vector<not_null<HistoryItem*>> &items) {
|
||||
_itemsAboutToBeDestroyed.fire_copy(items);
|
||||
}
|
||||
|
||||
auto Session::itemsAboutToBeDestroyed() const
|
||||
-> rpl::producer<std::vector<not_null<HistoryItem*>>> {
|
||||
return _itemsAboutToBeDestroyed.events();
|
||||
}
|
||||
|
||||
void Session::notifyViewAboutToBeRemoved(
|
||||
not_null<const ViewElement*> view,
|
||||
ViewRemovalReason reason) {
|
||||
_viewAboutToBeRemoved.fire({ view, reason });
|
||||
}
|
||||
|
||||
rpl::producer<ViewRemoval> Session::viewAboutToBeRemoved() const {
|
||||
return _viewAboutToBeRemoved.events();
|
||||
}
|
||||
|
||||
void Session::notifyViewRemoved(not_null<const ViewElement*> view) {
|
||||
_viewRemoved.fire_copy(view);
|
||||
}
|
||||
@@ -2490,6 +2637,11 @@ void Session::applyPinnedChats(
|
||||
if (folder) {
|
||||
LOG(("API Error: Nested folders detected."));
|
||||
}
|
||||
}, [&](const MTPDdialogPeerCommunity &data) {
|
||||
const auto channelId = ChannelId(data.vcommunity_id().v);
|
||||
if (const auto channel = channelLoaded(channelId)) {
|
||||
this->history(channel)->clearFolder();
|
||||
}
|
||||
});
|
||||
}
|
||||
chatsList(folder)->pinned()->applyList(this, list);
|
||||
@@ -2553,6 +2705,22 @@ void Session::applyDialog(
|
||||
setPinnedFromEntryList(folder, data.is_pinned());
|
||||
}
|
||||
|
||||
void Session::applyDialog(
|
||||
Data::Folder *requestFolder,
|
||||
const MTPDdialogCommunity &data) {
|
||||
const auto channelId = ChannelId(data.vcommunity_id().v);
|
||||
const auto channel = channelLoaded(channelId);
|
||||
if (!channel || !channel->isCommunity()) {
|
||||
return;
|
||||
}
|
||||
const auto history = this->history(channel);
|
||||
notifySettings().apply(
|
||||
peerFromChannel(channelId),
|
||||
data.vnotify_settings());
|
||||
channel->ensuredCommunityInfo()->ensureRowInChatList();
|
||||
setPinnedFromEntryList(history, data.is_pinned());
|
||||
}
|
||||
|
||||
bool Session::pinnedCanPin(not_null<Dialogs::Entry*> entry) const {
|
||||
if ([[maybe_unused]] const auto sublist = entry->asSublist()) {
|
||||
if (sublist->parentChat()) {
|
||||
@@ -2888,27 +3056,27 @@ void Session::unregisterMessageTTL(
|
||||
}
|
||||
|
||||
void Session::checkTTLs() {
|
||||
const auto &settings = AyuSettings::getInstance();
|
||||
|
||||
_ttlCheckTimer.cancel();
|
||||
const auto now = base::unixtime::now();
|
||||
|
||||
if (settings.saveDeletedMessages()) {
|
||||
auto toBeRemoved = ranges::views::take_while(
|
||||
_ttlMessages,
|
||||
[now](const auto &pair) {
|
||||
return pair.first <= now;
|
||||
}) | ranges::views::transform([](const auto &pair) {
|
||||
return pair.second;
|
||||
}) | ranges::views::join;
|
||||
|
||||
auto itemsToProcess = toBeRemoved | ranges::to_vector;
|
||||
for (const auto &item : itemsToProcess) {
|
||||
processMessageDelete(item);
|
||||
auto expired = std::vector<not_null<HistoryItem*>>();
|
||||
for (const auto &[when, items] : _ttlMessages) {
|
||||
if (when > now) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
while (!_ttlMessages.empty() && _ttlMessages.begin()->first <= now) {
|
||||
_ttlMessages.begin()->second.front()->destroy();
|
||||
expired.insert(expired.end(), items.begin(), items.end());
|
||||
}
|
||||
auto toDestroy = std::vector<not_null<HistoryItem*>>();
|
||||
for (const auto &item : expired) {
|
||||
if (isMessageSavable(item)) {
|
||||
processMessageDelete(item);
|
||||
} else {
|
||||
toDestroy.push_back(item);
|
||||
}
|
||||
}
|
||||
if (!toDestroy.empty()) {
|
||||
notifyItemsAboutToBeDestroyed(toDestroy);
|
||||
for (const auto &item : toDestroy) {
|
||||
item->destroy();
|
||||
}
|
||||
}
|
||||
scheduleNextTTLs();
|
||||
@@ -2966,41 +3134,60 @@ void Session::processMessagesDeleted(
|
||||
return;
|
||||
}
|
||||
|
||||
auto toDestroy = std::vector<not_null<HistoryItem*>>();
|
||||
auto historiesToCheck = base::flat_set<not_null<History*>>();
|
||||
for (const auto &messageId : data) {
|
||||
const auto i = list ? list->find(messageId.v) : Messages::iterator();
|
||||
if (list && i != list->end()) {
|
||||
const auto history = i->second->history();
|
||||
|
||||
processMessageDelete(i->second);
|
||||
|
||||
if (!history->chatListMessageKnown()) {
|
||||
historiesToCheck.emplace(history);
|
||||
const auto item = i->second;
|
||||
const auto history = item->history();
|
||||
if (isMessageSavable(item)) {
|
||||
processMessageDelete(item);
|
||||
} else {
|
||||
toDestroy.push_back(item);
|
||||
}
|
||||
historiesToCheck.emplace(history);
|
||||
} else if (affected) {
|
||||
affected->unknownMessageDeleted(messageId.v);
|
||||
}
|
||||
}
|
||||
if (!toDestroy.empty()) {
|
||||
notifyItemsAboutToBeDestroyed(toDestroy);
|
||||
for (const auto &item : toDestroy) {
|
||||
item->destroy();
|
||||
}
|
||||
}
|
||||
for (const auto &history : historiesToCheck) {
|
||||
history->requestChatListMessage();
|
||||
if (!history->chatListMessageKnown()) {
|
||||
history->requestChatListMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Session::processNonChannelMessagesDeleted(const QVector<MTPint> &data) {
|
||||
auto toDestroy = std::vector<not_null<HistoryItem*>>();
|
||||
auto historiesToCheck = base::flat_set<not_null<History*>>();
|
||||
for (const auto &messageId : data) {
|
||||
if (const auto item = nonChannelMessage(messageId.v)) {
|
||||
const auto history = item->history();
|
||||
|
||||
processMessageDelete(item);
|
||||
|
||||
if (!history->chatListMessageKnown()) {
|
||||
historiesToCheck.emplace(history);
|
||||
if (isMessageSavable(item)) {
|
||||
processMessageDelete(item);
|
||||
} else {
|
||||
toDestroy.push_back(item);
|
||||
}
|
||||
historiesToCheck.emplace(history);
|
||||
}
|
||||
}
|
||||
if (!toDestroy.empty()) {
|
||||
notifyItemsAboutToBeDestroyed(toDestroy);
|
||||
for (const auto &item : toDestroy) {
|
||||
item->destroy();
|
||||
}
|
||||
}
|
||||
for (const auto &history : historiesToCheck) {
|
||||
history->requestChatListMessage();
|
||||
if (!history->chatListMessageKnown()) {
|
||||
history->requestChatListMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3093,6 +3280,34 @@ HistoryItem *Session::message(FullMsgId itemId) const {
|
||||
return message(itemId.peer, itemId.msg);
|
||||
}
|
||||
|
||||
void Session::removeReactionsFromParticipant(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId msgId,
|
||||
not_null<PeerData*> participant,
|
||||
const ReactionId &reaction,
|
||||
MsgId originMsgId) {
|
||||
if (msgId) {
|
||||
if (const auto item = message(peer, msgId)) {
|
||||
item->removeReactionsFromParticipant(participant, reaction);
|
||||
}
|
||||
} else if (const auto list = messagesList(peer->id)) {
|
||||
for (const auto &entry : *list) {
|
||||
const auto knownReaction = (originMsgId
|
||||
&& (entry.second->id == originMsgId))
|
||||
? reaction
|
||||
: ReactionId();
|
||||
entry.second->removeReactionsFromParticipant(
|
||||
participant,
|
||||
knownReaction);
|
||||
}
|
||||
}
|
||||
notifyReactionsRemoved({
|
||||
.peer = peer,
|
||||
.msgId = msgId,
|
||||
.participant = participant,
|
||||
});
|
||||
}
|
||||
|
||||
HistoryItem *Session::nonChannelMessage(MsgId itemId) const {
|
||||
if (!IsServerMsgId(itemId)) {
|
||||
return nullptr;
|
||||
@@ -3176,14 +3391,13 @@ HistoryItem *Session::addNewMessage(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (data.type() == mtpc_message) {
|
||||
if (type == NewMessageType::Unread
|
||||
&& data.type() == mtpc_message) {
|
||||
if (const auto h = historyLoaded(peerId)) {
|
||||
if (const auto streamed = h->streamedDraftsIfExists()) {
|
||||
if (const auto adopted = streamed->adoptIncoming(
|
||||
data.c_message())) {
|
||||
if (type == NewMessageType::Unread) {
|
||||
CheckForSwitchInlineButton(adopted);
|
||||
}
|
||||
CheckForSwitchInlineButton(adopted);
|
||||
return adopted;
|
||||
}
|
||||
}
|
||||
@@ -3950,6 +4164,7 @@ not_null<WebPageData*> Session::processWebpage(
|
||||
nullptr,
|
||||
nullptr,
|
||||
0,
|
||||
0,
|
||||
QString(),
|
||||
false,
|
||||
false,
|
||||
@@ -3962,7 +4177,9 @@ not_null<WebPageData*> Session::processWebpage(
|
||||
not_null<WebPageData*> Session::webpage(
|
||||
WebPageId id,
|
||||
const QString &siteName,
|
||||
const TextWithEntities &content) {
|
||||
const TextWithEntities &content,
|
||||
PhotoData *photo,
|
||||
DocumentData *document) {
|
||||
return webpage(
|
||||
id,
|
||||
WebPageType::Article,
|
||||
@@ -3971,8 +4188,8 @@ not_null<WebPageData*> Session::webpage(
|
||||
siteName,
|
||||
QString(),
|
||||
content,
|
||||
nullptr,
|
||||
nullptr,
|
||||
photo,
|
||||
document,
|
||||
WebPageCollage(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
@@ -4020,6 +4237,7 @@ not_null<WebPageData*> Session::webpage(
|
||||
std::move(stickerSet),
|
||||
std::move(uniqueGift),
|
||||
nullptr,
|
||||
0,
|
||||
duration,
|
||||
author,
|
||||
hasLargeMedia,
|
||||
@@ -4072,6 +4290,8 @@ void Session::webpageApplyFields(
|
||||
return (DocumentData*)nullptr;
|
||||
}, [](const MTPDwebPageAttributeStarGiftAuction &) {
|
||||
return (DocumentData*)nullptr;
|
||||
}, [](const MTPDwebPageAttributeAiComposeTone &) {
|
||||
return (DocumentData*)nullptr;
|
||||
});
|
||||
if (result) {
|
||||
return result;
|
||||
@@ -4147,6 +4367,21 @@ void Session::webpageApplyFields(
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
const auto lookupComposeToneEmojiId = [&]() -> DocumentId {
|
||||
if (const auto attributes = data.vattributes()) {
|
||||
for (const auto &attribute : attributes->v) {
|
||||
const auto result = attribute.match([&](
|
||||
const MTPDwebPageAttributeAiComposeTone &data) {
|
||||
return DocumentId(data.vemoji_id().v);
|
||||
}, [](const auto &) { return DocumentId(0); });
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
auto story = (Data::Story*)nullptr;
|
||||
auto storyId = FullStoryId();
|
||||
if (const auto attributes = data.vattributes()) {
|
||||
@@ -4177,55 +4412,25 @@ void Session::webpageApplyFields(
|
||||
}, [](const auto &) {});
|
||||
}
|
||||
}
|
||||
if (const auto page = data.vcached_page()) {
|
||||
for (const auto &photo : page->data().vphotos().v) {
|
||||
processPhoto(photo);
|
||||
}
|
||||
for (const auto &document : page->data().vdocuments().v) {
|
||||
processDocument(document);
|
||||
}
|
||||
const auto process = [&](
|
||||
const MTPPageBlock &block,
|
||||
const auto &self) -> void {
|
||||
block.match([&](const MTPDpageBlockChannel &data) {
|
||||
processChat(data.vchannel());
|
||||
}, [&](const MTPDpageBlockCover &data) {
|
||||
self(data.vcover(), self);
|
||||
}, [&](const MTPDpageBlockEmbedPost &data) {
|
||||
for (const auto &block : data.vblocks().v) {
|
||||
self(block, self);
|
||||
}
|
||||
}, [&](const MTPDpageBlockCollage &data) {
|
||||
for (const auto &block : data.vitems().v) {
|
||||
self(block, self);
|
||||
}
|
||||
}, [&](const MTPDpageBlockSlideshow &data) {
|
||||
for (const auto &block : data.vitems().v) {
|
||||
self(block, self);
|
||||
}
|
||||
}, [&](const MTPDpageBlockDetails &data) {
|
||||
for (const auto &block : data.vblocks().v) {
|
||||
self(block, self);
|
||||
}
|
||||
}, [](const auto &) {});
|
||||
};
|
||||
for (const auto &block : page->data().vblocks().v) {
|
||||
process(block, process);
|
||||
}
|
||||
}
|
||||
const auto type = story ? WebPageType::Story : ParseWebPageType(data);
|
||||
auto iv = (data.vcached_page() && !IgnoreIv(type))
|
||||
? std::make_unique<Iv::Data>(data, *data.vcached_page())
|
||||
const auto cachedPage = data.vcached_page();
|
||||
const auto ivPhoto = photo ? processPhoto(*photo).get() : nullptr;
|
||||
const auto ivDocument = document ? processDocument(*document).get() : nullptr;
|
||||
const auto richPage = (cachedPage && !IgnoreIv(type))
|
||||
? Iv::ParseRichPage(_session, data)
|
||||
: nullptr;
|
||||
auto iv = richPage
|
||||
? std::make_unique<Iv::Data>(data, richPage)
|
||||
: nullptr;
|
||||
const auto resolvedPhoto = story
|
||||
? story->photo()
|
||||
: photo
|
||||
? processPhoto(*photo).get()
|
||||
? ivPhoto
|
||||
: nullptr;
|
||||
const auto resolvedDocument = story
|
||||
? story->document()
|
||||
: document
|
||||
? processDocument(*document).get()
|
||||
? ivDocument
|
||||
: lookupThemeDocument();
|
||||
const auto photoIsVideoCover = data.is_video_cover_photo()
|
||||
|| (resolvedDocument
|
||||
@@ -4248,6 +4453,7 @@ void Session::webpageApplyFields(
|
||||
lookupStickerSet(),
|
||||
lookupUniqueGift(),
|
||||
lookupAuction(),
|
||||
lookupComposeToneEmojiId(),
|
||||
data.vduration().value_or_empty(),
|
||||
qs(data.vauthor().value_or_empty()),
|
||||
data.is_has_large_media(),
|
||||
@@ -4271,6 +4477,7 @@ void Session::webpageApplyFields(
|
||||
std::unique_ptr<WebPageStickerSet> stickerSet,
|
||||
std::shared_ptr<UniqueGift> uniqueGift,
|
||||
std::unique_ptr<WebPageAuction> auction,
|
||||
DocumentId composeToneEmojiId,
|
||||
int duration,
|
||||
const QString &author,
|
||||
bool hasLargeMedia,
|
||||
@@ -4292,6 +4499,7 @@ void Session::webpageApplyFields(
|
||||
std::move(stickerSet),
|
||||
std::move(uniqueGift),
|
||||
std::move(auction),
|
||||
composeToneEmojiId,
|
||||
duration,
|
||||
author,
|
||||
hasLargeMedia,
|
||||
@@ -5102,6 +5310,11 @@ rpl::producer<not_null<ChannelData*>> Session::channelDifferenceTooLong() const
|
||||
return _channelDifferenceTooLong.events();
|
||||
}
|
||||
|
||||
auto Session::communityAdminPromotions() const
|
||||
-> rpl::producer<not_null<ChannelData*>> {
|
||||
return _communityAdminPromotions.events();
|
||||
}
|
||||
|
||||
void Session::registerItemView(not_null<ViewElement*> view) {
|
||||
_views[view->data()].push_back(view);
|
||||
}
|
||||
@@ -5172,6 +5385,13 @@ not_null<Dialogs::MainList*> Session::chatsListFor(
|
||||
return topic->forum()->topicsList();
|
||||
} else if (const auto sublist = entry->asSublist()) {
|
||||
return sublist->parent()->chatsList();
|
||||
} else if (const auto history = entry->asHistory()) {
|
||||
if (const auto info = history->communityListInfo()
|
||||
; info
|
||||
&& info->collapsedInChatLists()
|
||||
&& info->channel() != history->peer) {
|
||||
return info->chatsList();
|
||||
}
|
||||
}
|
||||
return chatsList(entry->folder());
|
||||
}
|
||||
@@ -5260,6 +5480,22 @@ void Session::refreshChatListEntry(Dialogs::Key key) {
|
||||
}
|
||||
}
|
||||
|
||||
void Session::refreshChatListUnreadOnTop() {
|
||||
auto entries = std::vector<not_null<Dialogs::Entry*>>();
|
||||
const auto collect = [&](not_null<Dialogs::MainList*> list) {
|
||||
for (const auto &row : list->indexed()->all()) {
|
||||
entries.push_back(row->entry());
|
||||
}
|
||||
};
|
||||
collect(&_chatsList);
|
||||
if (const auto folder = folderLoaded(Data::Folder::kId)) {
|
||||
collect(folder->chatsList());
|
||||
}
|
||||
for (const auto &entry : entries) {
|
||||
entry->updateChatListSortPosition();
|
||||
}
|
||||
}
|
||||
|
||||
void Session::removeChatListEntry(Dialogs::Key key) {
|
||||
using namespace Dialogs;
|
||||
|
||||
@@ -5343,7 +5579,8 @@ void Session::serviceNotification(
|
||||
MTPPeerColor(), // profile_color
|
||||
MTPint(), // bot_active_users
|
||||
MTPlong(), // bot_verification_icon
|
||||
MTPlong())); // send_paid_messages_stars
|
||||
MTPlong(), // send_paid_messages_stars
|
||||
MTPlong())); // linked_community_id
|
||||
}
|
||||
const auto history = this->history(PeerData::kServiceNotificationsId);
|
||||
const auto insert = [=] {
|
||||
@@ -5370,7 +5607,10 @@ void Session::insertCheckedServiceNotification(
|
||||
const auto localFlags = MessageFlag::ClientSideUnread
|
||||
| MessageFlag::Local;
|
||||
auto sending = TextWithEntities(), left = message;
|
||||
while (TextUtilities::CutPart(sending, left, MaxMessageSize)) {
|
||||
while (TextUtilities::CutPart(
|
||||
sending,
|
||||
left,
|
||||
kMaxServiceNotificationMessageSize)) {
|
||||
const auto id = nextLocalMessageId();
|
||||
addNewMessage(
|
||||
id,
|
||||
@@ -5385,6 +5625,7 @@ void Session::insertCheckedServiceNotification(
|
||||
MTPMessageFwdHeader(),
|
||||
MTPlong(), // via_bot_id
|
||||
MTPlong(), // via_business_bot_id
|
||||
MTPPeer(), // guestchat_via_from
|
||||
MTPMessageReplyHeader(),
|
||||
MTP_int(date),
|
||||
MTP_string(sending.text),
|
||||
@@ -5407,7 +5648,8 @@ void Session::insertCheckedServiceNotification(
|
||||
MTPlong(), // paid_message_stars
|
||||
MTPSuggestedPost(),
|
||||
MTPint(), // schedule_repeat_period
|
||||
MTPstring()), // summary_from_language
|
||||
MTPstring(), // summary_from_language
|
||||
MTPRichMessage()),
|
||||
localFlags,
|
||||
NewMessageType::Unread);
|
||||
}
|
||||
@@ -5527,6 +5769,15 @@ auto Session::webViewResultSent() const -> rpl::producer<WebViewResultSent> {
|
||||
return _webViewResultSent.events();
|
||||
}
|
||||
|
||||
void Session::joinChatWebViewDecision(JoinChatWebViewDecision &&decision) {
|
||||
return _joinChatWebViewDecision.fire(std::move(decision));
|
||||
}
|
||||
|
||||
auto Session::joinChatWebViewDecision() const
|
||||
-> rpl::producer<JoinChatWebViewDecision> {
|
||||
return _joinChatWebViewDecision.events();
|
||||
}
|
||||
|
||||
rpl::producer<not_null<PeerData*>> Session::peerDecorationsUpdated() const {
|
||||
return _peerDecorationsUpdated.events();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user