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 000000000..4d1f93652
Binary files /dev/null and b/Telegram/Resources/icons/chat/audio_once.png differ
diff --git a/Telegram/Resources/icons/chat/audio_once@2x.png b/Telegram/Resources/icons/chat/audio_once@2x.png
new file mode 100644
index 000000000..f66cfbbcb
Binary files /dev/null and b/Telegram/Resources/icons/chat/audio_once@2x.png differ
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 000000000..bce2481c5
Binary files /dev/null and b/Telegram/Resources/icons/chat/audio_once@3x.png differ
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 };
};