diff --git a/Telegram/SourceFiles/history/view/history_view_about_view.cpp b/Telegram/SourceFiles/history/view/history_view_about_view.cpp index c4028d362a..4a0229b25e 100644 --- a/Telegram/SourceFiles/history/view/history_view_about_view.cpp +++ b/Telegram/SourceFiles/history/view/history_view_about_view.cpp @@ -619,6 +619,8 @@ void AboutView::make(Data::ChatIntro data, bool preview) { const auto sendIntroSticker = [=](not_null sticker) { _sendIntroSticker.fire_copy(sticker); }; + owned->data()->setCustomServiceLink( + std::make_shared(handler)); owned->overrideMedia(std::make_unique( owned.get(), GenerateChatIntro( @@ -629,7 +631,6 @@ void AboutView::make(Data::ChatIntro data, bool preview) { sendIntroSticker), HistoryView::MediaGenericDescriptor{ .maxWidth = st::chatIntroWidth, - .serviceLink = std::make_shared(handler), .service = true, .hideServiceText = preview || text.isEmpty(), })); diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 293a4064b9..0b09c36dca 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -1107,9 +1107,8 @@ void Element::refreshMedia(Element *replacing) { GenerateSuggestDecisionMedia(this, decision), MediaGenericDescriptor{ .maxWidth = st::chatSuggestInfoWidth, - .serviceLink = decision->lnk, + .fullAreaLink = decision->lnk, .service = true, - .fullAreaLink = true, .hideServiceText = true, }); } else { diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 823d56dddb..a6f901bf9e 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -421,7 +421,9 @@ Message::Message( , _bottomInfo( &data->history()->owner().reactions(), BottomInfoDataFromMessage(this)) { - if (const auto media = data->media()) { + if (data->Get()) { + _hideReply = 1; + } else if (const auto media = data->media()) { if (media->giveawayResults()) { _hideReply = 1; } @@ -455,21 +457,33 @@ Message::~Message() { } } +void Message::refreshSuggestedInfo( + not_null item, + not_null suggest, + const HistoryMessageReply *replyData) { + const auto link = (replyData && replyData->resolvedMessage) + ? JumpToMessageClickHandler( + replyData->resolvedMessage.get(), + item->fullId()) + : ClickHandlerPtr(); + setServicePreMessage({}, link, std::make_unique( + this, + GenerateSuggestRequestMedia(this, suggest), + MediaGenericDescriptor{ + .maxWidth = st::chatSuggestWidth, + .fullAreaLink = link, + .service = true, + .hideServiceText = true, + })); +} + void Message::initPaidInformation() { const auto item = data(); - if (!item->history()->peer->isUser()) { - + if (item->history()->peer->isMonoforum()) { if (const auto suggest = item->Get()) { - setServicePreMessage({}, {}, std::make_unique( - this, - GenerateSuggestRequestMedia(this, suggest), - MediaGenericDescriptor{ - .maxWidth = st::chatSuggestWidth, - .service = true, - .hideServiceText = true, - })); + const auto replyData = item->Get(); + refreshSuggestedInfo(item, suggest, replyData); } - return; } const auto media = this->media(); @@ -828,6 +842,22 @@ QSize Message::performCountOptimalSize() { RemoveComponents(Reply::Bit()); } + if (item->history()->peer->isMonoforum()) { + if (const auto suggest = item->Get()) { + if (const auto service = Get()) { + // Ok, we didn't have the message, but now we have. + // That means this is not a plain post suggestion, + // but a suggestion of changes to previous suggestion. + if (service->media + && !service->handler + && replyData + && replyData->resolvedMessage) { + refreshSuggestedInfo(item, suggest, replyData); + } + } + } + } + const auto factcheck = item->Get(); if (factcheck && !factcheck->data.text.empty()) { AddComponents(Factcheck::Bit()); diff --git a/Telegram/SourceFiles/history/view/history_view_message.h b/Telegram/SourceFiles/history/view/history_view_message.h index efade0c7fa..e19d950e1e 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.h +++ b/Telegram/SourceFiles/history/view/history_view_message.h @@ -15,6 +15,8 @@ class HistoryItem; struct HistoryMessageEdited; struct HistoryMessageForwarded; struct HistoryMessageReplyMarkup; +struct HistoryMessageSuggestedPost; +struct HistoryMessageReply; namespace Data { struct ReactionId; @@ -175,6 +177,10 @@ private: bool updateBottomInfo(); void initPaidInformation(); + void refreshSuggestedInfo( + not_null item, + not_null suggest, + const HistoryMessageReply *reply); void initLogEntryOriginal(); void initPsa(); void fromNameUpdated(int width) const; diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp index cacaf4f59c..1e2bc404d5 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp @@ -77,19 +77,15 @@ MediaGeneric::MediaGeneric( MediaGenericDescriptor &&descriptor) : Media(parent) , _paintBg(std::move(descriptor.paintBg)) +, _fullAreaLink(descriptor.fullAreaLink) , _maxWidthCap(descriptor.maxWidth) , _service(descriptor.service) -, _fullAreaLink(descriptor.fullAreaLink) , _hideServiceText(descriptor.hideServiceText) { generate(this, [&](std::unique_ptr part) { _entries.push_back({ .object = std::move(part), }); }); - if (descriptor.serviceLink) { - parent->data()->setCustomServiceLink( - std::move(descriptor.serviceLink)); - } } MediaGeneric::~MediaGeneric() { @@ -164,11 +160,8 @@ TextState MediaGeneric::textState( } if (_fullAreaLink && QRect(0, 0, width(), height()).contains(point)) { - const auto link = _parent->data()->Get(); - if (link) { - result.link = link->link; - return result; - } + result.link = _fullAreaLink; + return result; } for (const auto &entry : _entries) { diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_generic.h b/Telegram/SourceFiles/history/view/media/history_view_media_generic.h index 766d1b18c9..e7b3b6b186 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_generic.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media_generic.h @@ -57,9 +57,8 @@ struct MediaGenericDescriptor { Painter&, const PaintContext&, not_null)> paintBg; - ClickHandlerPtr serviceLink; + ClickHandlerPtr fullAreaLink; bool service = false; - bool fullAreaLink = false; bool hideServiceText = false; }; @@ -129,9 +128,9 @@ private: Painter&, const PaintContext&, not_null)> _paintBg; + ClickHandlerPtr _fullAreaLink; int _maxWidthCap = 0; bool _service : 1 = false; - bool _fullAreaLink : 1 = false; bool _hideServiceText : 1 = false; }; diff --git a/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.cpp b/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.cpp index b3237a4755..7623f8eab9 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.cpp @@ -57,6 +57,53 @@ enum EmojiType { return QString::fromUtf8(Raw(type)); } +struct Changes { + bool date = false; + bool price = false; + bool message = true; +}; +[[nodiscard]] std::optional ResolveChanges( + not_null changed, + HistoryItem *original) { + const auto wasSuggest = original + ? original->Get() + : nullptr; + const auto nowSuggest = changed->Get(); + if (!wasSuggest || !nowSuggest) { + return {}; + } + auto result = Changes(); + if (wasSuggest->date != nowSuggest->date) { + result.date = true; + } + if (wasSuggest->stars != nowSuggest->stars) { + result.price = true; + } + const auto wasText = original->originalText(); + const auto nowText = changed->originalText(); + const auto mediaSame = [&] { + const auto wasMedia = original->media(); + const auto nowMedia = changed->media(); + if (!wasMedia && !nowMedia) { + return true; + } else if (!wasMedia + || !nowMedia + || !wasMedia->allowsEditCaption() + || !nowMedia->allowsEditCaption()) { + return false; + } + // We treat as "same" only same photo or same file. + return (wasMedia->photo() == nowMedia->photo()) + && (wasMedia->document() == nowMedia->document()); + }; + if (!result.price && !result.date) { + result.message = true; + } else if (wasText == nowText && mediaSame()) { + result.message = false; + } + return result; +} + } // namespace auto GenerateSuggestDecisionMedia( @@ -224,8 +271,14 @@ auto GenerateSuggestRequestMedia( result.setAlphaF(result.alphaF() * kFadedOpacity); return result; }; - const auto from = parent->data()->from(); - const auto peer = parent->history()->peer; + const auto item = parent->data(); + const auto replyData = item->Get(); + const auto original = replyData + ? replyData->resolvedMessage.get() + : nullptr; + const auto changes = ResolveChanges(item, original); + const auto from = item->from(); + const auto peer = item->history()->peer; auto pushText = [&]( TextWithEntities text, @@ -242,39 +295,67 @@ auto GenerateSuggestRequestMedia( }; pushText( - (from->isSelf() + ((!changes && from->isSelf()) ? tr::lng_suggest_action_your( tr::now, Ui::Text::WithEntities) - : tr::lng_suggest_action_his( - tr::now, - lt_from, - Ui::Text::Bold(from->shortName()), - Ui::Text::WithEntities)), + : (!changes + ? tr::lng_suggest_action_his + : changes->message + ? tr::lng_suggest_change_content + : (changes->date && changes->price) + ? tr::lng_suggest_change_price_time + : changes->price + ? tr::lng_suggest_change_price + : tr::lng_suggest_change_time)( + tr::now, + lt_from, + Ui::Text::Bold(from->shortName()), + Ui::Text::WithEntities)), st::chatSuggestInfoTitleMargin, style::al_top); auto entries = std::vector(); - entries.push_back({ - tr::lng_suggest_action_price_label(tr::now), - Ui::Text::Bold(suggest->stars - ? tr::lng_prize_credits_amount( + if (!changes || changes->price) { + entries.push_back({ + (changes + ? tr::lng_suggest_change_price_label + : tr::lng_suggest_action_price_label)(tr::now), + Ui::Text::Bold(suggest->stars + ? tr::lng_prize_credits_amount( + tr::now, + lt_count, + suggest->stars) + : tr::lng_suggest_action_price_free(tr::now)), + }); + } + if (!changes || changes->date) { + entries.push_back({ + (changes + ? tr::lng_suggest_change_time_label + : tr::lng_suggest_action_time_label)(tr::now), + Ui::Text::Bold(suggest->date + ? Ui::FormatDateTime(base::unixtime::parse(suggest->date)) + : tr::lng_suggest_action_time_any(tr::now)), + }); + } + if (!entries.empty()) { + push(std::make_unique( + std::move(entries), + ((changes && changes->message) + ? st::chatSuggestTableMiddleMargin + : st::chatSuggestTableLastMargin), + fadedFg, + normalFg)); + } + if (changes && changes->message) { + push(std::make_unique( + tr::lng_suggest_change_text_label( tr::now, - lt_count, - suggest->stars) - : tr::lng_suggest_action_price_free(tr::now)), - }); - entries.push_back({ - tr::lng_suggest_action_time_label(tr::now), - Ui::Text::Bold(suggest->date - ? Ui::FormatDateTime(base::unixtime::parse(suggest->date)) - : tr::lng_suggest_action_time_any(tr::now)), - }); - push(std::make_unique( - std::move(entries), - st::chatSuggestInfoLastMargin, - fadedFg, - normalFg)); + Ui::Text::WithEntities), + st::chatSuggestInfoLastMargin, + fadedFg)); + } }; } diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index 34bb08479d..65d11c42c0 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -1052,11 +1052,13 @@ chatSimilarName: TextStyle(defaultTextStyle) { chatSimilarWidthMax: 424px; chatSimilarSkip: 12px; -chatSuggestWidth: 216px; +chatSuggestWidth: 236px; chatSuggestInfoWidth: 272px; chatSuggestInfoTitleMargin: margins(16px, 16px, 16px, 6px); chatSuggestInfoMiddleMargin: margins(16px, 4px, 16px, 4px); chatSuggestInfoLastMargin: margins(16px, 4px, 16px, 16px); +chatSuggestTableMiddleMargin: margins(8px, 4px, 8px, 4px); +chatSuggestTableLastMargin: margins(8px, 4px, 8px, 16px); chatSuggestInfoFullMargin: margins(16px, 16px, 16px, 16px); premiumRequiredWidth: 186px;