Show user photos overview in PeerShortInfoBox.
This commit is contained in:
parent
64f6b86739
commit
360a92c198
|
@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto kShadowMaxAlpha = 80;
|
constexpr auto kShadowMaxAlpha = 80;
|
||||||
|
constexpr auto kInactiveBarOpacity = 0.5;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -52,6 +53,11 @@ PeerShortInfoBox::PeerShortInfoBox(
|
||||||
) | rpl::start_with_next([=](PeerShortInfoUserpic &&value) {
|
) | rpl::start_with_next([=](PeerShortInfoUserpic &&value) {
|
||||||
applyUserpic(std::move(value));
|
applyUserpic(std::move(value));
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
style::PaletteChanged(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
refreshBarImages();
|
||||||
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
PeerShortInfoBox::~PeerShortInfoBox() = default;
|
PeerShortInfoBox::~PeerShortInfoBox() = default;
|
||||||
|
@ -60,6 +66,10 @@ rpl::producer<> PeerShortInfoBox::openRequests() const {
|
||||||
return _openRequests.events();
|
return _openRequests.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<int> PeerShortInfoBox::moveRequests() const {
|
||||||
|
return _moveRequests.events();
|
||||||
|
}
|
||||||
|
|
||||||
void PeerShortInfoBox::prepare() {
|
void PeerShortInfoBox::prepare() {
|
||||||
addButton(tr::lng_close(), [=] { closeBox(); });
|
addButton(tr::lng_close(), [=] { closeBox(); });
|
||||||
|
|
||||||
|
@ -79,6 +89,8 @@ void PeerShortInfoBox::prepare() {
|
||||||
) | rpl::start_with_next([=](int height) {
|
) | rpl::start_with_next([=](int height) {
|
||||||
setDimensions(st::shortInfoWidth, st::shortInfoWidth + height);
|
setDimensions(st::shortInfoWidth, st::shortInfoWidth + height);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
setMouseTracking(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerShortInfoBox::prepareRows() {
|
void PeerShortInfoBox::prepareRows() {
|
||||||
|
@ -143,7 +155,6 @@ void PeerShortInfoBox::prepareRows() {
|
||||||
tr::lng_info_username_label(),
|
tr::lng_info_username_label(),
|
||||||
usernameValue() | Ui::Text::ToWithEntities(),
|
usernameValue() | Ui::Text::ToWithEntities(),
|
||||||
tr::lng_context_copy_mention(tr::now));
|
tr::lng_context_copy_mention(tr::now));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RectParts PeerShortInfoBox::customCornersFilling() {
|
RectParts PeerShortInfoBox::customCornersFilling() {
|
||||||
|
@ -192,8 +203,72 @@ void PeerShortInfoBox::paintEvent(QPaintEvent *e) {
|
||||||
_videoInstance->markFrameShown();
|
_videoInstance->markFrameShown();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_shadow.isNull()) {
|
paintBars(p);
|
||||||
_shadow = Images::GenerateShadow(
|
paintShadow(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerShortInfoBox::mouseMoveEvent(QMouseEvent *e) {
|
||||||
|
//const auto x = e->pos().x();
|
||||||
|
const auto cursor = (_count > 1)
|
||||||
|
? style::cur_pointer
|
||||||
|
: style::cur_default;
|
||||||
|
//const auto cursor = (_index > 0 && x < st::shortInfoWidth / 3)
|
||||||
|
// ? style::cur_pointer
|
||||||
|
// : (_index + 1 < _count && x >= st::shortInfoWidth / 3)
|
||||||
|
// ? style::cur_pointer
|
||||||
|
// : style::cur_default;
|
||||||
|
if (_cursor != cursor) {
|
||||||
|
_cursor = cursor;
|
||||||
|
setCursor(_cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerShortInfoBox::mousePressEvent(QMouseEvent *e) {
|
||||||
|
const auto x = e->pos().x();
|
||||||
|
if (e->button() != Qt::LeftButton) {
|
||||||
|
return;
|
||||||
|
} else if (/*_index > 0 && */x < st::shortInfoWidth / 3) {
|
||||||
|
_moveRequests.fire(-1);
|
||||||
|
} else if (/*_index + 1 < _count && */x >= st::shortInfoWidth / 3) {
|
||||||
|
_moveRequests.fire(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerShortInfoBox::paintBars(QPainter &p) {
|
||||||
|
const auto height = st::shortInfoLinePadding * 2 + st::shortInfoLine;
|
||||||
|
if (_shadowTop.isNull()) {
|
||||||
|
_shadowTop = Images::GenerateShadow(height, kShadowMaxAlpha, 0);
|
||||||
|
}
|
||||||
|
const auto shadowRect = QRect(0, 0, st::shortInfoWidth, height);
|
||||||
|
const auto factor = style::DevicePixelRatio();
|
||||||
|
p.drawImage(
|
||||||
|
shadowRect,
|
||||||
|
_shadowTop,
|
||||||
|
QRect(0, 0, _shadowTop.width(), height * factor));
|
||||||
|
if (!_smallWidth) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto top = st::shortInfoLinePadding;
|
||||||
|
const auto skip = st::shortInfoLineSkip;
|
||||||
|
const auto full = (st::shortInfoWidth - 2 * top - (_count - 1) * skip);
|
||||||
|
const auto width = full / float64(_count);
|
||||||
|
for (auto i = 0; i != _count; ++i) {
|
||||||
|
const auto left = top + i * (width + skip);
|
||||||
|
const auto right = left + width;
|
||||||
|
p.setOpacity((i == _index) ? 1. : kInactiveBarOpacity);
|
||||||
|
p.drawImage(
|
||||||
|
qRound(left),
|
||||||
|
top,
|
||||||
|
((qRound(right) == qRound(left) + _smallWidth)
|
||||||
|
? _barSmall
|
||||||
|
: _barLarge));
|
||||||
|
}
|
||||||
|
p.setOpacity(1.);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerShortInfoBox::paintShadow(QPainter &p) {
|
||||||
|
if (_shadowBottom.isNull()) {
|
||||||
|
_shadowBottom = Images::GenerateShadow(
|
||||||
st::shortInfoShadowHeight,
|
st::shortInfoShadowHeight,
|
||||||
0,
|
0,
|
||||||
kShadowMaxAlpha);
|
kShadowMaxAlpha);
|
||||||
|
@ -206,11 +281,11 @@ void PeerShortInfoBox::paintEvent(QPaintEvent *e) {
|
||||||
const auto factor = style::DevicePixelRatio();
|
const auto factor = style::DevicePixelRatio();
|
||||||
p.drawImage(
|
p.drawImage(
|
||||||
shadowRect,
|
shadowRect,
|
||||||
_shadow,
|
_shadowBottom,
|
||||||
QRect(
|
QRect(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
_shadow.width(),
|
_shadowBottom.width(),
|
||||||
st::shortInfoShadowHeight * factor));
|
st::shortInfoShadowHeight * factor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,14 +336,24 @@ rpl::producer<TextWithEntities> PeerShortInfoBox::aboutValue() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerShortInfoBox::applyUserpic(PeerShortInfoUserpic &&value) {
|
void PeerShortInfoBox::applyUserpic(PeerShortInfoUserpic &&value) {
|
||||||
|
if (_index != value.index) {
|
||||||
|
_index = value.index;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
if (_count != value.count) {
|
||||||
|
_count = value.count;
|
||||||
|
refreshBarImages();
|
||||||
|
update();
|
||||||
|
}
|
||||||
if (!value.photo.isNull()
|
if (!value.photo.isNull()
|
||||||
&& _userpicImage.cacheKey() != value.photo.cacheKey()) {
|
&& _userpicImage.cacheKey() != value.photo.cacheKey()) {
|
||||||
_userpicImage = std::move(value.photo);
|
_userpicImage = std::move(value.photo);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
if (value.videoDocument
|
if (!value.videoDocument) {
|
||||||
&& (!_videoInstance
|
_videoInstance = nullptr;
|
||||||
|| _videoInstance->shared() != value.videoDocument)) {
|
} else if (!_videoInstance
|
||||||
|
|| _videoInstance->shared() != value.videoDocument) {
|
||||||
const auto frame = currentVideoFrame();
|
const auto frame = currentVideoFrame();
|
||||||
if (!frame.isNull()) {
|
if (!frame.isNull()) {
|
||||||
_userpicImage = frame;
|
_userpicImage = frame;
|
||||||
|
@ -340,6 +425,40 @@ void PeerShortInfoBox::streamingReady(Media::Streaming::Information &&info) {
|
||||||
update(coverRect());
|
update(coverRect());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PeerShortInfoBox::refreshBarImages() {
|
||||||
|
if (_count < 2) {
|
||||||
|
_smallWidth = _largeWidth = 0;
|
||||||
|
_barSmall = _barLarge = QImage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto width = st::shortInfoWidth - 2 * st::shortInfoLinePadding;
|
||||||
|
_smallWidth = (width - (_count - 1) * st::shortInfoLineSkip) / _count;
|
||||||
|
if (_smallWidth < st::shortInfoLine) {
|
||||||
|
_smallWidth = _largeWidth = 0;
|
||||||
|
_barSmall = _barLarge = QImage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_largeWidth = _smallWidth + 1;
|
||||||
|
const auto makeBar = [](int size) {
|
||||||
|
const auto radius = st::shortInfoLine / 2.;
|
||||||
|
auto result = QImage(
|
||||||
|
QSize(size, st::shortInfoLine) * style::DevicePixelRatio(),
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
result.setDevicePixelRatio(style::DevicePixelRatio());
|
||||||
|
result.fill(Qt::transparent);
|
||||||
|
auto p = QPainter(&result);
|
||||||
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(st::groupCallVideoTextFg);
|
||||||
|
p.drawRoundedRect(0, 0, size, st::shortInfoLine, radius, radius);
|
||||||
|
p.end();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
_barSmall = makeBar(_smallWidth);
|
||||||
|
_barLarge = makeBar(_largeWidth);
|
||||||
|
}
|
||||||
|
|
||||||
QRect PeerShortInfoBox::coverRect() const {
|
QRect PeerShortInfoBox::coverRect() const {
|
||||||
return QRect(0, 0, st::shortInfoWidth, st::shortInfoWidth);
|
return QRect(0, 0, st::shortInfoWidth, st::shortInfoWidth);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ public:
|
||||||
~PeerShortInfoBox();
|
~PeerShortInfoBox();
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<> openRequests() const;
|
[[nodiscard]] rpl::producer<> openRequests() const;
|
||||||
|
[[nodiscard]] rpl::producer<int> moveRequests() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void prepare() override;
|
void prepare() override;
|
||||||
|
@ -66,6 +67,11 @@ private:
|
||||||
|
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent *e) override;
|
||||||
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
|
|
||||||
|
void paintBars(QPainter &p);
|
||||||
|
void paintShadow(QPainter &p);
|
||||||
|
|
||||||
[[nodiscard]] QImage currentVideoFrame() const;
|
[[nodiscard]] QImage currentVideoFrame() const;
|
||||||
|
|
||||||
|
@ -84,6 +90,8 @@ private:
|
||||||
void handleStreamingError(Media::Streaming::Error &&error);
|
void handleStreamingError(Media::Streaming::Error &&error);
|
||||||
void streamingReady(Media::Streaming::Information &&info);
|
void streamingReady(Media::Streaming::Information &&info);
|
||||||
|
|
||||||
|
void refreshBarImages();
|
||||||
|
|
||||||
const PeerShortInfoType _type = PeerShortInfoType::User;
|
const PeerShortInfoType _type = PeerShortInfoType::User;
|
||||||
|
|
||||||
rpl::variable<PeerShortInfoFields> _fields;
|
rpl::variable<PeerShortInfoFields> _fields;
|
||||||
|
@ -94,11 +102,22 @@ private:
|
||||||
not_null<Ui::VerticalLayout*> _rows;
|
not_null<Ui::VerticalLayout*> _rows;
|
||||||
|
|
||||||
QImage _userpicImage;
|
QImage _userpicImage;
|
||||||
|
QImage _barSmall;
|
||||||
|
QImage _barLarge;
|
||||||
|
QImage _shadowTop;
|
||||||
|
int _smallWidth = 0;
|
||||||
|
int _largeWidth = 0;
|
||||||
|
int _index = 0;
|
||||||
|
int _count = 0;
|
||||||
|
|
||||||
|
style::cursor _cursor = style::cur_default;
|
||||||
|
|
||||||
std::unique_ptr<Media::Streaming::Instance> _videoInstance;
|
std::unique_ptr<Media::Streaming::Instance> _videoInstance;
|
||||||
crl::time _videoStartPosition = 0;
|
crl::time _videoStartPosition = 0;
|
||||||
Fn<bool()> _videoPaused;
|
Fn<bool()> _videoPaused;
|
||||||
QImage _shadow;
|
QImage _shadowBottom;
|
||||||
|
|
||||||
rpl::event_stream<> _openRequests;
|
rpl::event_stream<> _openRequests;
|
||||||
|
rpl::event_stream<int> _moveRequests;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_chat.h"
|
#include "data/data_chat.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_peer_values.h"
|
#include "data/data_peer_values.h"
|
||||||
|
#include "data/data_user_photos.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
@ -29,12 +30,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kOverviewLimit = 48;
|
||||||
|
|
||||||
struct UserpicState {
|
struct UserpicState {
|
||||||
PeerShortInfoUserpic current;
|
PeerShortInfoUserpic current;
|
||||||
|
std::optional<UserPhotosSlice> userSlice;
|
||||||
|
PhotoId userpicPhotoId = PeerData::kUnknownPhotoId;
|
||||||
std::shared_ptr<Data::CloudImageView> userpicView;
|
std::shared_ptr<Data::CloudImageView> userpicView;
|
||||||
std::shared_ptr<Data::PhotoMedia> photoView;
|
std::shared_ptr<Data::PhotoMedia> photoView;
|
||||||
InMemoryKey userpicKey;
|
InMemoryKey userpicKey;
|
||||||
PhotoId photoId = 0;
|
PhotoId photoId = PeerData::kUnknownPhotoId;
|
||||||
bool waitingFull = false;
|
bool waitingFull = false;
|
||||||
bool waitingLoad = false;
|
bool waitingLoad = false;
|
||||||
};
|
};
|
||||||
|
@ -117,8 +122,11 @@ void ProcessFullPhoto(
|
||||||
} else if (const auto small = view->image(PhotoSize::Small)) {
|
} else if (const auto small = view->image(PhotoSize::Small)) {
|
||||||
GenerateImage(state, small, true);
|
GenerateImage(state, small, true);
|
||||||
} else {
|
} else {
|
||||||
|
const auto current = (peer->userpicPhotoId() == photo->id);
|
||||||
|
if (current) {
|
||||||
ProcessUserpic(peer, state);
|
ProcessUserpic(peer, state);
|
||||||
if (state->current.photo.isNull()) {
|
}
|
||||||
|
if (!current || state->current.photo.isNull()) {
|
||||||
if (const auto blurred = view->thumbnailInline()) {
|
if (const auto blurred = view->thumbnailInline()) {
|
||||||
GenerateImage(state, blurred, true);
|
GenerateImage(state, blurred, true);
|
||||||
}
|
}
|
||||||
|
@ -212,43 +220,113 @@ void ProcessFullPhoto(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<PeerShortInfoUserpic> UserpicValue(
|
void ProcessOld(not_null<PeerData*> peer, not_null<UserpicState*> state) {
|
||||||
not_null<PeerData*> peer) {
|
|
||||||
return [=](auto consumer) {
|
}
|
||||||
auto lifetime = rpl::lifetime();
|
|
||||||
const auto state = lifetime.make_state<UserpicState>();
|
void ValidatePhotoId(
|
||||||
const auto push = [=] {
|
not_null<UserpicState*> state,
|
||||||
state->waitingLoad = false;
|
PhotoId oldUserpicPhotoId) {
|
||||||
const auto nowPhotoId = peer->userpicPhotoId();
|
if (state->userSlice) {
|
||||||
const auto photo = (nowPhotoId
|
const auto count = state->userSlice->size();
|
||||||
&& (nowPhotoId != PeerData::kUnknownPhotoId)
|
const auto hasOld = state->userSlice->indexOf(oldUserpicPhotoId);
|
||||||
&& (state->photoId != nowPhotoId || state->photoView))
|
const auto hasNew = state->userSlice->indexOf(state->userpicPhotoId);
|
||||||
? peer->owner().photo(nowPhotoId).get()
|
const auto shift = (hasNew ? 0 : 1);
|
||||||
|
const auto fullCount = count + shift;
|
||||||
|
state->current.count = fullCount;
|
||||||
|
if (hasOld && !hasNew && state->current.index + 1 < fullCount) {
|
||||||
|
++state->current.index;
|
||||||
|
} else if (!hasOld && hasNew && state->current.index > 0) {
|
||||||
|
--state->current.index;
|
||||||
|
}
|
||||||
|
const auto index = state->current.index;
|
||||||
|
if (!index || index >= fullCount) {
|
||||||
|
state->current.index = 0;
|
||||||
|
state->photoId = state->userpicPhotoId;
|
||||||
|
} else {
|
||||||
|
state->photoId = (*state->userSlice)[index - shift];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state->photoId = state->userpicPhotoId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProcessCurrent(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
not_null<UserpicState*> state) {
|
||||||
|
const auto userpicPhotoId = peer->userpicPhotoId();
|
||||||
|
const auto userpicPhoto = (userpicPhotoId
|
||||||
|
&& (userpicPhotoId != PeerData::kUnknownPhotoId)
|
||||||
|
&& (state->userpicPhotoId != userpicPhotoId))
|
||||||
|
? peer->owner().photo(userpicPhotoId).get()
|
||||||
|
: (state->photoId == userpicPhotoId && state->photoView)
|
||||||
|
? state->photoView->owner().get()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
state->waitingFull = !(state->photoId == nowPhotoId)
|
state->waitingFull = (state->userpicPhotoId != userpicPhotoId)
|
||||||
&& ((nowPhotoId == PeerData::kUnknownPhotoId)
|
&& ((userpicPhotoId == PeerData::kUnknownPhotoId)
|
||||||
|| (nowPhotoId && photo->isNull()));
|
|| (userpicPhotoId && userpicPhoto->isNull()));
|
||||||
if (state->waitingFull) {
|
if (state->waitingFull) {
|
||||||
peer->updateFullForced();
|
peer->updateFullForced();
|
||||||
}
|
}
|
||||||
const auto oldPhotoId = state->waitingFull
|
const auto oldUserpicPhotoId = state->waitingFull
|
||||||
? state->photoId
|
? state->userpicPhotoId
|
||||||
: std::exchange(state->photoId, nowPhotoId);
|
: std::exchange(state->userpicPhotoId, userpicPhotoId);
|
||||||
const auto changedPhotoId = (state->photoId != oldPhotoId);
|
const auto changedUserpicPhotoId
|
||||||
|
= (state->userpicPhotoId != oldUserpicPhotoId);
|
||||||
const auto changedUserpic = (state->userpicKey
|
const auto changedUserpic = (state->userpicKey
|
||||||
!= peer->userpicUniqueKey(state->userpicView));
|
!= peer->userpicUniqueKey(state->userpicView));
|
||||||
|
|
||||||
|
const auto wasIndex = state->current.index;
|
||||||
|
const auto wasCount = state->current.count;
|
||||||
|
const auto wasPhotoId = state->photoId;
|
||||||
|
ValidatePhotoId(state, oldUserpicPhotoId);
|
||||||
|
const auto changedInSlice = (state->current.index != wasIndex)
|
||||||
|
|| (state->current.count != wasCount);
|
||||||
|
const auto changedPhotoId = (state->photoId != wasPhotoId);
|
||||||
|
const auto photo = (state->photoId == state->userpicPhotoId
|
||||||
|
&& userpicPhoto)
|
||||||
|
? userpicPhoto
|
||||||
|
: (state->photoId
|
||||||
|
&& (state->photoId != PeerData::kUnknownPhotoId)
|
||||||
|
&& changedPhotoId)
|
||||||
|
? peer->owner().photo(state->photoId).get()
|
||||||
|
: state->photoView
|
||||||
|
? state->photoView->owner().get()
|
||||||
|
: nullptr;
|
||||||
|
state->waitingLoad = false;
|
||||||
if (!changedPhotoId
|
if (!changedPhotoId
|
||||||
&& !changedUserpic
|
&& (state->current.index > 0 || !changedUserpic)
|
||||||
&& !state->photoView
|
&& !state->photoView
|
||||||
&& (!state->current.photo.isNull()
|
&& (!state->current.photo.isNull()
|
||||||
|| state->current.videoDocument)) {
|
|| state->current.videoDocument)) {
|
||||||
return;
|
return changedInSlice;
|
||||||
} else if (photo && !photo->isNull()) {
|
} else if (photo && !photo->isNull()) {
|
||||||
ProcessFullPhoto(peer, state, photo);
|
ProcessFullPhoto(peer, state, photo);
|
||||||
|
} else if (state->current.index > 0) {
|
||||||
|
return changedInSlice;
|
||||||
} else {
|
} else {
|
||||||
ProcessUserpic(peer, state);
|
ProcessUserpic(peer, state);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UserpicResult {
|
||||||
|
rpl::producer<PeerShortInfoUserpic> value;
|
||||||
|
Fn<void(int)> move;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] UserpicResult UserpicValue(not_null<PeerData*> peer) {
|
||||||
|
const auto moveRequests = std::make_shared<rpl::event_stream<int>>();
|
||||||
|
auto move = [=](int shift) {
|
||||||
|
moveRequests->fire_copy(shift);
|
||||||
|
};
|
||||||
|
auto value = [=](auto consumer) {
|
||||||
|
auto lifetime = rpl::lifetime();
|
||||||
|
const auto state = lifetime.make_state<UserpicState>();
|
||||||
|
const auto push = [=](bool force = false) {
|
||||||
|
if (ProcessCurrent(peer, state) || force) {
|
||||||
consumer.put_next_copy(state->current);
|
consumer.put_next_copy(state->current);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
using UpdateFlag = Data::PeerUpdate::Flag;
|
using UpdateFlag = Data::PeerUpdate::Flag;
|
||||||
peer->session().changes().peerFlagsValue(
|
peer->session().changes().peerFlagsValue(
|
||||||
|
@ -260,6 +338,30 @@ void ProcessFullPhoto(
|
||||||
push();
|
push();
|
||||||
}, lifetime);
|
}, lifetime);
|
||||||
|
|
||||||
|
if (const auto user = peer->asUser()) {
|
||||||
|
UserPhotosReversedViewer(
|
||||||
|
&peer->session(),
|
||||||
|
UserPhotosSlice::Key(peerToUser(user->id), PhotoId()),
|
||||||
|
kOverviewLimit,
|
||||||
|
kOverviewLimit
|
||||||
|
) | rpl::start_with_next([=](UserPhotosSlice &&slice) {
|
||||||
|
state->userSlice = std::move(slice);
|
||||||
|
push();
|
||||||
|
}, lifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
moveRequests->events(
|
||||||
|
) | rpl::filter([=] {
|
||||||
|
return (state->current.count > 1);
|
||||||
|
}) | rpl::start_with_next([=](int shift) {
|
||||||
|
state->current.index = std::clamp(
|
||||||
|
((state->current.index + shift + state->current.count)
|
||||||
|
% state->current.count),
|
||||||
|
0,
|
||||||
|
state->current.count - 1);
|
||||||
|
push(true);
|
||||||
|
}, lifetime);
|
||||||
|
|
||||||
peer->session().downloaderTaskFinished(
|
peer->session().downloaderTaskFinished(
|
||||||
) | rpl::filter([=] {
|
) | rpl::filter([=] {
|
||||||
return state->waitingLoad
|
return state->waitingLoad
|
||||||
|
@ -272,6 +374,7 @@ void ProcessFullPhoto(
|
||||||
|
|
||||||
return lifetime;
|
return lifetime;
|
||||||
};
|
};
|
||||||
|
return { .value = std::move(value), .move = std::move(move) };
|
||||||
}
|
}
|
||||||
|
|
||||||
object_ptr<Ui::BoxContent> PrepareShortInfoBox(
|
object_ptr<Ui::BoxContent> PrepareShortInfoBox(
|
||||||
|
@ -283,16 +386,20 @@ object_ptr<Ui::BoxContent> PrepareShortInfoBox(
|
||||||
: peer->isBroadcast()
|
: peer->isBroadcast()
|
||||||
? PeerShortInfoType::Channel
|
? PeerShortInfoType::Channel
|
||||||
: PeerShortInfoType::Group;
|
: PeerShortInfoType::Group;
|
||||||
|
auto userpic = UserpicValue(peer);
|
||||||
auto result = Box<PeerShortInfoBox>(
|
auto result = Box<PeerShortInfoBox>(
|
||||||
type,
|
type,
|
||||||
FieldsValue(peer),
|
FieldsValue(peer),
|
||||||
StatusValue(peer),
|
StatusValue(peer),
|
||||||
UserpicValue(peer),
|
std::move(userpic.value),
|
||||||
std::move(videoPaused));
|
std::move(videoPaused));
|
||||||
|
|
||||||
result->openRequests(
|
result->openRequests(
|
||||||
) | rpl::start_with_next(open, result->lifetime());
|
) | rpl::start_with_next(open, result->lifetime());
|
||||||
|
|
||||||
|
result->moveRequests(
|
||||||
|
) | rpl::start_with_next(userpic.move, result->lifetime());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -971,3 +971,6 @@ shortInfoNamePosition: point(25px, 37px);
|
||||||
shortInfoStatusPosition: point(25px, 14px);
|
shortInfoStatusPosition: point(25px, 14px);
|
||||||
shortInfoShadowHeight: 80px;
|
shortInfoShadowHeight: 80px;
|
||||||
shortInfoLabeledPadding: margins(20px, 16px, 20px, 0px);
|
shortInfoLabeledPadding: margins(20px, 16px, 20px, 0px);
|
||||||
|
shortInfoLinePadding: 8px;
|
||||||
|
shortInfoLineSkip: 4px;
|
||||||
|
shortInfoLine: 2px;
|
||||||
|
|
Loading…
Reference in New Issue