diff --git a/src/appdownloadbasedialog.cpp b/src/appdownloadbasedialog.cpp index 2f60bdc..64b7d28 100644 --- a/src/appdownloadbasedialog.cpp +++ b/src/appdownloadbasedialog.cpp @@ -57,16 +57,8 @@ AppDownloadBaseDialog::AppDownloadBaseDialog(const QString &appName, : QDialog(parent), m_appName(appName), m_downloadProcess(nullptr), m_progressTimer(nullptr), m_bundleId(bundleId) { - // Common UI: progress bar and action button m_layout = new QVBoxLayout(this); - m_layout->setSpacing(20); - m_layout->setContentsMargins(30, 30, 30, 30); - - QLabel *nameLabel = new QLabel(appName); - nameLabel->setStyleSheet("font-size: 20px; font-weight: bold;"); - m_layout->addWidget(nameLabel); - - m_actionButton = nullptr; // Derived classes set this + m_layout->setContentsMargins(20, 20, 20, 20); } void AppDownloadBaseDialog::startDownloadProcess(const QString &bundleId, diff --git a/src/appdownloaddialog.cpp b/src/appdownloaddialog.cpp index e592ea2..1f7d2d7 100644 --- a/src/appdownloaddialog.cpp +++ b/src/appdownloaddialog.cpp @@ -18,7 +18,7 @@ */ #include "appdownloaddialog.h" -#include "Backdrop.h" +#include "BackDrop.h" #include "iDescriptor-ui.h" #include "iDescriptor.h" #include "libipatool-go.h" @@ -43,17 +43,41 @@ AppDownloadDialog::AppDownloadDialog(const QString &appName, setWindowTitle("Download " + appName + " IPA"); setModal(true); setFixedWidth(500); + setContentsMargins(0, 0, 0, 0); - m_loadingWidget = new ZLoadingWidget(this); + m_loadingWidget = new ZLoadingWidget(true, this); layout()->addWidget(m_loadingWidget); - QVBoxLayout *contentLayout = new QVBoxLayout(this); + QVBoxLayout *contentLayout = new QVBoxLayout(); contentLayout->setContentsMargins(0, 0, 0, 0); - m_bgLabel = new QLabel(); - // FIMXE: causes infinite scaling for some reason, need to investigate - // m_bgLabel->setScaledContents(true); - // m_bgLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); - // contentLayout->addWidget(m_bgLabel); + // m_bgLabel = new QLabel(); + // m_bgLabel->setScaledContents(true); + // m_bgLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + // contentLayout->addWidget(m_bgLabel); + + QHBoxLayout *cardLayout = new QHBoxLayout(); + cardLayout->setContentsMargins(20, 20, 20, 20); + contentLayout->addLayout(cardLayout); + + m_appIcon = new QLabel(); + m_appIcon->setFixedSize(64, 64); + cardLayout->addWidget(m_appIcon); + cardLayout->addSpacing(5); + QVBoxLayout *textLayout = new QVBoxLayout(); + + QLabel *nameLabel = new QLabel(appName); + nameLabel->setStyleSheet("font-size: 18px; font-weight: bold;"); + nameLabel->setWordWrap(true); + textLayout->addWidget(nameLabel); + + textLayout->addSpacing(5); + + QLabel *descLabel = new QLabel(description); + descLabel->setWordWrap(true); + descLabel->setStyleSheet("font-size: 14px; color: #666;"); + textLayout->addWidget(descLabel); + + cardLayout->addLayout(textLayout); QPointer safeThis = this; fetchAppIconFromApple( @@ -61,20 +85,17 @@ AppDownloadDialog::AppDownloadDialog(const QString &appName, [safeThis](const QPixmap &icon, const QJsonObject &appInfo) { if (auto dialog = safeThis.data()) { if (!icon.isNull()) { - QPixmap blurred = BackDrop::blurPixmap(icon, 30); - dialog->m_bgLabel->setPixmap(blurred.scaled( - dialog->size(), Qt::KeepAspectRatioByExpanding, - Qt::SmoothTransformation)); + dialog->m_appIcon->setPixmap(icon.scaled( + 64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + // QPixmap blurred = BackDrop::blurPixmap(icon, 30); + // dialog->m_bgLabel->setPixmap(blurred.scaled( + // dialog->size(), Qt::KeepAspectRatioByExpanding, + // Qt::SmoothTransformation)); } dialog->m_loadingWidget->stop(true); } }); - QLabel *descLabel = new QLabel(description); - descLabel->setWordWrap(true); - descLabel->setStyleSheet("font-size: 14px; color: #666;"); - contentLayout->insertWidget(1, descLabel); - // Directory selection UI QHBoxLayout *dirLayout = new QHBoxLayout(); QLabel *dirTextLabel = new QLabel("Save to:"); @@ -102,7 +123,7 @@ AppDownloadDialog::AppDownloadDialog(const QString &appName, }); dirLayout->addWidget(m_dirButton); - contentLayout->insertLayout(2, dirLayout); + contentLayout->addLayout(dirLayout); QHBoxLayout *buttonLayout = new QHBoxLayout(); diff --git a/src/appdownloaddialog.h b/src/appdownloaddialog.h index 2701880..2772494 100644 --- a/src/appdownloaddialog.h +++ b/src/appdownloaddialog.h @@ -35,12 +35,12 @@ public: const QString &description, QWidget *parent = nullptr); -protected: - void resizeEvent(QResizeEvent *event) override - { - QWidget::resizeEvent(event); - m_bgLabel->setFixedSize(event->size()); - } + // protected: + // void resizeEvent(QResizeEvent *event) override + // { + // QWidget::resizeEvent(event); + // m_bgLabel->setFixedSize(event->size()); + // } private slots: void onDownloadClicked(); @@ -50,7 +50,9 @@ private: QPushButton *m_dirButton; ZLabel *m_dirLabel; QString m_bundleId; + // FIXME: remove this if not needed QLabel *m_bgLabel; + QLabel *m_appIcon; ZLoadingWidget *m_loadingWidget; }; diff --git a/src/core/services/init_device.cpp b/src/core/services/init_device.cpp index 6520e02..6d63d13 100644 --- a/src/core/services/init_device.cpp +++ b/src/core/services/init_device.cpp @@ -373,6 +373,11 @@ init_idescriptor_device(const QString &udid, qDebug() << "Initializing iDescriptor device with UDID: " << udid << (isWireless ? "over wireless" : "over USB"); + if (isWireless) { + qDebug() << "Wireless args" << "IP:" << wirelessArgs.ip + << "for mac address" << udid; + } + iDescriptorInitDeviceResult result = {}; UsbmuxdConnectionHandle *usbmuxd_conn = nullptr; @@ -550,12 +555,16 @@ init_idescriptor_device(const QString &udid, result.heartbeatThread = heartbeatThread; // TODO cache pairing file path result.deviceInfo.isWireless = isWireless; + result.deviceInfo.ipAddress = wirelessArgs.ip.toStdString(); fullDeviceInfo(infoXml, afc_client, result.diagRelay.get(), result); - ::QObject::connect(heartbeatThread, &HeartbeatThread::heartbeatFailed, - AppContext::sharedInstance(), - &AppContext::heartbeatFailed); - ::QObject::connect(heartbeatThread, &HeartbeatThread::heartbeatThreadExited, - AppContext::sharedInstance(), &AppContext::removeDevice); + if (isWireless) { + ::QObject::connect(heartbeatThread, &HeartbeatThread::heartbeatFailed, + AppContext::sharedInstance(), + &AppContext::heartbeatFailed); + ::QObject::connect( + heartbeatThread, &HeartbeatThread::heartbeatThreadExited, + AppContext::sharedInstance(), &AppContext::removeDevice); + } cleanup: // Cleanup on error // FIXME: implement proper cleanup diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 9138147..416fdc9 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -360,10 +360,7 @@ MainWindow::MainWindow(QWidget *parent) // Handle device connection switch (event) { case DeviceMonitorThread::IDEVICE_DEVICE_ADD: { - /* this should never happen iDescriptor does not - support network devices but for some reason even - though we are only listening for USB devices, we - still get network devices on macOS*/ + /* never gets fired on any platform */ if (conn_type == DeviceMonitorThread::CONNECTION_NETWORK) { return; } @@ -388,11 +385,8 @@ MainWindow::MainWindow(QWidget *parent) } case DeviceMonitorThread::IDEVICE_DEVICE_PAIRED: { + /* never gets fired on any platform */ if (conn_type == DeviceMonitorThread::CONNECTION_NETWORK) { - qDebug() << "Network devices are not supported but a " - "network device was " - "received in event listener. Please report " - "this issue."; return; } qDebug() << "Device paired: " << udid; @@ -417,8 +411,14 @@ MainWindow::MainWindow(QWidget *parent) QTimer::singleShot(std::chrono::seconds(1), this, [this]() { m_deviceMonitor->start(); }); + // ═══════════════════════════════════════════════════════════════════════ + // Upgrade to wireless when a "WIRED" device is removed + // ═══════════════════════════════════════════════════════════════════════ connect(AppContext::sharedInstance(), &AppContext::deviceRemoved, this, - [](const std::string &udid, const std::string &wifiMacAddress) { + [](const std::string &udid, const std::string &wifiMacAddress, + const std::string &ipAddress, bool wasWireless) { + if (wasWireless) + return; qDebug() << "Upgrading device to wireless connection for UDID" << QString::fromStdString(udid); QMetaObject::invokeMethod( @@ -428,26 +428,14 @@ MainWindow::MainWindow(QWidget *parent) Q_ARG(DeviceMonitorThread::IdeviceConnectionType, DeviceMonitorThread::CONNECTION_NETWORK), Q_ARG(AddType, AddType::UpgradeToWireless), - Q_ARG(QString, QString::fromStdString(wifiMacAddress))); + Q_ARG(QString, QString::fromStdString(wifiMacAddress)), + Q_ARG(QString, QString::fromStdString(ipAddress))); }); connect(NetworkDeviceManager::sharedInstance(), &NetworkDeviceManager::deviceAdded, this, [this](const NetworkDevice &device) { // return; // FIXME: disable for now - const iDescriptorDevice *idevice = - AppContext::sharedInstance()->getDeviceByMacAddress( - device.macAddress); - if (idevice) { - qDebug() << "Network device matched to connected device:" - << QString::fromStdString( - idevice->deviceInfo.deviceName) - << "MAC:" << device.macAddress; - // You can now use 'idevice' as needed - } - // FIXME: both macAddress and udid can be used to get pairing - // file - if (AppContext::sharedInstance()->getDeviceByMacAddress( device.macAddress)) { qDebug() << "Prefering wired connection on device MAC:" @@ -463,9 +451,8 @@ MainWindow::MainWindow(QWidget *parent) Q_ARG(DeviceMonitorThread::IdeviceConnectionType, DeviceMonitorThread::CONNECTION_NETWORK), Q_ARG(AddType, AddType::Wireless), - Q_ARG(QString, device.macAddress)); - - // Handle network device addition if needed + Q_ARG(QString, device.macAddress), + Q_ARG(QString, device.address)); }); connect(AppContext::sharedInstance(), &AppContext::deviceHeartbeatFailed, @@ -482,15 +469,6 @@ MainWindow::MainWindow(QWidget *parent) // toast->setPosition(ToastPosition::BOTTOM_MIDDLE); // toast->show(); }); - - // NetworkDevicesWidget *m_networkDevicesWidget = new - // NetworkDevicesWidget(); - // m_networkDevicesWidget->setAttribute(Qt::WA_DeleteOnClose); - // m_networkDevicesWidget->setWindowFlag(Qt::Window); - // m_networkDevicesWidget->resize(500, 600); - // // connect(m_networkDevicesWidget, &QObject::destroyed, this, - // // [this]() { m_networkDevicesWidget = nullptr; }); - // m_networkDevicesWidget->show(); } void MainWindow::createMenus() @@ -518,9 +496,9 @@ void MainWindow::updateNoDevicesConnected() return m_mainStackedWidget->setCurrentIndex(0); // Show Welcome page } int deviceCount = AppContext::sharedInstance()->getConnectedDeviceCount(); - // m_connectedDeviceCountLabel->setText( - // "iDescriptor: " + QString::number(deviceCount) + - // (deviceCount == 1 ? " device" : " devices") + " connected"); + m_connectedDeviceCountLabel->setText( + "iDescriptor: " + QString::number(deviceCount) + + (deviceCount == 1 ? " device" : " devices") + " connected"); m_mainStackedWidget->setCurrentIndex(1); // Show device list page } diff --git a/src/networkdevicestoconnectwidget.cpp b/src/networkdevicestoconnectwidget.cpp index a08b4f3..cecd186 100644 --- a/src/networkdevicestoconnectwidget.cpp +++ b/src/networkdevicestoconnectwidget.cpp @@ -33,6 +33,90 @@ #include #include +NetworkDeviceCard::NetworkDeviceCard(const NetworkDevice &device, + QWidget *parent) + : QWidget(parent) +{ + QVBoxLayout *cardLayout = new QVBoxLayout(this); + cardLayout->setContentsMargins(12, 10, 12, 10); + cardLayout->setSpacing(4); + + // Device name (primary) + QLabel *nameLabel = new QLabel(device.name); + nameLabel->setWordWrap(true); + QFont nameFont = nameLabel->font(); + nameFont.setPointSize(13); + nameFont.setWeight(QFont::Medium); + nameLabel->setFont(nameFont); + QPalette namePalette = nameLabel->palette(); + namePalette.setColor(QPalette::WindowText, + palette().color(QPalette::WindowText)); + nameLabel->setPalette(namePalette); + + // Device info container + QWidget *infoContainer = new QWidget(); + QHBoxLayout *infoLayout = new QHBoxLayout(infoContainer); + infoLayout->setContentsMargins(0, 0, 0, 0); + infoLayout->setSpacing(12); + + // Address info + QLabel *addressLabel = new QLabel(QString("IP: %1").arg(device.address)); + QFont addressFont = addressLabel->font(); + addressFont.setPointSize(11); + addressLabel->setFont(addressFont); + QPalette addressPalette = addressLabel->palette(); + QColor secondaryColor = palette().color(QPalette::WindowText); + secondaryColor.setAlpha(180); + addressPalette.setColor(QPalette::WindowText, secondaryColor); + addressLabel->setPalette(addressPalette); + + // Port info + QLabel *portLabel = new QLabel(QString("Port: %1").arg(device.port)); + portLabel->setFont(addressFont); + portLabel->setPalette(addressPalette); + + infoLayout->addWidget(addressLabel); + infoLayout->addWidget(portLabel); + infoLayout->addStretch(); + + m_connectButton = new QPushButton("Connect"); + m_connectButton->setDefault(true); + connect(m_connectButton, &QPushButton::clicked, this, [this, device]() { + m_connectButton->setText("Connecting..."); + m_connectButton->setEnabled(false); + AppContext::sharedInstance()->tryToConnectToNetworkDevice( + device.macAddress); + }); + infoLayout->addWidget(m_connectButton); + infoLayout->addSpacing(5); + + // Status indicator + QLabel *statusIndicator = new QLabel("●"); + QFont statusFont = statusIndicator->font(); + statusFont.setPointSize(12); + statusIndicator->setFont(statusFont); + QPalette statusPalette = statusIndicator->palette(); + statusPalette.setColor(QPalette::WindowText, + QColor(52, 199, 89)); // iOS green + statusIndicator->setPalette(statusPalette); + + infoLayout->addWidget(statusIndicator); + + cardLayout->addWidget(nameLabel); + cardLayout->addWidget(infoContainer); +} + +void NetworkDeviceCard::failed() +{ + m_connectButton->setText("Failed to connect"); + m_connectButton->setEnabled(false); + + QTimer::singleShot(2000, this, [this]() { + m_connectButton->setText("Connect"); + m_connectButton->setEnabled(true); + }); +} + NetworkDevicesToConnectWidget::NetworkDevicesToConnectWidget(QWidget *parent) : QWidget(parent) { @@ -57,6 +141,12 @@ NetworkDevicesToConnectWidget::NetworkDevicesToConnectWidget(QWidget *parent) // Initial device list update updateDeviceList(); + + connect(AppContext::sharedInstance(), + &AppContext::noPairingFileForWirelessDevice, this, + &NetworkDevicesToConnectWidget::onNoPairingFileForWirelessDevice); + connect(AppContext::sharedInstance(), &AppContext::initFailed, this, + &NetworkDevicesToConnectWidget::onDeviceInitFailed); } NetworkDevicesToConnectWidget::~NetworkDevicesToConnectWidget() @@ -126,90 +216,18 @@ void NetworkDevicesToConnectWidget::createDeviceCard( const NetworkDevice &device) { // Main card frame - QWidget *card = new QWidget(); + NetworkDeviceCard *card = new NetworkDeviceCard(device); - QVBoxLayout *cardLayout = new QVBoxLayout(card); - cardLayout->setContentsMargins(12, 10, 12, 10); - cardLayout->setSpacing(4); - - // Device name (primary) - QLabel *nameLabel = new QLabel(device.name); - nameLabel->setWordWrap(true); - QFont nameFont = nameLabel->font(); - nameFont.setPointSize(13); - nameFont.setWeight(QFont::Medium); - nameLabel->setFont(nameFont); - QPalette namePalette = nameLabel->palette(); - namePalette.setColor(QPalette::WindowText, - palette().color(QPalette::WindowText)); - nameLabel->setPalette(namePalette); - - // Device info container - QWidget *infoContainer = new QWidget(); - QHBoxLayout *infoLayout = new QHBoxLayout(infoContainer); - infoLayout->setContentsMargins(0, 0, 0, 0); - infoLayout->setSpacing(12); - - // Address info - QLabel *addressLabel = new QLabel(QString("IP: %1").arg(device.address)); - QFont addressFont = addressLabel->font(); - addressFont.setPointSize(11); - addressLabel->setFont(addressFont); - QPalette addressPalette = addressLabel->palette(); - QColor secondaryColor = palette().color(QPalette::WindowText); - secondaryColor.setAlpha(180); - addressPalette.setColor(QPalette::WindowText, secondaryColor); - addressLabel->setPalette(addressPalette); - - // Port info - QLabel *portLabel = new QLabel(QString("Port: %1").arg(device.port)); - portLabel->setFont(addressFont); - portLabel->setPalette(addressPalette); - - infoLayout->addWidget(addressLabel); - infoLayout->addWidget(portLabel); - infoLayout->addStretch(); - - QPushButton *connectButton = new QPushButton("Connect"); - connectButton->setDefault(true); - connect(connectButton, &QPushButton::clicked, this, - [this, device, connectButton]() { - connectButton->setText("Connecting..."); - connectButton->setEnabled(false); - AppContext::sharedInstance()->tryToConnectToNetworkDevice( - device.macAddress); - }); - infoLayout->addWidget(connectButton); - infoLayout->addSpacing(5); - - // Status indicator - QLabel *statusIndicator = new QLabel("●"); - QFont statusFont = statusIndicator->font(); - statusFont.setPointSize(12); - statusIndicator->setFont(statusFont); - QPalette statusPalette = statusIndicator->palette(); - statusPalette.setColor(QPalette::WindowText, - QColor(52, 199, 89)); // iOS green - statusIndicator->setPalette(statusPalette); - - infoLayout->addWidget(statusIndicator); - - cardLayout->addWidget(nameLabel); - cardLayout->addWidget(infoContainer); - - // Store the device info as property for later removal - card->setProperty("deviceName", device.name); - card->setProperty("deviceAddress", device.address); - - // Insert before the stretch m_deviceLayout->insertWidget(m_deviceLayout->count() - 1, card); - m_deviceCards.append(card); + m_deviceCards[device.macAddress] = card; } void NetworkDevicesToConnectWidget::clearDeviceCards() { for (QWidget *card : m_deviceCards) { - card->deleteLater(); + if (card) { + card->deleteLater(); + } } m_deviceCards.clear(); } @@ -244,16 +262,13 @@ void NetworkDevicesToConnectWidget::onWirelessDeviceAdded( } void NetworkDevicesToConnectWidget::onWirelessDeviceRemoved( - const QString &deviceName) + const QString &macAddress) { // Find and remove the corresponding card - for (int i = 0; i < m_deviceCards.count(); ++i) { - QWidget *card = m_deviceCards[i]; - if (card->property("deviceName").toString() == deviceName) { - m_deviceCards.removeAt(i); - card->deleteLater(); - break; - } + NetworkDeviceCard *card = m_deviceCards[macAddress]; + m_deviceCards.remove(macAddress); + if (card) { + card->deleteLater(); } // Update status @@ -264,4 +279,20 @@ void NetworkDevicesToConnectWidget::onWirelessDeviceRemoved( m_statusLabel->setText( QString("Found %1 network device(s)").arg(deviceCount)); } +} + +void NetworkDevicesToConnectWidget::onNoPairingFileForWirelessDevice( + const QString &macAddress) +{ + // m_deviceCards. +} + +// udid or mac address +void NetworkDevicesToConnectWidget::onDeviceInitFailed(const QString &udid) +{ + NetworkDeviceCard *deviceCard = m_deviceCards[udid]; + if (deviceCard) { + qDebug() << "Calling failed() on device card for" << udid; + deviceCard->failed(); + } } \ No newline at end of file diff --git a/src/networkdevicestoconnectwidget.h b/src/networkdevicestoconnectwidget.h index 0f22f2b..5536495 100644 --- a/src/networkdevicestoconnectwidget.h +++ b/src/networkdevicestoconnectwidget.h @@ -28,10 +28,25 @@ #include #include +#include #include #include #include +class NetworkDeviceCard : public QWidget +{ + Q_OBJECT +public: + explicit NetworkDeviceCard(const NetworkDevice &device, + QWidget *parent = nullptr); + +private: + QPushButton *m_connectButton = nullptr; + +public: + void failed(); +}; + class NetworkDevicesToConnectWidget : public QWidget { Q_OBJECT @@ -43,6 +58,8 @@ public: private slots: void onWirelessDeviceAdded(const NetworkDevice &device); void onWirelessDeviceRemoved(const QString &deviceName); + void onNoPairingFileForWirelessDevice(const QString &macAddress); + void onDeviceInitFailed(const QString &udid); private: void setupUI(); @@ -62,7 +79,7 @@ private: DnssdService *m_networkProvider = nullptr; #endif - QList m_deviceCards; + QMap m_deviceCards; }; #endif // NETWORKDEVICESTOCONNECTWIDGET_H \ No newline at end of file