Play ttl media horizontally where the message was.

This commit is contained in:
John Preston 2024-01-16 10:34:49 +04:00
parent b462d7627f
commit 104cf504ab
3 changed files with 99 additions and 50 deletions

View file

@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/tooltip.h" #include "ui/widgets/tooltip.h"
#include "window/section_widget.h" // Window::ChatThemeValueFromPeer. #include "window/section_widget.h" // Window::ChatThemeValueFromPeer.
#include "window/themes/window_theme.h" #include "window/themes/window_theme.h"
#include "window/window_controller.h"
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
#include "styles/style_chat_helpers.h" #include "styles/style_chat_helpers.h"
@ -44,6 +45,7 @@ public:
PreviewDelegate( PreviewDelegate(
not_null<QWidget*> parent, not_null<QWidget*> parent,
not_null<Ui::ChatStyle*> st, not_null<Ui::ChatStyle*> st,
rpl::producer<bool> chatWideValue,
Fn<void()> update); Fn<void()> update);
bool elementAnimationsPaused() override; bool elementAnimationsPaused() override;
@ -54,15 +56,18 @@ public:
private: private:
const not_null<QWidget*> _parent; const not_null<QWidget*> _parent;
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient; const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
rpl::variable<bool> _chatWide;
}; };
PreviewDelegate::PreviewDelegate( PreviewDelegate::PreviewDelegate(
not_null<QWidget*> parent, not_null<QWidget*> parent,
not_null<Ui::ChatStyle*> st, not_null<Ui::ChatStyle*> st,
rpl::producer<bool> chatWideValue,
Fn<void()> update) Fn<void()> update)
: _parent(parent) : _parent(parent)
, _pathGradient(HistoryView::MakePathShiftGradient(st, update)) { , _pathGradient(HistoryView::MakePathShiftGradient(st, update))
, _chatWide(std::move(chatWideValue)) {
} }
bool PreviewDelegate::elementAnimationsPaused() { bool PreviewDelegate::elementAnimationsPaused() {
@ -78,7 +83,7 @@ HistoryView::Context PreviewDelegate::elementContext() {
} }
bool PreviewDelegate::elementIsChatWide() { bool PreviewDelegate::elementIsChatWide() {
return true; return _chatWide.current();
} }
class PreviewWrap final : public Ui::RpWidget { class PreviewWrap final : public Ui::RpWidget {
@ -86,6 +91,8 @@ public:
PreviewWrap( PreviewWrap(
not_null<Ui::RpWidget*> parent, not_null<Ui::RpWidget*> parent,
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
rpl::producer<QRect> viewportValue,
rpl::producer<bool> chatWideValue,
rpl::producer<std::shared_ptr<Ui::ChatTheme>> theme); rpl::producer<std::shared_ptr<Ui::ChatTheme>> theme);
~PreviewWrap(); ~PreviewWrap();
@ -93,13 +100,17 @@ public:
private: private:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
[[nodiscard]] QRect elementRect() const;
const not_null<HistoryItem*> _item; const not_null<HistoryItem*> _item;
const std::unique_ptr<Ui::ChatStyle> _style; const std::unique_ptr<Ui::ChatStyle> _style;
const std::unique_ptr<PreviewDelegate> _delegate; const std::unique_ptr<PreviewDelegate> _delegate;
rpl::variable<QRect> _globalViewport;
rpl::variable<bool> _chatWide;
std::shared_ptr<Ui::ChatTheme> _theme; std::shared_ptr<Ui::ChatTheme> _theme;
std::unique_ptr<HistoryView::Element> _element; std::unique_ptr<HistoryView::Element> _element;
QRect _viewport;
QRect _elementGeometry;
rpl::variable<QRect> _elementInner;
rpl::lifetime _elementLifetime; rpl::lifetime _elementLifetime;
struct { struct {
@ -114,6 +125,8 @@ private:
PreviewWrap::PreviewWrap( PreviewWrap::PreviewWrap(
not_null<Ui::RpWidget*> parent, not_null<Ui::RpWidget*> parent,
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
rpl::producer<QRect> viewportValue,
rpl::producer<bool> chatWideValue,
rpl::producer<std::shared_ptr<Ui::ChatTheme>> theme) rpl::producer<std::shared_ptr<Ui::ChatTheme>> theme)
: RpWidget(parent) : RpWidget(parent)
, _item(item) , _item(item)
@ -122,8 +135,9 @@ PreviewWrap::PreviewWrap(
, _delegate(std::make_unique<PreviewDelegate>( , _delegate(std::make_unique<PreviewDelegate>(
parent, parent,
_style.get(), _style.get(),
[=] { update(elementRect()); })) { std::move(chatWideValue),
[=] { update(_elementGeometry); }))
, _globalViewport(std::move(viewportValue)) {
const auto isRound = _item const auto isRound = _item
&& _item->media() && _item->media()
&& _item->media()->document() && _item->media()->document()
@ -140,7 +154,7 @@ PreviewWrap::PreviewWrap(
session->data().viewRepaintRequest( session->data().viewRepaintRequest(
) | rpl::start_with_next([=](not_null<const HistoryView::Element*> view) { ) | rpl::start_with_next([=](not_null<const HistoryView::Element*> view) {
if (view == _element.get()) { if (view == _element.get()) {
update(elementRect()); update(_elementGeometry);
} }
}, lifetime()); }, lifetime());
@ -157,11 +171,15 @@ PreviewWrap::PreviewWrap(
close->setClickedCallback(closeCallback); close->setClickedCallback(closeCallback);
close->setTextTransform(Ui::RoundButton::TextTransform::NoTransform); close->setTextTransform(Ui::RoundButton::TextTransform::NoTransform);
sizeValue( rpl::combine(
) | rpl::start_with_next([=](const QSize &s) { sizeValue(),
_elementInner.value()
) | rpl::start_with_next([=](QSize size, QRect inner) {
close->moveToLeft( close->moveToLeft(
(s.width() - close->width()) / 2, inner.x() + (inner.width() - close->width()) / 2,
s.height() - close->height() - st::ttlMediaButtonBottomSkip); (size.height()
- close->height()
- st::ttlMediaButtonBottomSkip));
}, close->lifetime()); }, close->lifetime());
} }
@ -170,11 +188,27 @@ PreviewWrap::PreviewWrap(
{ {
_element->initDimensions(); _element->initDimensions();
widthValue( rpl::combine(
) | rpl::filter([=](int width) { sizeValue(),
return width > st::msgMinWidth; _globalViewport.value()
}) | rpl::start_with_next([=](int width) { ) | rpl::start_with_next([=](QSize outer, QRect globalViewport) {
_element->resizeGetHeight(width); _viewport = globalViewport.isEmpty()
? rect()
: mapFromGlobal(globalViewport);
if (_viewport.width() < st::msgMinWidth) {
return;
}
_element->resizeGetHeight(_viewport.width());
_elementGeometry = QRect(
(_viewport.width() - _element->width()) / 2,
(_viewport.height() - _element->height()) / 2,
_element->width(),
_element->height()
).translated(_viewport.topLeft());
const auto media = _element->media();
_elementInner = _element->innerGeometry().translated(
_elementGeometry.topLeft());
update();
}, _elementLifetime); }, _elementLifetime);
} }
@ -203,22 +237,17 @@ PreviewWrap::PreviewWrap(
st::defaultImportantTooltip.padding), st::defaultImportantTooltip.padding),
st::dialogsStoriesTooltip); st::dialogsStoriesTooltip);
tooltip->toggleFast(true); tooltip->toggleFast(true);
sizeValue( _elementInner.value(
) | rpl::filter( ) | rpl::filter([](const QRect &inner) {
[](const QSize &s) { return !s.isNull(); } return !inner.isEmpty();
) | rpl::take(1) | rpl::start_with_next([=](const QSize &s) { }) | rpl::start_with_next([=](const QRect &inner) {
if (s.isEmpty()) { tooltip->pointAt(inner, RectPart::Top, [=](QSize size) {
return;
}
auto area = elementRect();
area.setWidth(_element->media()
? _element->media()->width()
: _element->width());
tooltip->pointAt(area, RectPart::Top, [=](QSize size) {
return QPoint{ return QPoint{
(area.width() - size.width()) / 2, inner.x() + (inner.width() - size.width()) / 2,
(s.height() - size.height() * 2 - _element->height()) / 2 (inner.y()
- st::defaultImportantTooltip.padding.top(), - st::normalFont->height
- size.height()
- st::defaultImportantTooltip.padding.top()),
}; };
}); });
}, tooltip->lifetime()); }, tooltip->lifetime());
@ -232,14 +261,6 @@ PreviewWrap::PreviewWrap(
}, lifetime()); }, lifetime());
} }
QRect PreviewWrap::elementRect() const {
return QRect(
(width() - _element->width()) / 2,
(height() - _element->height()) / 2,
_element->width(),
_element->height());
}
rpl::producer<> PreviewWrap::closeRequests() const { rpl::producer<> PreviewWrap::closeRequests() const {
return _closeRequests.events(); return _closeRequests.events();
} }
@ -250,13 +271,14 @@ PreviewWrap::~PreviewWrap() {
} }
void PreviewWrap::paintEvent(QPaintEvent *e) { void PreviewWrap::paintEvent(QPaintEvent *e) {
if (!_element) { if (!_element || _elementGeometry.isEmpty()) {
return; return;
} }
auto p = QPainter(this); auto p = QPainter(this);
const auto r = rect(); //p.fillRect(_viewport, QColor(255, 0, 0, 64));
//p.fillRect(_elementGeometry, QColor(0, 255, 0, 64));
//p.fillRect(_elementInner.current(), QColor(0, 0, 255, 64));
if (!_last.use) { if (!_last.use) {
const auto size = _element->currentSize(); const auto size = _element->currentSize();
auto result = QImage( auto result = QImage(
@ -276,12 +298,35 @@ void PreviewWrap::paintEvent(QPaintEvent *e) {
} }
_last.frame = std::move(result); _last.frame = std::move(result);
} }
p.translate( p.translate(_elementGeometry.topLeft());
(r.width() - _element->width()) / 2,
(r.height() - _element->height()) / 2);
p.drawImage(0, 0, _last.frame); p.drawImage(0, 0, _last.frame);
} }
rpl::producer<QRect> GlobalViewportForWindow(
not_null<Window::SessionController*> controller) {
const auto delegate = controller->window().floatPlayerDelegate();
return rpl::single(rpl::empty) | rpl::then(
delegate->floatPlayerAreaUpdates()
) | rpl::map([=] {
auto section = (Media::Player::FloatSectionDelegate*)nullptr;
delegate->floatPlayerEnumerateSections([&](
not_null<Media::Player::FloatSectionDelegate*> check,
Window::Column column) {
if ((column == Window::Column::First && !section)
|| column == Window::Column::Second) {
section = check;
}
});
if (section) {
const auto rect = section->floatPlayerAvailableRect();
if (rect.width() >= st::msgMinWidth) {
return rect;
}
}
return QRect();
});
}
} // namespace } // namespace
void ShowTTLMediaLayerWidget( void ShowTTLMediaLayerWidget(
@ -292,6 +337,8 @@ void ShowTTLMediaLayerWidget(
auto preview = base::make_unique_q<PreviewWrap>( auto preview = base::make_unique_q<PreviewWrap>(
parent, parent,
item, item,
GlobalViewportForWindow(controller),
controller->adaptive().chatWideValue(),
Window::ChatThemeValueFromPeer( Window::ChatThemeValueFromPeer(
controller, controller,
item->history()->peer)); item->history()->peer));

View file

@ -1984,6 +1984,7 @@ bool Message::hasFromPhoto() const {
case Context::AdminLog: case Context::AdminLog:
return true; return true;
case Context::History: case Context::History:
case Context::TTLViewer:
case Context::Pinned: case Context::Pinned:
case Context::Replies: case Context::Replies:
case Context::SavedSublist: { case Context::SavedSublist: {
@ -2005,7 +2006,6 @@ bool Message::hasFromPhoto() const {
return !item->out() && !item->history()->peer->isUser(); return !item->out() && !item->history()->peer->isUser();
} break; } break;
case Context::ContactPreview: case Context::ContactPreview:
case Context::TTLViewer:
return false; return false;
} }
Unexpected("Context in Message::hasFromPhoto."); Unexpected("Context in Message::hasFromPhoto.");
@ -3171,6 +3171,7 @@ bool Message::hasFromName() const {
case Context::AdminLog: case Context::AdminLog:
return true; return true;
case Context::History: case Context::History:
case Context::TTLViewer:
case Context::Pinned: case Context::Pinned:
case Context::Replies: case Context::Replies:
case Context::SavedSublist: { case Context::SavedSublist: {
@ -3201,7 +3202,6 @@ bool Message::hasFromName() const {
return false; return false;
} break; } break;
case Context::ContactPreview: case Context::ContactPreview:
case Context::TTLViewer:
return false; return false;
} }
Unexpected("Context in Message::hasFromName."); Unexpected("Context in Message::hasFromName.");

View file

@ -243,10 +243,12 @@ void PaintWaveform(
p.fillRect( p.fillRect(
QRectF(barLeft, barTop, leftWidth, barHeight), QRectF(barLeft, barTop, leftWidth, barHeight),
active); active);
p.fillRect( if (!ttl) {
QRectF(activeWidth, barTop, rightWidth, barHeight), p.fillRect(
inactive); QRectF(activeWidth, barTop, rightWidth, barHeight),
} else { inactive);
}
} else if (!ttl || barLeft < activeWidth) {
const auto &color = (barLeft >= activeWidth) ? inactive : active; const auto &color = (barLeft >= activeWidth) ? inactive : active;
p.fillRect(QRectF(barLeft, barTop, barWidth, barHeight), color); p.fillRect(QRectF(barLeft, barTop, barWidth, barHeight), color);
} }