mirror of
https://github.com/iDescriptor/iDescriptor.git
synced 2026-06-22 03:45:51 +08:00
393 lines
13 KiB
C++
393 lines
13 KiB
C++
/*
|
|
* 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"
|
|
|
|
#include "appcontext.h"
|
|
#include <QApplication>
|
|
#include <QFrame>
|
|
#include <QHBoxLayout>
|
|
#include <QLabel>
|
|
#include <QPalette>
|
|
#include <QPushButton>
|
|
#include <QTimer>
|
|
|
|
NetworkDeviceCard::NetworkDeviceCard(const NetworkDevice &device,
|
|
QWidget *parent)
|
|
: QWidget(parent), m_device(device)
|
|
{
|
|
QVBoxLayout *cardLayout = new QVBoxLayout(this);
|
|
cardLayout->setContentsMargins(12, 10, 12, 10);
|
|
cardLayout->setSpacing(4);
|
|
|
|
// Device name
|
|
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);
|
|
});
|
|
infoLayout->addWidget(m_connectButton);
|
|
infoLayout->addSpacing(5);
|
|
|
|
QLabel *statusIndicator = new QLabel("●");
|
|
statusIndicator->setStyleSheet(
|
|
QString("QLabel { font-size: 14px; color: %1; }")
|
|
#ifdef WIN32
|
|
.arg(COLOR_ACCENT_BLUE.name()));
|
|
#else
|
|
.arg(COLOR_GREEN.name()));
|
|
#endif
|
|
|
|
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);
|
|
});
|
|
}
|
|
|
|
void NetworkDeviceCard::noPairingFile()
|
|
{
|
|
// TODO: add a button or hint to explain how to create a pairing file for
|
|
// this device
|
|
m_connectButton->setText("No pairing file");
|
|
m_connectButton->setEnabled(false);
|
|
|
|
QTimer::singleShot(5000, this, [this]() {
|
|
m_connectButton->setText("Connect");
|
|
m_connectButton->setEnabled(true);
|
|
});
|
|
}
|
|
|
|
void NetworkDeviceCard::connected()
|
|
{
|
|
m_connectButton->setText("Connected");
|
|
m_connectButton->setEnabled(false);
|
|
|
|
QTimer::singleShot(10000, this, [this]() {
|
|
m_connectButton->setText("Connect");
|
|
m_connectButton->setEnabled(true);
|
|
});
|
|
}
|
|
|
|
void NetworkDeviceCard::alreadyExists()
|
|
{
|
|
m_connectButton->setText("Already connected");
|
|
m_connectButton->setEnabled(false);
|
|
|
|
QTimer::singleShot(3000, this, [this]() {
|
|
m_connectButton->setText("Connect");
|
|
m_connectButton->setEnabled(true);
|
|
});
|
|
}
|
|
|
|
void NetworkDeviceCard::initStarted()
|
|
{
|
|
m_connectButton->setText("Connecting...");
|
|
m_connectButton->setEnabled(false);
|
|
}
|
|
|
|
NetworkDevicesToConnectWidget::NetworkDevicesToConnectWidget(QWidget *parent)
|
|
: QWidget(parent)
|
|
{
|
|
setupUI();
|
|
|
|
connect(NetworkDeviceProvider::sharedInstance(),
|
|
&NetworkDeviceProvider::deviceAdded, this,
|
|
&NetworkDevicesToConnectWidget::onWirelessDeviceAdded);
|
|
connect(NetworkDeviceProvider::sharedInstance(),
|
|
&NetworkDeviceProvider::deviceRemoved, this,
|
|
&NetworkDevicesToConnectWidget::onWirelessDeviceRemoved);
|
|
|
|
updateDeviceList();
|
|
|
|
// in case the backend fails to find pairing file
|
|
connect(AppContext::sharedInstance()->core, &CXX::Core::no_pairing_file,
|
|
this,
|
|
&NetworkDevicesToConnectWidget::onNoPairingFileForWirelessDevice);
|
|
|
|
connect(AppContext::sharedInstance(),
|
|
&AppContext::noPairingFileForWirelessDevice, this,
|
|
&NetworkDevicesToConnectWidget::onNoPairingFileForWirelessDevice);
|
|
|
|
connect(AppContext::sharedInstance()->core, &CXX::Core::init_failed, this,
|
|
&NetworkDevicesToConnectWidget::onDeviceInitFailed);
|
|
connect(AppContext::sharedInstance(), &AppContext::initStarted, this,
|
|
&NetworkDevicesToConnectWidget::onDeviceInitStarted);
|
|
connect(AppContext::sharedInstance(), &AppContext::deviceAdded, this,
|
|
&NetworkDevicesToConnectWidget::onDeviceAdded);
|
|
connect(AppContext::sharedInstance(), &AppContext::deviceAlreadyExistsMAC,
|
|
this, &NetworkDevicesToConnectWidget::onDeviceAlreadyExists);
|
|
|
|
// eval interval
|
|
QTimer *evalTimer = new QTimer(this);
|
|
connect(evalTimer, &QTimer::timeout, this,
|
|
&NetworkDevicesToConnectWidget::eval);
|
|
evalTimer->start(30000); // evaluate every 30 seconds
|
|
}
|
|
|
|
NetworkDevicesToConnectWidget::~NetworkDevicesToConnectWidget() {}
|
|
|
|
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->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
|
m_scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
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, 1);
|
|
|
|
mainLayout->addWidget(m_deviceGroup, 1);
|
|
}
|
|
|
|
void NetworkDevicesToConnectWidget::createDeviceCard(
|
|
const NetworkDevice &device)
|
|
{
|
|
NetworkDeviceCard *card = new NetworkDeviceCard(device);
|
|
|
|
m_deviceLayout->insertWidget(m_deviceLayout->count() - 1, card);
|
|
m_deviceCards[device.macAddress] = card;
|
|
}
|
|
|
|
void NetworkDevicesToConnectWidget::clearDeviceCards()
|
|
{
|
|
for (QWidget *card : m_deviceCards) {
|
|
if (card) {
|
|
card->deleteLater();
|
|
}
|
|
}
|
|
m_deviceCards.clear();
|
|
}
|
|
void NetworkDevicesToConnectWidget::updateDeviceList()
|
|
{
|
|
clearDeviceCards();
|
|
|
|
QMap<QString, NetworkDevice> devices =
|
|
NetworkDeviceProvider::sharedInstance()->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)
|
|
{
|
|
if (m_deviceCards.contains(device.macAddress)) {
|
|
qDebug() << "Device with MAC" << device.macAddress
|
|
<< "already exists in the list. Skipping addition.";
|
|
return;
|
|
}
|
|
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 &macAddress)
|
|
{
|
|
// Find and remove the corresponding card
|
|
NetworkDeviceCard *card = m_deviceCards[macAddress];
|
|
m_deviceCards.remove(macAddress);
|
|
if (card) {
|
|
card->deleteLater();
|
|
}
|
|
|
|
// 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));
|
|
}
|
|
}
|
|
|
|
void NetworkDevicesToConnectWidget::eval()
|
|
{
|
|
if (QCoreApplication::closingDown() ||
|
|
!SettingsManager::sharedInstance()->autoConnectWirelessDevices())
|
|
return;
|
|
bool forceCache = true;
|
|
for (const auto &card : m_deviceCards) {
|
|
if (card) {
|
|
NetworkDevice device = card->getDevice();
|
|
AppContext::sharedInstance()->tryToConnectToNetworkDevice(
|
|
device, forceCache, false);
|
|
forceCache = false; // force cache once
|
|
}
|
|
}
|
|
}
|
|
|
|
void NetworkDevicesToConnectWidget::onNoPairingFileForWirelessDevice(
|
|
const QString &macAddress)
|
|
{
|
|
NetworkDeviceCard *deviceCard = m_deviceCards[macAddress];
|
|
if (deviceCard) {
|
|
qDebug() << "Calling noPairingFile() on device card for" << macAddress;
|
|
deviceCard->noPairingFile();
|
|
}
|
|
}
|
|
|
|
// udid or mac address
|
|
void NetworkDevicesToConnectWidget::onDeviceInitFailed(const QString &uniq)
|
|
{
|
|
NetworkDeviceCard *deviceCard = m_deviceCards[uniq];
|
|
if (deviceCard) {
|
|
qDebug() << "Calling failed() on device card for" << uniq;
|
|
deviceCard->failed();
|
|
}
|
|
}
|
|
|
|
void NetworkDevicesToConnectWidget::onDeviceInitStarted(const QString &uniq)
|
|
{
|
|
NetworkDeviceCard *deviceCard = m_deviceCards[uniq];
|
|
if (deviceCard) {
|
|
qDebug() << "Calling initStarted() on device card for" << uniq;
|
|
deviceCard->initStarted();
|
|
}
|
|
}
|
|
|
|
void NetworkDevicesToConnectWidget::onDeviceAdded(
|
|
const std::shared_ptr<iDescriptorDevice> device)
|
|
{
|
|
NetworkDeviceCard *deviceCard = m_deviceCards[QString::fromStdString(
|
|
device->deviceInfo.wifiMacAddress)];
|
|
if (deviceCard) {
|
|
qDebug() << "Calling connected() on device card for"
|
|
<< QString::fromStdString(device->deviceInfo.wifiMacAddress);
|
|
deviceCard->connected();
|
|
return;
|
|
}
|
|
qDebug() << "No device card found for"
|
|
<< QString::fromStdString(device->deviceInfo.wifiMacAddress);
|
|
}
|
|
|
|
void NetworkDevicesToConnectWidget::onDeviceAlreadyExists(
|
|
const iDescriptor::Uniq &uniq)
|
|
{
|
|
NetworkDeviceCard *deviceCard = m_deviceCards[QString(uniq.get())];
|
|
if (deviceCard) {
|
|
qDebug() << "Calling alreadyExists() on device card for" << uniq.get();
|
|
deviceCard->alreadyExists();
|
|
return;
|
|
}
|
|
qDebug() << "No device card found for" << uniq.get();
|
|
}
|