add WeatherService, WeatherApplet with hover panel and lock screen widget

This commit is contained in:
Damocles 2026-04-22 22:06:58 +02:00
parent 6f385130ff
commit 9285365732
8 changed files with 150 additions and 26 deletions

View file

@ -0,0 +1,41 @@
import QtQuick
import "../services" as S
Column {
id: root
required property color accentColor
// Weather icon + summary
Item {
width: parent.width
height: 28
Text {
anchors.left: parent.left
anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter
text: S.WeatherService.icon
color: root.accentColor
font.pixelSize: S.Theme.fontSize + 2
font.family: S.Theme.fontFamily
}
}
// Forecast details from wttrbar tooltip
Text {
width: parent.width - 24
anchors.horizontalCenter: parent.horizontalCenter
text: S.WeatherService.tooltip
color: S.Theme.base05
font.pixelSize: S.Theme.fontSize - 2
font.family: S.Theme.fontFamily
wrapMode: Text.WordWrap
lineHeight: 1.3
}
Item {
width: 1
height: 4
}
}

View file

@ -11,4 +11,5 @@ MprisApplet 1.0 MprisApplet.qml
NetworkApplet 1.0 NetworkApplet.qml
TemperatureApplet 1.0 TemperatureApplet.qml
VolumeApplet 1.0 VolumeApplet.qml
WeatherApplet 1.0 WeatherApplet.qml
# keep-sorted end

View file

@ -27,13 +27,34 @@ Item {
}
implicitHeight: _widgetContent.implicitHeight
visible: _mprisCard.visible || _volumeCard.visible || _backlightCard.visible || _notifPills.visible
visible: _weatherCard.visible || _mprisCard.visible || _volumeCard.visible || _backlightCard.visible || _notifPills.visible
Column {
id: _widgetContent
width: parent.width
spacing: 12
// Weather widget
Rectangle {
id: _weatherCard
width: parent.width
height: _weatherContent.implicitHeight + 16
radius: S.Theme.radius + 2
color: Qt.rgba(S.Theme.base01.r, S.Theme.base01.g, S.Theme.base01.b, 0.7)
border.color: Qt.rgba(S.Theme.base03.r, S.Theme.base03.g, S.Theme.base03.b, 0.3)
border.width: 1
visible: (S.Modules.lock.weather ?? true) && S.WeatherService.available
C.WeatherApplet {
id: _weatherContent
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.topMargin: 8
accentColor: S.Theme.base0C
}
}
// Notification pills
LockNotifPills {
id: _notifPills

View file

@ -1,41 +1,53 @@
import QtQuick
import Quickshell.Io
import Quickshell
import "." as M
import "../services" as S
import "../applets" as C
M.BarSection {
id: root
spacing: S.Theme.moduleSpacing
tooltip: root.weatherTooltip
tooltip: ""
visible: S.Modules.weather.enable && S.WeatherService.available
property string weatherTooltip: ""
property bool _pinned: false
readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered
readonly property bool _showPanel: _anyHover || _pinned
Process {
id: proc
running: true
command: ["wttrbar"].concat(S.Modules.weather.args)
stdout: StdioCollector {
onStreamFinished: {
try {
const data = JSON.parse(text);
label.icon = data.text ?? "";
root.weatherTooltip = data.tooltip ?? "";
} catch (e) {
label.icon = "";
root.weatherTooltip = "";
}
}
}
on_AnyHoverChanged: {
if (_anyHover)
_unpinTimer.stop();
else if (_pinned)
_unpinTimer.start();
}
Timer {
interval: S.Modules.weather.interval || 3600000
running: true
repeat: true
onTriggered: proc.running = true
id: _unpinTimer
interval: 500
onTriggered: root._pinned = false
}
M.BarIcon {
id: label
icon: S.WeatherService.icon
anchors.verticalCenter: parent.verticalCenter
TapHandler {
onTapped: root._pinned = !root._pinned
}
}
M.HoverPanel {
id: hoverPanel
showPanel: root._showPanel
screen: QsWindow.window?.screen ?? null
anchorItem: root
accentColor: root.accentColor
panelNamespace: "nova-weather"
panelTitle: "Weather"
contentWidth: 280
C.WeatherApplet {
width: hoverPanel.contentWidth
accentColor: root.accentColor
}
}
}

View file

@ -98,7 +98,8 @@ QtObject {
screenshot: true,
notifications: true,
mpris: true,
volume: true
volume: true,
weather: true
})
property var statsDaemon: ({
interval: -1

View file

@ -0,0 +1,42 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
import "." as S
QtObject {
id: root
property string icon: ""
property string tooltip: ""
readonly property bool available: icon !== ""
property Process _proc: Process {
running: S.Modules.weather.enable
command: ["wttrbar"].concat(S.Modules.weather.args)
stdout: StdioCollector {
onStreamFinished: {
try {
const data = JSON.parse(text);
root.icon = data.text ?? "";
root.tooltip = data.tooltip ?? "";
} catch (e) {
root.icon = "";
root.tooltip = "";
}
}
}
}
property Timer _poll: Timer {
interval: S.Modules.weather.interval || 3600000
running: S.Modules.weather.enable
repeat: true
onTriggered: root._proc.running = true
}
function refresh() {
_proc.running = true;
}
}

View file

@ -15,4 +15,5 @@ singleton PowerProfileService 1.0 PowerProfileService.qml
singleton ScreenshotService 1.0 ScreenshotService.qml
singleton SystemStats 1.0 SystemStats.qml
singleton Theme 1.0 Theme.qml
singleton WeatherService 1.0 WeatherService.qml
# keep-sorted end