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_widget.cpp
ui/layers/layer_widget.h
ui/layers/show.cpp
ui/layers/show.h
ui/paint/arcs.cpp
ui/paint/arcs.h
@ -180,8 +181,6 @@ PRIVATE
ui/toast/toast_manager.h
ui/toast/toast_widget.cpp
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.h
ui/widgets/buttons.cpp

View file

@ -19,6 +19,98 @@
#include "styles/palette.h"
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) {
getDelegate()->setTitle(std::move(title) | Text::ToWithEntities());
@ -197,6 +289,27 @@ int BoxContent::scrollHeight() const {
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) {
_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

View file

@ -35,6 +35,11 @@ namespace st {
extern const style::ScrollArea &boxScroll;
} // namespace st
namespace Ui::Toast {
struct Config;
class Instance;
} // namespace Ui::Toast
namespace Ui {
class GenericBox;
} // namespace Ui
@ -101,7 +106,6 @@ public:
};
class BoxContent : public RpWidget {
public:
BoxContent() {
setAttribute(Qt::WA_OpaquePaintEvent);
@ -214,6 +218,16 @@ public:
[[nodiscard]] int scrollTop() 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:
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

View file

@ -68,7 +68,8 @@ ManagerShow::operator bool() const {
} // namespace
LayerManager::LayerManager(not_null<RpWidget*> widget) : _widget(widget) {
LayerManager::LayerManager(not_null<RpWidget*> widget)
: _widget(widget) {
}
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
#include "base/weak_ptr.h"
#include "ui/layers/layer_widget.h"
struct TextWithEntities;
namespace Ui::Toast {
struct Config;
class Instance;
} // namespace Ui::Toast
namespace Ui {
class BoxContent;
inline constexpr auto kZOrderBasic = 0;
class Show {
public:
virtual ~Show() = 0;
@ -22,6 +32,18 @@ public:
[[nodiscard]] virtual not_null<QWidget*> toastParent() const = 0;
[[nodiscard]] virtual bool valid() 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;

View file

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

View file

@ -17,6 +17,10 @@ namespace style {
struct Toast;
} // namespace style
namespace st {
extern const style::Toast &defaultMultilineToast;
} // namespace st
namespace Ui {
namespace Toast {
@ -30,10 +34,10 @@ using ClickHandlerFilter = Fn<bool(const ClickHandlerPtr&, Qt::MouseButton)>;
inline constexpr auto kDefaultDuration = crl::time(1500);
struct Config {
TextWithEntities text;
not_null<const style::Toast*> st;
crl::time durationMs = kDefaultDuration;
not_null<const style::Toast*> st = &st::defaultMultilineToast;
crl::time duration = kDefaultDuration;
int maxLines = 16;
bool multiline = false;
bool multiline = true;
bool dark = false;
RectPart slideSide = RectPart::None;
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/wrap/padding_wrap.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/toasts/common_toasts.h"
#include "ui/platform/ui_platform_utility.h"
#include "ui/layers/layer_widget.h"
#include "ui/layers/show.h"
@ -410,15 +409,25 @@ void SeparatePanel::showBox(
}
}
std::shared_ptr<Show> SeparatePanel::uiShow() {
return std::make_shared<PanelShow>(this);
base::weak_ptr<Toast::Instance> SeparatePanel::showToast(
Toast::Config &&config) {
return PanelShow(this).showToast(std::move(config));
}
void SeparatePanel::showToast(const TextWithEntities &text) {
Ui::ShowMultilineToast({
.parentOverride = this,
.text = text,
});
base::weak_ptr<Toast::Instance> SeparatePanel::showToast(
TextWithEntities &&text,
crl::time duration) {
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() {

View file

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