diff --git a/Telegram/Resources/animations/voice_ttl_idle.tgs b/Telegram/Resources/animations/voice_ttl_idle.tgs new file mode 100644 index 0000000000..0166112981 Binary files /dev/null and b/Telegram/Resources/animations/voice_ttl_idle.tgs differ diff --git a/Telegram/Resources/animations/voice_ttl_start.tgs b/Telegram/Resources/animations/voice_ttl_start.tgs new file mode 100644 index 0000000000..835556dd0b Binary files /dev/null and b/Telegram/Resources/animations/voice_ttl_start.tgs differ diff --git a/Telegram/Resources/qrc/telegram/animations.qrc b/Telegram/Resources/qrc/telegram/animations.qrc index 705b508a24..76ea1ef4a3 100644 --- a/Telegram/Resources/qrc/telegram/animations.qrc +++ b/Telegram/Resources/qrc/telegram/animations.qrc @@ -11,5 +11,7 @@ ../../animations/ttl.tgs ../../animations/discussion.tgs ../../animations/stats.tgs + ../../animations/voice_ttl_idle.tgs + ../../animations/voice_ttl_start.tgs diff --git a/Telegram/SourceFiles/data/data_media_types.cpp b/Telegram/SourceFiles/data/data_media_types.cpp index 71e2929acc..e9c4dd66e8 100644 --- a/Telegram/SourceFiles/data/data_media_types.cpp +++ b/Telegram/SourceFiles/data/data_media_types.cpp @@ -1140,6 +1140,10 @@ crl::time MediaFile::ttlSeconds() const { return _ttlSeconds; } +bool MediaFile::allowsForward() const { + return !ttlSeconds(); +} + bool MediaFile::updateInlineResultMedia(const MTPMessageMedia &media) { if (media.type() != mtpc_messageMediaDocument) { return false; diff --git a/Telegram/SourceFiles/data/data_media_types.h b/Telegram/SourceFiles/data/data_media_types.h index 27d1718c1c..b2323af8a5 100644 --- a/Telegram/SourceFiles/data/data_media_types.h +++ b/Telegram/SourceFiles/data/data_media_types.h @@ -281,6 +281,7 @@ public: bool dropForwardedInfo() const override; bool hasSpoiler() const override; crl::time ttlSeconds() const override; + bool allowsForward() const override; bool updateInlineResultMedia(const MTPMessageMedia &media) override; bool updateSentMedia(const MTPMessageMedia &media) override; diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index df9f0f7518..f1d273d635 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/random.h" #include "lang/lang_keys.h" +#include "lottie/lottie_icon.h" #include "storage/localstorage.h" #include "main/main_session.h" #include "media/player/media_player_float.h" // Media::Player::RoundPainter. @@ -31,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/cached_round_corners.h" #include "ui/painter.h" #include "ui/power_saving.h" +#include "ui/rect.h" #include "ui/ui_utility.h" #include "data/data_session.h" #include "data/data_document.h" @@ -48,6 +50,52 @@ namespace { constexpr auto kAudioVoiceMsgUpdateView = crl::time(100); +[[nodiscard]] HistoryView::TtlPaintCallback CreateTtlPaintCallback( + std::shared_ptr lifetime, + Fn update) { + struct State final { + std::unique_ptr start; + std::unique_ptr idle; + }; + const auto iconSize = Size(std::min( + st::historyFileInPause.width(), + st::historyFileInPause.height())); + const auto state = lifetime->make_state(); + state->start = Lottie::MakeIcon({ + .name = u"voice_ttl_start"_q, + .color = &st::historyFileInIconFg, + .sizeOverride = iconSize, + }); + + const auto animateSingle = [=]( + not_null icon, + Fn next) { + auto callback = [=] { + update(); + if (icon->frameIndex() == icon->framesCount()) { + next(); + } + }; + icon->animate(std::move(callback), 0, icon->framesCount()); + }; + const auto animate = [=](auto reanimate) -> void { + animateSingle(state->idle.get(), [=] { reanimate(reanimate); }); + }; + animateSingle( + state->start.get(), + [=] { + state->idle = Lottie::MakeIcon({ + .name = u"voice_ttl_idle"_q, + .color = &st::historyFileInIconFg, + .sizeOverride = iconSize, + }); + animate(animate); + }); + return [=](QPainter &p, QRect r, QColor c) { + (state->idle ? state->idle : state->start)->paintInCenter(p, r, c); + }; +} + [[nodiscard]] bool OncePlayable(not_null item) { return !item->out() && item->media()->ttlSeconds(); } @@ -249,9 +297,11 @@ Document::Document( Ui::Text::WithEntities) }); if (lifetime) { + _drawTtl = nullptr; base::take(lifetime)->destroy(); } }, *lifetime); + _drawTtl = CreateTtlPaintCallback(lifetime, [=] { repaint(); }); return false; }); @@ -670,7 +720,9 @@ void Document::draw( : nullptr; const auto paintContent = [&](QPainter &q) { - if (previous && radialOpacity > 0. && radialOpacity < 1.) { + if (_drawTtl) { + _drawTtl(q, inner, context.st->historyFileInIconFg()->c); + } else if (previous && radialOpacity > 0. && radialOpacity < 1.) { PaintInterpolatedIcon(q, icon, *previous, radialOpacity, inner); } else { icon.paintInCenter(q, inner); diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.h b/Telegram/SourceFiles/history/view/media/history_view_document.h index 126a7c7778..5e57308ed5 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.h +++ b/Telegram/SourceFiles/history/view/media/history_view_document.h @@ -25,6 +25,8 @@ class String; namespace HistoryView { +using TtlPaintCallback = Fn; + class Document final : public File , public RuntimeComposer { @@ -178,6 +180,8 @@ private: mutable TooltipFilename _tooltipFilename; + TtlPaintCallback _drawTtl; + bool _transcribedRound = false; };