diff --git a/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp b/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp index 56912fde9..8a09de0f3 100644 --- a/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp +++ b/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp @@ -105,7 +105,7 @@ public: Dying, }; - Thumb(Key key, ImagePtr image); + Thumb(Key key, ImagePtr image, base::lambda handler); int leftToUpdate() const; int rightToUpdate() const; @@ -118,6 +118,7 @@ public: bool removed() const; void paint(Painter &p, int x, int y, int outerWidth, float64 progress); + ClickHandlerPtr getState(QPoint point) const; private: QSize wantedPixSize() const; @@ -126,30 +127,33 @@ private: int currentWidth() const; int finalLeft() const; int finalWidth() const; - void toggle(bool visible); void animateTo(int left, int width); + ClickHandlerPtr _link; const Key _key; ImagePtr _image; State _state = State::Alive; QPixmap _full; int _fullWidth = 0; - bool _hiding = true; + bool _hiding = false; anim::value _left = { 0. }; anim::value _width = { 0. }; - anim::value _opacity = { 0. }; + anim::value _opacity = { 0., 1. }; }; -GroupThumbs::Thumb::Thumb(Key key, ImagePtr image) +GroupThumbs::Thumb::Thumb( + Key key, + ImagePtr image, + base::lambda handler) : _key(key) , _image(image) { + _link = std::make_shared(std::move(handler)); _fullWidth = std::min( wantedPixSize().width(), st::mediaviewGroupWidthMax); validateImage(); - toggle(true); } QSize GroupThumbs::Thumb::wantedPixSize() const { @@ -229,23 +233,21 @@ void GroupThumbs::Thumb::setState(State state) { _left = anim::value(-_fullWidth / 2); _width = anim::value(_fullWidth); } else { - toggle(true); + _opacity.start(1.); } + _hiding = false; animateTo(-_fullWidth / 2, _fullWidth); } else if (_state == State::Alive) { - toggle(true); + _opacity.start(0.7); + _hiding = false; } else if (_state == State::Dying) { - toggle(false); + _opacity.start(0.); + _hiding = true; _left.restart(); _width.restart(); } } -void GroupThumbs::Thumb::toggle(bool visible) { - _hiding = !visible; - _opacity.start(_hiding ? 0. : 1.); -} - void GroupThumbs::Thumb::animateTo(int left, int width) { _left.start(left); _width.start(width); @@ -324,6 +326,17 @@ void GroupThumbs::Thumb::paint( p.setOpacity(opacity); } +ClickHandlerPtr GroupThumbs::Thumb::getState(QPoint point) const { + if (_state != State::Alive) { + return nullptr; + } + const auto left = finalLeft(); + const auto width = finalWidth(); + return QRect(left, 0, width, st::mediaviewGroupHeight).contains(point) + ? _link + : nullptr; +} + GroupThumbs::GroupThumbs(Context context) : _context(context) { } @@ -486,7 +499,12 @@ auto GroupThumbs::createThumb(Key key) -> std::unique_ptr { auto GroupThumbs::createThumb(Key key, ImagePtr image) -> std::unique_ptr { - return std::make_unique(key, image); + const auto weak = base::make_weak(this); + return std::make_unique(key, image, [=] { + if (const auto strong = weak.get()) { + strong->_activateStream.fire_copy(key); + } + }); } auto GroupThumbs::validateCacheEntry(Key key) -> not_null { @@ -597,6 +615,16 @@ void GroupThumbs::paint( } } +ClickHandlerPtr GroupThumbs::getState(QPoint point) const { + point -= QPoint((_width / 2), st::mediaviewGroupPadding.top()); + for (const auto &[key, thumb] : _cache) { + if (auto link = thumb->getState(point)) { + return link; + } + } + return nullptr; +} + void GroupThumbs::countUpdatedRect() { if (_cache.empty()) { return; diff --git a/Telegram/SourceFiles/media/view/media_view_group_thumbs.h b/Telegram/SourceFiles/media/view/media_view_group_thumbs.h index 23fbcd2d3..7b31f5a30 100644 --- a/Telegram/SourceFiles/media/view/media_view_group_thumbs.h +++ b/Telegram/SourceFiles/media/view/media_view_group_thumbs.h @@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #pragma once #include "history/history_item_components.h" +#include "base/weak_ptr.h" class SharedMediaWithLastSlice; class UserPhotosSlice; @@ -28,8 +29,10 @@ class UserPhotosSlice; namespace Media { namespace View { -class GroupThumbs { +class GroupThumbs : public base::has_weak_ptr { public: + using Key = base::variant; + static void Refresh( std::unique_ptr &instance, const SharedMediaWithLastSlice &slice, @@ -49,17 +52,21 @@ public: void checkForAnimationStart(); void paint(Painter &p, int x, int y, int outerWidth, TimeMs ms); + ClickHandlerPtr getState(QPoint point) const; rpl::producer updateRequests() const { return _updateRequests.events(); } + rpl::producer activateRequests() const { + return _activateStream.events(); + } + rpl::lifetime &lifetime() { return _lifetime; } using Context = base::optional_variant; - using Key = base::variant; GroupThumbs(Context context); ~GroupThumbs(); @@ -98,11 +105,12 @@ private: base::flat_map> _cache; int _width = 0; int _limit = 0; - rpl::event_stream _updateRequests; - rpl::lifetime _lifetime; - QRect _updatedRect; + rpl::event_stream _updateRequests; + rpl::event_stream _activateStream; + rpl::lifetime _lifetime; + }; } // namespace View diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index e562feb29..88921ceeb 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -1288,24 +1288,41 @@ void MediaView::refreshGroupThumbs() { _groupThumbs->resizeToWidth(_groupThumbsAvailableWidth); } if (_groupThumbs && !existed) { - _groupThumbs->updateRequests( - ) | rpl::start_with_next([this](QRect rect) { - const auto shift = (width() / 2); - _groupThumbsRect = QRect( - shift + rect.x(), - _groupThumbsTop, - rect.width(), - _groupThumbs->height()); - update(_groupThumbsRect); - }, _groupThumbs->lifetime()); - _groupThumbsRect = QRect( - _groupThumbsLeft, - _groupThumbsTop, - width() - 2 * _groupThumbsLeft, - height() - _groupThumbsTop); + initGroupThumbs(); } } +void MediaView::initGroupThumbs() { + Expects(_groupThumbs != nullptr); + + _groupThumbs->updateRequests( + ) | rpl::start_with_next([this](QRect rect) { + const auto shift = (width() / 2); + _groupThumbsRect = QRect( + shift + rect.x(), + _groupThumbsTop, + rect.width(), + _groupThumbs->height()); + update(_groupThumbsRect); + }, _groupThumbs->lifetime()); + + _groupThumbs->activateRequests( + ) | rpl::start_with_next([this](Media::View::GroupThumbs::Key key) { + if (const auto photoId = base::get_if(&key)) { + const auto photo = App::photo(*photoId); + moveToEntity({ photo, nullptr }); + } else if (const auto itemId = base::get_if(&key)) { + moveToEntity(entityForItemId(*itemId)); + } + }, _groupThumbs->lifetime()); + + _groupThumbsRect = QRect( + _groupThumbsLeft, + _groupThumbsTop, + width() - 2 * _groupThumbsLeft, + height() - _groupThumbsTop); +} + void MediaView::showPhoto(not_null photo, HistoryItem *context) { if (context) { setContext(context); @@ -2421,16 +2438,21 @@ MediaView::Entity MediaView::entityForSharedMedia(int index) const { // Last peer photo. return { *photo, nullptr }; } else if (const auto itemId = base::get_if(&value)) { - if (const auto item = App::histItemById(*itemId)) { - if (const auto media = item->getMedia()) { - if (const auto photo = media->getPhoto()) { - return { photo, item }; - } else if (const auto document = media->getDocument()) { - return { document, item }; - } + return entityForItemId(*itemId); + } + return { base::none, nullptr }; +} + +MediaView::Entity MediaView::entityForItemId(const FullMsgId &itemId) const { + if (const auto item = App::histItemById(itemId)) { + if (const auto media = item->getMedia()) { + if (const auto photo = media->getPhoto()) { + return { photo, item }; + } else if (const auto document = media->getDocument()) { + return { document, item }; } - return { base::none, item }; } + return { base::none, item }; } return { base::none, nullptr }; } @@ -2481,12 +2503,14 @@ bool MediaView::moveToNext(int delta) { return false; } auto newIndex = *_index + delta; - auto entity = entityByIndex(newIndex); + return moveToEntity(entityByIndex(newIndex)); +} + +bool MediaView::moveToEntity(const Entity &entity, int preloadDelta) { if (!entity.data && !entity.item) { return false; } - _index = newIndex; - if (auto item = entity.item) { + if (const auto item = entity.item) { setContext(item); } else if (_peer) { setContext(_peer); @@ -2501,7 +2525,7 @@ bool MediaView::moveToNext(int delta) { } else { displayDocument(nullptr, entity.item); } - preloadData(delta); + preloadData(preloadDelta); return true; } @@ -2695,8 +2719,13 @@ void MediaView::updateOver(QPoint pos) { auto textState = _caption.getState(pos - _captionRect.topLeft(), _captionRect.width()); lnk = textState.link; lnkhost = this; + } else if (_groupThumbs && _groupThumbsRect.contains(pos)) { + const auto point = pos - QPoint(_groupThumbsLeft, _groupThumbsTop); + lnk = _groupThumbs->getState(point); + lnkhost = this; } + // retina if (pos.x() == width()) { pos.setX(pos.x() - 1); diff --git a/Telegram/SourceFiles/mediaview.h b/Telegram/SourceFiles/mediaview.h index f6c3793fb..3667064a8 100644 --- a/Telegram/SourceFiles/mediaview.h +++ b/Telegram/SourceFiles/mediaview.h @@ -161,6 +161,8 @@ private: Entity entityForUserPhotos(int index) const; Entity entityForSharedMedia(int index) const; Entity entityByIndex(int index) const; + Entity entityForItemId(const FullMsgId &itemId) const; + bool moveToEntity(const Entity &entity, int preloadDelta = 0); void setContext(base::optional_variant< not_null, not_null> context); @@ -250,8 +252,8 @@ private: bool updateOverState(OverState newState); float64 overLevel(OverState control) const; - QRect groupThumbsFullRect() const; void checkGroupThumbsAnimation(); + void initGroupThumbs(); QBrush _transparentBrush;