mirror of
https://github.com/kavishdevar/librepods.git
synced 2026-04-02 11:19:02 +00:00
[Linux] Let users edit Phone bluetooth MAC via GUI (#195)
initial commit
This commit is contained in:
@@ -154,8 +154,28 @@ ApplicationWindow {
|
|||||||
visible: airPodsTrayApp.airpodsConnected
|
visible: airPodsTrayApp.airpodsConnected
|
||||||
text: "Conversational Awareness"
|
text: "Conversational Awareness"
|
||||||
checked: airPodsTrayApp.deviceInfo.conversationalAwareness
|
checked: airPodsTrayApp.deviceInfo.conversationalAwareness
|
||||||
|
// Disable when no phone MAC set or using default placeholder
|
||||||
|
enabled: !(PHONE_MAC_ADDRESS === "" || PHONE_MAC_ADDRESS === "00:00:00:00:00:00")
|
||||||
onCheckedChanged: airPodsTrayApp.setConversationalAwareness(checked)
|
onCheckedChanged: airPodsTrayApp.setConversationalAwareness(checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Instruction when Conversational Awareness is disabled due to missing phone MAC
|
||||||
|
Row {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
spacing: 8
|
||||||
|
visible: airPodsTrayApp.airpodsConnected && (PHONE_MAC_ADDRESS === "" || PHONE_MAC_ADDRESS === "00:00:00:00:00:00")
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: "Set your phone's MAC in Settings to use this feature"
|
||||||
|
font.pixelSize: 12
|
||||||
|
color: "gray"
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Open Settings"
|
||||||
|
onClicked: stackView.push(settingsPage)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RoundButton {
|
RoundButton {
|
||||||
@@ -269,6 +289,23 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: 10
|
||||||
|
visible: airPodsTrayApp.airpodsConnected
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: newPhoneMacField
|
||||||
|
placeholderText: (PHONE_MAC_ADDRESS !== "" ? PHONE_MAC_ADDRESS : "00:00:00:00:00:00")
|
||||||
|
maximumLength: 32
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Change Phone MAC"
|
||||||
|
onClicked: airPodsTrayApp.setPhoneMac(newPhoneMacField.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "Show Magic Cloud Keys QR"
|
text: "Show Magic Cloud Keys QR"
|
||||||
onClicked: keysQrDialog.show()
|
onClicked: keysQrDialog.show()
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include "airpods_packets.h"
|
#include "airpods_packets.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
@@ -40,6 +41,7 @@ class AirPodsTrayApp : public QObject {
|
|||||||
Q_PROPERTY(int retryAttempts READ retryAttempts WRITE setRetryAttempts NOTIFY retryAttemptsChanged)
|
Q_PROPERTY(int retryAttempts READ retryAttempts WRITE setRetryAttempts NOTIFY retryAttemptsChanged)
|
||||||
Q_PROPERTY(bool hideOnStart READ hideOnStart CONSTANT)
|
Q_PROPERTY(bool hideOnStart READ hideOnStart CONSTANT)
|
||||||
Q_PROPERTY(DeviceInfo *deviceInfo READ deviceInfo CONSTANT)
|
Q_PROPERTY(DeviceInfo *deviceInfo READ deviceInfo CONSTANT)
|
||||||
|
Q_PROPERTY(QString phoneMacStatus READ phoneMacStatus NOTIFY phoneMacStatusChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AirPodsTrayApp(bool debugMode, bool hideOnStart, QQmlApplicationEngine *parent = nullptr)
|
AirPodsTrayApp(bool debugMode, bool hideOnStart, QQmlApplicationEngine *parent = nullptr)
|
||||||
@@ -119,6 +121,7 @@ public:
|
|||||||
int retryAttempts() const { return m_retryAttempts; }
|
int retryAttempts() const { return m_retryAttempts; }
|
||||||
bool hideOnStart() const { return m_hideOnStart; }
|
bool hideOnStart() const { return m_hideOnStart; }
|
||||||
DeviceInfo *deviceInfo() const { return m_deviceInfo; }
|
DeviceInfo *deviceInfo() const { return m_deviceInfo; }
|
||||||
|
QString phoneMacStatus() const { return m_phoneMacStatus; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool debugMode;
|
bool debugMode;
|
||||||
@@ -310,6 +313,51 @@ public slots:
|
|||||||
emit crossDeviceEnabledChanged(enabled);
|
emit crossDeviceEnabledChanged(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setPhoneMac(const QString &mac)
|
||||||
|
{
|
||||||
|
if (mac.isEmpty()) {
|
||||||
|
LOG_WARN("Empty MAC provided, ignoring");
|
||||||
|
m_phoneMacStatus = QStringLiteral("No MAC provided (ignoring)");
|
||||||
|
emit phoneMacStatusChanged();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basic MAC address validation (accepts formats like AA:BB:CC:DD:EE:FF, AABBCCDDEEFF, AA-BB-CC-DD-EE-FF)
|
||||||
|
QRegularExpression re("^([0-9A-Fa-f]{2}([-:]?)){5}[0-9A-Fa-f]{2}$");
|
||||||
|
if (!re.match(mac).hasMatch()) {
|
||||||
|
LOG_ERROR("Invalid MAC address format: " << mac);
|
||||||
|
m_phoneMacStatus = QStringLiteral("Invalid MAC: ") + mac;
|
||||||
|
emit phoneMacStatusChanged();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set environment variable for the running process
|
||||||
|
qputenv("PHONE_MAC_ADDRESS", mac.toUtf8());
|
||||||
|
LOG_INFO("PHONE_MAC_ADDRESS environment variable set to: " << mac);
|
||||||
|
|
||||||
|
m_phoneMacStatus = QStringLiteral("Updated MAC: ") + mac;
|
||||||
|
emit phoneMacStatusChanged();
|
||||||
|
|
||||||
|
// Update QML context property so UI placeholders reflect the new value
|
||||||
|
if (parent) {
|
||||||
|
parent->rootContext()->setContextProperty("PHONE_MAC_ADDRESS", mac);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a phone socket exists, restart connection using the new MAC
|
||||||
|
if (phoneSocket && phoneSocket->isOpen()) {
|
||||||
|
phoneSocket->close();
|
||||||
|
phoneSocket->deleteLater();
|
||||||
|
phoneSocket = nullptr;
|
||||||
|
}
|
||||||
|
connectToPhone();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updatePhoneMacStatus(const QString &status)
|
||||||
|
{
|
||||||
|
m_phoneMacStatus = status;
|
||||||
|
emit phoneMacStatusChanged();
|
||||||
|
}
|
||||||
|
|
||||||
bool writePacketToSocket(const QByteArray &packet, const QString &logMessage)
|
bool writePacketToSocket(const QByteArray &packet, const QString &logMessage)
|
||||||
{
|
{
|
||||||
if (socket && socket->isOpen())
|
if (socket && socket->isOpen())
|
||||||
@@ -658,6 +706,7 @@ private slots:
|
|||||||
}
|
}
|
||||||
QBluetoothAddress phoneAddress("00:00:00:00:00:00"); // Default address, will be overwritten if PHONE_MAC_ADDRESS is set
|
QBluetoothAddress phoneAddress("00:00:00:00:00:00"); // Default address, will be overwritten if PHONE_MAC_ADDRESS is set
|
||||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||||
|
|
||||||
if (!env.value("PHONE_MAC_ADDRESS").isEmpty())
|
if (!env.value("PHONE_MAC_ADDRESS").isEmpty())
|
||||||
{
|
{
|
||||||
phoneAddress = QBluetoothAddress(env.value("PHONE_MAC_ADDRESS"));
|
phoneAddress = QBluetoothAddress(env.value("PHONE_MAC_ADDRESS"));
|
||||||
@@ -854,6 +903,7 @@ signals:
|
|||||||
void notificationsEnabledChanged(bool enabled);
|
void notificationsEnabledChanged(bool enabled);
|
||||||
void retryAttemptsChanged(int attempts);
|
void retryAttemptsChanged(int attempts);
|
||||||
void oneBudANCModeChanged(bool enabled);
|
void oneBudANCModeChanged(bool enabled);
|
||||||
|
void phoneMacStatusChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QBluetoothSocket *socket = nullptr;
|
QBluetoothSocket *socket = nullptr;
|
||||||
@@ -870,6 +920,7 @@ private:
|
|||||||
DeviceInfo *m_deviceInfo;
|
DeviceInfo *m_deviceInfo;
|
||||||
BleManager *m_bleManager;
|
BleManager *m_bleManager;
|
||||||
SystemSleepMonitor *m_systemSleepMonitor = nullptr;
|
SystemSleepMonitor *m_systemSleepMonitor = nullptr;
|
||||||
|
QString m_phoneMacStatus;
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
@@ -917,6 +968,16 @@ int main(int argc, char *argv[]) {
|
|||||||
qmlRegisterType<DeviceInfo>("me.kavishdevar.DeviceInfo", 1, 0, "DeviceInfo");
|
qmlRegisterType<DeviceInfo>("me.kavishdevar.DeviceInfo", 1, 0, "DeviceInfo");
|
||||||
AirPodsTrayApp *trayApp = new AirPodsTrayApp(debugMode, hideOnStart, &engine);
|
AirPodsTrayApp *trayApp = new AirPodsTrayApp(debugMode, hideOnStart, &engine);
|
||||||
engine.rootContext()->setContextProperty("airPodsTrayApp", trayApp);
|
engine.rootContext()->setContextProperty("airPodsTrayApp", trayApp);
|
||||||
|
|
||||||
|
// Expose PHONE_MAC_ADDRESS environment variable to QML for placeholder in settings
|
||||||
|
{
|
||||||
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||||
|
QString phoneMacEnv = env.value("PHONE_MAC_ADDRESS", "");
|
||||||
|
engine.rootContext()->setContextProperty("PHONE_MAC_ADDRESS", phoneMacEnv);
|
||||||
|
// Initialize the visible status in the GUI
|
||||||
|
trayApp->updatePhoneMacStatus(phoneMacEnv.isEmpty() ? QStringLiteral("No phone MAC set") : phoneMacEnv);
|
||||||
|
}
|
||||||
|
|
||||||
engine.addImageProvider("qrcode", new QRCodeImageProvider());
|
engine.addImageProvider("qrcode", new QRCodeImageProvider());
|
||||||
trayApp->loadMainModule();
|
trayApp->loadMainModule();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user