Toast: refactored service vs UI.

This commit is contained in:
LemmyCook 2025-09-14 13:15:13 -04:00
parent f9d7de2e3c
commit d348cfc2b0
8 changed files with 341 additions and 526 deletions

View file

@ -2,247 +2,23 @@ pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Commons
Singleton {
id: root
// Queue of pending toast messages
property var messageQueue: []
property bool isShowingToast: false
// Simple signal-based notification system
signal notify(string message, string description, string type, int duration)
// Reference to all toast instances (set by ToastOverlay)
property var allToasts: []
// Properties for command checking
property var commandCheckCallback: null
property string commandCheckSuccessMessage: ""
property string commandCheckFailMessage: ""
// Properties for command running
property var commandRunCallback: null
property string commandRunSuccessMessage: ""
property string commandRunFailMessage: ""
// Properties for delayed toast
property string delayedToastMessage: ""
property string delayedToastType: "notice"
// Process for command checking
Process {
id: commandCheckProcess
command: ["which", "test"]
onExited: function (exitCode) {
if (exitCode === 0) {
showNotice(commandCheckSuccessMessage)
if (commandCheckCallback)
commandCheckCallback()
} else {
showWarning(commandCheckFailMessage)
}
}
stdout: StdioCollector {}
stderr: StdioCollector {}
// Convenience methods
function showNotice(message, description = "", duration = 3000) {
notify(message, description, "notice", duration)
}
// Process for command running
Process {
id: commandRunProcess
command: ["echo", "test"]
onExited: function (exitCode) {
if (exitCode === 0) {
showNotice(commandRunSuccessMessage)
if (commandRunCallback)
commandRunCallback()
} else {
showWarning(commandRunFailMessage)
}
}
stdout: StdioCollector {}
stderr: StdioCollector {}
function showWarning(message, description = "", duration = 4000) {
notify(message, description, "warning", duration)
}
// Timer for delayed toast
Timer {
id: delayedToastTimer
interval: 1000
repeat: false
onTriggered: {
showToast(delayedToastMessage, delayedToastType)
}
}
// Methods to show different types of messages
function showNotice(label, description = "", persistent = false, duration = 3000) {
showToast(label, description, "notice", persistent, duration)
}
function showWarning(label, description = "", persistent = false, duration = 4000) {
showToast(label, description, "warning", persistent, duration)
}
// Utility function to check if a command exists and show appropriate toast
function checkCommandAndToast(command, successMessage, failMessage, onSuccess = null) {
// Store callback for use in the process
commandCheckCallback = onSuccess
commandCheckSuccessMessage = successMessage
commandCheckFailMessage = failMessage
// Start the command check process
commandCheckProcess.command = ["which", command]
commandCheckProcess.running = true
}
// Simple function to show a random toast (useful for testing or fun messages)
function showRandomToast() {
var messages = [{
"type": "notice",
"text": "Everything is working smoothly!"
}, {
"type": "notice",
"text": "Noctalia is looking great today!"
}, {
"type": "notice",
"text": "Your desktop setup is amazing!"
}, {
"type": "warning",
"text": "Don't forget to take a break!"
}, {
"type": "notice",
"text": "Configuration saved successfully!"
}, {
"type": "warning",
"text": "Remember to backup your settings!"
}]
var randomMessage = messages[Math.floor(Math.random() * messages.length)]
showToast(randomMessage.text, randomMessage.type)
}
// Convenience function for quick notifications
function quickNotice(message) {
showNotice(message, false, 2000) // Short duration
}
function quickWarning(message) {
showWarning(message, false, 3000) // Medium duration
}
// Generic command runner with toast feedback
function runCommandWithToast(command, args, successMessage, failMessage, onSuccess = null) {
// Store callback for use in the process
commandRunCallback = onSuccess
commandRunSuccessMessage = successMessage
commandRunFailMessage = failMessage
// Start the command run process
commandRunProcess.command = [command].concat(args || [])
commandRunProcess.running = true
}
// Check if a file/directory exists
function checkPathAndToast(path, successMessage, failMessage, onSuccess = null) {
runCommandWithToast("test", ["-e", path], successMessage, failMessage, onSuccess)
}
// Show toast after a delay (useful for delayed feedback)
function delayedToast(message, type = "notice", delayMs = 1000) {
delayedToastMessage = message
delayedToastType = type
delayedToastTimer.interval = delayMs
delayedToastTimer.restart()
}
// Generic method to show a toast
function showToast(label, description = "", type = "notice", persistent = false, duration = 3000) {
var toastData = {
"label": label,
"description": description,
"type": type,
"persistent": persistent,
"duration": duration,
"timestamp": Date.now()
}
// If there's already a toast showing, instantly start hide animation and show new one
if (isShowingToast) {
// Instantly start hide animation of current toast
for (var i = 0; i < allToasts.length; i++) {
allToasts[i].hide()
}
// Clear the queue since we're showing the new toast immediately
messageQueue = []
}
// Add to queue
messageQueue.push(toastData)
// Always process immediately for instant display
processQueue()
}
// Process the message queue
function processQueue() {
if (messageQueue.length === 0 || allToasts.length === 0) {
// Added this so we don't accidentally get duplicate toasts
// if it causes issues, remove it and we'll find a different solution
if (allToasts.length === 0 && messageQueue.length > 0) {
messageQueue = []
}
isShowingToast = false
return
}
var toastData = messageQueue.shift()
isShowingToast = true
// Configure and show toast on all screens
for (var i = 0; i < allToasts.length; i++) {
var toast = allToasts[i]
toast.label = toastData.label
toast.description = toastData.description
toast.type = toastData.type
toast.persistent = toastData.persistent
toast.duration = toastData.duration
toast.show()
}
}
// Called when a toast is dismissed
function onToastDismissed() {
// Check if all toasts are dismissed
var allDismissed = true
for (var i = 0; i < allToasts.length; i++) {
if (allToasts[i].visible) {
allDismissed = false
break
}
}
if (allDismissed) {
isShowingToast = false
// Small delay before showing next toast
Qt.callLater(function () {
processQueue()
})
}
}
// Clear all pending messages
function clearQueue() {
messageQueue = []
}
// Hide current toast
function hideCurrentToast() {
if (isShowingToast) {
for (var i = 0; i < allToasts.length; i++) {
allToasts[i].hide()
}
}
function showError(message, description = "", duration = 5000) {
notify(message, description, "error", duration)
}
}