Files
aiden-niri-noctalia/home/aiden/.config/noctalia/plugins/privacy-indicator/BarWidget.qml
2026-02-17 21:43:15 -06:00

174 lines
5.4 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services.UI
import qs.Widgets
Item {
id: root
property var pluginApi: null
property ShellScreen screen
property string widgetId: ""
property string section: ""
// Bar positioning properties
readonly property string screenName: screen ? screen.name : ""
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
readonly property real barHeight: Style.getBarHeightForScreen(screenName)
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screenName)
readonly property real barFontSize: Style.getBarFontSizeForScreen(screenName)
// Access main instance for state
readonly property var mainInstance: pluginApi?.mainInstance
property bool micActive: mainInstance ? mainInstance.micActive : false
property bool camActive: mainInstance ? mainInstance.camActive : false
property bool scrActive: mainInstance ? mainInstance.scrActive : false
property var micApps: mainInstance ? mainInstance.micApps : []
property var camApps: mainInstance ? mainInstance.camApps : []
property var scrApps: mainInstance ? mainInstance.scrApps : []
property var cfg: pluginApi?.pluginSettings || ({})
property var defaults: pluginApi?.manifest?.metadata?.defaultSettings || ({})
property bool hideInactive: cfg.hideInactive ?? defaults.hideInactive
property bool removeMargins: cfg.removeMargins ?? defaults.removeMargins
property int iconSpacing: cfg.iconSpacing || Style.marginXS
property string activeColorKey: cfg.activeColor ?? defaults.activeColor
property string inactiveColorKey: cfg.inactiveColor ?? defaults.inactiveColor
readonly property color activeColor: Color.resolveColorKey(activeColorKey)
readonly property color inactiveColor: inactiveColorKey === "none" ? Qt.alpha(Color.mOnSurfaceVariant, 0.3) : Color.resolveColorKey(inactiveColorKey)
readonly property color micColor: micActive ? activeColor : inactiveColor
readonly property color camColor: camActive ? activeColor : inactiveColor
readonly property color scrColor: scrActive ? activeColor : inactiveColor
readonly property bool isVisible: !hideInactive || micActive || camActive || scrActive
property real margins: removeMargins ? 0 : Style.marginM * 2
readonly property real contentWidth: isVertical ? Style.capsuleHeight : Math.round(layout.implicitWidth + margins)
readonly property real contentHeight: isVertical ? Math.round(layout.implicitHeight + margins) : Style.capsuleHeight
implicitWidth: contentWidth
implicitHeight: contentHeight
Layout.alignment: Qt.AlignVCenter
visible: root.isVisible
opacity: root.isVisible ? 1.0 : 0.0
function buildTooltip() {
var parts = [];
if (micActive && micApps.length > 0) {
parts.push("Mic: " + micApps.join(", "));
}
if (camActive && camApps.length > 0) {
parts.push("Cam: " + camApps.join(", "));
}
if (scrActive && scrApps.length > 0) {
parts.push("Screen sharing: " + scrApps.join(", "));
}
return parts.length > 0 ? parts.join("\n") : "";
}
Rectangle {
id: visualCapsule
x: Style.pixelAlignCenter(parent.width, width)
y: Style.pixelAlignCenter(parent.height, height)
width: root.contentWidth
height: root.contentHeight
radius: Style.radiusM
color: Style.capsuleColor
border.color: Style.capsuleBorderColor
border.width: Style.capsuleBorderWidth
Item {
id: layout
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
implicitWidth: iconsLayout.implicitWidth
implicitHeight: iconsLayout.implicitHeight
GridLayout {
id: iconsLayout
columns: root.isVertical ? 1 : 3
rows: root.isVertical ? 3 : 1
rowSpacing: root.iconSpacing
columnSpacing: root.iconSpacing
NIcon {
visible: micActive || !root.hideInactive
icon: micActive ? "microphone" : "microphone-off"
color: root.micColor
}
NIcon {
visible: camActive || !root.hideInactive
icon: camActive ? "camera" : "camera-off"
color: root.camColor
}
NIcon {
visible: scrActive || !root.hideInactive
icon: scrActive ? "screen-share" : "screen-share-off"
color: root.scrColor
}
}
}
}
NPopupContextMenu {
id: contextMenu
model: [
{
"label": pluginApi?.tr("menu.settings"),
"action": "settings",
"icon": "settings"
},
]
onTriggered: function (action) {
contextMenu.close();
PanelService.closeContextMenu(screen);
if (action === "settings") {
BarService.openPluginSettings(root.screen, pluginApi.manifest);
}
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton | Qt.LeftButton
hoverEnabled: true
onClicked: function (mouse) {
if (mouse.button === Qt.RightButton) {
PanelService.showContextMenu(contextMenu, root, screen);
} else if (mouse.button === Qt.LeftButton) {
if (pluginApi) pluginApi.openPanel(root.screen, root);
}
}
onEntered: {
var tooltipText = buildTooltip();
if (tooltipText) {
TooltipService.show(root, tooltipText, BarService.getTooltipDirection());
}
}
onExited: TooltipService.hide()
}
}