From b9bff056fdac8e84387bafe499885688d9cd76fa Mon Sep 17 00:00:00 2001 From: uncor3 Date: Tue, 16 Sep 2025 18:53:12 +0000 Subject: [PATCH] Refactor device management and add pending device handling - Removed unused noDevicesConnected() method and updated its logic. - Introduced DevicePendingWidget and DevicePendingSidebarItem for better UI handling of pending devices. - Updated DeviceManagerWidget to manage pending and paired devices more effectively. - Added LoadingSpinnerWidget for visual feedback during device pairing. --- src/appcontext.cpp | 39 +++++++------ src/appcontext.h | 2 +- src/devicemanagerwidget.cpp | 109 ++++++++++++++++++++--------------- src/devicemanagerwidget.h | 12 +++- src/devicependingwidget.cpp | 15 +++++ src/devicependingwidget.h | 15 +++++ src/devicesidebarwidget.cpp | 38 ++++++++++++ src/devicesidebarwidget.h | 15 +++++ src/loadingspinnerwidget.cpp | 43 ++++++++++++++ src/loadingspinnerwidget.h | 28 +++++++++ 10 files changed, 250 insertions(+), 66 deletions(-) create mode 100644 src/devicependingwidget.cpp create mode 100644 src/devicependingwidget.h create mode 100644 src/loadingspinnerwidget.cpp create mode 100644 src/loadingspinnerwidget.h diff --git a/src/appcontext.cpp b/src/appcontext.cpp index 30f76d7..35a3f40 100644 --- a/src/appcontext.cpp +++ b/src/appcontext.cpp @@ -34,11 +34,6 @@ AppContext::AppContext(QObject *parent) : QObject{parent} // } } -bool AppContext::noDevicesConnected() const -{ - return (m_devices.isEmpty() && m_recoveryDevices.isEmpty()); -} - void AppContext::handleDBusSignal(const QDBusMessage &msg) { if (msg.arguments().isEmpty()) { @@ -72,9 +67,8 @@ void AppContext::addDevice(QString udid, idevice_connection_type conn_type, IDescriptorInitDeviceResult initResult = init_idescriptor_device(udid.toStdString().c_str()); - qDebug() << "Device initialized: " << udid; - - qDebug() << "Success: " << initResult.success; + qDebug() << "init_idescriptor_device success ?: " << initResult.success; + qDebug() << "init_idescriptor_device error code: " << initResult.error; if (!initResult.success) { qDebug() << "Failed to initialize device with UDID: " << udid; @@ -88,13 +82,20 @@ void AppContext::addDevice(QString udid, idevice_connection_type conn_type, // the reason why we don't handle pairing devices here is // because it's less likely that it will be an error typeof // LOCKDOWN_E_PASSWORD_PROTECTED if the device is paired type - if (addType == AddType::Regular) - emit devicePairPending(udid); - } else if (initResult.error == LOCKDOWN_E_INVALID_HOST_ID) { - warn("Device with UDID " + udid + - " is not trusted. Please trust this computer on the " - "device and try again.", - "Warning"); + if (addType == AddType::Regular) { // TODO:IMPLEMENT + // emit devicePasswordProtected(udid); + }; + } else if (initResult.error == + LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING) { + m_pendingDevices.append(udid); + // FIXME: if a device never gets paired, it will stay in this + // list forever + emit devicePairPending(udid); + + // warn("Device with UDID " + udid + + // " is not trusted. Please trust this computer on the + // " "device and try again.", + // "Warning"); } else { warn("Failed to initialize device with UDID " + udid + ". Error code: " + QString::number(initResult.error), @@ -102,6 +103,8 @@ void AppContext::addDevice(QString udid, idevice_connection_type conn_type, } return; } + qDebug() << "Device initialized: " << udid; + iDescriptorDevice *device = new iDescriptorDevice{ .udid = udid.toStdString(), .conn_type = conn_type, @@ -113,6 +116,7 @@ void AppContext::addDevice(QString udid, idevice_connection_type conn_type, if (addType == AddType::Regular) return emit deviceAdded(device); emit devicePaired(device); + m_pendingDevices.removeAll(udid); } catch (const std::exception &e) { qDebug() << "Exception in onDeviceAdded: " << e.what(); @@ -214,9 +218,10 @@ QList AppContext::getAllRecoveryDevices() } // Returns whether there are any devices connected (regular or recovery) -bool AppContext::noDevicesConnected() +bool AppContext::noDevicesConnected() const { - return (m_devices.isEmpty() && m_recoveryDevices.isEmpty()); + return (m_devices.isEmpty() && m_recoveryDevices.isEmpty() && + m_pendingDevices.isEmpty()); } std::string AppContext::addRecoveryDevice(RecoveryDeviceInfo *deviceInfo) diff --git a/src/appcontext.h b/src/appcontext.h index 8c3499c..f330187 100644 --- a/src/appcontext.h +++ b/src/appcontext.h @@ -23,7 +23,6 @@ public: void removeRecoveryDevice(const QString &udid); // Returns whether there are any devices connected (regular or recovery) - bool noDevicesConnected(); QList getAllRecoveryDevices(); ~AppContext(); void instanceRemoveDevice(QString _udid); @@ -31,6 +30,7 @@ public: private: QMap m_devices; QMap m_recoveryDevices; + QStringList m_pendingDevices; signals: void deviceAdded(iDescriptorDevice *device); void deviceRemoved(const std::string &udid); diff --git a/src/devicemanagerwidget.cpp b/src/devicemanagerwidget.cpp index 6cce9e7..52567c3 100644 --- a/src/devicemanagerwidget.cpp +++ b/src/devicemanagerwidget.cpp @@ -21,50 +21,17 @@ DeviceManagerWidget::DeviceManagerWidget(QWidget *parent) emit updateNoDevicesConnected(); }); - // TODO: doesnt seem to work - // connect( - // AppContext::sharedInstance(), &AppContext::devicePairPending, this, - // [this](const QString &udid) { - // QWidget *placeholderWidget = new QWidget(); - // QVBoxLayout *layout = new QVBoxLayout(placeholderWidget); - // QLabel *label = new QLabel( - // "Device is not paired. Please pair the device to continue."); - // label->setAlignment(Qt::AlignCenter); - // layout->addWidget(label); - // placeholderWidget->setLayout(layout); - // m_device_menu_widgets[udid.toStdString()] = placeholderWidget; + connect(AppContext::sharedInstance(), &AppContext::devicePairPending, this, + [this](const QString &udid) { + addPendingDevice(udid); + emit updateNoDevicesConnected(); + }); - // QString tabTitle = QString::fromStdString(udid.toStdString()); - // int mostRecentDevice = - // m_deviceManager->addDevice(placeholderWidget, tabTitle); - // m_deviceManager->setCurrentDevice(mostRecentDevice); - // ui->stackedWidget->setCurrentIndex(1); // Show device list page - // }); - - // TODO: could use some refactoring - // connect(AppContext::sharedInstance(), &AppContext::devicePaired, this, - // [this](iDescriptorDevice *device) { - // qDebug() << "Device paired:" - // << QString::fromStdString(device->udid); - - // DeviceMenuWidget *deviceWidget = new - // DeviceMenuWidget(device); - - // QString tabTitle = - // QString::fromStdString(device->deviceInfo.productType); - - // int mostRecentDevice = - // addDevice(deviceWidget, tabTitle); - // setCurrentDevice(mostRecentDevice); - // // Makes sense ? - // // emit updateNoDevicesConnected() - - // // Clean up old mapping and update - // if (m_device_menu_widgets.count(device->udid)) { - // m_device_menu_widgets[device->udid]->deleteLater(); - // } - // m_device_menu_widgets[device->udid] = deviceWidget; - // }); + connect(AppContext::sharedInstance(), &AppContext::devicePaired, this, + [this](iDescriptorDevice *device) { + addPairedDevice(device); + emit updateNoDevicesConnected(); + }); // connect(AppContext::sharedInstance(), &AppContext::recoveryDeviceRemoved, // this, [this](const QString &ecid) { @@ -107,16 +74,20 @@ void DeviceManagerWidget::setupUI() &DeviceManagerWidget::onSidebarNavigationChanged); } -int DeviceManagerWidget::addDevice(iDescriptorDevice *device) +void DeviceManagerWidget::addDevice(iDescriptorDevice *device) { - + if (m_deviceWidgets.contains(device->udid)) { + qWarning() << "Device already exists:" + << QString::fromStdString(device->udid); + return; + } qDebug() << "Connect ::deviceAdded Adding:" << QString::fromStdString(device->udid); DeviceMenuWidget *deviceWidget = new DeviceMenuWidget(device, this); QString tabTitle = QString::fromStdString(device->deviceInfo.productType); - int deviceIndex = m_stackedWidget->addWidget(deviceWidget); + m_stackedWidget->addWidget(deviceWidget); m_deviceWidgets[device->udid] = std::pair{ deviceWidget, m_sidebar->addToSidebar(tabTitle, device->udid)}; @@ -124,8 +95,52 @@ int DeviceManagerWidget::addDevice(iDescriptorDevice *device) // if (m_currentDeviceIndex == -1) { // setCurrentDevice(deviceIndex); // } +} - return deviceIndex; +void DeviceManagerWidget::addPendingDevice(const QString &udid) +{ + qDebug() << "Adding pending device:" << udid; + + DevicePendingWidget *pendingWidget = new DevicePendingWidget(this); + + m_stackedWidget->addWidget(pendingWidget); + m_pendingDeviceWidgets[udid.toStdString()] = + std::pair{pendingWidget, m_sidebar->addPendingToSidebar(udid)}; + + // If this is the first device, make it current + // if (m_currentDeviceIndex == -1) { + // setCurrentDevice(deviceIndex); + // } +} + +void DeviceManagerWidget::addPairedDevice(iDescriptorDevice *device) +{ + qDebug() << "Device paired:" << QString::fromStdString(device->udid); + + // Check if pending device exists + if (m_pendingDeviceWidgets.contains(device->udid)) { + std::pair &pair = + m_pendingDeviceWidgets[device->udid]; + + // Remove from sidebar if it exists + if (pair.second) { + qDebug() << "Removing pending device from sidebar:" + << QString::fromStdString(device->udid); + m_sidebar->removePendingFromSidebar(pair.second); + } + + // Clean up widget if it exists + if (pair.first) { + qDebug() << "Removing pending device widget:" + << QString::fromStdString(device->udid); + m_stackedWidget->removeWidget(pair.first); + pair.first->deleteLater(); + } + + m_pendingDeviceWidgets.remove(device->udid); + } + + addDevice(device); } void DeviceManagerWidget::removeDevice(const std::string &uuid) diff --git a/src/devicemanagerwidget.h b/src/devicemanagerwidget.h index 78c938d..6dde9e6 100644 --- a/src/devicemanagerwidget.h +++ b/src/devicemanagerwidget.h @@ -2,6 +2,7 @@ #define DEVICEMANAGERWIDGET_H #include "devicemenuwidget.h" +#include "devicependingwidget.h" #include "devicesidebarwidget.h" #include "iDescriptor.h" #include @@ -16,7 +17,11 @@ class DeviceManagerWidget : public QWidget public: explicit DeviceManagerWidget(QWidget *parent = nullptr); - int addDevice(iDescriptorDevice *device); + void addDevice(iDescriptorDevice *device); + // TODO:udid or uuid ? + void addPendingDevice(const QString &udid); + void addPairedDevice(iDescriptorDevice *device); + void removeDevice(const std::string &uuid); void setCurrentDevice(const std::string &uuid); std::string getCurrentDevice() const; @@ -46,6 +51,11 @@ private: QMap> m_deviceWidgets; // Map to store devices by UDID + + QMap> + m_pendingDeviceWidgets; // Map to store devices by UDID + std::string m_currentDeviceUuid; }; diff --git a/src/devicependingwidget.cpp b/src/devicependingwidget.cpp new file mode 100644 index 0000000..b186257 --- /dev/null +++ b/src/devicependingwidget.cpp @@ -0,0 +1,15 @@ +#include "devicependingwidget.h" +#include +#include + +DevicePendingWidget::DevicePendingWidget(QWidget *parent) : QWidget{parent} +{ + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(5); + + QLabel *label = new QLabel("Please click on trust on the popup", this); + + layout->addWidget(label); + setLayout(layout); +} diff --git a/src/devicependingwidget.h b/src/devicependingwidget.h new file mode 100644 index 0000000..9cd43e8 --- /dev/null +++ b/src/devicependingwidget.h @@ -0,0 +1,15 @@ +#ifndef DEVICEPENDINGWIDGET_H +#define DEVICEPENDINGWIDGET_H + +#include + +class DevicePendingWidget : public QWidget +{ + Q_OBJECT +public: + explicit DevicePendingWidget(QWidget *parent = nullptr); + +signals: +}; + +#endif // DEVICEPENDINGWIDGET_H diff --git a/src/devicesidebarwidget.cpp b/src/devicesidebarwidget.cpp index 76a74f5..3039dce 100644 --- a/src/devicesidebarwidget.cpp +++ b/src/devicesidebarwidget.cpp @@ -1,5 +1,6 @@ #include "devicesidebarwidget.h" #include "clickablewidget.h" +#include "loadingspinnerwidget.h" #include #include @@ -266,6 +267,24 @@ DeviceSidebarItem *DeviceSidebarWidget::addToSidebar(const QString &deviceName, return item; } +DevicePendingSidebarItem * +DeviceSidebarWidget::addPendingToSidebar(const QString &uuid) +{ + DevicePendingSidebarItem *item = new DevicePendingSidebarItem(uuid, this); + m_devicePendingSidebarItems.append(item); + m_contentLayout->insertWidget(m_contentLayout->count() - 1, + item); // Insert before stretch + return item; +} + +void DeviceSidebarWidget::removePendingFromSidebar( + DevicePendingSidebarItem *item) +{ + m_devicePendingSidebarItems.removeAll(item); + m_contentLayout->removeWidget(item); + item->deleteLater(); +} + void DeviceSidebarWidget::setCurrentDevice(std::string uuid) { if (m_currentDeviceUuid == uuid) @@ -328,4 +347,23 @@ void DeviceSidebarWidget::updateSelection() for (DeviceSidebarItem *item : m_deviceSidebarItems) { item->setSelected(item->getDeviceUuid() == m_currentDeviceUuid); } +} + +DevicePendingSidebarItem::DevicePendingSidebarItem(const QString &udid, + QWidget *parent) + : QFrame(parent) +{ + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(5); + + LoadingSpinnerWidget *spinner = new LoadingSpinnerWidget(this); + spinner->setFixedSize(16, 16); // Make it a bit smaller + spinner->setColor(QColor("#0d6efd")); // Use a theme color + + QLabel *label = new QLabel("Pairing...", this); + layout->addWidget(label); + layout->addWidget(spinner); + + setLayout(layout); } \ No newline at end of file diff --git a/src/devicesidebarwidget.h b/src/devicesidebarwidget.h index e7bc866..dd89365 100644 --- a/src/devicesidebarwidget.h +++ b/src/devicesidebarwidget.h @@ -61,6 +61,18 @@ private: QPropertyAnimation *m_collapseAnimation; }; +#ifndef DEVICEPENDINGSIDEBARITEM_H +#define DEVICEPENDINGSIDEBARITEM_H +class DevicePendingSidebarItem : public QFrame +{ + Q_OBJECT +public: + explicit DevicePendingSidebarItem(const QString &deviceName, + QWidget *parent = nullptr); +signals: +}; +#endif // DEVICEPENDINGSIDEBARITEM_H + class DeviceSidebarWidget : public QWidget { Q_OBJECT @@ -72,6 +84,8 @@ public: DeviceSidebarItem *addToSidebar(const QString &deviceName, const std::string &uuid); + DevicePendingSidebarItem *addPendingToSidebar(const QString &uuid); + void removePendingFromSidebar(DevicePendingSidebarItem *item); void setDeviceNavigationSection(int deviceIndex, const QString §ion); void updateSidebar(std::string uuid); @@ -93,6 +107,7 @@ private: std::string m_currentDeviceUuid; QList m_deviceSidebarItems; + QList m_devicePendingSidebarItems; }; #endif // DEVICESIDEBARWIDGET_H \ No newline at end of file diff --git a/src/loadingspinnerwidget.cpp b/src/loadingspinnerwidget.cpp new file mode 100644 index 0000000..f5222fb --- /dev/null +++ b/src/loadingspinnerwidget.cpp @@ -0,0 +1,43 @@ +#include "loadingspinnerwidget.h" +#include + +LoadingSpinnerWidget::LoadingSpinnerWidget(QWidget *parent) + : QWidget(parent), m_angle(0), m_color(Qt::gray) +{ + connect(&m_timer, &QTimer::timeout, this, + &LoadingSpinnerWidget::updateRotation); + m_timer.setInterval(15); // Update every 15ms for smooth animation + m_timer.start(); + setFixedSize(24, 24); // Default size +} + +void LoadingSpinnerWidget::setColor(const QColor &color) +{ + m_color = color; + update(); // Trigger a repaint with the new color +} + +void LoadingSpinnerWidget::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event); + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + + int penWidth = 2; + QRectF rect(penWidth / 2.0, penWidth / 2.0, width() - penWidth, + height() - penWidth); + + QPen pen(m_color); + pen.setWidth(penWidth); + pen.setCapStyle(Qt::RoundCap); + painter.setPen(pen); + + // Draw a 270-degree arc, rotating the start angle + painter.drawArc(rect, m_angle * 16, 270 * 16); +} + +void LoadingSpinnerWidget::updateRotation() +{ + m_angle = (m_angle + 10) % 360; + update(); // Schedule a repaint +} \ No newline at end of file diff --git a/src/loadingspinnerwidget.h b/src/loadingspinnerwidget.h new file mode 100644 index 0000000..289aff7 --- /dev/null +++ b/src/loadingspinnerwidget.h @@ -0,0 +1,28 @@ +#ifndef LOADINGSPINNERWIDGET_H +#define LOADINGSPINNERWIDGET_H + +#include +#include +#include + +class LoadingSpinnerWidget : public QWidget +{ + Q_OBJECT + +public: + explicit LoadingSpinnerWidget(QWidget *parent = nullptr); + void setColor(const QColor &color); + +protected: + void paintEvent(QPaintEvent *event) override; + +private slots: + void updateRotation(); + +private: + QTimer m_timer; + int m_angle; + QColor m_color; +}; + +#endif // LOADINGSPINNERWIDGET_H \ No newline at end of file