diff --git a/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml b/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml index 8000f679..6d740bff 100644 --- a/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml +++ b/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml @@ -301,12 +301,22 @@ Column { property var widgetDef: root.model?.getWidgetForId(widgetData.id || "") width: parent.width height: 60 + iconBlinking: { + const id = widgetData.id || ""; + if (id === "wifi") + return NetworkService.isWifiConnecting; + if (id === "bluetooth") + return BluetoothService.connecting; + return false; + } iconName: { switch (widgetData.id || "") { case "wifi": { if (NetworkService.wifiToggling) return "sync"; + if (NetworkService.isConnecting && !NetworkService.ethernetConnected) + return NetworkService.wifiSignalIcon; const status = NetworkService.networkStatus; if (status === "ethernet") @@ -360,6 +370,8 @@ Column { { if (NetworkService.wifiToggling) return NetworkService.wifiEnabled ? I18n.tr("Disabling WiFi...", "network status") : I18n.tr("Enabling WiFi...", "network status"); + if (NetworkService.isConnecting && !NetworkService.ethernetConnected) + return NetworkService.connectingSSID || I18n.tr("Connecting...", "network status"); const status = NetworkService.networkStatus; if (status === "ethernet") @@ -400,6 +412,8 @@ Column { { if (NetworkService.wifiToggling) return I18n.tr("Please wait...", "network status"); + if (NetworkService.isConnecting && !NetworkService.ethernetConnected) + return I18n.tr("Connecting...", "network status"); const status = NetworkService.networkStatus; if (status === "ethernet") @@ -422,6 +436,8 @@ Column { return I18n.tr("No adapters", "bluetooth status"); if (!BluetoothService.adapter || !BluetoothService.adapter.enabled) return I18n.tr("Off", "bluetooth status"); + if (BluetoothService.connecting) + return I18n.tr("Connecting...", "bluetooth status"); const primaryDevice = (() => { if (!BluetoothService.adapter || !BluetoothService.adapter.devices) return null; diff --git a/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml b/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml index 74679cc8..f99bef5c 100644 --- a/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml +++ b/quickshell/Modules/ControlCenter/Widgets/CompoundPill.qml @@ -10,6 +10,7 @@ Rectangle { property string iconName: "" property color iconColor: Theme.surfaceText + property bool iconBlinking: false property string primaryText: "" property string secondaryText: "" property bool expanded: false @@ -109,10 +110,16 @@ Rectangle { } DankIcon { + id: pillIcon anchors.centerIn: parent name: iconName size: Theme.iconSize color: isActive ? _tileIconActive : _tileIconInactive + + DankBlink { + target: pillIcon + running: root.iconBlinking + } } DankRipple { diff --git a/quickshell/Modules/DankBar/Widgets/ControlCenterButton.qml b/quickshell/Modules/DankBar/Widgets/ControlCenterButton.qml index 5413d20c..e4717499 100644 --- a/quickshell/Modules/DankBar/Widgets/ControlCenterButton.qml +++ b/quickshell/Modules/DankBar/Widgets/ControlCenterButton.qml @@ -131,9 +131,19 @@ BasePill { function getNetworkIconColor() { if (NetworkService.wifiToggling) return Theme.primary; + if (NetworkService.isConnecting && !NetworkService.ethernetConnected) + return Theme.primary; return NetworkService.networkStatus !== "disconnected" ? Theme.primary : Theme.surfaceText; } + function getIconBlinking(id) { + if (id === "network") + return NetworkService.isWifiConnecting; + if (id === "bluetooth") + return BluetoothService.connecting; + return false; + } + function getVolumeIconName() { if (!AudioService.sink?.audio) return "volume_up"; @@ -485,6 +495,7 @@ BasePill { } DankIcon { + id: vIconOnlyItem anchors.centerIn: parent visible: !verticalGroupItem.modelData.composite name: { @@ -515,7 +526,7 @@ BasePill { case "vpn": return NetworkService.vpnConnected ? Theme.primary : Theme.surfaceText; case "bluetooth": - return BluetoothService.connected ? Theme.primary : Theme.surfaceText; + return (BluetoothService.connected || BluetoothService.connecting) ? Theme.primary : Theme.surfaceText; case "battery": return root.getBatteryIconColor(); case "printer": @@ -524,6 +535,11 @@ BasePill { return Theme.widgetIconColor; } } + + DankBlink { + target: vIconOnlyItem + running: root.getIconBlinking(verticalGroupItem.modelData.id) + } } DankIcon { @@ -687,7 +703,7 @@ BasePill { case "vpn": return NetworkService.vpnConnected ? Theme.primary : Theme.surfaceText; case "bluetooth": - return BluetoothService.connected ? Theme.primary : Theme.surfaceText; + return (BluetoothService.connected || BluetoothService.connecting) ? Theme.primary : Theme.surfaceText; case "battery": return root.getBatteryIconColor(); case "printer": @@ -696,6 +712,11 @@ BasePill { return Theme.widgetIconColor; } } + + DankBlink { + target: iconOnlyItem + running: root.getIconBlinking(horizontalGroupItem.modelData.id) + } } Rectangle { diff --git a/quickshell/Modules/Lock/LockScreenContent.qml b/quickshell/Modules/Lock/LockScreenContent.qml index 04ba4b3f..d83d7075 100644 --- a/quickshell/Modules/Lock/LockScreenContent.qml +++ b/quickshell/Modules/Lock/LockScreenContent.qml @@ -1461,6 +1461,7 @@ Item { } DankIcon { + id: lockNetworkIcon name: { if (NetworkService.wifiToggling) return "sync"; @@ -1474,9 +1475,14 @@ Item { } } size: Theme.iconSize - 2 - color: NetworkService.networkStatus !== "disconnected" ? "white" : Qt.rgba(255, 255, 255, 0.5) + color: (NetworkService.networkStatus !== "disconnected" || NetworkService.isConnecting) ? "white" : Qt.rgba(255, 255, 255, 0.5) anchors.verticalCenter: parent.verticalCenter visible: NetworkService.networkAvailable + + DankBlink { + target: lockNetworkIcon + running: NetworkService.isWifiConnecting + } } DankIcon { @@ -1488,11 +1494,17 @@ Item { } DankIcon { + id: lockBluetoothIcon name: "bluetooth" size: Theme.iconSize - 2 color: "white" anchors.verticalCenter: parent.verticalCenter visible: BluetoothService.available && BluetoothService.enabled + + DankBlink { + target: lockBluetoothIcon + running: BluetoothService.connecting + } } DankIcon { diff --git a/quickshell/Services/BluetoothService.qml b/quickshell/Services/BluetoothService.qml index 774a5337..f1f04abc 100644 --- a/quickshell/Services/BluetoothService.qml +++ b/quickshell/Services/BluetoothService.qml @@ -28,6 +28,20 @@ Singleton { }); return isConnected; } + readonly property bool connecting: { + if (!adapter || !adapter.devices) { + return false; + } + + let busy = false; + adapter.devices.values.forEach(dev => { + if (!dev) + return; + if (dev.pairing || dev.state === BluetoothDeviceState.Connecting) + busy = true; + }); + return busy; + } readonly property var pairedDevices: { if (!adapter || !adapter.devices) { return []; diff --git a/quickshell/Services/DMSNetworkService.qml b/quickshell/Services/DMSNetworkService.qml index a4c1782c..db71f0a2 100644 --- a/quickshell/Services/DMSNetworkService.qml +++ b/quickshell/Services/DMSNetworkService.qml @@ -41,6 +41,9 @@ Singleton { property var savedConnections: [] property var ssidToConnectionName: ({}) property var wifiSignalIcon: { + if (isConnecting) { + return "wifi"; + } if (!wifiConnected) { return "wifi_off"; } diff --git a/quickshell/Services/LegacyNetworkService.qml b/quickshell/Services/LegacyNetworkService.qml index decc82f7..9ece973b 100644 --- a/quickshell/Services/LegacyNetworkService.qml +++ b/quickshell/Services/LegacyNetworkService.qml @@ -99,6 +99,9 @@ Singleton { } readonly property string wifiSignalIcon: { + if (isConnecting) { + return "wifi"; + } if (!wifiConnected || networkStatus !== "wifi") { return "wifi_off"; } diff --git a/quickshell/Services/NetworkService.qml b/quickshell/Services/NetworkService.qml index 7b988dcc..3bcb6135 100644 --- a/quickshell/Services/NetworkService.qml +++ b/quickshell/Services/NetworkService.qml @@ -42,6 +42,7 @@ Singleton { property string userPreference: activeService?.userPreference ?? "auto" property bool isConnecting: activeService?.isConnecting ?? false + readonly property bool isWifiConnecting: isConnecting && !ethernetConnected && !wifiToggling property string connectingSSID: activeService?.connectingSSID ?? "" property string connectionError: activeService?.connectionError ?? "" diff --git a/quickshell/Widgets/DankBlink.qml b/quickshell/Widgets/DankBlink.qml new file mode 100644 index 00000000..fd1c77c3 --- /dev/null +++ b/quickshell/Widgets/DankBlink.qml @@ -0,0 +1,28 @@ +import QtQuick + +SequentialAnimation { + id: root + + property Item target + property real minOpacity: 0.3 + property int pulseDuration: 600 + + loops: Animation.Infinite + + NumberAnimation { + target: root.target + property: "opacity" + to: root.minOpacity + duration: root.pulseDuration + easing.type: Easing.InOutQuad + } + NumberAnimation { + target: root.target + property: "opacity" + to: 1.0 + duration: root.pulseDuration + easing.type: Easing.InOutQuad + } + + onStopped: if (root.target) root.target.opacity = 1.0 +}