Preview lottie animations in media viewer.

This commit is contained in:
John Preston 2019-04-29 17:08:09 +04:00
parent 22c2054dcf
commit f073963582
3 changed files with 86 additions and 16 deletions

View File

@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image_source.h" #include "ui/image/image_source.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "core/application.h" #include "core/application.h"
#include "lottie/lottie_animation.h"
#include "media/streaming/media_streaming_loader_mtproto.h" #include "media/streaming/media_streaming_loader_mtproto.h"
#include "media/streaming/media_streaming_loader_local.h" #include "media/streaming/media_streaming_loader_local.h"
@ -302,7 +303,11 @@ void DocumentOpenClickHandler::Open(
const auto guard = gsl::finally([&] { const auto guard = gsl::finally([&] {
location.accessDisable(); location.accessDisable();
}); });
if (QImageReader(location.name()).canRead()) { const auto path = location.name();
if (QImageReader(path).canRead()) {
Core::App().showDocument(data, context);
return;
} else if (Lottie::ValidateFile(path)) {
Core::App().showDocument(data, context); Core::App().showDocument(data, context);
return; return;
} }

View File

@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/streaming/media_streaming_player.h" #include "media/streaming/media_streaming_player.h"
#include "media/streaming/media_streaming_loader.h" #include "media/streaming/media_streaming_loader.h"
#include "media/player/media_player_instance.h" #include "media/player/media_player_instance.h"
#include "lottie/lottie_animation.h"
#include "history/history.h" #include "history/history.h"
#include "history/history_message.h" #include "history/history_message.h"
#include "data/data_media_types.h" #include "data/data_media_types.h"
@ -126,6 +127,21 @@ void PaintImageProfile(QPainter &p, const QImage &image, QRect rect, QRect fill)
}); });
} }
QPixmap PrepareStaticImage(const QString &path) {
auto image = App::readImage(path, nullptr, false);
#if defined Q_OS_MAC && !defined OS_MAC_OLD
if (image.width() > kMaxDisplayImageSize
|| image.height() > kMaxDisplayImageSize) {
image = image.scaled(
kMaxDisplayImageSize,
kMaxDisplayImageSize,
Qt::KeepAspectRatio,
Qt::SmoothTransformation);
}
#endif // Q_OS_MAC && !OS_MAC_OLD
return App::pixmapFromImageInPlace(std::move(image));
}
} // namespace } // namespace
struct OverlayWidget::SharedMedia { struct OverlayWidget::SharedMedia {
@ -175,6 +191,16 @@ struct OverlayWidget::Streamed {
bool resumeOnCallEnd = false; bool resumeOnCallEnd = false;
}; };
struct OverlayWidget::LottieFile {
template <typename Callback>
LottieFile(
std::unique_ptr<Lottie::Animation> data,
Callback &&animationCallback);
std::unique_ptr<Lottie::Animation> data;
Ui::Animations::Basic animation;
};
template <typename Callback> template <typename Callback>
OverlayWidget::Streamed::Streamed( OverlayWidget::Streamed::Streamed(
not_null<Data::Session*> owner, not_null<Data::Session*> owner,
@ -189,6 +215,14 @@ OverlayWidget::Streamed::Streamed(
st::mediaviewStreamingRadial) { st::mediaviewStreamingRadial) {
} }
template <typename Callback>
OverlayWidget::LottieFile::LottieFile(
std::unique_ptr<Lottie::Animation> data,
Callback &&animationCallback)
: data(std::move(data))
, animation(std::forward<Callback>(animationCallback)) {
}
OverlayWidget::OverlayWidget() OverlayWidget::OverlayWidget()
: OverlayParent(nullptr) : OverlayParent(nullptr)
, _transparentBrush(style::transparentPlaceholderBrush()) , _transparentBrush(style::transparentPlaceholderBrush())
@ -401,7 +435,11 @@ bool OverlayWidget::documentContentShown() const {
bool OverlayWidget::documentBubbleShown() const { bool OverlayWidget::documentBubbleShown() const {
return (!_photo && !_doc) return (!_photo && !_doc)
|| (_doc && !_themePreviewShown && _current.isNull() && !_streamed); || (_doc
&& !_themePreviewShown
&& !_streamed
&& !_lottie
&& _current.isNull());
} }
void OverlayWidget::clearStreaming() { void OverlayWidget::clearStreaming() {
@ -409,6 +447,10 @@ void OverlayWidget::clearStreaming() {
_streamed = nullptr; _streamed = nullptr;
} }
void OverlayWidget::clearLottie() {
_lottie = nullptr;
}
void OverlayWidget::documentUpdated(DocumentData *doc) { void OverlayWidget::documentUpdated(DocumentData *doc) {
if (documentBubbleShown() && _doc && _doc == doc) { if (documentBubbleShown() && _doc && _doc == doc) {
if ((_doc->loading() && _docCancel->isHidden()) || (!_doc->loading() && !_docCancel->isHidden())) { if ((_doc->loading() && _docCancel->isHidden()) || (!_doc->loading() && !_docCancel->isHidden())) {
@ -927,6 +969,7 @@ void OverlayWidget::clearData() {
_animationOpacities.clear(); _animationOpacities.clear();
} }
clearStreaming(); clearStreaming();
clearLottie();
delete _menu; delete _menu;
_menu = nullptr; _menu = nullptr;
setContext(std::nullopt); setContext(std::nullopt);
@ -1721,6 +1764,7 @@ void OverlayWidget::displayPhoto(not_null<PhotoData*> photo, HistoryItem *item)
} }
clearStreaming(); clearStreaming();
clearLottie();
destroyThemePreview(); destroyThemePreview();
_doc = nullptr; _doc = nullptr;
_fullScreenVideo = false; _fullScreenVideo = false;
@ -1772,6 +1816,7 @@ void OverlayWidget::displayDocument(DocumentData *doc, HistoryItem *item) {
_fullScreenVideo = false; _fullScreenVideo = false;
_current = QPixmap(); _current = QPixmap();
clearStreaming(); clearStreaming();
clearLottie();
destroyThemePreview(); destroyThemePreview();
_doc = doc; _doc = doc;
_photo = nullptr; _photo = nullptr;
@ -1801,19 +1846,14 @@ void OverlayWidget::displayDocument(DocumentData *doc, HistoryItem *item) {
} else { } else {
auto &location = _doc->location(true); auto &location = _doc->location(true);
if (location.accessEnable()) { if (location.accessEnable()) {
if (QImageReader(location.name()).canRead()) { const auto &path = location.name();
auto image = App::readImage(location.name(), nullptr, false); if (QImageReader(path).canRead()) {
#if defined Q_OS_MAC && !defined OS_MAC_OLD _current = PrepareStaticImage(path);
if (image.width() > kMaxDisplayImageSize } else if (auto lottie = Lottie::FromFile(path)) {
|| image.height() > kMaxDisplayImageSize) { _lottie = std::make_unique<LottieFile>(
image = image.scaled( std::move(lottie),
kMaxDisplayImageSize, [=] { update(); });
kMaxDisplayImageSize, _lottie->animation.start();
Qt::KeepAspectRatio,
Qt::SmoothTransformation);
}
#endif // Q_OS_MAC && !OS_MAC_OLD
_current = App::pixmapFromImageInPlace(std::move(image));
} }
} }
location.accessDisable(); location.accessDisable();
@ -2513,6 +2553,8 @@ void OverlayWidget::paintEvent(QPaintEvent *e) {
} }
} else if (_themePreviewShown) { } else if (_themePreviewShown) {
paintThemePreview(p, r); paintThemePreview(p, r);
} else if (_lottie) {
paintLottieFrame(p, r);
} else if (documentBubbleShown()) { } else if (documentBubbleShown()) {
if (_docRect.intersects(r)) { if (_docRect.intersects(r)) {
p.fillRect(_docRect, st::mediaviewFileBg); p.fillRect(_docRect, st::mediaviewFileBg);
@ -2879,6 +2921,19 @@ void OverlayWidget::paintThemePreview(Painter &p, QRect clip) {
} }
} }
void OverlayWidget::paintLottieFrame(Painter &p, QRect clip) {
Expects(_lottie != nullptr);
const auto frame = _lottie->data->frame(crl::now());
if (!frame.isNull()) {
const auto x = (width() - frame.width()) / 2;
const auto y = (height() - frame.height()) / 2;
const auto background = _lottieDark ? Qt::black : Qt::white;
p.fillRect(x, y, frame.width(), frame.height(), background);
p.drawImage(x, y, frame);
}
}
void OverlayWidget::keyPressEvent(QKeyEvent *e) { void OverlayWidget::keyPressEvent(QKeyEvent *e) {
const auto ctrl = e->modifiers().testFlag(Qt::ControlModifier); const auto ctrl = e->modifiers().testFlag(Qt::ControlModifier);
if (_streamed) { if (_streamed) {
@ -2931,6 +2986,9 @@ void OverlayWidget::keyPressEvent(QKeyEvent *e) {
zoomOut(); zoomOut();
} else if (e->key() == Qt::Key_0) { } else if (e->key() == Qt::Key_0) {
zoomReset(); zoomReset();
} else if (e->key() == Qt::Key_I) {
_lottieDark = !_lottieDark;
update();
} }
} }
} }
@ -3124,6 +3182,7 @@ bool OverlayWidget::moveToEntity(const Entity &entity, int preloadDelta) {
setContext(std::nullopt); setContext(std::nullopt);
} }
clearStreaming(); clearStreaming();
clearLottie();
_streamingStartPaused = false; _streamingStartPaused = false;
if (auto photo = base::get_if<not_null<PhotoData*>>(&entity.data)) { if (auto photo = base::get_if<not_null<PhotoData*>>(&entity.data)) {
displayPhoto(*photo, entity.item); displayPhoto(*photo, entity.item);
@ -3614,6 +3673,7 @@ void OverlayWidget::setVisibleHook(bool visible) {
QCoreApplication::instance()->removeEventFilter(this); QCoreApplication::instance()->removeEventFilter(this);
clearStreaming(); clearStreaming();
clearLottie();
destroyThemePreview(); destroyThemePreview();
_radial.stop(); _radial.stop();
_current = QPixmap(); _current = QPixmap();

View File

@ -32,7 +32,6 @@ namespace Notify {
struct PeerUpdate; struct PeerUpdate;
} // namespace Notify } // namespace Notify
namespace Media { namespace Media {
namespace Player { namespace Player {
struct TrackState; struct TrackState;
@ -121,6 +120,7 @@ private slots:
private: private:
struct Streamed; struct Streamed;
struct LottieFile;
enum OverState { enum OverState {
OverNone, OverNone,
@ -314,6 +314,9 @@ private:
void paintTransformedVideoFrame(Painter &p); void paintTransformedVideoFrame(Painter &p);
void clearStreaming(); void clearStreaming();
void paintLottieFrame(Painter &p, QRect clip);
void clearLottie();
QBrush _transparentBrush; QBrush _transparentBrush;
PhotoData *_photo = nullptr; PhotoData *_photo = nullptr;
@ -362,6 +365,8 @@ private:
bool _blurred = true; bool _blurred = true;
std::unique_ptr<Streamed> _streamed; std::unique_ptr<Streamed> _streamed;
std::unique_ptr<LottieFile> _lottie;
bool _lottieDark = false;
const style::icon *_docIcon = nullptr; const style::icon *_docIcon = nullptr;
style::color _docIconColor; style::color _docIconColor;