diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp index 939891fa0..83d3e5585 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.cpp @@ -618,6 +618,12 @@ void Controller::drawRepostInfo( _repostView->draw(p, x, y, availableWidth); } +RepostClickHandler Controller::lookupRepostHandler(QPoint position) const { + return _repostView + ? _repostView->lookupHandler(position) + : RepostClickHandler(); +} + void Controller::toggleLiked() { _reactions->toggleLiked(); } diff --git a/Telegram/SourceFiles/media/stories/media_stories_controller.h b/Telegram/SourceFiles/media/stories/media_stories_controller.h index 7916808b2..db494d9ee 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_controller.h +++ b/Telegram/SourceFiles/media/stories/media_stories_controller.h @@ -70,6 +70,7 @@ class CaptionFullView; class RepostView; enum class ReactionsMode; class SuggestedReactionView; +struct RepostClickHandler; enum class HeaderLayout { Normal, @@ -130,6 +131,8 @@ public: [[nodiscard]] QMargins repostCaptionPadding() const; void drawRepostInfo(Painter &p, int x, int y, int availableWidth) const; + [[nodiscard]] RepostClickHandler lookupRepostHandler( + QPoint position) const; [[nodiscard]] std::shared_ptr uiShow() const; [[nodiscard]] auto stickerOrEmojiChosen() const diff --git a/Telegram/SourceFiles/media/stories/media_stories_repost_view.cpp b/Telegram/SourceFiles/media/stories/media_stories_repost_view.cpp index 4a729bb5f..6c53c0fd4 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_repost_view.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_repost_view.cpp @@ -7,14 +7,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "media/stories/media_stories_repost_view.h" +#include "chat_helpers/compose/compose_show.h" #include "core/ui_integration.h" #include "data/data_peer.h" #include "data/data_session.h" #include "data/data_stories.h" #include "history/view/history_view_reply.h" +#include "lang/lang_keys.h" #include "main/main_session.h" #include "media/stories/media_stories_controller.h" +#include "media/stories/media_stories_view.h" #include "ui/effects/ripple_animation.h" +#include "ui/layers/box_content.h" #include "ui/text/text_custom_emoji.h" #include "ui/text/text_options.h" #include "ui/painter.h" @@ -60,7 +64,7 @@ void RepostView::draw(Painter &p, int x, int y, int availableWidth) { if (simple) { y += st::normalFont->height; } - const auto w = std::min(int(_maxWidth), availableWidth); + const auto w = _lastWidth = std::min(int(_maxWidth), availableWidth); const auto h = height() - (simple ? st::normalFont->height : 0); const auto rect = QRect(x, y, w, h); const auto colorPeer = _story->repostSourcePeer(); @@ -147,6 +151,39 @@ void RepostView::draw(Painter &p, int x, int y, int availableWidth) { } } +RepostClickHandler RepostView::lookupHandler(QPoint position) { + if (_loading) { + return {}; + } + const auto simple = _text.isEmpty(); + const auto w = _lastWidth; + const auto skip = simple ? st::normalFont->height : 0; + const auto h = height() - skip; + const auto rect = QRect(0, skip, w, h); + if (!rect.contains(position)) { + return {}; + } else if (!_link) { + _link = std::make_shared(crl::guard(this, [=] { + const auto peer = _story->repostSourcePeer(); + const auto owner = &_story->owner(); + if (const auto id = peer ? _story->repostSourceId() : 0) { + const auto of = owner->stories().lookup({ peer->id, id }); + if (of) { + using namespace Data; + _controller->show(*of, { StoriesContextSingle() }); + } else { + _controller->uiShow()->show(PrepareShortInfoBox(peer)); + } + } else { + _controller->uiShow()->showToast( + tr::lng_forwarded_story_expired(tr::now)); + } + })); + } + _lastPosition = position; + return { _link, this }; +} + void RepostView::recountDimensions() { const auto sender = _story->repostSourcePeer(); const auto name = sender ? sender->name() : _story->repostSourceName(); @@ -216,4 +253,29 @@ void RepostView::recountDimensions() { + st::historyReplyPadding.right(); } +void RepostView::clickHandlerPressedChanged( + const ClickHandlerPtr &action, + bool pressed) { + if (action == _link) { + if (pressed) { + const auto simple = _text.isEmpty(); + const auto skip = simple ? st::normalFont->height : 0; + if (!_ripple) { + const auto h = height() - skip; + _ripple = std::make_unique( + st::defaultRippleAnimation, + Ui::RippleAnimation::RoundRectMask( + QSize(_lastWidth, h), + (simple + ? st::storiesRepostSimpleStyle + : st::messageQuoteStyle).radius), + [=] { _controller->repaint(); }); + } + _ripple->add(_lastPosition - QPoint(0, skip)); + } else if (_ripple) { + _ripple->lastStop(); + } + } +} + } // namespace Media::Stories diff --git a/Telegram/SourceFiles/media/stories/media_stories_repost_view.h b/Telegram/SourceFiles/media/stories/media_stories_repost_view.h index 404c4f0a6..0667eab38 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_repost_view.h +++ b/Telegram/SourceFiles/media/stories/media_stories_repost_view.h @@ -23,8 +23,11 @@ class RippleAnimation; namespace Media::Stories { class Controller; +struct RepostClickHandler; -class RepostView final : public base::has_weak_ptr { +class RepostView final + : public base::has_weak_ptr + , public ClickHandlerHost { public: RepostView( not_null controller, @@ -33,12 +36,18 @@ public: [[nodiscard]] int height() const; void draw(Painter &p, int x, int y, int availableWidth); + [[nodiscard]] RepostClickHandler lookupHandler(QPoint position); private: void recountDimensions(); + void clickHandlerPressedChanged( + const ClickHandlerPtr &action, + bool pressed); + const not_null _controller; const not_null _story; + ClickHandlerPtr _link; std::unique_ptr _ripple; Ui::Text::String _name; @@ -46,6 +55,8 @@ private: Ui::Text::QuotePaintCache _quoteCache; Ui::BackgroundEmojiData _backgroundEmojiData; Ui::ColorIndicesCompressed _colorIndices; + QPoint _lastPosition; + mutable int _lastWidth = 0; uint32 _maxWidth : 31 = 0; uint32 _loading : 1 = 0; diff --git a/Telegram/SourceFiles/media/stories/media_stories_view.cpp b/Telegram/SourceFiles/media/stories/media_stories_view.cpp index 21eccb5e0..e21cd1fd9 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_view.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_view.cpp @@ -162,6 +162,10 @@ void View::drawRepostInfo( _controller->drawRepostInfo(p, x, y, availableWidth); } +RepostClickHandler View::lookupRepostHandler(QPoint position) const { + return _controller->lookupRepostHandler(position); +} + void View::showFullCaption() { _controller->showFullCaption(); } diff --git a/Telegram/SourceFiles/media/stories/media_stories_view.h b/Telegram/SourceFiles/media/stories/media_stories_view.h index 785877413..46a6662e2 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_view.h +++ b/Telegram/SourceFiles/media/stories/media_stories_view.h @@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +class ClickHandlerHost; + namespace Data { class Story; struct StoriesContext; @@ -58,6 +60,15 @@ struct SiblingView { } }; +struct RepostClickHandler { + ClickHandlerPtr link; + ClickHandlerHost *host = nullptr; + + explicit operator bool() const { + return link && host; + } +}; + inline constexpr auto kCollapsedCaptionLines = 2; inline constexpr auto kMaxShownCaptionLines = 4; @@ -83,6 +94,8 @@ public: [[nodiscard]] QMargins repostCaptionPadding() const; void drawRepostInfo(Painter &p, int x, int y, int availableWidth) const; + [[nodiscard]] RepostClickHandler lookupRepostHandler( + QPoint position) const; void updatePlayback(const Player::TrackState &state); [[nodiscard]] ClickHandlerPtr lookupAreaHandler(QPoint point) const; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index f793d9e70..2295982fe 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -2173,14 +2173,22 @@ void OverlayWidget::assignMediaPointer(not_null photo) { } } -void OverlayWidget::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { - setCursor((active || ClickHandler::getPressed()) ? style::cur_pointer : style::cur_default); - update(QRegion(_saveMsg) + _captionRect); +void OverlayWidget::clickHandlerActiveChanged( + const ClickHandlerPtr &p, + bool active) { + setCursor((active || ClickHandler::getPressed()) + ? style::cur_pointer + : style::cur_default); + update(QRegion(_saveMsg) + captionGeometry()); } -void OverlayWidget::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) { - setCursor((pressed || ClickHandler::getActive()) ? style::cur_pointer : style::cur_default); - update(QRegion(_saveMsg) + _captionRect); +void OverlayWidget::clickHandlerPressedChanged( + const ClickHandlerPtr &p, + bool pressed) { + setCursor((pressed || ClickHandler::getActive()) + ? style::cur_pointer + : style::cur_default); + update(QRegion(_saveMsg) + captionGeometry()); } rpl::lifetime &OverlayWidget::lifetime() { @@ -5707,7 +5715,15 @@ void OverlayWidget::updateOver(QPoint pos) { } lnkhost = this; } else if (_stories && captionGeometry().contains(pos)) { - //_stories->repostState(); + const auto padding = st::mediaviewCaptionPadding; + const auto handler = _stories->lookupRepostHandler( + pos - captionGeometry().marginsRemoved(padding).topLeft()); + if (handler) { + lnk = handler.link; + lnkhost = handler.host; + setCursor(style::cur_pointer); + _cursorOverriden = true; + } } else if (_groupThumbs && _groupThumbsRect.contains(pos)) { const auto point = pos - QPoint(_groupThumbsLeft, _groupThumbsTop); lnk = _groupThumbs->getState(point); @@ -5717,7 +5733,6 @@ void OverlayWidget::updateOver(QPoint pos) { lnkhost = this; } - // retina if (pos.x() == width()) { pos.setX(pos.x() - 1); @@ -5726,6 +5741,10 @@ void OverlayWidget::updateOver(QPoint pos) { pos.setY(pos.y() - 1); } + if (_cursorOverriden && (!lnkhost || lnkhost == this)) { + _cursorOverriden = false; + setCursor(style::cur_default); + } ClickHandler::setActive(lnk, lnkhost); if (_pressed || _dragging) return; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index a813641ae..94a7e7b2f 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -611,6 +611,7 @@ private: float64 _zoomToDefault = 0.; QPoint _mStart; bool _pressed = false; + bool _cursorOverriden = false; int32 _dragging = 0; QImage _staticContent; bool _staticContentTransparent = false;