mirror of
https://github.com/samjage/weather-and-stats.git
synced 2026-06-06 00:20:42 +00:00
Compare commits
4 Commits
79abd20615
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| b213bd5fd1 | |||
| 79e6bc082b | |||
| 277cd6915b | |||
| f98cd558cc |
@@ -94,6 +94,8 @@ Right-click the widget → **Configure Weather and Stats**
|
|||||||
| Setting | Description | Default |
|
| Setting | Description | Default |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Nerd Font icons | Disable for plain Unicode symbol fallback | On |
|
| Nerd Font icons | Disable for plain Unicode symbol fallback | On |
|
||||||
|
| Font size | Set a custom point size for the panel text | Auto |
|
||||||
|
| Stat order | Reorder stats left to right using ↑ ↓ buttons | Weather, CPU Temp, CPU Usage, Memory, Network |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,12 @@ import org.kde.plasma.configuration
|
|||||||
ConfigModel {
|
ConfigModel {
|
||||||
ConfigCategory {
|
ConfigCategory {
|
||||||
name: "General"
|
name: "General"
|
||||||
icon: "weather-clear"
|
icon: "weather-and-stats"
|
||||||
source: "configGeneral.qml"
|
source: "configGeneral.qml"
|
||||||
}
|
}
|
||||||
|
ConfigCategory {
|
||||||
|
name: "Appearance"
|
||||||
|
icon: "preferences-desktop-theme"
|
||||||
|
source: "configAppearance.qml"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,5 +47,11 @@
|
|||||||
<entry name="useNerdFont" type="Bool">
|
<entry name="useNerdFont" type="Bool">
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry name="fontSize" type="Int">
|
||||||
|
<default>0</default>
|
||||||
|
</entry>
|
||||||
|
<entry name="statOrder" type="String">
|
||||||
|
<default>weather,cputemp,cpuusage,memory,network</default>
|
||||||
|
</entry>
|
||||||
</group>
|
</group>
|
||||||
</kcfg>
|
</kcfg>
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ IFACE=$(awk 'NR>2{gsub(/:$/,"",$1); if($1!="lo") print $1, ($2+0)+($10+0)}' /pro
|
|||||||
[ -z "$IFACE" ] && IFACE="lo"
|
[ -z "$IFACE" ] && IFACE="lo"
|
||||||
|
|
||||||
# Helper functions for sampling
|
# Helper functions for sampling
|
||||||
get_cpu() { awk 'NR==1{t=0; for(i=2;i<=NF;i++) t+=$i; print t, $6}' /proc/stat; }
|
get_cpu() { awk 'NR==1{t=0; for(i=2;i<=NF;i++) t+=$i; print t, $5+$6}' /proc/stat; }
|
||||||
get_net() { awk -v d="$IFACE:" '$1==d{print $2, $10}' /proc/net/dev; }
|
get_net() { awk -v d="$IFACE:" '$1==d{print $2, $10}' /proc/net/dev; }
|
||||||
|
|
||||||
# First samples
|
# First samples
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls as QQC2
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
implicitHeight: col.implicitHeight
|
||||||
|
|
||||||
|
property int cfg_fontSize: 0
|
||||||
|
property string cfg_statOrder: "weather,cputemp,cpuusage,memory,network"
|
||||||
|
|
||||||
|
// ── Order model ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
property bool syncingOrder: false
|
||||||
|
|
||||||
|
ListModel { id: orderModel }
|
||||||
|
|
||||||
|
readonly property var labelMap: ({
|
||||||
|
weather: "Weather",
|
||||||
|
cputemp: "CPU Temp",
|
||||||
|
cpuusage: "CPU Usage",
|
||||||
|
memory: "Memory",
|
||||||
|
network: "Network"
|
||||||
|
})
|
||||||
|
|
||||||
|
// Plasma sets cfg_statOrder from saved config after the component loads,
|
||||||
|
// so we populate the model on the first external change rather than onCompleted.
|
||||||
|
onCfg_statOrderChanged: {
|
||||||
|
if (syncingOrder) return
|
||||||
|
orderModel.clear()
|
||||||
|
var keys = cfg_statOrder.split(",")
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var key = keys[i].trim()
|
||||||
|
orderModel.append({ key: key, label: labelMap[key] || key })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncOrder() {
|
||||||
|
syncingOrder = true
|
||||||
|
var keys = []
|
||||||
|
for (var i = 0; i < orderModel.count; i++) keys.push(orderModel.get(i).key)
|
||||||
|
cfg_statOrder = keys.join(",")
|
||||||
|
syncingOrder = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Section header component ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
component SectionHeader: ColumnLayout {
|
||||||
|
property string title: ""
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 8
|
||||||
|
spacing: 4
|
||||||
|
|
||||||
|
QQC2.Label {
|
||||||
|
text: title
|
||||||
|
font.bold: true
|
||||||
|
font.pointSize: 9
|
||||||
|
font.letterSpacing: 2
|
||||||
|
opacity: 0.5
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
height: 1
|
||||||
|
opacity: 0.15
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Layout ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: col
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 20
|
||||||
|
anchors.topMargin: 16
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
// ── FONT ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
SectionHeader { title: "FONT" }
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 12
|
||||||
|
|
||||||
|
QQC2.Label { text: "Font size:" }
|
||||||
|
QQC2.SpinBox {
|
||||||
|
from: 0; to: 32
|
||||||
|
value: cfg_fontSize
|
||||||
|
onValueChanged: cfg_fontSize = value
|
||||||
|
textFromValue: function(val) { return val === 0 ? "Auto" : val + " pt" }
|
||||||
|
valueFromText: function(text) { return text === "Auto" ? 0 : parseInt(text) || 0 }
|
||||||
|
}
|
||||||
|
QQC2.Label { text: "(0 = inherit from panel)"; opacity: 0.6 }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── ORDER ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
SectionHeader { title: "ORDER" }
|
||||||
|
|
||||||
|
QQC2.Label {
|
||||||
|
text: "Use ↑ ↓ to set left-to-right order:"
|
||||||
|
opacity: 0.7
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: orderModel
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
QQC2.Label {
|
||||||
|
text: (index + 1) + ". " + model.label
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
QQC2.Button {
|
||||||
|
text: "↑"
|
||||||
|
enabled: index > 0
|
||||||
|
implicitWidth: 36
|
||||||
|
onClicked: { orderModel.move(index, index - 1, 1); root.syncOrder() }
|
||||||
|
}
|
||||||
|
QQC2.Button {
|
||||||
|
text: "↓"
|
||||||
|
enabled: index < orderModel.count - 1
|
||||||
|
implicitWidth: 36
|
||||||
|
onClicked: { orderModel.move(index, index + 1, 1); root.syncOrder() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { Layout.fillHeight: true; Layout.minimumHeight: 16 }
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
-17
@@ -22,6 +22,8 @@ PlasmoidItem {
|
|||||||
property bool showMemory: Plasmoid.configuration.showMemory !== false
|
property bool showMemory: Plasmoid.configuration.showMemory !== false
|
||||||
property bool showNetwork: Plasmoid.configuration.showNetwork !== false
|
property bool showNetwork: Plasmoid.configuration.showNetwork !== false
|
||||||
property bool useNerdFont: Plasmoid.configuration.useNerdFont !== false
|
property bool useNerdFont: Plasmoid.configuration.useNerdFont !== false
|
||||||
|
property int fontSize: Plasmoid.configuration.fontSize || 0
|
||||||
|
property string statOrder: Plasmoid.configuration.statOrder || "weather,cputemp,cpuusage,memory,network"
|
||||||
|
|
||||||
readonly property var ic: useNerdFont ? ({
|
readonly property var ic: useNerdFont ? ({
|
||||||
cpuTemp: "\uf2c8", cpu: "\uf2db", mem: "\ue266",
|
cpuTemp: "\uf2c8", cpu: "\uf2db", mem: "\ue266",
|
||||||
@@ -71,32 +73,37 @@ PlasmoidItem {
|
|||||||
Layout.preferredWidth: implicitWidth + 16
|
Layout.preferredWidth: implicitWidth + 16
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
textFormat: Text.RichText
|
textFormat: Text.RichText
|
||||||
|
leftPadding: 6
|
||||||
|
font.pointSize: root.fontSize > 0 ? root.fontSize : Kirigami.Theme.defaultFont.pointSize
|
||||||
|
|
||||||
text: {
|
text: {
|
||||||
var hot = root.cpuTempRaw > 0 && root.cpuTempRaw >= root.cpuTempThreshold
|
var hot = root.cpuTempRaw > 0 && root.cpuTempRaw >= root.cpuTempThreshold
|
||||||
var sp = "\u00a0\u00a0\u00a0\u00a0"
|
var sp = "\u00a0\u00a0\u00a0\u00a0"
|
||||||
var div = "\u00a0\u00a0\u2502\u00a0\u00a0"
|
var div = "\u00a0\u00a0\u2502\u00a0\u00a0"
|
||||||
|
|
||||||
var s = root.weatherIcon + "\u00a0\u00a0" + root.temperature + "°" + (root.fahrenheit ? "F" : "C")
|
var order = root.statOrder.split(",")
|
||||||
if (root.showCondition && root.weatherCondition !== "")
|
var segments = []
|
||||||
s += " " + root.weatherCondition
|
|
||||||
|
|
||||||
var cpuMem = []
|
for (var i = 0; i < order.length; i++) {
|
||||||
if (root.showCpuTemp) {
|
var key = order[i].trim()
|
||||||
var tempStr = root.ic.cpuTemp + "\u00a0\u00a0" + root.cpuTempDisplay
|
if (key === "weather") {
|
||||||
cpuMem.push(hot ? "<font color='#ff5555'>" + tempStr + "</font>" : tempStr)
|
var seg = root.weatherIcon + "\u00a0\u00a0" + root.temperature + "°" + (root.fahrenheit ? "F" : "C")
|
||||||
|
if (root.showCondition && root.weatherCondition !== "")
|
||||||
|
seg += " " + root.weatherCondition
|
||||||
|
segments.push(seg)
|
||||||
|
} else if (key === "cputemp" && root.showCpuTemp) {
|
||||||
|
var tempStr = root.ic.cpuTemp + "\u00a0\u00a0" + root.cpuTempDisplay
|
||||||
|
segments.push(hot ? "<font color='#ff5555'>" + tempStr + "</font>" : tempStr)
|
||||||
|
} else if (key === "cpuusage" && root.showCpuUsage) {
|
||||||
|
segments.push(root.ic.cpu + "\u00a0\u00a0" + (root.cpuUsage >= 0 ? padPct(root.cpuUsage) : "\u00a0--"))
|
||||||
|
} else if (key === "memory" && root.showMemory) {
|
||||||
|
segments.push(root.ic.mem + "\u00a0\u00a0" + (root.memUsage >= 0 ? padPct(root.memUsage) : "\u00a0--"))
|
||||||
|
} else if (key === "network" && root.showNetwork) {
|
||||||
|
segments.push(root.ic.down + "\u00a0\u00a0" + formatNetSpeed(root.netDown) + sp + root.ic.up + "\u00a0\u00a0" + formatNetSpeed(root.netUp))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (root.showCpuUsage)
|
|
||||||
cpuMem.push(root.ic.cpu + "\u00a0\u00a0" + (root.cpuUsage >= 0 ? padPct(root.cpuUsage) : "\u00a0--"))
|
|
||||||
if (root.showMemory)
|
|
||||||
cpuMem.push(root.ic.mem + "\u00a0\u00a0" + (root.memUsage >= 0 ? padPct(root.memUsage) : "\u00a0--"))
|
|
||||||
|
|
||||||
if (cpuMem.length > 0) s += div + cpuMem.join(sp)
|
return segments.join(div) + " "
|
||||||
|
|
||||||
if (root.showNetwork)
|
|
||||||
s += div + root.ic.down + "\u00a0\u00a0" + formatNetSpeed(root.netDown) + sp + root.ic.up + "\u00a0\u00a0" + formatNetSpeed(root.netUp)
|
|
||||||
|
|
||||||
return s + " "
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
"Description": "Live weather and system stats for the KDE panel",
|
"Description": "Live weather and system stats for the KDE panel",
|
||||||
"Icon": "weather-and-stats",
|
"Icon": "weather-and-stats",
|
||||||
"Id": "com.github.samjage.weatherstats",
|
"Id": "com.github.samjage.weatherstats",
|
||||||
"Version": "1.2",
|
"Version": "1.4",
|
||||||
"License": "GPL-2.0",
|
"License": "GPL-2.0",
|
||||||
"Category": "System Information",
|
"Category": "System Information",
|
||||||
"Authors": [
|
"Authors": [
|
||||||
|
|||||||
Reference in New Issue
Block a user