From 0ca5d505468d8d9dfdf01531f869ff5904f25ccc Mon Sep 17 00:00:00 2001 From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> Date: Sun, 21 Sep 2025 16:43:45 +1000 Subject: utilities: add toasts --- plugin/src/Caelestia/CMakeLists.txt | 1 + plugin/src/Caelestia/toaster.cpp | 116 ++++++++++++++++++++++++++++++++++++ plugin/src/Caelestia/toaster.hpp | 81 +++++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 plugin/src/Caelestia/toaster.cpp create mode 100644 plugin/src/Caelestia/toaster.hpp (limited to 'plugin/src/Caelestia') diff --git a/plugin/src/Caelestia/CMakeLists.txt b/plugin/src/Caelestia/CMakeLists.txt index 5fd8874..4ad308f 100644 --- a/plugin/src/Caelestia/CMakeLists.txt +++ b/plugin/src/Caelestia/CMakeLists.txt @@ -44,6 +44,7 @@ qml_module(caelestia qalculator.hpp qalculator.cpp appdb.hpp appdb.cpp requests.hpp requests.cpp + toaster.hpp toaster.cpp LIBRARIES Qt::Gui Qt::Quick diff --git a/plugin/src/Caelestia/toaster.cpp b/plugin/src/Caelestia/toaster.cpp new file mode 100644 index 0000000..4e2acd5 --- /dev/null +++ b/plugin/src/Caelestia/toaster.cpp @@ -0,0 +1,116 @@ +#include "toaster.hpp" + +#include +#include +#include + +namespace caelestia { + +Toast::Toast(const QString& title, const QString& message, const QString& icon, Type type, int timeout, QObject* parent) + : QObject(parent) + , m_closed(false) + , m_title(title) + , m_message(message) + , m_icon(icon) + , m_type(type) + , m_timeout(timeout) { + QTimer::singleShot(timeout, this, &Toast::close); + + if (m_icon.isEmpty()) { + switch (m_type) { + case Type::Success: + m_icon = "check_circle_unread"; + break; + case Type::Warning: + m_icon = "warning"; + break; + case Type::Error: + m_icon = "error"; + break; + default: + m_icon = "info"; + break; + } + } + + if (timeout <= 0) { + switch (m_type) { + case Type::Warning: + m_timeout = 7000; + break; + case Type::Error: + m_timeout = 10000; + break; + default: + m_timeout = 5000; + break; + } + } +} + +bool Toast::closed() const { + return m_closed; +} + +QString Toast::title() const { + return m_title; +} + +QString Toast::message() const { + return m_message; +} + +QString Toast::icon() const { + return m_icon; +} + +int Toast::timeout() const { + return m_timeout; +} + +Toast::Type Toast::type() const { + return m_type; +} + +void Toast::close() { + if (!m_closed) { + m_closed = true; + emit closedChanged(); + } + + if (m_locks.isEmpty()) { + emit finishedClose(); + } +} + +void Toast::lock(QObject* sender) { + m_locks << sender; + QObject::connect(sender, &QObject::destroyed, this, &Toast::unlock); +} + +void Toast::unlock(QObject* sender) { + if (m_locks.remove(sender) && m_closed) { + close(); + } +} + +Toaster::Toaster(QObject* parent) + : QObject(parent) {} + +QList Toaster::toasts() const { + return m_toasts; +} + +void Toaster::toast(const QString& title, const QString& message, const QString& icon, Toast::Type type, int timeout) { + auto* toast = new Toast(title, message, icon, type, timeout, this); + QObject::connect(toast, &Toast::finishedClose, this, [toast, this]() { + if (m_toasts.removeOne(toast)) { + emit toastsChanged(); + toast->deleteLater(); + } + }); + m_toasts.push_front(toast); + emit toastsChanged(); +} + +} // namespace caelestia diff --git a/plugin/src/Caelestia/toaster.hpp b/plugin/src/Caelestia/toaster.hpp new file mode 100644 index 0000000..22da212 --- /dev/null +++ b/plugin/src/Caelestia/toaster.hpp @@ -0,0 +1,81 @@ +#pragma once + +#include +#include +#include + +namespace caelestia { + +class Toast : public QObject { + Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("Toast instances can only be retrieved from a Toaster") + + Q_PROPERTY(bool closed READ closed NOTIFY closedChanged) + Q_PROPERTY(QString title READ title CONSTANT) + Q_PROPERTY(QString message READ message CONSTANT) + Q_PROPERTY(QString icon READ icon CONSTANT) + Q_PROPERTY(int timeout READ timeout CONSTANT) + Q_PROPERTY(Type type READ type CONSTANT) + +public: + enum class Type { + Info = 0, + Success, + Warning, + Error + }; + Q_ENUM(Type) + + explicit Toast(const QString& title, const QString& message, const QString& icon, Type type, int timeout, + QObject* parent = nullptr); + + [[nodiscard]] bool closed() const; + [[nodiscard]] QString title() const; + [[nodiscard]] QString message() const; + [[nodiscard]] QString icon() const; + [[nodiscard]] int timeout() const; + [[nodiscard]] Type type() const; + + Q_INVOKABLE void close(); + Q_INVOKABLE void lock(QObject* sender); + Q_INVOKABLE void unlock(QObject* sender); + +signals: + void closedChanged(); + void finishedClose(); + +private: + QSet m_locks; + + bool m_closed; + QString m_title; + QString m_message; + QString m_icon; + Type m_type; + int m_timeout; +}; + +class Toaster : public QObject { + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + + Q_PROPERTY(QList toasts READ toasts NOTIFY toastsChanged) + +public: + explicit Toaster(QObject* parent = nullptr); + + [[nodiscard]] QList toasts() const; + + Q_INVOKABLE void toast(const QString& title, const QString& message, const QString& icon = QString(), + Toast::Type type = Toast::Type::Info, int timeout = 5000); + +signals: + void toastsChanged(); + +private: + QList m_toasts; +}; + +} // namespace caelestia -- cgit v1.2.3-freya