Feedback immediato al clic: stato ottimistico, stato autorevole dall'output del comando, pulsazione+Plasmoid.busy durante l'operazione, polling 3s
This commit is contained in:
@@ -148,12 +148,15 @@ cmd_off() {
|
||||
"$SYSTEMCTL" --user stop "$UNIT_SCREEN" "$UNIT_SLEEP" >/dev/null 2>&1
|
||||
fi
|
||||
rm -f "$DEADLINE_FILE"
|
||||
if [ "$notify" = "notify" ] && command -v notify-send >/dev/null 2>&1; then
|
||||
notify-send -a "Caffeine" -i preferences-system-power-management \
|
||||
"Caffeine disattivato" \
|
||||
"Il timer è scaduto: schermo e sospensione tornano alla gestione automatica." || true
|
||||
fi
|
||||
echo "ok=1"
|
||||
cmd_status
|
||||
if [ "$notify" = "notify" ] && command -v notify-send >/dev/null 2>&1; then
|
||||
# in background: non ritarda la conferma al plasmoid
|
||||
(notify-send -a "Caffeine" -i preferences-system-power-management \
|
||||
"Caffeine disattivato" \
|
||||
"Il timer è scaduto: schermo e sospensione tornano alla gestione automatica." \
|
||||
>/dev/null 2>&1 &)
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_toggle() {
|
||||
|
||||
+79
-15
@@ -32,6 +32,9 @@ PlasmoidItem {
|
||||
property bool timerExpiring: false
|
||||
property bool unitsReady: false
|
||||
property string lastError: ""
|
||||
// operazione in corso verso il backend (feedback ottimistico)
|
||||
property bool pending: false
|
||||
property string pendingTarget: "" // stato atteso: on | off
|
||||
|
||||
readonly property bool active: backendState === "on"
|
||||
readonly property bool timerActive: active && remainingSec > 0
|
||||
@@ -41,10 +44,13 @@ PlasmoidItem {
|
||||
// ------------------------------------------------------------ presentazione
|
||||
Plasmoid.icon: active ? iconOnPath : iconOffPath
|
||||
Plasmoid.status: active ? PlasmaCore.Types.ActiveStatus : PlasmaCore.Types.PassiveStatus
|
||||
toolTipMainText: active ? "Caffeine attivo" : "Caffeine inattivo"
|
||||
Plasmoid.busy: pending
|
||||
toolTipMainText: pending
|
||||
? "Caffeine: aggiornamento…"
|
||||
: (active ? "Caffeine attivo" : "Caffeine inattivo")
|
||||
toolTipTextFormat: Text.PlainText
|
||||
toolTipSubText: {
|
||||
let text = modeText()
|
||||
let text = pending ? "Operazione in corso verso il backend…" : modeText()
|
||||
if (timerActive) {
|
||||
text += "\nSi disattiva automaticamente tra " + formatDuration(remainingSec)
|
||||
}
|
||||
@@ -89,6 +95,18 @@ PlasmoidItem {
|
||||
values[line.substring(0, index)] = line.substring(index + 1).trim()
|
||||
}
|
||||
})
|
||||
// durante un'operazione in corso i risultati del polling periodico
|
||||
// potrebbero essere ancora quelli vecchi: non smentire l'icona
|
||||
// ottimistica finché il backend non conferma il cambio di stato
|
||||
if (pending && pendingTarget !== "") {
|
||||
const confirmed = pendingTarget === "off"
|
||||
? values["state"] === "off"
|
||||
: values["state"] === "on"
|
||||
if (!confirmed) {
|
||||
return
|
||||
}
|
||||
clearPending()
|
||||
}
|
||||
if (values["backend"] !== undefined) {
|
||||
backend = values["backend"]
|
||||
}
|
||||
@@ -129,20 +147,46 @@ PlasmoidItem {
|
||||
statusSource.connectSource(statusCommand)
|
||||
}
|
||||
|
||||
// ------------------------------------------------- feedback ottimistico
|
||||
// Il backend risponde in ~70 ms, ma la conferma poteva arrivare solo al
|
||||
// giro di polling successivo: l'icona viene quindi aggiornata subito e
|
||||
// messa in stato "pending" (pulsazione + busy) finché il backend conferma.
|
||||
function beginPending(target) {
|
||||
pending = true
|
||||
pendingTarget = target
|
||||
pendingTimeout.restart()
|
||||
}
|
||||
|
||||
function clearPending() {
|
||||
pending = false
|
||||
pendingTarget = ""
|
||||
pendingTimeout.stop()
|
||||
}
|
||||
|
||||
// output autorevole del comando appena eseguito (contiene state=/mode=)
|
||||
function finishPending(output) {
|
||||
clearPending()
|
||||
applyStatus(output)
|
||||
}
|
||||
|
||||
function activate() {
|
||||
const minutes = plasmoid.configuration.autoOffMinutes
|
||||
timerExpiring = false
|
||||
run("on " + startMode + " " + minutes)
|
||||
backendState = "on"
|
||||
backendMode = startMode
|
||||
remainingSec = minutes > 0 ? minutes * 60 : 0
|
||||
refreshDelay.restart()
|
||||
beginPending("on")
|
||||
run("on " + startMode + " " + minutes)
|
||||
}
|
||||
|
||||
function deactivate(fromTimer) {
|
||||
const notify = (fromTimer === true && plasmoid.configuration.notifyOnTimerEnd) ? " notify" : ""
|
||||
run("off" + notify)
|
||||
backendState = "off"
|
||||
backendMode = "none"
|
||||
remainingSec = 0
|
||||
deadlineEpoch = 0
|
||||
refreshDelay.restart()
|
||||
beginPending("off")
|
||||
run("off" + notify)
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
@@ -168,8 +212,9 @@ PlasmoidItem {
|
||||
return
|
||||
}
|
||||
timerExpiring = false
|
||||
backendMode = keepScreen ? "screen" : "sleep"
|
||||
beginPending("on")
|
||||
run("switch " + (keepScreen ? "screen" : "sleep"))
|
||||
refreshDelay.restart()
|
||||
}
|
||||
|
||||
function changeTimer(minutes) {
|
||||
@@ -177,6 +222,7 @@ PlasmoidItem {
|
||||
return
|
||||
}
|
||||
timerExpiring = false
|
||||
beginPending("on")
|
||||
if (minutes > 0) {
|
||||
remainingSec = minutes * 60
|
||||
run("on " + startMode + " " + minutes)
|
||||
@@ -184,15 +230,15 @@ PlasmoidItem {
|
||||
remainingSec = 0
|
||||
run("switch " + startMode)
|
||||
}
|
||||
refreshDelay.restart()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- backend
|
||||
// Stato: polling ogni 2 secondi (systemctl --user is-active).
|
||||
// Stato: polling periodico (systemctl --user is-active); la conferma di
|
||||
// un'operazione arriva però dall'output del comando stesso (~70 ms).
|
||||
P5Support.DataSource {
|
||||
id: statusSource
|
||||
engine: "executable"
|
||||
interval: 2000
|
||||
interval: 3000
|
||||
connectedSources: [root.statusCommand]
|
||||
onNewData: function(sourceName, data) {
|
||||
root.applyStatus(data ? data["stdout"] : "")
|
||||
@@ -206,11 +252,16 @@ PlasmoidItem {
|
||||
connectedSources: []
|
||||
onNewData: function(sourceName, data) {
|
||||
const output = data ? String(data["stdout"] || "") : ""
|
||||
root.lastError = output.indexOf("error=") === 0 ? output : ""
|
||||
root.lastError = output.indexOf("error=") === 0 ? output.trim() : ""
|
||||
if (root.lastError !== "") {
|
||||
console.warn("enne2-caffeine:", root.lastError)
|
||||
root.clearPending()
|
||||
}
|
||||
if (output.indexOf("state=") !== -1) {
|
||||
root.finishPending(output)
|
||||
} else {
|
||||
root.refresh()
|
||||
}
|
||||
root.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,11 +277,15 @@ PlasmoidItem {
|
||||
}
|
||||
}
|
||||
|
||||
// Il backend non ha confermato entro il timeout: torna a fidarsi del polling.
|
||||
Timer {
|
||||
id: refreshDelay
|
||||
interval: 300
|
||||
id: pendingTimeout
|
||||
interval: 6000
|
||||
repeat: false
|
||||
onTriggered: root.refresh()
|
||||
onTriggered: {
|
||||
root.clearPending()
|
||||
root.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
// Countdown del timer di disattivazione automatica.
|
||||
@@ -277,6 +332,15 @@ PlasmoidItem {
|
||||
implicitWidth: Kirigami.Units.iconSizes.smallMedium
|
||||
implicitHeight: Kirigami.Units.iconSizes.smallMedium
|
||||
|
||||
// operazione in corso: pulsazione dell'icona come feedback
|
||||
SequentialAnimation on opacity {
|
||||
running: root.pending
|
||||
loops: Animation.Infinite
|
||||
NumberAnimation { to: 0.4; duration: 220; easing.type: Easing.InOutQuad }
|
||||
NumberAnimation { to: 1.0; duration: 220; easing.type: Easing.InOutQuad }
|
||||
onStopped: compactIcon.opacity = 1.0
|
||||
}
|
||||
|
||||
// Kirigami.Icon può assorbire i clic (bug KDE 518024):
|
||||
// area cliccabile direttamente sopra l'icona.
|
||||
MouseArea {
|
||||
|
||||
Reference in New Issue
Block a user