mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-07 19:59:14 -04:00
feat: Blink WiFi/Bluetooth icons while connecting (#2448)
Pulses the WiFi and Bluetooth status icons while a connection is in progress (lock screen, DankBar control center button, control center compound pill). The pulse is implemented as a reusable Widgets/DankBlink component, and the wifi-connecting condition is centralized as NetworkService.isWifiConnecting. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -301,12 +301,22 @@ Column {
|
|||||||
property var widgetDef: root.model?.getWidgetForId(widgetData.id || "")
|
property var widgetDef: root.model?.getWidgetForId(widgetData.id || "")
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 60
|
height: 60
|
||||||
|
iconBlinking: {
|
||||||
|
const id = widgetData.id || "";
|
||||||
|
if (id === "wifi")
|
||||||
|
return NetworkService.isWifiConnecting;
|
||||||
|
if (id === "bluetooth")
|
||||||
|
return BluetoothService.connecting;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
iconName: {
|
iconName: {
|
||||||
switch (widgetData.id || "") {
|
switch (widgetData.id || "") {
|
||||||
case "wifi":
|
case "wifi":
|
||||||
{
|
{
|
||||||
if (NetworkService.wifiToggling)
|
if (NetworkService.wifiToggling)
|
||||||
return "sync";
|
return "sync";
|
||||||
|
if (NetworkService.isConnecting && !NetworkService.ethernetConnected)
|
||||||
|
return NetworkService.wifiSignalIcon;
|
||||||
|
|
||||||
const status = NetworkService.networkStatus;
|
const status = NetworkService.networkStatus;
|
||||||
if (status === "ethernet")
|
if (status === "ethernet")
|
||||||
@@ -360,6 +370,8 @@ Column {
|
|||||||
{
|
{
|
||||||
if (NetworkService.wifiToggling)
|
if (NetworkService.wifiToggling)
|
||||||
return NetworkService.wifiEnabled ? I18n.tr("Disabling WiFi...", "network status") : I18n.tr("Enabling WiFi...", "network status");
|
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;
|
const status = NetworkService.networkStatus;
|
||||||
if (status === "ethernet")
|
if (status === "ethernet")
|
||||||
@@ -400,6 +412,8 @@ Column {
|
|||||||
{
|
{
|
||||||
if (NetworkService.wifiToggling)
|
if (NetworkService.wifiToggling)
|
||||||
return I18n.tr("Please wait...", "network status");
|
return I18n.tr("Please wait...", "network status");
|
||||||
|
if (NetworkService.isConnecting && !NetworkService.ethernetConnected)
|
||||||
|
return I18n.tr("Connecting...", "network status");
|
||||||
|
|
||||||
const status = NetworkService.networkStatus;
|
const status = NetworkService.networkStatus;
|
||||||
if (status === "ethernet")
|
if (status === "ethernet")
|
||||||
@@ -422,6 +436,8 @@ Column {
|
|||||||
return I18n.tr("No adapters", "bluetooth status");
|
return I18n.tr("No adapters", "bluetooth status");
|
||||||
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled)
|
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled)
|
||||||
return I18n.tr("Off", "bluetooth status");
|
return I18n.tr("Off", "bluetooth status");
|
||||||
|
if (BluetoothService.connecting)
|
||||||
|
return I18n.tr("Connecting...", "bluetooth status");
|
||||||
const primaryDevice = (() => {
|
const primaryDevice = (() => {
|
||||||
if (!BluetoothService.adapter || !BluetoothService.adapter.devices)
|
if (!BluetoothService.adapter || !BluetoothService.adapter.devices)
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ Rectangle {
|
|||||||
|
|
||||||
property string iconName: ""
|
property string iconName: ""
|
||||||
property color iconColor: Theme.surfaceText
|
property color iconColor: Theme.surfaceText
|
||||||
|
property bool iconBlinking: false
|
||||||
property string primaryText: ""
|
property string primaryText: ""
|
||||||
property string secondaryText: ""
|
property string secondaryText: ""
|
||||||
property bool expanded: false
|
property bool expanded: false
|
||||||
@@ -109,10 +110,16 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
|
id: pillIcon
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
name: iconName
|
name: iconName
|
||||||
size: Theme.iconSize
|
size: Theme.iconSize
|
||||||
color: isActive ? _tileIconActive : _tileIconInactive
|
color: isActive ? _tileIconActive : _tileIconInactive
|
||||||
|
|
||||||
|
DankBlink {
|
||||||
|
target: pillIcon
|
||||||
|
running: root.iconBlinking
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankRipple {
|
DankRipple {
|
||||||
|
|||||||
@@ -131,9 +131,19 @@ BasePill {
|
|||||||
function getNetworkIconColor() {
|
function getNetworkIconColor() {
|
||||||
if (NetworkService.wifiToggling)
|
if (NetworkService.wifiToggling)
|
||||||
return Theme.primary;
|
return Theme.primary;
|
||||||
|
if (NetworkService.isConnecting && !NetworkService.ethernetConnected)
|
||||||
|
return Theme.primary;
|
||||||
return NetworkService.networkStatus !== "disconnected" ? Theme.primary : Theme.surfaceText;
|
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() {
|
function getVolumeIconName() {
|
||||||
if (!AudioService.sink?.audio)
|
if (!AudioService.sink?.audio)
|
||||||
return "volume_up";
|
return "volume_up";
|
||||||
@@ -485,6 +495,7 @@ BasePill {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
|
id: vIconOnlyItem
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
visible: !verticalGroupItem.modelData.composite
|
visible: !verticalGroupItem.modelData.composite
|
||||||
name: {
|
name: {
|
||||||
@@ -515,7 +526,7 @@ BasePill {
|
|||||||
case "vpn":
|
case "vpn":
|
||||||
return NetworkService.vpnConnected ? Theme.primary : Theme.surfaceText;
|
return NetworkService.vpnConnected ? Theme.primary : Theme.surfaceText;
|
||||||
case "bluetooth":
|
case "bluetooth":
|
||||||
return BluetoothService.connected ? Theme.primary : Theme.surfaceText;
|
return (BluetoothService.connected || BluetoothService.connecting) ? Theme.primary : Theme.surfaceText;
|
||||||
case "battery":
|
case "battery":
|
||||||
return root.getBatteryIconColor();
|
return root.getBatteryIconColor();
|
||||||
case "printer":
|
case "printer":
|
||||||
@@ -524,6 +535,11 @@ BasePill {
|
|||||||
return Theme.widgetIconColor;
|
return Theme.widgetIconColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DankBlink {
|
||||||
|
target: vIconOnlyItem
|
||||||
|
running: root.getIconBlinking(verticalGroupItem.modelData.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
@@ -687,7 +703,7 @@ BasePill {
|
|||||||
case "vpn":
|
case "vpn":
|
||||||
return NetworkService.vpnConnected ? Theme.primary : Theme.surfaceText;
|
return NetworkService.vpnConnected ? Theme.primary : Theme.surfaceText;
|
||||||
case "bluetooth":
|
case "bluetooth":
|
||||||
return BluetoothService.connected ? Theme.primary : Theme.surfaceText;
|
return (BluetoothService.connected || BluetoothService.connecting) ? Theme.primary : Theme.surfaceText;
|
||||||
case "battery":
|
case "battery":
|
||||||
return root.getBatteryIconColor();
|
return root.getBatteryIconColor();
|
||||||
case "printer":
|
case "printer":
|
||||||
@@ -696,6 +712,11 @@ BasePill {
|
|||||||
return Theme.widgetIconColor;
|
return Theme.widgetIconColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DankBlink {
|
||||||
|
target: iconOnlyItem
|
||||||
|
running: root.getIconBlinking(horizontalGroupItem.modelData.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|||||||
@@ -1461,6 +1461,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
|
id: lockNetworkIcon
|
||||||
name: {
|
name: {
|
||||||
if (NetworkService.wifiToggling)
|
if (NetworkService.wifiToggling)
|
||||||
return "sync";
|
return "sync";
|
||||||
@@ -1474,9 +1475,14 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
size: Theme.iconSize - 2
|
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
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: NetworkService.networkAvailable
|
visible: NetworkService.networkAvailable
|
||||||
|
|
||||||
|
DankBlink {
|
||||||
|
target: lockNetworkIcon
|
||||||
|
running: NetworkService.isWifiConnecting
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
@@ -1488,11 +1494,17 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
|
id: lockBluetoothIcon
|
||||||
name: "bluetooth"
|
name: "bluetooth"
|
||||||
size: Theme.iconSize - 2
|
size: Theme.iconSize - 2
|
||||||
color: "white"
|
color: "white"
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: BluetoothService.available && BluetoothService.enabled
|
visible: BluetoothService.available && BluetoothService.enabled
|
||||||
|
|
||||||
|
DankBlink {
|
||||||
|
target: lockBluetoothIcon
|
||||||
|
running: BluetoothService.connecting
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
|
|||||||
@@ -28,6 +28,20 @@ Singleton {
|
|||||||
});
|
});
|
||||||
return isConnected;
|
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: {
|
readonly property var pairedDevices: {
|
||||||
if (!adapter || !adapter.devices) {
|
if (!adapter || !adapter.devices) {
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ Singleton {
|
|||||||
property var savedConnections: []
|
property var savedConnections: []
|
||||||
property var ssidToConnectionName: ({})
|
property var ssidToConnectionName: ({})
|
||||||
property var wifiSignalIcon: {
|
property var wifiSignalIcon: {
|
||||||
|
if (isConnecting) {
|
||||||
|
return "wifi";
|
||||||
|
}
|
||||||
if (!wifiConnected) {
|
if (!wifiConnected) {
|
||||||
return "wifi_off";
|
return "wifi_off";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,6 +99,9 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
readonly property string wifiSignalIcon: {
|
readonly property string wifiSignalIcon: {
|
||||||
|
if (isConnecting) {
|
||||||
|
return "wifi";
|
||||||
|
}
|
||||||
if (!wifiConnected || networkStatus !== "wifi") {
|
if (!wifiConnected || networkStatus !== "wifi") {
|
||||||
return "wifi_off";
|
return "wifi_off";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ Singleton {
|
|||||||
|
|
||||||
property string userPreference: activeService?.userPreference ?? "auto"
|
property string userPreference: activeService?.userPreference ?? "auto"
|
||||||
property bool isConnecting: activeService?.isConnecting ?? false
|
property bool isConnecting: activeService?.isConnecting ?? false
|
||||||
|
readonly property bool isWifiConnecting: isConnecting && !ethernetConnected && !wifiToggling
|
||||||
property string connectingSSID: activeService?.connectingSSID ?? ""
|
property string connectingSSID: activeService?.connectingSSID ?? ""
|
||||||
property string connectionError: activeService?.connectionError ?? ""
|
property string connectionError: activeService?.connectionError ?? ""
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user