diff --git a/modules/Bar.qml b/modules/Bar.qml index 701c70b..25d2570 100644 --- a/modules/Bar.qml +++ b/modules/Bar.qml @@ -57,6 +57,7 @@ PanelWindow { anchors.verticalCenter: parent.verticalCenter spacing: M.Theme.barSpacing + M.Privacy {} M.BarGroup { borderColor: M.Theme.base0D M.Clock { diff --git a/modules/Privacy.qml b/modules/Privacy.qml new file mode 100644 index 0000000..549743b --- /dev/null +++ b/modules/Privacy.qml @@ -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 } + } + } +} diff --git a/modules/qmldir b/modules/qmldir index e936add..42004e8 100644 --- a/modules/qmldir +++ b/modules/qmldir @@ -34,3 +34,4 @@ PowerProfile 1.0 PowerProfile.qml IdleInhibitor 1.0 IdleInhibitor.qml Notifications 1.0 Notifications.qml Power 1.0 Power.qml +Privacy 1.0 Privacy.qml