From 21dcb7b13c634044c4e9f325d31338a8e13e2938 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sun, 14 Jan 2024 03:49:09 +0300 Subject: [PATCH] Added initial ability to play video messages with ttl. --- .../Resources/art/ttl/video_message_icon.svg | 4 + Telegram/Resources/icons/chat/audio_once.png | Bin 0 -> 776 bytes .../Resources/icons/chat/audio_once@2x.png | Bin 0 -> 1426 bytes .../Resources/icons/chat/audio_once@3x.png | Bin 0 -> 2115 bytes Telegram/Resources/qrc/telegram/telegram.qrc | 1 + .../history/history_item_helpers.cpp | 4 - .../history/history_item_helpers.h | 1 - .../view/media/history_view_document.cpp | 2 +- .../history/view/media/history_view_gif.cpp | 124 +++++++++++++++--- .../history/view/media/history_view_gif.h | 7 + Telegram/SourceFiles/ui/chat/chat.style | 2 + Telegram/SourceFiles/ui/chat/chat_style.cpp | 4 + Telegram/SourceFiles/ui/chat/chat_style.h | 1 + 13 files changed, 128 insertions(+), 22 deletions(-) create mode 100644 Telegram/Resources/art/ttl/video_message_icon.svg create mode 100644 Telegram/Resources/icons/chat/audio_once.png create mode 100644 Telegram/Resources/icons/chat/audio_once@2x.png create mode 100644 Telegram/Resources/icons/chat/audio_once@3x.png diff --git a/Telegram/Resources/art/ttl/video_message_icon.svg b/Telegram/Resources/art/ttl/video_message_icon.svg new file mode 100644 index 000000000..aeadc8385 --- /dev/null +++ b/Telegram/Resources/art/ttl/video_message_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Telegram/Resources/icons/chat/audio_once.png b/Telegram/Resources/icons/chat/audio_once.png new file mode 100644 index 0000000000000000000000000000000000000000..4d1f93652302cd716fe27732e3c5dbe8aba3f60c GIT binary patch literal 776 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1SIoCSFHz9jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uv49!D1}S`GTDq2jfvL#T#WBP} zaBGNdww9yF)guZ*M~-McViz+@@=z3WQp#AUk)^n(b-@x((T-MEoi)xTEZVy#_zALb z|8I!sXl*TPYF*GF->dY<-C$OEP1@bq^1HA0a$6Tazf+u6{%-DWn|t<~E+_w~NH z;msVU$3;88RQ#tAsQnhY&DBN=Uc65^K{Hs}Ci*~*#u?i0l|H5(IYx(85^XFfd zcv&JfKY8=b42|bZrUw~~XY!ofwP#Pv+OVTZ6I(d=^?TeF-^}^;=uy*wy7W7oa}qX2 zc&JQ@=U934xdHdW0F40amIS%}=LyO>@o{kipQ`qLV6Di@%QKkfrP>qX9Hc$<)bZo) zHge(|+s-goS64@`zrLhk`hvq-1Q!Kpv|RsHW5<**fBSS+n;r{e>sH~rtG7vit+MSo z!LhtWHN!w+*=5aNf*aquZH?kxd^9QXVUg1cexXhI3UaT$fBhP&H$5^`#`4wo-!H5e z26%AU+uKjn+Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NG{7FPXR9Fe^SXn4`T@*HD4jIZE z$&i#GQs#Lolth{0Lbx;}TqsIOnKFcwF(o%jp$v(VL|hOVE@V!I%rbq?|DU&QpY!f_ zlGlInf9GoLwVt*1bJpHx@3oGK%HQWVGN7%kt)`~-8#6KI(9zL}kB{%@=$M|K-rU^0 zzP|qa{5(HD_w@8+;+3UTRaH$%Nf{j-eRy~P1M#Q1xmhr`y1KfrudlJOu|WR=!I5=8U<{+^haD3}Q;1OP8kRaK>@rzfy7hpJ31t#oj3=P?fBqErVmX=~iOY`B|^!4>yTU)_{1cBh>#|x zq@xTB3>X<1$>%CW`T6;6Y;17RK+e|IR)~-}#@F=m@xg^al8TFqWx7ZQXliOAyAu-= zX=!QFkqoQ1xA)`YBgf|D3SRk{+Bu5^;P34y3ra zxbpIHcXxNbMdAqQArrN?x3h5?8XA|EmmF?#a*_=a)4I92EiW&V=$J_i!cb^wX>nIF z9PjV%4Gatzpz!c;5;r0uf`Qx#FXl!IFD=QekM<^pB12+kt+}vE@45%>(p}@dE zp;^}WdxQ`b?_+IkO@|ll74Ahj16{<>P-V!+$H#)OqRQOT(vlc{lMtDd2qHpQ$S>7@ z*gvSKhzQYHp_h-aRFZ(Q1m6=KTttXoOM3Ze=#R^&bC3ue*#!j!B)EtW3U#8gx3?#< zQUw&HCMG6G5{?ftk%$m(-QC??PK%q8n3X3O8XDpxoy48ji;Ih2205hR;bG2E zVsXO{g4{ekJ#j8OJ3D+MHL9+zCKm|(1{8!XVwLf+TwGkB<6$HCTJ-#+|3nSLH&P=k z78+!Z)85`5$|%YxLqr2f_Jj=Rzh?C2V`F2rwY4%zo&5ZKlBB-AK6yeb7X!Ye%LFqt zAZB?~p3p!coDihQ*wxi_Wn~4S(EWV# zOv%g3Bby1r)YO!not+{aL|B|AB_$EYo)ihnNd-Q8VpZ*Njk63z%AT5R0Y(?he_+S>B*@exBQs6a{v z2M5XD88QJ@VSavoXlSUuz8?Q;LPJBv1H+NSqW}c#C$C7f$+&R{8>Wzzl_lV0V`GEU zZ+3R}8;ye?6np6J@88zec6fNmB-Gg0$aYgitEve23+v_Og|Z1hG4QJu4~k5%#Px>@ g=L_^#`hR5L4={7U!d34{WB>pF07*qoM6N<$f-Fvk6951J literal 0 HcmV?d00001 diff --git a/Telegram/Resources/icons/chat/audio_once@3x.png b/Telegram/Resources/icons/chat/audio_once@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..bce2481c5534a96ce9c1659f2e5b8becf9c2eb20 GIT binary patch literal 2115 zcmV-J2)y@+P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS?tw}^dRA>e5n@5NhO%Q;0U31Q2 zR?Ha{RLqF7tcnrLC`Lr_Vz>w-KbHc1`QgND_5>m zsZu3NmVEZ?+4}YCU%h%2lhC->rl+U3Z{L3Q?AeD8AO8IL^M7u?2M->UE?qh<4I<~; zuwlc63m4wMf8Wg(wQtz4VUa5kJ;QeG+U?%G`}gnPs`~nN|Ni}TdW;=A_Mbn$88c=S zDN;m-7H>Zv&%S;8^!mGxoIZWJP@zJunhh8*K+@d1cW>y>p{|&II>R^*=5p@bxie?Z zEL^y-hm7yvzu&!k_tvdjj~_q&_s{S4?c00z?)~xOhbz^N9Xo~(AFd1?KYo1l=+SUc z`lD}Fty=ZWnKN=~75Ln_b93g*>C&Z(x7kk3)~#Eou(FzO-@Y9*Xpj>>${xO`r%#`{ zivRfW0)vsUw_3PKJ%;{XPU_ofk212&P*RNllg6UkbVnxM@6%F)0hHKQQ zk)56G6k+u=ZQ9fakANskmo9b6`}OPB=FOWqhyyY+pm*rdf&J_hH+b-117*-*{De~s zTfbMYUO`#;#Lvjcm_L91&!0bSx!=Bht5vI(PjX*qef#!hWo!W!aP8W)diCo0qR#KAiSV)d3LU#1%QN^kgCr$)Col?Y>gc>+^#VW#x3Kc3OF!CbA4eI5~m(sBJ@836R z(j-M}A*>J1AhLJcqjm+e3B6mp%+_PuTWRzg7YSpT3*s#GqZ8-y( z^T3ypXIESVQNlo6C`sjNmS3pj56~lO|0v5V#F(GUP@Vpzp$k3z9#d zj~8*{#*HO5v%+@rBG8N}w}B%^j*ym`Rv}X*4%=r4f6^MguFUcGqn;!fQXhA~DuKw|ub z%%Kz)6h=L=j!&LEA=)Np@*-F2T~nq^@xl%=7RNb8%FI4>*>2RkrAA3BcJt;t-)Ygbz(!cpREy9tnF*yYQYCGxGf zZQC}fD)&7@&6>)pB$zd8mUbF~3`A=fZjd~u)br4xLy9^{Tahs(b(1>jM5*_XAw!g- z=-|PF62S!~?UDmTc~hrOm4*S2963@WB|vwdK7Du&0k=4AES^e7UV2w|>`PJ;TY@nvcxPOnZn+ zIR2EqWcP#y@MfWDZ9;q?i_a@MoIa0}bT49T`~<-ISlh;)7>FbBA_*C}1@R)lw#ov? zOMB(+a!b(=a<^>RqS!_-iQ^8zDz!*Rft){oUa^hBwCnvRwNy81!@);zsn|vxFsc~R zsKB^!x+qZ9*b4v9nI2%t29x=&) z$P$L1^L`3rQ&8Q!Cu|9YgfO1 z{mkWHjdTJoHk-{*0z?b3=P5V?ly6#U0L&{Y@0~f*iBq{*Y~8w*cMBdRQdUekTG;u#d~%tCSi6|TWy_X1i_6k5 zC(NPbG5v(2Z{ECt3YWWT)hgwh9IH7hb1H7UPf{`vPJ3jJ_dg}5jo>88moKkM%9S=j z7MD@-C9ZB-S_SO!Pl;Sn-j`5jdf>o;t5>fk>~h_u9{-f^CBQdQjBiD820TyZro)AR t4aSd0Bp&~i@U3$`V*U)|&p-;y!2gyI^B>FjSK$Bv002ovPDHLkV1mRq0BryO literal 0 HcmV?d00001 diff --git a/Telegram/Resources/qrc/telegram/telegram.qrc b/Telegram/Resources/qrc/telegram/telegram.qrc index 57afe3882..ccf1a1d7a 100644 --- a/Telegram/Resources/qrc/telegram/telegram.qrc +++ b/Telegram/Resources/qrc/telegram/telegram.qrc @@ -26,6 +26,7 @@ ../../art/recording/recording_info_audio.svg ../../art/recording/recording_info_video_landscape.svg ../../art/recording/recording_info_video_portrait.svg + ../../art/ttl/video_message_icon.svg ../../icons/settings/dino.svg ../../icons/settings/star.svg ../../icons/settings/starmini.svg diff --git a/Telegram/SourceFiles/history/history_item_helpers.cpp b/Telegram/SourceFiles/history/history_item_helpers.cpp index 4a29e4e93..a249195c9 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.cpp +++ b/Telegram/SourceFiles/history/history_item_helpers.cpp @@ -808,7 +808,3 @@ void ClearMediaAsExpired(not_null item) { } } } - -[[nodiscard]] bool IsVoiceOncePlayable(not_null item) { - return !item->out() && item->media()->ttlSeconds(); -} diff --git a/Telegram/SourceFiles/history/history_item_helpers.h b/Telegram/SourceFiles/history/history_item_helpers.h index f96d9c092..c438eccbe 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.h +++ b/Telegram/SourceFiles/history/history_item_helpers.h @@ -158,4 +158,3 @@ ClickHandlerPtr JumpToStoryClickHandler( void ShowTrialTranscribesToast(int left, TimeId until); void ClearMediaAsExpired(not_null item); -[[nodiscard]] bool IsVoiceOncePlayable(not_null item); diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 32763b683..cf5560009 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -425,7 +425,7 @@ void Document::createComponents(bool caption) { _realParent->fullId()); } if (const auto voice = Get()) { - voice->seekl = !IsVoiceOncePlayable(_parent->data()) + voice->seekl = !_parent->data()->media()->ttlSeconds() ? std::make_shared(_data, [](FullMsgId) {}) : nullptr; if (_transcribedRound) { diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index 87a0e00bf..6176bf050 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/view/media_view_playback_progress.h" #include "ui/boxes/confirm_box.h" #include "ui/painter.h" +#include "ui/rect.h" #include "history/history_item_components.h" #include "history/history_item_helpers.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_reply.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_spoiler.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 "styles/style_chat.h" +#include + namespace HistoryView { namespace { @@ -65,6 +69,41 @@ int gifMaxStatusWidth(DocumentData *document) { return result; } +[[nodiscard]] HistoryView::TtlRoundPaintCallback CreateTtlPaintCallback( + Fn 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( + 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 struct Gif::Streamed { @@ -83,6 +122,12 @@ Gif::Streamed::Streamed( : instance(std::move(shared), std::move(waitingCallback)) { } +[[nodiscard]] bool IsHiddenRoundMessage(not_null parent) { + return parent->delegate()->elementContext() != Context::TTLViewer + && parent->data()->media() + && parent->data()->media()->ttlSeconds(); +} + Gif::Gif( not_null parent, not_null realParent, @@ -95,18 +140,45 @@ Gif::Gif( : FullStoryId()) , _caption( st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) -, _spoiler(spoiler ? std::make_unique() : nullptr) +, _spoiler((spoiler || IsHiddenRoundMessage(_parent)) + ? std::make_unique() + : nullptr) , _downloadSize(Ui::FormatSizeText(_data->size)) { - setDocumentLinks(_data, realParent, [=] { - if (!_data->createMediaView()->canBePlayed(realParent) - || !_data->isAnimation() - || _data->isVideoMessage() - || !CanPlayInline(_data)) { - return false; + auto hasDefaultDocumentLinks = false; + if (_data->isVideoMessage() && _parent->data()->media()->ttlSeconds()) { + if (_spoiler) { + _drawTtl = CreateTtlPaintCallback([=] { repaint(); }); } - playAnimation(false); - return true; - }); + const auto fullId = _realParent->fullId(); + _parent->data()->removeFromSharedMediaIndex(); + setDocumentLinks(_data, realParent, [=] { + auto lifetime = std::make_shared(); + 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); 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())); - 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.) : 1.; const auto fullHiddenBySpoiler = (revealed == 0.); @@ -525,10 +603,19 @@ void Gif::draw(Painter &p, const PaintContext &context) const { p.drawImage(rthumb, _thumbCache); } - if (!isRound && revealed < 1.) { + if (revealed < 1.) { p.setOpacity(1. - revealed); - p.drawImage(rthumb.topLeft(), _spoiler->background); - fillImageSpoiler(p, _spoiler.get(), rthumb, context); + if (!isRound) { + 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.); } if (context.selected()) { @@ -793,6 +880,9 @@ void Gif::draw(Painter &p, const PaintContext &context) const { paintTranscribe(p, usex, fullBottom, false, context); } } + if (_drawTtl) { + _drawTtl(p, rthumb, context); + } } void Gif::paintTranscribe( @@ -1108,7 +1198,9 @@ TextState Gif::textState(QPoint point, StateRequest request) const { } if (QRect(usex + paintx, painty, usew, painth).contains(point)) { ensureDataMediaCreated(); - result.link = (_spoiler && !_spoiler->revealed) + result.link = (isRound && _parent->data()->media()->ttlSeconds()) + ? _openl // Overriden. + : (_spoiler && !_spoiler->revealed) ? _spoiler->link : _data->uploading() ? _cancell @@ -1970,7 +2062,7 @@ bool Gif::needCornerStatusDisplay() const { void Gif::ensureTranscribeButton() const { if (_data->isVideoMessage() - && !IsVoiceOncePlayable(_parent->data()) + && !_parent->data()->media()->ttlSeconds() && (_data->session().premium() || _data->session().api().transcribes().trialsSupport())) { if (!_transcribe) { diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.h b/Telegram/SourceFiles/history/view/media/history_view_gif.h index 1d1b30e4a..dad49b351 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.h +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.h @@ -40,6 +40,11 @@ namespace HistoryView { class Reply; class TranscribeButton; +using TtlRoundPaintCallback = Fn; + class Gif final : public File { public: Gif( @@ -214,6 +219,8 @@ private: void togglePollingStory(bool enabled) const; + TtlRoundPaintCallback _drawTtl; + const not_null _data; const FullStoryId _storyId; Ui::Text::String _caption; diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style index bc54f7366..378393643 100644 --- a/Telegram/SourceFiles/ui/chat/chat.style +++ b/Telegram/SourceFiles/ui/chat/chat.style @@ -536,6 +536,8 @@ historyVideoMessageMute: icon {{ "volume_mute", historyFileThumbIconFg }}; historyVideoMessageMuteSelected: icon {{ "volume_mute", historyFileThumbIconFgSelected }}; historyVideoMessageMuteSize: 25px; historyVideoMessageProgressOpacity: 0.72; +historyVideoMessageTtlIcon: icon {{ "chat/audio_once", historyFileThumbIconFg }}; +historyVideoMessageTtlIconSelected: icon {{ "chat/audio_once", historyFileThumbIconFgSelected }}; historyAdminLogEmptyWidth: 260px; historyAdminLogEmptyPadding: margins(10px, 12px, 10px, 12px); diff --git a/Telegram/SourceFiles/ui/chat/chat_style.cpp b/Telegram/SourceFiles/ui/chat/chat_style.cpp index 0fc4840f1..4acf416ba 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.cpp +++ b/Telegram/SourceFiles/ui/chat/chat_style.cpp @@ -528,6 +528,10 @@ ChatStyle::ChatStyle(rpl::producer colorIndices) { &MessageImageStyle::historyVideoMessageMute, st::historyVideoMessageMute, st::historyVideoMessageMuteSelected); + make( + &MessageImageStyle::historyVideoMessageTtlIcon, + st::historyVideoMessageTtlIcon, + st::historyVideoMessageTtlIconSelected); make( &MessageImageStyle::historyPageEnlarge, st::historyPageEnlarge, diff --git a/Telegram/SourceFiles/ui/chat/chat_style.h b/Telegram/SourceFiles/ui/chat/chat_style.h index 45a4f3caf..11890a061 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.h +++ b/Telegram/SourceFiles/ui/chat/chat_style.h @@ -118,6 +118,7 @@ struct MessageImageStyle { style::icon historyVideoDownload = { Qt::Uninitialized }; style::icon historyVideoCancel = { Qt::Uninitialized }; style::icon historyVideoMessageMute = { Qt::Uninitialized }; + style::icon historyVideoMessageTtlIcon = { Qt::Uninitialized }; style::icon historyPageEnlarge = { Qt::Uninitialized }; };