From dcc326e17f15d95b27d77eb6dc9951644505732d Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 10 Nov 2023 13:27:47 +0400 Subject: [PATCH] Update API scheme to layer 167. Support quote offset passing to API. Support simple phrases in giveaway results message. --- Telegram/Resources/langs/lang.strings | 4 + Telegram/SourceFiles/data/data_histories.cpp | 6 +- Telegram/SourceFiles/data/data_msg_id.h | 1 + .../export/data/export_data_types.cpp | 11 +- .../export/data/export_data_types.h | 14 +- .../export/output/export_output_html.cpp | 14 +- .../export/output/export_output_json.cpp | 11 +- .../history/history_inner_widget.cpp | 18 +- Telegram/SourceFiles/history/history_item.cpp | 256 +++++++++--------- .../history/history_item_components.cpp | 11 +- .../history/history_item_components.h | 7 +- .../history/history_item_helpers.cpp | 20 +- .../history/history_item_helpers.h | 6 +- .../history_view_highlight_manager.cpp | 32 +-- .../history/history_view_highlight_manager.h | 9 +- .../SourceFiles/history/history_widget.cpp | 61 +++-- Telegram/SourceFiles/history/history_widget.h | 16 +- .../controls/history_view_draft_options.cpp | 3 +- .../view/history_view_context_menu.cpp | 12 +- .../history/view/history_view_context_menu.h | 4 +- .../history/view/history_view_element.cpp | 17 +- .../history/view/history_view_element.h | 7 +- .../history/view/history_view_list_widget.cpp | 16 +- .../history/view/history_view_list_widget.h | 3 +- .../history/view/history_view_message.cpp | 12 +- .../history/view/history_view_message.h | 3 +- .../view/history_view_replies_section.cpp | 9 +- .../view/history_view_replies_section.h | 9 +- .../view/history_view_service_message.cpp | 3 +- .../view/history_view_service_message.h | 3 +- .../view/media/history_view_document.cpp | 4 +- .../view/media/history_view_document.h | 3 +- .../history/view/media/history_view_gif.cpp | 6 +- .../history/view/media/history_view_gif.h | 3 +- .../history/view/media/history_view_media.h | 3 +- .../view/media/history_view_media_grouped.cpp | 13 +- .../view/media/history_view_media_grouped.h | 3 +- .../history/view/media/history_view_photo.cpp | 6 +- .../history/view/media/history_view_photo.h | 3 +- Telegram/SourceFiles/mainwidget.cpp | 8 +- Telegram/SourceFiles/mtproto/scheme/api.tl | 36 ++- Telegram/SourceFiles/mtproto/scheme/layer.tl | 2 +- .../window/window_session_controller.cpp | 3 +- .../window/window_session_controller.h | 1 + 44 files changed, 389 insertions(+), 303 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 429addc84..ff69f9773 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1667,6 +1667,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_action_story_mention_me_unavailable" = "The story where you mentioned {user} is no longer available."; "lng_action_story_mention_unavailable" = "The story where {user} mentioned you is no longer available."; "lng_action_giveaway_started" = "{from} just started a giveaway of Telegram Premium subscriptions to its followers."; +"lng_action_giveaway_results#one" = "{count} winner of the giveaway was randomly selected by Telegram and received private messages with giftcodes."; +"lng_action_giveaway_results#other" = "{count} winners of the giveaway were randomly selected by Telegram and received private messages with giftcodes."; +"lng_action_giveaway_results_some" = "Some winners of the giveaway was randomly selected by Telegram and received private messages with giftcodes."; +"lng_action_giveaway_results_none" = "No winners of the giveaway could be selected."; "lng_premium_gift_duration_months#one" = "for {count} month"; "lng_premium_gift_duration_months#other" = "for {count} months"; diff --git a/Telegram/SourceFiles/data/data_histories.cpp b/Telegram/SourceFiles/data/data_histories.cpp index 0f252aa53..dd5b435ee 100644 --- a/Telegram/SourceFiles/data/data_histories.cpp +++ b/Telegram/SourceFiles/data/data_histories.cpp @@ -72,7 +72,7 @@ MTPInputReplyTo ReplyToForMTP( | (external ? Flag::f_reply_to_peer_id : Flag()) | (replyTo.quote.text.isEmpty() ? Flag() - : Flag::f_quote_text) + : (Flag::f_quote_text | Flag::f_quote_offset)) | (quoteEntities.v.isEmpty() ? Flag() : Flag::f_quote_entities)), @@ -82,7 +82,8 @@ MTPInputReplyTo ReplyToForMTP( ? owner->peer(replyTo.messageId.peer)->input : MTPInputPeer()), MTP_string(replyTo.quote.text), - quoteEntities); + quoteEntities, + MTP_int(replyTo.quoteOffset)); } return MTPInputReplyTo(); } @@ -983,6 +984,7 @@ int Histories::sendPreparedMessage( .quote = replyTo.quote, .storyId = replyTo.storyId, .topicRootId = convertTopicReplyToId(history, replyTo.topicRootId), + .quoteOffset = replyTo.quoteOffset, }; return v::match(message(history, realReplyTo), [&](const auto &request) { const auto type = RequestType::Send; diff --git a/Telegram/SourceFiles/data/data_msg_id.h b/Telegram/SourceFiles/data/data_msg_id.h index 43260a10c..4555bda3b 100644 --- a/Telegram/SourceFiles/data/data_msg_id.h +++ b/Telegram/SourceFiles/data/data_msg_id.h @@ -161,6 +161,7 @@ struct FullReplyTo { TextWithEntities quote; FullStoryId storyId; MsgId topicRootId = 0; + int quoteOffset = 0; [[nodiscard]] bool valid() const { return messageId || (storyId && peerIsUser(storyId.peer)); diff --git a/Telegram/SourceFiles/export/data/export_data_types.cpp b/Telegram/SourceFiles/export/data/export_data_types.cpp index bbfcd37aa..ceb61bcc3 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.cpp +++ b/Telegram/SourceFiles/export/data/export_data_types.cpp @@ -1316,9 +1316,9 @@ ServiceAction ParseServiceAction( }, [&](const MTPDmessageActionSetChatWallPaper &data) { auto content = ActionSetChatWallPaper(); // #TODO wallpapers + content.same = data.is_same(); + content.both = data.is_for_both(); result.content = content; - }, [&](const MTPDmessageActionSetSameChatWallPaper &data) { - result.content = ActionSetSameChatWallPaper(); }, [&](const MTPDmessageActionRequestedPeer &data) { auto content = ActionRequestedPeer(); content.peerId = ParsePeerId(data.vpeer()); @@ -1334,9 +1334,14 @@ ServiceAction ParseServiceAction( content.months = data.vmonths().v; content.code = data.vslug().v; result.content = content; - }, [&](const MTPDmessageActionGiveawayLaunch &) { + }, [&](const MTPDmessageActionGiveawayLaunch &data) { auto content = ActionGiveawayLaunch(); result.content = content; + }, [&](const MTPDmessageActionGiveawayResults &data) { + auto content = ActionGiveawayResults(); + content.winners = data.vwinners_count().v; + content.unclaimed = data.vunclaimed_count().v; + result.content = content; }, [](const MTPDmessageActionEmpty &data) {}); return result; } diff --git a/Telegram/SourceFiles/export/data/export_data_types.h b/Telegram/SourceFiles/export/data/export_data_types.h index 99848724c..59ffa1c39 100644 --- a/Telegram/SourceFiles/export/data/export_data_types.h +++ b/Telegram/SourceFiles/export/data/export_data_types.h @@ -533,12 +533,11 @@ struct ActionSuggestProfilePhoto { }; struct ActionSetChatWallPaper { + bool same = false; + bool both = false; // #TODO wallpapers }; -struct ActionSetSameChatWallPaper { -}; - struct ActionGiftCode { QByteArray code; PeerId boostPeerId = 0; @@ -555,6 +554,11 @@ struct ActionRequestedPeer { struct ActionGiveawayLaunch { }; +struct ActionGiveawayResults { + int winners = 0; + int unclaimed = 0; +}; + struct ServiceAction { std::variant< v::null_t, @@ -593,9 +597,9 @@ struct ServiceAction { ActionSuggestProfilePhoto, ActionRequestedPeer, ActionSetChatWallPaper, - ActionSetSameChatWallPaper, ActionGiftCode, - ActionGiveawayLaunch> content; + ActionGiveawayLaunch, + ActionGiveawayResults> content; }; ServiceAction ParseServiceAction( diff --git a/Telegram/SourceFiles/export/output/export_output_html.cpp b/Telegram/SourceFiles/export/output/export_output_html.cpp index c2cb8d46e..3a19a8b4a 100644 --- a/Telegram/SourceFiles/export/output/export_output_html.cpp +++ b/Telegram/SourceFiles/export/output/export_output_html.cpp @@ -1273,12 +1273,12 @@ auto HtmlWriter::Wrap::pushMessage( }, [&](const ActionRequestedPeer &data) { return "requested: "_q/* + data.peerId*/; }, [&](const ActionSetChatWallPaper &data) { - return serviceFrom + " set a new background for this chat"; - }, [&](const ActionSetSameChatWallPaper &data) { return serviceFrom - + " set " - + wrapReplyToLink("the same background") - + " for this chat"; + + (data.same + ? (" set " + + wrapReplyToLink("the same background") + + " for this chat") + : " set a new background for this chat"); }, [&](const ActionGiftCode &data) { return data.unclaimed ? ("This is an unclaimed Telegram Premium for " @@ -1297,6 +1297,10 @@ auto HtmlWriter::Wrap::pushMessage( }, [&](const ActionGiveawayLaunch &data) { return serviceFrom + " just started a giveaway " "of Telegram Premium subscriptions to its followers."; + }, [&](const ActionGiveawayResults &data) { + return QByteArray::number(data.winners) + + " of the giveaway were randomly selected by Telegram " + "and received private messages with giftcodes."; }, [](v::null_t) { return QByteArray(); }); if (!serviceText.isEmpty()) { diff --git a/Telegram/SourceFiles/export/output/export_output_json.cpp b/Telegram/SourceFiles/export/output/export_output_json.cpp index 8cdbb5dbb..53e8a89d6 100644 --- a/Telegram/SourceFiles/export/output/export_output_json.cpp +++ b/Telegram/SourceFiles/export/output/export_output_json.cpp @@ -604,12 +604,15 @@ QByteArray SerializeMessage( push("via_giveaway", data.viaGiveaway); }, [&](const ActionGiveawayLaunch &data) { pushAction("giveaway_launch"); + }, [&](const ActionGiveawayResults &data) { + pushAction("giveaway_results"); + push("winners", data.winners); + push("unclaimed", data.unclaimed); }, [&](const ActionSetChatWallPaper &data) { pushActor(); - pushAction("set_chat_wallpaper"); - }, [&](const ActionSetSameChatWallPaper &data) { - pushActor(); - pushAction("set_same_chat_wallpaper"); + pushAction(data.same + ? "set_same_chat_wallpaper" + : "set_chat_wallpaper"); pushReplyToMsgId("message_id"); }, [](v::null_t) {}); diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp index 7c3fbbcaa..dfed773ba 100644 --- a/Telegram/SourceFiles/history/history_inner_widget.cpp +++ b/Telegram/SourceFiles/history/history_inner_widget.cpp @@ -1144,7 +1144,7 @@ void HistoryInner::paintEvent(QPaintEvent *e) { } else if (item->isUnreadMention() && !item->isUnreadMedia()) { readContents.insert(item); - _widget->enqueueMessageHighlight(view, {}); + _widget->enqueueMessageHighlight({ item }); } } session().data().reactions().poll(item, context.now); @@ -2410,17 +2410,25 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { const auto replyToItem = selected.item ? selected.item : item; const auto itemId = replyToItem->fullId(); const auto quote = selected.text; + const auto quoteOffset = selected.offset; text.replace('&', u"&&"_q); _menu->addAction(text, [=] { if (canSendReply) { - _widget->replyToMessage({ itemId, quote }); + _widget->replyToMessage({ + .messageId = itemId, + .quote = quote, + .quoteOffset = quoteOffset, + }); if (!quote.empty()) { _widget->clearSelected(); } } else { - HistoryView::Controls::ShowReplyToChatBox( - controller->uiShow(), - { itemId, quote }); + const auto show = controller->uiShow(); + HistoryView::Controls::ShowReplyToChatBox(show, { + .messageId = itemId, + .quote = quote, + .quoteOffset = quoteOffset, + }); } }, &st::menuIconReply); } diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index ef3cf5172..ec13d776c 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -78,6 +78,20 @@ constexpr auto kPinnedMessageTextLimit = 16; using ItemPreview = HistoryView::ItemPreview; +template +[[nodiscard]] PreparedServiceText PrepareEmptyText(const T &) { + return PreparedServiceText(); +}; + +template +[[nodiscard]] PreparedServiceText PrepareErrorText(const T &data) { + if constexpr (!std::is_same_v) { + const auto name = QString::fromUtf8(typeid(data).name()); + LOG(("API Error: %1 received.").arg(name)); + } + return PreparedServiceText{ { tr::lng_message_empty(tr::now) } }; +} + [[nodiscard]] TextWithEntities SpoilerLoginCode(TextWithEntities text) { const auto r = QRegularExpression(u"([\\d\\-]{5,7})"_q); const auto m = r.match(text.text); @@ -449,7 +463,7 @@ HistoryItem::HistoryItem( const auto originalMedia = original->media(); const auto dropForwardInfo = original->computeDropForwardedInfo(); config.reply.messageId = config.reply.topMessageId = topicRootId; - config.reply.topicPost = (topicRootId != 0); + config.reply.topicPost = (topicRootId != 0) ? 1 : 0; if (const auto originalReply = original->Get()) { if (originalReply->external()) { config.reply = originalReply->fields().clone(this); @@ -3371,13 +3385,15 @@ void HistoryItem::createComponentsHelper( && topic->rootId() != to->topicRootId()) { config.reply.externalPeerId = replyTo.messageId.peer; } - config.reply.topicPost = config.reply.externalPeerId + const auto topicPost = config.reply.externalPeerId ? (replyTo.topicRootId && (replyTo.topicRootId != Data::ForumTopic::kGeneralId)) : (LookupReplyIsTopicPost(to) || (to && to->Has()) || (forum && forum->creating(config.reply.topMessageId))); - config.reply.manualQuote = !replyTo.quote.empty(); + config.reply.topicPost = topicPost ? 1 : 0; + config.reply.manualQuote = replyTo.quote.empty() ? 0 : 1; + config.reply.quoteOffset = replyTo.quoteOffset; config.reply.quote = std::move(replyTo.quote); } config.markup = std::move(markup); @@ -3696,8 +3712,12 @@ void HistoryItem::createServiceFromMtp(const MTPDmessageService &message) { } }, call->lifetime); } - } else if (type == mtpc_messageActionSetSameChatWallPaper) { - UpdateComponents(HistoryServiceSameBackground::Bit()); + } else if (type == mtpc_messageActionSetChatWallPaper) { + if (action.c_messageActionSetChatWallPaper().is_same()) { + UpdateComponents(HistoryServiceSameBackground::Bit()); + } else { + RemoveComponents(HistoryServiceSameBackground::Bit()); + } } if (const auto replyTo = message.vreply_to()) { replyTo->match([&](const MTPDmessageReplyHeader &data) { @@ -3877,7 +3897,7 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { return result; }; - auto prepareChatDeletePhoto = [this] { + auto prepareChatDeletePhoto = [&](const MTPDmessageActionChatDeletePhoto &action) { auto result = PreparedServiceText(); if (isPost()) { result.text = tr::lng_action_removed_photo_channel( @@ -3956,7 +3976,23 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { return result; }; - auto prepareScreenshotTaken = [this] { + auto preparePinMessage = [&](const MTPDmessageActionPinMessage &) { + return preparePinnedText(); + }; + + auto prepareGameScore = [&](const MTPDmessageActionGameScore &) { + return prepareGameScoreText(); + }; + + auto preparePhoneCall = [&](const MTPDmessageActionPhoneCall &) -> PreparedServiceText { + Unexpected("PhoneCall type in setServiceMessageFromMtp."); + }; + + auto preparePaymentSent = [&](const MTPDmessageActionPaymentSent &) { + return preparePaymentSentText(); + }; + + auto prepareScreenshotTaken = [this](const MTPDmessageActionScreenshotTaken &) { auto result = PreparedServiceText(); if (out()) { result.text = tr::lng_action_you_took_screenshot( @@ -4055,7 +4091,7 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { return result; }; - auto prepareContactSignUp = [this] { + auto prepareContactSignUp = [this](const MTPDmessageActionContactSignUp &data) { auto result = PreparedServiceText(); result.links.push_back(fromLink()); result.text = tr::lng_action_user_registered( @@ -4258,6 +4294,10 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { return result; }; + auto prepareGroupCallScheduled = [&](const MTPDmessageActionGroupCallScheduled &data) { + return prepareCallScheduledText(data.vschedule_date().v); + }; + auto prepareSetChatTheme = [this](const MTPDmessageActionSetChatTheme &action) { auto result = PreparedServiceText(); const auto text = qs(action.vemoticon()); @@ -4459,28 +4499,7 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { auto prepareSetChatWallPaper = [&]( const MTPDmessageActionSetChatWallPaper &action) { const auto isSelf = (_from->id == _from->session().userPeerId()); - const auto peer = isSelf ? history()->peer : _from; - const auto user = peer->asUser(); - const auto name = (user && !user->firstName.isEmpty()) - ? user->firstName - : peer->name(); - auto result = PreparedServiceText{}; - result.links.push_back(peer->createOpenLink()); - result.text = isSelf - ? tr::lng_action_set_wallpaper_me( - tr::now, - Ui::Text::WithEntities) - : tr::lng_action_set_wallpaper( - tr::now, - lt_user, - Ui::Text::Link(name, 1), // Link 1. - Ui::Text::WithEntities); - return result; - }; - - auto prepareSetSameChatWallPaper = [&]( - const MTPDmessageActionSetSameChatWallPaper &action) { - const auto isSelf = (_from->id == _from->session().userPeerId()); + const auto same = action.is_same(); const auto peer = isSelf ? history()->peer : _from; const auto user = peer->asUser(); const auto name = (user && !user->firstName.isEmpty()) @@ -4491,14 +4510,18 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { result.links.push_back(peer->createOpenLink()); } result.text = isSelf - ? tr::lng_action_set_same_wallpaper_me( - tr::now, - Ui::Text::WithEntities) - : tr::lng_action_set_same_wallpaper( - tr::now, - lt_user, - Ui::Text::Link(name, 1), // Link 1. - Ui::Text::WithEntities); + ? (same + ? tr::lng_action_set_same_wallpaper_me + : tr::lng_action_set_wallpaper_me)( + tr::now, + Ui::Text::WithEntities) + : (same + ? tr::lng_action_set_same_wallpaper + : tr::lng_action_set_wallpaper)( + tr::now, + lt_user, + Ui::Text::Link(name, 1), // Link 1. + Ui::Text::WithEntities); return result; }; @@ -4532,93 +4555,65 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { return result; }; - setServiceText(action.match([&]( - const MTPDmessageActionChatAddUser &data) { - return prepareChatAddUserText(data); - }, [&](const MTPDmessageActionChatJoinedByLink &data) { - return prepareChatJoinedByLink(data); - }, [&](const MTPDmessageActionChatCreate &data) { - return prepareChatCreate(data); - }, [](const MTPDmessageActionChatMigrateTo &) { - return PreparedServiceText(); - }, [](const MTPDmessageActionChannelMigrateFrom &) { - return PreparedServiceText(); - }, [](const MTPDmessageActionHistoryClear &) { - return PreparedServiceText(); - }, [&](const MTPDmessageActionChannelCreate &data) { - return prepareChannelCreate(data); - }, [&](const MTPDmessageActionChatDeletePhoto &) { - return prepareChatDeletePhoto(); - }, [&](const MTPDmessageActionChatDeleteUser &data) { - return prepareChatDeleteUser(data); - }, [&](const MTPDmessageActionChatEditPhoto &data) { - return prepareChatEditPhoto(data); - }, [&](const MTPDmessageActionChatEditTitle &data) { - return prepareChatEditTitle(data); - }, [&](const MTPDmessageActionPinMessage &) { - return preparePinnedText(); - }, [&](const MTPDmessageActionGameScore &) { - return prepareGameScoreText(); - }, [&](const MTPDmessageActionPhoneCall &) -> PreparedServiceText { - Unexpected("PhoneCall type in setServiceMessageFromMtp."); - }, [&](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 MTPDmessageActionGeoProximityReached &data) { - return prepareProximityReached(data); - }, [](const MTPDmessageActionPaymentSentMe &) { - LOG(("API Error: messageActionPaymentSentMe received.")); - return PreparedServiceText{ { tr::lng_message_empty(tr::now) } }; - }, [](const MTPDmessageActionSecureValuesSentMe &) { - LOG(("API Error: messageActionSecureValuesSentMe received.")); - return PreparedServiceText{ { tr::lng_message_empty(tr::now) } }; - }, [&](const MTPDmessageActionGroupCall &data) { - return prepareGroupCall(data); - }, [&](const MTPDmessageActionInviteToGroupCall &data) { - return prepareInviteToGroupCall(data); - }, [&](const MTPDmessageActionSetMessagesTTL &data) { - return prepareSetMessagesTTL(data); - }, [&](const MTPDmessageActionGroupCallScheduled &data) { - return prepareCallScheduledText(data.vschedule_date().v); - }, [&](const MTPDmessageActionSetChatTheme &data) { - return prepareSetChatTheme(data); - }, [&](const MTPDmessageActionChatJoinedByRequest &data) { - return prepareChatJoinedByRequest(data); - }, [&](const MTPDmessageActionWebViewDataSent &data) { - return prepareWebViewDataSent(data); - }, [&](const MTPDmessageActionGiftPremium &data) { - return prepareGiftPremium(data); - }, [&](const MTPDmessageActionTopicCreate &data) { - return prepareTopicCreate(data); - }, [&](const MTPDmessageActionTopicEdit &data) { - return prepareTopicEdit(data); - }, [&](const MTPDmessageActionWebViewDataSentMe &data) { - LOG(("API Error: messageActionWebViewDataSentMe received.")); - return PreparedServiceText{ { tr::lng_message_empty(tr::now) } }; - }, [&](const MTPDmessageActionSuggestProfilePhoto &data) { - return prepareSuggestProfilePhoto(data); - }, [&](const MTPDmessageActionRequestedPeer &data) { - return prepareRequestedPeer(data); - }, [&](const MTPDmessageActionSetChatWallPaper &data) { - return prepareSetChatWallPaper(data); - }, [&](const MTPDmessageActionSetSameChatWallPaper &data) { - return prepareSetSameChatWallPaper(data); - }, [&](const MTPDmessageActionGiftCode &data) { - return prepareGiftCode(data); - }, [&](const MTPDmessageActionGiveawayLaunch &data) { - return prepareGiveawayLaunch(data); - }, [](const MTPDmessageActionEmpty &) { - return PreparedServiceText{ { tr::lng_message_empty(tr::now) } }; - })); + auto prepareGiveawayResults = [&](const MTPDmessageActionGiveawayResults &action) { + auto result = PreparedServiceText(); + const auto winners = action.vwinners_count().v; + const auto unclaimed = action.vunclaimed_count().v; + result.text = { + (!winners + ? tr::lng_action_giveaway_results_none(tr::now) + : unclaimed + ? tr::lng_action_giveaway_results_some(tr::now) + : tr::lng_action_giveaway_results( + tr::now, + lt_count, + winners)) + }; + return result; + }; + + setServiceText(action.match( + prepareChatAddUserText, + prepareChatJoinedByLink, + prepareChatCreate, + PrepareEmptyText, + PrepareEmptyText, + PrepareEmptyText, + prepareChannelCreate, + prepareChatDeletePhoto, + prepareChatDeleteUser, + prepareChatEditPhoto, + prepareChatEditTitle, + preparePinMessage, + prepareGameScore, + preparePhoneCall, + preparePaymentSent, + prepareScreenshotTaken, + prepareCustomAction, + prepareBotAllowed, + prepareSecureValuesSent, + prepareContactSignUp, + prepareProximityReached, + PrepareErrorText, + PrepareErrorText, + prepareGroupCall, + prepareInviteToGroupCall, + prepareSetMessagesTTL, + prepareGroupCallScheduled, + prepareSetChatTheme, + prepareChatJoinedByRequest, + prepareWebViewDataSent, + prepareGiftPremium, + prepareTopicCreate, + prepareTopicEdit, + PrepareErrorText, + prepareSuggestProfilePhoto, + prepareRequestedPeer, + prepareSetChatWallPaper, + prepareGiftCode, + prepareGiveawayLaunch, + prepareGiveawayResults, + PrepareErrorText)); // Additional information. applyAction(action); @@ -4680,10 +4675,13 @@ void HistoryItem::applyAction(const MTPMessageAction &action) { }, [](const MTPDphotoEmpty &) { }); }, [&](const MTPDmessageActionSetChatWallPaper &data) { - const auto session = &history()->session(); - const auto &attached = data.vwallpaper(); - if (const auto paper = Data::WallPaper::Create(session, attached)) { - _media = std::make_unique(this, *paper); + if (!data.is_same()) { + using namespace Data; + const auto session = &history()->session(); + const auto &attached = data.vwallpaper(); + if (const auto paper = WallPaper::Create(session, attached)) { + _media = std::make_unique(this, *paper); + } } }, [&](const MTPDmessageActionGiftCode &data) { const auto boostedId = data.vboost_peer() diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp index 66e30a58d..2fee9928f 100644 --- a/Telegram/SourceFiles/history/history_item_components.cpp +++ b/Telegram/SourceFiles/history/history_item_components.cpp @@ -283,8 +283,9 @@ ReplyFields ReplyFields::clone(not_null parent) const { .messageId = messageId, .topMessageId = topMessageId, .storyId = storyId, - .topicPost = topicPost, + .quoteOffset = quoteOffset, .manualQuote = manualQuote, + .topicPost = topicPost, }; } @@ -303,7 +304,7 @@ ReplyFields ReplyFieldsFromMTP( : id; result.topMessageId = data.vreply_to_top_id().value_or(id); - result.topicPost = data.is_forum_topic(); + result.topicPost = data.is_forum_topic() ? 1 : 0; } if (const auto header = data.vreply_from()) { const auto &data = header->data(); @@ -324,7 +325,8 @@ ReplyFields ReplyFieldsFromMTP( &owner->session(), data.vquote_entities().value_or_empty()), }; - result.manualQuote = data.is_quote(); + result.quoteOffset = data.vquote_offset().value_or_empty(); + result.manualQuote = data.is_quote() ? 1 : 0; return result; }, [&](const MTPDmessageReplyStoryHeader &data) { return ReplyFields{ @@ -357,6 +359,7 @@ FullReplyTo ReplyToFromMTP( &history->session(), data.vquote_entities().value_or_empty()), }; + result.quoteOffset = data.vquote_offset().value_or_empty(); return result; }, [&](const MTPDinputReplyToStory &data) { if (const auto parsed = Data::UserFromInputMTP( @@ -461,7 +464,7 @@ void HistoryMessageReply::updateFields( MsgId messageId, MsgId topMessageId, bool topicPost) { - _fields.topicPost = topicPost; + _fields.topicPost = topicPost ? 1 : 0; if ((_fields.messageId != messageId) && !IsServerMsgId(_fields.messageId)) { _fields.messageId = messageId; diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index 3d363225f..9275cf1b9 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -233,7 +233,7 @@ private: }; struct ReplyFields { - ReplyFields clone(not_null parent) const; + [[nodiscard]] ReplyFields clone(not_null parent) const; TextWithEntities quote; std::unique_ptr externalMedia; @@ -244,8 +244,9 @@ struct ReplyFields { MsgId messageId = 0; MsgId topMessageId = 0; StoryId storyId = 0; - bool topicPost = false; - bool manualQuote = false; + uint32 quoteOffset : 30 = 0; + uint32 manualQuote : 1 = 0; + uint32 topicPost : 1 = 0; }; [[nodiscard]] ReplyFields ReplyFieldsFromMTP( diff --git a/Telegram/SourceFiles/history/history_item_helpers.cpp b/Telegram/SourceFiles/history/history_item_helpers.cpp index 15b5d5ad8..a9f663c63 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.cpp +++ b/Telegram/SourceFiles/history/history_item_helpers.cpp @@ -270,19 +270,22 @@ bool IsItemScheduledUntilOnline(not_null item) { ClickHandlerPtr JumpToMessageClickHandler( not_null item, FullMsgId returnToId, - TextWithEntities highlightPart) { + TextWithEntities highlightPart, + int highlightPartOffsetHint) { return JumpToMessageClickHandler( item->history()->peer, item->id, returnToId, - std::move(highlightPart)); + std::move(highlightPart), + highlightPartOffsetHint); } ClickHandlerPtr JumpToMessageClickHandler( not_null peer, MsgId msgId, FullMsgId returnToId, - TextWithEntities highlightPart) { + TextWithEntities highlightPart, + int highlightPartOffsetHint) { return std::make_shared([=] { const auto separate = Core::App().separateWindowForPeer(peer); const auto controller = separate @@ -293,6 +296,7 @@ ClickHandlerPtr JumpToMessageClickHandler( Window::SectionShow::Way::Forward }; params.highlightPart = highlightPart; + params.highlightPartOffsetHint = highlightPartOffsetHint; params.origin = Window::SectionShow::OriginMessage{ returnToId }; @@ -392,8 +396,11 @@ MTPMessageReplyHeader NewMessageReplyHeader(const Api::SendAction &action) { MTP_flags(Flag::f_reply_to_msg_id | (replyToTop ? Flag::f_reply_to_top_id : Flag()) | (externalPeerId ? Flag::f_reply_to_peer_id : Flag()) - | (replyTo.quote.empty() ? Flag() : Flag::f_quote) - | (replyTo.quote.empty() ? Flag() : Flag::f_quote_text) + | (replyTo.quote.empty() + ? Flag() + : (Flag::f_quote + | Flag::f_quote_text + | Flag::f_quote_offset)) | (quoteEntities.v.empty() ? Flag() : Flag::f_quote_entities)), @@ -403,7 +410,8 @@ MTPMessageReplyHeader NewMessageReplyHeader(const Api::SendAction &action) { MTPMessageMedia(), // reply_media MTP_int(replyToTop), MTP_string(replyTo.quote.text), - quoteEntities); + quoteEntities, + MTP_int(replyTo.quoteOffset)); } return MTPMessageReplyHeader(); } diff --git a/Telegram/SourceFiles/history/history_item_helpers.h b/Telegram/SourceFiles/history/history_item_helpers.h index cf1045abd..a39c4b0e2 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.h +++ b/Telegram/SourceFiles/history/history_item_helpers.h @@ -124,11 +124,13 @@ struct SendingErrorRequest { not_null peer, MsgId msgId, FullMsgId returnToId = FullMsgId(), - TextWithEntities highlightPart = {}); + TextWithEntities highlightPart = {}, + int highlightPartOffsetHint = 0); [[nodiscard]] ClickHandlerPtr JumpToMessageClickHandler( not_null item, FullMsgId returnToId = FullMsgId(), - TextWithEntities highlightPart = {}); + TextWithEntities highlightPart = {}, + int highlightPartOffsetHint = 0); [[nodiscard]] ClickHandlerPtr JumpToStoryClickHandler( not_null story); ClickHandlerPtr JumpToStoryClickHandler( diff --git a/Telegram/SourceFiles/history/history_view_highlight_manager.cpp b/Telegram/SourceFiles/history/history_view_highlight_manager.cpp index 29e157344..ee07a1571 100644 --- a/Telegram/SourceFiles/history/history_view_highlight_manager.cpp +++ b/Telegram/SourceFiles/history/history_view_highlight_manager.cpp @@ -25,10 +25,8 @@ ElementHighlighter::ElementHighlighter( , _animation(*this) { } -void ElementHighlighter::enqueue( - not_null view, - const TextWithEntities &part) { - const auto data = computeHighlight(view, part); +void ElementHighlighter::enqueue(const SelectedQuote "e) { + const auto data = computeHighlight(quote); if (_queue.empty() && !_animation.animating()) { highlight(data); } else if (_highlighted != data && !base::contains(_queue, data)) { @@ -37,10 +35,8 @@ void ElementHighlighter::enqueue( } } -void ElementHighlighter::highlight( - not_null view, - const TextWithEntities &part) { - highlight(computeHighlight(view, part)); +void ElementHighlighter::highlight(const SelectedQuote "e) { + highlight(computeHighlight(quote)); } void ElementHighlighter::checkNextHighlight() { @@ -75,9 +71,10 @@ Ui::ChatPaintHighlight ElementHighlighter::state( } ElementHighlighter::Highlight ElementHighlighter::computeHighlight( - not_null view, - const TextWithEntities &part) { - const auto item = view->data(); + const SelectedQuote "e) { + Assert(quote.item != nullptr); + + const auto item = not_null(quote.item); const auto owner = &item->history()->owner(); if (const auto group = owner->groups().find(item)) { const auto leader = group->items.front(); @@ -85,20 +82,19 @@ ElementHighlighter::Highlight ElementHighlighter::computeHighlight( const auto i = ranges::find(group->items, item); if (i != end(group->items)) { const auto index = int(i - begin(group->items)); - if (part.empty()) { + if (quote.text.empty()) { return { leaderId, AddGroupItemSelection({}, index) }; } else if (const auto leaderView = _viewForItem(leader)) { - return { - leaderId, - leaderView->selectionFromQuote(item, part), - }; + return { leaderId, leaderView->selectionFromQuote(quote) }; } } return { leaderId }; - } else if (part.empty()) { + } else if (quote.text.empty()) { return { item->fullId() }; + } else if (const auto view = _viewForItem(item)) { + return { item->fullId(), view->selectionFromQuote(quote) }; } - return { item->fullId(), view->selectionFromQuote(item, part) }; + return { item->fullId() }; } void ElementHighlighter::highlight(Highlight data) { diff --git a/Telegram/SourceFiles/history/history_view_highlight_manager.h b/Telegram/SourceFiles/history/history_view_highlight_manager.h index 7fdcdfc0b..5a3b43ca8 100644 --- a/Telegram/SourceFiles/history/history_view_highlight_manager.h +++ b/Telegram/SourceFiles/history/history_view_highlight_manager.h @@ -23,6 +23,7 @@ struct ChatPaintHighlight; namespace HistoryView { class Element; +struct SelectedQuote; class ElementHighlighter final { public: @@ -33,8 +34,8 @@ public: ViewForItem viewForItem, RepaintView repaintView); - void enqueue(not_null view, const TextWithEntities &part); - void highlight(not_null view, const TextWithEntities &part); + void enqueue(const SelectedQuote "e); + void highlight(const SelectedQuote "e); void clear(); [[nodiscard]] Ui::ChatPaintHighlight state( @@ -71,9 +72,7 @@ private: friend inline bool operator==(Highlight, Highlight) = default; }; - [[nodiscard]] Highlight computeHighlight( - not_null view, - const TextWithEntities &part); + [[nodiscard]] Highlight computeHighlight(const SelectedQuote "e); void highlight(Highlight data); void checkNextHighlight(); void repaintHighlightedItem(not_null view); diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 5b8a51753..849234013 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -1075,7 +1075,7 @@ void HistoryWidget::initTabbedSelector() { if (!data.recipientOverride) { return true; } else if (data.recipientOverride != _peer) { - showHistory(data.recipientOverride->id, ShowAtTheEndMsgId, {}); + showHistory(data.recipientOverride->id, ShowAtTheEndMsgId); } return (data.recipientOverride == _peer); }) | rpl::start_with_next([=](ChatHelpers::InlineChosen data) { @@ -1270,9 +1270,8 @@ void HistoryWidget::scrollToAnimationCallback( } void HistoryWidget::enqueueMessageHighlight( - not_null view, - const TextWithEntities &part) { - _highlighter.enqueue(view, part); + const HistoryView::SelectedQuote "e) { + _highlighter.enqueue(quote); } Ui::ChatPaintHighlight HistoryWidget::itemHighlight( @@ -1973,10 +1972,12 @@ bool HistoryWidget::insideJumpToEndInsteadOfToUnread() const { void HistoryWidget::showHistory( const PeerId &peerId, MsgId showAtMsgId, - const TextWithEntities &highlightPart) { + const TextWithEntities &highlightPart, + int highlightPartOffsetHint) { _pinnedClickedId = FullMsgId(); _minPinnedId = std::nullopt; _showAtMsgHighlightPart = {}; + _showAtMsgHighlightPartOffsetHint = 0; const auto wasDialogsEntryState = computeDialogsEntryState(); const auto startBot = (showAtMsgId == ShowAndStartBotMsgId); @@ -2024,10 +2025,16 @@ void HistoryWidget::showHistory( ).arg(_history->inboxReadTillId().bare ).arg(Logs::b(_history->loadedAtBottom()) ).arg(showAtMsgId.bare)); - delayedShowAt(showAtMsgId, highlightPart); + delayedShowAt( + showAtMsgId, + highlightPart, + highlightPartOffsetHint); } else if (_showAtMsgId != showAtMsgId) { clearAllLoadRequests(); - setMsgId(showAtMsgId, highlightPart); + setMsgId( + showAtMsgId, + highlightPart, + highlightPartOffsetHint); firstLoadMessages(); doneShow(); } @@ -2047,7 +2054,10 @@ void HistoryWidget::showHistory( _cornerButtons.skipReplyReturn(skipId); } - setMsgId(showAtMsgId, highlightPart); + setMsgId( + showAtMsgId, + highlightPart, + highlightPartOffsetHint); if (_historyInited) { DEBUG_LOG(("JumpToEnd(%1, %2, %3): " "Showing instant at %4." @@ -2151,6 +2161,7 @@ void HistoryWidget::showHistory( _showAtMsgId = showAtMsgId; _showAtMsgHighlightPart = highlightPart; + _showAtMsgHighlightPartOffsetHint = highlightPartOffsetHint; _historyInited = false; _contactStatus = nullptr; @@ -3305,7 +3316,10 @@ void HistoryWidget::messagesReceived( } _delayedShowAtRequest = 0; - setMsgId(_delayedShowAtMsgId, _delayedShowAtMsgHighlightPart); + setMsgId( + _delayedShowAtMsgId, + _delayedShowAtMsgHighlightPart, + _delayedShowAtMsgHighlightPartOffsetHint); historyLoaded(); } if (session().supportMode()) { @@ -3529,13 +3543,15 @@ void HistoryWidget::loadMessagesDown() { void HistoryWidget::delayedShowAt( MsgId showAtMsgId, - const TextWithEntities &highlightPart) { + const TextWithEntities &highlightPart, + int highlightPartOffsetHint) { if (!_history) { return; } if (_delayedShowAtMsgHighlightPart != highlightPart) { _delayedShowAtMsgHighlightPart = highlightPart; } + _delayedShowAtMsgHighlightPartOffsetHint = highlightPartOffsetHint; if (_delayedShowAtRequest && _delayedShowAtMsgId == showAtMsgId) { return; } @@ -4120,10 +4136,12 @@ PeerData *HistoryWidget::peer() const { // Sometimes _showAtMsgId is set directly. void HistoryWidget::setMsgId( MsgId showAtMsgId, - const TextWithEntities &highlightPart) { + const TextWithEntities &highlightPart, + int highlightPartOffsetHint) { if (_showAtMsgHighlightPart != highlightPart) { _showAtMsgHighlightPart = highlightPart; } + _showAtMsgHighlightPartOffsetHint = highlightPartOffsetHint; if (_showAtMsgId != showAtMsgId) { _showAtMsgId = showAtMsgId; if (_history) { @@ -4244,11 +4262,11 @@ void HistoryWidget::cornerButtonsShowAtPosition( ).arg(_history->peer->name() ).arg(_history->inboxReadTillId().bare ).arg(Logs::b(_history->loadedAtBottom()))); - showHistory(_peer->id, ShowAtUnreadMsgId, {}); + showHistory(_peer->id, ShowAtUnreadMsgId); } else if (_peer && position.fullId.peer == _peer->id) { - showHistory(_peer->id, position.fullId.msg, {}); + showHistory(_peer->id, position.fullId.msg); } else if (_migrated && position.fullId.peer == _migrated->peer->id) { - showHistory(_peer->id, -position.fullId.msg, {}); + showHistory(_peer->id, -position.fullId.msg); } } @@ -5700,9 +5718,11 @@ int HistoryWidget::countInitialScrollTop() { const auto view = item->mainView(); Assert(view != nullptr); - enqueueMessageHighlight( - view, - base::take(_showAtMsgHighlightPart)); + enqueueMessageHighlight({ + item, + base::take(_showAtMsgHighlightPart), + base::take(_showAtMsgHighlightPartOffsetHint), + }); const auto result = itemTopForHighlight(view); createUnreadBarIfBelowVisibleArea(result); return result; @@ -6386,8 +6406,7 @@ void HistoryWidget::handlePeerMigration() { if (_peer != channel) { showHistory( channel->id, - (_showAtMsgId > 0) ? (-_showAtMsgId) : _showAtMsgId, - {}); + (_showAtMsgId > 0) ? (-_showAtMsgId) : _showAtMsgId); channel->session().api().chatParticipants().requestCountDelayed( channel); } else { @@ -6483,7 +6502,7 @@ bool HistoryWidget::showSlowmodeError() { if (const auto item = _history->latestSendingMessage()) { if (const auto view = item->mainView()) { animatedScrollToItem(item->id); - enqueueMessageHighlight(view, {}); + enqueueMessageHighlight({ item }); } return tr::lng_slowmode_no_many(tr::now); } @@ -7149,7 +7168,7 @@ void HistoryWidget::replyToMessage( if (isJoinChannel()) { return; } - _processingReplyTo = { .messageId = item->fullId(), .quote = quote}; + _processingReplyTo = { .messageId = item->fullId(), .quote = quote }; _processingReplyItem = item; processReply(); } diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index 10a54c858..51d5aac84 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -95,6 +95,7 @@ class Element; class PinnedTracker; class TranslateBar; class ComposeSearch; +struct SelectedQuote; } // namespace HistoryView namespace HistoryView::Controls { @@ -149,7 +150,8 @@ public: void firstLoadMessages(); void delayedShowAt( MsgId showAtMsgId, - const TextWithEntities &highlightPart); + const TextWithEntities &highlightPart, + int highlightPartOffsetHint); bool updateReplaceMediaButton(); void updateFieldPlaceholder(); @@ -165,7 +167,8 @@ public: PeerData *peer() const; void setMsgId( MsgId showAtMsgId, - const TextWithEntities &highlightPart = {}); + const TextWithEntities &highlightPart = {}, + int highlightPartOffsetHint = 0); MsgId msgId() const; bool hasTopBarShadow() const { @@ -182,9 +185,7 @@ public: bool touchScroll(const QPoint &delta); - void enqueueMessageHighlight( - not_null view, - const TextWithEntities &part); + void enqueueMessageHighlight(const HistoryView::SelectedQuote "e); [[nodiscard]] Ui::ChatPaintHighlight itemHighlight( not_null item) const; @@ -228,7 +229,8 @@ public: void showHistory( const PeerId &peer, MsgId showAtMsgId, - const TextWithEntities &highlightPart); + const TextWithEntities &highlightPart = {}, + int highlightPartOffsetHint = 0); void setChooseReportMessagesDetails( Ui::ReportReason reason, Fn callback); @@ -693,6 +695,7 @@ private: bool _canSendTexts = false; MsgId _showAtMsgId = ShowAtUnreadMsgId; TextWithEntities _showAtMsgHighlightPart; + int _showAtMsgHighlightPartOffsetHint = 0; int _firstLoadRequest = 0; // Not real mtpRequestId. int _preloadRequest = 0; // Not real mtpRequestId. @@ -700,6 +703,7 @@ private: MsgId _delayedShowAtMsgId = -1; TextWithEntities _delayedShowAtMsgHighlightPart; + int _delayedShowAtMsgHighlightPartOffsetHint = 0; int _delayedShowAtRequest = 0; // Not real mtpRequestId. History *_supportPreloadHistory = nullptr; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp index 18edcd0c4..60abbf021 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_draft_options.cpp @@ -235,7 +235,7 @@ rpl::producer PreviewWrap::showQuoteSelector( initElement(); - _selection = _element->selectionFromQuote(item, quote.text); + _selection = _element->selectionFromQuote(quote); return _selection.value( ) | rpl::map([=](TextSelection selection) { if (const auto result = _element->selectedQuote(selection)) { @@ -643,6 +643,7 @@ void DraftOptionsBox( if (const auto current = state->quote.current()) { result.messageId = current.item->fullId(); result.quote = current.text; + result.quoteOffset = current.offset; } else { result.quote = {}; } diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index 1775a3177..cc680ab1d 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -581,7 +581,9 @@ bool AddReplyToMessageAction( const ContextMenuRequest &request, not_null list) { const auto context = list->elementContext(); - const auto item = request.quoteItem ? request.quoteItem : request.item; + const auto item = request.quote.item + ? request.quote.item + : request.item; const auto topic = item ? item->topic() : nullptr; const auto peer = item ? item->history()->peer.get() : nullptr; if (!item @@ -598,7 +600,7 @@ bool AddReplyToMessageAction( } const auto "e = request.quote; - auto text = quote.empty() + auto text = quote.text.empty() ? tr::lng_context_reply_msg(tr::now) : tr::lng_context_quote_and_reply(tr::now); text.replace('&', u"&&"_q); @@ -607,7 +609,11 @@ bool AddReplyToMessageAction( if (!item) { return; } else { - list->replyToMessageRequestNotify({ itemId, quote }); + list->replyToMessageRequestNotify({ + .messageId = itemId, + .quote = quote.text, + .quoteOffset = quote.offset, + }); } }, &st::menuIconReply); return true; diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.h b/Telegram/SourceFiles/history/view/history_view_context_menu.h index fb99d2cc6..53a45e36c 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.h +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "base/unique_qptr.h" +#include "history/view/history_view_element.h" namespace Data { struct ReactionId; @@ -47,8 +48,7 @@ struct ContextMenuRequest { HistoryItem *item = nullptr; SelectedItems selectedItems; TextForMimeData selectedText; - TextWithEntities quote; - HistoryItem *quoteItem = nullptr; + SelectedQuote quote; bool overSelection = false; PointState pointState = PointState(); }; diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 5c1e76063..be4e9f941 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -1647,29 +1647,30 @@ SelectedQuote Element::FindSelectedQuote( ++i; } } - return { item, result }; + return { item, result, modified.from }; } TextSelection Element::FindSelectionFromQuote( const Ui::Text::String &text, - not_null item, - const TextWithEntities "e) { - if (quote.empty()) { + const SelectedQuote "e) { + Expects(quote.item != nullptr); + + if (quote.text.empty()) { return {}; } - const auto &original = item->originalText(); + const auto &original = quote.item->originalText(); auto result = TextSelection(); auto offset = 0; while (true) { - const auto i = original.text.indexOf(quote.text, offset); + const auto i = original.text.indexOf(quote.text.text, offset); if (i < 0) { return {}; } auto selection = TextSelection{ uint16(i), - uint16(i + quote.text.size()), + uint16(i + quote.text.text.size()), }; - if (CheckQuoteEntities(quote.entities, original, selection)) { + if (CheckQuoteEntities(quote.text.entities, original, selection)) { result = selection; break; } diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index a5e7a86a4..2ba36333a 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -270,6 +270,7 @@ struct TopicButton { struct SelectedQuote { HistoryItem *item = nullptr; TextWithEntities text; + int offset = 0; explicit operator bool() const { return item && !text.empty(); @@ -401,8 +402,7 @@ public: virtual SelectedQuote selectedQuote( TextSelection selection) const = 0; virtual TextSelection selectionFromQuote( - not_null item, - const TextWithEntities "e) const = 0; + const SelectedQuote "e) const = 0; [[nodiscard]] virtual TextSelection adjustSelection( TextSelection selection, TextSelectType type) const; @@ -413,8 +413,7 @@ public: not_null item); [[nodiscard]] static TextSelection FindSelectionFromQuote( const Ui::Text::String &text, - not_null item, - const TextWithEntities "e); + const SelectedQuote "e); [[nodiscard]] virtual auto reactionButtonParameters( QPoint position, diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 2db6bddb8..eff514b35 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -709,9 +709,10 @@ bool ListWidget::isBelowPosition(Data::MessagePosition position) const { void ListWidget::highlightMessage( FullMsgId itemId, - const TextWithEntities &part) { + const TextWithEntities &part, + int partOffsetHint) { if (const auto view = viewForItem(itemId)) { - _highlighter.highlight(view, part); + _highlighter.highlight({ view->data(), part, partOffsetHint }); } } @@ -787,7 +788,10 @@ bool ListWidget::showAtPositionNow( computeScrollTo(*scrollTop, position, params.animated); if (position != Data::MaxMessagePosition && position != Data::UnreadMessagePosition) { - highlightMessage(position.fullId, params.highlightPart); + highlightMessage( + position.fullId, + params.highlightPart, + params.highlightPartOffsetHint); } if (done) { const auto found = !position.fullId.peer @@ -2143,7 +2147,7 @@ void ListWidget::paintEvent(QPaintEvent *e) { } else if (item->isUnreadMention() && !item->isUnreadMedia()) { readContents.insert(item); - _highlighter.enqueue(view, {}); + _highlighter.enqueue({ item }); } } session->data().reactions().poll(item, context.now); @@ -2603,12 +2607,10 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) { request.view = _overElement; request.item = overItem; request.pointState = _overState.pointState; - const auto quote = (_overElement + request.quote = (_overElement && _selectedTextItem == _overElement->data()) ? _overElement->selectedQuote(_selectedTextRange) : SelectedQuote(); - request.quote = quote.text; - request.quoteItem = quote.item; request.selectedText = _selectedText; request.selectedItems = collectSelectedItems(); const auto hasSelection = !request.selectedItems.empty() diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.h b/Telegram/SourceFiles/history/view/history_view_list_widget.h index 95b641a04..1321a24ba 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.h @@ -233,7 +233,8 @@ public: bool isBelowPosition(Data::MessagePosition position) const; void highlightMessage( FullMsgId itemId, - const TextWithEntities &part); + const TextWithEntities &part, + int partOffsetHint); void showAtPosition( Data::MessagePosition position, diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 9e9436176..c8f00f853 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -2684,11 +2684,13 @@ SelectedQuote Message::selectedQuote(TextSelection selection) const { } TextSelection Message::selectionFromQuote( - not_null item, - const TextWithEntities "e) const { - if (quote.empty()) { + const SelectedQuote "e) const { + Expects(quote.item != nullptr); + + if (quote.text.empty()) { return {}; } + const auto item = quote.item; const auto &translated = item->translatedText(); const auto &original = item->originalText(); if (&translated != &original) { @@ -2697,11 +2699,11 @@ TextSelection Message::selectionFromQuote( const auto media = this->media(); const auto mediaDisplayed = media && media->isDisplayed(); const auto mediaBefore = mediaDisplayed && invertMedia(); - const auto result = FindSelectionFromQuote(text(), item, quote); + const auto result = FindSelectionFromQuote(text(), quote); return mediaBefore ? media->unskipSelection(result) : result; } else if (const auto media = this->media()) { if (media->isDisplayed() || isHiddenByGroup()) { - return media->selectionFromQuote(item, quote); + return media->selectionFromQuote(quote); } } return {}; diff --git a/Telegram/SourceFiles/history/view/history_view_message.h b/Telegram/SourceFiles/history/view/history_view_message.h index 2b9112c1c..4b75f21fa 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.h +++ b/Telegram/SourceFiles/history/view/history_view_message.h @@ -97,8 +97,7 @@ public: TextForMimeData selectedText(TextSelection selection) const override; SelectedQuote selectedQuote(TextSelection selection) const override; TextSelection selectionFromQuote( - not_null item, - const TextWithEntities "e) const override; + const SelectedQuote "e) const override; TextSelection adjustSelection( TextSelection selection, TextSelectType type) const override; diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp index d71aacdba..24c1ba4a4 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.cpp +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.cpp @@ -130,11 +130,13 @@ RepliesMemento::RepliesMemento( not_null history, MsgId rootId, MsgId highlightId, - const TextWithEntities &highlightPart) + const TextWithEntities &highlightPart, + int highlightPartOffsetHint) : _history(history) , _rootId(rootId) -, _highlightId(highlightId) -, _highlightPart(highlightPart) { +, _highlightPart(highlightPart) +, _highlightPartOffsetHint(highlightPartOffsetHint) +, _highlightId(highlightId) { if (highlightId) { _list.setAroundPosition({ .fullId = FullMsgId(_history->peer->id, highlightId), @@ -2149,6 +2151,7 @@ void RepliesWidget::restoreState(not_null memento) { Window::SectionShow::Way::Forward, anim::type::instant); params.highlightPart = memento->highlightPart(); + params.highlightPartOffsetHint = memento->highlightPartOffsetHint(); showAtPosition(Data::MessagePosition{ .fullId = FullMsgId(_history->peer->id, highlight), .date = TimeId(0), diff --git a/Telegram/SourceFiles/history/view/history_view_replies_section.h b/Telegram/SourceFiles/history/view/history_view_replies_section.h index e8d3e6139..68f95177b 100644 --- a/Telegram/SourceFiles/history/view/history_view_replies_section.h +++ b/Telegram/SourceFiles/history/view/history_view_replies_section.h @@ -381,7 +381,8 @@ public: not_null history, MsgId rootId, MsgId highlightId = 0, - const TextWithEntities &highlightPart = {}); + const TextWithEntities &highlightPart = {}, + int highlightPartOffsetHint = 0); explicit RepliesMemento( not_null commentsItem, MsgId commentId = 0); @@ -431,14 +432,18 @@ public: [[nodiscard]] const TextWithEntities &highlightPart() const { return _highlightPart; } + [[nodiscard]] int highlightPartOffsetHint() const { + return _highlightPartOffsetHint; + } private: void setupTopicViewer(); const not_null _history; MsgId _rootId = 0; - const MsgId _highlightId = 0; const TextWithEntities _highlightPart; + const int _highlightPartOffsetHint = 0; + const MsgId _highlightId = 0; ListMemento _list; std::shared_ptr _replies; QVector _replyReturns; diff --git a/Telegram/SourceFiles/history/view/history_view_service_message.cpp b/Telegram/SourceFiles/history/view/history_view_service_message.cpp index 0705ff2a5..8c2ed651d 100644 --- a/Telegram/SourceFiles/history/view/history_view_service_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_service_message.cpp @@ -674,8 +674,7 @@ SelectedQuote Service::selectedQuote(TextSelection selection) const { } TextSelection Service::selectionFromQuote( - not_null item, - const TextWithEntities "e) const { + const SelectedQuote "e) const { return {}; } diff --git a/Telegram/SourceFiles/history/view/history_view_service_message.h b/Telegram/SourceFiles/history/view/history_view_service_message.h index 617dd1adb..30f422981 100644 --- a/Telegram/SourceFiles/history/view/history_view_service_message.h +++ b/Telegram/SourceFiles/history/view/history_view_service_message.h @@ -45,8 +45,7 @@ public: TextForMimeData selectedText(TextSelection selection) const override; SelectedQuote selectedQuote(TextSelection selection) const override; TextSelection selectionFromQuote( - not_null item, - const TextWithEntities "e) const override; + const SelectedQuote "e) const override; TextSelection adjustSelection( TextSelection selection, TextSelectType type) const override; diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 06825b37d..4a533b88d 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -1232,12 +1232,10 @@ SelectedQuote Document::selectedQuote(TextSelection selection) const { } TextSelection Document::selectionFromQuote( - not_null item, - const TextWithEntities "e) const { + const SelectedQuote "e) const { if (const auto captioned = Get()) { const auto result = Element::FindSelectionFromQuote( captioned->caption, - item, quote); if (result.empty()) { return {}; diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.h b/Telegram/SourceFiles/history/view/media/history_view_document.h index ec2dc0d78..126a7c777 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.h +++ b/Telegram/SourceFiles/history/view/media/history_view_document.h @@ -48,8 +48,7 @@ public: TextForMimeData selectedText(TextSelection selection) const override; SelectedQuote selectedQuote(TextSelection selection) const override; TextSelection selectionFromQuote( - not_null item, - const TextWithEntities "e) const override; + const SelectedQuote "e) const override; bool uploading() const override; diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index 128797f8f..1739c6390 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -1205,10 +1205,8 @@ SelectedQuote Gif::selectedQuote(TextSelection selection) const { return Element::FindSelectedQuote(_caption, selection, _realParent); } -TextSelection Gif::selectionFromQuote( - not_null item, - const TextWithEntities "e) const { - return Element::FindSelectionFromQuote(_caption, item, quote); +TextSelection Gif::selectionFromQuote(const SelectedQuote "e) const { + return Element::FindSelectionFromQuote(_caption, quote); } bool Gif::fullFeaturedGrouped(RectParts sides) const { diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.h b/Telegram/SourceFiles/history/view/media/history_view_gif.h index f20549771..1d1b30e4a 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.h +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.h @@ -71,8 +71,7 @@ public: TextForMimeData selectedText(TextSelection selection) const override; SelectedQuote selectedQuote(TextSelection selection) const override; TextSelection selectionFromQuote( - not_null item, - const TextWithEntities "e) const override; + const SelectedQuote "e) const override; bool uploading() const override; diff --git a/Telegram/SourceFiles/history/view/media/history_view_media.h b/Telegram/SourceFiles/history/view/media/history_view_media.h index 7dadb5f87..b8c04d0b5 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media.h @@ -92,8 +92,7 @@ public: [[nodiscard]] virtual SelectedQuote selectedQuote( TextSelection selection) const; [[nodiscard]] virtual TextSelection selectionFromQuote( - not_null item, - const TextWithEntities "e) const { + const SelectedQuote "e) const { return {}; } diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp index d0133aa76..233422631 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp @@ -622,19 +622,20 @@ SelectedQuote GroupedMedia::selectedQuote(TextSelection selection) const { } TextSelection GroupedMedia::selectionFromQuote( - not_null item, - const TextWithEntities "e) const { + const SelectedQuote "e) const { + Expects(quote.item != nullptr); + if (_mode != Mode::Column) { - return (_captionItem == item) - ? Element::FindSelectionFromQuote(_caption, item, quote) + return (_captionItem == quote.item) + ? Element::FindSelectionFromQuote(_caption, quote) : TextSelection(); } - const auto i = ranges::find(_parts, item, &Part::item); + const auto i = ranges::find(_parts, not_null(quote.item), &Part::item); if (i == end(_parts)) { return {}; } const auto index = int(i - begin(_parts)); - auto result = i->content->selectionFromQuote(item, quote); + auto result = i->content->selectionFromQuote(quote); if (result.empty()) { return AddGroupItemSelection({}, index); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h index b6fbc77d9..f8baabe8a 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h @@ -57,8 +57,7 @@ public: TextForMimeData selectedText(TextSelection selection) const override; SelectedQuote selectedQuote(TextSelection selection) const override; TextSelection selectionFromQuote( - not_null item, - const TextWithEntities "e) const override; + const SelectedQuote "e) const override; std::vector getBubbleSelectionIntervals( TextSelection selection) const override; diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp index 85a2997a8..84b88da8a 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp @@ -1098,10 +1098,8 @@ SelectedQuote Photo::selectedQuote(TextSelection selection) const { return Element::FindSelectedQuote(_caption, selection, _realParent); } -TextSelection Photo::selectionFromQuote( - not_null item, - const TextWithEntities "e) const { - return Element::FindSelectionFromQuote(_caption, item, quote); +TextSelection Photo::selectionFromQuote(const SelectedQuote "e) const { + return Element::FindSelectionFromQuote(_caption, quote); } void Photo::hideSpoilers() { diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.h b/Telegram/SourceFiles/history/view/media/history_view_photo.h index 4b123cc7c..1c99839ce 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.h +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.h @@ -59,8 +59,7 @@ public: TextForMimeData selectedText(TextSelection selection) const override; SelectedQuote selectedQuote(TextSelection selection) const override; TextSelection selectionFromQuote( - not_null item, - const TextWithEntities "e) const override; + const SelectedQuote "e) const override; PhotoData *getPhoto() const override { return _data; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 2540e2c98..cacb19ff6 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1411,7 +1411,11 @@ void MainWidget::showHistory( && way != Way::Forward) { clearBotStartToken(_history->peer()); } - _history->showHistory(peerId, showAtMsgId, params.highlightPart); + _history->showHistory( + peerId, + showAtMsgId, + params.highlightPart, + params.highlightPartOffsetHint); if (alreadyThatPeer && params.reapplyLocalDraft) { _history->applyDraft(HistoryWidget::FieldHistoryAction::NewEntry); } @@ -1772,7 +1776,7 @@ void MainWidget::showNewSection( } else { _mainSection = std::move(newMainSection); _history->finishAnimating(); - _history->showHistory(0, 0, {}); + _history->showHistory(PeerId(), MsgId()); if (const auto entry = _mainSection->activeChat(); entry.key) { _controller->setActiveChatEntry(entry); diff --git a/Telegram/SourceFiles/mtproto/scheme/api.tl b/Telegram/SourceFiles/mtproto/scheme/api.tl index 41afd1025..551c7b6bd 100644 --- a/Telegram/SourceFiles/mtproto/scheme/api.tl +++ b/Telegram/SourceFiles/mtproto/scheme/api.tl @@ -101,7 +101,7 @@ channel#1981ea7e flags:# creator:flags.0?true left:flags.2?true broadcast:flags. channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat; chatFull#c9d31138 flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions = ChatFull; -channelFull#723027bd flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions stories:flags2.4?PeerStories = ChatFull; +channelFull#723027bd flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions stories:flags2.4?PeerStories = ChatFull; chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant; chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant; @@ -170,12 +170,12 @@ messageActionTopicCreate#d999256 flags:# title:string icon_color:int icon_emoji_ messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = MessageAction; messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction; messageActionRequestedPeer#fe77345d button_id:int peer:Peer = MessageAction; -messageActionSetChatWallPaper#bc44a927 wallpaper:WallPaper = MessageAction; -messageActionSetSameChatWallPaper#c0787d6d wallpaper:WallPaper = MessageAction; +messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction; messageActionGiftCode#d2cfdb0e flags:# via_giveaway:flags.0?true unclaimed:flags.2?true boost_peer:flags.1?Peer months:int slug:string = MessageAction; messageActionGiveawayLaunch#332ba9ed = MessageAction; +messageActionGiveawayResults#2a9fadc5 winners_count:int unclaimed_count:int = MessageAction; -dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; +dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; photoEmpty#2331b22d id:long = Photo; @@ -392,6 +392,9 @@ updateReadStories#f74e932b peer:Peer max_id:int = Update; updateStoryID#1bf335b9 id:int random_id:long = Update; updateStoriesStealthMode#2c084dc1 stealth_mode:StoriesStealthMode = Update; updateSentStoryReaction#7d627683 peer:Peer story_id:int reaction:Reaction = Update; +updateBotChatBoost#904dd49c peer:Peer boost:Boost qts:int = Update; +updateChannelViewForumAsMessages#7b68920 channel_id:long enabled:Bool = Update; +updatePeerWallpaper#ae3f101d flags:# peer:Peer wallpaper:flags.0?WallPaper = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -1232,7 +1235,7 @@ statsGraph#8ea464b6 flags:# json:DataJSON zoom_token:flags.0?string = StatsGraph messageInteractionCounters#ad4fc9bd msg_id:int views:int forwards:int = MessageInteractionCounters; -stats.broadcastStats#bdf78394 period:StatsDateRangeDays followers:StatsAbsValueAndPrev views_per_post:StatsAbsValueAndPrev shares_per_post:StatsAbsValueAndPrev enabled_notifications:StatsPercentValue growth_graph:StatsGraph followers_graph:StatsGraph mute_graph:StatsGraph top_hours_graph:StatsGraph interactions_graph:StatsGraph iv_interactions_graph:StatsGraph views_by_source_graph:StatsGraph new_followers_by_source_graph:StatsGraph languages_graph:StatsGraph recent_message_interactions:Vector = stats.BroadcastStats; +stats.broadcastStats#cb303962 period:StatsDateRangeDays followers:StatsAbsValueAndPrev views_per_post:StatsAbsValueAndPrev shares_per_post:StatsAbsValueAndPrev enabled_notifications:StatsPercentValue growth_graph:StatsGraph followers_graph:StatsGraph mute_graph:StatsGraph top_hours_graph:StatsGraph interactions_graph:StatsGraph iv_interactions_graph:StatsGraph views_by_source_graph:StatsGraph new_followers_by_source_graph:StatsGraph languages_graph:StatsGraph reactions_by_emotion_graph:StatsGraph story_interactions_graph:StatsGraph story_reactions_by_emotion_graph:StatsGraph recent_message_interactions:Vector = stats.BroadcastStats; help.promoDataEmpty#98f6ac75 expires:int = help.PromoData; help.promoData#8c39793f flags:# proxy:flags.0?true expires:int peer:Peer chats:Vector users:Vector psa_type:flags.1?string psa_message:flags.2?string = help.PromoData; @@ -1264,14 +1267,14 @@ messages.messageViews#b6c4f543 views:Vector chats:Vector use messages.discussionMessage#a6341782 flags:# messages:Vector max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector users:Vector = messages.DiscussionMessage; -messageReplyHeader#6eebcabd flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector = MessageReplyHeader; +messageReplyHeader#afbc09db flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector quote_offset:flags.10?int = MessageReplyHeader; messageReplyStoryHeader#9c98bfc1 user_id:long story_id:int = MessageReplyHeader; messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies; peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; -stats.messageStats#8999f295 views_graph:StatsGraph = stats.MessageStats; +stats.messageStats#7fe91c14 views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.MessageStats; groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; groupCall#d597650c flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int = GroupCall; @@ -1334,7 +1337,7 @@ account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordR account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult; account.resetPasswordOk#e926d63e = account.ResetPasswordResult; -sponsoredMessage#daafff6b flags:# recommended:flags.5?true show_peer_photo:flags.6?true random_id:bytes from_id:flags.3?Peer chat_invite:flags.4?ChatInvite chat_invite_hash:flags.4?string channel_post:flags.2?int start_param:flags.0?string webpage:flags.9?SponsoredWebPage message:string entities:flags.1?Vector sponsor_info:flags.7?string additional_info:flags.8?string = SponsoredMessage; +sponsoredMessage#ed5383f7 flags:# recommended:flags.5?true show_peer_photo:flags.6?true random_id:bytes from_id:flags.3?Peer chat_invite:flags.4?ChatInvite chat_invite_hash:flags.4?string channel_post:flags.2?int start_param:flags.0?string webpage:flags.9?SponsoredWebPage app:flags.10?BotApp message:string entities:flags.1?Vector button_text:flags.11?string sponsor_info:flags.7?string additional_info:flags.8?string = SponsoredMessage; messages.sponsoredMessages#c9ee1d87 flags:# posts_between:flags.0?int messages:Vector chats:Vector users:Vector = messages.SponsoredMessages; messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages; @@ -1544,7 +1547,7 @@ storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_co storyItemDeleted#51e6ee4f id:int = StoryItem; storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true id:int date:int expire_date:int = StoryItem; -storyItem#44c457ce flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int expire_date:int caption:flags.0?string entities:flags.1?Vector media:MessageMedia media_areas:flags.14?Vector privacy:flags.2?Vector views:flags.3?StoryViews sent_reaction:flags.15?Reaction = StoryItem; +storyItem#af6365a1 flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector media:MessageMedia media_areas:flags.14?Vector privacy:flags.2?Vector views:flags.3?StoryViews sent_reaction:flags.15?Reaction = StoryItem; stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories; stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector chats:Vector users:Vector stealth_mode:StoriesStealthMode = stories.AllStories; @@ -1557,7 +1560,7 @@ stories.storyViewsList#46e9b9ec flags:# count:int reactions_count:int views:Vect stories.storyViews#de9eed1d views:Vector users:Vector = stories.StoryViews; -inputReplyToMessage#73ec805 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector = InputReplyTo; +inputReplyToMessage#22c0f6d5 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector quote_offset:flags.4?int = InputReplyTo; inputReplyToStory#15b0f283 user_id:InputUser story_id:int = InputReplyTo; exportedStoryLink#3fc9053b link:string = ExportedStoryLink; @@ -1596,6 +1599,10 @@ premium.myBoosts#9ae228e2 my_boosts:Vector chats:Vector users:Vec premium.boostsStatus#4959427a flags:# my_boost:flags.2?true level:int current_level_boosts:int boosts:int gift_boosts:flags.4?int next_level_boosts:flags.0?int premium_audience:flags.1?StatsPercentValue boost_url:string prepaid_giveaways:flags.3?Vector my_boost_slots:flags.2?Vector = premium.BoostsStatus; +storyFwdHeader#b826e150 flags:# from:flags.0?Peer from_name:flags.1?string story_id:flags.2?int = StoryFwdHeader; + +stats.storyStats#50cd067c views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.StoryStats; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -1936,7 +1943,8 @@ messages.searchCustomEmoji#2c11c0d7 emoticon:string hash:long = EmojiList; messages.togglePeerTranslations#e47cb579 flags:# disabled:flags.0?true peer:InputPeer = Bool; messages.getBotApp#34fdc5c3 app:InputBotApp hash:long = messages.BotApp; messages.requestAppWebView#8c5a3b3c flags:# write_allowed:flags.0?true peer:InputPeer app:InputBotApp start_param:flags.1?string theme_params:flags.2?DataJSON platform:string = AppWebViewResult; -messages.setChatWallPaper#8ffacae1 flags:# peer:InputPeer wallpaper:flags.0?InputWallPaper settings:flags.2?WallPaperSettings id:flags.1?int = Updates; +messages.setChatWallPaper#8ffacae1 flags:# for_both:flags.3?true revert:flags.4?true peer:InputPeer wallpaper:flags.0?InputWallPaper settings:flags.2?WallPaperSettings id:flags.1?int = Updates; +messages.searchEmojiStickerSets#92b4494c flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; updates.getState#edd4882a = updates.State; updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; @@ -2038,6 +2046,8 @@ channels.reportAntiSpamFalsePositive#a850a693 channel:InputChannel msg_id:int = channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates; channels.clickSponsoredMessage#18afbc93 channel:InputChannel random_id:bytes = Bool; channels.updateColor#621a201f flags:# channel:InputChannel color:int background_emoji_id:flags.0?long = Updates; +channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates; +channels.getChannelRecommendations#83b70d97 channel:InputChannel = messages.Chats; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; @@ -2129,6 +2139,7 @@ stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph; stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats; stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats; +stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats; chatlists.exportChatlistInvite#8472478e chatlist:InputChatlist title:string peers:Vector = chatlists.ExportedChatlistInvite; chatlists.deleteExportedInvite#719c5c5e chatlist:InputChatlist slug:string = Bool; @@ -2143,7 +2154,7 @@ chatlists.getLeaveChatlistSuggestions#fdbcd714 chatlist:InputChatlist = Vector

= Updates; stories.canSendStory#c7dfdfdd peer:InputPeer = Bool; -stories.sendStory#bcb73644 flags:# pinned:flags.2?true noforwards:flags.4?true peer:InputPeer media:InputMedia media_areas:flags.5?Vector caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long period:flags.3?int = Updates; +stories.sendStory#e4e6694b flags:# pinned:flags.2?true noforwards:flags.4?true peer:InputPeer media:InputMedia media_areas:flags.5?Vector caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long period:flags.3?int fwd_from_id:flags.6?InputPeer fwd_from_story:flags.6?int = Updates; stories.editStory#b583ba46 flags:# peer:InputPeer id:int media:flags.0?InputMedia media_areas:flags.3?Vector caption:flags.1?string entities:flags.1?Vector privacy_rules:flags.2?Vector = Updates; stories.deleteStories#ae59db5f peer:InputPeer id:Vector = Vector; stories.togglePinned#9a75a1ef peer:InputPeer id:Vector pinned:Bool = Vector; @@ -2170,3 +2181,4 @@ premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset: premium.getMyBoosts#be77b4a = premium.MyBoosts; premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector peer:InputPeer = premium.MyBoosts; premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus; +premium.getUserBoosts#39854d1f peer:InputPeer user_id:InputUser = premium.BoostsList; diff --git a/Telegram/SourceFiles/mtproto/scheme/layer.tl b/Telegram/SourceFiles/mtproto/scheme/layer.tl index ede506364..668ec5b5a 100644 --- a/Telegram/SourceFiles/mtproto/scheme/layer.tl +++ b/Telegram/SourceFiles/mtproto/scheme/layer.tl @@ -1 +1 @@ -// LAYER 166 +// LAYER 167 diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index fc24d544f..b36291d4d 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -806,7 +806,8 @@ void SessionNavigation::showRepliesForMessage( history, rootId, commentId, - params.highlightPart); + params.highlightPart, + params.highlightPartOffsetHint); memento->setFromTopic(topic); showSection(std::move(memento), params); return; diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 0a5fa2225..3a8eddbbe 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -168,6 +168,7 @@ struct SectionShow { } TextWithEntities highlightPart; + int highlightPartOffsetHint = 0; Way way = Way::Forward; anim::type animated = anim::type::normal; anim::activation activation = anim::activation::normal;