Simplify working with Ui::Show and toasts.

This commit is contained in:
John Preston 2023-05-02 13:32:56 +04:00
parent 7c9aa94533
commit b850852221
12 changed files with 242 additions and 169 deletions

View file

@ -97,6 +97,7 @@ PRIVATE
ui/layers/layer_manager.h ui/layers/layer_manager.h
ui/layers/layer_widget.cpp ui/layers/layer_widget.cpp
ui/layers/layer_widget.h ui/layers/layer_widget.h
ui/layers/show.cpp
ui/layers/show.h ui/layers/show.h
ui/paint/arcs.cpp ui/paint/arcs.cpp
ui/paint/arcs.h ui/paint/arcs.h
@ -180,8 +181,6 @@ PRIVATE
ui/toast/toast_manager.h ui/toast/toast_manager.h
ui/toast/toast_widget.cpp ui/toast/toast_widget.cpp
ui/toast/toast_widget.h ui/toast/toast_widget.h
ui/toasts/common_toasts.cpp
ui/toasts/common_toasts.h
ui/widgets/box_content_divider.cpp ui/widgets/box_content_divider.cpp
ui/widgets/box_content_divider.h ui/widgets/box_content_divider.h
ui/widgets/buttons.cpp ui/widgets/buttons.cpp

View file

@ -19,6 +19,98 @@
#include "styles/palette.h" #include "styles/palette.h"
namespace Ui { namespace Ui {
namespace {
class BoxShow final : public Show {
public:
explicit BoxShow(not_null<Ui::BoxContent*> box);
BoxShow(const BoxShow &other);
~BoxShow();
void showBox(
object_ptr<BoxContent> content,
LayerOptions options = LayerOption::KeepOther) const override;
void hideLayer() const override;
[[nodiscard]] not_null<QWidget*> toastParent() const override;
[[nodiscard]] bool valid() const override;
operator bool() const override;
private:
BoxShow(QPointer<BoxContent> weak, ShowPtr wrapped);
bool resolve() const;
const QPointer<Ui::BoxContent> _weak;
mutable std::shared_ptr<Show> _wrapped;
rpl::lifetime _lifetime;
};
BoxShow::BoxShow(not_null<BoxContent*> box)
: BoxShow(MakeWeak(box.get()), nullptr) {
}
BoxShow::BoxShow(const BoxShow &other)
: BoxShow(other._weak, other._wrapped) {
}
BoxShow::BoxShow(QPointer<BoxContent> weak, ShowPtr wrapped)
: _weak(weak)
, _wrapped(std::move(wrapped)) {
if (!resolve()) {
if (const auto box = _weak.data()) {
box->boxClosing(
) | rpl::start_with_next([=] {
resolve();
_lifetime.destroy();
}, _lifetime);
}
}
}
BoxShow::~BoxShow() = default;
bool BoxShow::resolve() const {
if (_wrapped) {
return true;
} else if (const auto strong = _weak.data()) {
if (strong->hasDelegate()) {
_wrapped = strong->getDelegate()->showFactory()();
return true;
}
}
return false;
}
void BoxShow::showBox(
object_ptr<BoxContent> content,
LayerOptions options) const {
if (resolve()) {
_wrapped->showBox(std::move(content), options);
}
}
void BoxShow::hideLayer() const {
if (resolve()) {
_wrapped->hideLayer();
}
}
not_null<QWidget*> BoxShow::toastParent() const {
if (resolve()) {
return _wrapped->toastParent();
}
Unexpected("Stale BoxShow::toastParent call.");
}
bool BoxShow::valid() const {
return resolve() && _wrapped->valid();
}
BoxShow::operator bool() const {
return valid();
}
} // namespace
void BoxContent::setTitle(rpl::producer<QString> title) { void BoxContent::setTitle(rpl::producer<QString> title) {
getDelegate()->setTitle(std::move(title) | Text::ToWithEntities()); getDelegate()->setTitle(std::move(title) | Text::ToWithEntities());
@ -197,6 +289,27 @@ int BoxContent::scrollHeight() const {
return _scroll ? _scroll->height() : 0; return _scroll ? _scroll->height() : 0;
} }
base::weak_ptr<Toast::Instance> BoxContent::showToast(
Toast::Config &&config) {
return BoxShow(this).showToast(std::move(config));
}
base::weak_ptr<Toast::Instance> BoxContent::showToast(
TextWithEntities &&text,
crl::time duration) {
return BoxShow(this).showToast(std::move(text), duration);
}
base::weak_ptr<Toast::Instance> BoxContent::showToast(
const QString &text,
crl::time duration) {
return BoxShow(this).showToast(text, duration);
}
std::shared_ptr<Show> BoxContent::uiShow() {
return std::make_shared<BoxShow>(this);
}
void BoxContent::scrollByDraggingDelta(int delta) { void BoxContent::scrollByDraggingDelta(int delta) {
_draggingScroll.checkDeltaScroll(_scroll ? delta : 0); _draggingScroll.checkDeltaScroll(_scroll ? delta : 0);
} }
@ -335,69 +448,4 @@ void BoxContent::paintEvent(QPaintEvent *e) {
} }
} }
BoxShow::BoxShow(not_null<BoxContent*> box)
: BoxShow(MakeWeak(box.get()), nullptr) {
}
BoxShow::BoxShow(const BoxShow &other)
: BoxShow(other._weak, other._wrapped) {
}
BoxShow::BoxShow(QPointer<BoxContent> weak, ShowPtr wrapped)
: _weak(weak)
, _wrapped(std::move(wrapped)) {
if (!resolve()) {
if (const auto box = _weak.data()) {
box->boxClosing(
) | rpl::start_with_next([=] {
resolve();
_lifetime.destroy();
}, _lifetime);
}
}
}
BoxShow::~BoxShow() = default;
bool BoxShow::resolve() const {
if (_wrapped) {
return true;
} else if (const auto strong = _weak.data()) {
if (strong->hasDelegate()) {
_wrapped = strong->getDelegate()->showFactory()();
return true;
}
}
return false;
}
void BoxShow::showBox(
object_ptr<BoxContent> content,
LayerOptions options) const {
if (resolve()) {
_wrapped->showBox(std::move(content), options);
}
}
void BoxShow::hideLayer() const {
if (resolve()) {
_wrapped->hideLayer();
}
}
not_null<QWidget*> BoxShow::toastParent() const {
if (resolve()) {
return _wrapped->toastParent();
}
Unexpected("Stale BoxShow::toastParent call.");
}
bool BoxShow::valid() const {
return resolve() && _wrapped->valid();
}
BoxShow::operator bool() const {
return valid();
}
} // namespace Ui } // namespace Ui

View file

@ -35,6 +35,11 @@ namespace st {
extern const style::ScrollArea &boxScroll; extern const style::ScrollArea &boxScroll;
} // namespace st } // namespace st
namespace Ui::Toast {
struct Config;
class Instance;
} // namespace Ui::Toast
namespace Ui { namespace Ui {
class GenericBox; class GenericBox;
} // namespace Ui } // namespace Ui
@ -101,7 +106,6 @@ public:
}; };
class BoxContent : public RpWidget { class BoxContent : public RpWidget {
public: public:
BoxContent() { BoxContent() {
setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_OpaquePaintEvent);
@ -214,6 +218,16 @@ public:
[[nodiscard]] int scrollTop() const; [[nodiscard]] int scrollTop() const;
[[nodiscard]] int scrollHeight() const; [[nodiscard]] int scrollHeight() const;
base::weak_ptr<Toast::Instance> showToast(Toast::Config &&config);
base::weak_ptr<Toast::Instance> showToast(
TextWithEntities &&text,
crl::time duration = 0);
base::weak_ptr<Toast::Instance> showToast(
const QString &text,
crl::time duration = 0);
[[nodiscard]] std::shared_ptr<Show> uiShow();
protected: protected:
virtual void prepare() = 0; virtual void prepare() = 0;
@ -357,28 +371,4 @@ private:
}; };
class BoxShow : public Show {
public:
explicit BoxShow(not_null<Ui::BoxContent*> box);
BoxShow(const BoxShow &other);
~BoxShow();
void showBox(
object_ptr<BoxContent> content,
LayerOptions options = LayerOption::KeepOther) const override;
void hideLayer() const override;
[[nodiscard]] not_null<QWidget*> toastParent() const override;
[[nodiscard]] bool valid() const override;
operator bool() const override;
private:
BoxShow(QPointer<BoxContent> weak, ShowPtr wrapped);
bool resolve() const;
const QPointer<Ui::BoxContent> _weak;
mutable std::shared_ptr<Show> _wrapped;
rpl::lifetime _lifetime;
};
} // namespace Ui } // namespace Ui

View file

@ -68,7 +68,8 @@ ManagerShow::operator bool() const {
} // namespace } // namespace
LayerManager::LayerManager(not_null<RpWidget*> widget) : _widget(widget) { LayerManager::LayerManager(not_null<RpWidget*> widget)
: _widget(widget) {
} }
void LayerManager::setStyleOverrides( void LayerManager::setStyleOverrides(

43
ui/layers/show.cpp Normal file
View file

@ -0,0 +1,43 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#include "ui/layers/show.h"
#include "ui/toast/toast.h"
namespace Ui {
namespace {
using namespace Toast;
} // namespace
base::weak_ptr<Instance> Show::showToast(Config &&config) {
if (const auto strong = _lastToast.get()) {
strong->hideAnimated();
}
_lastToast = valid()
? Toast::Show(toastParent(), std::move(config))
: base::weak_ptr<Instance>();
return _lastToast;
}
base::weak_ptr<Instance> Show::showToast(
TextWithEntities &&text,
crl::time duration) {
return showToast({ .text = std::move(text), .duration = duration });
}
base::weak_ptr<Instance> Show::showToast(
const QString &text,
crl::time duration) {
return showToast({
.text = TextWithEntities{ text },
.duration = duration,
});
}
} // namespace Ui

View file

@ -6,12 +6,22 @@
// //
#pragma once #pragma once
#include "base/weak_ptr.h"
#include "ui/layers/layer_widget.h" #include "ui/layers/layer_widget.h"
struct TextWithEntities;
namespace Ui::Toast {
struct Config;
class Instance;
} // namespace Ui::Toast
namespace Ui { namespace Ui {
class BoxContent; class BoxContent;
inline constexpr auto kZOrderBasic = 0;
class Show { class Show {
public: public:
virtual ~Show() = 0; virtual ~Show() = 0;
@ -22,6 +32,18 @@ public:
[[nodiscard]] virtual not_null<QWidget*> toastParent() const = 0; [[nodiscard]] virtual not_null<QWidget*> toastParent() const = 0;
[[nodiscard]] virtual bool valid() const = 0; [[nodiscard]] virtual bool valid() const = 0;
virtual operator bool() const = 0; virtual operator bool() const = 0;
base::weak_ptr<Toast::Instance> showToast(Toast::Config &&config);
base::weak_ptr<Toast::Instance> showToast(
TextWithEntities &&text,
crl::time duration = 0);
base::weak_ptr<Toast::Instance> showToast(
const QString &text,
crl::time duration = 0);
private:
base::weak_ptr<Toast::Instance> _lastToast;
}; };
inline Show::~Show() = default; inline Show::~Show() = default;

View file

@ -23,7 +23,8 @@ Instance::Instance(
not_null<QWidget*> widgetParent, not_null<QWidget*> widgetParent,
const Private &) const Private &)
: _st(config.st) : _st(config.st)
, _hideAt(crl::now() + config.durationMs) , _hideAt(crl::now()
+ (config.duration ? config.duration : kDefaultDuration))
, _sliding(config.slideSide != RectPart::None) , _sliding(config.slideSide != RectPart::None)
, _widget(std::make_unique<internal::Widget>(widgetParent, config)) { , _widget(std::make_unique<internal::Widget>(widgetParent, config)) {
_shownAnimation.start( _shownAnimation.start(

View file

@ -17,6 +17,10 @@ namespace style {
struct Toast; struct Toast;
} // namespace style } // namespace style
namespace st {
extern const style::Toast &defaultMultilineToast;
} // namespace st
namespace Ui { namespace Ui {
namespace Toast { namespace Toast {
@ -30,10 +34,10 @@ using ClickHandlerFilter = Fn<bool(const ClickHandlerPtr&, Qt::MouseButton)>;
inline constexpr auto kDefaultDuration = crl::time(1500); inline constexpr auto kDefaultDuration = crl::time(1500);
struct Config { struct Config {
TextWithEntities text; TextWithEntities text;
not_null<const style::Toast*> st; not_null<const style::Toast*> st = &st::defaultMultilineToast;
crl::time durationMs = kDefaultDuration; crl::time duration = kDefaultDuration;
int maxLines = 16; int maxLines = 16;
bool multiline = false; bool multiline = true;
bool dark = false; bool dark = false;
RectPart slideSide = RectPart::None; RectPart slideSide = RectPart::None;
ClickHandlerFilter filter; ClickHandlerFilter filter;

View file

@ -1,31 +0,0 @@
/*
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/toasts/common_toasts.h"
#include "ui/toast/toast.h"
#include "styles/style_widgets.h"
namespace Ui {
base::weak_ptr<Toast::Instance> ShowMultilineToast(
MultilineToastArgs &&args) {
auto config = Ui::Toast::Config{
.text = std::move(args.text),
.st = &st::defaultMultilineToast,
.durationMs = (args.duration
? args.duration
: Ui::Toast::kDefaultDuration),
.multiline = true,
.filter = std::move(args.filter),
};
return args.parentOverride
? Ui::Toast::Show(args.parentOverride, std::move(config))
: Ui::Toast::Show(std::move(config));
}
} // namespace Ui

View file

@ -1,32 +0,0 @@
/*
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
#include "ui/text/text_entity.h"
#include "base/weak_ptr.h"
class ClickHandler;
using ClickHandlerPtr = std::shared_ptr<ClickHandler>;
using ClickHandlerFilter = Fn<bool(const ClickHandlerPtr&, Qt::MouseButton)>;
namespace Ui {
namespace Toast {
class Instance;
} // namespace Toast
struct MultilineToastArgs {
QWidget *parentOverride = nullptr;
TextWithEntities text;
crl::time duration = 0;
ClickHandlerFilter filter;
};
base::weak_ptr<Toast::Instance> ShowMultilineToast(
MultilineToastArgs &&args);
} // namespace Ui

View file

@ -16,7 +16,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/menu/menu_add_action_callback_factory.h" #include "ui/widgets/menu/menu_add_action_callback_factory.h"
#include "ui/wrap/padding_wrap.h" #include "ui/wrap/padding_wrap.h"
#include "ui/wrap/fade_wrap.h" #include "ui/wrap/fade_wrap.h"
#include "ui/toasts/common_toasts.h"
#include "ui/platform/ui_platform_utility.h" #include "ui/platform/ui_platform_utility.h"
#include "ui/layers/layer_widget.h" #include "ui/layers/layer_widget.h"
#include "ui/layers/show.h" #include "ui/layers/show.h"
@ -410,15 +409,25 @@ void SeparatePanel::showBox(
} }
} }
std::shared_ptr<Show> SeparatePanel::uiShow() { base::weak_ptr<Toast::Instance> SeparatePanel::showToast(
return std::make_shared<PanelShow>(this); Toast::Config &&config) {
return PanelShow(this).showToast(std::move(config));
} }
void SeparatePanel::showToast(const TextWithEntities &text) { base::weak_ptr<Toast::Instance> SeparatePanel::showToast(
Ui::ShowMultilineToast({ TextWithEntities &&text,
.parentOverride = this, crl::time duration) {
.text = text, return PanelShow(this).showToast(std::move(text), duration);
}); }
base::weak_ptr<Toast::Instance> SeparatePanel::showToast(
const QString &text,
crl::time duration) {
return PanelShow(this).showToast(text, duration);
}
std::shared_ptr<Show> SeparatePanel::uiShow() {
return std::make_shared<PanelShow>(this);
} }
void SeparatePanel::ensureLayerCreated() { void SeparatePanel::ensureLayerCreated() {

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "base/weak_ptr.h"
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
#include "ui/effects/animations.h" #include "ui/effects/animations.h"
#include "ui/layers/layer_widget.h" #include "ui/layers/layer_widget.h"
@ -18,6 +19,11 @@ namespace Ui::Menu {
struct MenuCallback; struct MenuCallback;
} // namespace Ui::Menu } // namespace Ui::Menu
namespace Ui::Toast {
struct Config;
class Instance;
} // namespace Ui::Toast
namespace Ui { namespace Ui {
class Show; class Show;
@ -32,6 +38,7 @@ class FadeWrapScaled;
struct SeparatePanelArgs { struct SeparatePanelArgs {
QWidget *parent = nullptr; QWidget *parent = nullptr;
bool onAllSpaces = false; bool onAllSpaces = false;
Fn<bool(int zorder)> animationsPaused;
}; };
class SeparatePanel final : public RpWidget { class SeparatePanel final : public RpWidget {
@ -52,15 +59,25 @@ public:
object_ptr<BoxContent> box, object_ptr<BoxContent> box,
LayerOptions options, LayerOptions options,
anim::type animated); anim::type animated);
void showToast(const TextWithEntities &text);
void destroyLayer(); void destroyLayer();
[[nodiscard]] bool animationsPaused(int zorder) const;
[[nodiscard]] rpl::producer<> backRequests() const; [[nodiscard]] rpl::producer<> backRequests() const;
[[nodiscard]] rpl::producer<> closeRequests() const; [[nodiscard]] rpl::producer<> closeRequests() const;
[[nodiscard]] rpl::producer<> closeEvents() const; [[nodiscard]] rpl::producer<> closeEvents() const;
void setBackAllowed(bool allowed); void setBackAllowed(bool allowed);
void setMenuAllowed(Fn<void(const Menu::MenuCallback&)> fill); void setMenuAllowed(Fn<void(const Menu::MenuCallback&)> fill);
base::weak_ptr<Toast::Instance> showToast(Toast::Config &&config);
base::weak_ptr<Toast::Instance> showToast(
TextWithEntities &&text,
crl::time duration = 0);
base::weak_ptr<Toast::Instance> showToast(
const QString &text,
crl::time duration = 0);
[[nodiscard]] std::shared_ptr<Show> uiShow(); [[nodiscard]] std::shared_ptr<Show> uiShow();
protected: protected:
@ -127,6 +144,8 @@ private:
QPixmap _animationCache; QPixmap _animationCache;
QPixmap _borderParts; QPixmap _borderParts;
Fn<bool(int zorder)> _animationsPaused;
}; };
} // namespace Ui } // namespace Ui