Handle click on group thumb item in MediaView.

This commit is contained in:
John Preston 2017-12-29 17:58:53 +03:00
parent 59e5ffe743
commit 0171a4e874
4 changed files with 115 additions and 48 deletions

View File

@ -105,7 +105,7 @@ public:
Dying,
};
Thumb(Key key, ImagePtr image);
Thumb(Key key, ImagePtr image, base::lambda<void()> 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<void()> handler)
: _key(key)
, _image(image) {
_link = std::make_shared<LambdaClickHandler>(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<Thumb> {
auto GroupThumbs::createThumb(Key key, ImagePtr image)
-> std::unique_ptr<Thumb> {
return std::make_unique<Thumb>(key, image);
const auto weak = base::make_weak(this);
return std::make_unique<Thumb>(key, image, [=] {
if (const auto strong = weak.get()) {
strong->_activateStream.fire_copy(key);
}
});
}
auto GroupThumbs::validateCacheEntry(Key key) -> not_null<Thumb*> {
@ -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;

View File

@ -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<PhotoId, FullMsgId>;
static void Refresh(
std::unique_ptr<GroupThumbs> &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<QRect> updateRequests() const {
return _updateRequests.events();
}
rpl::producer<Key> activateRequests() const {
return _activateStream.events();
}
rpl::lifetime &lifetime() {
return _lifetime;
}
using Context = base::optional_variant<PeerId, MessageGroupId>;
using Key = base::variant<PhotoId, FullMsgId>;
GroupThumbs(Context context);
~GroupThumbs();
@ -98,11 +105,12 @@ private:
base::flat_map<Key, std::unique_ptr<Thumb>> _cache;
int _width = 0;
int _limit = 0;
rpl::event_stream<QRect> _updateRequests;
rpl::lifetime _lifetime;
QRect _updatedRect;
rpl::event_stream<QRect> _updateRequests;
rpl::event_stream<Key> _activateStream;
rpl::lifetime _lifetime;
};
} // namespace View

View File

@ -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<PhotoId>(&key)) {
const auto photo = App::photo(*photoId);
moveToEntity({ photo, nullptr });
} else if (const auto itemId = base::get_if<FullMsgId>(&key)) {
moveToEntity(entityForItemId(*itemId));
}
}, _groupThumbs->lifetime());
_groupThumbsRect = QRect(
_groupThumbsLeft,
_groupThumbsTop,
width() - 2 * _groupThumbsLeft,
height() - _groupThumbsTop);
}
void MediaView::showPhoto(not_null<PhotoData*> 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<FullMsgId>(&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);

View File

@ -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<HistoryItem*>,
not_null<PeerData*>> context);
@ -250,8 +252,8 @@ private:
bool updateOverState(OverState newState);
float64 overLevel(OverState control) const;
QRect groupThumbsFullRect() const;
void checkGroupThumbsAnimation();
void initGroupThumbs();
QBrush _transparentBrush;