From b185900b4f0bdd92703675f9ff7a060df49bcd48 Mon Sep 17 00:00:00 2001 From: People-11 <41558215+People-11@users.noreply.github.com> Date: Fri, 27 Mar 2026 02:35:01 +1030 Subject: [PATCH] feat: improve message shot Add Show Spoiler Fix photo not showing date in shot Fix show date in media group Hide inapplicable options Co-authored-by: AlexeyZavar --- Telegram/Resources/langs/lang.strings | 1 + Telegram/SourceFiles/ayu/ayu_settings.cpp | 10 +- Telegram/SourceFiles/ayu/ayu_settings.h | 5 +- .../features/message_shot/message_shot.cpp | 3 + .../ayu/ui/boxes/message_shot_box.cpp | 138 ++++++++++++++---- .../history/view/history_view_element.cpp | 9 ++ .../history/view/history_view_element.h | 1 + .../view/media/history_view_document.cpp | 6 + .../view/media/history_view_document.h | 1 + .../history/view/media/history_view_gif.cpp | 6 + .../history/view/media/history_view_gif.h | 1 + .../history/view/media/history_view_media.h | 2 + .../view/media/history_view_media_grouped.cpp | 12 +- .../view/media/history_view_media_grouped.h | 1 + .../history/view/media/history_view_photo.cpp | 10 ++ .../history/view/media/history_view_photo.h | 1 + .../view/media/history_view_service_box.cpp | 4 + .../view/media/history_view_service_box.h | 1 + .../view/media/history_view_todo_list.cpp | 11 ++ .../view/media/history_view_todo_list.h | 1 + 20 files changed, 189 insertions(+), 35 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index fb22814d87..cf00f36349 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -8080,6 +8080,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "ayu_MessageShotShowDate" = "Show date"; "ayu_MessageShotShowReactions" = "Show reactions"; "ayu_MessageShotShowColorfulReplies" = "Show colorful replies"; +"ayu_MessageShotRevealSpoilers" = "Reveal spoilers"; "ayu_SendAsSticker" = "Send as Sticker"; "ayu_SendWithSound" = "Send With Sound"; "ayu_AyuForwardStatusPreparing" = "Forwarding messages"; diff --git a/Telegram/SourceFiles/ayu/ayu_settings.cpp b/Telegram/SourceFiles/ayu/ayu_settings.cpp index 4d5d3f8068..8dbc9e77e4 100644 --- a/Telegram/SourceFiles/ayu/ayu_settings.cpp +++ b/Telegram/SourceFiles/ayu/ayu_settings.cpp @@ -220,6 +220,12 @@ void MessageShotSettings::setShowColorfulReplies(bool val) { AyuSettings::save(); } +void MessageShotSettings::setRevealSpoilers(bool val) { + if (_revealSpoilers.current() == val) return; + _revealSpoilers = val; + AyuSettings::save(); +} + bool MessageShotSettings::isCloudThemeEmpty() const { return !_cloudThemeId.current() && !_cloudThemeAccessHash.current() @@ -285,6 +291,7 @@ void to_json(nlohmann::json &j, const MessageShotSettings &s) { {"showDate", s._showDate.current()}, {"showReactions", s._showReactions.current()}, {"showColorfulReplies", s._showColorfulReplies.current()}, + {"revealSpoilers", s._revealSpoilers.current()}, {"embeddedThemeType", s._embeddedThemeType.current()}, {"embeddedThemeAccentColor", s._embeddedThemeAccentColor.current()}, {"cloudThemeId", s._cloudThemeId.current()}, @@ -299,7 +306,8 @@ void from_json(const nlohmann::json &j, MessageShotSettings &s) { s._showBackground = j.value("showBackground", true); s._showDate = j.value("showDate", false); s._showReactions = j.value("showReactions", false); - s._showColorfulReplies = j.value("showColorfulReplies", false); + s._showColorfulReplies = j.value("showColorfulReplies", true); + s._revealSpoilers = j.value("revealSpoilers", true); s._embeddedThemeType = j.value("embeddedThemeType", j.value("themeType", -1)); s._embeddedThemeAccentColor = j.value("embeddedThemeAccentColor", j.value("themeAccentColor", uint32(0))); s._cloudThemeId = j.value("cloudThemeId", uint64(0)); diff --git a/Telegram/SourceFiles/ayu/ayu_settings.h b/Telegram/SourceFiles/ayu/ayu_settings.h index f1b79b4187..711e8eea94 100644 --- a/Telegram/SourceFiles/ayu/ayu_settings.h +++ b/Telegram/SourceFiles/ayu/ayu_settings.h @@ -167,6 +167,7 @@ public: [[nodiscard]] bool showDate() const { return _showDate.current(); } [[nodiscard]] bool showReactions() const { return _showReactions.current(); } [[nodiscard]] bool showColorfulReplies() const { return _showColorfulReplies.current(); } + [[nodiscard]] bool revealSpoilers() const { return _revealSpoilers.current(); } [[nodiscard]] int embeddedThemeType() const { return _embeddedThemeType.current(); } [[nodiscard]] uint32 embeddedThemeAccentColor() const { return _embeddedThemeAccentColor.current(); } [[nodiscard]] uint64 cloudThemeId() const { return _cloudThemeId.current(); } @@ -179,6 +180,7 @@ public: void setShowDate(bool val); void setShowReactions(bool val); void setShowColorfulReplies(bool val); + void setRevealSpoilers(bool val); void setEmbeddedTheme(int type, uint32 accentColor = 0); void setCloudTheme(uint64 accountId, uint64 id, uint64 accessHash, uint64 documentId, const QString &title); @@ -195,7 +197,8 @@ private: rpl::variable _showBackground = true; rpl::variable _showDate = false; rpl::variable _showReactions = false; - rpl::variable _showColorfulReplies = false; + rpl::variable _showColorfulReplies = true; + rpl::variable _revealSpoilers = true; rpl::variable _embeddedThemeType = -1; rpl::variable _embeddedThemeAccentColor = 0; diff --git a/Telegram/SourceFiles/ayu/features/message_shot/message_shot.cpp b/Telegram/SourceFiles/ayu/features/message_shot/message_shot.cpp index 094c479a82..67a48ad501 100644 --- a/Telegram/SourceFiles/ayu/features/message_shot/message_shot.cpp +++ b/Telegram/SourceFiles/ayu/features/message_shot/message_shot.cpp @@ -315,6 +315,9 @@ void Make(not_null box, const ShotConfig &config, const FnitemDataChanged(); // refresh reactions height += view->resizeGetHeight(width); + if (AyuSettings::getInstance().messageShotSettings().revealSpoilers()) { + view->revealSpoilers(); + } } width *= style::DevicePixelRatio(); diff --git a/Telegram/SourceFiles/ayu/ui/boxes/message_shot_box.cpp b/Telegram/SourceFiles/ayu/ui/boxes/message_shot_box.cpp index 601aab975b..d96f66d724 100644 --- a/Telegram/SourceFiles/ayu/ui/boxes/message_shot_box.cpp +++ b/Telegram/SourceFiles/ayu/ui/boxes/message_shot_box.cpp @@ -12,6 +12,8 @@ #include "ayu/ui/components/image_view.h" #include "ayu/utils/telegram_helpers.h" #include "boxes/abstract_box.h" +#include "data/data_todo_list.h" +#include "history/history_item.h" #include "main/main_session.h" #include "settings/settings_common.h" #include "styles/style_ayu_styles.h" @@ -83,6 +85,55 @@ void MessageShotBox::setupContent() { AddSkip(content); AddSubsectionTitle(content, tr::ayu_MessageShotPreferences()); + auto hasReactions = false; + auto hasReplies = false; + auto hasSpoilers = false; + for (const auto &item : _config.messages) { + if (!hasReactions && !item->reactions().empty()) { + hasReactions = true; + } + if (!hasReplies) { + if (item->replyTo().replying() + || (item->media() && item->media()->webpage())) { + hasReplies = true; + } + } + if (!hasSpoilers) { + for (const auto &entity : item->originalText().entities) { + if (entity.type() == EntityType::Spoiler) { + hasSpoilers = true; + break; + } + } + if (!hasSpoilers && item->media()) { + if (item->media()->hasSpoiler()) { + hasSpoilers = true; + } else if (const auto todoList = item->media()->todolist()) { + for (const auto &entity : todoList->title.entities) { + if (entity.type() == EntityType::Spoiler) { + hasSpoilers = true; + break; + } + } + if (!hasSpoilers) { + for (const auto &task : todoList->items) { + for (const auto &entity : task.text.entities) { + if (entity.type() == EntityType::Spoiler) { + hasSpoilers = true; + break; + } + } + if (hasSpoilers) break; + } + } + } + } + } + if (hasReactions && hasReplies && hasSpoilers) { + break; + } + } + const auto firstPreviewLatch = std::make_shared(1); const auto generation = content->lifetime().make_state(0); const auto weak = base::make_weak(this); @@ -187,11 +238,12 @@ void MessageShotBox::setupContent() { }, content->lifetime()); - AddButtonWithIcon( + auto latestToggle = AddButtonWithIcon( content, tr::ayu_MessageShotShowDate(), st::settingsButtonNoIcon - )->toggleOn(rpl::single(shotSettings.showDate()) + ); + latestToggle->toggleOn(rpl::single(shotSettings.showDate()) )->toggledValue( ) | rpl::skip(1) | on_next( [=](bool enabled) @@ -201,38 +253,60 @@ void MessageShotBox::setupContent() { }, content->lifetime()); - AddButtonWithIcon( - content, - tr::ayu_MessageShotShowReactions(), - st::settingsButtonNoIcon - )->toggleOn(rpl::single(shotSettings.showReactions()) - )->toggledValue( - ) | rpl::skip(1) | on_next( - [=](bool enabled) - { - AyuSettings::getInstance().messageShotSettings().setShowReactions(enabled); - updatePreview(); - }, - content->lifetime()); + if (hasReactions) { + latestToggle = AddButtonWithIcon( + content, + tr::ayu_MessageShotShowReactions(), + st::settingsButtonNoIcon + ); + latestToggle->toggleOn(rpl::single(shotSettings.showReactions()) + )->toggledValue( + ) | rpl::skip(1) | on_next( + [=](bool enabled) + { + AyuSettings::getInstance().messageShotSettings().setShowReactions(enabled); + updatePreview(); + }, + content->lifetime()); + } - const auto latestToggle = AddButtonWithIcon( - content, - tr::ayu_MessageShotShowColorfulReplies(), - st::settingsButtonNoIcon - ); - latestToggle->toggleOn(rpl::single(shotSettings.showColorfulReplies()) - )->toggledValue( - ) | rpl::skip(1) | on_next( - [=](bool enabled) - { - auto ¤tSettings = AyuSettings::getInstance(); - currentSettings.messageShotSettings().setShowColorfulReplies(enabled); - currentSettings.setSimpleQuotesAndReplies(!enabled); + if (hasReplies) { + latestToggle = AddButtonWithIcon( + content, + tr::ayu_MessageShotShowColorfulReplies(), + st::settingsButtonNoIcon + ); + latestToggle->toggleOn(rpl::single(shotSettings.showColorfulReplies()) + )->toggledValue( + ) | rpl::skip(1) | on_next( + [=](bool enabled) + { + auto ¤tSettings = AyuSettings::getInstance(); + currentSettings.messageShotSettings().setShowColorfulReplies(enabled); + currentSettings.setSimpleQuotesAndReplies(!enabled); - _config.st = std::make_shared(_config.st.get()); - updatePreview(); - }, - content->lifetime()); + _config.st = std::make_shared(_config.st.get()); + updatePreview(); + }, + content->lifetime()); + } + + if (hasSpoilers) { + latestToggle = AddButtonWithIcon( + content, + tr::ayu_MessageShotRevealSpoilers(), + st::settingsButtonNoIcon + ); + latestToggle->toggleOn(rpl::single(shotSettings.revealSpoilers()) + )->toggledValue( + ) | rpl::skip(1) | on_next( + [=](bool enabled) + { + AyuSettings::getInstance().messageShotSettings().setRevealSpoilers(enabled); + updatePreview(); + }, + content->lifetime()); + } AddSkip(content); diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 624ac55c7a..a3f6d7c0d4 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -1298,6 +1298,15 @@ void Element::hideSpoilers() { } } +void Element::revealSpoilers() { + if (_text.hasSpoilers()) { + _text.setSpoilerRevealed(true, anim::type::instant); + } + if (_media) { + _media->revealSpoilers(); + } +} + void Element::customEmojiRepaint() { if (!(_flags & Flag::CustomEmojiRepainting)) { _flags |= Flag::CustomEmojiRepainting; diff --git a/Telegram/SourceFiles/history/view/history_view_element.h b/Telegram/SourceFiles/history/view/history_view_element.h index 29ddc34662..8bccc0977f 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.h +++ b/Telegram/SourceFiles/history/view/history_view_element.h @@ -654,6 +654,7 @@ public: const Reactions::InlineList &reactions) const; void clearCustomEmojiRepaint() const; void hideSpoilers(); + void revealSpoilers(); void repaint(QRect r = QRect()) const; [[nodiscard]] ClickHandlerPtr fromPhotoLink() const { diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index acfc6a38cf..99f31c3587 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -1738,6 +1738,12 @@ void Document::hideSpoilers() { } } +void Document::revealSpoilers() { + if (const auto captioned = Get()) { + captioned->caption.setSpoilerRevealed(true, anim::type::instant); + } +} + Ui::Text::String Document::createCaption() const { return File::createCaption(_realParent); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.h b/Telegram/SourceFiles/history/view/media/history_view_document.h index d47cf20456..da76c79c1b 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.h +++ b/Telegram/SourceFiles/history/view/media/history_view_document.h @@ -61,6 +61,7 @@ public: } void hideSpoilers() override; + void revealSpoilers() override; bool needsBubble() const override { return true; } diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index dc00937607..92df22ce21 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -1701,6 +1701,12 @@ void Gif::hideSpoilers() { } } +void Gif::revealSpoilers() { + if (_spoiler) { + _spoiler->revealed = true; + } +} + bool Gif::needsBubble() const { if (_storyId) { return true; diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.h b/Telegram/SourceFiles/history/view/media/history_view_gif.h index f663d00d24..ac4a7fd954 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.h +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.h @@ -102,6 +102,7 @@ public: QImage spoilerTagBackground() const override; void hideSpoilers() override; + void revealSpoilers() override; bool needsBubble() const override; bool unwrapped() const override; bool customInfoLayout() 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 1cf8f4747e..a7c52c6c78 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media.h @@ -265,6 +265,8 @@ public: virtual void hideSpoilers() { } + virtual void revealSpoilers() { + } [[nodiscard]] virtual bool needsBubble() const = 0; [[nodiscard]] virtual bool unwrapped() const { return false; 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 52d80034e6..c3f912a10d 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp @@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL // AyuGram includes #include "ayu/ayu_settings.h" +#include "ayu/features/message_shot/message_shot.h" namespace HistoryView { @@ -512,7 +513,7 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const { if (_parent->media() == this && (!_parent->hasBubble() || isBubbleBottom())) { auto fullRight = width(); auto fullBottom = height(); - if (needInfoDisplay()) { + if (needInfoDisplay() && !AyuFeatures::MessageShot::ignoreRender(AyuFeatures::MessageShot::RenderPart::Date)) { _parent->drawInfo( p, context, @@ -847,6 +848,12 @@ void GroupedMedia::hideSpoilers() { } } +void GroupedMedia::revealSpoilers() { + for (const auto &part : _parts) { + part.content->revealSpoilers(); + } +} + Storage::SharedMediaTypesMask GroupedMedia::sharedMediaTypes() const { return main()->sharedMediaTypes(); } @@ -960,6 +967,9 @@ bool GroupedMedia::computeNeedBubble() const { } bool GroupedMedia::needInfoDisplay() const { + if (AyuFeatures::MessageShot::isTakingShot()) { + return (_mode != Mode::Column); + } const auto item = _parent->data(); return (_mode != Mode::Column) && (item->isSending() 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 6e5adebd05..c233cb6408 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h @@ -74,6 +74,7 @@ public: bool pressed) override; void hideSpoilers() override; + void revealSpoilers() override; Storage::SharedMediaTypesMask sharedMediaTypes() const override; bool overrideEditedDate() 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 4b27a51af7..5202d35320 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp @@ -893,6 +893,10 @@ bool Photo::needInfoDisplay() const { return false; } + if (AyuFeatures::MessageShot::isTakingShot()) { + return true; + } + if (_parent->data()->isFakeAboutView()) { return false; } @@ -1094,6 +1098,12 @@ void Photo::hideSpoilers() { } } +void Photo::revealSpoilers() { + if (_spoiler) { + _spoiler->revealed = true; + } +} + bool Photo::needsBubble() const { if (_storyId) { return true; diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.h b/Telegram/SourceFiles/history/view/media/history_view_photo.h index 14c6f83448..96e3c7ff16 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.h +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.h @@ -84,6 +84,7 @@ public: QImage spoilerTagBackground() const override; void hideSpoilers() override; + void revealSpoilers() override; bool needsBubble() const override; bool customInfoLayout() const override { return true; diff --git a/Telegram/SourceFiles/history/view/media/history_view_service_box.cpp b/Telegram/SourceFiles/history/view/media/history_view_service_box.cpp index f28fd31c3e..492b3bf7b0 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_service_box.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_service_box.cpp @@ -422,6 +422,10 @@ void ServiceBox::hideSpoilers() { _subtitle.setSpoilerRevealed(false, anim::type::instant); } +void ServiceBox::revealSpoilers() { + _subtitle.setSpoilerRevealed(true, anim::type::instant); +} + bool ServiceBox::hasHeavyPart() const { return _content->hasHeavyPart(); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_service_box.h b/Telegram/SourceFiles/history/view/media/history_view_service_box.h index 235ed2a4ca..4842a0605a 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_service_box.h +++ b/Telegram/SourceFiles/history/view/media/history_view_service_box.h @@ -103,6 +103,7 @@ public: return _content->hideServiceText(); } void hideSpoilers() override; + void revealSpoilers() override; bool hasHeavyPart() const override; void unloadHeavyPart() override; diff --git a/Telegram/SourceFiles/history/view/media/history_view_todo_list.cpp b/Telegram/SourceFiles/history/view/media/history_view_todo_list.cpp index d849a1cc7d..4e5caf1b8d 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_todo_list.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_todo_list.cpp @@ -864,6 +864,17 @@ void TodoList::hideSpoilers() { } } +void TodoList::revealSpoilers() { + if (_title.hasSpoilers()) { + _title.setSpoilerRevealed(true, anim::type::instant); + } + for (auto &task : _tasks) { + if (task.text.hasSpoilers()) { + task.text.setSpoilerRevealed(true, anim::type::instant); + } + } +} + std::vector TodoList::takeTasksInfo() { if (_tasks.empty()) { return {}; diff --git a/Telegram/SourceFiles/history/view/media/history_view_todo_list.h b/Telegram/SourceFiles/history/view/media/history_view_todo_list.h index b17e7853cc..290bc7aa10 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_todo_list.h +++ b/Telegram/SourceFiles/history/view/media/history_view_todo_list.h @@ -65,6 +65,7 @@ public: bool hasHeavyPart() const override; void hideSpoilers() override; + void revealSpoilers() override; std::vector takeTasksInfo() override;