Show profile video in PeerShortInfoBox.

This commit is contained in:
John Preston 2021-10-18 18:17:09 +04:00
parent 61ac7e6c1d
commit 24e0ea2a59
5 changed files with 161 additions and 15 deletions

View File

@ -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<PeerListRow*> row) {
showRestricted(user);
} else {
Assert(_navigation != nullptr);
_navigation->showPeerInfo(participant);
AssertIsDebug();
_navigation->parentController()->show(PrepareShortInfoBox(
participant,
_navigation));
}
}

View File

@ -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<PeerShortInfoFields> fields,
rpl::producer<QString> status,
rpl::producer<PeerShortInfoUserpic> userpic)
rpl::producer<PeerShortInfoUserpic> userpic,
Fn<bool()> 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<QString> 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<Instance>(
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());
}
}

View File

@ -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<Media::Streaming::Document> videoDocument;
crl::time videoStartPosition = 0;
};
class PeerShortInfoBox final : public Ui::BoxContent {
@ -44,7 +48,8 @@ public:
PeerShortInfoType type,
rpl::producer<PeerShortInfoFields> fields,
rpl::producer<QString> status,
rpl::producer<PeerShortInfoUserpic> userpic);
rpl::producer<PeerShortInfoUserpic> userpic,
Fn<bool()> 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<QString> 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<Media::Streaming::Instance> _videoInstance;
crl::time _videoStartPosition = 0;
Fn<bool()> _videoPaused;
rpl::event_stream<> _openRequests;

View File

@ -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<Ui::BoxContent> PrepareShortInfoBox(
not_null<PeerData*> peer,
Fn<void()> open) {
Fn<void()> open,
Fn<bool()> videoPaused) {
const auto type = peer->isUser()
? PeerShortInfoType::User
: peer->isBroadcast()
@ -284,7 +286,8 @@ object_ptr<Ui::BoxContent> 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<Ui::BoxContent> PrepareShortInfoBox(
object_ptr<Ui::BoxContent> PrepareShortInfoBox(
not_null<PeerData*> peer,
not_null<Window::SessionNavigation*> 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);
}

View File

@ -21,7 +21,8 @@ class SessionNavigation;
[[nodiscard]] object_ptr<Ui::BoxContent> PrepareShortInfoBox(
not_null<PeerData*> peer,
Fn<void()> open);
Fn<void()> open,
Fn<bool()> videoPaused);
[[nodiscard]] object_ptr<Ui::BoxContent> PrepareShortInfoBox(
not_null<PeerData*> peer,