diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index d36e7f77ed..da2e1a761f 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -4436,7 +4436,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_suggest_action_your" = "You suggest to post this message."; "lng_suggest_action_his" = "{from} suggests to post this message."; "lng_suggest_action_price_label" = "Price"; +"lng_suggest_action_price_free" = "Free"; "lng_suggest_action_time_label" = "Time"; +"lng_suggest_action_time_any" = "Anytime"; "lng_suggest_action_agreement" = "Agreement reached!"; "lng_suggest_action_agree_date" = "The post will be automatically published on {channel} {date}."; "lng_suggest_action_your_charged" = "You have been charged {amount}."; diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 251eb7d823..89949f8636 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -602,7 +602,8 @@ void MonoforumSenderBar::Paint( void ServicePreMessage::init( PreparedServiceText string, - ClickHandlerPtr fullClickHandler) { + ClickHandlerPtr fullClickHandler, + std::unique_ptr media) { text = Ui::Text::String( st::serviceTextStyle, string.text, @@ -612,6 +613,7 @@ void ServicePreMessage::init( for (auto i = 0; i != int(string.links.size()); ++i) { text.setLink(i + 1, string.links[i]); } + this->media = std::move(media); } int ServicePreMessage::resizeToWidth(int newWidth, ElementChatMode mode) { @@ -621,27 +623,38 @@ int ServicePreMessage::resizeToWidth(int newWidth, ElementChatMode mode) { width, st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()); } - auto contentWidth = width; - contentWidth -= st::msgServiceMargin.left() + st::msgServiceMargin.right(); - if (contentWidth < st::msgServicePadding.left() + st::msgServicePadding.right() + 1) { - contentWidth = st::msgServicePadding.left() + st::msgServicePadding.right() + 1; + + if (media) { + media->initDimensions(); + media->resizeGetHeight(width); } - auto maxWidth = text.maxWidth() - + st::msgServicePadding.left() - + st::msgServicePadding.right(); - auto minHeight = text.minHeight(); + if (media && media->hideServiceText()) { + height = media->height() + st::msgServiceMargin.bottom(); + } else { + auto contentWidth = width; + contentWidth -= st::msgServiceMargin.left() + st::msgServiceMargin.right(); + if (contentWidth < st::msgServicePadding.left() + st::msgServicePadding.right() + 1) { + contentWidth = st::msgServicePadding.left() + st::msgServicePadding.right() + 1; + } + + auto maxWidth = text.maxWidth() + + st::msgServicePadding.left() + + st::msgServicePadding.right(); + auto minHeight = text.minHeight(); + + auto nwidth = qMax(contentWidth + - st::msgServicePadding.left() + - st::msgServicePadding.right(), 0); + height = (contentWidth >= maxWidth) + ? minHeight + : text.countHeight(nwidth); + height += st::msgServicePadding.top() + + st::msgServicePadding.bottom() + + st::msgServiceMargin.top() + + st::msgServiceMargin.bottom(); + } - auto nwidth = qMax(contentWidth - - st::msgServicePadding.left() - - st::msgServicePadding.right(), 0); - height = (contentWidth >= maxWidth) - ? minHeight - : text.countHeight(nwidth); - height += st::msgServicePadding.top() - + st::msgServicePadding.bottom() - + st::msgServiceMargin.top() - + st::msgServiceMargin.bottom(); return height; } @@ -650,41 +663,53 @@ void ServicePreMessage::paint( const PaintContext &context, QRect g, ElementChatMode mode) const { - const auto top = g.top() - height - st::msgMargin.top(); - p.translate(0, top); + if (media && media->hideServiceText()) { + const auto left = (width - media->width()) / 2; + const auto top = g.top() - height - st::msgMargin.bottom(); + const auto position = QPoint(left, top); + p.translate(position); + media->draw(p, context.translated(-position).withSelection({})); + p.translate(-position); + } else { + const auto top = g.top() - height - st::msgMargin.top(); + p.translate(0, top); - const auto rect = QRect(0, 0, width, height) - - st::msgServiceMargin; - const auto trect = rect - st::msgServicePadding; + const auto rect = QRect(0, 0, width, height) + - st::msgServiceMargin; + const auto trect = rect - st::msgServicePadding; - ServiceMessagePainter::PaintComplexBubble( - p, - context.st, - rect.left(), - rect.width(), - text, - trect); + ServiceMessagePainter::PaintComplexBubble( + p, + context.st, + rect.left(), + rect.width(), + text, + trect); - p.setBrush(Qt::NoBrush); - p.setPen(context.st->msgServiceFg()); - p.setFont(st::msgServiceFont); - text.draw(p, { - .position = trect.topLeft(), - .availableWidth = trect.width(), - .align = style::al_top, - .palette = &context.st->serviceTextPalette(), - .now = context.now, - .fullWidthSelection = false, - //.selection = context.selection, - }); + p.setBrush(Qt::NoBrush); + p.setPen(context.st->msgServiceFg()); + p.setFont(st::msgServiceFont); + text.draw(p, { + .position = trect.topLeft(), + .availableWidth = trect.width(), + .align = style::al_top, + .palette = &context.st->serviceTextPalette(), + .now = context.now, + .fullWidthSelection = false, + //.selection = context.selection, + }); - p.translate(0, -top); + p.translate(0, -top); + } } ClickHandlerPtr ServicePreMessage::textState( QPoint point, const StateRequest &request, QRect g) const { + if (media && media->hideServiceText()) { + return {}; + } const auto top = g.top() - height - st::msgMargin.top(); const auto rect = QRect(0, top, width, height) - st::msgServiceMargin; @@ -1082,6 +1107,7 @@ void Element::refreshMedia(Element *replacing) { .maxWidth = st::chatSuggestInfoWidth, .serviceLink = decision->lnk, .service = true, + .fullAreaLink = true, .hideServiceText = true, }); } else { @@ -1639,11 +1665,15 @@ void Element::setDisplayDate(bool displayDate) { void Element::setServicePreMessage( PreparedServiceText text, - ClickHandlerPtr fullClickHandler) { - if (!text.text.empty()) { + ClickHandlerPtr fullClickHandler, + std::unique_ptr media) { + if (!text.text.empty() || media) { AddComponents(ServicePreMessage::Bit()); const auto service = Get(); - service->init(std::move(text), std::move(fullClickHandler)); + service->init( + std::move(text), + std::move(fullClickHandler), + std::move(media)); setPendingResize(); } else if (Has()) { RemoveComponents(ServicePreMessage::Bit()); diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index a27dcae59d..1bf9a8e1a0 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -309,7 +309,10 @@ private: // Any HistoryView::Element can have this Component for // displaying some text in layout of a service message above the message. struct ServicePreMessage : RuntimeComponent { - void init(PreparedServiceText string, ClickHandlerPtr fullClickHandler); + void init( + PreparedServiceText string, + ClickHandlerPtr fullClickHandler, + std::unique_ptr media = nullptr); int resizeToWidth(int newWidth, ElementChatMode mode); @@ -323,6 +326,7 @@ struct ServicePreMessage : RuntimeComponent { const StateRequest &request, QRect g) const; + std::unique_ptr media; Ui::Text::String text; ClickHandlerPtr handler; int width = 0; @@ -459,7 +463,8 @@ public: void setDisplayDate(bool displayDate); void setServicePreMessage( PreparedServiceText text, - ClickHandlerPtr fullClickHandler = nullptr); + ClickHandlerPtr fullClickHandler = nullptr, + std::unique_ptr media = nullptr); bool computeIsAttachToPrevious(not_null previous); diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 8c097f9472..74d02d17ce 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -14,7 +14,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_cursor_state.h" #include "history/history_item_components.h" #include "history/history_item_helpers.h" +#include "history/view/media/history_view_media_generic.h" #include "history/view/media/history_view_web_page.h" +#include "history/view/media/history_view_suggest_decision.h" #include "history/view/reactions/history_view_reactions.h" #include "history/view/reactions/history_view_reactions_button.h" #include "history/view/history_view_group_call_bar.h" // UserpicInRow. @@ -458,17 +460,14 @@ void Message::initPaidInformation() { if (!item->history()->peer->isUser()) { if (const auto suggest = item->Get()) { - auto text = PreparedServiceText(); - if (!suggest->stars && !suggest->date) { - text = { { u"suggestion to publish for free anytime"_q } }; - } else if (!suggest->date) { - text = { { u"suggestion to publish for %1 stars anytime"_q.arg(suggest->stars) } }; - } else if (!suggest->stars) { - text = { { u"suggestion to publish for free %1"_q.arg(langDateTime(base::unixtime::parse(suggest->date))) } }; - } else { - text = { { u"suggestion to publish for %1 stars %2"_q.arg(suggest->stars).arg(langDateTime(base::unixtime::parse(suggest->date))) } }; - } - setServicePreMessage(std::move(text)); + setServicePreMessage({}, {}, std::make_unique( + this, + GenerateSuggestRequestMedia(this, suggest), + MediaGenericDescriptor{ + .maxWidth = st::chatSuggestWidth, + .service = true, + .hideServiceText = true, + })); } return; 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 7961f5c696..f0991f8f95 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp @@ -79,6 +79,7 @@ MediaGeneric::MediaGeneric( , _paintBg(std::move(descriptor.paintBg)) , _maxWidthCap(descriptor.maxWidth) , _service(descriptor.service) +, _fullAreaLink(descriptor.fullAreaLink) , _hideServiceText(descriptor.hideServiceText) { generate(this, [&](std::unique_ptr part) { _entries.push_back({ @@ -157,6 +158,14 @@ TextState MediaGeneric::textState( return result; } + if (_fullAreaLink && QRect(0, 0, width(), height()).contains(point)) { + const auto link = _parent->data()->Get(); + if (link) { + result.link = link->link; + return result; + } + } + for (const auto &entry : _entries) { const auto raw = entry.object.get(); const auto height = raw->height(); 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 b5133743b3..766d1b18c9 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_generic.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media_generic.h @@ -59,6 +59,7 @@ struct MediaGenericDescriptor { not_null)> paintBg; ClickHandlerPtr serviceLink; bool service = false; + bool fullAreaLink = false; bool hideServiceText = false; }; @@ -130,6 +131,7 @@ private: not_null)> _paintBg; 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 d242eb0a89..b3237a4755 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.cpp @@ -11,11 +11,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_channel.h" #include "data/data_session.h" #include "history/view/media/history_view_media_generic.h" +#include "history/view/media/history_view_unique_gift.h" #include "history/view/history_view_element.h" #include "history/history.h" #include "history/history_item.h" #include "history/history_item_components.h" #include "lang/lang_keys.h" +#include "ui/chat/chat_style.h" #include "ui/text/text_utilities.h" #include "ui/text/format_values.h" #include "styles/style_chat.h" @@ -24,6 +26,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace HistoryView { namespace { +constexpr auto kFadedOpacity = 0.85; + enum EmojiType { kAgreement, kCalendar, @@ -114,12 +118,17 @@ auto GenerateSuggestDecisionMedia( ? st::chatSuggestInfoTitleMargin : st::chatSuggestInfoFullMargin)); if (withComment) { - pushText( + const auto fadedFg = [](const PaintContext &context) { + auto result = context.st->msgServiceFg()->c; + result.setAlphaF(result.alphaF() * kFadedOpacity); + return result; + }; + push(std::make_unique( TextWithEntities().append('"').append( decision->rejectComment ).append('"'), st::chatSuggestInfoLastMargin, - style::al_top); + fadedFg)); } } else { const auto stars = decision->stars; @@ -130,6 +139,7 @@ auto GenerateSuggestDecisionMedia( ), st::chatSuggestInfoTitleMargin, style::al_top); + const auto date = base::unixtime::parse(decision->date); pushText( TextWithEntities( ).append(Emoji(kCalendar)).append(' ').append( @@ -138,8 +148,16 @@ auto GenerateSuggestDecisionMedia( lt_channel, Ui::Text::Bold(broadcast->name()), lt_date, - Ui::Text::Bold(Ui::FormatDateTime( - base::unixtime::parse(decision->date))), + Ui::Text::Bold(tr::lng_mediaview_date_time( + tr::now, + lt_date, + QLocale().toString( + date.date(), + QLocale::ShortFormat), + lt_time, + QLocale().toString( + date.time(), + QLocale::ShortFormat))), Ui::Text::WithEntities)), (stars ? st::chatSuggestInfoMiddleMargin @@ -189,4 +207,75 @@ auto GenerateSuggestDecisionMedia( }; } +auto GenerateSuggestRequestMedia( + not_null parent, + not_null suggest) + -> Fn, + Fn)>)> { + return [=]( + not_null media, + Fn)> push) { + const auto normalFg = [](const PaintContext &context) { + return context.st->msgServiceFg()->c; + }; + const auto fadedFg = [](const PaintContext &context) { + auto result = context.st->msgServiceFg()->c; + result.setAlphaF(result.alphaF() * kFadedOpacity); + return result; + }; + const auto from = parent->data()->from(); + const auto peer = parent->history()->peer; + + auto pushText = [&]( + TextWithEntities text, + QMargins margins = {}, + style::align align = style::al_left, + const base::flat_map &links = {}) { + push(std::make_unique( + std::move(text), + margins, + st::defaultTextStyle, + links, + Ui::Text::MarkedContext(), + align)); + }; + + pushText( + (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)), + 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( + 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)); + }; +} + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.h b/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.h index 6315d50b9f..56fc4f58f1 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.h +++ b/Telegram/SourceFiles/history/view/media/history_view_suggest_decision.h @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +struct HistoryMessageSuggestedPost; struct HistoryServiceSuggestDecision; namespace HistoryView { @@ -22,4 +23,11 @@ auto GenerateSuggestDecisionMedia( not_null, Fn)>)>; +auto GenerateSuggestRequestMedia( + not_null parent, + not_null suggest +) -> Fn, + Fn)>)>; + } // namespace HistoryView diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index 53791b79b2..34bb08479d 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -1052,6 +1052,7 @@ chatSimilarName: TextStyle(defaultTextStyle) { chatSimilarWidthMax: 424px; chatSimilarSkip: 12px; +chatSuggestWidth: 216px; chatSuggestInfoWidth: 272px; chatSuggestInfoTitleMargin: margins(16px, 16px, 16px, 6px); chatSuggestInfoMiddleMargin: margins(16px, 4px, 16px, 4px);