mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
PluginSystem+Toast: added toast actiong to go straight to the plugin tab
This commit is contained in:
@@ -2246,7 +2246,9 @@
|
||||
"update": "Update",
|
||||
"update-all": "Update All ({count})",
|
||||
"update-all-success": "All plugins updated successfully",
|
||||
"update-available": "{count} plugins update(s) available",
|
||||
"update-available": "{count} plugin update available",
|
||||
"update-available_plural": "{count} plugin updates available",
|
||||
"open-plugins-tab": "Open plugins settings",
|
||||
"update-error": "Failed to update plugin: {plugin}: {error}",
|
||||
"update-incompatible": "Requires Noctalia v{version} or higher",
|
||||
"update-success": "Updated {plugin} to v{version}",
|
||||
|
||||
@@ -12,6 +12,8 @@ Item {
|
||||
property string icon: ""
|
||||
property string type: "notice"
|
||||
property int duration: 3000
|
||||
property string actionLabel: ""
|
||||
property var actionCallback: null
|
||||
readonly property real initialScale: 0.7
|
||||
|
||||
signal hidden
|
||||
@@ -94,6 +96,14 @@ Item {
|
||||
hideAnimation.stop();
|
||||
}
|
||||
|
||||
// Click anywhere dismiss the toast (must be before content so action link can override)
|
||||
MouseArea {
|
||||
anchors.fill: background
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onClicked: root.hide()
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: contentLayout
|
||||
anchors.fill: background
|
||||
@@ -152,18 +162,23 @@ Item {
|
||||
wrapMode: Text.WordWrap
|
||||
visible: text.length > 0
|
||||
}
|
||||
|
||||
// Action button
|
||||
NButton {
|
||||
text: root.actionLabel
|
||||
visible: root.actionLabel.length > 0 && root.actionCallback !== null
|
||||
Layout.topMargin: Style.marginXS
|
||||
onClicked: {
|
||||
if (root.actionCallback) {
|
||||
root.actionCallback();
|
||||
root.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Click anywhere dismiss the toast
|
||||
MouseArea {
|
||||
anchors.fill: background
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onClicked: root.hide()
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
|
||||
function show(msg, desc, msgIcon, msgType, msgDuration) {
|
||||
function show(msg, desc, msgIcon, msgType, msgDuration, msgActionLabel, msgActionCallback) {
|
||||
// Stop all timers first
|
||||
hideTimer.stop();
|
||||
hideAnimation.stop();
|
||||
@@ -173,6 +188,8 @@ Item {
|
||||
icon = msgIcon || "";
|
||||
type = msgType || "notice";
|
||||
duration = msgDuration || 3000;
|
||||
actionLabel = msgActionLabel || "";
|
||||
actionCallback = msgActionCallback || null;
|
||||
|
||||
visible = true;
|
||||
opacity = 1;
|
||||
|
||||
@@ -20,13 +20,15 @@ Item {
|
||||
Connections {
|
||||
target: ToastService
|
||||
|
||||
function onNotify(message, description, icon, type, duration) {
|
||||
function onNotify(message, description, icon, type, duration, actionLabel, actionCallback) {
|
||||
root.enqueueToast({
|
||||
"message": message,
|
||||
"description": description,
|
||||
"icon": icon,
|
||||
"type": type,
|
||||
"duration": duration,
|
||||
"actionLabel": actionLabel || "",
|
||||
"actionCallback": actionCallback || null,
|
||||
"timestamp": Date.now()
|
||||
});
|
||||
}
|
||||
@@ -121,7 +123,7 @@ Item {
|
||||
onStatusChanged: {
|
||||
// When loader becomes ready, show the pending toast
|
||||
if (status === Loader.Ready && pendingToast !== null) {
|
||||
item.showToast(pendingToast.message, pendingToast.description, pendingToast.icon, pendingToast.type, pendingToast.duration);
|
||||
item.showToast(pendingToast.message, pendingToast.description, pendingToast.icon, pendingToast.type, pendingToast.duration, pendingToast.actionLabel, pendingToast.actionCallback);
|
||||
pendingToast = null;
|
||||
}
|
||||
}
|
||||
@@ -215,8 +217,8 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
function showToast(message, description, icon, type, duration) {
|
||||
toastItem.show(message, description, icon, type, duration);
|
||||
function showToast(message, description, icon, type, duration, actionLabel, actionCallback) {
|
||||
toastItem.show(message, description, icon, type, duration, actionLabel, actionCallback);
|
||||
}
|
||||
|
||||
function hideToast() {
|
||||
|
||||
@@ -4,6 +4,7 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Commons
|
||||
import qs.Modules.Panels.Settings
|
||||
import qs.Services.Noctalia
|
||||
import qs.Services.UI
|
||||
|
||||
@@ -1143,9 +1144,27 @@ Singleton {
|
||||
|
||||
if (updateCount > 0) {
|
||||
Logger.i("PluginService", updateCount, "plugin update(s) available");
|
||||
ToastService.showNotice(I18n.tr("settings.plugins.update-available", {
|
||||
"count": updateCount
|
||||
}), I18n.tr("common.check-settings"));
|
||||
ToastService.showNotice(I18n.trp("settings.plugins.update-available", updateCount, "{count} plugin update available", "{count} plugin updates available", {
|
||||
"count": updateCount
|
||||
}), "", "plugin", 5000, I18n.tr("settings.plugins.open-plugins-tab"), function () {
|
||||
// Open settings panel to Plugins tab on the screen where the cursor is
|
||||
if (root.screenDetector) {
|
||||
root.screenDetector.withCurrentScreen(function (screen) {
|
||||
var panel = PanelService.getPanel("settingsPanel", screen);
|
||||
if (panel) {
|
||||
panel.requestedTab = SettingsPanel.Tab.Plugins;
|
||||
panel.open();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Fallback to primary screen if screen detector is not available
|
||||
var panel = PanelService.getPanel("settingsPanel", Quickshell.screens[0]);
|
||||
if (panel) {
|
||||
panel.requestedTab = SettingsPanel.Tab.Plugins;
|
||||
panel.open();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Logger.i("PluginService", "All plugins are up to date");
|
||||
}
|
||||
|
||||
@@ -7,18 +7,20 @@ Singleton {
|
||||
id: root
|
||||
|
||||
// Simple signal-based notification system
|
||||
signal notify(string message, string description, string icon, string type, int duration)
|
||||
// actionLabel: optional label for clickable action link
|
||||
// actionCallback: optional function to call when action is clicked
|
||||
signal notify(string message, string description, string icon, string type, int duration, string actionLabel, var actionCallback)
|
||||
|
||||
// Convenience methods
|
||||
function showNotice(message, description = "", icon = "", duration = 3000) {
|
||||
notify(message, description, icon, "notice", duration);
|
||||
function showNotice(message, description = "", icon = "", duration = 3000, actionLabel = "", actionCallback = null) {
|
||||
notify(message, description, icon, "notice", duration, actionLabel, actionCallback);
|
||||
}
|
||||
|
||||
function showWarning(message, description = "", duration = 4000) {
|
||||
notify(message, description, "", "warning", duration);
|
||||
function showWarning(message, description = "", duration = 4000, actionLabel = "", actionCallback = null) {
|
||||
notify(message, description, "", "warning", duration, actionLabel, actionCallback);
|
||||
}
|
||||
|
||||
function showError(message, description = "", duration = 6000) {
|
||||
notify(message, description, "", "error", duration);
|
||||
function showError(message, description = "", duration = 6000, actionLabel = "", actionCallback = null) {
|
||||
notify(message, description, "", "error", duration, actionLabel, actionCallback);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user