aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/modules
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/modules')
-rw-r--r--desktop/modules/appearance/WallEngine.qml57
-rw-r--r--desktop/modules/appearance/WallEngineModule.qml33
-rw-r--r--desktop/modules/appearance/WallEngineTab.qml28
3 files changed, 100 insertions, 18 deletions
diff --git a/desktop/modules/appearance/WallEngine.qml b/desktop/modules/appearance/WallEngine.qml
index fe45f7b..54705f6 100644
--- a/desktop/modules/appearance/WallEngine.qml
+++ b/desktop/modules/appearance/WallEngine.qml
@@ -33,7 +33,6 @@ Singleton {
function listed(path, which) { return list(which).indexOf(path) >= 0; }
// A gallery folder by its Wallpapers.groups key, "" for the hearted list.
function folder(which) { return which === "V" ? cfg.folderV : cfg.folderH; }
- function setFolder(which, key) { Prefs.setWallEngine(which === "V" ? { folderV: key } : { folderH: key }); }
// What a tick draws from. A folder that is no longer in the gallery
// gives nothing, so that screen is left alone rather than falling back
// to the list behind the user's back.
@@ -65,9 +64,46 @@ Singleton {
}
}
- function setMinutes(m) {
- if (Number.isInteger(m) && m >= 1 && m !== cfg.minutes) Prefs.setWallEngine({ minutes: m });
+ // The page's draft, like every settings page: the interval and the two
+ // sources change here and reach Prefs on Start or Apply. Reset binds
+ // them back to what is saved. Hearts are not drafted: the picker writes
+ // them as they are clicked.
+ property int draftMinutes: cfg.minutes
+ property string draftFolderH: cfg.folderH
+ property string draftFolderV: cfg.folderV
+ readonly property bool dirty: draftMinutes !== cfg.minutes
+ || draftFolderH !== cfg.folderH || draftFolderV !== cfg.folderV
+ function draftFolder(which) { return which === "V" ? draftFolderV : draftFolderH; }
+ function setDraftFolder(which, key) {
+ if (which === "V") draftFolderV = key;
+ else draftFolderH = key;
}
+ function setDraftMinutes(m) {
+ if (Number.isInteger(m) && m >= 1) draftMinutes = m;
+ }
+ function reset() {
+ draftMinutes = Qt.binding(() => cfg.minutes);
+ draftFolderH = Qt.binding(() => cfg.folderH);
+ draftFolderV = Qt.binding(() => cfg.folderV);
+ }
+ function commit() {
+ Prefs.setWallEngine({ minutes: draftMinutes, folderH: draftFolderH, folderV: draftFolderV });
+ reset();
+ }
+
+ // Start changes the wallpapers at once: the first timer change would
+ // otherwise be a whole interval away, which read as the engine not
+ // working.
+ function start() {
+ commit();
+ setOn(true);
+ next();
+ }
+ function apply() {
+ commit();
+ restartTimer();
+ }
+ function stop() { setOn(false); }
// ponytail: in memory, so a restart starts a new round.
property var bagH: []
@@ -88,7 +124,15 @@ Singleton {
function next() {
tick();
+ restartTimer();
+ }
+
+ // When the timer next fires, for the page's header; 0 while off. Timer
+ // has no such property, so it is kept beside it.
+ property double nextAt: 0
+ function restartTimer() {
timer.restart();
+ nextAt = Date.now() + timer.interval;
}
// A switch-off during a run cannot start its own; it goes when that run
@@ -106,7 +150,10 @@ Singleton {
interval: root.cfg.minutes * 60000
repeat: true
running: root.on
- onTriggered: root.tick()
+ onTriggered: { root.nextAt = Date.now() + interval; root.tick(); }
+ // A running Timer restarts on a new interval.
+ onIntervalChanged: if (running) root.nextAt = Date.now() + interval
+ onRunningChanged: root.nextAt = running ? Date.now() + interval : 0
}
Connections {
@@ -116,7 +163,7 @@ Singleton {
if (!root.on) return;
Prefs.setWallEngine({ homeH: h !== "" ? h : root.cfg.homeH,
homeV: v !== "" ? v : root.cfg.homeV });
- timer.restart();
+ root.restartTimer();
}
function onFinished() {
if (!root.homeWaiting || root.on) return;
diff --git a/desktop/modules/appearance/WallEngineModule.qml b/desktop/modules/appearance/WallEngineModule.qml
index e907695..5b8a39c 100644
--- a/desktop/modules/appearance/WallEngineModule.qml
+++ b/desktop/modules/appearance/WallEngineModule.qml
@@ -19,6 +19,7 @@ Module {
// nf-fa-shuffle, present in Inconsolata Nerd Font.
icon: "\uf074"
settings: true
+ dirty: WallEngine.dirty
group: "Appearance"
keywords: ["wallpaper", "timer", "rotate", "rotation", "shuffle", "slideshow", "heart"]
@@ -30,6 +31,38 @@ Module {
page: Component {
Page {
title: "Wallpaper engine"
+ // SaveBar's place, not SaveBar: the engine is started and stopped
+ // here as well as saved, and its state is what the header reports.
+ actions: Component {
+ Row {
+ spacing: 8
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ text: WallEngine.dirty ? "unsaved changes"
+ : WallEngine.on ? "running, next change at "
+ + Qt.formatTime(new Date(WallEngine.nextAt), "hh:mm")
+ : "stopped"
+ color: WallEngine.dirty ? Theme.yellow : WallEngine.on ? Theme.green : Theme.overlay
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 }
+ }
+ Button {
+ visible: WallEngine.dirty
+ text: "Reset"
+ onClicked: WallEngine.reset()
+ }
+ Button {
+ visible: WallEngine.on
+ text: "Stop"
+ enabled: !Wallpapers.applying
+ onClicked: WallEngine.stop()
+ }
+ Button {
+ text: WallEngine.on ? "Apply" : "Start"
+ enabled: (!WallEngine.on || WallEngine.dirty) && !Wallpapers.applying
+ onClicked: WallEngine.on ? WallEngine.apply() : WallEngine.start()
+ }
+ }
+ }
WallEngineTab { width: parent.width }
}
}
diff --git a/desktop/modules/appearance/WallEngineTab.qml b/desktop/modules/appearance/WallEngineTab.qml
index caa01f4..3f72d83 100644
--- a/desktop/modules/appearance/WallEngineTab.qml
+++ b/desktop/modules/appearance/WallEngineTab.qml
@@ -22,20 +22,21 @@ Item {
Row {
spacing: 8
- Toggle {
+ Text {
anchors.verticalCenter: parent.verticalCenter
- checked: WallEngine.on
- label: "Change the wallpapers every"
- onToggled: WallEngine.setOn(checked)
+ text: "Change the wallpapers every"
+ color: Theme.subtext
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 }
}
Field {
anchors.verticalCenter: parent.verticalCenter
width: 50
- value: String(WallEngine.cfg.minutes)
- onEdited: {
- WallEngine.setMinutes(Number(value));
- value = String(WallEngine.cfg.minutes);
- }
+ value: String(WallEngine.draftMinutes)
+ // On every keystroke, not on edited: that waits for Enter
+ // or a focus change, and clicking Start takes neither, so a
+ // typed interval was silently left at the old one.
+ onValueChanged: WallEngine.setDraftMinutes(Number(value))
+ onEdited: value = String(WallEngine.draftMinutes)
}
Text {
anchors.verticalCenter: parent.verticalCenter
@@ -54,7 +55,7 @@ Item {
width: col.width
wrapMode: Text.Wrap
text: "Timer changes recolour the desktop and leave GRUB, the homepage and the login screen alone. "
- + "Switching off puts back each screen's home wallpaper, the one last applied by hand, with a full run."
+ + "Stop puts back each screen's home wallpaper, the one last applied by hand, with a full run."
color: Theme.overlay
font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 }
}
@@ -67,7 +68,8 @@ Item {
required property var modelData
readonly property var paths: WallEngine.list(modelData.which)
readonly property string home: modelData.which === "V" ? WallEngine.cfg.homeV : WallEngine.cfg.homeH
- readonly property string folder: WallEngine.folder(modelData.which)
+ // The draft's source: what Start or Apply will use.
+ readonly property string folder: WallEngine.draftFolder(modelData.which)
readonly property var group: Wallpapers.groups.find(g => g.key === folder) ?? null
width: col.width
spacing: 8
@@ -90,7 +92,7 @@ Item {
Tab {
text: "Hearted"
selected: screen.folder === ""
- onClicked: WallEngine.setFolder(screen.modelData.which, "")
+ onClicked: WallEngine.setDraftFolder(screen.modelData.which, "")
}
Repeater {
model: Wallpapers.groups
@@ -98,7 +100,7 @@ Item {
required property var modelData
text: modelData.name
selected: screen.folder === modelData.key
- onClicked: WallEngine.setFolder(screen.modelData.which, modelData.key)
+ onClicked: WallEngine.setDraftFolder(screen.modelData.which, modelData.key)
}
}
}