diff --git a/linux/Main.qml b/linux/Main.qml index de3f502..28e9eee 100644 --- a/linux/Main.qml +++ b/linux/Main.qml @@ -226,6 +226,19 @@ ApplicationWindow { onCheckedChanged: airPodsTrayApp.notificationsEnabled = checked } + Switch { + visible: airPodsTrayApp.airpodsConnected + text: "One Bud ANC Mode" + checked: airPodsTrayApp.oneBudANCMode + onCheckedChanged: airPodsTrayApp.oneBudANCMode = checked + + ToolTip { + visible: parent.hovered + text: "Enable ANC when using one AirPod\n(More noise reduction, but uses more battery)" + delay: 500 + } + } + Row { spacing: 5 Label { diff --git a/linux/main.cpp b/linux/main.cpp index 05e099a..925757f 100644 --- a/linux/main.cpp +++ b/linux/main.cpp @@ -37,6 +37,7 @@ class AirPodsTrayApp : public QObject { Q_PROPERTY(bool notificationsEnabled READ notificationsEnabled WRITE setNotificationsEnabled NOTIFY notificationsEnabledChanged) Q_PROPERTY(int retryAttempts READ retryAttempts WRITE setRetryAttempts NOTIFY retryAttemptsChanged) Q_PROPERTY(bool hideOnStart READ hideOnStart CONSTANT) + Q_PROPERTY(bool oneBudANCMode READ oneBudANCMode WRITE setOneBudANCMode NOTIFY oneBudANCModeChanged) public: AirPodsTrayApp(bool debugMode, bool hideOnStart, QQmlApplicationEngine *parent = nullptr) @@ -146,6 +147,7 @@ public: void setNotificationsEnabled(bool enabled) { trayManager->setNotificationsEnabled(enabled); } int retryAttempts() const { return m_retryAttempts; } bool hideOnStart() const { return m_hideOnStart; } + bool oneBudANCMode() const { return m_oneBudANCMode; } private: bool debugMode; @@ -227,6 +229,29 @@ public slots: emit conversationalAwarenessChanged(enabled); } + void setOneBudANCMode(bool enabled) + { + if (m_oneBudANCMode == enabled) + { + LOG_INFO("One Bud ANC mode is already " << (enabled ? "enabled" : "disabled")); + return; + } + + LOG_INFO("Setting One Bud ANC mode to: " << (enabled ? "enabled" : "disabled")); + QByteArray packet = enabled ? AirPodsPackets::OneBudANCMode::ENABLED + : AirPodsPackets::OneBudANCMode::DISABLED; + + if (writePacketToSocket(packet, "One Bud ANC mode packet written: ")) + { + m_oneBudANCMode = enabled; + emit oneBudANCModeChanged(enabled); + } + else + { + LOG_ERROR("Failed to send One Bud ANC mode command: socket not open"); + } + } + void setRetryAttempts(int attempts) { if (m_retryAttempts != attempts) @@ -440,6 +465,7 @@ private slots: trayManager->showNotification( tr("AirPods Disconnected"), tr("Your AirPods have been disconnected")); + trayManager->resetTrayIcon(); } void bluezDeviceDisconnected(const QString &address, const QString &name) @@ -697,6 +723,19 @@ private slots: } emit airPodsStatusChanged(); } + else if (data.startsWith(AirPodsPackets::OneBudANCMode::HEADER)) { + auto result = AirPodsPackets::OneBudANCMode::parseState(data); + if (result.has_value()) + { + m_oneBudANCMode = result.value(); + LOG_INFO("One Bud ANC mode received: " << m_conversationalAwareness); + emit oneBudANCModeChanged(m_conversationalAwareness); + } + else + { + LOG_ERROR("Failed to parse One Bud ANC mode"); + } + } else { LOG_DEBUG("Unrecognized packet format: " << data.toHex()); @@ -926,6 +965,7 @@ signals: void crossDeviceEnabledChanged(bool enabled); void notificationsEnabledChanged(bool enabled); void retryAttemptsChanged(int attempts); + void oneBudANCModeChanged(bool enabled); private: QBluetoothSocket *socket = nullptr; @@ -953,6 +993,7 @@ private: bool m_secoundaryInEar = false; QByteArray m_magicAccIRK; QByteArray m_magicAccEncKey; + bool m_oneBudANCMode = false; }; int main(int argc, char *argv[]) { diff --git a/linux/trayiconmanager.h b/linux/trayiconmanager.h index a6384e3..25c1530 100644 --- a/linux/trayiconmanager.h +++ b/linux/trayiconmanager.h @@ -33,6 +33,12 @@ public: } } + void resetTrayIcon() + { + trayIcon->setIcon(QIcon(":/icons/assets/airpods.png")); + trayIcon->setToolTip(""); + } + signals: void notificationsEnabledChanged(bool enabled);