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

@@ -105,6 +105,11 @@ Singleton {
property bool controlCenterShowNetworkIcon: true
property bool controlCenterShowBluetoothIcon: true
property bool controlCenterShowAudioIcon: true
property bool controlCenterShowVpnIcon: false
property bool controlCenterShowBrightnessIcon: false
property bool controlCenterShowMicIcon: false
property bool controlCenterShowBatteryIcon: false
property bool controlCenterShowPrinterIcon: false
property bool showPrivacyButton: true
property bool privacyShowMicIcon: false
property bool privacyShowCameraIcon: false

View File

@@ -51,6 +51,11 @@ var SPEC = {
controlCenterShowNetworkIcon: { def: true },
controlCenterShowBluetoothIcon: { def: true },
controlCenterShowAudioIcon: { def: true },
controlCenterShowVpnIcon: { def: false },
controlCenterShowBrightnessIcon: { def: false },
controlCenterShowMicIcon: { def: false },
controlCenterShowBatteryIcon: { def: false },
controlCenterShowPrinterIcon: { def: false },
showPrivacyButton: { def: true },
privacyShowMicIcon: { def: false },

View File

@@ -2,7 +2,6 @@ import QtQuick
import qs.Common
import qs.Services
import qs.Modules.ControlCenter.Details
import qs.Modules.ControlCenter.Models
Item {
id: root
@@ -11,17 +10,21 @@ Item {
property var expandedWidgetData: null
property var bluetoothCodecSelector: null
property string screenName: ""
property string screenModel: ""
property var pluginDetailInstance: null
property var widgetModel: null
property var collapseCallback: null
function getDetailHeight(section) {
const maxAvailable = parent ? parent.height - Theme.spacingS : 9999
if (section === "wifi") return Math.min(350, maxAvailable)
if (section === "bluetooth") return Math.min(350, maxAvailable)
if (section.startsWith("brightnessSlider_")) return Math.min(400, maxAvailable)
return Math.min(250, maxAvailable)
const maxAvailable = parent ? parent.height - Theme.spacingS : 9999;
if (section === "wifi")
return Math.min(350, maxAvailable);
if (section === "bluetooth")
return Math.min(350, maxAvailable);
if (section.startsWith("brightnessSlider_"))
return Math.min(400, maxAvailable);
return Math.min(250, maxAvailable);
}
Loader {
@@ -49,18 +52,18 @@ Item {
function onDeviceNameChanged(newDeviceName) {
if (root.expandedWidgetData && root.expandedWidgetData.id === "brightnessSlider") {
const widgets = SettingsData.controlCenterWidgets || []
const widgets = SettingsData.controlCenterWidgets || [];
const newWidgets = widgets.map(w => {
if (w.id === "brightnessSlider" && w.instanceId === root.expandedWidgetData.instanceId) {
const updatedWidget = Object.assign({}, w)
updatedWidget.deviceName = newDeviceName
return updatedWidget
const updatedWidget = Object.assign({}, w);
updatedWidget.deviceName = newDeviceName;
return updatedWidget;
}
return w
})
SettingsData.set("controlCenterWidgets", newWidgets)
return w;
});
SettingsData.set("controlCenterWidgets", newWidgets);
if (root.collapseCallback) {
root.collapseCallback()
root.collapseCallback();
}
}
}
@@ -73,18 +76,18 @@ Item {
function onMountPathChanged(newMountPath) {
if (root.expandedWidgetData && root.expandedWidgetData.id === "diskUsage") {
const widgets = SettingsData.controlCenterWidgets || []
const widgets = SettingsData.controlCenterWidgets || [];
const newWidgets = widgets.map(w => {
if (w.id === "diskUsage" && w.instanceId === root.expandedWidgetData.instanceId) {
const updatedWidget = Object.assign({}, w)
updatedWidget.mountPath = newMountPath
return updatedWidget
const updatedWidget = Object.assign({}, w);
updatedWidget.mountPath = newMountPath;
return updatedWidget;
}
return w
})
SettingsData.set("controlCenterWidgets", newWidgets)
return w;
});
SettingsData.set("controlCenterWidgets", newWidgets);
if (root.collapseCallback) {
root.collapseCallback()
root.collapseCallback();
}
}
}
@@ -92,86 +95,97 @@ Item {
onExpandedSectionChanged: {
if (pluginDetailInstance) {
pluginDetailInstance.destroy()
pluginDetailInstance = null
pluginDetailInstance.destroy();
pluginDetailInstance = null;
}
pluginDetailLoader.active = false
coreDetailLoader.active = false
pluginDetailLoader.active = false;
coreDetailLoader.active = false;
if (!root.expandedSection) {
return
return;
}
if (root.expandedSection.startsWith("builtin_")) {
const builtinId = root.expandedSection
let builtinInstance = null
const builtinId = root.expandedSection;
let builtinInstance = null;
if (builtinId === "builtin_vpn") {
if (widgetModel?.vpnLoader) {
widgetModel.vpnLoader.active = true
widgetModel.vpnLoader.active = true;
}
builtinInstance = widgetModel.vpnBuiltinInstance
builtinInstance = widgetModel.vpnBuiltinInstance;
}
if (builtinId === "builtin_cups") {
if (widgetModel?.cupsLoader) {
widgetModel.cupsLoader.active = true
widgetModel.cupsLoader.active = true;
}
builtinInstance = widgetModel.cupsBuiltinInstance
builtinInstance = widgetModel.cupsBuiltinInstance;
}
if (!builtinInstance || !builtinInstance.ccDetailContent) {
return
return;
}
pluginDetailLoader.sourceComponent = builtinInstance.ccDetailContent
pluginDetailLoader.active = parent.height > 0
return
pluginDetailLoader.sourceComponent = builtinInstance.ccDetailContent;
pluginDetailLoader.active = parent.height > 0;
return;
}
if (root.expandedSection.startsWith("plugin_")) {
const pluginId = root.expandedSection.replace("plugin_", "")
const pluginComponent = PluginService.pluginWidgetComponents[pluginId]
const pluginId = root.expandedSection.replace("plugin_", "");
const pluginComponent = PluginService.pluginWidgetComponents[pluginId];
if (!pluginComponent) {
return
return;
}
pluginDetailInstance = pluginComponent.createObject(null)
pluginDetailInstance = pluginComponent.createObject(null);
if (!pluginDetailInstance || !pluginDetailInstance.ccDetailContent) {
if (pluginDetailInstance) {
pluginDetailInstance.destroy()
pluginDetailInstance = null
pluginDetailInstance.destroy();
pluginDetailInstance = null;
}
return
return;
}
pluginDetailLoader.sourceComponent = pluginDetailInstance.ccDetailContent
pluginDetailLoader.active = parent.height > 0
return
pluginDetailLoader.sourceComponent = pluginDetailInstance.ccDetailContent;
pluginDetailLoader.active = parent.height > 0;
return;
}
if (root.expandedSection.startsWith("diskUsage_")) {
coreDetailLoader.sourceComponent = diskUsageDetailComponent
coreDetailLoader.active = parent.height > 0
return
coreDetailLoader.sourceComponent = diskUsageDetailComponent;
coreDetailLoader.active = parent.height > 0;
return;
}
if (root.expandedSection.startsWith("brightnessSlider_")) {
coreDetailLoader.sourceComponent = brightnessDetailComponent
coreDetailLoader.active = parent.height > 0
return
coreDetailLoader.sourceComponent = brightnessDetailComponent;
coreDetailLoader.active = parent.height > 0;
return;
}
switch (root.expandedSection) {
case "network":
case "wifi": coreDetailLoader.sourceComponent = networkDetailComponent; break
case "bluetooth": coreDetailLoader.sourceComponent = bluetoothDetailComponent; break
case "audioOutput": coreDetailLoader.sourceComponent = audioOutputDetailComponent; break
case "audioInput": coreDetailLoader.sourceComponent = audioInputDetailComponent; break
case "battery": coreDetailLoader.sourceComponent = batteryDetailComponent; break
default: return
case "wifi":
coreDetailLoader.sourceComponent = networkDetailComponent;
break;
case "bluetooth":
coreDetailLoader.sourceComponent = bluetoothDetailComponent;
break;
case "audioOutput":
coreDetailLoader.sourceComponent = audioOutputDetailComponent;
break;
case "audioInput":
coreDetailLoader.sourceComponent = audioInputDetailComponent;
break;
case "battery":
coreDetailLoader.sourceComponent = batteryDetailComponent;
break;
default:
return;
}
coreDetailLoader.active = parent.height > 0
coreDetailLoader.active = parent.height > 0;
}
Component {
@@ -185,10 +199,10 @@ Item {
id: bluetoothDetail
onShowCodecSelector: function (device) {
if (root.bluetoothCodecSelector) {
root.bluetoothCodecSelector.show(device)
root.bluetoothCodecSelector.show(device);
root.bluetoothCodecSelector.codecSelected.connect(function (deviceAddress, codecName) {
bluetoothDetail.updateDeviceCodecDisplay(deviceAddress, codecName)
})
bluetoothDetail.updateDeviceCodecDisplay(deviceAddress, codecName);
});
}
}
}
@@ -223,6 +237,7 @@ Item {
initialDeviceName: root.expandedWidgetData?.deviceName || ""
instanceId: root.expandedWidgetData?.instanceId || ""
screenName: root.screenName
screenModel: root.screenModel
}
}
}

View File

@@ -16,16 +16,17 @@ Column {
property var bluetoothCodecSelector: null
property bool darkModeTransitionPending: false
property string screenName: ""
property string screenModel: ""
property var parentScreen: null
signal expandClicked(var widgetData, int globalIndex)
signal removeWidget(int index)
signal moveWidget(int fromIndex, int toIndex)
signal toggleWidgetSize(int index)
signal collapseRequested()
signal collapseRequested
function requestCollapse() {
collapseRequested()
collapseRequested();
}
spacing: editMode ? Theme.spacingL : Theme.spacingS
@@ -36,27 +37,27 @@ Column {
property var colorPickerModal: null
function calculateRowsAndWidgets() {
return LayoutUtils.calculateRowsAndWidgets(root, expandedSection, expandedWidgetIndex)
return LayoutUtils.calculateRowsAndWidgets(root, expandedSection, expandedWidgetIndex);
}
property var layoutResult: {
const dummy = [expandedSection, expandedWidgetIndex, model?.controlCenterWidgets]
return calculateRowsAndWidgets()
const dummy = [expandedSection, expandedWidgetIndex, model?.controlCenterWidgets];
return calculateRowsAndWidgets();
}
onLayoutResultChanged: {
expandedRowIndex = layoutResult.expandedRowIndex
expandedRowIndex = layoutResult.expandedRowIndex;
}
function moveToTop(item) {
const children = root.children
const children = root.children;
for (var i = 0; i < children.length; i++) {
if (children[i] === item)
continue
continue;
if (children[i].z)
children[i].z = Math.min(children[i].z, 999)
children[i].z = Math.min(children[i].z, 999);
}
item.z = 1000
item.z = 1000;
}
Repeater {
@@ -68,10 +69,10 @@ Column {
property int rowIndex: index
property var rowWidgets: modelData
property bool isSliderOnlyRow: {
const widgets = rowWidgets || []
const widgets = rowWidgets || [];
if (widgets.length === 0)
return false
return widgets.every(w => w.id === "volumeSlider" || w.id === "brightnessSlider" || w.id === "inputVolumeSlider")
return false;
return widgets.every(w => w.id === "volumeSlider" || w.id === "brightnessSlider" || w.id === "inputVolumeSlider");
}
topPadding: isSliderOnlyRow ? (root.editMode ? 4 : -6) : 0
bottomPadding: isSliderOnlyRow ? (root.editMode ? 4 : -6) : 0
@@ -86,32 +87,32 @@ Column {
DragDropWidgetWrapper {
widgetData: modelData
property int globalWidgetIndex: {
const widgets = SettingsData.controlCenterWidgets || []
const widgets = SettingsData.controlCenterWidgets || [];
for (var i = 0; i < widgets.length; i++) {
if (widgets[i].id === modelData.id) {
if (modelData.id === "diskUsage" || modelData.id === "brightnessSlider") {
if (widgets[i].instanceId === modelData.instanceId) {
return i
return i;
}
} else {
return i
return i;
}
}
}
return -1
return -1;
}
property int widgetWidth: modelData.width || 50
width: {
const baseWidth = root.width
const spacing = Theme.spacingS
const baseWidth = root.width;
const spacing = Theme.spacingS;
if (widgetWidth <= 25) {
return (baseWidth - spacing * 3) / 4
return (baseWidth - spacing * 3) / 4;
} else if (widgetWidth <= 50) {
return (baseWidth - spacing) / 2
return (baseWidth - spacing) / 2;
} else if (widgetWidth <= 75) {
return (baseWidth - spacing * 2) * 0.75
return (baseWidth - spacing * 2) * 0.75;
} else {
return baseWidth
return baseWidth;
}
}
height: isSliderOnlyRow ? 48 : 60
@@ -123,32 +124,32 @@ Column {
gridColumns: 4
gridLayout: root
isSlider: {
const id = modelData.id || ""
return id === "volumeSlider" || id === "brightnessSlider" || id === "inputVolumeSlider"
const id = modelData.id || "";
return id === "volumeSlider" || id === "brightnessSlider" || id === "inputVolumeSlider";
}
widgetComponent: {
const id = modelData.id || ""
const id = modelData.id || "";
if (id.startsWith("builtin_")) {
return builtinPluginWidgetComponent
return builtinPluginWidgetComponent;
} else if (id.startsWith("plugin_")) {
return pluginWidgetComponent
return pluginWidgetComponent;
} else if (id === "wifi" || id === "bluetooth" || id === "audioOutput" || id === "audioInput") {
return compoundPillComponent
return compoundPillComponent;
} else if (id === "volumeSlider") {
return audioSliderComponent
return audioSliderComponent;
} else if (id === "brightnessSlider") {
return brightnessSliderComponent
return brightnessSliderComponent;
} else if (id === "inputVolumeSlider") {
return inputAudioSliderComponent
return inputAudioSliderComponent;
} else if (id === "battery") {
return widgetWidth <= 25 ? smallBatteryComponent : batteryPillComponent
return widgetWidth <= 25 ? smallBatteryComponent : batteryPillComponent;
} else if (id === "diskUsage") {
return diskUsagePillComponent
return diskUsagePillComponent;
} else if (id === "colorPicker") {
return colorPickerPillComponent
return colorPickerPillComponent;
} else {
return widgetWidth <= 25 ? smallToggleComponent : toggleButtonComponent
return widgetWidth <= 25 ? smallToggleComponent : toggleButtonComponent;
}
}
@@ -165,19 +166,19 @@ Column {
height: active ? (getDetailHeight(root.expandedSection) + Theme.spacingS) : 0
property bool active: {
if (root.expandedSection === "")
return false
return false;
if (root.expandedSection.startsWith("diskUsage_") && root.expandedWidgetData) {
const expandedInstanceId = root.expandedWidgetData.instanceId
return rowWidgets.some(w => w.id === "diskUsage" && w.instanceId === expandedInstanceId)
const expandedInstanceId = root.expandedWidgetData.instanceId;
return rowWidgets.some(w => w.id === "diskUsage" && w.instanceId === expandedInstanceId);
}
if (root.expandedSection.startsWith("brightnessSlider_") && root.expandedWidgetData) {
const expandedInstanceId = root.expandedWidgetData.instanceId
return rowWidgets.some(w => w.id === "brightnessSlider" && w.instanceId === expandedInstanceId)
const expandedInstanceId = root.expandedWidgetData.instanceId;
return rowWidgets.some(w => w.id === "brightnessSlider" && w.instanceId === expandedInstanceId);
}
return rowIndex === root.expandedRowIndex
return rowIndex === root.expandedRowIndex;
}
visible: active
expandedSection: root.expandedSection
@@ -186,6 +187,7 @@ Column {
widgetModel: root.model
collapseCallback: root.requestCollapse
screenName: root.screenName
screenModel: root.screenModel
}
}
}
@@ -198,9 +200,9 @@ Column {
height: 60
primaryMessage: {
if (!DMSService.dmsAvailable) {
return I18n.tr("DMS_SOCKET not available")
return I18n.tr("DMS_SOCKET not available");
}
return I18n.tr("NM not supported")
return I18n.tr("NM not supported");
}
secondaryMessage: I18n.tr("update dms for NM integration.")
}
@@ -219,50 +221,50 @@ Column {
case "wifi":
{
if (NetworkService.wifiToggling)
return "sync"
return "sync";
const status = NetworkService.networkStatus
const status = NetworkService.networkStatus;
if (status === "ethernet")
return "settings_ethernet"
return "settings_ethernet";
if (status === "vpn")
return NetworkService.ethernetConnected ? "settings_ethernet" : NetworkService.wifiSignalIcon
return NetworkService.ethernetConnected ? "settings_ethernet" : NetworkService.wifiSignalIcon;
if (status === "wifi")
return NetworkService.wifiSignalIcon
return NetworkService.wifiSignalIcon;
if (NetworkService.wifiEnabled)
return "wifi_off"
return "wifi_off"
return "wifi_off";
return "wifi_off";
}
case "bluetooth":
{
if (!BluetoothService.available)
return "bluetooth_disabled"
return "bluetooth_disabled";
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled)
return "bluetooth_disabled"
return "bluetooth"
return "bluetooth_disabled";
return "bluetooth";
}
case "audioOutput":
{
if (!AudioService.sink)
return "volume_off"
let volume = AudioService.sink.audio.volume
let muted = AudioService.sink.audio.muted
return "volume_off";
let volume = AudioService.sink.audio.volume;
let muted = AudioService.sink.audio.muted;
if (muted || volume === 0.0)
return "volume_off"
return "volume_off";
if (volume <= 0.33)
return "volume_down"
return "volume_down";
if (volume <= 0.66)
return "volume_up"
return "volume_up"
return "volume_up";
return "volume_up";
}
case "audioInput":
{
if (!AudioService.source)
return "mic_off"
let muted = AudioService.source.audio.muted
return muted ? "mic_off" : "mic"
return "mic_off";
let muted = AudioService.source.audio.muted;
return muted ? "mic_off" : "mic";
}
default:
return widgetDef?.icon || "help"
return widgetDef?.icon || "help";
}
}
primaryText: {
@@ -270,39 +272,39 @@ Column {
case "wifi":
{
if (NetworkService.wifiToggling)
return NetworkService.wifiEnabled ? "Disabling WiFi..." : "Enabling WiFi..."
return NetworkService.wifiEnabled ? "Disabling WiFi..." : "Enabling WiFi...";
const status = NetworkService.networkStatus
const status = NetworkService.networkStatus;
if (status === "ethernet")
return "Ethernet"
return "Ethernet";
if (status === "vpn") {
if (NetworkService.ethernetConnected)
return "Ethernet"
return "Ethernet";
if (NetworkService.wifiConnected && NetworkService.currentWifiSSID)
return NetworkService.currentWifiSSID
return NetworkService.currentWifiSSID;
}
if (status === "wifi" && NetworkService.currentWifiSSID)
return NetworkService.currentWifiSSID
return NetworkService.currentWifiSSID;
if (NetworkService.wifiEnabled)
return "Not connected"
return "WiFi off"
return "Not connected";
return "WiFi off";
}
case "bluetooth":
{
if (!BluetoothService.available)
return "Bluetooth"
return "Bluetooth";
if (!BluetoothService.adapter)
return "No adapter"
return "No adapter";
if (!BluetoothService.adapter.enabled)
return "Disabled"
return "Enabled"
return "Disabled";
return "Enabled";
}
case "audioOutput":
return AudioService.sink?.description || "No output device"
return AudioService.sink?.description || "No output device";
case "audioInput":
return AudioService.source?.description || "No input device"
return AudioService.source?.description || "No input device";
default:
return widgetDef?.text || "Unknown"
return widgetDef?.text || "Unknown";
}
}
secondaryText: {
@@ -310,67 +312,67 @@ Column {
case "wifi":
{
if (NetworkService.wifiToggling)
return "Please wait..."
return "Please wait...";
const status = NetworkService.networkStatus
const status = NetworkService.networkStatus;
if (status === "ethernet")
return "Connected"
return "Connected";
if (status === "vpn") {
if (NetworkService.ethernetConnected)
return "Connected"
return "Connected";
if (NetworkService.wifiConnected)
return NetworkService.wifiSignalStrength > 0 ? NetworkService.wifiSignalStrength + "%" : "Connected"
return NetworkService.wifiSignalStrength > 0 ? NetworkService.wifiSignalStrength + "%" : "Connected";
}
if (status === "wifi")
return NetworkService.wifiSignalStrength > 0 ? NetworkService.wifiSignalStrength + "%" : "Connected"
return NetworkService.wifiSignalStrength > 0 ? NetworkService.wifiSignalStrength + "%" : "Connected";
if (NetworkService.wifiEnabled)
return "Select network"
return ""
return "Select network";
return "";
}
case "bluetooth":
{
if (!BluetoothService.available)
return "No adapters"
return "No adapters";
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled)
return "Off"
return "Off";
const primaryDevice = (() => {
if (!BluetoothService.adapter || !BluetoothService.adapter.devices)
return null
let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]
return null;
let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))];
for (let device of devices) {
if (device && device.connected)
return device
return device;
}
return null
})()
return null;
})();
if (primaryDevice)
return primaryDevice.name || primaryDevice.alias || primaryDevice.deviceName || "Connected Device"
return "No devices"
return primaryDevice.name || primaryDevice.alias || primaryDevice.deviceName || "Connected Device";
return "No devices";
}
case "audioOutput":
{
if (!AudioService.sink)
return "Select device"
return "Select device";
if (AudioService.sink.audio.muted)
return "Muted"
const volume = AudioService.sink.audio.volume
return "Muted";
const volume = AudioService.sink.audio.volume;
if (typeof volume !== "number" || isNaN(volume))
return "0%"
return Math.round(volume * 100) + "%"
return "0%";
return Math.round(volume * 100) + "%";
}
case "audioInput":
{
if (!AudioService.source)
return "Select device"
return "Select device";
if (AudioService.source.audio.muted)
return "Muted"
const volume = AudioService.source.audio.volume
return "Muted";
const volume = AudioService.source.audio.volume;
if (typeof volume !== "number" || isNaN(volume))
return "0%"
return Math.round(volume * 100) + "%"
return "0%";
return Math.round(volume * 100) + "%";
}
default:
return widgetDef?.description || ""
return widgetDef?.description || "";
}
}
isActive: {
@@ -378,97 +380,97 @@ Column {
case "wifi":
{
if (NetworkService.wifiToggling)
return false
return false;
const status = NetworkService.networkStatus
const status = NetworkService.networkStatus;
if (status === "ethernet")
return true
return true;
if (status === "vpn")
return NetworkService.ethernetConnected || NetworkService.wifiConnected
return NetworkService.ethernetConnected || NetworkService.wifiConnected;
if (status === "wifi")
return true
return NetworkService.wifiEnabled
return true;
return NetworkService.wifiEnabled;
}
case "bluetooth":
return !!(BluetoothService.available && BluetoothService.adapter && BluetoothService.adapter.enabled)
return !!(BluetoothService.available && BluetoothService.adapter && BluetoothService.adapter.enabled);
case "audioOutput":
return !!(AudioService.sink && !AudioService.sink.audio.muted)
return !!(AudioService.sink && !AudioService.sink.audio.muted);
case "audioInput":
return !!(AudioService.source && !AudioService.source.audio.muted)
return !!(AudioService.source && !AudioService.source.audio.muted);
default:
return false
return false;
}
}
enabled: widgetDef?.enabled ?? true
onToggled: {
if (root.editMode)
return
return;
switch (widgetData.id || "") {
case "wifi":
{
if (NetworkService.networkStatus !== "ethernet" && !NetworkService.wifiToggling) {
NetworkService.toggleWifiRadio()
NetworkService.toggleWifiRadio();
}
break
break;
}
case "bluetooth":
{
if (BluetoothService.available && BluetoothService.adapter) {
BluetoothService.adapter.enabled = !BluetoothService.adapter.enabled
BluetoothService.adapter.enabled = !BluetoothService.adapter.enabled;
}
break
break;
}
case "audioOutput":
{
if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.muted = !AudioService.sink.audio.muted
AudioService.sink.audio.muted = !AudioService.sink.audio.muted;
}
break
break;
}
case "audioInput":
{
if (AudioService.source && AudioService.source.audio) {
AudioService.source.audio.muted = !AudioService.source.audio.muted
AudioService.source.audio.muted = !AudioService.source.audio.muted;
}
break
break;
}
}
}
onExpandClicked: {
if (root.editMode)
return
root.expandClicked(widgetData, widgetIndex)
return;
root.expandClicked(widgetData, widgetIndex);
}
onWheelEvent: function (wheelEvent) {
if (root.editMode)
return
const id = widgetData.id || ""
return;
const id = widgetData.id || "";
if (id === "audioOutput") {
if (!AudioService.sink || !AudioService.sink.audio)
return
let delta = wheelEvent.angleDelta.y
let currentVolume = AudioService.sink.audio.volume * 100
let newVolume
return;
let delta = wheelEvent.angleDelta.y;
let currentVolume = AudioService.sink.audio.volume * 100;
let newVolume;
if (delta > 0)
newVolume = Math.min(100, currentVolume + 5)
newVolume = Math.min(100, currentVolume + 5);
else
newVolume = Math.max(0, currentVolume - 5)
AudioService.sink.audio.muted = false
AudioService.sink.audio.volume = newVolume / 100
wheelEvent.accepted = true
newVolume = Math.max(0, currentVolume - 5);
AudioService.sink.audio.muted = false;
AudioService.sink.audio.volume = newVolume / 100;
wheelEvent.accepted = true;
} else if (id === "audioInput") {
if (!AudioService.source || !AudioService.source.audio)
return
let delta = wheelEvent.angleDelta.y
let currentVolume = AudioService.source.audio.volume * 100
let newVolume
return;
let delta = wheelEvent.angleDelta.y;
let currentVolume = AudioService.source.audio.volume * 100;
let newVolume;
if (delta > 0)
newVolume = Math.min(100, currentVolume + 5)
newVolume = Math.min(100, currentVolume + 5);
else
newVolume = Math.max(0, currentVolume - 5)
AudioService.source.audio.muted = false
AudioService.source.audio.volume = newVolume / 100
wheelEvent.accepted = true
newVolume = Math.max(0, currentVolume - 5);
AudioService.source.audio.muted = false;
AudioService.source.audio.volume = newVolume / 100;
wheelEvent.accepted = true;
}
}
}
@@ -512,7 +514,7 @@ Column {
onIconClicked: {
if (!root.editMode && DisplayService.devices && DisplayService.devices.length > 1) {
root.expandClicked(widgetData, widgetIndex)
root.expandClicked(widgetData, widgetIndex);
}
}
}
@@ -546,7 +548,7 @@ Column {
onExpandClicked: {
if (!root.editMode) {
root.expandClicked(widgetData, widgetIndex)
root.expandClicked(widgetData, widgetIndex);
}
}
}
@@ -562,7 +564,7 @@ Column {
onClicked: {
if (!root.editMode) {
root.expandClicked(widgetData, widgetIndex)
root.expandClicked(widgetData, widgetIndex);
}
}
}
@@ -579,54 +581,54 @@ Column {
iconName: {
switch (widgetData.id || "") {
case "nightMode":
return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"
return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode";
case "darkMode":
return "contrast"
return "contrast";
case "doNotDisturb":
return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"
return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off";
case "idleInhibitor":
return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"
return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle";
default:
return "help"
return "help";
}
}
text: {
switch (widgetData.id || "") {
case "nightMode":
return I18n.tr("Night Mode")
return I18n.tr("Night Mode");
case "darkMode":
return I18n.tr("Dark Mode")
return I18n.tr("Dark Mode");
case "doNotDisturb":
return I18n.tr("Do Not Disturb")
return I18n.tr("Do Not Disturb");
case "idleInhibitor":
return SessionService.idleInhibited ? I18n.tr("Keeping Awake") : I18n.tr("Keep Awake")
return SessionService.idleInhibited ? I18n.tr("Keeping Awake") : I18n.tr("Keep Awake");
default:
return "Unknown"
return "Unknown";
}
}
iconRotation: {
if (widgetData.id !== "darkMode")
return 0
return 0;
if (darkModeTransitionPending) {
return SessionData.isLightMode ? 180 : 0
return SessionData.isLightMode ? 180 : 0;
}
return SessionData.isLightMode ? 180 : 0
return SessionData.isLightMode ? 180 : 0;
}
isActive: {
switch (widgetData.id || "") {
case "nightMode":
return DisplayService.nightModeEnabled || false
return DisplayService.nightModeEnabled || false;
case "darkMode":
return !SessionData.isLightMode
return !SessionData.isLightMode;
case "doNotDisturb":
return SessionData.doNotDisturb || false
return SessionData.doNotDisturb || false;
case "idleInhibitor":
return SessionService.idleInhibited || false
return SessionService.idleInhibited || false;
default:
return false
return false;
}
}
@@ -634,30 +636,30 @@ Column {
onClicked: {
if (root.editMode)
return
return;
switch (widgetData.id || "") {
case "nightMode":
{
if (DisplayService.automationAvailable)
DisplayService.toggleNightMode()
break
DisplayService.toggleNightMode();
break;
}
case "darkMode":
{
const newMode = !SessionData.isLightMode
Theme.screenTransition()
Theme.setLightMode(newMode)
break
const newMode = !SessionData.isLightMode;
Theme.screenTransition();
Theme.setLightMode(newMode);
break;
}
case "doNotDisturb":
{
SessionData.setDoNotDisturb(!SessionData.doNotDisturb)
break
SessionData.setDoNotDisturb(!SessionData.doNotDisturb);
break;
}
case "idleInhibitor":
{
SessionService.toggleIdleInhibit()
break
SessionService.toggleIdleInhibit();
break;
}
}
}
@@ -675,39 +677,39 @@ Column {
iconName: {
switch (widgetData.id || "") {
case "nightMode":
return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"
return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode";
case "darkMode":
return "contrast"
return "contrast";
case "doNotDisturb":
return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"
return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off";
case "idleInhibitor":
return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"
return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle";
default:
return "help"
return "help";
}
}
iconRotation: {
if (widgetData.id !== "darkMode")
return 0
return 0;
if (darkModeTransitionPending) {
return SessionData.isLightMode ? 180 : 0
return SessionData.isLightMode ? 180 : 0;
}
return SessionData.isLightMode ? 180 : 0
return SessionData.isLightMode ? 180 : 0;
}
isActive: {
switch (widgetData.id || "") {
case "nightMode":
return DisplayService.nightModeEnabled || false
return DisplayService.nightModeEnabled || false;
case "darkMode":
return !SessionData.isLightMode
return !SessionData.isLightMode;
case "doNotDisturb":
return SessionData.doNotDisturb || false
return SessionData.doNotDisturb || false;
case "idleInhibitor":
return SessionService.idleInhibited || false
return SessionService.idleInhibited || false;
default:
return false
return false;
}
}
@@ -715,30 +717,30 @@ Column {
onClicked: {
if (root.editMode)
return
return;
switch (widgetData.id || "") {
case "nightMode":
{
if (DisplayService.automationAvailable)
DisplayService.toggleNightMode()
break
DisplayService.toggleNightMode();
break;
}
case "darkMode":
{
const newMode = !SessionData.isLightMode
Theme.screenTransition()
Theme.setLightMode(newMode)
break
const newMode = !SessionData.isLightMode;
Theme.screenTransition();
Theme.setLightMode(newMode);
break;
}
case "doNotDisturb":
{
SessionData.setDoNotDisturb(!SessionData.doNotDisturb)
break
SessionData.setDoNotDisturb(!SessionData.doNotDisturb);
break;
}
case "idleInhibitor":
{
SessionService.toggleIdleInhibit()
break
SessionService.toggleIdleInhibit();
break;
}
}
}
@@ -758,7 +760,7 @@ Column {
onExpandClicked: {
if (!root.editMode) {
root.expandClicked(widgetData, widgetIndex)
root.expandClicked(widgetData, widgetIndex);
}
}
}
@@ -788,33 +790,33 @@ Column {
property var builtinInstance: null
Component.onCompleted: {
const id = widgetData.id || ""
const id = widgetData.id || "";
if (id === "builtin_vpn") {
if (root.model?.vpnLoader) {
root.model.vpnLoader.active = true
root.model.vpnLoader.active = true;
}
builtinInstance = Qt.binding(() => root.model?.vpnBuiltinInstance)
builtinInstance = Qt.binding(() => root.model?.vpnBuiltinInstance);
}
if (id === "builtin_cups") {
if (root.model?.cupsLoader) {
root.model.cupsLoader.active = true
root.model.cupsLoader.active = true;
}
builtinInstance = Qt.binding(() => root.model?.cupsBuiltinInstance)
builtinInstance = Qt.binding(() => root.model?.cupsBuiltinInstance);
}
}
sourceComponent: {
if (!builtinInstance)
return null
return null;
const hasDetail = builtinInstance.ccDetailContent !== null
const hasDetail = builtinInstance.ccDetailContent !== null;
if (widgetWidth <= 25) {
return builtinSmallToggleComponent
return builtinSmallToggleComponent;
} else if (hasDetail) {
return builtinCompoundPillComponent
return builtinCompoundPillComponent;
} else {
return builtinToggleComponent
return builtinToggleComponent;
}
}
}
@@ -834,19 +836,19 @@ Column {
onToggled: {
if (root.editMode)
return
return;
if (builtinInstance) {
builtinInstance.ccWidgetToggled()
builtinInstance.ccWidgetToggled();
}
}
onExpandClicked: {
if (root.editMode)
return
return;
if (builtinInstance) {
builtinInstance.ccWidgetExpanded()
builtinInstance.ccWidgetExpanded();
}
root.expandClicked(widgetData, widgetIndex)
root.expandClicked(widgetData, widgetIndex);
}
}
}
@@ -865,9 +867,9 @@ Column {
onClicked: {
if (root.editMode)
return
return;
if (builtinInstance) {
builtinInstance.ccWidgetToggled()
builtinInstance.ccWidgetToggled();
}
}
}
@@ -886,9 +888,9 @@ Column {
onClicked: {
if (root.editMode)
return
return;
if (builtinInstance) {
builtinInstance.ccWidgetToggled()
builtinInstance.ccWidgetToggled();
}
}
}
@@ -908,22 +910,22 @@ Column {
sourceComponent: {
if (!pluginInstance)
return null
return null;
const hasDetail = pluginInstance.ccDetailContent !== null
const hasDetail = pluginInstance.ccDetailContent !== null;
if (widgetWidth <= 25) {
return pluginSmallToggleComponent
return pluginSmallToggleComponent;
} else if (hasDetail) {
return pluginCompoundPillComponent
return pluginCompoundPillComponent;
} else {
return pluginToggleComponent
return pluginToggleComponent;
}
}
Component.onCompleted: {
Qt.callLater(() => {
const pluginComponent = PluginService.pluginWidgetComponents[pluginId]
const pluginComponent = PluginService.pluginWidgetComponents[pluginId];
if (pluginComponent) {
const instance = pluginComponent.createObject(null, {
"pluginId": pluginId,
@@ -931,26 +933,26 @@ Column {
"visible": false,
"width": 0,
"height": 0
})
});
if (instance) {
pluginInstance = instance
pluginInstance = instance;
}
}
})
});
}
Connections {
target: PluginService
function onPluginDataChanged(changedPluginId) {
if (changedPluginId === pluginId && pluginInstance) {
pluginInstance.loadPluginData()
pluginInstance.loadPluginData();
}
}
}
Component.onDestruction: {
if (pluginInstance) {
pluginInstance.destroy()
pluginInstance.destroy();
}
}
}
@@ -970,19 +972,19 @@ Column {
onToggled: {
if (root.editMode)
return
return;
if (pluginInstance) {
pluginInstance.ccWidgetToggled()
pluginInstance.ccWidgetToggled();
}
}
onExpandClicked: {
if (root.editMode)
return
return;
if (pluginInstance) {
pluginInstance.ccWidgetExpanded()
pluginInstance.ccWidgetExpanded();
}
root.expandClicked(widgetData, widgetIndex)
root.expandClicked(widgetData, widgetIndex);
}
}
}
@@ -1003,9 +1005,9 @@ Column {
onClicked: {
if (root.editMode)
return
return;
if (pluginInstance) {
pluginInstance.ccWidgetToggled()
pluginInstance.ccWidgetToggled();
}
}
}
@@ -1025,11 +1027,11 @@ Column {
onClicked: {
if (root.editMode)
return
return;
if (pluginInstance && pluginInstance.ccDetailContent) {
root.expandClicked(widgetData, widgetIndex)
root.expandClicked(widgetData, widgetIndex);
} else if (pluginInstance) {
pluginInstance.ccWidgetToggled()
pluginInstance.ccWidgetToggled();
}
}
}

View File

@@ -82,6 +82,7 @@ DankPopout {
onShouldBeVisibleChanged: {
if (shouldBeVisible) {
collapseAll();
Qt.callLater(() => {
if (NetworkService.activeService) {
NetworkService.activeService.autoRefreshEnabled = NetworkService.wifiEnabled;
@@ -179,6 +180,7 @@ DankPopout {
bluetoothCodecSelector: bluetoothCodecSelector
colorPickerModal: root.colorPickerModal
screenName: root.triggerScreen?.name || ""
screenModel: root.triggerScreen?.model || ""
parentScreen: root.triggerScreen
onExpandClicked: (widgetData, globalIndex) => {
root.expandedWidgetIndex = globalIndex;

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
@@ -99,9 +99,9 @@ Rectangle {
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"]
return node.audio && !node.isSink && !node.isStream;
});
const pins = SettingsData.audioInputDevicePins || {};
const pinnedName = pins["preferredInput"];
let sorted = [...nodes]
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;
}
}
}

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 resolveDeviceName() {
if (!DisplayService.brightnessAvailable || !DisplayService.devices || DisplayService.devices.length === 0) {
return ""
function getScreenPinKey() {
if (SettingsData.displayNameMode === "model" && screenModel && screenModel.length > 0) {
return screenModel;
}
return screenName || "";
}
if (screenName && screenName.length > 0) {
const pins = SettingsData.brightnessDevicePins || {}
const pinnedDevice = pins[screenName]
if (pinnedDevice && pinnedDevice.length > 0) {
const found = DisplayService.devices.find(dev => dev.name === pinnedDevice)
if (found) {
return found.name
function resolveDeviceName() {
if (!DisplayService.brightnessAvailable || !DisplayService.devices || DisplayService.devices.length === 0) {
return "";
}
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;
}
}
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);
}
}
}

View File

@@ -17,17 +17,17 @@ QtObject {
}
onItemChanged: {
root.vpnBuiltinInstance = item
root.vpnBuiltinInstance = item;
}
Connections {
target: SettingsData
function onControlCenterWidgetsChanged() {
const widgets = SettingsData.controlCenterWidgets || []
const hasVpnWidget = widgets.some(w => w.id === "builtin_vpn")
const widgets = SettingsData.controlCenterWidgets || [];
const hasVpnWidget = widgets.some(w => w.id === "builtin_vpn");
if (!hasVpnWidget && vpnLoader.active) {
console.log("VpnWidget: No VPN widget in control center, deactivating loader")
vpnLoader.active = false
console.log("VpnWidget: No VPN widget in control center, deactivating loader");
vpnLoader.active = false;
}
}
}
@@ -40,35 +40,36 @@ QtObject {
}
onItemChanged: {
root.cupsBuiltinInstance = item
root.cupsBuiltinInstance = item;
if (item && !DMSService.activeSubscriptions.includes("cups") && !DMSService.activeSubscriptions.includes("all")) {
DMSService.addSubscription("cups")
DMSService.addSubscription("cups");
}
}
onActiveChanged: {
if (!active) {
if (DMSService.activeSubscriptions.includes("cups")) {
DMSService.removeSubscription("cups")
DMSService.removeSubscription("cups");
}
root.cupsBuiltinInstance = null
root.cupsBuiltinInstance = null;
}
}
Connections {
target: SettingsData
function onControlCenterWidgetsChanged() {
const widgets = SettingsData.controlCenterWidgets || []
const hasCupsWidget = widgets.some(w => w.id === "builtin_cups")
const widgets = SettingsData.controlCenterWidgets || [];
const hasCupsWidget = widgets.some(w => w.id === "builtin_cups");
if (!hasCupsWidget && cupsLoader.active) {
console.log("CupsWidget: No CUPS widget in control center, deactivating loader")
cupsLoader.active = false
console.log("CupsWidget: No CUPS widget in control center, deactivating loader");
cupsLoader.active = false;
}
}
}
}
readonly property var coreWidgetDefinitions: [{
readonly property var coreWidgetDefinitions: [
{
"id": "nightMode",
"text": "Night Mode",
"description": "Blue light filter",
@@ -76,28 +77,32 @@ QtObject {
"type": "toggle",
"enabled": DisplayService.automationAvailable,
"warning": !DisplayService.automationAvailable ? "Requires night mode support" : undefined
}, {
},
{
"id": "darkMode",
"text": "Dark Mode",
"description": "System theme toggle",
"icon": "contrast",
"type": "toggle",
"enabled": true
}, {
},
{
"id": "doNotDisturb",
"text": "Do Not Disturb",
"description": "Block notifications",
"icon": "do_not_disturb_on",
"type": "toggle",
"enabled": true
}, {
},
{
"id": "idleInhibitor",
"text": "Keep Awake",
"description": "Prevent screen timeout",
"icon": "motion_sensor_active",
"type": "toggle",
"enabled": true
}, {
},
{
"id": "wifi",
"text": "Network",
"description": "Wi-Fi and Ethernet connection",
@@ -105,7 +110,8 @@ QtObject {
"type": "connection",
"enabled": NetworkService.wifiAvailable,
"warning": !NetworkService.wifiAvailable ? "Wi-Fi not available" : undefined
}, {
},
{
"id": "bluetooth",
"text": "Bluetooth",
"description": "Device connections",
@@ -113,28 +119,32 @@ QtObject {
"type": "connection",
"enabled": BluetoothService.available,
"warning": !BluetoothService.available ? "Bluetooth not available" : undefined
}, {
},
{
"id": "audioOutput",
"text": "Audio Output",
"description": "Speaker settings",
"icon": "volume_up",
"type": "connection",
"enabled": true
}, {
},
{
"id": "audioInput",
"text": "Audio Input",
"description": "Microphone settings",
"icon": "mic",
"type": "connection",
"enabled": true
}, {
},
{
"id": "volumeSlider",
"text": "Volume Slider",
"description": "Audio volume control",
"icon": "volume_up",
"type": "slider",
"enabled": true
}, {
},
{
"id": "brightnessSlider",
"text": "Brightness Slider",
"description": "Display brightness control",
@@ -143,21 +153,24 @@ QtObject {
"enabled": DisplayService.brightnessAvailable,
"warning": !DisplayService.brightnessAvailable ? "Brightness control not available" : undefined,
"allowMultiple": true
}, {
},
{
"id": "inputVolumeSlider",
"text": "Input Volume Slider",
"description": "Microphone volume control",
"icon": "mic",
"type": "slider",
"enabled": true
}, {
},
{
"id": "battery",
"text": "Battery",
"description": "Battery and power management",
"icon": "battery_std",
"type": "action",
"enabled": true
}, {
},
{
"id": "diskUsage",
"text": "Disk Usage",
"description": "Filesystem usage monitoring",
@@ -166,14 +179,16 @@ QtObject {
"enabled": DgopService.dgopAvailable,
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined,
"allowMultiple": true
}, {
},
{
"id": "colorPicker",
"text": "Color Picker",
"description": "Choose colors from palette",
"icon": "palette",
"type": "action",
"enabled": true
}, {
},
{
"id": "builtin_vpn",
"text": "VPN",
"description": "VPN connections",
@@ -182,7 +197,8 @@ QtObject {
"enabled": DMSNetworkService.available,
"warning": !DMSNetworkService.available ? "VPN not available" : undefined,
"isBuiltinPlugin": true
}, {
},
{
"id": "builtin_cups",
"text": "Printers",
"description": "Print Server Management",
@@ -191,34 +207,35 @@ QtObject {
"enabled": CupsService.available,
"warning": !CupsService.available ? "CUPS not available" : undefined,
"isBuiltinPlugin": true
}]
}
]
function getPluginWidgets() {
const plugins = []
const loadedPlugins = PluginService.getLoadedPlugins()
const plugins = [];
const loadedPlugins = PluginService.getLoadedPlugins();
for (var i = 0; i < loadedPlugins.length; i++) {
const plugin = loadedPlugins[i]
const plugin = loadedPlugins[i];
if (plugin.type === "daemon") {
continue
continue;
}
const pluginComponent = PluginService.pluginWidgetComponents[plugin.id]
const pluginComponent = PluginService.pluginWidgetComponents[plugin.id];
if (!pluginComponent || typeof pluginComponent.createObject !== 'function') {
continue
continue;
}
const tempInstance = pluginComponent.createObject(null)
const tempInstance = pluginComponent.createObject(null);
if (!tempInstance) {
continue
continue;
}
const hasCCWidget = tempInstance.ccWidgetIcon && tempInstance.ccWidgetIcon.length > 0
tempInstance.destroy()
const hasCCWidget = tempInstance.ccWidgetIcon && tempInstance.ccWidgetIcon.length > 0;
tempInstance.destroy();
if (!hasCCWidget) {
continue
continue;
}
plugins.push({
@@ -230,39 +247,39 @@ QtObject {
"type": "plugin",
"enabled": true,
"isPlugin": true
})
});
}
return plugins
return plugins;
}
readonly property var baseWidgetDefinitions: coreWidgetDefinitions
function getWidgetForId(widgetId) {
return WidgetUtils.getWidgetForId(baseWidgetDefinitions, widgetId)
return WidgetUtils.getWidgetForId(baseWidgetDefinitions, widgetId);
}
function addWidget(widgetId) {
WidgetUtils.addWidget(widgetId)
WidgetUtils.addWidget(widgetId);
}
function removeWidget(index) {
WidgetUtils.removeWidget(index)
WidgetUtils.removeWidget(index);
}
function toggleWidgetSize(index) {
WidgetUtils.toggleWidgetSize(index)
WidgetUtils.toggleWidgetSize(index);
}
function moveWidget(fromIndex, toIndex) {
WidgetUtils.moveWidget(fromIndex, toIndex)
WidgetUtils.moveWidget(fromIndex, toIndex);
}
function resetToDefault() {
WidgetUtils.resetToDefault()
WidgetUtils.resetToDefault();
}
function clearAll() {
WidgetUtils.clearAll()
WidgetUtils.clearAll();
}
}

View File

@@ -1144,6 +1144,8 @@ Item {
return controlCenterLoader.item;
}
parentScreen: barWindow.screen
screenName: barWindow.screen?.name || ""
screenModel: barWindow.screen?.model || ""
widgetData: parent.widgetData
Component.onCompleted: {

View File

@@ -10,9 +10,138 @@ BasePill {
property bool isActive: false
property var popoutTarget: null
property var widgetData: null
property string screenName: ""
property string screenModel: ""
property bool showNetworkIcon: SettingsData.controlCenterShowNetworkIcon
property bool showBluetoothIcon: SettingsData.controlCenterShowBluetoothIcon
property bool showAudioIcon: SettingsData.controlCenterShowAudioIcon
property bool showVpnIcon: SettingsData.controlCenterShowVpnIcon
property bool showBrightnessIcon: SettingsData.controlCenterShowBrightnessIcon
property bool showMicIcon: SettingsData.controlCenterShowMicIcon
property bool showBatteryIcon: SettingsData.controlCenterShowBatteryIcon
property bool showPrinterIcon: SettingsData.controlCenterShowPrinterIcon
function getNetworkIconName() {
if (NetworkService.wifiToggling)
return "sync";
switch (NetworkService.networkStatus) {
case "ethernet":
return "lan";
case "vpn":
return NetworkService.ethernetConnected ? "lan" : NetworkService.wifiSignalIcon;
default:
return NetworkService.wifiSignalIcon;
}
}
function getNetworkIconColor() {
if (NetworkService.wifiToggling)
return Theme.primary;
return NetworkService.networkStatus !== "disconnected" ? Theme.primary : Theme.outlineButton;
}
function getVolumeIconName() {
if (!AudioService.sink?.audio)
return "volume_up";
if (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0)
return "volume_off";
if (AudioService.sink.audio.volume * 100 < 33)
return "volume_down";
return "volume_up";
}
function getMicIconName() {
if (!AudioService.source?.audio)
return "mic";
if (AudioService.source.audio.muted || AudioService.source.audio.volume === 0)
return "mic_off";
return "mic";
}
function getMicIconColor() {
if (!AudioService.source?.audio)
return Theme.outlineButton;
if (AudioService.source.audio.muted || AudioService.source.audio.volume === 0)
return Theme.outlineButton;
return Theme.widgetIconColor;
}
function getBrightnessIconName() {
const deviceName = getPinnedBrightnessDevice();
if (!deviceName)
return "brightness_medium";
const level = DisplayService.getDeviceBrightness(deviceName);
if (level <= 33)
return "brightness_low";
if (level <= 66)
return "brightness_medium";
return "brightness_high";
}
function getScreenPinKey() {
if (SettingsData.displayNameMode === "model" && root.screenModel && root.screenModel.length > 0) {
return root.screenModel;
}
return root.screenName || "";
}
function getPinnedBrightnessDevice() {
const pinKey = getScreenPinKey();
if (!pinKey)
return "";
const pins = SettingsData.brightnessDevicePins || {};
return pins[pinKey] || "";
}
function hasPinnedBrightnessDevice() {
return getPinnedBrightnessDevice().length > 0;
}
function handleVolumeWheel(delta) {
if (!AudioService.sink?.audio)
return;
const currentVolume = AudioService.sink.audio.volume * 100;
const newVolume = delta > 0 ? Math.min(100, currentVolume + 5) : Math.max(0, currentVolume - 5);
AudioService.sink.audio.muted = false;
AudioService.sink.audio.volume = newVolume / 100;
AudioService.playVolumeChangeSoundIfEnabled();
}
function handleMicWheel(delta) {
if (!AudioService.source?.audio)
return;
const currentVolume = AudioService.source.audio.volume * 100;
const newVolume = delta > 0 ? Math.min(100, currentVolume + 5) : Math.max(0, currentVolume - 5);
AudioService.source.audio.muted = false;
AudioService.source.audio.volume = newVolume / 100;
}
function handleBrightnessWheel(delta) {
const deviceName = getPinnedBrightnessDevice();
if (!deviceName)
return;
const currentBrightness = DisplayService.getDeviceBrightness(deviceName);
const newBrightness = delta > 0 ? Math.min(100, currentBrightness + 5) : Math.max(1, currentBrightness - 5);
DisplayService.setBrightness(newBrightness, deviceName, false);
}
function getBatteryIconColor() {
if (!BatteryService.batteryAvailable)
return Theme.widgetIconColor;
if (BatteryService.isLowBattery && !BatteryService.isCharging)
return Theme.error;
if (BatteryService.isCharging || BatteryService.isPluggedIn)
return Theme.primary;
return Theme.widgetIconColor;
}
function hasPrintJobs() {
return CupsService.getTotalJobsNum() > 0;
}
function hasNoVisibleIcons() {
return !root.showNetworkIcon && !root.showBluetoothIcon && !root.showAudioIcon && !root.showVpnIcon && !root.showBrightnessIcon && !root.showMicIcon && !root.showBatteryIcon && !root.showPrinterIcon;
}
content: Component {
Item {
@@ -26,34 +155,21 @@ BasePill {
spacing: Theme.spacingXS
DankIcon {
name: {
if (NetworkService.wifiToggling) {
return "sync"
}
const status = NetworkService.networkStatus
if (status === "ethernet") {
return "lan"
}
if (status === "vpn") {
return NetworkService.ethernetConnected ? "lan" : NetworkService.wifiSignalIcon
}
return NetworkService.wifiSignalIcon
}
name: root.getNetworkIconName()
size: Theme.barIconSize(root.barThickness)
color: {
if (NetworkService.wifiToggling) {
return Theme.primary
}
return NetworkService.networkStatus !== "disconnected" ? Theme.primary : Theme.outlineButton
}
color: root.getNetworkIconColor()
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showNetworkIcon && NetworkService.networkAvailable
}
DankIcon {
name: "vpn_lock"
size: Theme.barIconSize(root.barThickness)
color: NetworkService.vpnConnected ? Theme.primary : Theme.outlineButton
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showVpnIcon && NetworkService.vpnAvailable && NetworkService.vpnConnected
}
DankIcon {
name: "bluetooth"
size: Theme.barIconSize(root.barThickness)
@@ -71,19 +187,7 @@ BasePill {
DankIcon {
id: audioIconV
name: {
if (AudioService.sink && AudioService.sink.audio) {
if (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0) {
return "volume_off"
} else if (AudioService.sink.audio.volume * 100 < 33) {
return "volume_down"
} else {
return "volume_up"
}
}
return "volume_up"
}
name: root.getVolumeIconName()
size: Theme.barIconSize(root.barThickness)
color: Theme.widgetIconColor
anchors.centerIn: parent
@@ -93,30 +197,84 @@ BasePill {
anchors.fill: parent
acceptedButtons: Qt.NoButton
onWheel: function (wheelEvent) {
let delta = wheelEvent.angleDelta.y
let currentVolume = (AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.volume * 100) || 0
let newVolume
if (delta > 0) {
newVolume = Math.min(100, currentVolume + 5)
} else {
newVolume = Math.max(0, currentVolume - 5)
}
if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.muted = false
AudioService.sink.audio.volume = newVolume / 100
AudioService.playVolumeChangeSoundIfEnabled()
}
wheelEvent.accepted = true
root.handleVolumeWheel(wheelEvent.angleDelta.y);
wheelEvent.accepted = true;
}
}
}
Rectangle {
width: micIconV.implicitWidth + 4
height: micIconV.implicitHeight + 4
color: "transparent"
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showMicIcon
DankIcon {
id: micIconV
name: root.getMicIconName()
size: Theme.barIconSize(root.barThickness)
color: root.getMicIconColor()
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
onWheel: function (wheelEvent) {
root.handleMicWheel(wheelEvent.angleDelta.y);
wheelEvent.accepted = true;
}
}
}
Rectangle {
width: brightnessIconV.implicitWidth + 4
height: brightnessIconV.implicitHeight + 4
color: "transparent"
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showBrightnessIcon && DisplayService.brightnessAvailable && root.hasPinnedBrightnessDevice()
DankIcon {
id: brightnessIconV
name: root.getBrightnessIconName()
size: Theme.barIconSize(root.barThickness)
color: Theme.widgetIconColor
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
onWheel: function (wheelEvent) {
root.handleBrightnessWheel(wheelEvent.angleDelta.y);
wheelEvent.accepted = true;
}
}
}
DankIcon {
name: Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable)
size: Theme.barIconSize(root.barThickness)
color: root.getBatteryIconColor()
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showBatteryIcon && BatteryService.batteryAvailable
}
DankIcon {
name: "print"
size: Theme.barIconSize(root.barThickness)
color: Theme.primary
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showPrinterIcon && CupsService.cupsAvailable && root.hasPrintJobs()
}
DankIcon {
name: "settings"
size: Theme.barIconSize(root.barThickness)
color: root.isActive ? Theme.primary : Theme.widgetIconColor
anchors.horizontalCenter: parent.horizontalCenter
visible: !root.showNetworkIcon && !root.showBluetoothIcon && !root.showAudioIcon
visible: root.hasNoVisibleIcons()
}
}
@@ -128,38 +286,24 @@ BasePill {
DankIcon {
id: networkIcon
name: {
if (NetworkService.wifiToggling) {
return "sync"
}
const status = NetworkService.networkStatus
if (status === "ethernet") {
return "lan"
}
if (status === "vpn") {
return NetworkService.ethernetConnected ? "lan" : NetworkService.wifiSignalIcon
}
return NetworkService.wifiSignalIcon
}
name: root.getNetworkIconName()
size: Theme.barIconSize(root.barThickness)
color: {
if (NetworkService.wifiToggling) {
return Theme.primary
}
return NetworkService.networkStatus !== "disconnected" ? Theme.primary : Theme.outlineButton
}
color: root.getNetworkIconColor()
anchors.verticalCenter: parent.verticalCenter
visible: root.showNetworkIcon && NetworkService.networkAvailable
}
DankIcon {
id: bluetoothIcon
id: vpnIcon
name: "vpn_lock"
size: Theme.barIconSize(root.barThickness)
color: NetworkService.vpnConnected ? Theme.primary : Theme.outlineButton
anchors.verticalCenter: parent.verticalCenter
visible: root.showVpnIcon && NetworkService.vpnAvailable && NetworkService.vpnConnected
}
DankIcon {
id: bluetoothIcon
name: "bluetooth"
size: Theme.barIconSize(root.barThickness)
color: BluetoothService.connected ? Theme.primary : Theme.outlineButton
@@ -176,19 +320,7 @@ BasePill {
DankIcon {
id: audioIcon
name: {
if (AudioService.sink && AudioService.sink.audio) {
if (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0) {
return "volume_off";
} else if (AudioService.sink.audio.volume * 100 < 33) {
return "volume_down";
} else {
return "volume_up";
}
}
return "volume_up";
}
name: root.getVolumeIconName()
size: Theme.barIconSize(root.barThickness)
color: Theme.widgetIconColor
anchors.centerIn: parent
@@ -196,34 +328,83 @@ BasePill {
MouseArea {
id: audioWheelArea
anchors.fill: parent
acceptedButtons: Qt.NoButton
onWheel: function (wheelEvent) {
let delta = wheelEvent.angleDelta.y;
let currentVolume = (AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.volume * 100) || 0;
let newVolume;
if (delta > 0) {
newVolume = Math.min(100, currentVolume + 5);
} else {
newVolume = Math.max(0, currentVolume - 5);
root.handleVolumeWheel(wheelEvent.angleDelta.y);
wheelEvent.accepted = true;
}
if (AudioService.sink && AudioService.sink.audio) {
AudioService.sink.audio.muted = false;
AudioService.sink.audio.volume = newVolume / 100;
AudioService.playVolumeChangeSoundIfEnabled();
}
}
Rectangle {
width: micIcon.implicitWidth + 4
height: micIcon.implicitHeight + 4
color: "transparent"
anchors.verticalCenter: parent.verticalCenter
visible: root.showMicIcon
DankIcon {
id: micIcon
name: root.getMicIconName()
size: Theme.barIconSize(root.barThickness)
color: root.getMicIconColor()
anchors.centerIn: parent
}
MouseArea {
id: micWheelArea
anchors.fill: parent
acceptedButtons: Qt.NoButton
onWheel: function (wheelEvent) {
root.handleMicWheel(wheelEvent.angleDelta.y);
wheelEvent.accepted = true;
}
}
}
Rectangle {
width: brightnessIcon.implicitWidth + 4
height: brightnessIcon.implicitHeight + 4
color: "transparent"
anchors.verticalCenter: parent.verticalCenter
visible: root.showBrightnessIcon && DisplayService.brightnessAvailable && root.hasPinnedBrightnessDevice()
DankIcon {
id: brightnessIcon
name: root.getBrightnessIconName()
size: Theme.barIconSize(root.barThickness)
color: Theme.widgetIconColor
anchors.centerIn: parent
}
MouseArea {
id: brightnessWheelArea
anchors.fill: parent
acceptedButtons: Qt.NoButton
onWheel: function (wheelEvent) {
root.handleBrightnessWheel(wheelEvent.angleDelta.y);
wheelEvent.accepted = true;
}
}
}
DankIcon {
name: "mic"
id: batteryIcon
name: Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable)
size: Theme.barIconSize(root.barThickness)
color: root.getBatteryIconColor()
anchors.verticalCenter: parent.verticalCenter
visible: root.showBatteryIcon && BatteryService.batteryAvailable
}
DankIcon {
id: printerIcon
name: "print"
size: Theme.barIconSize(root.barThickness)
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
visible: false
visible: root.showPrinterIcon && CupsService.cupsAvailable && root.hasPrintJobs()
}
DankIcon {
@@ -231,8 +412,14 @@ BasePill {
size: Theme.barIconSize(root.barThickness)
color: root.isActive ? Theme.primary : Theme.widgetIconColor
anchors.verticalCenter: parent.verticalCenter
visible: !root.showNetworkIcon && !root.showBluetoothIcon && !root.showAudioIcon
}
visible: root.hasNoVisibleIcons()
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.NoButton
}
}
}

View File

@@ -7,6 +7,10 @@ DankOSD {
id: root
readonly property bool useVertical: isVerticalLayout
property int targetBrightness: {
DisplayService.brightnessVersion;
return DisplayService.brightnessLevel;
}
osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2)
osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2)
@@ -17,7 +21,7 @@ DankOSD {
target: DisplayService
function onBrightnessChanged(showOsd) {
if (showOsd && SettingsData.osdBrightnessEnabled) {
root.show()
root.show();
}
}
}
@@ -48,13 +52,13 @@ DankOSD {
DankIcon {
anchors.centerIn: parent
name: {
const deviceInfo = DisplayService.getCurrentDeviceInfo()
const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") {
return "brightness_medium"
return "brightness_medium";
} else if (deviceInfo.name.includes("kbd")) {
return "keyboard"
return "keyboard";
} else {
return "lightbulb"
return "lightbulb";
}
}
size: Theme.iconSize
@@ -70,74 +74,50 @@ DankOSD {
x: parent.gap * 2 + Theme.iconSize
anchors.verticalCenter: parent.verticalCenter
minimum: {
const deviceInfo = DisplayService.getCurrentDeviceInfo()
if (!deviceInfo) return 1
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id)
const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo)
return 1;
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id);
if (isExponential) {
return 1
return 1;
}
return (deviceInfo.class === "backlight" || deviceInfo.class === "ddc") ? 1 : 0
return (deviceInfo.class === "backlight" || deviceInfo.class === "ddc") ? 1 : 0;
}
maximum: {
const deviceInfo = DisplayService.getCurrentDeviceInfo()
if (!deviceInfo) return 100
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id)
const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo)
return 100;
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id);
if (isExponential) {
return 100
return 100;
}
return deviceInfo.displayMax || 100
return deviceInfo.displayMax || 100;
}
enabled: DisplayService.brightnessAvailable
showValue: true
unit: {
const deviceInfo = DisplayService.getCurrentDeviceInfo()
if (!deviceInfo) return "%"
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id)
const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo)
return "%";
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id);
if (isExponential) {
return "%"
return "%";
}
return deviceInfo.class === "ddc" ? "" : "%"
return deviceInfo.class === "ddc" ? "" : "%";
}
thumbOutlineColor: Theme.surfaceContainer
alwaysShowValue: SettingsData.osdAlwaysShowValue
Component.onCompleted: {
if (DisplayService.brightnessAvailable) {
value = DisplayService.brightnessLevel
}
}
value: !isDragging ? root.targetBrightness : value
onSliderValueChanged: newValue => {
if (DisplayService.brightnessAvailable) {
DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true)
resetHideTimer()
DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true);
resetHideTimer();
}
}
onContainsMouseChanged: {
setChildHovered(containsMouse)
}
onSliderDragFinished: finalValue => {
if (DisplayService.brightnessAvailable) {
DisplayService.setBrightness(finalValue, DisplayService.lastIpcDevice, true)
}
}
Connections {
target: DisplayService
function onBrightnessChanged(showOsd) {
if (!brightnessSlider.pressed && brightnessSlider.value !== DisplayService.brightnessLevel) {
brightnessSlider.value = DisplayService.brightnessLevel
}
}
function onDeviceSwitched() {
if (!brightnessSlider.pressed && brightnessSlider.value !== DisplayService.brightnessLevel) {
brightnessSlider.value = DisplayService.brightnessLevel
}
}
setChildHovered(containsMouse);
}
}
}
@@ -161,13 +141,13 @@ DankOSD {
DankIcon {
anchors.centerIn: parent
name: {
const deviceInfo = DisplayService.getCurrentDeviceInfo()
const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") {
return "brightness_medium"
return "brightness_medium";
} else if (deviceInfo.name.includes("kbd")) {
return "keyboard"
return "keyboard";
} else {
return "lightbulb"
return "lightbulb";
}
}
size: Theme.iconSize
@@ -183,22 +163,26 @@ DankOSD {
y: gap * 2 + Theme.iconSize
property bool dragging: false
property int value: DisplayService.brightnessAvailable ? DisplayService.brightnessLevel : 0
property int value: !dragging ? root.targetBrightness : value
readonly property int minimum: {
const deviceInfo = DisplayService.getCurrentDeviceInfo()
if (!deviceInfo) return 1
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id)
if (isExponential) return 1
return (deviceInfo.class === "backlight" || deviceInfo.class === "ddc") ? 1 : 0
const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo)
return 1;
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id);
if (isExponential)
return 1;
return (deviceInfo.class === "backlight" || deviceInfo.class === "ddc") ? 1 : 0;
}
readonly property int maximum: {
const deviceInfo = DisplayService.getCurrentDeviceInfo()
if (!deviceInfo) return 100
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id)
if (isExponential) return 100
return deviceInfo.displayMax || 100
const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo)
return 100;
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id);
if (isExponential)
return 100;
return deviceInfo.displayMax || 100;
}
Rectangle {
@@ -214,8 +198,8 @@ DankOSD {
id: vertFill
width: parent.width
height: {
const ratio = (vertSlider.value - vertSlider.minimum) / (vertSlider.maximum - vertSlider.minimum)
return ratio * parent.height
const ratio = (vertSlider.value - vertSlider.minimum) / (vertSlider.maximum - vertSlider.minimum);
return ratio * parent.height;
}
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
@@ -229,9 +213,9 @@ DankOSD {
height: 8
radius: Theme.cornerRadius
y: {
const ratio = (vertSlider.value - vertSlider.minimum) / (vertSlider.maximum - vertSlider.minimum)
const travel = parent.height - height
return Math.max(0, Math.min(travel, travel * (1 - ratio)))
const ratio = (vertSlider.value - vertSlider.minimum) / (vertSlider.maximum - vertSlider.minimum);
const travel = parent.height - height;
return Math.max(0, Math.min(travel, travel * (1 - ratio)));
}
anchors.horizontalCenter: parent.horizontalCenter
color: Theme.primary
@@ -248,50 +232,34 @@ DankOSD {
cursorShape: Qt.PointingHandCursor
onContainsMouseChanged: {
setChildHovered(containsMouse)
setChildHovered(containsMouse);
}
onPressed: mouse => {
vertSlider.dragging = true
updateBrightness(mouse)
vertSlider.dragging = true;
updateBrightness(mouse);
}
onReleased: {
vertSlider.dragging = false
vertSlider.dragging = false;
}
onPositionChanged: mouse => {
if (pressed) {
updateBrightness(mouse)
updateBrightness(mouse);
}
}
onClicked: mouse => {
updateBrightness(mouse)
updateBrightness(mouse);
}
function updateBrightness(mouse) {
if (DisplayService.brightnessAvailable) {
const ratio = 1.0 - (mouse.y / height)
const newValue = Math.round(vertSlider.minimum + ratio * (vertSlider.maximum - vertSlider.minimum))
DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true)
resetHideTimer()
}
}
}
Connections {
target: DisplayService
function onBrightnessChanged(showOsd) {
if (!vertSlider.dragging && vertSlider.value !== DisplayService.brightnessLevel) {
vertSlider.value = DisplayService.brightnessLevel
}
}
function onDeviceSwitched() {
if (!vertSlider.dragging && vertSlider.value !== DisplayService.brightnessLevel) {
vertSlider.value = DisplayService.brightnessLevel
const ratio = 1.0 - (mouse.y / height);
const newValue = Math.round(vertSlider.minimum + ratio * (vertSlider.maximum - vertSlider.minimum));
DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true);
resetHideTimer();
}
}
}
@@ -302,10 +270,10 @@ DankOSD {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottomMargin: gap
text: {
const deviceInfo = DisplayService.getCurrentDeviceInfo()
const isExponential = deviceInfo ? SessionData.getBrightnessExponential(deviceInfo.id) : false
const unit = (deviceInfo && deviceInfo.class === "ddc" && !isExponential) ? "" : "%"
return vertSlider.value + unit
const deviceInfo = DisplayService.getCurrentDeviceInfo();
const isExponential = deviceInfo ? SessionData.getBrightnessExponential(deviceInfo.id) : false;
const unit = (deviceInfo && deviceInfo.class === "ddc" && !isExponential) ? "" : "%";
return vertSlider.value + unit;
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText

View File

@@ -784,13 +784,31 @@ Item {
}
function handleControlCenterSettingChanged(sectionId, widgetIndex, settingName, value) {
// Control Center settings are global, not per-widget instance
if (settingName === "showNetworkIcon") {
SettingsData.set("controlCenterShowNetworkIcon", value);
} else if (settingName === "showBluetoothIcon") {
SettingsData.set("controlCenterShowBluetoothIcon", value);
} else if (settingName === "showAudioIcon") {
SettingsData.set("controlCenterShowAudioIcon", value);
switch (settingName) {
case "showNetworkIcon":
SettingsData.set("controlCenterShowNetworkIcon", value)
break
case "showBluetoothIcon":
SettingsData.set("controlCenterShowBluetoothIcon", value)
break
case "showAudioIcon":
SettingsData.set("controlCenterShowAudioIcon", value)
break
case "showVpnIcon":
SettingsData.set("controlCenterShowVpnIcon", value)
break
case "showBrightnessIcon":
SettingsData.set("controlCenterShowBrightnessIcon", value)
break
case "showMicIcon":
SettingsData.set("controlCenterShowMicIcon", value)
break
case "showBatteryIcon":
SettingsData.set("controlCenterShowBatteryIcon", value)
break
case "showPrinterIcon":
SettingsData.set("controlCenterShowPrinterIcon", value)
break
}
}

View File

@@ -497,39 +497,69 @@ Column {
}
DankActionButton {
id: ccMenuButton
visible: modelData.id === "controlCenterButton"
buttonSize: 32
iconName: "more_vert"
iconSize: 18
iconColor: Theme.outline
onClicked: {
console.log("Control Center three-dot button clicked for widget:", modelData.id);
controlCenterContextMenu.widgetData = modelData;
controlCenterContextMenu.sectionId = root.sectionId;
controlCenterContextMenu.widgetIndex = index;
// Position relative to the action buttons row, not the specific button
var parentPos = parent.mapToItem(root, 0, 0);
controlCenterContextMenu.x = parentPos.x - 210; // Position to the left with margin
controlCenterContextMenu.y = parentPos.y - 10; // Slightly above
var buttonPos = ccMenuButton.mapToItem(root, 0, 0);
var popupWidth = controlCenterContextMenu.width;
var popupHeight = controlCenterContextMenu.height;
var xPos = buttonPos.x - popupWidth - Theme.spacingS;
if (xPos < 0) {
xPos = buttonPos.x + ccMenuButton.width + Theme.spacingS;
}
var yPos = buttonPos.y - popupHeight / 2 + ccMenuButton.height / 2;
if (yPos < 0) {
yPos = Theme.spacingS;
} else if (yPos + popupHeight > root.height) {
yPos = root.height - popupHeight - Theme.spacingS;
}
controlCenterContextMenu.x = xPos;
controlCenterContextMenu.y = yPos;
controlCenterContextMenu.open();
}
}
DankActionButton {
id: privacyMenuButton
visible: modelData.id === "privacyIndicator"
buttonSize: 32
iconName: "more_vert"
iconSize: 18
iconColor: Theme.outline
onClicked: {
console.log("Privacy three-dot button clicked for widget:", modelData.id);
privacyContextMenu.widgetData = modelData;
privacyContextMenu.sectionId = root.sectionId;
privacyContextMenu.widgetIndex = index;
// Position relative to the action buttons row, not the specific button
var parentPos = parent.mapToItem(root, 0, 0);
privacyContextMenu.x = parentPos.x - 210; // Position to the left with margin
privacyContextMenu.y = parentPos.y - 10; // Slightly above
var buttonPos = privacyMenuButton.mapToItem(root, 0, 0);
var popupWidth = privacyContextMenu.width;
var popupHeight = privacyContextMenu.height;
var xPos = buttonPos.x - popupWidth - Theme.spacingS;
if (xPos < 0) {
xPos = buttonPos.x + privacyMenuButton.width + Theme.spacingS;
}
var yPos = buttonPos.y - popupHeight / 2 + privacyMenuButton.height / 2;
if (yPos < 0) {
yPos = Theme.spacingS;
} else if (yPos + popupHeight > root.height) {
yPos = root.height - popupHeight - Theme.spacingS;
}
privacyContextMenu.x = xPos;
privacyContextMenu.y = yPos;
privacyContextMenu.open();
}
}
@@ -699,21 +729,13 @@ Column {
property string sectionId: ""
property int widgetIndex: -1
width: 200
height: 120
width: 220
height: menuColumn.implicitHeight + Theme.spacingS * 2
padding: 0
modal: true
focus: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
onOpened: {
console.log("Control Center context menu opened");
}
onClosed: {
console.log("Control Center context menu closed");
}
background: Rectangle {
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
radius: Theme.cornerRadius
@@ -722,124 +744,72 @@ Column {
}
contentItem: Item {
Column {
id: menuColumn
anchors.fill: parent
anchors.margins: Theme.spacingS
spacing: 2
Rectangle {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: networkToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: "lan"
size: 16
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Network Icon")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Normal
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
id: networkToggle
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
width: 40
height: 20
Repeater {
model: [
{
icon: "lan",
label: I18n.tr("Network"),
setting: "showNetworkIcon",
checked: SettingsData.controlCenterShowNetworkIcon
onToggled: {
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showNetworkIcon", toggled);
}
}
MouseArea {
id: networkToggleArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
networkToggle.checked = !networkToggle.checked;
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showNetworkIcon", networkToggle.checked);
}
}
}
Rectangle {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: bluetoothToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: "bluetooth"
size: 16
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Bluetooth Icon")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Normal
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
id: bluetoothToggle
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
width: 40
height: 20
},
{
icon: "vpn_lock",
label: I18n.tr("VPN"),
setting: "showVpnIcon",
checked: SettingsData.controlCenterShowVpnIcon
},
{
icon: "bluetooth",
label: I18n.tr("Bluetooth"),
setting: "showBluetoothIcon",
checked: SettingsData.controlCenterShowBluetoothIcon
onToggled: {
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showBluetoothIcon", toggled);
}
},
{
icon: "volume_up",
label: I18n.tr("Audio"),
setting: "showAudioIcon",
checked: SettingsData.controlCenterShowAudioIcon
},
{
icon: "mic",
label: I18n.tr("Microphone"),
setting: "showMicIcon",
checked: SettingsData.controlCenterShowMicIcon
},
{
icon: "brightness_high",
label: I18n.tr("Brightness"),
setting: "showBrightnessIcon",
checked: SettingsData.controlCenterShowBrightnessIcon
},
{
icon: "battery_full",
label: I18n.tr("Battery"),
setting: "showBatteryIcon",
checked: SettingsData.controlCenterShowBatteryIcon
},
{
icon: "print",
label: I18n.tr("Printer"),
setting: "showPrinterIcon",
checked: SettingsData.controlCenterShowPrinterIcon
}
]
MouseArea {
id: bluetoothToggleArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
bluetoothToggle.checked = !bluetoothToggle.checked;
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showBluetoothIcon", bluetoothToggle.checked);
}
}
}
delegate: Rectangle {
required property var modelData
required property int index
Rectangle {
width: parent.width
width: menuColumn.width
height: 32
radius: Theme.cornerRadius
color: audioToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
color: toggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Row {
anchors.left: parent.left
@@ -848,14 +818,14 @@ Column {
spacing: Theme.spacingS
DankIcon {
name: "volume_up"
name: modelData.icon
size: 16
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Audio Icon")
text: modelData.label
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Normal
@@ -864,26 +834,27 @@ Column {
}
DankToggle {
id: audioToggle
id: toggle
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
width: 40
height: 20
checked: SettingsData.controlCenterShowAudioIcon
checked: modelData.checked
onToggled: {
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showAudioIcon", toggled);
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, modelData.setting, toggled);
}
}
MouseArea {
id: audioToggleArea
id: toggleArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onPressed: {
audioToggle.checked = !audioToggle.checked;
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showAudioIcon", audioToggle.checked);
toggle.checked = !toggle.checked;
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, modelData.setting, toggle.checked);
}
}
}
}
@@ -932,7 +903,7 @@ Column {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: networkToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
color: "transparent"
Row {
anchors.left: parent.left
@@ -954,7 +925,7 @@ Column {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: networkToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
color: micToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Row {
anchors.left: parent.left
@@ -1006,7 +977,7 @@ Column {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: networkToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
color: cameraToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Row {
anchors.left: parent.left
@@ -1058,7 +1029,7 @@ Column {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: networkToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
color: screenshareToggleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Row {
anchors.left: parent.left

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,8 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Common
Singleton {
id: root
@@ -70,6 +67,14 @@ Singleton {
property bool subscriptionConnected: activeService?.subscriptionConnected ?? false
property var vpnProfiles: activeService?.vpnProfiles ?? []
property var vpnActive: activeService?.vpnActive ?? []
property bool vpnAvailable: activeService?.vpnAvailable ?? false
property bool vpnIsBusy: activeService?.vpnIsBusy ?? false
property bool vpnConnected: activeService?.vpnConnected ?? false
property string vpnActiveUuid: activeService?.activeUuid ?? ""
property string vpnActiveName: activeService?.activeName ?? ""
property string credentialsToken: activeService?.credentialsToken ?? ""
property string credentialsSSID: activeService?.credentialsSSID ?? ""
property string credentialsSetting: activeService?.credentialsSetting ?? ""
@@ -88,12 +93,12 @@ Singleton {
readonly property string socketPath: Quickshell.env("DMS_SOCKET")
Component.onCompleted: {
console.info("NetworkService: Initializing...")
console.info("NetworkService: Initializing...");
if (!socketPath || socketPath.length === 0) {
console.info("NetworkService: DMS_SOCKET not set, using LegacyNetworkService")
useLegacyService()
console.info("NetworkService: DMS_SOCKET not set, using LegacyNetworkService");
useLegacyService();
} else {
console.log("NetworkService: DMS_SOCKET found, waiting for capabilities...")
console.log("NetworkService: DMS_SOCKET found, waiting for capabilities...");
}
}
@@ -102,191 +107,191 @@ Singleton {
function onNetworkAvailableChanged() {
if (!activeService && DMSNetworkService.networkAvailable) {
console.info("NetworkService: Network capability detected, using DMSNetworkService")
activeService = DMSNetworkService
usingLegacy = false
console.info("NetworkService: Switched to DMSNetworkService, networkAvailable:", networkAvailable)
connectSignals()
console.info("NetworkService: Network capability detected, using DMSNetworkService");
activeService = DMSNetworkService;
usingLegacy = false;
console.info("NetworkService: Switched to DMSNetworkService, networkAvailable:", networkAvailable);
connectSignals();
} else if (!activeService && !DMSNetworkService.networkAvailable && socketPath && socketPath.length > 0) {
console.info("NetworkService: Network capability not available in DMS, using LegacyNetworkService")
useLegacyService()
console.info("NetworkService: Network capability not available in DMS, using LegacyNetworkService");
useLegacyService();
}
}
}
function useLegacyService() {
activeService = LegacyNetworkService
usingLegacy = true
console.info("NetworkService: Switched to LegacyNetworkService, networkAvailable:", networkAvailable)
activeService = LegacyNetworkService;
usingLegacy = true;
console.info("NetworkService: Switched to LegacyNetworkService, networkAvailable:", networkAvailable);
if (LegacyNetworkService.activate) {
LegacyNetworkService.activate()
LegacyNetworkService.activate();
}
connectSignals()
connectSignals();
}
function connectSignals() {
if (activeService) {
if (activeService.networksUpdated) {
activeService.networksUpdated.connect(root.networksUpdated)
activeService.networksUpdated.connect(root.networksUpdated);
}
if (activeService.connectionChanged) {
activeService.connectionChanged.connect(root.connectionChanged)
activeService.connectionChanged.connect(root.connectionChanged);
}
if (activeService.credentialsNeeded) {
activeService.credentialsNeeded.connect(root.credentialsNeeded)
activeService.credentialsNeeded.connect(root.credentialsNeeded);
}
}
}
function addRef() {
if (activeService && activeService.addRef) {
activeService.addRef()
activeService.addRef();
}
}
function removeRef() {
if (activeService && activeService.removeRef) {
activeService.removeRef()
activeService.removeRef();
}
}
function getState() {
if (activeService && activeService.getState) {
activeService.getState()
activeService.getState();
}
}
function scanWifi() {
if (activeService && activeService.scanWifi) {
activeService.scanWifi()
activeService.scanWifi();
}
}
function scanWifiNetworks() {
if (activeService && activeService.scanWifiNetworks) {
activeService.scanWifiNetworks()
activeService.scanWifiNetworks();
}
}
function connectToWifi(ssid, password = "", username = "", anonymousIdentity = "", domainSuffixMatch = "") {
if (activeService && activeService.connectToWifi) {
activeService.connectToWifi(ssid, password, username, anonymousIdentity, domainSuffixMatch)
activeService.connectToWifi(ssid, password, username, anonymousIdentity, domainSuffixMatch);
}
}
function disconnectWifi() {
if (activeService && activeService.disconnectWifi) {
activeService.disconnectWifi()
activeService.disconnectWifi();
}
}
function forgetWifiNetwork(ssid) {
if (activeService && activeService.forgetWifiNetwork) {
activeService.forgetWifiNetwork(ssid)
activeService.forgetWifiNetwork(ssid);
}
}
function toggleWifiRadio() {
if (activeService && activeService.toggleWifiRadio) {
activeService.toggleWifiRadio()
activeService.toggleWifiRadio();
}
}
function enableWifiDevice() {
if (activeService && activeService.enableWifiDevice) {
activeService.enableWifiDevice()
activeService.enableWifiDevice();
}
}
function setNetworkPreference(preference) {
if (activeService && activeService.setNetworkPreference) {
activeService.setNetworkPreference(preference)
activeService.setNetworkPreference(preference);
}
}
function setConnectionPriority(type) {
if (activeService && activeService.setConnectionPriority) {
activeService.setConnectionPriority(type)
activeService.setConnectionPriority(type);
}
}
function connectToWifiAndSetPreference(ssid, password, username = "", anonymousIdentity = "", domainSuffixMatch = "") {
if (activeService && activeService.connectToWifiAndSetPreference) {
activeService.connectToWifiAndSetPreference(ssid, password, username, anonymousIdentity, domainSuffixMatch)
activeService.connectToWifiAndSetPreference(ssid, password, username, anonymousIdentity, domainSuffixMatch);
}
}
function toggleNetworkConnection(type) {
if (activeService && activeService.toggleNetworkConnection) {
activeService.toggleNetworkConnection(type)
activeService.toggleNetworkConnection(type);
}
}
function startAutoScan() {
if (activeService && activeService.startAutoScan) {
activeService.startAutoScan()
activeService.startAutoScan();
}
}
function stopAutoScan() {
if (activeService && activeService.stopAutoScan) {
activeService.stopAutoScan()
activeService.stopAutoScan();
}
}
function fetchNetworkInfo(ssid) {
if (activeService && activeService.fetchNetworkInfo) {
activeService.fetchNetworkInfo(ssid)
activeService.fetchNetworkInfo(ssid);
}
}
function fetchWiredNetworkInfo(uuid) {
if (activeService && activeService.fetchWiredNetworkInfo) {
activeService.fetchWiredNetworkInfo(uuid)
activeService.fetchWiredNetworkInfo(uuid);
}
}
function getNetworkInfo(ssid) {
if (activeService && activeService.getNetworkInfo) {
return activeService.getNetworkInfo(ssid)
return activeService.getNetworkInfo(ssid);
}
return null
return null;
}
function getWiredNetworkInfo(uuid) {
if (activeService && activeService.getWiredNetworkInfo) {
return activeService.getWiredNetworkInfo(uuid)
return activeService.getWiredNetworkInfo(uuid);
}
return null
return null;
}
function refreshNetworkState() {
if (activeService && activeService.refreshNetworkState) {
activeService.refreshNetworkState()
activeService.refreshNetworkState();
}
}
function connectToSpecificWiredConfig(uuid) {
if (activeService && activeService.connectToSpecificWiredConfig) {
activeService.connectToSpecificWiredConfig(uuid)
activeService.connectToSpecificWiredConfig(uuid);
}
}
function submitCredentials(token, secrets, save) {
if (activeService && activeService.submitCredentials) {
activeService.submitCredentials(token, secrets, save)
activeService.submitCredentials(token, secrets, save);
}
}
function cancelCredentials(token) {
if (activeService && activeService.cancelCredentials) {
activeService.cancelCredentials(token)
activeService.cancelCredentials(token);
}
}
function setWifiAutoconnect(ssid, autoconnect) {
if (activeService && activeService.setWifiAutoconnect) {
activeService.setWifiAutoconnect(ssid, autoconnect)
activeService.setWifiAutoconnect(ssid, autoconnect);
}
}
}