diff --git a/Telegram/Resources/icons/mediaview/mini_repost.png b/Telegram/Resources/icons/mediaview/mini_repost.png new file mode 100644 index 000000000..95e0e71eb Binary files /dev/null and b/Telegram/Resources/icons/mediaview/mini_repost.png differ diff --git a/Telegram/Resources/icons/mediaview/mini_repost@2x.png b/Telegram/Resources/icons/mediaview/mini_repost@2x.png new file mode 100644 index 000000000..47e5fd6af Binary files /dev/null and b/Telegram/Resources/icons/mediaview/mini_repost@2x.png differ diff --git a/Telegram/Resources/icons/mediaview/mini_repost@3x.png b/Telegram/Resources/icons/mediaview/mini_repost@3x.png new file mode 100644 index 000000000..3b73fe2d3 Binary files /dev/null and b/Telegram/Resources/icons/mediaview/mini_repost@3x.png differ diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp index 64e056727..6eabefc35 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp @@ -879,6 +879,8 @@ void Controller::show( const auto document = story->document(); _header->show({ .peer = peer, + .repostPeer = story->repostSourcePeer(), + .repostFrom = _repostView ? _repostView->fromName() : nullptr, .date = story->date(), .fullIndex = _sliderCount ? _index : 0, .fullCount = _sliderCount ? shownCount() : 0, diff --git a/Telegram/SourceFiles/media/stories/media_stories_header.cpp b/Telegram/SourceFiles/media/stories/media_stories_header.cpp index 3440f4018..635370eef 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_header.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_header.cpp @@ -9,7 +9,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/unixtime.h" #include "chat_helpers/compose/compose_show.h" +#include "core/ui_integration.h" +#include "data/stickers/data_custom_emoji.h" #include "data/data_peer.h" +#include "data/data_session.h" #include "media/stories/media_stories_controller.h" #include "lang/lang_keys.h" #include "ui/controls/userpic_button.h" @@ -252,9 +255,24 @@ struct MadePrivacyBadge { result.text.append( QString::fromUtf8(" \xE2\x80\xA2 ") + tr::lng_edited(tr::now)); } + if (!data.repostFrom.isEmpty()) { + result.text = QString::fromUtf8("\xC2\xA0\xE2\x80\xA2 ") + + result.text; + } return result; } +[[nodiscard]] TextWithEntities RepostNameValue( + not_null owner, + QString name) { + const auto result = Ui::Text::SingleCustomEmoji( + owner->customEmojiManager().registerInternalEmoji( + st::storiesRepostIcon, + st::storiesRepostIconPadding) + ).append(name); + return Ui::Text::Link(result); +} + } // namespace Header::Header(not_null controller) @@ -275,7 +293,9 @@ void Header::show(HeaderData data) { const auto namex = st::storiesHeaderNamePosition.x(); const auto namer = namex + _name->width(); const auto datex = st::storiesHeaderDatePosition.x(); - const auto dater = datex + _date->width(); + const auto dater = datex + + (_repost ? _repost->width() : 0) + + _date->width(); const auto r = std::max(namer, dater); _info->setGeometry({ 0, 0, r, _widget->height() }); } @@ -285,6 +305,7 @@ void Header::show(HeaderData data) { if (peerChanged) { _volume = nullptr; _date = nullptr; + _repost = nullptr; _name = nullptr; _counter = nullptr; _userpic = nullptr; @@ -350,6 +371,32 @@ void Header::show(HeaderData data) { _date->widthValue( ) | rpl::start_with_next(updateInfoGeometry, _date->lifetime()); + if (data.repostFrom.isEmpty()) { + _repost = nullptr; + } else { + _repost = std::make_unique( + _widget.get(), + st::storiesHeaderDate); + const auto repostName = RepostNameValue( + &data.peer->owner(), + data.repostFrom); + _repost->setMarkedText( + data.repostPeer ? Ui::Text::Link(repostName) : repostName, + Core::MarkedTextContext{ + .session = &data.peer->session(), + .customEmojiRepaint = [=] { _repost->update(); }, + }); + if (const auto peer = data.repostPeer) { + _repost->setClickHandlerFilter([=](const auto &...) { + _controller->uiShow()->show(PrepareShortInfoBox(peer)); + return false; + }); + } + _repost->show(); + _repost->widthValue( + ) | rpl::start_with_next(updateInfoGeometry, _repost->lifetime()); + } + auto counter = ComposeCounter(data); if (!counter.isEmpty()) { _counter = std::make_unique( @@ -433,13 +480,30 @@ void Header::show(HeaderData data) { _counter->move(counterLeft, _name->y()); } const auto dateLeft = st::storiesHeaderDatePosition.x(); - const auto dateAvailable = right - dateLeft; + const auto dateTop = st::storiesHeaderDatePosition.y(); + const auto dateSkip = _repost ? st::storiesHeaderRepostWidthMin : 0; + const auto dateAvailable = right - dateLeft - dateSkip; if (dateAvailable <= 0) { _date->hide(); } else { _date->show(); _date->resizeToNaturalWidth(dateAvailable); } + if (_repost) { + const auto repostAvailable = dateAvailable + + dateSkip + - _date->width(); + if (repostAvailable <= 0) { + _repost->hide(); + } else { + _repost->show(); + _repost->resizeToNaturalWidth(repostAvailable); + } + _repost->move(dateLeft, dateTop); + _date->move(dateLeft + _repost->width(), dateTop); + } else { + _date->move(dateLeft, dateTop); + } }, _date->lifetime()); if (timestamp.changes > 0) { diff --git a/Telegram/SourceFiles/media/stories/media_stories_header.h b/Telegram/SourceFiles/media/stories/media_stories_header.h index 1da36174f..cf360cc90 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_header.h +++ b/Telegram/SourceFiles/media/stories/media_stories_header.h @@ -32,6 +32,8 @@ enum class PauseState; struct HeaderData { not_null peer; + PeerData *repostPeer = nullptr; + QString repostFrom; TimeId date = 0; int fullIndex = 0; int fullCount = 0; @@ -84,6 +86,7 @@ private: std::unique_ptr _userpic; std::unique_ptr _name; std::unique_ptr _counter; + std::unique_ptr _repost; std::unique_ptr _date; rpl::event_stream<> _dateUpdated; std::unique_ptr _playPause; diff --git a/Telegram/SourceFiles/media/stories/media_stories_repost_view.cpp b/Telegram/SourceFiles/media/stories/media_stories_repost_view.cpp index 6c53c0fd4..75bddd008 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_repost_view.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_repost_view.cpp @@ -184,6 +184,11 @@ RepostClickHandler RepostView::lookupHandler(QPoint position) { return { _link, this }; } +QString RepostView::fromName() const { + const auto sender = _story->repostSourcePeer(); + return sender ? sender->name() : _story->repostSourceName(); +} + void RepostView::recountDimensions() { const auto sender = _story->repostSourcePeer(); const auto name = sender ? sender->name() : _story->repostSourceName(); diff --git a/Telegram/SourceFiles/media/stories/media_stories_repost_view.h b/Telegram/SourceFiles/media/stories/media_stories_repost_view.h index 0667eab38..f98fe0350 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_repost_view.h +++ b/Telegram/SourceFiles/media/stories/media_stories_repost_view.h @@ -38,6 +38,8 @@ public: void draw(Painter &p, int x, int y, int availableWidth); [[nodiscard]] RepostClickHandler lookupHandler(QPoint position); + [[nodiscard]] QString fromName() const; + private: void recountDimensions(); diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index 674129d22..c857368f3 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -433,10 +433,14 @@ storiesHeaderName: FlatLabel(defaultFlatLabel) { storiesHeaderNamePosition: point(50px, 0px); storiesHeaderDate: FlatLabel(defaultFlatLabel) { textFg: mediaviewControlFg; + palette: TextPalette(defaultTextPalette) { + linkFg: mediaviewControlFg; + } minWidth: 10px; maxHeight: 20px; } storiesHeaderDatePosition: point(50px, 17px); +storiesHeaderRepostWidthMin: 40px; storiesShadowTop: icon{{ "mediaview/shadow_bottom-flip_vertical", windowShadowFg }}; storiesShadowBottom: mediaviewShadowBottom; storiesControlsMinWidth: 280px; @@ -1009,9 +1013,12 @@ storiesLikeCountStyle: TextStyle(defaultTextStyle) { font: font(32px semibold); } storiesChangelogFooterWidthMin: 240px; + storiesRepostSimpleStyle: QuoteStyle(defaultQuoteStyle) { padding: margins(8px, 2px, 8px, 2px); verticalSkip: 4px; outline: 0px; radius: 10px; } +storiesRepostIcon: icon {{ "mediaview/mini_repost", windowFg }}; +storiesRepostIconPadding: margins(0px, 4px, 4px, 0px);