1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-03 20:32:07 -04: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 controlCenterShowNetworkIcon: true
property bool controlCenterShowBluetoothIcon: true property bool controlCenterShowBluetoothIcon: true
property bool controlCenterShowAudioIcon: 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 showPrivacyButton: true
property bool privacyShowMicIcon: false property bool privacyShowMicIcon: false
property bool privacyShowCameraIcon: false property bool privacyShowCameraIcon: false

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -10,9 +10,138 @@ BasePill {
property bool isActive: false property bool isActive: false
property var popoutTarget: null property var popoutTarget: null
property var widgetData: null property var widgetData: null
property string screenName: ""
property string screenModel: ""
property bool showNetworkIcon: SettingsData.controlCenterShowNetworkIcon property bool showNetworkIcon: SettingsData.controlCenterShowNetworkIcon
property bool showBluetoothIcon: SettingsData.controlCenterShowBluetoothIcon property bool showBluetoothIcon: SettingsData.controlCenterShowBluetoothIcon
property bool showAudioIcon: SettingsData.controlCenterShowAudioIcon 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 { content: Component {
Item { Item {
@@ -26,34 +155,21 @@ BasePill {
spacing: Theme.spacingXS spacing: Theme.spacingXS
DankIcon { DankIcon {
name: { name: root.getNetworkIconName()
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
}
size: Theme.barIconSize(root.barThickness) size: Theme.barIconSize(root.barThickness)
color: { color: root.getNetworkIconColor()
if (NetworkService.wifiToggling) {
return Theme.primary
}
return NetworkService.networkStatus !== "disconnected" ? Theme.primary : Theme.outlineButton
}
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
visible: root.showNetworkIcon && NetworkService.networkAvailable 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 { DankIcon {
name: "bluetooth" name: "bluetooth"
size: Theme.barIconSize(root.barThickness) size: Theme.barIconSize(root.barThickness)
@@ -71,19 +187,7 @@ BasePill {
DankIcon { DankIcon {
id: audioIconV id: audioIconV
name: root.getVolumeIconName()
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"
}
size: Theme.barIconSize(root.barThickness) size: Theme.barIconSize(root.barThickness)
color: Theme.widgetIconColor color: Theme.widgetIconColor
anchors.centerIn: parent anchors.centerIn: parent
@@ -93,30 +197,84 @@ BasePill {
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
onWheel: function (wheelEvent) { onWheel: function (wheelEvent) {
let delta = wheelEvent.angleDelta.y root.handleVolumeWheel(wheelEvent.angleDelta.y);
let currentVolume = (AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.volume * 100) || 0 wheelEvent.accepted = true;
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
} }
} }
} }
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 { DankIcon {
name: "settings" name: "settings"
size: Theme.barIconSize(root.barThickness) size: Theme.barIconSize(root.barThickness)
color: root.isActive ? Theme.primary : Theme.widgetIconColor color: root.isActive ? Theme.primary : Theme.widgetIconColor
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
visible: !root.showNetworkIcon && !root.showBluetoothIcon && !root.showAudioIcon visible: root.hasNoVisibleIcons()
} }
} }
@@ -128,38 +286,24 @@ BasePill {
DankIcon { DankIcon {
id: networkIcon id: networkIcon
name: root.getNetworkIconName()
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
}
size: Theme.barIconSize(root.barThickness) size: Theme.barIconSize(root.barThickness)
color: { color: root.getNetworkIconColor()
if (NetworkService.wifiToggling) {
return Theme.primary
}
return NetworkService.networkStatus !== "disconnected" ? Theme.primary : Theme.outlineButton
}
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: root.showNetworkIcon && NetworkService.networkAvailable visible: root.showNetworkIcon && NetworkService.networkAvailable
} }
DankIcon { 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" name: "bluetooth"
size: Theme.barIconSize(root.barThickness) size: Theme.barIconSize(root.barThickness)
color: BluetoothService.connected ? Theme.primary : Theme.outlineButton color: BluetoothService.connected ? Theme.primary : Theme.outlineButton
@@ -176,19 +320,7 @@ BasePill {
DankIcon { DankIcon {
id: audioIcon id: audioIcon
name: root.getVolumeIconName()
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";
}
size: Theme.barIconSize(root.barThickness) size: Theme.barIconSize(root.barThickness)
color: Theme.widgetIconColor color: Theme.widgetIconColor
anchors.centerIn: parent anchors.centerIn: parent
@@ -196,34 +328,83 @@ BasePill {
MouseArea { MouseArea {
id: audioWheelArea id: audioWheelArea
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.NoButton acceptedButtons: Qt.NoButton
onWheel: function (wheelEvent) { onWheel: function (wheelEvent) {
let delta = wheelEvent.angleDelta.y; root.handleVolumeWheel(wheelEvent.angleDelta.y);
let currentVolume = (AudioService.sink && AudioService.sink.audio && AudioService.sink.audio.volume * 100) || 0; wheelEvent.accepted = true;
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();
} }
}
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; wheelEvent.accepted = true;
} }
} }
} }
DankIcon { 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) size: Theme.barIconSize(root.barThickness)
color: Theme.primary color: Theme.primary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: false visible: root.showPrinterIcon && CupsService.cupsAvailable && root.hasPrintJobs()
} }
DankIcon { DankIcon {
@@ -231,8 +412,14 @@ BasePill {
size: Theme.barIconSize(root.barThickness) size: Theme.barIconSize(root.barThickness)
color: root.isActive ? Theme.primary : Theme.widgetIconColor color: root.isActive ? Theme.primary : Theme.widgetIconColor
anchors.verticalCenter: parent.verticalCenter 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 id: root
readonly property bool useVertical: isVerticalLayout 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) 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) osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2)
@@ -17,7 +21,7 @@ DankOSD {
target: DisplayService target: DisplayService
function onBrightnessChanged(showOsd) { function onBrightnessChanged(showOsd) {
if (showOsd && SettingsData.osdBrightnessEnabled) { if (showOsd && SettingsData.osdBrightnessEnabled) {
root.show() root.show();
} }
} }
} }
@@ -48,13 +52,13 @@ DankOSD {
DankIcon { DankIcon {
anchors.centerIn: parent anchors.centerIn: parent
name: { name: {
const deviceInfo = DisplayService.getCurrentDeviceInfo() const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") { if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") {
return "brightness_medium" return "brightness_medium";
} else if (deviceInfo.name.includes("kbd")) { } else if (deviceInfo.name.includes("kbd")) {
return "keyboard" return "keyboard";
} else { } else {
return "lightbulb" return "lightbulb";
} }
} }
size: Theme.iconSize size: Theme.iconSize
@@ -70,74 +74,50 @@ DankOSD {
x: parent.gap * 2 + Theme.iconSize x: parent.gap * 2 + Theme.iconSize
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
minimum: { minimum: {
const deviceInfo = DisplayService.getCurrentDeviceInfo() const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo) return 1 if (!deviceInfo)
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id) return 1;
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id);
if (isExponential) { 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: { maximum: {
const deviceInfo = DisplayService.getCurrentDeviceInfo() const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo) return 100 if (!deviceInfo)
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id) return 100;
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id);
if (isExponential) { if (isExponential) {
return 100 return 100;
} }
return deviceInfo.displayMax || 100 return deviceInfo.displayMax || 100;
} }
enabled: DisplayService.brightnessAvailable enabled: DisplayService.brightnessAvailable
showValue: true showValue: true
unit: { unit: {
const deviceInfo = DisplayService.getCurrentDeviceInfo() const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo) return "%" if (!deviceInfo)
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id) return "%";
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id);
if (isExponential) { if (isExponential) {
return "%" return "%";
} }
return deviceInfo.class === "ddc" ? "" : "%" return deviceInfo.class === "ddc" ? "" : "%";
} }
thumbOutlineColor: Theme.surfaceContainer thumbOutlineColor: Theme.surfaceContainer
alwaysShowValue: SettingsData.osdAlwaysShowValue alwaysShowValue: SettingsData.osdAlwaysShowValue
value: !isDragging ? root.targetBrightness : value
Component.onCompleted: {
if (DisplayService.brightnessAvailable) {
value = DisplayService.brightnessLevel
}
}
onSliderValueChanged: newValue => { onSliderValueChanged: newValue => {
if (DisplayService.brightnessAvailable) { if (DisplayService.brightnessAvailable) {
DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true) DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true);
resetHideTimer() resetHideTimer();
} }
} }
onContainsMouseChanged: { onContainsMouseChanged: {
setChildHovered(containsMouse) 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
}
}
} }
} }
} }
@@ -161,13 +141,13 @@ DankOSD {
DankIcon { DankIcon {
anchors.centerIn: parent anchors.centerIn: parent
name: { name: {
const deviceInfo = DisplayService.getCurrentDeviceInfo() const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") { if (!deviceInfo || deviceInfo.class === "backlight" || deviceInfo.class === "ddc") {
return "brightness_medium" return "brightness_medium";
} else if (deviceInfo.name.includes("kbd")) { } else if (deviceInfo.name.includes("kbd")) {
return "keyboard" return "keyboard";
} else { } else {
return "lightbulb" return "lightbulb";
} }
} }
size: Theme.iconSize size: Theme.iconSize
@@ -183,22 +163,26 @@ DankOSD {
y: gap * 2 + Theme.iconSize y: gap * 2 + Theme.iconSize
property bool dragging: false property bool dragging: false
property int value: DisplayService.brightnessAvailable ? DisplayService.brightnessLevel : 0 property int value: !dragging ? root.targetBrightness : value
readonly property int minimum: { readonly property int minimum: {
const deviceInfo = DisplayService.getCurrentDeviceInfo() const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo) return 1 if (!deviceInfo)
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id) return 1;
if (isExponential) return 1 const isExponential = SessionData.getBrightnessExponential(deviceInfo.id);
return (deviceInfo.class === "backlight" || deviceInfo.class === "ddc") ? 1 : 0 if (isExponential)
return 1;
return (deviceInfo.class === "backlight" || deviceInfo.class === "ddc") ? 1 : 0;
} }
readonly property int maximum: { readonly property int maximum: {
const deviceInfo = DisplayService.getCurrentDeviceInfo() const deviceInfo = DisplayService.getCurrentDeviceInfo();
if (!deviceInfo) return 100 if (!deviceInfo)
const isExponential = SessionData.getBrightnessExponential(deviceInfo.id) return 100;
if (isExponential) return 100 const isExponential = SessionData.getBrightnessExponential(deviceInfo.id);
return deviceInfo.displayMax || 100 if (isExponential)
return 100;
return deviceInfo.displayMax || 100;
} }
Rectangle { Rectangle {
@@ -214,8 +198,8 @@ DankOSD {
id: vertFill id: vertFill
width: parent.width width: parent.width
height: { height: {
const ratio = (vertSlider.value - vertSlider.minimum) / (vertSlider.maximum - vertSlider.minimum) const ratio = (vertSlider.value - vertSlider.minimum) / (vertSlider.maximum - vertSlider.minimum);
return ratio * parent.height return ratio * parent.height;
} }
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
@@ -229,9 +213,9 @@ DankOSD {
height: 8 height: 8
radius: Theme.cornerRadius radius: Theme.cornerRadius
y: { y: {
const ratio = (vertSlider.value - vertSlider.minimum) / (vertSlider.maximum - vertSlider.minimum) const ratio = (vertSlider.value - vertSlider.minimum) / (vertSlider.maximum - vertSlider.minimum);
const travel = parent.height - height const travel = parent.height - height;
return Math.max(0, Math.min(travel, travel * (1 - ratio))) return Math.max(0, Math.min(travel, travel * (1 - ratio)));
} }
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
color: Theme.primary color: Theme.primary
@@ -248,50 +232,34 @@ DankOSD {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onContainsMouseChanged: { onContainsMouseChanged: {
setChildHovered(containsMouse) setChildHovered(containsMouse);
} }
onPressed: mouse => { onPressed: mouse => {
vertSlider.dragging = true vertSlider.dragging = true;
updateBrightness(mouse) updateBrightness(mouse);
} }
onReleased: { onReleased: {
vertSlider.dragging = false vertSlider.dragging = false;
} }
onPositionChanged: mouse => { onPositionChanged: mouse => {
if (pressed) { if (pressed) {
updateBrightness(mouse) updateBrightness(mouse);
} }
} }
onClicked: mouse => { onClicked: mouse => {
updateBrightness(mouse) updateBrightness(mouse);
} }
function updateBrightness(mouse) { function updateBrightness(mouse) {
if (DisplayService.brightnessAvailable) { if (DisplayService.brightnessAvailable) {
const ratio = 1.0 - (mouse.y / height) const ratio = 1.0 - (mouse.y / height);
const newValue = Math.round(vertSlider.minimum + ratio * (vertSlider.maximum - vertSlider.minimum)) const newValue = Math.round(vertSlider.minimum + ratio * (vertSlider.maximum - vertSlider.minimum));
DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true) DisplayService.setBrightness(newValue, DisplayService.lastIpcDevice, true);
resetHideTimer() 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
} }
} }
} }
@@ -302,10 +270,10 @@ DankOSD {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.bottomMargin: gap anchors.bottomMargin: gap
text: { text: {
const deviceInfo = DisplayService.getCurrentDeviceInfo() const deviceInfo = DisplayService.getCurrentDeviceInfo();
const isExponential = deviceInfo ? SessionData.getBrightnessExponential(deviceInfo.id) : false const isExponential = deviceInfo ? SessionData.getBrightnessExponential(deviceInfo.id) : false;
const unit = (deviceInfo && deviceInfo.class === "ddc" && !isExponential) ? "" : "%" const unit = (deviceInfo && deviceInfo.class === "ddc" && !isExponential) ? "" : "%";
return vertSlider.value + unit return vertSlider.value + unit;
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText

View File

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

File diff suppressed because it is too large Load Diff

View File

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