diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index 4f17aeaeb..0e2988031 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -1017,6 +1017,7 @@ Singleton { "islandHomeClockDisplay": "both", "islandHomeVolumeDisplay": "both", "islandHomeBrightnessDisplay": "both", + "islandHomeStatusContent": "battery", "islandBatteryStyle": "solid", "islandSatellitesEnabled": true, "islandSatellitePosition": "edges", @@ -1046,6 +1047,11 @@ Singleton { return value === "time" || value === "date" || value === "both" ? value : "both"; } + function islandHomeStatusContent(bc) { + const value = islandSetting(bc, "islandHomeStatusContent"); + return value === "battery" || value === "connectivity" ? value : "battery"; + } + function islandEdge(bc) { return positionToSide(bc?.position ?? SettingsData.Position.Top) || "top"; } diff --git a/quickshell/Modules/DankIsland/Activities/HomeCompact.qml b/quickshell/Modules/DankIsland/Activities/HomeCompact.qml index de2109a02..56abab098 100644 --- a/quickshell/Modules/DankIsland/Activities/HomeCompact.qml +++ b/quickshell/Modules/DankIsland/Activities/HomeCompact.qml @@ -127,6 +127,61 @@ Item { DisplayService.setBrightness(next, root.brightnessDevice.id, true); } + function connectivityIconName(type) { + if (type === "wifi") { + if (!NetworkService.wifiAvailable || !NetworkService.networkAvailable) + return "wifi_off"; + if (NetworkService.wifiToggling) + return "sync"; + if (!NetworkService.wifiEnabled) + return "wifi_off"; + return NetworkService.wifiSignalIcon; + } + + if (!BluetoothService.available) + return "bluetooth_disabled"; + return BluetoothService.connected ? "bluetooth_connected" : "bluetooth"; + } + + function connectivityIconColor(type) { + if (type === "wifi") { + if (!NetworkService.wifiAvailable || !NetworkService.networkAvailable) + return Theme.surfaceTextMedium; + if (NetworkService.wifiToggling || NetworkService.isWifiConnecting || NetworkService.wifiConnected) + return Theme.primary; + if (!NetworkService.wifiEnabled) + return Theme.surfaceTextMedium; + return Theme.surfaceText; + } + + if (!BluetoothService.available || !BluetoothService.enabled) + return Theme.surfaceTextMedium; + return (BluetoothService.connected || BluetoothService.connecting) ? Theme.primary : Theme.surfaceText; + } + + function connectivityIconOpacity(type) { + if (type === "wifi") + return NetworkService.wifiAvailable && NetworkService.networkAvailable && (NetworkService.wifiEnabled || NetworkService.wifiToggling) ? 1 : 0.5; + return BluetoothService.available && BluetoothService.enabled ? 1 : 0.5; + } + + function connectivityBusy(type) { + return type === "wifi" ? (NetworkService.wifiToggling || NetworkService.isWifiConnecting) : BluetoothService.connecting; + } + + function toggleConnectivity(type) { + if (type === "wifi") { + if (!NetworkService.wifiAvailable || !NetworkService.networkAvailable || NetworkService.wifiToggling || NetworkService.isWifiConnecting) + return; + NetworkService.toggleWifiRadio(); + return; + } + + if (!BluetoothService.available || BluetoothService.connecting) + return; + BluetoothService.toggleBluetooth(); + } + function syncWeatherRef(wanted) { if (wanted === weatherRefHeld) return; @@ -197,7 +252,8 @@ Item { readonly property bool isNotifications: item.groupId === "notifications" readonly property bool isVolume: item.groupId === "volume" readonly property bool isBrightness: item.groupId === "brightness" - readonly property bool usesBattery: item.isStatus && BatteryService.batteryAvailable + readonly property bool usesConnectivity: item.isStatus && root.controller.homeStatusContent === "connectivity" + readonly property bool usesBattery: item.isStatus && !item.usesConnectivity && BatteryService.batteryAvailable width: { if (item.isMedia) @@ -209,7 +265,7 @@ Item { if (item.isVolume || item.isBrightness) return systemLevelRow.implicitWidth; if (item.isStatus) - return item.usesBattery ? batteryMeter.width : root.iconSize; + return item.usesConnectivity ? connectivityRow.implicitWidth : (item.usesBattery ? batteryMeter.width : root.iconSize); return clockRow.implicitWidth; } height: root.slotSize @@ -357,9 +413,57 @@ Item { levelColors: (root.controller.barConfig?.batteryColorMode ?? "theme") === "level" } + Row { + id: connectivityRow + + anchors.centerIn: parent + visible: item.usesConnectivity + spacing: Theme.spacingXXS + + Item { + width: root.iconSize + height: root.iconSize + opacity: root.connectivityIconOpacity("wifi") + + DankIcon { + id: wifiIcon + + anchors.centerIn: parent + name: root.connectivityIconName("wifi") + size: root.statusIconSize + color: root.connectivityIconColor("wifi") + + DankBlink { + target: wifiIcon + running: item.usesConnectivity && root.connectivityBusy("wifi") + } + } + } + + Item { + width: root.iconSize + height: root.iconSize + opacity: root.connectivityIconOpacity("bluetooth") + + DankIcon { + id: bluetoothIcon + + anchors.centerIn: parent + name: root.connectivityIconName("bluetooth") + size: root.statusIconSize + color: root.connectivityIconColor("bluetooth") + + DankBlink { + target: bluetoothIcon + running: item.usesConnectivity && root.connectivityBusy("bluetooth") + } + } + } + } + DankIcon { anchors.centerIn: parent - visible: item.isStatus && !item.usesBattery + visible: item.isStatus && !item.usesBattery && !item.usesConnectivity name: "tune" size: root.iconSize color: Theme.surfaceText @@ -375,7 +479,16 @@ Item { enabled: !item.isClock controller: root.controller acceptedButtons: Qt.LeftButton | Qt.MiddleButton - onClicked: (event) => { + onClicked: event => { + if (item.usesConnectivity) { + const type = event.x < item.leadPad + item.width / 2 ? "wifi" : "bluetooth"; + if (event.button === Qt.MiddleButton) { + root.toggleConnectivity(type); + return; + } + root.controller.requestControlCenter("", false); + return; + } if (event.button === Qt.MiddleButton) { if (item.isMedia && root.controller.mediaAvailable && MprisController.activePlayer?.canTogglePlaying) MprisController.activePlayer.togglePlaying(); @@ -385,7 +498,7 @@ Item { } return; } - root.activateGroup(item.groupId) + root.activateGroup(item.groupId); } onWheel: wheel => { if (!item.isVolume && !item.isBrightness) @@ -412,7 +525,8 @@ Item { readonly property bool isNotifications: item.groupId === "notifications" readonly property bool isVolume: item.groupId === "volume" readonly property bool isBrightness: item.groupId === "brightness" - readonly property bool usesBattery: item.isStatus && BatteryService.batteryAvailable + readonly property bool usesConnectivity: item.isStatus && root.controller.homeStatusContent === "connectivity" + readonly property bool usesBattery: item.isStatus && !item.usesConnectivity && BatteryService.batteryAvailable width: root.width height: stack.implicitHeight @@ -562,9 +676,55 @@ Item { levelColors: (root.controller.barConfig?.batteryColorMode ?? "theme") === "level" } + Column { + anchors.horizontalCenter: parent.horizontalCenter + visible: item.usesConnectivity + spacing: Theme.spacingXXS + + Item { + width: root.iconSize + height: root.iconSize + opacity: root.connectivityIconOpacity("wifi") + + DankIcon { + id: verticalWifiIcon + + anchors.centerIn: parent + name: root.connectivityIconName("wifi") + size: root.statusIconSize + color: root.connectivityIconColor("wifi") + + DankBlink { + target: verticalWifiIcon + running: item.usesConnectivity && root.connectivityBusy("wifi") + } + } + } + + Item { + width: root.iconSize + height: root.iconSize + opacity: root.connectivityIconOpacity("bluetooth") + + DankIcon { + id: verticalBluetoothIcon + + anchors.centerIn: parent + name: root.connectivityIconName("bluetooth") + size: root.statusIconSize + color: root.connectivityIconColor("bluetooth") + + DankBlink { + target: verticalBluetoothIcon + running: item.usesConnectivity && root.connectivityBusy("bluetooth") + } + } + } + } + DankIcon { anchors.horizontalCenter: parent.horizontalCenter - visible: item.isStatus && !item.usesBattery + visible: item.isStatus && !item.usesBattery && !item.usesConnectivity name: "tune" size: root.iconSize color: Theme.surfaceText @@ -581,7 +741,16 @@ Item { enabled: !item.isClock controller: root.controller acceptedButtons: Qt.LeftButton | Qt.MiddleButton - onClicked: (event) => { + onClicked: event => { + if (item.usesConnectivity) { + const type = event.y < item.leadPad + item.height / 2 ? "wifi" : "bluetooth"; + if (event.button === Qt.MiddleButton) { + root.toggleConnectivity(type); + return; + } + root.controller.requestControlCenter("", false); + return; + } if (event.button === Qt.MiddleButton) { if (item.isMedia && root.controller.mediaAvailable && MprisController.activePlayer?.canTogglePlaying) MprisController.activePlayer.togglePlaying(); @@ -591,7 +760,7 @@ Item { } return; } - root.activateGroup(item.groupId) + root.activateGroup(item.groupId); } onWheel: wheel => { if (!item.isVolume && !item.isBrightness) diff --git a/quickshell/Modules/DankIsland/DankIslandHostWindow.qml b/quickshell/Modules/DankIsland/DankIslandHostWindow.qml index 3e46cdc7d..36b8b4910 100644 --- a/quickshell/Modules/DankIsland/DankIslandHostWindow.qml +++ b/quickshell/Modules/DankIsland/DankIslandHostWindow.qml @@ -176,6 +176,7 @@ PanelWindow { compactThickness: root.compactThickness cornerRadius: Math.max(0, Math.min(64, root.setting("islandCornerRadius"))) homeCompactTight: root.setting("islandHomeCompactTight") + homeStatusContent: SettingsData.islandHomeStatusContent(root.barConfig) homeClockDisplay: SettingsData.islandClockDisplay(root.barConfig) homeVolumeDisplay: SettingsData.islandLevelDisplay(root.barConfig, "islandHomeVolumeDisplay") homeBrightnessDisplay: SettingsData.islandLevelDisplay(root.barConfig, "islandHomeBrightnessDisplay") diff --git a/quickshell/Modules/DankIsland/IslandController.qml b/quickshell/Modules/DankIsland/IslandController.qml index 4fedf8a38..364759c5f 100644 --- a/quickshell/Modules/DankIsland/IslandController.qml +++ b/quickshell/Modules/DankIsland/IslandController.qml @@ -281,6 +281,7 @@ QtObject { readonly property var homeLeftGroups: homeGroups("left") readonly property var homeRightGroups: homeGroups("right") + property string homeStatusContent: "battery" property string homeClockDisplay: "both" property string homeVolumeDisplay: "both" property string homeBrightnessDisplay: "both" diff --git a/quickshell/Modules/Settings/DankIslandTab.qml b/quickshell/Modules/Settings/DankIslandTab.qml index 8f86e6ee3..baa92e884 100644 --- a/quickshell/Modules/Settings/DankIslandTab.qml +++ b/quickshell/Modules/Settings/DankIslandTab.qml @@ -55,6 +55,7 @@ Item { } readonly property var clockDisplayValues: ["time", "date", "both"] readonly property var systemLevelDisplayValues: ["icon", "percentage", "both"] + readonly property var statusContentValues: ["battery", "connectivity"] readonly property var paletteValues: ["default", "bright", "dim"] readonly property var batteryStyleValues: ["solid", "outline", "ring"] readonly property var satellitePositionValues: ["island", "edges"] @@ -274,6 +275,19 @@ Item { } } + SettingsButtonGroupRow { + settingKey: "islandHomeStatusContent" + tags: ["island", "home", "compact", "status", "battery", "wifi", "bluetooth", "connectivity"] + text: I18n.tr("Control Center", "island settings: status group content row") + visible: SettingsData.islandHomeGroupEnabled(root.config, "status") + model: [I18n.tr("Battery", "island settings: status group battery content"), I18n.tr("Wi-Fi & Bluetooth", "island settings: status group connectivity content")] + currentIndex: root.valueIndex(root.statusContentValues, SettingsData.islandHomeStatusContent(root.config), "battery") + onSelectionChanged: (index, selected) => { + if (selected) + root.apply("islandHomeStatusContent", root.statusContentValues[index] ?? "battery"); + } + } + SettingsToggleRow { settingKey: "islandHomeCompactTight" tags: ["island", "home", "compact", "narrow", "width", "height", "clock"] @@ -379,7 +393,7 @@ Item { tags: ["island", "battery", "gauge", "solid", "outline", "ring", "circle", "appearance"] text: I18n.tr("Battery Style", "island settings: battery meter style row") description: I18n.tr("Solid or outlined material meter, or a circular gauge", "island settings: battery style description") - visible: BatteryService.batteryAvailable + visible: SettingsData.islandHomeGroupEnabled(root.config, "status") && BatteryService.batteryAvailable && SettingsData.islandHomeStatusContent(root.config) === "battery" model: [I18n.tr("Solid", "island settings: filled battery meter style"), I18n.tr("Outline", "island settings: outlined battery meter style"), I18n.tr("Circle", "island settings: circular battery meter style")] currentIndex: root.valueIndex(root.batteryStyleValues, root.setting("islandBatteryStyle"), "solid") onSelectionChanged: (index, selected) => { diff --git a/quickshell/Modules/Settings/IslandHomeLayoutEditor.qml b/quickshell/Modules/Settings/IslandHomeLayoutEditor.qml index 46943281f..f6faec886 100644 --- a/quickshell/Modules/Settings/IslandHomeLayoutEditor.qml +++ b/quickshell/Modules/Settings/IslandHomeLayoutEditor.qml @@ -35,9 +35,9 @@ Item { "description": SettingsData.weatherEnabled ? I18n.tr("Weather icon and temperature open the weather activity", "island settings: weather slot description") : I18n.tr("Enable weather in Time & Weather to show this shortcut", "island settings: weather slot disabled hint") }, "status": { - "icon": BatteryService.batteryAvailable ? "battery_full" : "tune", - "text": I18n.tr("Battery / Control Center", "island settings: battery or control center slot row"), - "description": BatteryService.batteryAvailable ? I18n.tr("Battery gauge opens Control Center", "island settings: status slot description with battery") : I18n.tr("Tools icon opens Control Center", "island settings: status slot description without battery") + "icon": "settings", + "text": I18n.tr("Control Center", "island settings: battery or control center slot row"), + "description": I18n.tr("Choose between battery gauge or connectivity icons", "island settings: control center slot description") }, "volume": { "icon": "volume_up", diff --git a/quickshell/translations/settings_search_index.json b/quickshell/translations/settings_search_index.json index 3fdd6e392..39616545b 100644 --- a/quickshell/translations/settings_search_index.json +++ b/quickshell/translations/settings_search_index.json @@ -12619,6 +12619,25 @@ "description": "Compact home clock pill in both width and height", "conditionKey": "islandEnabled" }, + { + "section": "islandHomeStatusContent", + "label": "Control Center", + "tabIndex": 46, + "category": "Island", + "keywords": [ + "battery", + "bluetooth", + "center", + "compact", + "connectivity", + "control", + "home", + "island", + "status", + "wifi" + ], + "conditionKey": "islandEnabled" + }, { "section": "islandCornerRadius", "label": "Corner Radius",