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.
This commit is contained in:
uncor3
2025-09-16 18:53:12 +00:00
parent dae024b783
commit b9bff056fd
10 changed files with 250 additions and 66 deletions
+22 -17
View File
@@ -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<RecoveryDeviceInfo *> 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)
+1 -1
View File
@@ -23,7 +23,6 @@ public:
void removeRecoveryDevice(const QString &udid);
// Returns whether there are any devices connected (regular or recovery)
bool noDevicesConnected();
QList<RecoveryDeviceInfo *> getAllRecoveryDevices();
~AppContext();
void instanceRemoveDevice(QString _udid);
@@ -31,6 +30,7 @@ public:
private:
QMap<std::string, iDescriptorDevice *> m_devices;
QMap<std::string, RecoveryDeviceInfo *> m_recoveryDevices;
QStringList m_pendingDevices;
signals:
void deviceAdded(iDescriptorDevice *device);
void deviceRemoved(const std::string &udid);
+62 -47
View File
@@ -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<DevicePendingWidget *, DevicePendingSidebarItem *> &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)
+11 -1
View File
@@ -2,6 +2,7 @@
#define DEVICEMANAGERWIDGET_H
#include "devicemenuwidget.h"
#include "devicependingwidget.h"
#include "devicesidebarwidget.h"
#include "iDescriptor.h"
#include <QHBoxLayout>
@@ -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<std::string, std::pair<DeviceMenuWidget *, DeviceSidebarItem *>>
m_deviceWidgets; // Map to store devices by UDID
QMap<std::string,
std::pair<DevicePendingWidget *, DevicePendingSidebarItem *>>
m_pendingDeviceWidgets; // Map to store devices by UDID
std::string m_currentDeviceUuid;
};
+15
View File
@@ -0,0 +1,15 @@
#include "devicependingwidget.h"
#include <QLabel>
#include <QVBoxLayout>
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);
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef DEVICEPENDINGWIDGET_H
#define DEVICEPENDINGWIDGET_H
#include <QWidget>
class DevicePendingWidget : public QWidget
{
Q_OBJECT
public:
explicit DevicePendingWidget(QWidget *parent = nullptr);
signals:
};
#endif // DEVICEPENDINGWIDGET_H
+38
View File
@@ -1,5 +1,6 @@
#include "devicesidebarwidget.h"
#include "clickablewidget.h"
#include "loadingspinnerwidget.h"
#include <QDebug>
#include <QEasingCurve>
@@ -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);
}
+15
View File
@@ -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 &section);
void updateSidebar(std::string uuid);
@@ -93,6 +107,7 @@ private:
std::string m_currentDeviceUuid;
QList<DeviceSidebarItem *> m_deviceSidebarItems;
QList<DevicePendingSidebarItem *> m_devicePendingSidebarItems;
};
#endif // DEVICESIDEBARWIDGET_H
+43
View File
@@ -0,0 +1,43 @@
#include "loadingspinnerwidget.h"
#include <QPainter>
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
}
+28
View File
@@ -0,0 +1,28 @@
#ifndef LOADINGSPINNERWIDGET_H
#define LOADINGSPINNERWIDGET_H
#include <QColor>
#include <QTimer>
#include <QWidget>
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