diff --git a/Telegram/SourceFiles/ui/effects/loading_element.cpp b/Telegram/SourceFiles/ui/effects/loading_element.cpp new file mode 100644 index 000000000..67de701cf --- /dev/null +++ b/Telegram/SourceFiles/ui/effects/loading_element.cpp @@ -0,0 +1,142 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#include "ui/effects/loading_element.h" + +#include "ui/effects/glare.h" + +#include "base/object_ptr.h" +#include "styles/palette.h" +#include "styles/style_basic.h" +#include "styles/style_widgets.h" +#include "base/random.h" +#include "ui/painter.h" +#include "ui/rp_widget.h" + +namespace Ui { +namespace { + +class LoadingElement { +public: + LoadingElement() = default; + + [[nodiscard]] virtual int height() const = 0; + virtual void paint(QPainter &p, int width) = 0; +}; + +class LoadingText final : public LoadingElement { +public: + LoadingText(const style::FlatLabel &st); + + [[nodiscard]] int height() const override; + void paint(QPainter &p, int width) override; + +private: + const style::FlatLabel &_st; + +}; + +LoadingText::LoadingText(const style::FlatLabel &st) : _st(st) { +} + +int LoadingText::height() const { + return _st.style.lineHeight; +} + +void LoadingText::paint(QPainter &p, int width) { + auto hq = PainterHighQualityEnabler(p); + + p.setPen(Qt::NoPen); + + p.setBrush(st::dialogsDateFg); + const auto h = _st.style.font->ascent; + p.drawRoundedRect( + 0, + height() - h - (height() - _st.style.font->height), + width, + h, + h / 2, + h / 2); +} + +} // namespace + +object_ptr CreateLoadingTextWidget( + not_null parent, + const style::FlatLabel &st, + int lines, + rpl::producer rtl) { + auto widget = object_ptr(parent); + const auto raw = widget.data(); + + struct State { + GlareEffect glare; + Ui::Animations::Simple animation; + int lastLineWidth = 0; + rpl::variable rtl; + }; + + const auto state = widget->lifetime().make_state(); + state->rtl = std::move(rtl); + state->rtl.value( + ) | rpl::start_with_next([=] { raw->update(); }, raw->lifetime()); + raw->resize(raw->width(), LoadingText(st).height() * lines); + + const auto draw = [=](QPainter &p) { + auto loading = LoadingText(st); + const auto countRows = lines; + for (auto i = 0; i < countRows; i++) { + const auto w = (i == countRows - 1) + ? state->lastLineWidth + : raw->width(); + loading.paint(p, w); + p.translate(0, loading.height()); + } + p.resetTransform(); + + auto &_glare = state->glare; + if (_glare.glare.birthTime) { + const auto progress = _glare.progress(crl::now()); + const auto x = (-_glare.width) + + (raw->width() + _glare.width * 2) * progress; + const auto h = raw->height(); + + p.drawTiledPixmap(x, 0, _glare.width, h, _glare.pixmap, 0, 0); + } + }; + + widget->paintRequest( + ) | rpl::start_with_next([=](const QRect &r) { + auto p = QPainter(raw); + if (state->rtl.current()) { + const auto r = raw->rect(); + p.translate(r.center()); + p.scale(-1., 1.); + p.translate(-r.center()); + } + draw(p); + }, widget->lifetime()); + + constexpr auto kTimeout = crl::time(1000); + constexpr auto kDuration = crl::time(1000); + widget->widthValue( + ) | rpl::start_with_next([=](int width) { + state->glare.width = width; + state->glare.validate( + st::dialogsBg->c, + [=] { raw->update(); }, + kTimeout, + kDuration); + if (width) { + state->lastLineWidth = (width / 4) + base::RandomIndex(width / 2); + } + }, widget->lifetime()); + + return widget; +} + +} // namespace Ui diff --git a/Telegram/SourceFiles/ui/effects/loading_element.h b/Telegram/SourceFiles/ui/effects/loading_element.h new file mode 100644 index 000000000..ec2264859 --- /dev/null +++ b/Telegram/SourceFiles/ui/effects/loading_element.h @@ -0,0 +1,27 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +template +class object_ptr; + +namespace style { +struct FlatLabel; +} // namespace style + +namespace Ui { + +class RpWidget; + +object_ptr CreateLoadingTextWidget( + not_null parent, + const style::FlatLabel &st, + int lines, + rpl::producer rtl); + +} // namespace Ui diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake index 048610152..7fb2e8def 100644 --- a/Telegram/cmake/td_ui.cmake +++ b/Telegram/cmake/td_ui.cmake @@ -236,6 +236,8 @@ PRIVATE ui/effects/fireworks_animation.h ui/effects/glare.cpp ui/effects/glare.h + ui/effects/loading_element.cpp + ui/effects/loading_element.h ui/effects/premium_graphics.cpp ui/effects/premium_graphics.h ui/effects/premium_stars.cpp