From 24e0ea2a5904f19534fc28e6d00a1a58fabb5eda Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 18 Oct 2021 18:17:09 +0400 Subject: [PATCH] Show profile video in PeerShortInfoBox. --- .../boxes/peers/edit_participants_box.cpp | 6 +- .../boxes/peers/peer_short_info_box.cpp | 129 +++++++++++++++++- .../boxes/peers/peer_short_info_box.h | 19 ++- .../boxes/peers/prepare_short_info_box.cpp | 19 ++- .../boxes/peers/prepare_short_info_box.h | 3 +- 5 files changed, 161 insertions(+), 15 deletions(-) diff --git a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp index 914b12f0bc..a336f7223b 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_participants_box.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/peer_list_controllers.h" #include "boxes/peers/edit_participant_box.h" #include "boxes/peers/add_participants_box.h" +#include "boxes/peers/prepare_short_info_box.h" // PrepareShortInfoBox #include "ui/boxes/confirm_box.h" #include "boxes/max_invite_box.h" #include "boxes/add_contact_box.h" @@ -1434,7 +1435,10 @@ void ParticipantsBoxController::rowClicked(not_null row) { showRestricted(user); } else { Assert(_navigation != nullptr); - _navigation->showPeerInfo(participant); + AssertIsDebug(); + _navigation->parentController()->show(PrepareShortInfoBox( + participant, + _navigation)); } } diff --git a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp index 4b1ff59e5c..89c2547588 100644 --- a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/labels.h" #include "ui/image/image_prepare.h" #include "media/streaming/media_streaming_instance.h" +#include "media/streaming/media_streaming_player.h" #include "lang/lang_keys.h" #include "styles/style_layers.h" #include "styles/style_info.h" @@ -23,11 +24,13 @@ PeerShortInfoBox::PeerShortInfoBox( PeerShortInfoType type, rpl::producer fields, rpl::producer status, - rpl::producer userpic) + rpl::producer userpic, + Fn videoPaused) : _type(type) , _fields(std::move(fields)) , _name(this, nameValue(), st::shortInfoName) -, _status(this, std::move(status), st::shortInfoStatus) { +, _status(this, std::move(status), st::shortInfoStatus) +, _videoPaused(std::move(videoPaused)) { std::move( userpic ) | rpl::start_with_next([=](PeerShortInfoUserpic &&value) { @@ -66,17 +69,42 @@ void PeerShortInfoBox::resizeEvent(QResizeEvent *e) { void PeerShortInfoBox::paintEvent(QPaintEvent *e) { auto p = QPainter(this); - const auto coverSize = st::shortInfoWidth; - if (_userpicImage.isNull()) { - const auto size = coverSize * style::DevicePixelRatio(); - auto image = QImage(size, size, QImage::Format_ARGB32_Premultiplied); + checkStreamedIsStarted(); + const auto frame = currentVideoFrame(); + auto paused = _videoPaused && _videoPaused(); + if (frame.isNull() && _userpicImage.isNull()) { + auto image = QImage( + coverRect().size() * style::DevicePixelRatio(), + QImage::Format_ARGB32_Premultiplied); image.fill(Qt::black); Images::prepareRound( image, ImageRoundRadius::Small, RectPart::TopLeft | RectPart::TopRight); + _userpicImage = std::move(image); } - p.drawImage(QRect(0, 0, coverSize, coverSize), _userpicImage); + p.drawImage( + coverRect(), + frame.isNull() ? _userpicImage : frame); + if (_videoInstance && _videoInstance->ready() && !paused) { + _videoInstance->markFrameShown(); + } +} + +QImage PeerShortInfoBox::currentVideoFrame() const { + const auto coverSize = st::shortInfoWidth; + const auto size = QSize(coverSize, coverSize); + const auto request = Media::Streaming::FrameRequest{ + .resize = size * style::DevicePixelRatio(), + .outer = size, + .radius = ImageRoundRadius::Small, + .corners = RectPart::TopLeft | RectPart::TopRight, + }; + return (_videoInstance + && _videoInstance->player().ready() + && !_videoInstance->player().videoSize().isEmpty()) + ? _videoInstance->frame(request) + : QImage(); } rpl::producer PeerShortInfoBox::nameValue() const { @@ -91,4 +119,91 @@ void PeerShortInfoBox::applyUserpic(PeerShortInfoUserpic &&value) { _userpicImage = std::move(value.photo); update(); } + if (value.videoDocument + && (!_videoInstance + || _videoInstance->shared() != value.videoDocument)) { + const auto frame = currentVideoFrame(); + if (!frame.isNull()) { + _userpicImage = frame; + } + using namespace Media::Streaming; + _videoInstance = std::make_unique( + std::move(value.videoDocument), + [=] { videoWaiting(); }); + _videoStartPosition = value.videoStartPosition; + _videoInstance->lockPlayer(); + _videoInstance->player().updates( + ) | rpl::start_with_next_error([=](Update &&update) { + handleStreamingUpdate(std::move(update)); + }, [=](Error &&error) { + handleStreamingError(std::move(error)); + }, _videoInstance->lifetime()); + if (_videoInstance->ready()) { + streamingReady(base::duplicate(_videoInstance->info())); + } + if (!_videoInstance->valid()) { + _videoInstance = nullptr; + } + } +} + +void PeerShortInfoBox::checkStreamedIsStarted() { + if (!_videoInstance) { + return; + } else if (_videoInstance->paused()) { + _videoInstance->resume(); + } + if (!_videoInstance + || _videoInstance->active() + || _videoInstance->failed()) { + return; + } + auto options = Media::Streaming::PlaybackOptions(); + options.position = _videoStartPosition; + options.mode = Media::Streaming::Mode::Video; + options.loop = true; + _videoInstance->play(options); +} + +void PeerShortInfoBox::handleStreamingUpdate( + Media::Streaming::Update &&update) { + using namespace Media::Streaming; + + v::match(update.data, [&](Information &update) { + streamingReady(std::move(update)); + }, [&](const PreloadedVideo &update) { + }, [&](const UpdateVideo &update) { + this->update(coverRect()); + }, [&](const PreloadedAudio &update) { + }, [&](const UpdateAudio &update) { + }, [&](const WaitingForData &update) { + }, [&](MutedByOther) { + }, [&](Finished) { + }); +} + +void PeerShortInfoBox::handleStreamingError( + Media::Streaming::Error &&error) { + //_streamedPhoto->setVideoPlaybackFailed(); + //_streamedPhoto = nullptr; + _videoInstance = nullptr; +} + +void PeerShortInfoBox::streamingReady(Media::Streaming::Information &&info) { + update(coverRect()); +} + +QRect PeerShortInfoBox::coverRect() const { + return QRect(0, 0, st::shortInfoWidth, st::shortInfoWidth); +} + +QRect PeerShortInfoBox::radialRect() const { + const auto cover = coverRect(); + return cover; +} + +void PeerShortInfoBox::videoWaiting() { + if (!anim::Disabled()) { + update(radialRect()); + } } diff --git a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h index ade41a6c4f..e6d7f11d26 100644 --- a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h +++ b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.h @@ -12,6 +12,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Media::Streaming { class Document; class Instance; +struct Update; +enum class Error; +struct Information; } // namespace Media::Streaming enum class PeerShortInfoType { @@ -35,6 +38,7 @@ struct PeerShortInfoUserpic { QImage photo; float64 photoLoadingProgress = 0.; std::shared_ptr videoDocument; + crl::time videoStartPosition = 0; }; class PeerShortInfoBox final : public Ui::BoxContent { @@ -44,7 +48,8 @@ public: PeerShortInfoType type, rpl::producer fields, rpl::producer status, - rpl::producer userpic); + rpl::producer userpic, + Fn videoPaused); ~PeerShortInfoBox(); [[nodiscard]] rpl::producer<> openRequests() const; @@ -56,8 +61,18 @@ private: void resizeEvent(QResizeEvent *e) override; void paintEvent(QPaintEvent *e) override; + [[nodiscard]] QImage currentVideoFrame() const; + [[nodiscard]] rpl::producer nameValue() const; void applyUserpic(PeerShortInfoUserpic &&value); + QRect coverRect() const; + QRect radialRect() const; + + void videoWaiting(); + void checkStreamedIsStarted(); + void handleStreamingUpdate(Media::Streaming::Update &&update); + void handleStreamingError(Media::Streaming::Error &&error); + void streamingReady(Media::Streaming::Information &&info); const PeerShortInfoType _type = PeerShortInfoType::User; @@ -68,6 +83,8 @@ private: QImage _userpicImage; std::unique_ptr _videoInstance; + crl::time _videoStartPosition = 0; + Fn _videoPaused; rpl::event_stream<> _openRequests; diff --git a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp index daab8a1883..284935188d 100644 --- a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp @@ -56,8 +56,8 @@ void GenerateImage( size * factor, size * factor, options, - size * factor, - size * factor); + size, + size); } void GenerateImage( @@ -134,6 +134,7 @@ void ProcessFullPhoto( state->current.videoDocument = peer->owner().streaming().sharedDocument( photo, origin); + state->current.videoStartPosition = photo->videoStartPosition(); state->photoView = nullptr; state->current.photoLoadingProgress = 1.; } @@ -274,7 +275,8 @@ void ProcessFullPhoto( object_ptr PrepareShortInfoBox( not_null peer, - Fn open) { + Fn open, + Fn videoPaused) { const auto type = peer->isUser() ? PeerShortInfoType::User : peer->isBroadcast() @@ -284,7 +286,8 @@ object_ptr PrepareShortInfoBox( type, FieldsValue(peer), StatusValue(peer), - UserpicValue(peer)); + UserpicValue(peer), + std::move(videoPaused)); result->openRequests( ) | rpl::start_with_next(open, result->lifetime()); @@ -295,7 +298,13 @@ object_ptr PrepareShortInfoBox( object_ptr PrepareShortInfoBox( not_null peer, not_null navigation) { + const auto open = [=] { navigation->showPeerHistory(peer); }; + const auto videoIsPaused = [=] { + return navigation->parentController()->isGifPausedAtLeastFor( + Window::GifPauseReason::Layer); + }; return PrepareShortInfoBox( peer, - [=] { navigation->showPeerHistory(peer); }); + open, + videoIsPaused); } diff --git a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.h b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.h index 7494db61c2..5ebb41cae0 100644 --- a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.h +++ b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.h @@ -21,7 +21,8 @@ class SessionNavigation; [[nodiscard]] object_ptr PrepareShortInfoBox( not_null peer, - Fn open); + Fn open, + Fn videoPaused); [[nodiscard]] object_ptr PrepareShortInfoBox( not_null peer,