1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 21:42:51 -05:00

dankbar/controlcenter: add VPN, mic, brightness, battery, and printer

options for widget
This commit is contained in:
bbedward
2025-11-24 16:36:49 -05:00
parent 7f15227de1
commit d341a5a60b
15 changed files with 1692 additions and 1486 deletions

View File

@@ -1,5 +1,4 @@
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Services.Pipewire
import qs.Common
@@ -10,8 +9,8 @@ Rectangle {
id: root
property bool hasInputVolumeSliderInCC: {
const widgets = SettingsData.controlCenterWidgets || []
return widgets.some(widget => widget.id === "inputVolumeSlider")
const widgets = SettingsData.controlCenterWidgets || [];
return widgets.some(widget => widget.id === "inputVolumeSlider");
}
implicitHeight: headerRow.height + (hasInputVolumeSliderInCC ? 0 : volumeSlider.height) + audioContent.height + Theme.spacingM
@@ -66,7 +65,7 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onClicked: {
if (AudioService.source && AudioService.source.audio) {
AudioService.source.audio.muted = !AudioService.source.audio.muted
AudioService.source.audio.muted = !AudioService.source.audio.muted;
}
}
}
@@ -74,9 +73,10 @@ Rectangle {
DankIcon {
anchors.centerIn: parent
name: {
if (!AudioService.source || !AudioService.source.audio) return "mic_off"
let muted = AudioService.source.audio.muted
return muted ? "mic_off" : "mic"
if (!AudioService.source || !AudioService.source.audio)
return "mic_off";
let muted = AudioService.source.audio.muted;
return muted ? "mic_off" : "mic";
}
size: Theme.iconSize
color: AudioService.source && AudioService.source.audio && !AudioService.source.audio.muted && AudioService.source.audio.volume > 0 ? Theme.primary : Theme.surfaceText
@@ -97,11 +97,11 @@ Rectangle {
valueOverride: actualVolumePercent
thumbOutlineColor: Theme.surfaceVariant
onSliderValueChanged: function(newValue) {
onSliderValueChanged: function (newValue) {
if (AudioService.source && AudioService.source.audio) {
AudioService.source.audio.volume = newValue / 100
AudioService.source.audio.volume = newValue / 100;
if (newValue > 0 && AudioService.source.audio.muted) {
AudioService.source.audio.muted = false
AudioService.source.audio.muted = false;
}
}
}
@@ -128,22 +128,26 @@ Rectangle {
model: ScriptModel {
values: {
const nodes = Pipewire.nodes.values.filter(node => {
return node.audio && !node.isSink && !node.isStream
})
const pins = SettingsData.audioInputDevicePins || {}
const pinnedName = pins["preferredInput"]
let sorted = [...nodes]
return node.audio && !node.isSink && !node.isStream;
});
const pins = SettingsData.audioInputDevicePins || {};
const pinnedName = pins["preferredInput"];
let sorted = [...nodes];
sorted.sort((a, b) => {
// Pinned device first
if (a.name === pinnedName && b.name !== pinnedName) return -1
if (b.name === pinnedName && a.name !== pinnedName) return 1
if (a.name === pinnedName && b.name !== pinnedName)
return -1;
if (b.name === pinnedName && a.name !== pinnedName)
return 1;
// Then active device
if (a === AudioService.source && b !== AudioService.source) return -1
if (b === AudioService.source && a !== AudioService.source) return 1
return 0
})
return sorted
if (a === AudioService.source && b !== AudioService.source)
return -1;
if (b === AudioService.source && a !== AudioService.source)
return 1;
return 0;
});
return sorted;
}
}
@@ -167,11 +171,11 @@ Rectangle {
DankIcon {
name: {
if (modelData.name.includes("bluez"))
return "headset"
return "headset";
else if (modelData.name.includes("usb"))
return "headset"
return "headset";
else
return "mic"
return "mic";
}
size: Theme.iconSize - 4
color: modelData === AudioService.source ? Theme.primary : Theme.surfaceText
@@ -181,9 +185,9 @@ Rectangle {
Column {
anchors.verticalCenter: parent.verticalCenter
width: {
const iconWidth = Theme.iconSize
const pinButtonWidth = pinInputRow.width + Theme.spacingS * 4 + Theme.spacingM
return parent.parent.width - iconWidth - parent.spacing - pinButtonWidth - Theme.spacingM * 2
const iconWidth = Theme.iconSize;
const pinButtonWidth = pinInputRow.width + Theme.spacingS * 4 + Theme.spacingM;
return parent.parent.width - iconWidth - parent.spacing - pinButtonWidth - Theme.spacingM * 2;
}
StyledText {
@@ -215,8 +219,8 @@ Rectangle {
height: 28
radius: height / 2
color: {
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05)
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05);
}
Row {
@@ -228,21 +232,21 @@ Rectangle {
name: "push_pin"
size: 16
color: {
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name
return isThisDevicePinned ? Theme.primary : Theme.surfaceText
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: {
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name
return isThisDevicePinned ? "Pinned" : "Pin"
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
return isThisDevicePinned ? "Pinned" : "Pin";
}
font.pixelSize: Theme.fontSizeSmall
color: {
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name
return isThisDevicePinned ? Theme.primary : Theme.surfaceText
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
}
@@ -252,16 +256,16 @@ Rectangle {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
const pins = JSON.parse(JSON.stringify(SettingsData.audioInputDevicePins || {}))
const isCurrentlyPinned = pins["preferredInput"] === modelData.name
const pins = JSON.parse(JSON.stringify(SettingsData.audioInputDevicePins || {}));
const isCurrentlyPinned = pins["preferredInput"] === modelData.name;
if (isCurrentlyPinned) {
delete pins["preferredInput"]
delete pins["preferredInput"];
} else {
pins["preferredInput"] = modelData.name
pins["preferredInput"] = modelData.name;
}
SettingsData.set("audioInputDevicePins", pins)
SettingsData.set("audioInputDevicePins", pins);
}
}
}
@@ -274,7 +278,7 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onClicked: {
if (modelData) {
Pipewire.preferredDefaultAudioSource = modelData
Pipewire.preferredDefaultAudioSource = modelData;
}
}
}
@@ -282,4 +286,4 @@ Rectangle {
}
}
}
}
}

View File

@@ -1,6 +1,4 @@
import QtQuick
import QtQuick.Controls
import Quickshell
import qs.Common
import qs.Services
import qs.Widgets
@@ -11,88 +9,91 @@ Rectangle {
property string initialDeviceName: ""
property string instanceId: ""
property string screenName: ""
property string screenModel: ""
signal deviceNameChanged(string newDeviceName)
property string currentDeviceName: ""
function getScreenPinKey() {
if (SettingsData.displayNameMode === "model" && screenModel && screenModel.length > 0) {
return screenModel;
}
return screenName || "";
}
function resolveDeviceName() {
if (!DisplayService.brightnessAvailable || !DisplayService.devices || DisplayService.devices.length === 0) {
return ""
return "";
}
if (screenName && screenName.length > 0) {
const pins = SettingsData.brightnessDevicePins || {}
const pinnedDevice = pins[screenName]
const pinKey = getScreenPinKey();
if (pinKey.length > 0) {
const pins = SettingsData.brightnessDevicePins || {};
const pinnedDevice = pins[pinKey];
if (pinnedDevice && pinnedDevice.length > 0) {
const found = DisplayService.devices.find(dev => dev.name === pinnedDevice)
if (found) {
return found.name
}
const found = DisplayService.devices.find(dev => dev.name === pinnedDevice);
if (found)
return found.name;
}
}
if (initialDeviceName && initialDeviceName.length > 0) {
const found = DisplayService.devices.find(dev => dev.name === initialDeviceName)
if (found) {
return found.name
}
const found = DisplayService.devices.find(dev => dev.name === initialDeviceName);
if (found)
return found.name;
}
const currentDeviceNameFromService = DisplayService.currentDevice
const currentDeviceNameFromService = DisplayService.currentDevice;
if (currentDeviceNameFromService) {
const found = DisplayService.devices.find(dev => dev.name === currentDeviceNameFromService)
if (found) {
return found.name
}
const found = DisplayService.devices.find(dev => dev.name === currentDeviceNameFromService);
if (found)
return found.name;
}
const backlight = DisplayService.devices.find(d => d.class === "backlight")
if (backlight) {
return backlight.name
}
const backlight = DisplayService.devices.find(d => d.class === "backlight");
if (backlight)
return backlight.name;
const ddc = DisplayService.devices.find(d => d.class === "ddc")
if (ddc) {
return ddc.name
}
const ddc = DisplayService.devices.find(d => d.class === "ddc");
if (ddc)
return ddc.name;
return DisplayService.devices.length > 0 ? DisplayService.devices[0].name : ""
return DisplayService.devices.length > 0 ? DisplayService.devices[0].name : "";
}
Component.onCompleted: {
currentDeviceName = resolveDeviceName()
currentDeviceName = resolveDeviceName();
}
property bool isPinnedToScreen: {
if (!screenName || screenName.length === 0) {
return false
}
const pins = SettingsData.brightnessDevicePins || {}
return pins[screenName] === currentDeviceName
const pinKey = getScreenPinKey();
if (!pinKey || pinKey.length === 0)
return false;
const pins = SettingsData.brightnessDevicePins || {};
return pins[pinKey] === currentDeviceName;
}
function togglePinToScreen() {
if (!screenName || screenName.length === 0 || !currentDeviceName || currentDeviceName.length === 0) {
return
}
const pins = JSON.parse(JSON.stringify(SettingsData.brightnessDevicePins || {}))
const pinKey = getScreenPinKey();
if (!pinKey || pinKey.length === 0 || !currentDeviceName || currentDeviceName.length === 0)
return;
const pins = JSON.parse(JSON.stringify(SettingsData.brightnessDevicePins || {}));
if (isPinnedToScreen) {
delete pins[screenName]
delete pins[pinKey];
} else {
pins[screenName] = currentDeviceName
pins[pinKey] = currentDeviceName;
}
SettingsData.set("brightnessDevicePins", pins)
SettingsData.set("brightnessDevicePins", pins);
}
implicitHeight: {
if (height > 0) {
return height
return height;
}
return brightnessContent.height + Theme.spacingM
return brightnessContent.height + Theme.spacingM;
}
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
@@ -165,7 +166,7 @@ Rectangle {
}
StyledText {
text: screenName || "Unknown Monitor"
text: root.getScreenPinKey() || "Unknown Monitor"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
@@ -216,8 +217,8 @@ Rectangle {
required property int index
property real deviceBrightness: {
DisplayService.brightnessVersion
return DisplayService.getDeviceBrightness(modelData.name)
DisplayService.brightnessVersion;
return DisplayService.getDeviceBrightness(modelData.name);
}
width: parent.width
@@ -248,19 +249,19 @@ Rectangle {
DankIcon {
name: {
const deviceClass = modelData.class || ""
const deviceName = modelData.name || ""
const deviceClass = modelData.class || "";
const deviceName = modelData.name || "";
if (deviceClass === "backlight" || deviceClass === "ddc") {
if (deviceBrightness <= 33)
return "brightness_low"
return "brightness_low";
if (deviceBrightness <= 66)
return "brightness_medium"
return "brightness_high"
return "brightness_medium";
return "brightness_high";
} else if (deviceName.includes("kbd")) {
return "keyboard"
return "keyboard";
} else {
return "lightbulb"
return "lightbulb";
}
}
size: Theme.iconSize
@@ -283,12 +284,12 @@ Rectangle {
StyledText {
text: {
const name = modelData.name || ""
const deviceClass = modelData.class || ""
const name = modelData.name || "";
const deviceClass = modelData.class || "";
if (deviceClass === "backlight") {
return name.replace("_", " ").replace(/\b\w/g, c => c.toUpperCase())
return name.replace("_", " ").replace(/\b\w/g, c => c.toUpperCase());
}
return name
return name;
}
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
@@ -307,14 +308,14 @@ Rectangle {
StyledText {
text: {
const deviceClass = modelData.class || ""
const deviceClass = modelData.class || "";
if (deviceClass === "backlight")
return "Backlight device"
return "Backlight device";
if (deviceClass === "ddc")
return "DDC/CI monitor"
return "DDC/CI monitor";
if (deviceClass === "leds")
return "LED device"
return deviceClass
return "LED device";
return deviceClass;
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
@@ -353,9 +354,9 @@ Rectangle {
cornerRadius: parent.radius
enabled: SessionData.getBrightnessExponent(modelData.name) > 1.0
onClicked: {
const current = SessionData.getBrightnessExponent(modelData.name)
const newValue = Math.max(1.0, Math.round((current - 0.1) * 10) / 10)
SessionData.setBrightnessExponent(modelData.name, newValue)
const current = SessionData.getBrightnessExponent(modelData.name);
const newValue = Math.max(1.0, Math.round((current - 0.1) * 10) / 10);
SessionData.setBrightnessExponent(modelData.name, newValue);
}
}
}
@@ -395,9 +396,9 @@ Rectangle {
cornerRadius: parent.radius
enabled: SessionData.getBrightnessExponent(modelData.name) < 2.5
onClicked: {
const current = SessionData.getBrightnessExponent(modelData.name)
const newValue = Math.min(2.5, Math.round((current + 0.1) * 10) / 10)
SessionData.setBrightnessExponent(modelData.name, newValue)
const current = SessionData.getBrightnessExponent(modelData.name);
const newValue = Math.min(2.5, Math.round((current + 0.1) * 10) / 10);
SessionData.setBrightnessExponent(modelData.name, newValue);
}
}
}
@@ -433,8 +434,8 @@ Rectangle {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
const currentState = SessionData.getBrightnessExponential(modelData.name)
SessionData.setBrightnessExponential(modelData.name, !currentState)
const currentState = SessionData.getBrightnessExponential(modelData.name);
SessionData.setBrightnessExponential(modelData.name, !currentState);
}
}
}
@@ -447,15 +448,16 @@ Rectangle {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (screenName && screenName.length > 0 && modelData.name !== currentDeviceName) {
const pins = JSON.parse(JSON.stringify(SettingsData.brightnessDevicePins || {}))
if (pins[screenName]) {
delete pins[screenName]
SettingsData.set("brightnessDevicePins", pins)
const pinKey = root.getScreenPinKey();
if (pinKey.length > 0 && modelData.name !== currentDeviceName) {
const pins = JSON.parse(JSON.stringify(SettingsData.brightnessDevicePins || {}));
if (pins[pinKey]) {
delete pins[pinKey];
SettingsData.set("brightnessDevicePins", pins);
}
}
currentDeviceName = modelData.name
deviceNameChanged(modelData.name)
currentDeviceName = modelData.name;
deviceNameChanged(modelData.name);
}
}
}