From bb9bed4184f7f2f703144e0a839f302280bcc172 Mon Sep 17 00:00:00 2001 From: ArnoldCordewiner Date: Sat, 5 Sep 2026 20:29:14 +0200 Subject: [PATCH] v1.3.0: live-bind display mode to config (dialog changes apply without restart); add configurable split-flap cascade seconds --- README.md | 10 +++++++--- bitcoin-price-1.3.0.plasmoid | Bin 0 -> 10216 bytes contents/config/main.xml | 6 ++++++ contents/ui/DisplayFlip.qml | 19 +++++++++++++++---- contents/ui/configGeneral.qml | 10 ++++++++++ contents/ui/main.qml | 29 ++++++++++++++++++++++++++++- metadata.desktop | 2 +- 7 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 bitcoin-price-1.3.0.plasmoid diff --git a/README.md b/README.md index b3c1a2f..5a8423f 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Three display styles, configurable in the settings dialog: In the split-flap and nixie styles the digits keep their display color and the trend (up/down/unchanged) is shown on a small LED next to the display. +Display style changes apply immediately, without restarting the shell. | Situation | Plain text color | Trend LED | |---|---|---| @@ -32,19 +33,22 @@ representations. - **Refresh interval (minutes)** — default 5, minimum **5**, maximum 1440. The 5-minute floor exists because the CoinGecko API allows one request per 5 minutes. A hint text in the config dialog explains this. +- **Split-flap cascade (seconds)** — default 3, range 1–15. Spreads the flip + animation of a price change evenly over this many seconds (applies to the + split-flap display style). Configurable via right-click on the widget → *Configure Bitcoin Price…* → *General*. ## Installation ### Graphical -Double-click `bitcoin-price-1.2.0.plasmoid` in Dolphin (Plasma installs it to +Double-click `bitcoin-price-1.3.0.plasmoid` in Dolphin (Plasma installs it to `~/.local/share/plasma/plasmoids/` automatically). The latest build is attached -to the [v1.2.0 release](../../releases/tag/v1.2.0). +to the [v1.3.0 release](../../releases/tag/v1.2.0). ### Terminal ```bash -kpackagetool5 --type Plasma/Applet --upgrade bitcoin-price-1.2.0.plasmoid +kpackagetool5 --type Plasma/Applet --upgrade bitcoin-price-1.3.0.plasmoid # Then restart the shell if needed: plasmashell --replace & ``` diff --git a/bitcoin-price-1.3.0.plasmoid b/bitcoin-price-1.3.0.plasmoid new file mode 100644 index 0000000000000000000000000000000000000000..f82a94f0ee6251daf861164c794f6cfd0a33f677 GIT binary patch literal 10216 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 0 + + + 3 + 1 + 15 + 5 diff --git a/contents/ui/DisplayFlip.qml b/contents/ui/DisplayFlip.qml index f041aae..234ae85 100644 --- a/contents/ui/DisplayFlip.qml +++ b/contents/ui/DisplayFlip.qml @@ -13,6 +13,8 @@ Row { // wired by the parent loader property string display: "--" property color trendColor: "#9e9e9e" + // seconds over which the cascade to a new price is spread + property int flapSeconds: 3 spacing: height * 0.06 @@ -20,6 +22,8 @@ Row { property bool ready: false readonly property real cellFont: height * 0.72 readonly property real cellWidth: cellFont * 0.80 + // one flap open+close takes 260 ms; keep delays above that + readonly property int flapDuration: 260 Component.onCompleted: { chars = display.split(""); @@ -32,14 +36,21 @@ Row { } var nc = display.split(""); var n = Math.max(chars.length, nc.length); + // spread the changed cells evenly across flapSeconds + var changed = []; for (var i = 0; i < n; i++) { var from = i < chars.length ? chars[i] : ""; var to = i < nc.length ? nc[i] : ""; if (from !== to) { - var cell = rep.itemAt(i); - if (cell) { - cell.flipTo(to, i * 45); - } + changed.push([i, to]); + } + } + var span = Math.max(1, flapSeconds) * 1000 - flapDuration; + var step = changed.length > 1 ? Math.max(0, Math.floor(span / (changed.length - 1))) : 0; + for (var j = 0; j < changed.length; j++) { + var cell = rep.itemAt(changed[j][0]); + if (cell) { + cell.flipTo(changed[j][1], j * step); } } chars = nc; diff --git a/contents/ui/configGeneral.qml b/contents/ui/configGeneral.qml index b57c85d..0b9f870 100644 --- a/contents/ui/configGeneral.qml +++ b/contents/ui/configGeneral.qml @@ -14,6 +14,7 @@ Kirigami.FormLayout { // The cfg_ prefix is what Plasma uses to read/write plasmoid.configuration property alias cfg_displayMode: modeCombo.currentIndex property alias cfg_refreshMinutes: intervalSpin.value + property alias cfg_flapSeconds: flapSpin.value Item { Kirigami.FormData.isSection: true @@ -25,6 +26,15 @@ Kirigami.FormLayout { model: [i18n("Plain text"), i18n("Split-flap board"), i18n("Nixie tubes")] } + QQC2.SpinBox { + id: flapSpin + Kirigami.FormData.label: i18n("Split-flap cascade (seconds):") + from: 1 + to: 15 + stepSize: 1 + editable: true + } + QQC2.SpinBox { id: intervalSpin Kirigami.FormData.label: i18n("Refresh interval (minutes):") diff --git a/contents/ui/main.qml b/contents/ui/main.qml index d684e0d..fc6e1ad 100644 --- a/contents/ui/main.qml +++ b/contents/ui/main.qml @@ -25,11 +25,29 @@ Item { readonly property int refreshMinutes: Math.max(5, plasmoid.configuration.refreshMinutes) + // Seconds over which the split-flap display cascades to a new price + readonly property int flapSeconds: Math.max(1, plasmoid.configuration.flapSeconds) + // 0 = plain text, 1 = split-flap board, 2 = nixie tubes property int displayMode: 0 readonly property string modeSource: displayMode === 1 ? "DisplayFlip.qml" : displayMode === 2 ? "DisplayNixie.qml" : "DisplayText.qml" + + // Enum config values arrive either as an int index or as the choice + // name, depending on the Plasma version — accept both. + function modeFromConfig(v) { + if (typeof v === "number") { + return Math.max(0, Math.min(2, Math.round(v))); + } + if (v === "SplitFlap") { + return 1; + } + if (v === "Nixie") { + return 2; + } + return 0; + } readonly property string apiUrl: "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=eur" // -1 = down, 0 = unchanged / no previous reading yet, 1 = up @@ -72,7 +90,10 @@ Item { Component.onCompleted: { try { - displayMode = Math.max(0, Math.min(2, plasmoid.configuration.displayMode)); + // live binding: config changes from the dialog apply immediately + displayMode = Qt.binding(function () { + return modeFromConfig(plasmoid.configuration.displayMode); + }); } catch (e) { // outside a real plasmoid shell (tests): keep the default } @@ -119,6 +140,9 @@ Item { onLoaded: { item.display = Qt.binding(function () { return root.displayText; }); item.trendColor = Qt.binding(function () { return root.priceColor; }); + if (item.flapSeconds !== undefined) { + item.flapSeconds = Qt.binding(function () { return root.flapSeconds; }); + } } } } @@ -154,6 +178,9 @@ Item { onLoaded: { item.display = Qt.binding(function () { return root.displayText; }); item.trendColor = Qt.binding(function () { return root.priceColor; }); + if (item.flapSeconds !== undefined) { + item.flapSeconds = Qt.binding(function () { return root.flapSeconds; }); + } } } diff --git a/metadata.desktop b/metadata.desktop index d0e3d90..82bf150 100644 --- a/metadata.desktop +++ b/metadata.desktop @@ -10,7 +10,7 @@ X-KDE-ServiceTypes=Plasma/Applet X-KDE-PluginInfo-Author=Arnold Cordewiner X-KDE-PluginInfo-Email=hermes@a14r.be X-KDE-PluginInfo-Name=nl.a14r.bitcoinprice -X-KDE-PluginInfo-Version=1.2.0 +X-KDE-PluginInfo-Version=1.3.0 X-KDE-PluginInfo-Website=https://gitea.a14r.be/hermes/plasma-bitcoin-price X-KDE-PluginInfo-Category=Utilities X-KDE-PluginInfo-License=MIT