Compare commits

...

2 commits

6 changed files with 134 additions and 3 deletions

View file

@ -57,6 +57,7 @@ PanelWindow {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: M.Theme.barSpacing spacing: M.Theme.barSpacing
M.Privacy {}
M.BarGroup { M.BarGroup {
borderColor: M.Theme.base0D borderColor: M.Theme.base0D
M.Clock { M.Clock {

View file

@ -41,8 +41,23 @@ M.BarSection {
onStreamFinished: root._parse(text) onStreamFinished: root._parse(text)
} }
} }
// Event-driven: watch BlueZ DBus property changes
Process {
id: btMonitor
running: true
command: ["sh", "-c", "dbus-monitor --system \"interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path_namespace='/org/bluez'\" 2>/dev/null"]
stdout: SplitParser {
splitMarker: "\n"
onRead: _debounce.restart()
}
}
Timer { Timer {
interval: M.Modules.bluetooth.interval || 5000 id: _debounce
interval: 500
onTriggered: proc.running = true
}
Timer {
interval: 60000
running: true running: true
repeat: true repeat: true
onTriggered: proc.running = true onTriggered: proc.running = true

View file

@ -68,8 +68,24 @@ M.BarSection {
} }
} }
} }
// Event-driven: re-poll on any network change
Process {
id: monitor
running: true
command: ["nmcli", "monitor"]
stdout: SplitParser {
splitMarker: "\n"
onRead: _debounce.restart()
}
}
Timer { Timer {
interval: M.Modules.network.interval || 5000 id: _debounce
interval: 300
onTriggered: proc.running = true
}
// Fallback poll
Timer {
interval: 60000
running: true running: true
repeat: true repeat: true
onTriggered: proc.running = true onTriggered: proc.running = true

View file

@ -28,8 +28,23 @@ M.BarIcon {
onStreamFinished: root.profile = text.trim() onStreamFinished: root.profile = text.trim()
} }
} }
// Event-driven: watch power-profiles-daemon DBus changes
Process {
id: ppMonitor
running: true
command: ["sh", "-c", "dbus-monitor --system \"interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='/net/hadess/PowerProfiles'\" 2>/dev/null"]
stdout: SplitParser {
splitMarker: "\n"
onRead: _debounce.restart()
}
}
Timer { Timer {
interval: M.Modules.powerProfile.interval || 5000 id: _debounce
interval: 300
onTriggered: proc.running = true
}
Timer {
interval: 60000
running: true running: true
repeat: true repeat: true
onTriggered: proc.running = true onTriggered: proc.running = true

83
modules/Privacy.qml Normal file
View file

@ -0,0 +1,83 @@
import QtQuick
import QtQuick.Effects
import Quickshell.Services.Pipewire
import "." as M
Row {
id: root
spacing: M.Theme.moduleSpacing
readonly property bool _screenShare: {
if (!Pipewire.nodes) return false;
for (const node of Pipewire.nodes.values) {
if (!node.isStream) continue;
const mc = node.properties?.["media.class"] ?? "";
if (mc.includes("Video")) return true;
}
return false;
}
readonly property bool _audioIn: {
if (!Pipewire.nodes) return false;
for (const node of Pipewire.nodes.values) {
if (!node.isStream) continue;
const mc = node.properties?.["media.class"] ?? "";
if (mc === "Stream/Input/Audio") return true;
}
return false;
}
visible: root._screenShare || root._audioIn
// Screenshare indicator
Text {
visible: root._screenShare
text: "\uF03D"
color: M.Theme.base08
font.pixelSize: M.Theme.fontSize + 2
font.family: M.Theme.iconFontFamily
anchors.verticalCenter: parent.verticalCenter
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: true
shadowColor: M.Theme.base08
shadowBlur: 0.8
shadowVerticalOffset: 0
shadowHorizontalOffset: 0
}
SequentialAnimation on opacity {
running: root._screenShare
loops: Animation.Infinite
NumberAnimation { to: 0.4; duration: 600; easing.type: Easing.InOutQuad }
NumberAnimation { to: 1; duration: 600; easing.type: Easing.InOutQuad }
}
}
// Microphone indicator
Text {
visible: root._audioIn
text: "\uF130"
color: M.Theme.base0B
font.pixelSize: M.Theme.fontSize + 2
font.family: M.Theme.iconFontFamily
anchors.verticalCenter: parent.verticalCenter
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: true
shadowColor: M.Theme.base0B
shadowBlur: 0.8
shadowVerticalOffset: 0
shadowHorizontalOffset: 0
}
SequentialAnimation on opacity {
running: root._audioIn
loops: Animation.Infinite
NumberAnimation { to: 0.4; duration: 600; easing.type: Easing.InOutQuad }
NumberAnimation { to: 1; duration: 600; easing.type: Easing.InOutQuad }
}
}
}

View file

@ -34,3 +34,4 @@ PowerProfile 1.0 PowerProfile.qml
IdleInhibitor 1.0 IdleInhibitor.qml IdleInhibitor 1.0 IdleInhibitor.qml
Notifications 1.0 Notifications.qml Notifications 1.0 Notifications.qml
Power 1.0 Power.qml Power 1.0 Power.qml
Privacy 1.0 Privacy.qml