Show suggested service info.

This commit is contained in:
John Preston 2025-06-19 23:19:22 +04:00
parent bf9492e083
commit ebce4d0f31
9 changed files with 209 additions and 64 deletions

View file

@ -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}.";

View file

@ -602,7 +602,8 @@ void MonoforumSenderBar::Paint(
void ServicePreMessage::init(
PreparedServiceText string,
ClickHandlerPtr fullClickHandler) {
ClickHandlerPtr fullClickHandler,
std::unique_ptr<Media> 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,6 +623,15 @@ int ServicePreMessage::resizeToWidth(int newWidth, ElementChatMode mode) {
width,
st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left());
}
if (media) {
media->initDimensions();
media->resizeGetHeight(width);
}
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) {
@ -642,6 +653,8 @@ int ServicePreMessage::resizeToWidth(int newWidth, ElementChatMode mode) {
+ st::msgServicePadding.bottom()
+ st::msgServiceMargin.top()
+ st::msgServiceMargin.bottom();
}
return height;
}
@ -650,6 +663,14 @@ void ServicePreMessage::paint(
const PaintContext &context,
QRect g,
ElementChatMode mode) const {
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);
@ -680,11 +701,15 @@ void ServicePreMessage::paint(
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> media) {
if (!text.text.empty() || media) {
AddComponents(ServicePreMessage::Bit());
const auto service = Get<ServicePreMessage>();
service->init(std::move(text), std::move(fullClickHandler));
service->init(
std::move(text),
std::move(fullClickHandler),
std::move(media));
setPendingResize();
} else if (Has<ServicePreMessage>()) {
RemoveComponents(ServicePreMessage::Bit());

View file

@ -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<ServicePreMessage, Element> {
void init(PreparedServiceText string, ClickHandlerPtr fullClickHandler);
void init(
PreparedServiceText string,
ClickHandlerPtr fullClickHandler,
std::unique_ptr<Media> media = nullptr);
int resizeToWidth(int newWidth, ElementChatMode mode);
@ -323,6 +326,7 @@ struct ServicePreMessage : RuntimeComponent<ServicePreMessage, Element> {
const StateRequest &request,
QRect g) const;
std::unique_ptr<Media> 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> media = nullptr);
bool computeIsAttachToPrevious(not_null<Element*> previous);

View file

@ -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<HistoryMessageSuggestedPost>()) {
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<MediaGeneric>(
this,
GenerateSuggestRequestMedia(this, suggest),
MediaGenericDescriptor{
.maxWidth = st::chatSuggestWidth,
.service = true,
.hideServiceText = true,
}));
}
return;

View file

@ -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> 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<HistoryServiceCustomLink>();
if (link) {
result.link = link->link;
return result;
}
}
for (const auto &entry : _entries) {
const auto raw = entry.object.get();
const auto height = raw->height();

View file

@ -59,6 +59,7 @@ struct MediaGenericDescriptor {
not_null<const MediaGeneric*>)> paintBg;
ClickHandlerPtr serviceLink;
bool service = false;
bool fullAreaLink = false;
bool hideServiceText = false;
};
@ -130,6 +131,7 @@ private:
not_null<const MediaGeneric*>)> _paintBg;
int _maxWidthCap = 0;
bool _service : 1 = false;
bool _fullAreaLink : 1 = false;
bool _hideServiceText : 1 = false;
};

View file

@ -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<TextPartColored>(
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<Element*> parent,
not_null<const HistoryMessageSuggestedPost*> suggest)
-> Fn<void(
not_null<MediaGeneric*>,
Fn<void(std::unique_ptr<MediaGenericPart>)>)> {
return [=](
not_null<MediaGeneric*> media,
Fn<void(std::unique_ptr<MediaGenericPart>)> 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<uint16, ClickHandlerPtr> &links = {}) {
push(std::make_unique<MediaGenericTextPart>(
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<AttributeTable::Entry>();
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<AttributeTable>(
std::move(entries),
st::chatSuggestInfoLastMargin,
fadedFg,
normalFg));
};
}
} // namespace HistoryView

View file

@ -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<MediaGeneric*>,
Fn<void(std::unique_ptr<MediaGenericPart>)>)>;
auto GenerateSuggestRequestMedia(
not_null<Element*> parent,
not_null<const HistoryMessageSuggestedPost*> suggest
) -> Fn<void(
not_null<MediaGeneric*>,
Fn<void(std::unique_ptr<MediaGenericPart>)>)>;
} // namespace HistoryView

View file

@ -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);