Animate inline path thumbnails with sliding gradient.

This commit is contained in:
John Preston 2021-07-02 18:29:13 +03:00
parent 22d23c8be1
commit b22e2ffe1d
27 changed files with 258 additions and 39 deletions

View file

@ -399,7 +399,7 @@ BackgroundPreviewBox::BackgroundPreviewBox(
QWidget*, QWidget*,
not_null<Window::SessionController*> controller, not_null<Window::SessionController*> controller,
const Data::WallPaper &paper) const Data::WallPaper &paper)
: SimpleElementDelegate(controller) : SimpleElementDelegate(controller, [=] { update(); })
, _controller(controller) , _controller(controller)
, _text1(GenerateTextItem( , _text1(GenerateTextItem(
delegate(), delegate(),

View file

@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image.h" #include "ui/image/image.h"
#include "ui/image/image_location_factory.h" #include "ui/image/image_location_factory.h"
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/effects/path_shift_gradient.h"
#include "ui/emoji_config.h" #include "ui/emoji_config.h"
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
@ -128,6 +129,8 @@ private:
TimeId _setInstallDate = TimeId(0); TimeId _setInstallDate = TimeId(0);
ImageWithLocation _setThumbnail; ImageWithLocation _setThumbnail;
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
MTPInputStickerSet _input; MTPInputStickerSet _input;
mtpRequestId _installRequest = 0; mtpRequestId _installRequest = 0;
@ -328,6 +331,10 @@ StickerSetBox::Inner::Inner(
: RpWidget(parent) : RpWidget(parent)
, _controller(controller) , _controller(controller)
, _api(&_controller->session().mtp()) , _api(&_controller->session().mtp())
, _pathGradient(std::make_unique<Ui::PathShiftGradient>(
st::windowBgRipple,
st::windowBgOver,
[=] { update(); }))
, _input(set) , _input(set)
, _previewTimer([=] { showPreview(); }) { , _previewTimer([=] { showPreview(); }) {
set.match([&](const MTPDinputStickerSetID &data) { set.match([&](const MTPDinputStickerSetID &data) {
@ -652,6 +659,8 @@ void StickerSetBox::Inner::paintEvent(QPaintEvent *e) {
+ ((_elements.size() % kStickersPanelPerRow) ? 1 : 0); + ((_elements.size() % kStickersPanelPerRow) ? 1 : 0);
int32 from = qFloor(e->rect().top() / st::stickersSize.height()), to = qFloor(e->rect().bottom() / st::stickersSize.height()) + 1; int32 from = qFloor(e->rect().top() / st::stickersSize.height()), to = qFloor(e->rect().bottom() / st::stickersSize.height()) + 1;
_pathGradient->startFrame(0, width(), width() / 2);
for (int32 i = from; i < to; ++i) { for (int32 i = from; i < to; ++i) {
for (int32 j = 0; j < kStickersPanelPerRow; ++j) { for (int32 j = 0; j < kStickersPanelPerRow; ++j) {
int32 index = i * kStickersPanelPerRow + j; int32 index = i * kStickersPanelPerRow + j;
@ -747,7 +756,8 @@ void StickerSetBox::Inner::paintSticker(
const auto &media = element.documentMedia; const auto &media = element.documentMedia;
media->checkStickerSmall(); media->checkStickerSmall();
if (document->sticker()->animated const auto isAnimated = document->sticker()->animated;
if (isAnimated
&& !element.animated && !element.animated
&& media->loaded()) { && media->loaded()) {
const_cast<Inner*>(this)->setupLottie(index); const_cast<Inner*>(this)->setupLottie(index);
@ -755,7 +765,7 @@ void StickerSetBox::Inner::paintSticker(
auto w = 1; auto w = 1;
auto h = 1; auto h = 1;
if (element.animated && !document->dimensions.isEmpty()) { if (isAnimated && !document->dimensions.isEmpty()) {
const auto request = Lottie::FrameRequest{ boundingBoxSize() * cIntRetinaFactor() }; const auto request = Lottie::FrameRequest{ boundingBoxSize() * cIntRetinaFactor() };
const auto size = request.size(document->dimensions, true) / cIntRetinaFactor(); const auto size = request.size(document->dimensions, true) / cIntRetinaFactor();
w = std::max(size.width(), 1); w = std::max(size.width(), 1);
@ -767,6 +777,16 @@ void StickerSetBox::Inner::paintSticker(
h = std::max(qRound(coef * document->dimensions.height()), 1); h = std::max(qRound(coef * document->dimensions.height()), 1);
} }
QPoint ppos = position + QPoint((st::stickersSize.width() - w) / 2, (st::stickersSize.height() - h) / 2); QPoint ppos = position + QPoint((st::stickersSize.width() - w) / 2, (st::stickersSize.height() - h) / 2);
ChatHelpers::PaintStickerThumbnailPath(
p,
media.get(),
QRect(ppos, QSize(w, h)),
_pathGradient.get());
return; AssertIsDebug();
if (element.animated && element.animated->ready()) { if (element.animated && element.animated->ready()) {
const auto frame = element.animated->frame(); const auto frame = element.animated->frame();
p.drawImage( p.drawImage(
@ -784,7 +804,7 @@ void StickerSetBox::Inner::paintSticker(
p, p,
media.get(), media.get(),
QRect(ppos, QSize(w, h)), QRect(ppos, QSize(w, h)),
st::windowBgRipple->c); _pathGradient.get());
} }
} }

View file

@ -30,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "ui/widgets/input_fields.h" #include "ui/widgets/input_fields.h"
#include "ui/image/image.h" #include "ui/image/image.h"
#include "ui/effects/path_shift_gradient.h"
#include "ui/ui_utility.h" #include "ui/ui_utility.h"
#include "ui/cached_round_corners.h" #include "ui/cached_round_corners.h"
#include "base/unixtime.h" #include "base/unixtime.h"
@ -125,6 +126,8 @@ private:
bool _isOneColumn = false; bool _isOneColumn = false;
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
Fn<SendMenu::Type()> _sendMenuType; Fn<SendMenu::Type()> _sendMenuType;
rpl::event_stream<FieldAutocomplete::MentionChosen> _mentionChosen; rpl::event_stream<FieldAutocomplete::MentionChosen> _mentionChosen;
@ -738,6 +741,10 @@ FieldAutocomplete::Inner::Inner(
, _hrows(hrows) , _hrows(hrows)
, _brows(brows) , _brows(brows)
, _srows(srows) , _srows(srows)
, _pathGradient(std::make_unique<Ui::PathShiftGradient>(
st::windowBgRipple,
st::windowBgOver,
[=] { update(); }))
, _previewTimer([=] { showPreview(); }) { , _previewTimer([=] { showPreview(); }) {
controller->session().downloaderTaskFinished( controller->session().downloaderTaskFinished(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
@ -770,6 +777,11 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) {
- st::defaultScrollArea.width; - st::defaultScrollArea.width;
if (!_srows->empty()) { if (!_srows->empty()) {
_pathGradient->startFrame(
0,
width(),
std::min(st::msgMaxWidth / 2, width() / 2));
int32 rows = rowscount(_srows->size(), _stickersPerRow); int32 rows = rowscount(_srows->size(), _stickersPerRow);
int32 fromrow = floorclamp(r.y() - st::stickerPanPadding, st::stickerPanSize.height(), 0, rows); int32 fromrow = floorclamp(r.y() - st::stickerPanPadding, st::stickerPanSize.height(), 0, rows);
int32 torow = ceilclamp(r.y() + r.height() - st::stickerPanPadding, st::stickerPanSize.height(), 0, rows); int32 torow = ceilclamp(r.y() + r.height() - st::stickerPanPadding, st::stickerPanSize.height(), 0, rows);
@ -815,6 +827,17 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) {
w = std::max(qRound(coef * document->dimensions.width()), 1); w = std::max(qRound(coef * document->dimensions.width()), 1);
h = std::max(qRound(coef * document->dimensions.height()), 1); h = std::max(qRound(coef * document->dimensions.height()), 1);
} }
QPoint ppos = pos + QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
ChatHelpers::PaintStickerThumbnailPath(
p,
media.get(),
QRect(ppos, QSize(w, h)),
_pathGradient.get());
continue; AssertIsDebug();
if (sticker.animated && sticker.animated->ready()) { if (sticker.animated && sticker.animated->ready()) {
const auto frame = sticker.animated->frame(); const auto frame = sticker.animated->frame();
const auto size = frame.size() / cIntRetinaFactor(); const auto size = frame.size() / cIntRetinaFactor();
@ -838,7 +861,7 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) {
p, p,
media.get(), media.get(),
QRect(ppos, QSize(w, h)), QRect(ppos, QSize(w, h)),
st::windowBgRipple->c); _pathGradient.get());
} }
} }
} }

View file

@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "ui/effects/animations.h" #include "ui/effects/animations.h"
#include "ui/effects/ripple_animation.h" #include "ui/effects/ripple_animation.h"
#include "ui/effects/path_shift_gradient.h"
#include "ui/image/image.h" #include "ui/image/image.h"
#include "ui/cached_round_corners.h" #include "ui/cached_round_corners.h"
#include "lottie/lottie_multi_player.h" #include "lottie/lottie_multi_player.h"
@ -899,6 +900,10 @@ StickersListWidget::StickersListWidget(
: Inner(parent, controller) : Inner(parent, controller)
, _api(&controller->session().mtp()) , _api(&controller->session().mtp())
, _section(Section::Stickers) , _section(Section::Stickers)
, _pathGradient(std::make_unique<Ui::PathShiftGradient>(
st::windowBgRipple,
st::windowBgOver,
[=] { update(); }))
, _megagroupSetAbout(st::columnMinimalWidthThird - st::emojiScroll.width - st::emojiPanHeaderLeft) , _megagroupSetAbout(st::columnMinimalWidthThird - st::emojiScroll.width - st::emojiPanHeaderLeft)
, _addText(tr::lng_stickers_featured_add(tr::now).toUpper()) , _addText(tr::lng_stickers_featured_add(tr::now).toUpper())
, _addWidth(st::stickersTrendingAdd.font->width(_addText)) , _addWidth(st::stickersTrendingAdd.font->width(_addText))
@ -1531,6 +1536,8 @@ void StickersListWidget::paintStickers(Painter &p, QRect clip) {
toColumn = _columnCount - toColumn; toColumn = _columnCount - toColumn;
} }
_pathGradient->startFrame(0, width(), width() / 2);
auto &sets = shownSets(); auto &sets = shownSets();
auto selectedSticker = std::get_if<OverSticker>(&_selected); auto selectedSticker = std::get_if<OverSticker>(&_selected);
auto selectedButton = std::get_if<OverButton>(!v::is_null(_pressed) auto selectedButton = std::get_if<OverButton>(!v::is_null(_pressed)
@ -1889,6 +1896,16 @@ void StickersListWidget::paintSticker(Painter &p, Set &set, int y, int section,
h = std::max(qRound(coef * document->dimensions.height()), 1); h = std::max(qRound(coef * document->dimensions.height()), 1);
} }
auto ppos = pos + QPoint((_singleSize.width() - w) / 2, (_singleSize.height() - h) / 2); auto ppos = pos + QPoint((_singleSize.width() - w) / 2, (_singleSize.height() - h) / 2);
PaintStickerThumbnailPath(
p,
media.get(),
QRect(ppos, QSize{ w, h }),
_pathGradient.get());
return; AssertIsDebug();
if (sticker.animated && sticker.animated->ready()) { if (sticker.animated && sticker.animated->ready()) {
auto request = Lottie::FrameRequest(); auto request = Lottie::FrameRequest();
request.box = boundingBoxSize() * cIntRetinaFactor(); request.box = boundingBoxSize() * cIntRetinaFactor();
@ -1923,7 +1940,7 @@ void StickersListWidget::paintSticker(Painter &p, Set &set, int y, int section,
p, p,
media.get(), media.get(),
QRect(ppos, QSize{ w, h }), QRect(ppos, QSize{ w, h }),
st::windowBgRipple->c); _pathGradient.get());
} }
} }

View file

@ -25,6 +25,7 @@ class LinkButton;
class PopupMenu; class PopupMenu;
class RippleAnimation; class RippleAnimation;
class BoxContent; class BoxContent;
class PathShiftGradient;
} // namespace Ui } // namespace Ui
namespace Lottie { namespace Lottie {
@ -361,6 +362,8 @@ private:
OverState _pressed; OverState _pressed;
QPoint _lastMousePosition; QPoint _lastMousePosition;
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
Ui::Text::String _megagroupSetAbout; Ui::Text::String _megagroupSetAbout;
QString _megagroupSetButtonText; QString _megagroupSetButtonText;
int _megagroupSetButtonTextWidth = 0; int _megagroupSetButtonTextWidth = 0;

View file

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_file_origin.h" #include "data/data_file_origin.h"
#include "storage/cache/storage_cache_database.h" #include "storage/cache/storage_cache_database.h"
#include "ui/effects/path_shift_gradient.h"
#include "main/main_session.h" #include "main/main_session.h"
namespace ChatHelpers { namespace ChatHelpers {
@ -192,17 +193,25 @@ bool PaintStickerThumbnailPath(
QPainter &p, QPainter &p,
not_null<Data::DocumentMedia*> media, not_null<Data::DocumentMedia*> media,
QRect target, QRect target,
QColor fg) { QLinearGradient *gradient) {
const auto &path = media->thumbnailPath(); const auto &path = media->thumbnailPath();
const auto dimensions = media->owner()->dimensions; const auto dimensions = media->owner()->dimensions;
if (path.isEmpty() || dimensions.isEmpty()) { if (path.isEmpty() || dimensions.isEmpty() || target.isEmpty()) {
return false; return false;
} }
p.save(); p.save();
auto hq = PainterHighQualityEnabler(p); auto hq = PainterHighQualityEnabler(p);
p.setBrush(fg);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.translate(target.topLeft()); p.translate(target.topLeft());
if (gradient) {
const auto scale = dimensions.width() / float64(target.width());
const auto shift = p.worldTransform().dx();
gradient->setStart((gradient->start().x() - shift) * scale, 0);
gradient->setFinalStop(
(gradient->finalStop().x() - shift) * scale,
0);
p.setBrush(*gradient);
}
p.scale( p.scale(
target.width() / float64(dimensions.width()), target.width() / float64(dimensions.width()),
target.height() / float64(dimensions.height())); target.height() / float64(dimensions.height()));
@ -211,4 +220,19 @@ bool PaintStickerThumbnailPath(
return true; return true;
} }
bool PaintStickerThumbnailPath(
QPainter &p,
not_null<Data::DocumentMedia*> media,
QRect target,
not_null<Ui::PathShiftGradient*> gradient) {
return gradient->paint([&](const Ui::PathShiftGradient::Background &bg) {
if (const auto color = std::get_if<style::color>(&bg)) {
p.setBrush(*color);
return PaintStickerThumbnailPath(p, media, target);
}
const auto gradient = v::get<QLinearGradient*>(bg);
return PaintStickerThumbnailPath(p, media, target, gradient);
});
}
} // namespace ChatHelpers } // namespace ChatHelpers

View file

@ -26,6 +26,10 @@ namespace Main {
class Session; class Session;
} // namespace Main } // namespace Main
namespace Ui {
class PathShiftGradient;
} // namespace Ui
namespace Data { namespace Data {
class DocumentMedia; class DocumentMedia;
class StickersSetThumbnailView; class StickersSetThumbnailView;
@ -75,6 +79,12 @@ bool PaintStickerThumbnailPath(
QPainter &p, QPainter &p,
not_null<Data::DocumentMedia*> media, not_null<Data::DocumentMedia*> media,
QRect target, QRect target,
QColor fg); QLinearGradient *gradient = nullptr);
bool PaintStickerThumbnailPath(
QPainter &p,
not_null<Data::DocumentMedia*> media,
QRect target,
not_null<Ui::PathShiftGradient*> gradient);
} // namespace ChatHelpers } // namespace ChatHelpers

View file

@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image.h" #include "ui/image/image.h"
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/inactive_press.h" #include "ui/inactive_press.h"
#include "ui/effects/path_shift_gradient.h"
#include "core/file_utilities.h" #include "core/file_utilities.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "boxes/peers/edit_participant_box.h" #include "boxes/peers/edit_participant_box.h"
@ -234,6 +235,7 @@ InnerWidget::InnerWidget(
, _channel(channel) , _channel(channel)
, _history(channel->owner().history(channel)) , _history(channel->owner().history(channel))
, _api(&_channel->session().mtp()) , _api(&_channel->session().mtp())
, _pathGradient(HistoryView::MakePathShiftGradient([=] { update(); }))
, _scrollDateCheck([=] { scrollDateCheck(); }) , _scrollDateCheck([=] { scrollDateCheck(); })
, _emptyText( , _emptyText(
st::historyAdminLogEmptyWidth st::historyAdminLogEmptyWidth
@ -651,6 +653,10 @@ bool InnerWidget::elementIsChatWide() {
return _controller->adaptive().isChatWide(); return _controller->adaptive().isChatWide();
} }
not_null<Ui::PathShiftGradient*> InnerWidget::elementPathShiftGradient() {
return _pathGradient.get();
}
void InnerWidget::saveState(not_null<SectionMemento*> memento) { void InnerWidget::saveState(not_null<SectionMemento*> memento) {
memento->setFilter(std::move(_filter)); memento->setFilter(std::move(_filter));
memento->setAdmins(std::move(_admins)); memento->setAdmins(std::move(_admins));
@ -892,6 +898,11 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
if (_items.empty() && _upLoaded && _downLoaded) { if (_items.empty() && _upLoaded && _downLoaded) {
paintEmpty(p); paintEmpty(p);
} else { } else {
_pathGradient->startFrame(
0,
width(),
std::min(st::msgMaxWidth / 2, width() / 2));
auto begin = std::rbegin(_items), end = std::rend(_items); auto begin = std::rbegin(_items), end = std::rend(_items);
auto from = std::lower_bound(begin, end, clip.top(), [this](auto &elem, int top) { auto from = std::lower_bound(begin, end, clip.top(), [this](auto &elem, int top) {
return this->itemTop(elem) + elem->height() <= top; return this->itemTop(elem) + elem->height() <= top;

View file

@ -129,6 +129,7 @@ public:
const FullMsgId &context) override; const FullMsgId &context) override;
void elementHandleViaClick(not_null<UserData*> bot) override; void elementHandleViaClick(not_null<UserData*> bot) override;
bool elementIsChatWide() override; bool elementIsChatWide() override;
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
~InnerWidget(); ~InnerWidget();
@ -248,6 +249,8 @@ private:
const not_null<History*> _history; const not_null<History*> _history;
MTP::Sender _api; MTP::Sender _api;
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
std::vector<OwnedItem> _items; std::vector<OwnedItem> _items;
std::set<uint64> _eventIds; std::set<uint64> _eventIds;
std::map<not_null<const HistoryItem*>, not_null<Element*>> _itemsByData; std::map<not_null<const HistoryItem*>, not_null<Element*>> _itemsByData;

View file

@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "ui/image/image.h" #include "ui/image/image.h"
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
#include "ui/effects/path_shift_gradient.h"
#include "ui/text/text_options.h" #include "ui/text/text_options.h"
#include "ui/boxes/report_box.h" #include "ui/boxes/report_box.h"
#include "ui/layers/generic_box.h" #include "ui/layers/generic_box.h"
@ -156,6 +157,7 @@ HistoryInner::HistoryInner(
, _peer(history->peer) , _peer(history->peer)
, _history(history) , _history(history)
, _migrated(history->migrateFrom()) , _migrated(history->migrateFrom())
, _pathGradient(HistoryView::MakePathShiftGradient([=] { update(); }))
, _scrollDateCheck([this] { scrollDateCheck(); }) , _scrollDateCheck([this] { scrollDateCheck(); })
, _scrollDateHideTimer([this] { scrollDateHideByTimer(); }) { , _scrollDateHideTimer([this] { scrollDateHideByTimer(); }) {
Instance = this; Instance = this;
@ -551,6 +553,11 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
_userpicsCache.clear(); _userpicsCache.clear();
}); });
_pathGradient->startFrame(
0,
width(),
std::min(st::msgMaxWidth / 2, width() / 2));
Painter p(this); Painter p(this);
auto clip = e->rect(); auto clip = e->rect();
auto ms = crl::now(); auto ms = crl::now();
@ -2623,6 +2630,10 @@ bool HistoryInner::elementIsChatWide() {
return _isChatWide; return _isChatWide;
} }
not_null<Ui::PathShiftGradient*> HistoryInner::elementPathShiftGradient() {
return _pathGradient.get();
}
auto HistoryInner::getSelectionState() const auto HistoryInner::getSelectionState() const
-> HistoryView::TopBarWidget::SelectedState { -> HistoryView::TopBarWidget::SelectedState {
auto result = HistoryView::TopBarWidget::SelectedState {}; auto result = HistoryView::TopBarWidget::SelectedState {};
@ -3412,7 +3423,7 @@ void HistoryInner::onParentGeometryChanged() {
} }
not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() { not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() {
class Result : public HistoryView::ElementDelegate { class Result final : public HistoryView::ElementDelegate {
public: public:
HistoryView::Context elementContext() override { HistoryView::Context elementContext() override {
return HistoryView::Context::History; return HistoryView::Context::History;
@ -3521,6 +3532,11 @@ not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() {
? Instance->elementIsChatWide() ? Instance->elementIsChatWide()
: false; : false;
} }
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override {
Expects(Instance != nullptr);
return Instance->elementPathShiftGradient();
}
}; };
static Result result; static Result result;

View file

@ -36,6 +36,7 @@ class SessionController;
namespace Ui { namespace Ui {
class PopupMenu; class PopupMenu;
enum class ReportReason; enum class ReportReason;
class PathShiftGradient;
} // namespace Ui } // namespace Ui
class HistoryWidget; class HistoryWidget;
@ -105,6 +106,7 @@ public:
const FullMsgId &context); const FullMsgId &context);
void elementHandleViaClick(not_null<UserData*> bot); void elementHandleViaClick(not_null<UserData*> bot);
bool elementIsChatWide(); bool elementIsChatWide();
not_null<Ui::PathShiftGradient*> elementPathShiftGradient();
void updateBotInfo(bool recount = true); void updateBotInfo(bool recount = true);
@ -365,6 +367,7 @@ private:
SelectedItems _selected; SelectedItems _selected;
std::optional<Ui::ReportReason> _chooseForReportReason; std::optional<Ui::ReportReason> _chooseForReportReason;
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
bool _isChatWide = false; bool _isChatWide = false;
base::flat_set<not_null<const HistoryItem*>> _animatedStickersPlayed; base::flat_set<not_null<const HistoryItem*>> _animatedStickersPlayed;

View file

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h" #include "main/main_session.h"
#include "chat_helpers/stickers_emoji_pack.h" #include "chat_helpers/stickers_emoji_pack.h"
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
#include "ui/effects/path_shift_gradient.h"
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
#include "ui/toasts/common_toasts.h" #include "ui/toasts/common_toasts.h"
#include "data/data_session.h" #include "data/data_session.h"
@ -60,11 +61,23 @@ bool IsAttachedToPreviousInSavedMessages(
} // namespace } // namespace
SimpleElementDelegate::SimpleElementDelegate( std::unique_ptr<Ui::PathShiftGradient> MakePathShiftGradient(
not_null<Window::SessionController*> controller) Fn<void()> update) {
: _controller(controller) { return std::make_unique<Ui::PathShiftGradient>(
st::msgServiceBg,
st::msgServiceBgSelected,
std::move(update));
} }
SimpleElementDelegate::SimpleElementDelegate(
not_null<Window::SessionController*> controller,
Fn<void()> update)
: _controller(controller)
, _pathGradient(MakePathShiftGradient(std::move(update))) {
}
SimpleElementDelegate::~SimpleElementDelegate() = default;
std::unique_ptr<HistoryView::Element> SimpleElementDelegate::elementCreate( std::unique_ptr<HistoryView::Element> SimpleElementDelegate::elementCreate(
not_null<HistoryMessage*> message, not_null<HistoryMessage*> message,
Element *replacing) { Element *replacing) {
@ -151,6 +164,11 @@ bool SimpleElementDelegate::elementIsChatWide() {
return false; return false;
} }
auto SimpleElementDelegate::elementPathShiftGradient()
-> not_null<Ui::PathShiftGradient*> {
return _pathGradient.get();
}
TextSelection UnshiftItemSelection( TextSelection UnshiftItemSelection(
TextSelection selection, TextSelection selection,
uint16 byLength) { uint16 byLength) {

View file

@ -22,6 +22,10 @@ namespace Window {
class SessionController; class SessionController;
} // namespace Window } // namespace Window
namespace Ui {
class PathShiftGradient;
} // namespace Ui
namespace HistoryView { namespace HistoryView {
enum class PointState : char; enum class PointState : char;
@ -79,13 +83,22 @@ public:
const FullMsgId &context) = 0; const FullMsgId &context) = 0;
virtual void elementHandleViaClick(not_null<UserData*> bot) = 0; virtual void elementHandleViaClick(not_null<UserData*> bot) = 0;
virtual bool elementIsChatWide() = 0; virtual bool elementIsChatWide() = 0;
virtual not_null<Ui::PathShiftGradient*> elementPathShiftGradient() = 0;
virtual ~ElementDelegate() {
}
}; };
[[nodiscard]] std::unique_ptr<Ui::PathShiftGradient> MakePathShiftGradient(
Fn<void()> update);
class SimpleElementDelegate : public ElementDelegate { class SimpleElementDelegate : public ElementDelegate {
public: public:
explicit SimpleElementDelegate( SimpleElementDelegate(
not_null<Window::SessionController*> controller); not_null<Window::SessionController*> controller,
Fn<void()> update);
~SimpleElementDelegate();
std::unique_ptr<Element> elementCreate( std::unique_ptr<Element> elementCreate(
not_null<HistoryMessage*> message, not_null<HistoryMessage*> message,
@ -124,9 +137,11 @@ public:
const FullMsgId &context) override; const FullMsgId &context) override;
void elementHandleViaClick(not_null<UserData*> bot) override; void elementHandleViaClick(not_null<UserData*> bot) override;
bool elementIsChatWide() override; bool elementIsChatWide() override;
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
private: private:
const not_null<Window::SessionController*> _controller; const not_null<Window::SessionController*> _controller;
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
}; };

View file

@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
#include "ui/inactive_press.h" #include "ui/inactive_press.h"
#include "ui/effects/path_shift_gradient.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "boxes/peers/edit_participant_box.h" #include "boxes/peers/edit_participant_box.h"
#include "data/data_session.h" #include "data/data_session.h"
@ -251,6 +252,7 @@ ListWidget::ListWidget(
, _controller(controller) , _controller(controller)
, _context(_delegate->listContext()) , _context(_delegate->listContext())
, _itemAverageHeight(itemMinimalHeight()) , _itemAverageHeight(itemMinimalHeight())
, _pathGradient(MakePathShiftGradient([=] { update(); }))
, _scrollDateCheck([this] { scrollDateCheck(); }) , _scrollDateCheck([this] { scrollDateCheck(); })
, _applyUpdatedScrollState([this] { applyUpdatedScrollState(); }) , _applyUpdatedScrollState([this] { applyUpdatedScrollState(); })
, _selectEnabled(_delegate->listAllowsMultiSelect()) , _selectEnabled(_delegate->listAllowsMultiSelect())
@ -1351,6 +1353,10 @@ bool ListWidget::elementIsChatWide() {
return _isChatWide; return _isChatWide;
} }
not_null<Ui::PathShiftGradient*> ListWidget::elementPathShiftGradient() {
return _pathGradient.get();
}
void ListWidget::saveState(not_null<ListMemento*> memento) { void ListWidget::saveState(not_null<ListMemento*> memento) {
memento->setAroundPosition(_aroundPosition); memento->setAroundPosition(_aroundPosition);
auto state = countScrollState(); auto state = countScrollState();
@ -1499,6 +1505,11 @@ void ListWidget::paintEvent(QPaintEvent *e) {
Painter p(this); Painter p(this);
_pathGradient->startFrame(
0,
width(),
std::min(st::msgMaxWidth / 2, width() / 2));
auto ms = crl::now(); auto ms = crl::now();
auto clip = e->rect(); auto clip = e->rect();

View file

@ -253,6 +253,7 @@ public:
const FullMsgId &context) override; const FullMsgId &context) override;
void elementHandleViaClick(not_null<UserData*> bot) override; void elementHandleViaClick(not_null<UserData*> bot) override;
bool elementIsChatWide() override; bool elementIsChatWide() override;
not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
~ListWidget(); ~ListWidget();
@ -509,6 +510,8 @@ private:
not_null<PeerData*>, not_null<PeerData*>,
std::shared_ptr<Data::CloudImageView>> _userpics, _userpicsCache; std::shared_ptr<Data::CloudImageView>> _userpics, _userpicsCache;
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
int _minHeight = 0; int _minHeight = 0;
int _visibleTop = 0; int _visibleTop = 0;
int _visibleBottom = 0; int _visibleBottom = 0;

View file

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/history_view_cursor_state.h" #include "history/view/history_view_cursor_state.h"
#include "history/view/media/history_view_media_common.h" #include "history/view/media/history_view_media_common.h"
#include "ui/image/image.h" #include "ui/image/image.h"
#include "ui/effects/path_shift_gradient.h"
#include "ui/emoji_config.h" #include "ui/emoji_config.h"
#include "core/application.h" #include "core/application.h"
#include "core/core_settings.h" #include "core/core_settings.h"
@ -232,11 +233,20 @@ bool Sticker::paintPixmap(Painter &p, const QRect &r, bool selected) {
} }
void Sticker::paintPath(Painter &p, const QRect &r, bool selected) { void Sticker::paintPath(Painter &p, const QRect &r, bool selected) {
const auto pathGradient = _parent->delegate()->elementPathShiftGradient();
if (selected) {
pathGradient->overrideColors(
st::msgServiceBgSelected,
st::msgServiceBg);
} else {
pathGradient->clearOverridenColors();
}
p.setBrush(selected ? st::msgServiceBgSelected : st::msgServiceBg);
ChatHelpers::PaintStickerThumbnailPath( ChatHelpers::PaintStickerThumbnailPath(
p, p,
_dataMedia.get(), _dataMedia.get(),
r, r,
(selected ? st::msgServiceBgSelected : st::msgServiceBg)->c); pathGradient);
} }
QPixmap Sticker::paintedPixmap(bool selected) const { QPixmap Sticker::paintedPixmap(bool selected) const {

View file

@ -468,6 +468,22 @@ void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context)
p.setOpacity(1); p.setOpacity(1);
} }
if (context->pathGradient) {
const auto thumbSize = getThumbSize();
const auto w = thumbSize.width();
const auto h = thumbSize.height();
ChatHelpers::PaintStickerThumbnailPath(
p,
_dataMedia.get(),
QRect(
(st::stickerPanSize.width() - w) / 2,
(st::stickerPanSize.height() - h) / 2,
w,
h),
context->pathGradient);
}
return; AssertIsDebug();
prepareThumbnail(); prepareThumbnail();
if (_lottie && _lottie->ready()) { if (_lottie && _lottie->ready()) {
const auto frame = _lottie->frame(); const auto frame = _lottie->frame();
@ -483,7 +499,7 @@ void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context)
int w = _thumb.width() / cIntRetinaFactor(), h = _thumb.height() / cIntRetinaFactor(); int w = _thumb.width() / cIntRetinaFactor(), h = _thumb.height() / cIntRetinaFactor();
QPoint pos = QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2); QPoint pos = QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
p.drawPixmap(pos, _thumb); p.drawPixmap(pos, _thumb);
} else { } else if (context->pathGradient) {
const auto thumbSize = getThumbSize(); const auto thumbSize = getThumbSize();
const auto w = thumbSize.width(); const auto w = thumbSize.width();
const auto h = thumbSize.height(); const auto h = thumbSize.height();
@ -495,7 +511,7 @@ void Sticker::paint(Painter &p, const QRect &clip, const PaintContext *context)
(st::stickerPanSize.height() - h) / 2, (st::stickerPanSize.height() - h) / 2,
w, w,
h), h),
st::windowBgRipple->c); context->pathGradient);
} }
} }

View file

@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
class Image; class Image;
namespace Ui {
class PathShiftGradient;
} // namespace Ui
namespace Data { namespace Data {
class CloudImageView; class CloudImageView;
} // namespace Data } // namespace Data
@ -27,11 +31,12 @@ class ItemBase;
class PaintContext : public PaintContextBase { class PaintContext : public PaintContextBase {
public: public:
PaintContext(crl::time ms, bool selecting, bool paused, bool lastRow) PaintContext(crl::time ms, bool selecting, bool paused, bool lastRow)
: PaintContextBase(ms, selecting) : PaintContextBase(ms, selecting)
, paused(paused) , paused(paused)
, lastRow(lastRow) { , lastRow(lastRow) {
} }
bool paused, lastRow; bool paused, lastRow;
Ui::PathShiftGradient *pathGradient = nullptr;
}; };

View file

@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/popup_menu.h" #include "ui/widgets/popup_menu.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h" #include "ui/widgets/labels.h"
#include "ui/effects/path_shift_gradient.h"
#include "history/view/history_view_cursor_state.h" #include "history/view/history_view_cursor_state.h"
#include "styles/style_chat_helpers.h" #include "styles/style_chat_helpers.h"
@ -36,6 +37,10 @@ Inner::Inner(
not_null<Window::SessionController*> controller) not_null<Window::SessionController*> controller)
: RpWidget(parent) : RpWidget(parent)
, _controller(controller) , _controller(controller)
, _pathGradient(std::make_unique<Ui::PathShiftGradient>(
st::windowBgRipple,
st::windowBgOver,
[=] { update(); }))
, _updateInlineItems([=] { updateInlineItems(); }) , _updateInlineItems([=] { updateInlineItems(); })
, _previewTimer([=] { showPreview(); }) { , _previewTimer([=] { showPreview(); }) {
resize(st::emojiPanWidth - st::emojiScroll.width - st::roundRadiusSmall, st::inlineResultsMinHeight); resize(st::emojiPanWidth - st::emojiScroll.width - st::roundRadiusSmall, st::inlineResultsMinHeight);
@ -172,6 +177,8 @@ void Inner::paintInlineItems(Painter &p, const QRect &r) {
} }
auto gifPaused = _controller->isGifPausedAtLeastFor(Window::GifPauseReason::InlineResults); auto gifPaused = _controller->isGifPausedAtLeastFor(Window::GifPauseReason::InlineResults);
InlineBots::Layout::PaintContext context(crl::now(), false, gifPaused, false); InlineBots::Layout::PaintContext context(crl::now(), false, gifPaused, false);
context.pathGradient = _pathGradient.get();
context.pathGradient->startFrame(0, width(), width() / 2);
auto top = st::stickerPanPadding; auto top = st::stickerPanPadding;
if (_switchPmButton) { if (_switchPmButton) {

View file

@ -29,6 +29,7 @@ class RoundButton;
class FlatLabel; class FlatLabel;
class RippleAnimation; class RippleAnimation;
class PopupMenu; class PopupMenu;
class PathShiftGradient;
} // namespace Ui } // namespace Ui
namespace Window { namespace Window {
@ -154,6 +155,7 @@ private:
bool open); bool open);
not_null<Window::SessionController*> _controller; not_null<Window::SessionController*> _controller;
const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
int _visibleTop = 0; int _visibleTop = 0;
int _visibleBottom = 0; int _visibleBottom = 0;

View file

@ -691,7 +691,7 @@ rpl::producer<QString> CallsPeer2PeerPrivacyController::exceptionsDescription()
ForwardsPrivacyController::ForwardsPrivacyController( ForwardsPrivacyController::ForwardsPrivacyController(
not_null<Window::SessionController*> controller) not_null<Window::SessionController*> controller)
: SimpleElementDelegate(controller) : SimpleElementDelegate(controller, [] {})
, _controller(controller) { , _controller(controller) {
} }

View file

@ -173,7 +173,8 @@ void SetupPrivacy(
add( add(
tr::lng_settings_forwards_privacy(), tr::lng_settings_forwards_privacy(),
Key::Forwards, Key::Forwards,
[=] { return std::make_unique<ForwardsPrivacyController>(controller); }); [=] { return std::make_unique<ForwardsPrivacyController>(
controller); });
add( add(
tr::lng_settings_profile_photo_privacy(), tr::lng_settings_profile_photo_privacy(),
Key::ProfilePhoto, Key::ProfilePhoto,

View file

@ -508,7 +508,7 @@ ConfirmContactBox::ConfirmContactBox(
not_null<History*> history, not_null<History*> history,
const Contact &data, const Contact &data,
Fn<void(Qt::KeyboardModifiers)> submit) Fn<void(Qt::KeyboardModifiers)> submit)
: SimpleElementDelegate(controller) : SimpleElementDelegate(controller, [=] { update(); })
, _comment(GenerateCommentItem(this, history, data)) , _comment(GenerateCommentItem(this, history, data))
, _contact(GenerateContactItem(this, history, data)) , _contact(GenerateContactItem(this, history, data))
, _submit(submit) { , _submit(submit) {

View file

@ -108,9 +108,10 @@ QByteArray ExpandPathInlineBytes(const QByteArray &bytes) {
} else if (c >= 64) { } else if (c >= 64) {
result.append('-'); result.append('-');
} }
char buffer[3] = { 0 }; //char buffer[3] = { 0 }; // Unavailable on macOS < 10.15.
std::to_chars(buffer, buffer + 3, (c & 63)); //std::to_chars(buffer, buffer + 3, (c & 63));
result.append(buffer); //result.append(buffer);
result.append(QByteArray::number(c & 63));
} }
} }
result.append('z'); result.append('z');

@ -1 +1 @@
Subproject commit 3b3413e618864a9b1bec40911ca713f68726b177 Subproject commit baf4d80867e719a6fc0ae0cefd192ce061c3b879

View file

@ -34,7 +34,7 @@ Open **x64 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
cd ThirdParty cd ThirdParty
git clone https://github.com/desktop-app/patches.git git clone https://github.com/desktop-app/patches.git
cd patches cd patches
git checkout 7f8a282 git checkout d051cbc
cd ../ cd ../
git clone https://chromium.googlesource.com/external/gyp git clone https://chromium.googlesource.com/external/gyp
cd gyp cd gyp
@ -65,7 +65,7 @@ Open **x64 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
git clone https://github.com/desktop-app/patches.git git clone https://github.com/desktop-app/patches.git
cd patches cd patches
git checkout 7f8a282 git checkout d051cbc
cd .. cd ..
git clone https://github.com/desktop-app/lzma.git git clone https://github.com/desktop-app/lzma.git
@ -178,11 +178,11 @@ Open **x64 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
python scripts/bootstrap.py python scripts/bootstrap.py
gclient sync gclient sync
git apply ../patches/angle.patch for /r %i in (..\patches\angle\*) do git apply %i
gn gen out/Debug --args="is_component_build = false is_debug = true target_cpu = \"x64\" is_clang = false enable_iterator_debugging = true angle_enable_swiftshader=false angle_enable_vulkan=false" gn gen out/Debug --args="is_component_build=false is_debug=true target_cpu=\"x64\" is_clang=false enable_iterator_debugging=true angle_enable_swiftshader=false angle_enable_vulkan=false angle_default_d3d9=true"
gn gen out/Release --args="is_component_build = false is_debug = false target_cpu = \"x64\" is_clang = false enable_iterator_debugging = false angle_enable_swiftshader=false angle_enable_vulkan=false" gn gen out/Release --args="is_component_build=false is_debug=false target_cpu=\"x64\" is_clang=false enable_iterator_debugging=false angle_enable_swiftshader=false angle_enable_vulkan=false angle_default_d3d9=true"
ninja -C out/Debug libANGLE_static libGLESv2_static libEGL_static ninja -C out/Debug libANGLE_static libGLESv2_static libEGL_static
ninja -C out/Release libANGLE_static libGLESv2_static libEGL_static ninja -C out/Release libANGLE_static libGLESv2_static libEGL_static

View file

@ -34,7 +34,7 @@ Open **x86 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
cd ThirdParty cd ThirdParty
git clone https://github.com/desktop-app/patches.git git clone https://github.com/desktop-app/patches.git
cd patches cd patches
git checkout 7f8a282 git checkout d051cbc
cd ../ cd ../
git clone https://chromium.googlesource.com/external/gyp git clone https://chromium.googlesource.com/external/gyp
cd gyp cd gyp
@ -65,7 +65,7 @@ Open **x86 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
git clone https://github.com/desktop-app/patches.git git clone https://github.com/desktop-app/patches.git
cd patches cd patches
git checkout 7f8a282 git checkout d051cbc
cd .. cd ..
git clone https://github.com/desktop-app/lzma.git git clone https://github.com/desktop-app/lzma.git
@ -178,11 +178,11 @@ Open **x86 Native Tools Command Prompt for VS 2019.bat**, go to ***BuildPath***
python scripts/bootstrap.py python scripts/bootstrap.py
gclient sync gclient sync
git apply ../patches/angle.patch for /r %i in (..\patches\angle\*) do git apply %i
gn gen out/Debug --args="is_component_build = false is_debug = true target_cpu = \"x86\" is_clang = false enable_iterator_debugging = true angle_enable_swiftshader=false angle_enable_vulkan=false" gn gen out/Debug --args="is_component_build=false is_debug=true target_cpu=\"x86\" is_clang=false enable_iterator_debugging=true angle_enable_swiftshader=false angle_enable_vulkan=false angle_default_d3d9=true"
gn gen out/Release --args="is_component_build = false is_debug = false target_cpu = \"x86\" is_clang = false enable_iterator_debugging = false angle_enable_swiftshader=false angle_enable_vulkan=false" gn gen out/Release --args="is_component_build=false is_debug=false target_cpu=\"x86\" is_clang=false enable_iterator_debugging=false angle_enable_swiftshader=false angle_enable_vulkan=false angle_default_d3d9=true"
ninja -C out/Debug libANGLE_static libGLESv2_static libEGL_static ninja -C out/Debug libANGLE_static libGLESv2_static libEGL_static
ninja -C out/Release libANGLE_static libGLESv2_static libEGL_static ninja -C out/Release libANGLE_static libGLESv2_static libEGL_static