Merge pull request #662 from caelestia-dots/toasts
utilities: add toasts & battery warnings
This commit is contained in:
commit
37b61cb0d9
13 changed files with 693 additions and 72 deletions
27
README.md
27
README.md
|
|
@ -253,6 +253,30 @@ default, you must create it manually.
|
|||
"terminal": ["foot"],
|
||||
"audio": ["pavucontrol"]
|
||||
},
|
||||
"battery": {
|
||||
"warnLevels": [
|
||||
{
|
||||
"level": 20,
|
||||
"title": "Low battery",
|
||||
"message": "You might want to plug in a charger",
|
||||
"icon": "battery_android_frame_2"
|
||||
},
|
||||
{
|
||||
"level": 10,
|
||||
"title": "Did you see the previous message?",
|
||||
"message": "You should probably plug in a charger <b>now</b>",
|
||||
"icon": "battery_android_frame_1"
|
||||
},
|
||||
{
|
||||
"level": 5,
|
||||
"title": "Critical battery level",
|
||||
"message": "PLUG THE CHARGER RIGHT NOW!!",
|
||||
"icon": "battery_android_alert",
|
||||
"critical": true
|
||||
}
|
||||
],
|
||||
"criticalLevel": 3
|
||||
},
|
||||
"idle": {
|
||||
"inhibitWhenAudio": true,
|
||||
"lockTimeout": 180,
|
||||
|
|
@ -530,7 +554,8 @@ default, you must create it manually.
|
|||
"enabled": true
|
||||
},
|
||||
"utilities": {
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"maxToasts": 4
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import Quickshell.Io
|
|||
JsonObject {
|
||||
property Apps apps: Apps {}
|
||||
property Idle idle: Idle {}
|
||||
property Battery battery: Battery {}
|
||||
|
||||
component Apps: JsonObject {
|
||||
property list<string> terminal: ["foot"]
|
||||
|
|
@ -17,4 +18,29 @@ JsonObject {
|
|||
property real dpmsTimeout: 300 // 5 mins
|
||||
property real sleepTimeout: 600 // 10 mins
|
||||
}
|
||||
|
||||
component Battery: JsonObject {
|
||||
property list<var> warnLevels: [
|
||||
{
|
||||
level: 20,
|
||||
title: qsTr("Low battery"),
|
||||
message: qsTr("You might want to plug in a charger"),
|
||||
icon: "battery_android_frame_2"
|
||||
},
|
||||
{
|
||||
level: 10,
|
||||
title: qsTr("Did you see the previous message?"),
|
||||
message: qsTr("You should probably plug in a charger <b>now</b>"),
|
||||
icon: "battery_android_frame_1"
|
||||
},
|
||||
{
|
||||
level: 5,
|
||||
title: qsTr("Critical battery level"),
|
||||
message: qsTr("PLUG THE CHARGER RIGHT NOW!!"),
|
||||
icon: "battery_android_alert",
|
||||
critical: true
|
||||
},
|
||||
]
|
||||
property int criticalLevel: 3
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import Quickshell.Io
|
|||
|
||||
JsonObject {
|
||||
property bool enabled: true
|
||||
property int maxToasts: 4
|
||||
|
||||
property Sizes sizes: Sizes {}
|
||||
|
||||
|
|
|
|||
54
modules/BatteryMonitor.qml
Normal file
54
modules/BatteryMonitor.qml
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import qs.config
|
||||
import Caelestia
|
||||
import Quickshell
|
||||
import Quickshell.Services.UPower
|
||||
import QtQuick
|
||||
|
||||
Scope {
|
||||
id: root
|
||||
|
||||
readonly property list<var> warnLevels: [...Config.general.battery.warnLevels].sort((a, b) => b.level - a.level)
|
||||
|
||||
Connections {
|
||||
target: UPower
|
||||
|
||||
function onOnBatteryChanged(): void {
|
||||
if (UPower.onBattery) {
|
||||
Toaster.toast(qsTr("Charger unplugged"), qsTr("Battery is now on AC"), "power_off");
|
||||
} else {
|
||||
Toaster.toast(qsTr("Charger plugged in"), qsTr("Battery is charging"), "battery_android_frame_bolt");
|
||||
for (const level of root.warnLevels)
|
||||
level.warned = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: UPower.displayDevice
|
||||
|
||||
function onPercentageChanged(): void {
|
||||
if (!UPower.onBattery)
|
||||
return;
|
||||
|
||||
const p = UPower.displayDevice.percentage;
|
||||
for (const level of root.warnLevels) {
|
||||
if (p <= level.level && !level.warned) {
|
||||
level.warned = true;
|
||||
Toaster.toast(level.title ?? qsTr("Battery warning"), level.message ?? qsTr("Battery level is low"), level.icon ?? "battery_android_alert", level.critical ? Toast.Error : Toast.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hibernateTimer.running && p <= Config.general.battery.criticalLevel) {
|
||||
Toaster.toast(qsTr("Hibernating in 5 seconds"), qsTr("Hibernating to prevent data loss"), "battery_android_alert", Toast.Error);
|
||||
hibernateTimer.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: hibernateTimer
|
||||
|
||||
interval: 5000
|
||||
onTriggered: Quickshell.execDetached(["systemctl", "hibernate"])
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import qs.components.misc
|
||||
import qs.modules.controlcenter
|
||||
import qs.services
|
||||
import Caelestia
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
|
||||
|
|
@ -95,4 +96,24 @@ Scope {
|
|||
WindowFactory.create();
|
||||
}
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "toaster"
|
||||
|
||||
function info(title: string, message: string, icon: string): void {
|
||||
Toaster.toast(title, message, icon, Toast.Info);
|
||||
}
|
||||
|
||||
function success(title: string, message: string, icon: string): void {
|
||||
Toaster.toast(title, message, icon, Toast.Success);
|
||||
}
|
||||
|
||||
function warn(title: string, message: string, icon: string): void {
|
||||
Toaster.toast(title, message, icon, Toast.Warning);
|
||||
}
|
||||
|
||||
function error(title: string, message: string, icon: string): void {
|
||||
Toaster.toast(title, message, icon, Toast.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import qs.modules.launcher as Launcher
|
|||
import qs.modules.dashboard as Dashboard
|
||||
import qs.modules.bar.popouts as BarPopouts
|
||||
import qs.modules.utilities as Utilities
|
||||
import qs.modules.utilities.toasts as Toasts
|
||||
import qs.modules.sidebar as Sidebar
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
|
@ -17,14 +18,15 @@ Item {
|
|||
required property PersistentProperties visibilities
|
||||
required property Item bar
|
||||
|
||||
readonly property Osd.Wrapper osd: osd
|
||||
readonly property Notifications.Wrapper notifications: notifications
|
||||
readonly property Session.Wrapper session: session
|
||||
readonly property Launcher.Wrapper launcher: launcher
|
||||
readonly property Dashboard.Wrapper dashboard: dashboard
|
||||
readonly property BarPopouts.Wrapper popouts: popouts
|
||||
readonly property Utilities.Wrapper utilities: utilities
|
||||
readonly property Sidebar.Wrapper sidebar: sidebar
|
||||
readonly property alias osd: osd
|
||||
readonly property alias notifications: notifications
|
||||
readonly property alias session: session
|
||||
readonly property alias launcher: launcher
|
||||
readonly property alias dashboard: dashboard
|
||||
readonly property alias popouts: popouts
|
||||
readonly property alias utilities: utilities
|
||||
readonly property alias toasts: toasts
|
||||
readonly property alias sidebar: sidebar
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Config.border.thickness
|
||||
|
|
@ -112,6 +114,14 @@ Item {
|
|||
anchors.right: parent.right
|
||||
}
|
||||
|
||||
Toasts.Toasts {
|
||||
id: toasts
|
||||
|
||||
anchors.bottom: sidebar.visible ? parent.bottom : utilities.top
|
||||
anchors.right: sidebar.left
|
||||
anchors.margins: Appearance.padding.normal
|
||||
}
|
||||
|
||||
Sidebar.Wrapper {
|
||||
id: sidebar
|
||||
|
||||
|
|
|
|||
135
modules/utilities/toasts/ToastItem.qml
Normal file
135
modules/utilities/toasts/ToastItem.qml
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
import qs.components
|
||||
import qs.components.effects
|
||||
import qs.services
|
||||
import qs.config
|
||||
import Caelestia
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
StyledRect {
|
||||
id: root
|
||||
|
||||
required property Toast modelData
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
implicitHeight: layout.implicitHeight + Appearance.padding.smaller * 2
|
||||
|
||||
radius: Appearance.rounding.normal
|
||||
color: {
|
||||
if (root.modelData.type === Toast.Success)
|
||||
return Colours.palette.m3successContainer;
|
||||
if (root.modelData.type === Toast.Warning)
|
||||
return Colours.palette.m3secondary;
|
||||
if (root.modelData.type === Toast.Error)
|
||||
return Colours.palette.m3errorContainer;
|
||||
return Colours.palette.m3surface;
|
||||
}
|
||||
|
||||
border.width: 1
|
||||
border.color: {
|
||||
let colour = Colours.palette.m3outlineVariant;
|
||||
if (root.modelData.type === Toast.Success)
|
||||
colour = Colours.palette.m3success;
|
||||
if (root.modelData.type === Toast.Warning)
|
||||
colour = Colours.palette.m3secondaryContainer;
|
||||
if (root.modelData.type === Toast.Error)
|
||||
colour = Colours.palette.m3error;
|
||||
return Qt.alpha(colour, 0.3);
|
||||
}
|
||||
|
||||
Elevation {
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
opacity: parent.opacity
|
||||
z: -1
|
||||
level: 3
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: layout
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Appearance.padding.smaller
|
||||
anchors.leftMargin: Appearance.padding.normal
|
||||
anchors.rightMargin: Appearance.padding.normal
|
||||
spacing: Appearance.spacing.normal
|
||||
|
||||
StyledRect {
|
||||
radius: Appearance.rounding.normal
|
||||
color: {
|
||||
if (root.modelData.type === Toast.Success)
|
||||
return Colours.palette.m3success;
|
||||
if (root.modelData.type === Toast.Warning)
|
||||
return Colours.palette.m3secondaryContainer;
|
||||
if (root.modelData.type === Toast.Error)
|
||||
return Colours.palette.m3error;
|
||||
return Colours.palette.m3surfaceContainerHigh;
|
||||
}
|
||||
|
||||
implicitWidth: implicitHeight
|
||||
implicitHeight: icon.implicitHeight + Appearance.padding.normal * 2
|
||||
|
||||
MaterialIcon {
|
||||
id: icon
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: root.modelData.icon
|
||||
color: {
|
||||
if (root.modelData.type === Toast.Success)
|
||||
return Colours.palette.m3onSuccess;
|
||||
if (root.modelData.type === Toast.Warning)
|
||||
return Colours.palette.m3onSecondaryContainer;
|
||||
if (root.modelData.type === Toast.Error)
|
||||
return Colours.palette.m3onError;
|
||||
return Colours.palette.m3onSurfaceVariant;
|
||||
}
|
||||
font.pointSize: Appearance.font.size.large
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
StyledText {
|
||||
id: title
|
||||
|
||||
Layout.fillWidth: true
|
||||
text: root.modelData.title
|
||||
color: {
|
||||
if (root.modelData.type === Toast.Success)
|
||||
return Colours.palette.m3onSuccessContainer;
|
||||
if (root.modelData.type === Toast.Warning)
|
||||
return Colours.palette.m3onSecondary;
|
||||
if (root.modelData.type === Toast.Error)
|
||||
return Colours.palette.m3onErrorContainer;
|
||||
return Colours.palette.m3onSurface;
|
||||
}
|
||||
font.pointSize: Appearance.font.size.normal
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
StyledText {
|
||||
Layout.fillWidth: true
|
||||
textFormat: Text.StyledText
|
||||
text: root.modelData.message
|
||||
color: {
|
||||
if (root.modelData.type === Toast.Success)
|
||||
return Colours.palette.m3onSuccessContainer;
|
||||
if (root.modelData.type === Toast.Warning)
|
||||
return Colours.palette.m3onSecondary;
|
||||
if (root.modelData.type === Toast.Error)
|
||||
return Colours.palette.m3onErrorContainer;
|
||||
return Colours.palette.m3onSurface;
|
||||
}
|
||||
opacity: 0.8
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
142
modules/utilities/toasts/Toasts.qml
Normal file
142
modules/utilities/toasts/Toasts.qml
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
pragma ComponentBehavior: Bound
|
||||
|
||||
import qs.components
|
||||
import qs.config
|
||||
import Caelestia
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property int spacing: Appearance.spacing.small
|
||||
property bool flag
|
||||
|
||||
implicitWidth: Config.utilities.sizes.width - Appearance.padding.normal * 2
|
||||
implicitHeight: {
|
||||
let h = -spacing;
|
||||
for (let i = 0; i < repeater.count; i++) {
|
||||
const item = repeater.itemAt(i);
|
||||
if (!item.modelData.closed && !item.previewHidden)
|
||||
h += item.implicitHeight + spacing;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
|
||||
model: ScriptModel {
|
||||
values: {
|
||||
const toasts = [];
|
||||
let count = 0;
|
||||
for (const toast of Toaster.toasts) {
|
||||
toasts.push(toast);
|
||||
if (!toast.closed) {
|
||||
count++;
|
||||
if (count > Config.utilities.maxToasts)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return toasts;
|
||||
}
|
||||
onValuesChanged: root.flagChanged()
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: toast
|
||||
|
||||
required property int index
|
||||
required property Toast modelData
|
||||
|
||||
readonly property bool previewHidden: {
|
||||
let extraHidden = 0;
|
||||
for (let i = 0; i < index; i++)
|
||||
if (Toaster.toasts[i].closed)
|
||||
extraHidden++;
|
||||
return index >= Config.utilities.maxToasts + extraHidden;
|
||||
}
|
||||
|
||||
onPreviewHiddenChanged: {
|
||||
if (initAnim.running && previewHidden)
|
||||
initAnim.stop();
|
||||
}
|
||||
|
||||
opacity: modelData.closed || previewHidden ? 0 : 1
|
||||
scale: modelData.closed || previewHidden ? 0.7 : 1
|
||||
|
||||
anchors.bottomMargin: {
|
||||
root.flag; // Force update
|
||||
let y = 0;
|
||||
for (let i = 0; i < index; i++) {
|
||||
const item = repeater.itemAt(i);
|
||||
if (item && !item.modelData.closed && !item.previewHidden)
|
||||
y += item.implicitHeight + root.spacing;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
implicitHeight: toastInner.implicitHeight
|
||||
|
||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
|
||||
onClicked: modelData.close()
|
||||
|
||||
Component.onCompleted: modelData.lock(this)
|
||||
|
||||
Anim {
|
||||
id: initAnim
|
||||
|
||||
Component.onCompleted: running = !toast.previewHidden
|
||||
|
||||
target: toast
|
||||
properties: "opacity,scale"
|
||||
from: 0
|
||||
to: 1
|
||||
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
||||
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
||||
}
|
||||
|
||||
ParallelAnimation {
|
||||
running: toast.modelData.closed
|
||||
onStarted: toast.anchors.bottomMargin = toast.anchors.bottomMargin
|
||||
onFinished: toast.modelData.unlock(toast)
|
||||
|
||||
Anim {
|
||||
target: toast
|
||||
property: "opacity"
|
||||
to: 0
|
||||
}
|
||||
Anim {
|
||||
target: toast
|
||||
property: "scale"
|
||||
to: 0.7
|
||||
}
|
||||
}
|
||||
|
||||
ToastItem {
|
||||
id: toastInner
|
||||
|
||||
modelData: toast.modelData
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
Anim {}
|
||||
}
|
||||
|
||||
Behavior on anchors.bottomMargin {
|
||||
Anim {
|
||||
duration: Appearance.anim.durations.expressiveDefaultSpatial
|
||||
easing.bezierCurve: Appearance.anim.curves.expressiveDefaultSpatial
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
116
plugin/src/Caelestia/toaster.cpp
Normal file
116
plugin/src/Caelestia/toaster.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#include "toaster.hpp"
|
||||
|
||||
#include <qdebug.h>
|
||||
#include <qlogging.h>
|
||||
#include <qtimer.h>
|
||||
|
||||
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<Toast*> 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
|
||||
81
plugin/src/Caelestia/toaster.hpp
Normal file
81
plugin/src/Caelestia/toaster.hpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#pragma once
|
||||
|
||||
#include <qobject.h>
|
||||
#include <qqmlintegration.h>
|
||||
#include <qset.h>
|
||||
|
||||
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<QObject*> 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<Toast*> toasts READ toasts NOTIFY toastsChanged)
|
||||
|
||||
public:
|
||||
explicit Toaster(QObject* parent = nullptr);
|
||||
|
||||
[[nodiscard]] QList<Toast*> 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<Toast*> m_toasts;
|
||||
};
|
||||
|
||||
} // namespace caelestia
|
||||
|
|
@ -146,6 +146,10 @@ Singleton {
|
|||
readonly property color m3onError: root.layer(root.palette.m3onError)
|
||||
readonly property color m3errorContainer: root.layer(root.palette.m3errorContainer)
|
||||
readonly property color m3onErrorContainer: root.layer(root.palette.m3onErrorContainer)
|
||||
readonly property color m3success: root.layer(root.palette.m3success)
|
||||
readonly property color m3onSuccess: root.layer(root.palette.m3onSuccess)
|
||||
readonly property color m3successContainer: root.layer(root.palette.m3successContainer)
|
||||
readonly property color m3onSuccessContainer: root.layer(root.palette.m3onSuccessContainer)
|
||||
readonly property color m3primaryFixed: root.layer(root.palette.m3primaryFixed)
|
||||
readonly property color m3primaryFixedDim: root.layer(root.palette.m3primaryFixedDim)
|
||||
readonly property color m3onPrimaryFixed: root.layer(root.palette.m3onPrimaryFixed)
|
||||
|
|
@ -161,75 +165,79 @@ Singleton {
|
|||
}
|
||||
|
||||
component M3Palette: QtObject {
|
||||
property color m3primary_paletteKeyColor: "#a26387"
|
||||
property color m3secondary_paletteKeyColor: "#8b6f7d"
|
||||
property color m3tertiary_paletteKeyColor: "#9c6c53"
|
||||
property color m3neutral_paletteKeyColor: "#7f7478"
|
||||
property color m3neutral_variant_paletteKeyColor: "#827379"
|
||||
property color m3background: "#181115"
|
||||
property color m3onBackground: "#eddfe4"
|
||||
property color m3surface: "#181115"
|
||||
property color m3surfaceDim: "#181115"
|
||||
property color m3surfaceBright: "#40373b"
|
||||
property color m3surfaceContainerLowest: "#130c10"
|
||||
property color m3surfaceContainerLow: "#211a1d"
|
||||
property color m3surfaceContainer: "#251e21"
|
||||
property color m3surfaceContainerHigh: "#30282b"
|
||||
property color m3surfaceContainerHighest: "#3b3236"
|
||||
property color m3onSurface: "#eddfe4"
|
||||
property color m3surfaceVariant: "#504349"
|
||||
property color m3onSurfaceVariant: "#d3c2c9"
|
||||
property color m3inverseSurface: "#eddfe4"
|
||||
property color m3inverseOnSurface: "#362e32"
|
||||
property color m3outline: "#9c8d93"
|
||||
property color m3outlineVariant: "#504349"
|
||||
property color m3primary_paletteKeyColor: "#a8627b"
|
||||
property color m3secondary_paletteKeyColor: "#8e6f78"
|
||||
property color m3tertiary_paletteKeyColor: "#986e4c"
|
||||
property color m3neutral_paletteKeyColor: "#807477"
|
||||
property color m3neutral_variant_paletteKeyColor: "#837377"
|
||||
property color m3background: "#191114"
|
||||
property color m3onBackground: "#efdfe2"
|
||||
property color m3surface: "#191114"
|
||||
property color m3surfaceDim: "#191114"
|
||||
property color m3surfaceBright: "#403739"
|
||||
property color m3surfaceContainerLowest: "#130c0e"
|
||||
property color m3surfaceContainerLow: "#22191c"
|
||||
property color m3surfaceContainer: "#261d20"
|
||||
property color m3surfaceContainerHigh: "#31282a"
|
||||
property color m3surfaceContainerHighest: "#3c3235"
|
||||
property color m3onSurface: "#efdfe2"
|
||||
property color m3surfaceVariant: "#514347"
|
||||
property color m3onSurfaceVariant: "#d5c2c6"
|
||||
property color m3inverseSurface: "#efdfe2"
|
||||
property color m3inverseOnSurface: "#372e30"
|
||||
property color m3outline: "#9e8c91"
|
||||
property color m3outlineVariant: "#514347"
|
||||
property color m3shadow: "#000000"
|
||||
property color m3scrim: "#000000"
|
||||
property color m3surfaceTint: "#fbb1d8"
|
||||
property color m3primary: "#fbb1d8"
|
||||
property color m3onPrimary: "#511d3e"
|
||||
property color m3primaryContainer: "#6b3455"
|
||||
property color m3onPrimaryContainer: "#ffd8ea"
|
||||
property color m3inversePrimary: "#864b6e"
|
||||
property color m3secondary: "#dfbecd"
|
||||
property color m3onSecondary: "#402a36"
|
||||
property color m3secondaryContainer: "#5a424f"
|
||||
property color m3onSecondaryContainer: "#fcd9e9"
|
||||
property color m3tertiary: "#f3ba9c"
|
||||
property color m3onTertiary: "#4a2713"
|
||||
property color m3tertiaryContainer: "#b8856a"
|
||||
property color m3surfaceTint: "#ffb0ca"
|
||||
property color m3primary: "#ffb0ca"
|
||||
property color m3onPrimary: "#541d34"
|
||||
property color m3primaryContainer: "#6f334a"
|
||||
property color m3onPrimaryContainer: "#ffd9e3"
|
||||
property color m3inversePrimary: "#8b4a62"
|
||||
property color m3secondary: "#e2bdc7"
|
||||
property color m3onSecondary: "#422932"
|
||||
property color m3secondaryContainer: "#5a3f48"
|
||||
property color m3onSecondaryContainer: "#ffd9e3"
|
||||
property color m3tertiary: "#f0bc95"
|
||||
property color m3onTertiary: "#48290c"
|
||||
property color m3tertiaryContainer: "#b58763"
|
||||
property color m3onTertiaryContainer: "#000000"
|
||||
property color m3error: "#ffb4ab"
|
||||
property color m3onError: "#690005"
|
||||
property color m3errorContainer: "#93000a"
|
||||
property color m3onErrorContainer: "#ffdad6"
|
||||
property color m3primaryFixed: "#ffd8ea"
|
||||
property color m3primaryFixedDim: "#fbb1d8"
|
||||
property color m3onPrimaryFixed: "#370728"
|
||||
property color m3onPrimaryFixedVariant: "#6b3455"
|
||||
property color m3secondaryFixed: "#fcd9e9"
|
||||
property color m3secondaryFixedDim: "#dfbecd"
|
||||
property color m3onSecondaryFixed: "#291520"
|
||||
property color m3onSecondaryFixedVariant: "#58404c"
|
||||
property color m3tertiaryFixed: "#ffdbca"
|
||||
property color m3tertiaryFixedDim: "#f3ba9c"
|
||||
property color m3onTertiaryFixed: "#311302"
|
||||
property color m3onTertiaryFixedVariant: "#653d27"
|
||||
property color term0: "#353434"
|
||||
property color term1: "#fe45a7"
|
||||
property color term2: "#ffbac0"
|
||||
property color term3: "#ffdee3"
|
||||
property color term4: "#b3a2d5"
|
||||
property color term5: "#e491bd"
|
||||
property color term6: "#ffba93"
|
||||
property color term7: "#edd2d5"
|
||||
property color term8: "#b29ea1"
|
||||
property color term9: "#ff7db7"
|
||||
property color term10: "#ffd2d5"
|
||||
property color term11: "#fff1f2"
|
||||
property color term12: "#babfdd"
|
||||
property color term13: "#f3a9cd"
|
||||
property color term14: "#ffd1c0"
|
||||
property color term15: "#ffffff"
|
||||
property color m3success: "#B5CCBA"
|
||||
property color m3onSuccess: "#213528"
|
||||
property color m3successContainer: "#374B3E"
|
||||
property color m3onSuccessContainer: "#D1E9D6"
|
||||
property color m3primaryFixed: "#ffd9e3"
|
||||
property color m3primaryFixedDim: "#ffb0ca"
|
||||
property color m3onPrimaryFixed: "#39071f"
|
||||
property color m3onPrimaryFixedVariant: "#6f334a"
|
||||
property color m3secondaryFixed: "#ffd9e3"
|
||||
property color m3secondaryFixedDim: "#e2bdc7"
|
||||
property color m3onSecondaryFixed: "#2b151d"
|
||||
property color m3onSecondaryFixedVariant: "#5a3f48"
|
||||
property color m3tertiaryFixed: "#ffdcc3"
|
||||
property color m3tertiaryFixedDim: "#f0bc95"
|
||||
property color m3onTertiaryFixed: "#2f1500"
|
||||
property color m3onTertiaryFixedVariant: "#623f21"
|
||||
property color m3term0: "#353434"
|
||||
property color m3term1: "#ff4c8a"
|
||||
property color m3term2: "#ffbbb7"
|
||||
property color m3term3: "#ffdedf"
|
||||
property color m3term4: "#b3a2d5"
|
||||
property color m3term5: "#e98fb0"
|
||||
property color m3term6: "#ffba93"
|
||||
property color m3term7: "#eed1d2"
|
||||
property color m3term8: "#b39e9e"
|
||||
property color m3term9: "#ff80a3"
|
||||
property color m3term10: "#ffd3d0"
|
||||
property color m3term11: "#fff1f0"
|
||||
property color m3term12: "#dcbc93"
|
||||
property color m3term13: "#f9a8c2"
|
||||
property color m3term14: "#ffd1c0"
|
||||
property color m3term15: "#ffffff"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ ShellRoot {
|
|||
}
|
||||
|
||||
Shortcuts {}
|
||||
BatteryMonitor {}
|
||||
IdleMonitors {
|
||||
lock: lock
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue