Added initial ability to play video messages with ttl.

This commit is contained in:
23rd 2024-01-14 03:49:09 +03:00 committed by John Preston
parent 40ff71b2cd
commit 21dcb7b13c
13 changed files with 128 additions and 22 deletions

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg baseProfile="tiny" version="1.2" viewBox="0 0 72 72" xmlns="http://www.w3.org/2000/svg">
<path d="m27.57 30.79q0.77-0.44 1.14-1.28 4.38-9.86 4.67-24.25 0.03-1.64 1.63-1.54 1.14 0.07 1.9 0.65c14.45 10.9 28.35 31.97 18.06 50.37-9.55 17.08-32.38 15.75-41.59-0.69-5.25-9.37-0.83-23.06 4.26-32.03a2.13 2.12 43.5 0 1 3.64-0.09l5.53 8.68a0.57 0.56-31.3 0 0 0.76 0.18z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 776 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -26,6 +26,7 @@
<file alias="recording/info_audio.svg">../../art/recording/recording_info_audio.svg</file> <file alias="recording/info_audio.svg">../../art/recording/recording_info_audio.svg</file>
<file alias="recording/info_video_landscape.svg">../../art/recording/recording_info_video_landscape.svg</file> <file alias="recording/info_video_landscape.svg">../../art/recording/recording_info_video_landscape.svg</file>
<file alias="recording/info_video_portrait.svg">../../art/recording/recording_info_video_portrait.svg</file> <file alias="recording/info_video_portrait.svg">../../art/recording/recording_info_video_portrait.svg</file>
<file alias="ttl/video_message_icon.svg">../../art/ttl/video_message_icon.svg</file>
<file alias="icons/settings/dino.svg">../../icons/settings/dino.svg</file> <file alias="icons/settings/dino.svg">../../icons/settings/dino.svg</file>
<file alias="icons/settings/star.svg">../../icons/settings/star.svg</file> <file alias="icons/settings/star.svg">../../icons/settings/star.svg</file>
<file alias="icons/settings/starmini.svg">../../icons/settings/starmini.svg</file> <file alias="icons/settings/starmini.svg">../../icons/settings/starmini.svg</file>

View file

@ -808,7 +808,3 @@ void ClearMediaAsExpired(not_null<HistoryItem*> item) {
} }
} }
} }
[[nodiscard]] bool IsVoiceOncePlayable(not_null<HistoryItem*> item) {
return !item->out() && item->media()->ttlSeconds();
}

View file

@ -158,4 +158,3 @@ ClickHandlerPtr JumpToStoryClickHandler(
void ShowTrialTranscribesToast(int left, TimeId until); void ShowTrialTranscribesToast(int left, TimeId until);
void ClearMediaAsExpired(not_null<HistoryItem*> item); void ClearMediaAsExpired(not_null<HistoryItem*> item);
[[nodiscard]] bool IsVoiceOncePlayable(not_null<HistoryItem*> item);

View file

@ -425,7 +425,7 @@ void Document::createComponents(bool caption) {
_realParent->fullId()); _realParent->fullId());
} }
if (const auto voice = Get<HistoryDocumentVoice>()) { if (const auto voice = Get<HistoryDocumentVoice>()) {
voice->seekl = !IsVoiceOncePlayable(_parent->data()) voice->seekl = !_parent->data()->media()->ttlSeconds()
? std::make_shared<VoiceSeekClickHandler>(_data, [](FullMsgId) {}) ? std::make_shared<VoiceSeekClickHandler>(_data, [](FullMsgId) {})
: nullptr; : nullptr;
if (_transcribedRound) { if (_transcribedRound) {

View file

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/view/media_view_playback_progress.h" #include "media/view/media_view_playback_progress.h"
#include "ui/boxes/confirm_box.h" #include "ui/boxes/confirm_box.h"
#include "ui/painter.h" #include "ui/painter.h"
#include "ui/rect.h"
#include "history/history_item_components.h" #include "history/history_item_components.h"
#include "history/history_item_helpers.h" #include "history/history_item_helpers.h"
#include "history/history_item.h" #include "history/history_item.h"
@ -30,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_cursor_state.h" #include "history/view/history_view_cursor_state.h"
#include "history/view/history_view_reply.h" #include "history/view/history_view_reply.h"
#include "history/view/history_view_transcribe_button.h" #include "history/view/history_view_transcribe_button.h"
#include "history/view/media/history_view_document.h" // TTLVoiceStops
#include "history/view/media/history_view_media_common.h" #include "history/view/media/history_view_media_common.h"
#include "history/view/media/history_view_media_spoiler.h" #include "history/view/media/history_view_media_spoiler.h"
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
@ -52,6 +54,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document_media.h" #include "data/data_document_media.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
#include <QSvgRenderer>
namespace HistoryView { namespace HistoryView {
namespace { namespace {
@ -65,6 +69,41 @@ int gifMaxStatusWidth(DocumentData *document) {
return result; return result;
} }
[[nodiscard]] HistoryView::TtlRoundPaintCallback CreateTtlPaintCallback(
Fn<void()> update) {
const auto iconSize = Size(std::min(
st::historyFileInPause.width(),
st::historyFileInPause.height()));
const auto centerMargins = Margins(st::historyFileInPause.width() * 3);
const auto renderer = std::make_shared<QSvgRenderer>(
u":/gui/ttl/video_message_icon.svg"_q);
return [=](QPainter &p, QRect r, const PaintContext &context) {
const auto centerRect = r - centerMargins;
const auto &icon = context.imageStyle()->historyVideoMessageTtlIcon;
const auto iconRect = QRect(
rect::right(centerRect) - icon.width() * 0.75,
rect::bottom(centerRect) - icon.height() * 0.75,
icon.width(),
icon.height());
{
auto hq = PainterHighQualityEnabler(p);
auto path = QPainterPath();
path.setFillRule(Qt::WindingFill);
path.addEllipse(centerRect);
path.addEllipse(iconRect);
p.fillPath(path, st::shadowFg);
p.fillPath(path, st::shadowFg);
p.fillPath(path, st::shadowFg);
}
renderer->render(&p, centerRect - Margins(centerRect.width() / 4));
icon.paint(p, iconRect.topLeft(), centerRect.width());
};
}
} // namespace } // namespace
struct Gif::Streamed { struct Gif::Streamed {
@ -83,6 +122,12 @@ Gif::Streamed::Streamed(
: instance(std::move(shared), std::move(waitingCallback)) { : instance(std::move(shared), std::move(waitingCallback)) {
} }
[[nodiscard]] bool IsHiddenRoundMessage(not_null<Element*> parent) {
return parent->delegate()->elementContext() != Context::TTLViewer
&& parent->data()->media()
&& parent->data()->media()->ttlSeconds();
}
Gif::Gif( Gif::Gif(
not_null<Element*> parent, not_null<Element*> parent,
not_null<HistoryItem*> realParent, not_null<HistoryItem*> realParent,
@ -95,18 +140,45 @@ Gif::Gif(
: FullStoryId()) : FullStoryId())
, _caption( , _caption(
st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right())
, _spoiler(spoiler ? std::make_unique<MediaSpoiler>() : nullptr) , _spoiler((spoiler || IsHiddenRoundMessage(_parent))
? std::make_unique<MediaSpoiler>()
: nullptr)
, _downloadSize(Ui::FormatSizeText(_data->size)) { , _downloadSize(Ui::FormatSizeText(_data->size)) {
setDocumentLinks(_data, realParent, [=] { auto hasDefaultDocumentLinks = false;
if (!_data->createMediaView()->canBePlayed(realParent) if (_data->isVideoMessage() && _parent->data()->media()->ttlSeconds()) {
|| !_data->isAnimation() if (_spoiler) {
|| _data->isVideoMessage() _drawTtl = CreateTtlPaintCallback([=] { repaint(); });
|| !CanPlayInline(_data)) {
return false;
} }
playAnimation(false); const auto fullId = _realParent->fullId();
return true; _parent->data()->removeFromSharedMediaIndex();
}); setDocumentLinks(_data, realParent, [=] {
auto lifetime = std::make_shared<rpl::lifetime>();
TTLVoiceStops(fullId) | rpl::start_with_next([=]() mutable {
const auto item = _parent->data();
if (lifetime) {
base::take(lifetime)->destroy();
}
if (!item->out()) {
// Destroys this.
ClearMediaAsExpired(item);
}
}, *lifetime);
return false;
});
} else {
setDocumentLinks(_data, realParent, [=] {
if (!_data->createMediaView()->canBePlayed(realParent)
|| !_data->isAnimation()
|| _data->isVideoMessage()
|| !CanPlayInline(_data)) {
return false;
}
playAnimation(false);
return true;
});
}
setStatusSize(Ui::FileStatusSizeReady); setStatusSize(Ui::FileStatusSizeReady);
if (_spoiler) { if (_spoiler) {
@ -403,7 +475,13 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
QRect rthumb(style::rtlrect(usex + paintx, painty, usew, painth, width())); QRect rthumb(style::rtlrect(usex + paintx, painty, usew, painth, width()));
const auto revealed = (!isRound && _spoiler) const auto inTTLViewer = _parent->delegate()->elementContext()
== Context::TTLViewer;
const auto revealed = (isRound
&& item->media()->ttlSeconds()
&& !inTTLViewer)
? 0
: (!isRound && _spoiler)
? _spoiler->revealAnimation.value(_spoiler->revealed ? 1. : 0.) ? _spoiler->revealAnimation.value(_spoiler->revealed ? 1. : 0.)
: 1.; : 1.;
const auto fullHiddenBySpoiler = (revealed == 0.); const auto fullHiddenBySpoiler = (revealed == 0.);
@ -525,10 +603,19 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
p.drawImage(rthumb, _thumbCache); p.drawImage(rthumb, _thumbCache);
} }
if (!isRound && revealed < 1.) { if (revealed < 1.) {
p.setOpacity(1. - revealed); p.setOpacity(1. - revealed);
p.drawImage(rthumb.topLeft(), _spoiler->background); if (!isRound) {
fillImageSpoiler(p, _spoiler.get(), rthumb, context); p.drawImage(rthumb.topLeft(), _spoiler->background);
fillImageSpoiler(p, _spoiler.get(), rthumb, context);
} else {
auto frame = _spoiler->background;
{
auto q = QPainter(&frame);
fillImageSpoiler(q, _spoiler.get(), rthumb, context);
}
p.drawImage(rthumb.topLeft(), Images::Circle(std::move(frame)));
}
p.setOpacity(1.); p.setOpacity(1.);
} }
if (context.selected()) { if (context.selected()) {
@ -793,6 +880,9 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
paintTranscribe(p, usex, fullBottom, false, context); paintTranscribe(p, usex, fullBottom, false, context);
} }
} }
if (_drawTtl) {
_drawTtl(p, rthumb, context);
}
} }
void Gif::paintTranscribe( void Gif::paintTranscribe(
@ -1108,7 +1198,9 @@ TextState Gif::textState(QPoint point, StateRequest request) const {
} }
if (QRect(usex + paintx, painty, usew, painth).contains(point)) { if (QRect(usex + paintx, painty, usew, painth).contains(point)) {
ensureDataMediaCreated(); ensureDataMediaCreated();
result.link = (_spoiler && !_spoiler->revealed) result.link = (isRound && _parent->data()->media()->ttlSeconds())
? _openl // Overriden.
: (_spoiler && !_spoiler->revealed)
? _spoiler->link ? _spoiler->link
: _data->uploading() : _data->uploading()
? _cancell ? _cancell
@ -1970,7 +2062,7 @@ bool Gif::needCornerStatusDisplay() const {
void Gif::ensureTranscribeButton() const { void Gif::ensureTranscribeButton() const {
if (_data->isVideoMessage() if (_data->isVideoMessage()
&& !IsVoiceOncePlayable(_parent->data()) && !_parent->data()->media()->ttlSeconds()
&& (_data->session().premium() && (_data->session().premium()
|| _data->session().api().transcribes().trialsSupport())) { || _data->session().api().transcribes().trialsSupport())) {
if (!_transcribe) { if (!_transcribe) {

View file

@ -40,6 +40,11 @@ namespace HistoryView {
class Reply; class Reply;
class TranscribeButton; class TranscribeButton;
using TtlRoundPaintCallback = Fn<void(
QPainter&,
QRect,
const PaintContext &context)>;
class Gif final : public File { class Gif final : public File {
public: public:
Gif( Gif(
@ -214,6 +219,8 @@ private:
void togglePollingStory(bool enabled) const; void togglePollingStory(bool enabled) const;
TtlRoundPaintCallback _drawTtl;
const not_null<DocumentData*> _data; const not_null<DocumentData*> _data;
const FullStoryId _storyId; const FullStoryId _storyId;
Ui::Text::String _caption; Ui::Text::String _caption;

View file

@ -536,6 +536,8 @@ historyVideoMessageMute: icon {{ "volume_mute", historyFileThumbIconFg }};
historyVideoMessageMuteSelected: icon {{ "volume_mute", historyFileThumbIconFgSelected }}; historyVideoMessageMuteSelected: icon {{ "volume_mute", historyFileThumbIconFgSelected }};
historyVideoMessageMuteSize: 25px; historyVideoMessageMuteSize: 25px;
historyVideoMessageProgressOpacity: 0.72; historyVideoMessageProgressOpacity: 0.72;
historyVideoMessageTtlIcon: icon {{ "chat/audio_once", historyFileThumbIconFg }};
historyVideoMessageTtlIconSelected: icon {{ "chat/audio_once", historyFileThumbIconFgSelected }};
historyAdminLogEmptyWidth: 260px; historyAdminLogEmptyWidth: 260px;
historyAdminLogEmptyPadding: margins(10px, 12px, 10px, 12px); historyAdminLogEmptyPadding: margins(10px, 12px, 10px, 12px);

View file

@ -528,6 +528,10 @@ ChatStyle::ChatStyle(rpl::producer<ColorIndicesCompressed> colorIndices) {
&MessageImageStyle::historyVideoMessageMute, &MessageImageStyle::historyVideoMessageMute,
st::historyVideoMessageMute, st::historyVideoMessageMute,
st::historyVideoMessageMuteSelected); st::historyVideoMessageMuteSelected);
make(
&MessageImageStyle::historyVideoMessageTtlIcon,
st::historyVideoMessageTtlIcon,
st::historyVideoMessageTtlIconSelected);
make( make(
&MessageImageStyle::historyPageEnlarge, &MessageImageStyle::historyPageEnlarge,
st::historyPageEnlarge, st::historyPageEnlarge,

View file

@ -118,6 +118,7 @@ struct MessageImageStyle {
style::icon historyVideoDownload = { Qt::Uninitialized }; style::icon historyVideoDownload = { Qt::Uninitialized };
style::icon historyVideoCancel = { Qt::Uninitialized }; style::icon historyVideoCancel = { Qt::Uninitialized };
style::icon historyVideoMessageMute = { Qt::Uninitialized }; style::icon historyVideoMessageMute = { Qt::Uninitialized };
style::icon historyVideoMessageTtlIcon = { Qt::Uninitialized };
style::icon historyPageEnlarge = { Qt::Uninitialized }; style::icon historyPageEnlarge = { Qt::Uninitialized };
}; };