Show correctly change suggestions.

This commit is contained in:
John Preston 2025-06-20 14:31:31 +04:00
parent e29dcf7489
commit 498116c3f6
8 changed files with 167 additions and 56 deletions

View file

@ -619,6 +619,8 @@ void AboutView::make(Data::ChatIntro data, bool preview) {
const auto sendIntroSticker = [=](not_null<DocumentData*> sticker) { const auto sendIntroSticker = [=](not_null<DocumentData*> sticker) {
_sendIntroSticker.fire_copy(sticker); _sendIntroSticker.fire_copy(sticker);
}; };
owned->data()->setCustomServiceLink(
std::make_shared<LambdaClickHandler>(handler));
owned->overrideMedia(std::make_unique<HistoryView::MediaGeneric>( owned->overrideMedia(std::make_unique<HistoryView::MediaGeneric>(
owned.get(), owned.get(),
GenerateChatIntro( GenerateChatIntro(
@ -629,7 +631,6 @@ void AboutView::make(Data::ChatIntro data, bool preview) {
sendIntroSticker), sendIntroSticker),
HistoryView::MediaGenericDescriptor{ HistoryView::MediaGenericDescriptor{
.maxWidth = st::chatIntroWidth, .maxWidth = st::chatIntroWidth,
.serviceLink = std::make_shared<LambdaClickHandler>(handler),
.service = true, .service = true,
.hideServiceText = preview || text.isEmpty(), .hideServiceText = preview || text.isEmpty(),
})); }));

View file

@ -1107,9 +1107,8 @@ void Element::refreshMedia(Element *replacing) {
GenerateSuggestDecisionMedia(this, decision), GenerateSuggestDecisionMedia(this, decision),
MediaGenericDescriptor{ MediaGenericDescriptor{
.maxWidth = st::chatSuggestInfoWidth, .maxWidth = st::chatSuggestInfoWidth,
.serviceLink = decision->lnk, .fullAreaLink = decision->lnk,
.service = true, .service = true,
.fullAreaLink = true,
.hideServiceText = true, .hideServiceText = true,
}); });
} else { } else {

View file

@ -421,7 +421,9 @@ Message::Message(
, _bottomInfo( , _bottomInfo(
&data->history()->owner().reactions(), &data->history()->owner().reactions(),
BottomInfoDataFromMessage(this)) { BottomInfoDataFromMessage(this)) {
if (const auto media = data->media()) { if (data->Get<HistoryMessageSuggestedPost>()) {
_hideReply = 1;
} else if (const auto media = data->media()) {
if (media->giveawayResults()) { if (media->giveawayResults()) {
_hideReply = 1; _hideReply = 1;
} }
@ -455,21 +457,33 @@ Message::~Message() {
} }
} }
void Message::refreshSuggestedInfo(
not_null<HistoryItem*> item,
not_null<const HistoryMessageSuggestedPost*> suggest,
const HistoryMessageReply *replyData) {
const auto link = (replyData && replyData->resolvedMessage)
? JumpToMessageClickHandler(
replyData->resolvedMessage.get(),
item->fullId())
: ClickHandlerPtr();
setServicePreMessage({}, link, std::make_unique<MediaGeneric>(
this,
GenerateSuggestRequestMedia(this, suggest),
MediaGenericDescriptor{
.maxWidth = st::chatSuggestWidth,
.fullAreaLink = link,
.service = true,
.hideServiceText = true,
}));
}
void Message::initPaidInformation() { void Message::initPaidInformation() {
const auto item = data(); const auto item = data();
if (!item->history()->peer->isUser()) { if (item->history()->peer->isMonoforum()) {
if (const auto suggest = item->Get<HistoryMessageSuggestedPost>()) { if (const auto suggest = item->Get<HistoryMessageSuggestedPost>()) {
setServicePreMessage({}, {}, std::make_unique<MediaGeneric>( const auto replyData = item->Get<HistoryMessageReply>();
this, refreshSuggestedInfo(item, suggest, replyData);
GenerateSuggestRequestMedia(this, suggest),
MediaGenericDescriptor{
.maxWidth = st::chatSuggestWidth,
.service = true,
.hideServiceText = true,
}));
} }
return; return;
} }
const auto media = this->media(); const auto media = this->media();
@ -828,6 +842,22 @@ QSize Message::performCountOptimalSize() {
RemoveComponents(Reply::Bit()); RemoveComponents(Reply::Bit());
} }
if (item->history()->peer->isMonoforum()) {
if (const auto suggest = item->Get<HistoryMessageSuggestedPost>()) {
if (const auto service = Get<ServicePreMessage>()) {
// 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<HistoryMessageFactcheck>(); const auto factcheck = item->Get<HistoryMessageFactcheck>();
if (factcheck && !factcheck->data.text.empty()) { if (factcheck && !factcheck->data.text.empty()) {
AddComponents(Factcheck::Bit()); AddComponents(Factcheck::Bit());

View file

@ -15,6 +15,8 @@ class HistoryItem;
struct HistoryMessageEdited; struct HistoryMessageEdited;
struct HistoryMessageForwarded; struct HistoryMessageForwarded;
struct HistoryMessageReplyMarkup; struct HistoryMessageReplyMarkup;
struct HistoryMessageSuggestedPost;
struct HistoryMessageReply;
namespace Data { namespace Data {
struct ReactionId; struct ReactionId;
@ -175,6 +177,10 @@ private:
bool updateBottomInfo(); bool updateBottomInfo();
void initPaidInformation(); void initPaidInformation();
void refreshSuggestedInfo(
not_null<HistoryItem*> item,
not_null<const HistoryMessageSuggestedPost*> suggest,
const HistoryMessageReply *reply);
void initLogEntryOriginal(); void initLogEntryOriginal();
void initPsa(); void initPsa();
void fromNameUpdated(int width) const; void fromNameUpdated(int width) const;

View file

@ -77,19 +77,15 @@ MediaGeneric::MediaGeneric(
MediaGenericDescriptor &&descriptor) MediaGenericDescriptor &&descriptor)
: Media(parent) : Media(parent)
, _paintBg(std::move(descriptor.paintBg)) , _paintBg(std::move(descriptor.paintBg))
, _fullAreaLink(descriptor.fullAreaLink)
, _maxWidthCap(descriptor.maxWidth) , _maxWidthCap(descriptor.maxWidth)
, _service(descriptor.service) , _service(descriptor.service)
, _fullAreaLink(descriptor.fullAreaLink)
, _hideServiceText(descriptor.hideServiceText) { , _hideServiceText(descriptor.hideServiceText) {
generate(this, [&](std::unique_ptr<Part> part) { generate(this, [&](std::unique_ptr<Part> part) {
_entries.push_back({ _entries.push_back({
.object = std::move(part), .object = std::move(part),
}); });
}); });
if (descriptor.serviceLink) {
parent->data()->setCustomServiceLink(
std::move(descriptor.serviceLink));
}
} }
MediaGeneric::~MediaGeneric() { MediaGeneric::~MediaGeneric() {
@ -164,11 +160,8 @@ TextState MediaGeneric::textState(
} }
if (_fullAreaLink && QRect(0, 0, width(), height()).contains(point)) { if (_fullAreaLink && QRect(0, 0, width(), height()).contains(point)) {
const auto link = _parent->data()->Get<HistoryServiceCustomLink>(); result.link = _fullAreaLink;
if (link) { return result;
result.link = link->link;
return result;
}
} }
for (const auto &entry : _entries) { for (const auto &entry : _entries) {

View file

@ -57,9 +57,8 @@ struct MediaGenericDescriptor {
Painter&, Painter&,
const PaintContext&, const PaintContext&,
not_null<const MediaGeneric*>)> paintBg; not_null<const MediaGeneric*>)> paintBg;
ClickHandlerPtr serviceLink; ClickHandlerPtr fullAreaLink;
bool service = false; bool service = false;
bool fullAreaLink = false;
bool hideServiceText = false; bool hideServiceText = false;
}; };
@ -129,9 +128,9 @@ private:
Painter&, Painter&,
const PaintContext&, const PaintContext&,
not_null<const MediaGeneric*>)> _paintBg; not_null<const MediaGeneric*>)> _paintBg;
ClickHandlerPtr _fullAreaLink;
int _maxWidthCap = 0; int _maxWidthCap = 0;
bool _service : 1 = false; bool _service : 1 = false;
bool _fullAreaLink : 1 = false;
bool _hideServiceText : 1 = false; bool _hideServiceText : 1 = false;
}; };

View file

@ -57,6 +57,53 @@ enum EmojiType {
return QString::fromUtf8(Raw(type)); return QString::fromUtf8(Raw(type));
} }
struct Changes {
bool date = false;
bool price = false;
bool message = true;
};
[[nodiscard]] std::optional<Changes> ResolveChanges(
not_null<HistoryItem*> changed,
HistoryItem *original) {
const auto wasSuggest = original
? original->Get<HistoryMessageSuggestedPost>()
: nullptr;
const auto nowSuggest = changed->Get<HistoryMessageSuggestedPost>();
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 } // namespace
auto GenerateSuggestDecisionMedia( auto GenerateSuggestDecisionMedia(
@ -224,8 +271,14 @@ auto GenerateSuggestRequestMedia(
result.setAlphaF(result.alphaF() * kFadedOpacity); result.setAlphaF(result.alphaF() * kFadedOpacity);
return result; return result;
}; };
const auto from = parent->data()->from(); const auto item = parent->data();
const auto peer = parent->history()->peer; const auto replyData = item->Get<HistoryMessageReply>();
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 = [&]( auto pushText = [&](
TextWithEntities text, TextWithEntities text,
@ -242,39 +295,67 @@ auto GenerateSuggestRequestMedia(
}; };
pushText( pushText(
(from->isSelf() ((!changes && from->isSelf())
? tr::lng_suggest_action_your( ? tr::lng_suggest_action_your(
tr::now, tr::now,
Ui::Text::WithEntities) Ui::Text::WithEntities)
: tr::lng_suggest_action_his( : (!changes
tr::now, ? tr::lng_suggest_action_his
lt_from, : changes->message
Ui::Text::Bold(from->shortName()), ? tr::lng_suggest_change_content
Ui::Text::WithEntities)), : (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, st::chatSuggestInfoTitleMargin,
style::al_top); style::al_top);
auto entries = std::vector<AttributeTable::Entry>(); auto entries = std::vector<AttributeTable::Entry>();
entries.push_back({ if (!changes || changes->price) {
tr::lng_suggest_action_price_label(tr::now), entries.push_back({
Ui::Text::Bold(suggest->stars (changes
? tr::lng_prize_credits_amount( ? 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<AttributeTable>(
std::move(entries),
((changes && changes->message)
? st::chatSuggestTableMiddleMargin
: st::chatSuggestTableLastMargin),
fadedFg,
normalFg));
}
if (changes && changes->message) {
push(std::make_unique<TextPartColored>(
tr::lng_suggest_change_text_label(
tr::now, tr::now,
lt_count, Ui::Text::WithEntities),
suggest->stars) st::chatSuggestInfoLastMargin,
: tr::lng_suggest_action_price_free(tr::now)), fadedFg));
}); }
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));
}; };
} }

View file

@ -1052,11 +1052,13 @@ chatSimilarName: TextStyle(defaultTextStyle) {
chatSimilarWidthMax: 424px; chatSimilarWidthMax: 424px;
chatSimilarSkip: 12px; chatSimilarSkip: 12px;
chatSuggestWidth: 216px; chatSuggestWidth: 236px;
chatSuggestInfoWidth: 272px; chatSuggestInfoWidth: 272px;
chatSuggestInfoTitleMargin: margins(16px, 16px, 16px, 6px); chatSuggestInfoTitleMargin: margins(16px, 16px, 16px, 6px);
chatSuggestInfoMiddleMargin: margins(16px, 4px, 16px, 4px); chatSuggestInfoMiddleMargin: margins(16px, 4px, 16px, 4px);
chatSuggestInfoLastMargin: margins(16px, 4px, 16px, 16px); chatSuggestInfoLastMargin: margins(16px, 4px, 16px, 16px);
chatSuggestTableMiddleMargin: margins(8px, 4px, 8px, 4px);
chatSuggestTableLastMargin: margins(8px, 4px, 8px, 16px);
chatSuggestInfoFullMargin: margins(16px, 16px, 16px, 16px); chatSuggestInfoFullMargin: margins(16px, 16px, 16px, 16px);
premiumRequiredWidth: 186px; premiumRequiredWidth: 186px;