mirror of
https://github.com/iDescriptor/iDescriptor.git
synced 2026-06-22 03:45:51 +08:00
feat(ui): add NetworkDevicesToConnectWidget, update mainwindow
This commit is contained in:
+18
-14
@@ -37,6 +37,7 @@
|
||||
#include <QHBoxLayout>
|
||||
#include <QStack>
|
||||
#include <QStackedWidget>
|
||||
#include <QTimer>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <unistd.h>
|
||||
@@ -44,7 +45,7 @@
|
||||
#include "appcontext.h"
|
||||
#include "settingsmanager.h"
|
||||
// #include "devicemonitor.h"
|
||||
#include "Toast.h"
|
||||
// #include "Toast.h"
|
||||
#include "networkdevicemanager.h"
|
||||
#include "networkdeviceswidget.h"
|
||||
#include "statusballoon.h"
|
||||
@@ -414,7 +415,10 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
}
|
||||
});
|
||||
|
||||
m_deviceMonitor->start();
|
||||
/* If a device is connected before starting the app on slower machines ui
|
||||
* takes a lot of time to render so delay the monitoring a bit */
|
||||
QTimer::singleShot(std::chrono::seconds(1), this,
|
||||
[this]() { m_deviceMonitor->start(); });
|
||||
|
||||
connect(AppContext::sharedInstance(), &AppContext::deviceRemoved, this,
|
||||
[](const std::string &udid, const std::string &wifiMacAddress) {
|
||||
@@ -469,17 +473,17 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
|
||||
connect(AppContext::sharedInstance(), &AppContext::deviceHeartbeatFailed,
|
||||
this, [this](const QString &macAddress, int tries) {
|
||||
Toast *toast = new Toast(this);
|
||||
toast->setAttribute(Qt::WA_DeleteOnClose);
|
||||
toast->setDuration(8000); // Hide after 8 seconds
|
||||
toast->setTitle("Heartbeat failed");
|
||||
toast->setText(
|
||||
QString("Heartbeat failed for device with MAC %1. "
|
||||
"Number of failed attempts: %2")
|
||||
.arg(macAddress)
|
||||
.arg(tries));
|
||||
toast->setPosition(ToastPosition::BOTTOM_MIDDLE);
|
||||
toast->show();
|
||||
// Toast *toast = new Toast(this);
|
||||
// toast->setAttribute(Qt::WA_DeleteOnClose);
|
||||
// toast->setDuration(8000); // Hide after 8 seconds
|
||||
// toast->setTitle("Heartbeat failed");
|
||||
// toast->setText(
|
||||
// QString("Heartbeat failed for device with MAC %1. "
|
||||
// "Number of failed attempts: %2")
|
||||
// .arg(macAddress)
|
||||
// .arg(tries));
|
||||
// toast->setPosition(ToastPosition::BOTTOM_MIDDLE);
|
||||
// toast->show();
|
||||
});
|
||||
|
||||
// NetworkDevicesWidget *m_networkDevicesWidget = new
|
||||
@@ -532,7 +536,7 @@ MainWindow::~MainWindow()
|
||||
delete ui;
|
||||
m_deviceMonitor->requestInterruption();
|
||||
// FIXME:QThread: Destroyed while thread '' is still running
|
||||
// m_deviceMonitor->wait();
|
||||
// m_deviceMonitor->wait();
|
||||
delete m_deviceMonitor;
|
||||
// delete m_updater;
|
||||
// sleep(2);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "networkdevicemanager.h"
|
||||
#include <QTimer>
|
||||
|
||||
NetworkDeviceManager *NetworkDeviceManager::sharedInstance()
|
||||
{
|
||||
@@ -23,6 +24,7 @@ NetworkDeviceManager::NetworkDeviceManager(QObject *parent) : QObject{parent}
|
||||
&NetworkDeviceManager::deviceRemoved);
|
||||
#endif
|
||||
|
||||
// Start scanning for network devices
|
||||
m_networkProvider->startBrowsing();
|
||||
/* Helps main ui load a litte faster */
|
||||
QTimer::singleShot(std::chrono::seconds(1), this,
|
||||
[this]() { m_networkProvider->startBrowsing(); });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* iDescriptor: A free and open-source idevice management tool.
|
||||
*
|
||||
* Copyright (C) 2025 Uncore <https://github.com/uncor3>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "networkdevicestoconnectwidget.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include "core/services/avahi/avahi_service.h"
|
||||
#else
|
||||
#include "core/services/dnssd/dnssd_service.h"
|
||||
#endif
|
||||
|
||||
#include "appcontext.h"
|
||||
#include <QApplication>
|
||||
#include <QFrame>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPalette>
|
||||
#include <QPushButton>
|
||||
|
||||
NetworkDevicesToConnectWidget::NetworkDevicesToConnectWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setupUI();
|
||||
|
||||
#ifdef __linux__
|
||||
m_networkProvider = new AvahiService(this);
|
||||
connect(m_networkProvider, &AvahiService::deviceAdded, this,
|
||||
&NetworkDevicesToConnectWidget::onWirelessDeviceAdded);
|
||||
connect(m_networkProvider, &AvahiService::deviceRemoved, this,
|
||||
&NetworkDevicesToConnectWidget::onWirelessDeviceRemoved);
|
||||
#else
|
||||
m_networkProvider = new DnssdService(this);
|
||||
connect(m_networkProvider, &DnssdService::deviceAdded, this,
|
||||
&NetworkDevicesToConnectWidget::onWirelessDeviceAdded);
|
||||
connect(m_networkProvider, &DnssdService::deviceRemoved, this,
|
||||
&NetworkDevicesToConnectWidget::onWirelessDeviceRemoved);
|
||||
#endif
|
||||
|
||||
// Start scanning for network devices
|
||||
m_networkProvider->startBrowsing();
|
||||
|
||||
// Initial device list update
|
||||
updateDeviceList();
|
||||
}
|
||||
|
||||
NetworkDevicesToConnectWidget::~NetworkDevicesToConnectWidget()
|
||||
{
|
||||
if (m_networkProvider) {
|
||||
m_networkProvider->stopBrowsing();
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkDevicesToConnectWidget::setupUI()
|
||||
{
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setContentsMargins(10, 10, 10, 10);
|
||||
mainLayout->setSpacing(10);
|
||||
|
||||
// Status label
|
||||
m_statusLabel = new QLabel("Scanning for network devices...");
|
||||
QFont statusFont = m_statusLabel->font();
|
||||
statusFont.setPointSize(12);
|
||||
statusFont.setWeight(QFont::Medium);
|
||||
m_statusLabel->setFont(statusFont);
|
||||
m_statusLabel->setAlignment(Qt::AlignCenter);
|
||||
mainLayout->addWidget(m_statusLabel);
|
||||
|
||||
// Device group
|
||||
m_deviceGroup = new QGroupBox("Network Devices");
|
||||
QFont groupFont = m_deviceGroup->font();
|
||||
groupFont.setPointSize(14);
|
||||
groupFont.setWeight(QFont::Bold);
|
||||
m_deviceGroup->setFont(groupFont);
|
||||
|
||||
QVBoxLayout *groupLayout = new QVBoxLayout(m_deviceGroup);
|
||||
groupLayout->setContentsMargins(5, 15, 5, 5);
|
||||
groupLayout->setSpacing(0);
|
||||
|
||||
// Scroll area
|
||||
m_scrollArea = new QScrollArea();
|
||||
m_scrollArea->setWidgetResizable(true);
|
||||
m_scrollArea->setMinimumHeight(200);
|
||||
m_scrollArea->setMaximumHeight(400);
|
||||
m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
m_scrollArea->setStyleSheet(
|
||||
"QScrollArea { background: transparent; border: none; }");
|
||||
/* FIXME: We need a better approach to theme awareness */
|
||||
connect(qApp, &QApplication::paletteChanged, this, [this]() {
|
||||
m_scrollArea->setStyleSheet(
|
||||
"QScrollArea { background: transparent; border: none; }");
|
||||
});
|
||||
|
||||
// Scroll content
|
||||
m_scrollContent = new QWidget();
|
||||
m_scrollContent->setContentsMargins(0, 0, 0, 0);
|
||||
m_deviceLayout = new QVBoxLayout(m_scrollContent);
|
||||
m_deviceLayout->setContentsMargins(5, 5, 5, 5);
|
||||
m_deviceLayout->setSpacing(8);
|
||||
m_deviceLayout->addStretch();
|
||||
|
||||
m_scrollArea->setWidget(m_scrollContent);
|
||||
groupLayout->addWidget(m_scrollArea);
|
||||
|
||||
mainLayout->addWidget(m_deviceGroup);
|
||||
mainLayout->addStretch();
|
||||
}
|
||||
|
||||
void NetworkDevicesToConnectWidget::createDeviceCard(
|
||||
const NetworkDevice &device)
|
||||
{
|
||||
// Main card frame
|
||||
QWidget *card = new QWidget();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void NetworkDevicesToConnectWidget::clearDeviceCards()
|
||||
{
|
||||
for (QWidget *card : m_deviceCards) {
|
||||
card->deleteLater();
|
||||
}
|
||||
m_deviceCards.clear();
|
||||
}
|
||||
|
||||
void NetworkDevicesToConnectWidget::updateDeviceList()
|
||||
{
|
||||
clearDeviceCards();
|
||||
|
||||
QList<NetworkDevice> devices = m_networkProvider->getNetworkDevices();
|
||||
|
||||
if (devices.isEmpty()) {
|
||||
m_statusLabel->setText("No network devices found");
|
||||
} else {
|
||||
m_statusLabel->setText(
|
||||
QString("Found %1 network device(s)").arg(devices.count()));
|
||||
|
||||
for (const NetworkDevice &device : devices) {
|
||||
createDeviceCard(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkDevicesToConnectWidget::onWirelessDeviceAdded(
|
||||
const NetworkDevice &device)
|
||||
{
|
||||
createDeviceCard(device);
|
||||
|
||||
// Update status
|
||||
int deviceCount = m_deviceCards.count();
|
||||
m_statusLabel->setText(
|
||||
QString("Found %1 network device(s)").arg(deviceCount));
|
||||
}
|
||||
|
||||
void NetworkDevicesToConnectWidget::onWirelessDeviceRemoved(
|
||||
const QString &deviceName)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// Update status
|
||||
int deviceCount = m_deviceCards.count();
|
||||
if (deviceCount == 0) {
|
||||
m_statusLabel->setText("No network devices found");
|
||||
} else {
|
||||
m_statusLabel->setText(
|
||||
QString("Found %1 network device(s)").arg(deviceCount));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* iDescriptor: A free and open-source idevice management tool.
|
||||
*
|
||||
* Copyright (C) 2025 Uncore <https://github.com/uncor3>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NETWORKDEVICESTOCONNECTWIDGET_H
|
||||
#define NETWORKDEVICESTOCONNECTWIDGET_H
|
||||
|
||||
#ifdef __linux__
|
||||
#include "core/services/avahi/avahi_service.h"
|
||||
#else
|
||||
#include "core/services/dnssd/dnssd_service.h"
|
||||
#endif
|
||||
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
class NetworkDevicesToConnectWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit NetworkDevicesToConnectWidget(QWidget *parent = nullptr);
|
||||
~NetworkDevicesToConnectWidget();
|
||||
|
||||
private slots:
|
||||
void onWirelessDeviceAdded(const NetworkDevice &device);
|
||||
void onWirelessDeviceRemoved(const QString &deviceName);
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
void createDeviceCard(const NetworkDevice &device);
|
||||
void clearDeviceCards();
|
||||
void updateDeviceList();
|
||||
|
||||
QGroupBox *m_deviceGroup = nullptr;
|
||||
QScrollArea *m_scrollArea = nullptr;
|
||||
QWidget *m_scrollContent = nullptr;
|
||||
QVBoxLayout *m_deviceLayout = nullptr;
|
||||
QLabel *m_statusLabel = nullptr;
|
||||
|
||||
#ifdef __linux__
|
||||
AvahiService *m_networkProvider = nullptr;
|
||||
#else
|
||||
DnssdService *m_networkProvider = nullptr;
|
||||
#endif
|
||||
|
||||
QList<QWidget *> m_deviceCards;
|
||||
};
|
||||
|
||||
#endif // NETWORKDEVICESTOCONNECTWIDGET_H
|
||||
@@ -79,8 +79,9 @@ void ToolboxWidget::setupUI()
|
||||
m_scrollArea = new QScrollArea();
|
||||
m_scrollArea->setWidgetResizable(true);
|
||||
m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_scrollArea->setFrameStyle(QFrame::NoFrame);
|
||||
m_scrollArea->viewport()->setAutoFillBackground(false);
|
||||
m_scrollArea->setStyleSheet(
|
||||
"QScrollArea { background: transparent; border: none; }");
|
||||
m_scrollArea->viewport()->setStyleSheet("background: transparent;");
|
||||
|
||||
m_contentWidget = new QWidget();
|
||||
QVBoxLayout *contentLayout = new QVBoxLayout(m_contentWidget);
|
||||
|
||||
+16
-1
@@ -21,6 +21,7 @@
|
||||
#include "diagnosewidget.h"
|
||||
#include "iDescriptor-ui.h"
|
||||
#include "iDescriptor.h"
|
||||
#include "networkdevicestoconnectwidget.h"
|
||||
#include "responsiveqlabel.h"
|
||||
#include <QApplication>
|
||||
#include <QDesktopServices>
|
||||
@@ -53,6 +54,8 @@ void WelcomeWidget::setupUI()
|
||||
QPalette palette = m_subtitleLabel->palette();
|
||||
m_mainLayout->addWidget(m_subtitleLabel);
|
||||
|
||||
QHBoxLayout *imageAndWirelessDevicesLayout = new QHBoxLayout();
|
||||
|
||||
m_imageLabel = new ResponsiveQLabel();
|
||||
m_imageLabel->setPixmap(QPixmap(":/resources/connect.png"));
|
||||
m_imageLabel->setScaledContents(true);
|
||||
@@ -61,7 +64,19 @@ void WelcomeWidget::setupUI()
|
||||
m_imageLabel->setStyleSheet("background: transparent; border: none;");
|
||||
|
||||
m_imageLabel->setAlignment(Qt::AlignCenter);
|
||||
m_mainLayout->addWidget(m_imageLabel, 0, Qt::AlignHCenter);
|
||||
|
||||
imageAndWirelessDevicesLayout->addStretch(1);
|
||||
// m_imageLabel->setMaximumWidth(300);
|
||||
imageAndWirelessDevicesLayout->addWidget(m_imageLabel, 0, Qt::AlignHCenter);
|
||||
imageAndWirelessDevicesLayout->addStretch(1);
|
||||
NetworkDevicesToConnectWidget *networkDevicesWidget =
|
||||
new NetworkDevicesToConnectWidget();
|
||||
// FIMXE: resize original image
|
||||
networkDevicesWidget->setMinimumWidth(350);
|
||||
imageAndWirelessDevicesLayout->addWidget(networkDevicesWidget);
|
||||
imageAndWirelessDevicesLayout->addStretch(1);
|
||||
|
||||
m_mainLayout->addLayout(imageAndWirelessDevicesLayout);
|
||||
m_mainLayout->addSpacing(10);
|
||||
|
||||
m_instructionLabel = createStyledLabel(
|
||||
|
||||
Reference in New Issue
Block a user