diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index 0b07b10a2..0ccb6748e 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -25,6 +25,10 @@ namespace Data { class Session; } // namespace Data +namespace Media::Player { +class RoundPainter; +} // namespace Media::Player + namespace Images { struct CornersMaskRef; } // namespace Images @@ -508,6 +512,7 @@ public: std::unique_ptr transcribe; Ui::Text::String transcribeText; + std::unique_ptr round; private: bool _seeking = false; diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 299b61412..a6f9f3303 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "storage/localstorage.h" #include "main/main_session.h" +#include "media/player/media_player_float.h" // Media::Player::RoundPainter. #include "media/audio/media_audio.h" #include "media/player/media_player_instance.h" #include "history/history_item_components.h" @@ -255,6 +256,10 @@ void Document::createComponents(bool caption) { voice->seekl = std::make_shared( _data, [](FullMsgId) {}); + if (_transcribedRound) { + voice->round = std::make_unique<::Media::Player::RoundPainter>( + _realParent); + } } } @@ -542,9 +547,26 @@ void Document::draw( inner, context.selected()); if (!coverDrawn) { - PainterHighQualityEnabler hq(p); - p.setBrush(stm->msgFileBg); - p.drawEllipse(inner); + if (_transcribedRound) { + if (const auto voice = Get()) { + if (const auto &round = voice->round) { + if (round->fillFrame(inner.size())) { + p.drawImage(inner.topLeft(), round->frame()); + } else { + DrawThumbnailAsSongCover( + p, + st::transparent, + _dataMedia, + inner, + context.selected()); + } + } + } + } else { + PainterHighQualityEnabler hq(p); + p.setBrush(stm->msgFileBg); + p.drawEllipse(inner); + } } const auto &icon = [&]() -> const style::icon& { @@ -812,7 +834,9 @@ void Document::ensureDataMediaCreated() const { return; } _dataMedia = _data->createMediaView(); - if (Get() || _data->isSongWithCover()) { + if (Get() + || _data->isSongWithCover() + || _transcribedRound) { _dataMedia->thumbnailWanted(_realParent->fullId()); } history()->owner().registerHeavyViewPart(_parent); diff --git a/Telegram/SourceFiles/media/player/media_player_float.cpp b/Telegram/SourceFiles/media/player/media_player_float.cpp index 2a1ee92e7..0b8bfc976 100644 --- a/Telegram/SourceFiles/media/player/media_player_float.cpp +++ b/Telegram/SourceFiles/media/player/media_player_float.cpp @@ -38,6 +38,55 @@ namespace Player { using DoubleClickedCallback = Fn)>; +RoundPainter::RoundPainter(not_null item) +: _item(item) { +} + +bool RoundPainter::fillFrame(const QSize &size) { + auto creating = _frame.isNull(); + const auto ratio = style::DevicePixelRatio(); + if (creating) { + _frame = QImage( + size * ratio, + QImage::Format_ARGB32_Premultiplied); + _frame.setDevicePixelRatio(ratio); + } + auto frameInner = [&] { + return QRect(QPoint(), _frame.size() / ratio); + }; + if (const auto streamed = instance()->roundVideoStreamed(_item)) { + auto request = Streaming::FrameRequest::NonStrict(); + request.outer = request.resize = _frame.size(); + if (_roundingMask.size() != request.outer) { + _roundingMask = Images::EllipseMask(frameInner().size()); + } + request.mask = _roundingMask; + auto frame = streamed->frame(request); + if (!frame.isNull()) { + _frame.fill(Qt::transparent); + + auto p = QPainter(&_frame); + PainterHighQualityEnabler hq(p); + p.drawImage(frameInner(), frame); + return true; + } + } + if (creating) { + _frame.fill(Qt::transparent); + + auto p = QPainter(&_frame); + PainterHighQualityEnabler hq(p); + p.setPen(Qt::NoPen); + p.setBrush(st::imageBg); + p.drawEllipse(frameInner()); + } + return false; +} + +const QImage &RoundPainter::frame() const { + return _frame; +} + Float::Float( QWidget *parent, not_null item, @@ -60,6 +109,7 @@ Float::Float( auto size = 2 * margin + st::mediaPlayerFloatSize; resize(size, size); + _roundPainter = std::make_unique(item); prepareShadow(); document->session().data().itemRepaintRequest( @@ -156,6 +206,7 @@ void Float::pauseResume() { void Float::detach() { if (_item) { _item = nullptr; + _roundPainter = nullptr; if (_toggleCallback) { _toggleCallback(false); } @@ -163,9 +214,12 @@ void Float::detach() { } void Float::prepareShadow() { - auto shadow = QImage(size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); + const auto ratio = style::DevicePixelRatio(); + auto shadow = QImage( + size() * ratio, + QImage::Format_ARGB32_Premultiplied); shadow.fill(Qt::transparent); - shadow.setDevicePixelRatio(cRetinaFactor()); + shadow.setDevicePixelRatio(ratio); { auto p = QPainter(&shadow); PainterHighQualityEnabler hq(p); @@ -188,12 +242,15 @@ void Float::paintEvent(QPaintEvent *e) { p.setOpacity(_opacity); p.drawPixmap(0, 0, _shadow); - if (!fillFrame() && _toggleCallback) { + const auto inner = getInnerRect(); + if (!(_roundPainter && _roundPainter->fillFrame(inner.size())) + && _toggleCallback) { _toggleCallback(false); } - auto inner = getInnerRect(); - p.drawImage(inner.topLeft(), _frame); + if (_roundPainter) { + p.drawImage(inner.topLeft(), _roundPainter->frame()); + } const auto playback = getPlayback(); const auto progress = playback ? playback->value() : 1.; @@ -230,46 +287,6 @@ bool Float::hasFrame() const { return (getStreamed() != nullptr); } -bool Float::fillFrame() { - auto creating = _frame.isNull(); - if (creating) { - _frame = QImage( - getInnerRect().size() * cIntRetinaFactor(), - QImage::Format_ARGB32_Premultiplied); - _frame.setDevicePixelRatio(cRetinaFactor()); - } - auto frameInner = [&] { - return QRect(QPoint(), _frame.size() / cIntRetinaFactor()); - }; - if (const auto streamed = getStreamed()) { - auto request = Streaming::FrameRequest::NonStrict(); - request.outer = request.resize = _frame.size(); - if (_roundingMask.size() != request.outer) { - _roundingMask = Images::EllipseMask(frameInner().size()); - } - request.mask = _roundingMask; - auto frame = streamed->frame(request); - if (!frame.isNull()) { - _frame.fill(Qt::transparent); - - auto p = QPainter(&_frame); - PainterHighQualityEnabler hq(p); - p.drawImage(frameInner(), frame); - return true; - } - } - if (creating) { - _frame.fill(Qt::transparent); - - auto p = QPainter(&_frame); - PainterHighQualityEnabler hq(p); - p.setPen(Qt::NoPen); - p.setBrush(st::imageBg); - p.drawEllipse(frameInner()); - } - return false; -} - void Float::repaintItem() { update(); if (hasFrame() && _toggleCallback) { diff --git a/Telegram/SourceFiles/media/player/media_player_float.h b/Telegram/SourceFiles/media/player/media_player_float.h index 236b0bd6c..af9a68014 100644 --- a/Telegram/SourceFiles/media/player/media_player_float.h +++ b/Telegram/SourceFiles/media/player/media_player_float.h @@ -33,6 +33,21 @@ class Instance; namespace Media { namespace Player { +class RoundPainter { +public: + RoundPainter(not_null item); + + bool fillFrame(const QSize &size); + const QImage &frame() const; + +private: + const not_null _item; + + QImage _roundingMask; + QImage _frame; + +}; + class Float : public Ui::RpWidget, private base::Subscriber { public: Float( @@ -85,7 +100,6 @@ private: void repaintItem(); void prepareShadow(); bool hasFrame() const; - bool fillFrame(); [[nodiscard]] QRect getInnerRect() const; void finishDrag(bool closed); void pauseResume(); @@ -93,11 +107,11 @@ private: HistoryItem *_item = nullptr; Fn _toggleCallback; + std::unique_ptr _roundPainter; + float64 _opacity = 1.; QPixmap _shadow; - QImage _roundingMask; - QImage _frame; bool _down = false; QPoint _downPoint;