mirror of https://github.com/procxx/kepka.git
Preview lottie animations in media viewer.
This commit is contained in:
parent
22c2054dcf
commit
f073963582
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue