diff --git a/resources.qrc b/resources.qrc
index 2777c10..21645c9 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -19,6 +19,18 @@
resources/icons/MaterialSymbolsLightHome.png
resources/icons/MdiGithub.png
resources/icons/app-icon/icon.ico
+ resources/icons/MaterialSymbolsLightAirplayOutline.png
+ resources/icons/MaterialSymbolsLightCableRounded.png
+ resources/icons/MaterialSymbolsLocationOnOutline.png
+ resources/icons/MdiDisk.png
+ resources/icons/PepiconsPrintCellphoneEye.png
+ resources/icons/StreamlineProgrammingBrowserSearchSearchWindowGlassAppCodeProgrammingQueryFindMagnifyingApps.png
+ resources/icons/fuse.png
+ resources/icons/TablerDatabaseExport.png
+ resources/icons/StreamlineUltimateMultipleUsersNetwork.png
+ resources/icons/MaterialSymbolsAndroidWifi3BarPlus.png
+ resources/icons/IconParkTwotoneMoreTwo.png
+ resources/icons/BxBxsTerminal.png
qml/MapView.qml
resources/iphone.png
resources/ios-wallpapers/iphone-ios4.png
diff --git a/resources/icons/BxBxsTerminal.png b/resources/icons/BxBxsTerminal.png
new file mode 100644
index 0000000..f76e210
Binary files /dev/null and b/resources/icons/BxBxsTerminal.png differ
diff --git a/resources/icons/IconParkTwotoneMoreTwo.png b/resources/icons/IconParkTwotoneMoreTwo.png
new file mode 100644
index 0000000..c2f5dcd
Binary files /dev/null and b/resources/icons/IconParkTwotoneMoreTwo.png differ
diff --git a/resources/icons/MaterialSymbolsAndroidWifi3BarPlus.png b/resources/icons/MaterialSymbolsAndroidWifi3BarPlus.png
new file mode 100644
index 0000000..e1c39b0
Binary files /dev/null and b/resources/icons/MaterialSymbolsAndroidWifi3BarPlus.png differ
diff --git a/resources/icons/MaterialSymbolsLightAirplayOutline.png b/resources/icons/MaterialSymbolsLightAirplayOutline.png
new file mode 100644
index 0000000..99e9907
Binary files /dev/null and b/resources/icons/MaterialSymbolsLightAirplayOutline.png differ
diff --git a/resources/icons/MaterialSymbolsLightCableRounded.png b/resources/icons/MaterialSymbolsLightCableRounded.png
new file mode 100644
index 0000000..ca9bc5e
Binary files /dev/null and b/resources/icons/MaterialSymbolsLightCableRounded.png differ
diff --git a/resources/icons/MaterialSymbolsLocationOnOutline.png b/resources/icons/MaterialSymbolsLocationOnOutline.png
new file mode 100644
index 0000000..88ea17e
Binary files /dev/null and b/resources/icons/MaterialSymbolsLocationOnOutline.png differ
diff --git a/resources/icons/MdiDisk.png b/resources/icons/MdiDisk.png
new file mode 100644
index 0000000..3729f91
Binary files /dev/null and b/resources/icons/MdiDisk.png differ
diff --git a/resources/icons/PepiconsPrintCellphoneEye.png b/resources/icons/PepiconsPrintCellphoneEye.png
new file mode 100644
index 0000000..e537949
Binary files /dev/null and b/resources/icons/PepiconsPrintCellphoneEye.png differ
diff --git a/resources/icons/StreamlineProgrammingBrowserSearchSearchWindowGlassAppCodeProgrammingQueryFindMagnifyingApps.png b/resources/icons/StreamlineProgrammingBrowserSearchSearchWindowGlassAppCodeProgrammingQueryFindMagnifyingApps.png
new file mode 100644
index 0000000..8ccfcd4
Binary files /dev/null and b/resources/icons/StreamlineProgrammingBrowserSearchSearchWindowGlassAppCodeProgrammingQueryFindMagnifyingApps.png differ
diff --git a/resources/icons/StreamlineUltimateMultipleUsersNetwork.png b/resources/icons/StreamlineUltimateMultipleUsersNetwork.png
new file mode 100644
index 0000000..418c0d0
Binary files /dev/null and b/resources/icons/StreamlineUltimateMultipleUsersNetwork.png differ
diff --git a/resources/icons/TablerDatabaseExport.png b/resources/icons/TablerDatabaseExport.png
new file mode 100644
index 0000000..97e76c3
Binary files /dev/null and b/resources/icons/TablerDatabaseExport.png differ
diff --git a/resources/icons/fuse.png b/resources/icons/fuse.png
new file mode 100644
index 0000000..070981a
Binary files /dev/null and b/resources/icons/fuse.png differ
diff --git a/src/core/helpers/read_afc_file_to_byte_array.cpp b/src/core/helpers/read_afc_file_to_byte_array.cpp
index a2c4daa..88c3152 100644
--- a/src/core/helpers/read_afc_file_to_byte_array.cpp
+++ b/src/core/helpers/read_afc_file_to_byte_array.cpp
@@ -28,11 +28,11 @@ QByteArray read_afc_file_to_byte_array(afc_client_t afcClient, const char *path)
afc_file_open(afcClient, path, AFC_FOPEN_RDONLY, &fd_handle);
if (fd_err != AFC_E_SUCCESS) {
- qDebug() << "Could not open file" << path;
+ qDebug() << "Could not open file" << path << "Error:" << fd_err;
return QByteArray();
}
- // TODO: is this necessary
+ // TODO:Maybe use afc_get_file_info_plist instead?
char **info = NULL;
afc_get_file_info(afcClient, path, &info);
uint64_t fileSize = 0;
@@ -52,14 +52,18 @@ QByteArray read_afc_file_to_byte_array(afc_client_t afcClient, const char *path)
}
QByteArray buffer;
-
buffer.resize(fileSize);
- uint32_t bytesRead = 0;
- afc_file_read(afcClient, fd_handle, buffer.data(), buffer.size(),
- &bytesRead);
- if (bytesRead != fileSize) {
- qDebug() << "AFC Error: Read mismatch for file" << path;
+ uint32_t bytesRead = 0;
+ afc_error_t read_err = afc_file_read(afcClient, fd_handle, buffer.data(),
+ buffer.size(), &bytesRead);
+
+ afc_file_close(afcClient, fd_handle);
+
+ if (read_err != AFC_E_SUCCESS || bytesRead != fileSize) {
+ qDebug() << "AFC Error: Read mismatch for file" << path
+ << "Error:" << read_err << "Read:" << bytesRead
+ << "Expected:" << fileSize;
return QByteArray(); // Read failed
}
diff --git a/src/devdiskimageswidget.cpp b/src/devdiskimageswidget.cpp
index c56bc06..721dcb4 100644
--- a/src/devdiskimageswidget.cpp
+++ b/src/devdiskimageswidget.cpp
@@ -123,7 +123,6 @@ void DevDiskImagesWidget::setupUi()
m_imageListWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_imageListWidget->setStyleSheet(
"QListWidget { background: transparent; border: none; }");
- m_imageListWidget->viewport()->setStyleSheet("background: transparent;");
m_stackedWidget->addWidget(m_imageListWidget);
diff --git a/src/deviceinfowidget.cpp b/src/deviceinfowidget.cpp
index c73827f..f7f597a 100644
--- a/src/deviceinfowidget.cpp
+++ b/src/deviceinfowidget.cpp
@@ -153,7 +153,7 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent)
chargingLayout->setSpacing(5);
// Create icon label
- m_lightningIconLabel = new ZIconWidget(
+ m_lightningIconLabel = new ZIconLabel(
QIcon(":/resources/icons/MdiLightningBolt.png"), " Charging", this);
m_batteryWidget =
diff --git a/src/deviceinfowidget.h b/src/deviceinfowidget.h
index 2c2eeb3..4d6e0be 100644
--- a/src/deviceinfowidget.h
+++ b/src/deviceinfowidget.h
@@ -46,7 +46,7 @@ private:
QLabel *m_chargingStatusLabel;
QLabel *m_chargingWattsWithCableTypeLabel;
BatteryWidget *m_batteryWidget;
- ZIconWidget *m_lightningIconLabel;
+ ZIconLabel *m_lightningIconLabel;
DeviceImageWidget *m_deviceImageWidget;
};
diff --git a/src/devicemenuwidget.cpp b/src/devicemenuwidget.cpp
index 99cad13..aa051b9 100644
--- a/src/devicemenuwidget.cpp
+++ b/src/devicemenuwidget.cpp
@@ -99,3 +99,8 @@ void DeviceMenuWidget::switchToTab(const QString &tabName)
qDebug() << "Tab not found:" << tabName;
}
}
+
+DeviceMenuWidget::~DeviceMenuWidget()
+{
+ qDebug() << "DeviceMenuWidget destructor called";
+}
\ No newline at end of file
diff --git a/src/devicemenuwidget.h b/src/devicemenuwidget.h
index b43b759..cf0480a 100644
--- a/src/devicemenuwidget.h
+++ b/src/devicemenuwidget.h
@@ -35,7 +35,8 @@ public:
QWidget *parent = nullptr);
void switchToTab(const QString &tabName);
void init();
- // ~DeviceMenuWidget();
+ ~DeviceMenuWidget();
+
private:
QStackedWidget *stackedWidget; // Pointer to the stacked widget
iDescriptorDevice *device; // Pointer to the iDescriptor device
diff --git a/src/diagnosewidget.cpp b/src/diagnosewidget.cpp
index 27aede0..2841a2b 100644
--- a/src/diagnosewidget.cpp
+++ b/src/diagnosewidget.cpp
@@ -26,6 +26,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -129,7 +130,7 @@ void DependencyItem::setInstalling(bool installing)
void DependencyItem::onInstallClicked() { emit installRequested(m_name); }
DiagnoseWidget::DiagnoseWidget(QWidget *parent)
- : QWidget(parent), m_isExpanded(false)
+ : QFrame(parent), m_isExpanded(false)
{
setupUI();
@@ -144,7 +145,7 @@ DiagnoseWidget::DiagnoseWidget(QWidget *parent)
#ifdef __linux__
// Add Linux-specific dependency items
addDependencyItem("USB Device Permissions",
- "Required for recovery device access (udev rules)");
+ "Required for recovery devices (udev rules)");
#endif
// Auto-check on startup
@@ -153,7 +154,15 @@ DiagnoseWidget::DiagnoseWidget(QWidget *parent)
void DiagnoseWidget::setupUI()
{
- setAutoFillBackground(true);
+ setObjectName("diagnoseWidget");
+ setContentsMargins(20, 10, 10, 0);
+ setStyleSheet("QFrame#diagnoseWidget { "
+ " background-color: palette(window); " // Set background
+ // from the theme
+ " border-top-right-radius: 10px; "
+ " border-top-left-radius: 10px; "
+ " border-top: 1px solid #ccc; "
+ "}");
m_mainLayout = new QVBoxLayout(this);
m_mainLayout->setSpacing(10);
@@ -168,7 +177,7 @@ void DiagnoseWidget::setupUI()
// Check button
m_checkButton = new QPushButton("Refresh Check(s)");
- m_checkButton->setMaximumWidth(150);
+ m_checkButton->setMaximumWidth(m_checkButton->sizeHint().width());
connect(m_checkButton, &QPushButton::clicked, this,
[this]() { checkDependencies(false); });
@@ -488,8 +497,8 @@ void DiagnoseWidget::onInstallRequested(const QString &name)
QMessageBox::information(
this, "Installation Complete",
"USB device permissions have been configured.\n\n"
- "Note: You may need to log out and log back in for "
- "group membership changes to take full effect.");
+ "Note: You may need to log out and log back in for or "
+ "even restart for changes to take full effect.");
checkDependencies(false);
}
itemToInstall->setInstalling(false);
diff --git a/src/diagnosewidget.h b/src/diagnosewidget.h
index 006987d..f6d346f 100644
--- a/src/diagnosewidget.h
+++ b/src/diagnosewidget.h
@@ -20,6 +20,7 @@
#ifndef DIAGNOSE_WIDGET_H
#define DIAGNOSE_WIDGET_H
+#include
#include
#include
#include
@@ -27,7 +28,6 @@
#include
#include
#include
-#include
#include "qprocessindicator.h"
@@ -57,7 +57,7 @@ private:
QProcessIndicator *m_processIndicator;
};
-class DiagnoseWidget : public QWidget
+class DiagnoseWidget : public QFrame
{
Q_OBJECT
diff --git a/src/diskusagewidget.cpp b/src/diskusagewidget.cpp
index 0f70cb1..619ef67 100644
--- a/src/diskusagewidget.cpp
+++ b/src/diskusagewidget.cpp
@@ -88,11 +88,9 @@ void DiskUsageWidget::setupUI()
// Disk usage bar container
m_diskBarContainer = new QWidget(this);
- m_diskBarContainer->setMinimumHeight(20);
- m_diskBarContainer->setMaximumHeight(20);
- m_diskBarContainer->setObjectName("diskBarContainer");
- m_diskBarContainer->setStyleSheet(
- "QWidget#diskBarContainer { margin: 0; padding: 0; border: none; }");
+ m_diskBarContainer->setSizePolicy(QSizePolicy::Expanding,
+ QSizePolicy::Fixed);
+ m_diskBarContainer->setFixedHeight(20);
m_diskBarLayout = new QHBoxLayout(m_diskBarContainer);
m_diskBarLayout->setContentsMargins(0, 0, 0, 0);
m_diskBarLayout->setSpacing(0);
@@ -149,6 +147,13 @@ void DiskUsageWidget::setupUI()
"QWidget#freeBar { background-color: #474747; border: 1px solid "
"#4f4f4f; padding: 0; margin: 0; border-top-right-radius: 3px; "
"border-bottom-right-radius: 3px; }");
+
+ // remove padding margin from layout
+ m_systemBar->setContentsMargins(0, 0, 0, 0);
+ m_appsBar->setContentsMargins(0, 0, 0, 0);
+ m_mediaBar->setContentsMargins(0, 0, 0, 0);
+ m_othersBar->setContentsMargins(0, 0, 0, 0);
+ m_freeBar->setContentsMargins(0, 0, 0, 0);
#endif
m_diskBarLayout->addWidget(m_systemBar);
@@ -159,21 +164,22 @@ void DiskUsageWidget::setupUI()
m_dataLayout->addWidget(m_diskBarContainer);
- // Legend layout
- m_legendLayout = new QHBoxLayout();
+ QWidget *m_legendWidget = new QWidget();
+ m_legendWidget->setContentsMargins(0, 0, 0, 0);
+ m_legendWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+
+ m_legendLayout = new QHBoxLayout(m_legendWidget);
m_legendLayout->setSpacing(0);
m_legendLayout->setContentsMargins(0, 0, 0, 0);
- // Legend labels
- m_systemLabel = new QLabel("System", m_dataPage);
- m_appsLabel = new QLabel("Apps", m_dataPage);
- m_mediaLabel = new QLabel("Media", m_dataPage);
- m_othersLabel = new QLabel("Others", m_dataPage);
- m_freeLabel = new QLabel("Free", m_dataPage);
+ m_systemLabel = new QLabel("System", m_legendWidget);
+ m_appsLabel = new QLabel("Apps", m_legendWidget);
+ m_mediaLabel = new QLabel("Media", m_legendWidget);
+ m_othersLabel = new QLabel("Others", m_legendWidget);
+ m_freeLabel = new QLabel("Free", m_legendWidget);
- // Style legend labels with colored backgrounds
QString labelStyle =
- "padding: 2px 6px; margin: 0px; border-radius: 3px; font-size: 10px;";
+ "margin: 0px; padding: 0px 4px 0px 0px; font-size: 10px;";
m_systemLabel->setStyleSheet(labelStyle);
m_appsLabel->setStyleSheet(labelStyle);
m_mediaLabel->setStyleSheet(labelStyle);
@@ -187,8 +193,8 @@ void DiskUsageWidget::setupUI()
m_legendLayout->addWidget(m_freeLabel);
m_legendLayout->addStretch();
- m_dataLayout->addLayout(m_legendLayout);
- // m_dataLayout->addStretch();
+ // Add the legend widget (not the layout) to the data layout
+ m_dataLayout->addWidget(m_legendWidget);
m_stackedWidget->addWidget(m_dataPage);
@@ -196,8 +202,6 @@ void DiskUsageWidget::setupUI()
m_stackedWidget->setCurrentWidget(m_loadingErrorPage);
}
-QSize DiskUsageWidget::sizeHint() const { return QSize(400, 80); }
-
void DiskUsageWidget::updateUI()
{
if (m_state == Loading) {
diff --git a/src/diskusagewidget.h b/src/diskusagewidget.h
index 461fe36..40601a6 100644
--- a/src/diskusagewidget.h
+++ b/src/diskusagewidget.h
@@ -37,7 +37,6 @@ class DiskUsageWidget : public QWidget
public:
explicit DiskUsageWidget(iDescriptorDevice *device,
QWidget *parent = nullptr);
- QSize sizeHint() const override;
private:
void fetchData();
diff --git a/src/gallerywidget.cpp b/src/gallerywidget.cpp
index 76e5843..9db47e3 100644
--- a/src/gallerywidget.cpp
+++ b/src/gallerywidget.cpp
@@ -621,4 +621,9 @@ void GalleryWidget::onPhotoContextMenu(const QPoint &pos)
&GalleryWidget::onExportSelected);
contextMenu.exec(m_listView->viewport()->mapToGlobal(pos));
+}
+
+GalleryWidget::~GalleryWidget()
+{
+ qDebug() << "GalleryWidget destructor called";
}
\ No newline at end of file
diff --git a/src/gallerywidget.h b/src/gallerywidget.h
index 5a6ea16..78623f3 100644
--- a/src/gallerywidget.h
+++ b/src/gallerywidget.h
@@ -46,6 +46,7 @@ public:
explicit GalleryWidget(iDescriptorDevice *device,
QWidget *parent = nullptr);
void load();
+ ~GalleryWidget();
private slots:
void onSortOrderChanged();
diff --git a/src/iDescriptor-ui.h b/src/iDescriptor-ui.h
index 8f6f8aa..16964aa 100644
--- a/src/iDescriptor-ui.h
+++ b/src/iDescriptor-ui.h
@@ -90,8 +90,15 @@ public:
ZIcon(const QString &fileName) : QIcon(fileName) {}
ZIcon(const QPixmap &pixmap) : QIcon(pixmap) {}
+ void setThemable(bool themable) { m_themable = themable; }
+
QPixmap getThemedPixmap(const QSize &size, const QPalette &palette) const
{
+ // If not themable, return the original pixmap without color filling.
+ if (!m_themable) {
+ return QIcon::pixmap(size);
+ }
+
QPixmap pixmap = QIcon::pixmap(size);
if (pixmap.isNull()) {
return pixmap;
@@ -123,6 +130,9 @@ public:
QIcon::paint(painter, rect);
}
}
+
+private:
+ bool m_themable = true;
};
class ZIconWidget : public QAbstractButton
@@ -174,9 +184,61 @@ private:
ZIcon m_icon;
};
+// Add this new class for display-only icons
+class ZIconLabel : public QLabel
+{
+ Q_OBJECT
+public:
+ ZIconLabel(const QIcon &icon, const QString &tooltip,
+ QWidget *parent = nullptr)
+ : QLabel(parent), m_icon(icon), m_iconSize(24, 24)
+ {
+ setToolTip(tooltip);
+ // setFixedSize(32, 32);
+ connect(qApp, &QApplication::paletteChanged, this,
+ [this]() { update(); });
+ }
+
+ void setIcon(const QIcon &icon)
+ {
+ m_icon = ZIcon(icon);
+ update();
+ }
+
+ void setIconThemable(bool themable)
+ {
+ m_icon.setThemable(themable);
+ update();
+ }
+
+ void setIconSize(const QSize &size)
+ {
+ m_iconSize = size;
+ update();
+ }
+
+protected:
+ void paintEvent(QPaintEvent *event) override
+ {
+ Q_UNUSED(event)
+ QPainter painter(this);
+ painter.setRenderHint(QPainter::Antialiasing);
+
+ QRect iconRect = rect();
+ iconRect.setSize(m_iconSize);
+ iconRect.moveCenter(rect().center());
+
+ m_icon.paint(&painter, iconRect, palette());
+ }
+
+private:
+ ZIcon m_icon;
+ QSize m_iconSize;
+};
+
enum class iDescriptorTool {
Airplayer,
- RealtimeScreen,
+ LiveScreen,
MountDevImage,
VirtualLocation,
Restart,
@@ -184,7 +246,7 @@ enum class iDescriptorTool {
RecoveryMode,
QueryMobileGestalt,
DeveloperDiskImages,
- WirelessPhotoImport,
+ WirelessGalleryImport,
CableInfoWidget,
/*
TODO: to be implemented
diff --git a/src/jailbrokenwidget.cpp b/src/jailbrokenwidget.cpp
index 947c674..de1906e 100644
--- a/src/jailbrokenwidget.cpp
+++ b/src/jailbrokenwidget.cpp
@@ -19,8 +19,8 @@
#include "jailbrokenwidget.h"
#include "appcontext.h"
+#include "opensshterminalwidget.h"
#include "responsiveqlabel.h"
-#include "sshterminalwidget.h"
#ifdef __linux__
#include "core/services/avahi/avahi_service.h"
@@ -30,6 +30,7 @@
#include "iDescriptor-ui.h"
#include "iDescriptor.h"
+#include
#include
#include
#include
@@ -41,313 +42,107 @@
#include
#include
-// TODO: theming is broken
JailbrokenWidget::JailbrokenWidget(QWidget *parent) : QWidget{parent}
{
- QHBoxLayout *mainLayout = new QHBoxLayout(this);
- mainLayout->setContentsMargins(2, 2, 2, 2);
- mainLayout->setSpacing(2);
+ QGridLayout *mainLayout = new QGridLayout(this);
+ mainLayout->setContentsMargins(10, 10, 10, 10);
+ mainLayout->setSpacing(10);
- // Create responsive image label
- ResponsiveQLabel *deviceImageLabel = new ResponsiveQLabel(this);
- deviceImageLabel->setPixmap(QPixmap(":/resources/iphone.png"));
- deviceImageLabel->setMinimumWidth(200);
- deviceImageLabel->setSizePolicy(QSizePolicy::Ignored,
- QSizePolicy::Expanding);
- deviceImageLabel->setStyleSheet("background: transparent; border: none;");
+ // Define all the tools you want to display
+ QList tools;
+ tools.append({"Open SSH Terminal", "Connect to your device via SSH",
+ ":/resources/icons/TablerDatabaseExport.png"});
+ tools.append({"More Tools Coming", "New features will be added soon",
+ ":/resources/icons/TablerDatabaseExport.png",
+ false}); // Disabled placeholder
- mainLayout->addWidget(deviceImageLabel, 1);
+ const int maxColumns = 3;
+ for (int i = 0; i < tools.size(); ++i) {
+ const auto &toolInfo = tools[i];
+ ClickableWidget *toolWidget = createJailbreakTool(toolInfo);
- // Connect to AppContext for device events
- connect(AppContext::sharedInstance(), &AppContext::deviceAdded, this,
- &JailbrokenWidget::onWiredDeviceAdded);
- connect(AppContext::sharedInstance(), &AppContext::deviceRemoved, this,
- &JailbrokenWidget::onWiredDeviceRemoved);
+ int row = i / maxColumns;
+ int col = i % maxColumns;
+ mainLayout->addWidget(toolWidget, row, col);
+ }
-#ifdef __linux__
- m_wirelessProvider = new AvahiService(this);
- connect(m_wirelessProvider, &AvahiService::deviceAdded, this,
- &JailbrokenWidget::onWirelessDeviceAdded);
- connect(m_wirelessProvider, &AvahiService::deviceRemoved, this,
- &JailbrokenWidget::onWirelessDeviceRemoved);
-#else
- m_wirelessProvider = new DnssdService(this);
- connect(m_wirelessProvider, &DnssdService::deviceAdded, this,
- &JailbrokenWidget::onWirelessDeviceAdded);
- connect(m_wirelessProvider, &DnssdService::deviceRemoved, this,
- &JailbrokenWidget::onWirelessDeviceRemoved);
-#endif
-
- // Right side: Device selection and Terminal
- QWidget *rightContainer = new QWidget();
- rightContainer->setSizePolicy(QSizePolicy::Expanding,
- QSizePolicy::Expanding);
- rightContainer->setMinimumWidth(400);
- QVBoxLayout *rightLayout = new QVBoxLayout(rightContainer);
- rightLayout->setContentsMargins(15, 15, 15, 15);
- rightLayout->setSpacing(10);
-
- setupDeviceSelectionUI(rightLayout);
-
- mainLayout->addWidget(rightContainer, 3);
-
- // Start scanning for wireless devices
- m_wirelessProvider->startBrowsing();
-
- // Populate initial devices
- updateDeviceList();
+ // Add a stretch to the last row and column to push everything to the
+ // top-left
+ mainLayout->setRowStretch(mainLayout->rowCount(), 1);
+ mainLayout->setColumnStretch(mainLayout->columnCount(), 1);
}
-void JailbrokenWidget::setupDeviceSelectionUI(QVBoxLayout *layout)
+ClickableWidget *
+JailbrokenWidget::createJailbreakTool(const JailbreakToolInfo &info)
{
- // Create scroll area for device selection
- QScrollArea *scrollArea = new QScrollArea();
- scrollArea->setWidgetResizable(true);
- scrollArea->setMinimumHeight(200);
- scrollArea->setMaximumHeight(300);
- scrollArea->setObjectName("devicescrollArea");
+ ClickableWidget *b = new ClickableWidget();
+ b->setCursor(Qt::PointingHandCursor);
+ b->setEnabled(info.enabled);
- scrollArea->setStyleSheet("QWidget#devicescrollArea {border: none;}");
- QWidget *scrollContent = new QWidget();
- m_deviceLayout = new QVBoxLayout(scrollContent);
- m_deviceLayout->setContentsMargins(5, 5, 5, 5);
- m_deviceLayout->setSpacing(10);
+ // Use a theme-aware stylesheet for the background and hover effect
+ b->setStyleSheet("ClickableWidget {"
+ " border-radius: 8px;"
+ " padding: 10px;"
+ "}");
- // Button group for device selection
- m_deviceButtonGroup = new QButtonGroup(this);
- connect(m_deviceButtonGroup,
- QOverload::of(&QButtonGroup::buttonClicked),
- this, &JailbrokenWidget::onDeviceSelected);
+ QVBoxLayout *layout = new QVBoxLayout(b);
- // Wired devices group
- m_wiredDevicesGroup = new QGroupBox("Connected Devices");
- m_wiredDevicesLayout = new QVBoxLayout(m_wiredDevicesGroup);
- m_deviceLayout->addWidget(m_wiredDevicesGroup);
+ // Icon (using the theme-aware ZIcon pattern)
+ // ZIconLabel *iconLabel = new ZIconLabel();
+ ZIconLabel *iconLabel = new ZIconLabel(QIcon(), nullptr, this);
- // Wireless devices group
- m_wirelessDevicesGroup = new QGroupBox("Network Devices");
- m_wirelessDevicesLayout = new QVBoxLayout(m_wirelessDevicesGroup);
- m_deviceLayout->addWidget(m_wirelessDevicesGroup);
+ // iconLabel->setAlignment(Qt::AlignCenter);
+ // ZIcon toolIcon(QIcon(info.iconPath));
- scrollArea->setWidget(scrollContent);
- layout->addWidget(scrollArea);
+ // auto updateIcon = [b, iconLabel, toolIcon]() {
+ // iconLabel->setPixmap(
+ // toolIcon.getThemedPixmap(QSize(45, 45), b->palette()));
+ // };
+ // updateIcon();
+ // connect(qApp, &QApplication::paletteChanged, b, updateIcon);
- // Info and connect button
- m_infoLabel = new QLabel("Select a device to connect");
- layout->addWidget(m_infoLabel);
+ // Title
+ QLabel *titleLabel = new QLabel(info.title);
+ titleLabel->setAlignment(Qt::AlignCenter);
+ QFont titleFont = titleLabel->font();
+ titleFont.setBold(true);
+ titleLabel->setFont(titleFont);
- m_connectButton = new QPushButton("Open SSH Terminal");
- m_connectButton->setEnabled(false);
- connect(m_connectButton, &QPushButton::clicked, this,
- &JailbrokenWidget::onOpenSSHTerminal);
- layout->addWidget(m_connectButton);
+ // Description (using a theme-aware palette color)
+ QLabel *descLabel = new QLabel(info.description);
+ descLabel->setWordWrap(true);
+ descLabel->setAlignment(Qt::AlignCenter);
+ descLabel->setStyleSheet("font-size: 12px;");
+
+ layout->addWidget(iconLabel, 0, Qt::AlignCenter);
+ layout->addWidget(titleLabel);
+ layout->addWidget(descLabel);
+
+ // TODO: Connect the clicked signal to a slot
+ if (info.title == "Open SSH Terminal") {
+ iconLabel->setIcon(QIcon(":/resources/icons/BxBxsTerminal.png"));
+
+ connect(b, &ClickableWidget::clicked, this, [this]() {
+ if (m_sshTerminalWidget) {
+ m_sshTerminalWidget->raise();
+ m_sshTerminalWidget->activateWindow();
+ return;
+ }
+ m_sshTerminalWidget = new OpenSSHTerminalWidget();
+ m_sshTerminalWidget->setAttribute(Qt::WA_DeleteOnClose);
+ m_sshTerminalWidget->show();
+ m_sshTerminalWidget->raise();
+ m_sshTerminalWidget->activateWindow();
+ connect(m_sshTerminalWidget, &QObject::destroyed, this,
+ [this]() { m_sshTerminalWidget = nullptr; });
+ });
+ } else if (info.title == "More Tools Coming") {
+ iconLabel->setIcon(
+ QIcon(":/resources/icons/IconParkTwotoneMoreTwo.png"));
+ }
+ iconLabel->setFixedSize(60, 60);
+ iconLabel->setIconSize(QSize(45, 45));
+ return b;
}
-void JailbrokenWidget::updateDeviceList()
-{
- // Clear existing devices
- clearDeviceButtons();
-
- // Add wired devices
- QList wiredDevices =
- AppContext::sharedInstance()->getAllDevices();
- for (iDescriptorDevice *device : wiredDevices) {
- addWiredDevice(device);
- }
-
- // Add wireless devices
- QList wirelessDevices =
- m_wirelessProvider->getNetworkDevices();
- for (const NetworkDevice &device : wirelessDevices) {
- addWirelessDevice(device);
- }
-}
-
-void JailbrokenWidget::clearDeviceButtons()
-{
- // Remove all buttons from button group and layouts
- for (QAbstractButton *button : m_deviceButtonGroup->buttons()) {
- m_deviceButtonGroup->removeButton(button);
- button->deleteLater();
- }
-
- // Clear layouts
- QLayoutItem *item;
- while ((item = m_wiredDevicesLayout->takeAt(0)) != nullptr) {
- delete item->widget();
- delete item;
- }
- while ((item = m_wirelessDevicesLayout->takeAt(0)) != nullptr) {
- delete item->widget();
- delete item;
- }
-}
-
-void JailbrokenWidget::addWiredDevice(iDescriptorDevice *device)
-{
- QString deviceName = QString::fromStdString(device->deviceInfo.deviceName);
- QString udid = QString::fromStdString(device->udid);
- QString displayText = QString("%1\n%2").arg(deviceName, udid);
-
- QRadioButton *radioButton = new QRadioButton(displayText);
- radioButton->setProperty("deviceType", "wired");
- radioButton->setProperty("devicePointer",
- QVariant::fromValue(static_cast(device)));
- radioButton->setProperty("udid", udid);
-
- m_deviceButtonGroup->addButton(radioButton);
- m_wiredDevicesLayout->addWidget(radioButton);
-}
-
-void JailbrokenWidget::addWirelessDevice(const NetworkDevice &device)
-{
- QString displayText = QString("%1\n%2").arg(device.name, device.address);
-
- QRadioButton *radioButton = new QRadioButton(displayText);
- radioButton->setProperty("deviceType", "wireless");
- radioButton->setProperty("deviceAddress", device.address);
- radioButton->setProperty("deviceName", device.name);
- radioButton->setProperty("devicePort", device.port);
-
- m_deviceButtonGroup->addButton(radioButton);
- m_wirelessDevicesLayout->addWidget(radioButton);
-}
-
-void JailbrokenWidget::onWiredDeviceAdded(iDescriptorDevice *device)
-{
- addWiredDevice(device);
-}
-
-void JailbrokenWidget::onWiredDeviceRemoved(const std::string &udid)
-{
- QString qudid = QString::fromStdString(udid);
-
- // Find and remove the corresponding radio button
- for (QAbstractButton *button : m_deviceButtonGroup->buttons()) {
- if (button->property("deviceType").toString() == "wired" &&
- button->property("udid").toString() == qudid) {
- m_deviceButtonGroup->removeButton(button);
- button->deleteLater();
- break;
- }
- }
-
- // Reset selection if this device was selected
- if (m_selectedDeviceType == DeviceType::Wired && m_selectedWiredDevice &&
- m_selectedWiredDevice->udid == udid) {
- resetSelection();
- }
-}
-
-void JailbrokenWidget::onWirelessDeviceAdded(const NetworkDevice &device)
-{
- addWirelessDevice(device);
-}
-
-void JailbrokenWidget::onWirelessDeviceRemoved(const QString &deviceName)
-{
- // Find and remove the corresponding radio button
- for (QAbstractButton *button : m_deviceButtonGroup->buttons()) {
- if (button->property("deviceType").toString() == "wireless" &&
- button->property("deviceName").toString() == deviceName) {
- m_deviceButtonGroup->removeButton(button);
- button->deleteLater();
- break;
- }
- }
-
- // Reset selection if this device was selected
- if (m_selectedDeviceType == DeviceType::Wireless &&
- m_selectedNetworkDevice.name == deviceName) {
- resetSelection();
- }
-}
-
-void JailbrokenWidget::onDeviceSelected(QAbstractButton *button)
-{
- QString deviceType = button->property("deviceType").toString();
-
- if (deviceType == "wired") {
- m_selectedDeviceType = DeviceType::Wired;
- m_selectedWiredDevice = static_cast(
- button->property("devicePointer").value());
-
- if (m_selectedWiredDevice->deviceInfo.jailbroken) {
- m_infoLabel->setText("Jailbroken device selected");
- } else {
- m_infoLabel->setText(
- "Device selected (detected as non-jailbroken)");
- }
- } else if (deviceType == "wireless") {
- m_selectedDeviceType = DeviceType::Wireless;
- m_selectedNetworkDevice.name =
- button->property("deviceName").toString();
- m_selectedNetworkDevice.address =
- button->property("deviceAddress").toString();
- m_selectedNetworkDevice.port = button->property("devicePort").toUInt();
-
- m_infoLabel->setText(
- "Network device selected (jailbreak status unknown)");
- }
-
- m_connectButton->setEnabled(true);
- m_connectButton->setText("Open SSH Terminal");
-}
-
-void JailbrokenWidget::resetSelection()
-{
- m_selectedDeviceType = DeviceType::None;
- m_selectedWiredDevice = nullptr;
- m_selectedNetworkDevice = NetworkDevice{};
- m_connectButton->setEnabled(false);
- m_infoLabel->setText("Select a device to connect");
-
- // Uncheck all radio buttons
- if (m_deviceButtonGroup->checkedButton()) {
- m_deviceButtonGroup->setExclusive(false);
- m_deviceButtonGroup->checkedButton()->setChecked(false);
- m_deviceButtonGroup->setExclusive(true);
- }
-}
-
-void JailbrokenWidget::onOpenSSHTerminal()
-{
- if (m_selectedDeviceType == DeviceType::None) {
- m_infoLabel->setText("Please select a device first");
- return;
- }
-
- // Prepare connection info
- ConnectionInfo connectionInfo;
-
- if (m_selectedDeviceType == DeviceType::Wired) {
- if (!m_selectedWiredDevice) {
- m_infoLabel->setText("No wired device selected");
- return;
- }
-
- connectionInfo.type = ConnectionType::Wired;
- connectionInfo.deviceName = QString::fromStdString(
- m_selectedWiredDevice->deviceInfo.deviceName);
- connectionInfo.deviceUdid =
- QString::fromStdString(m_selectedWiredDevice->udid);
- connectionInfo.hostAddress = "127.0.0.1";
- connectionInfo.port = 22;
-
- } else if (m_selectedDeviceType == DeviceType::Wireless) {
- connectionInfo.type = ConnectionType::Wireless;
- connectionInfo.deviceName = m_selectedNetworkDevice.name;
- connectionInfo.deviceUdid = "";
- connectionInfo.hostAddress = m_selectedNetworkDevice.address;
- connectionInfo.port = m_selectedNetworkDevice.port;
- }
-
- // Create and show SSH terminal widget in a new window
- SSHTerminalWidget *sshTerminal = new SSHTerminalWidget(connectionInfo);
- sshTerminal->setAttribute(Qt::WA_DeleteOnClose);
- sshTerminal->show();
- sshTerminal->raise();
- sshTerminal->activateWindow();
-}
-
-JailbrokenWidget::~JailbrokenWidget() {}
+JailbrokenWidget::~JailbrokenWidget() {}
\ No newline at end of file
diff --git a/src/jailbrokenwidget.h b/src/jailbrokenwidget.h
index bc8fa51..1c37b17 100644
--- a/src/jailbrokenwidget.h
+++ b/src/jailbrokenwidget.h
@@ -27,7 +27,7 @@
#endif
#include "iDescriptor.h"
-#include "sshterminalwidget.h"
+#include "opensshterminalwidget.h"
#include
#include
#include
@@ -36,7 +36,15 @@
#include
#include
-enum class DeviceType { None, Wired, Wireless };
+class ClickableWidget;
+
+// Define the struct here so it's available to the class declaration
+struct JailbreakToolInfo {
+ QString title;
+ QString description;
+ QString iconPath;
+ bool enabled = true;
+};
class JailbrokenWidget : public QWidget
{
@@ -47,53 +55,10 @@ public:
~JailbrokenWidget();
private slots:
- void onOpenSSHTerminal();
- void onWiredDeviceAdded(iDescriptorDevice *device);
- void onWiredDeviceRemoved(const std::string &udid);
- void onWirelessDeviceAdded(const NetworkDevice &device);
- void onWirelessDeviceRemoved(const QString &deviceName);
- void onDeviceSelected(QAbstractButton *button);
-
private:
- void setupDeviceSelectionUI(QVBoxLayout *layout);
- void updateDeviceList();
- void clearDeviceButtons();
- void addWiredDevice(iDescriptorDevice *device);
- void addWirelessDevice(const NetworkDevice &device);
- void resetSelection();
-
- QLabel *m_infoLabel;
- QPushButton *m_connectButton;
-
- // Device selection UI
- QVBoxLayout *m_deviceLayout;
- QGroupBox *m_wiredDevicesGroup;
- QGroupBox *m_wirelessDevicesGroup;
- QVBoxLayout *m_wiredDevicesLayout;
- QVBoxLayout *m_wirelessDevicesLayout;
- QButtonGroup *m_deviceButtonGroup;
-
-#ifdef __linux__
- AvahiService *m_wirelessProvider = nullptr;
-#else
- DnssdService *m_wirelessProvider = nullptr;
-#endif
-
- DeviceType m_selectedDeviceType = DeviceType::None;
- iDescriptorDevice *m_selectedWiredDevice = nullptr;
- NetworkDevice m_selectedNetworkDevice;
-
- // Legacy device pointer (kept for compatibility)
- iDescriptorDevice *m_device = nullptr;
-
- // SSH components
- ssh_session m_sshSession;
- ssh_channel m_sshChannel;
- QTimer *m_sshTimer;
- QProcess *iproxyProcess = nullptr;
-
- bool m_sshConnected = false;
- bool m_isInitialized = false;
+ // Helper function to create a tool widget
+ ClickableWidget *createJailbreakTool(const JailbreakToolInfo &info);
+ OpenSSHTerminalWidget *m_sshTerminalWidget = nullptr;
};
#endif // JAILBROKENWIDGET_H
\ No newline at end of file
diff --git a/src/realtimescreenwidget.cpp b/src/livescreenwidget.cpp
similarity index 84%
rename from src/realtimescreenwidget.cpp
rename to src/livescreenwidget.cpp
index d3deace..e9bcc0b 100644
--- a/src/realtimescreenwidget.cpp
+++ b/src/livescreenwidget.cpp
@@ -17,7 +17,7 @@
* along with this program. If not, see .
*/
-#include "realtimescreenwidget.h"
+#include "livescreenwidget.h"
#include "appcontext.h"
#include "devdiskimagehelper.h"
#include "devdiskmanager.h"
@@ -31,13 +31,12 @@
#include
#include
#include
-// todo: rename to livescreenwidget
-RealtimeScreenWidget::RealtimeScreenWidget(iDescriptorDevice *device,
- QWidget *parent)
+
+LiveScreenWidget::LiveScreenWidget(iDescriptorDevice *device, QWidget *parent)
: QWidget{parent}, m_device(device), m_timer(nullptr),
- m_shotrClient(nullptr), m_fps(50)
+ m_shotrClient(nullptr), m_fps(20)
{
- setWindowTitle("Real-time Screen - iDescriptor");
+ setWindowTitle("Live Screen - iDescriptor");
unsigned int device_version = get_device_version(m_device->device);
unsigned int deviceMajorVersion = (device_version >> 16) & 0xFF;
@@ -71,20 +70,6 @@ RealtimeScreenWidget::RealtimeScreenWidget(iDescriptorDevice *device,
m_statusLabel->setAlignment(Qt::AlignCenter);
mainLayout->addWidget(m_statusLabel);
- // FPS control
- QHBoxLayout *controlLayout = new QHBoxLayout();
- QLabel *fpsLabel = new QLabel("Frame Rate:");
- QSpinBox *fpsSpinBox = new QSpinBox();
- fpsSpinBox->setRange(1, 50);
- fpsSpinBox->setValue(m_fps);
- fpsSpinBox->setSuffix(" FPS");
- fpsSpinBox->setMaximumWidth(100);
-
- controlLayout->addWidget(fpsLabel);
- controlLayout->addWidget(fpsSpinBox);
- controlLayout->addStretch();
- mainLayout->addLayout(controlLayout);
-
// Screenshot display
m_imageLabel = new QLabel();
m_imageLabel->setMinimumSize(300, 600);
@@ -96,15 +81,7 @@ RealtimeScreenWidget::RealtimeScreenWidget(iDescriptorDevice *device,
m_timer = new QTimer(this);
m_timer->setInterval(1000 / m_fps);
connect(m_timer, &QTimer::timeout, this,
- &RealtimeScreenWidget::updateScreenshot);
-
- connect(fpsSpinBox, QOverload::of(&QSpinBox::valueChanged), this,
- [this](int value) {
- m_fps = value;
- if (m_timer && m_timer->isActive()) {
- m_timer->setInterval(1000 / m_fps);
- }
- });
+ &LiveScreenWidget::updateScreenshot);
const bool initializeScreenshotServiceSuccess =
initializeScreenshotService(false);
@@ -135,7 +112,7 @@ RealtimeScreenWidget::RealtimeScreenWidget(iDescriptorDevice *device,
helper->start();
}
-RealtimeScreenWidget::~RealtimeScreenWidget()
+LiveScreenWidget::~LiveScreenWidget()
{
if (m_timer) {
m_timer->stop();
@@ -147,7 +124,7 @@ RealtimeScreenWidget::~RealtimeScreenWidget()
}
}
-bool RealtimeScreenWidget::initializeScreenshotService(bool notify)
+bool LiveScreenWidget::initializeScreenshotService(bool notify)
{
lockdownd_client_t lockdownClient = nullptr;
lockdownd_service_descriptor_t service = nullptr;
@@ -206,8 +183,7 @@ bool RealtimeScreenWidget::initializeScreenshotService(bool notify)
}
// Successfully initialized, start capturing
- m_statusLabel->setText("Capturing at " + QString::number(m_fps) +
- " FPS");
+ m_statusLabel->setText("Capturing");
startCapturing();
return true;
} catch (const std::exception &e) {
@@ -226,7 +202,7 @@ bool RealtimeScreenWidget::initializeScreenshotService(bool notify)
}
}
-void RealtimeScreenWidget::startCapturing()
+void LiveScreenWidget::startCapturing()
{
if (!m_shotrClient) {
qWarning()
@@ -236,11 +212,11 @@ void RealtimeScreenWidget::startCapturing()
if (m_timer) {
m_timer->start();
- qDebug() << "Started capturing at" << m_fps << "FPS";
+ qDebug() << "Started capturing";
}
}
-void RealtimeScreenWidget::updateScreenshot()
+void LiveScreenWidget::updateScreenshot()
{
if (!m_shotrClient) {
qWarning() << "Screenshot client not initialized";
diff --git a/src/realtimescreenwidget.h b/src/livescreenwidget.h
similarity index 82%
rename from src/realtimescreenwidget.h
rename to src/livescreenwidget.h
index 8d6f36a..19ebf4f 100644
--- a/src/realtimescreenwidget.h
+++ b/src/livescreenwidget.h
@@ -17,8 +17,8 @@
* along with this program. If not, see .
*/
-#ifndef REALTIMESCREEN_H
-#define REALTIMESCREEN_H
+#ifndef LIVESCREEN_H
+#define LIVESCREEN_H
#include "iDescriptor.h"
#include
@@ -27,13 +27,13 @@
#include
#include
-class RealtimeScreenWidget : public QWidget
+class LiveScreenWidget : public QWidget
{
Q_OBJECT
public:
- explicit RealtimeScreenWidget(iDescriptorDevice *device,
- QWidget *parent = nullptr);
- ~RealtimeScreenWidget();
+ explicit LiveScreenWidget(iDescriptorDevice *device,
+ QWidget *parent = nullptr);
+ ~LiveScreenWidget();
private:
bool initializeScreenshotService(bool notify);
@@ -50,4 +50,4 @@ private:
signals:
};
-#endif // REALTIMESCREEN_H
+#endif // LIVESCREEN_H
diff --git a/src/opensshterminalwidget.cpp b/src/opensshterminalwidget.cpp
new file mode 100644
index 0000000..39dbeb6
--- /dev/null
+++ b/src/opensshterminalwidget.cpp
@@ -0,0 +1,354 @@
+/*
+ * iDescriptor: A free and open-source idevice management tool.
+ *
+ * Copyright (C) 2025 Uncore
+ *
+ * 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 .
+ */
+
+#include "opensshterminalwidget.h"
+#include "appcontext.h"
+#include "responsiveqlabel.h"
+#include "sshterminalwidget.h"
+
+#ifdef __linux__
+#include "core/services/avahi/avahi_service.h"
+#else
+#include "core/services/dnssd/dnssd_service.h"
+#endif
+
+#include "iDescriptor-ui.h"
+#include "iDescriptor.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// TODO: theming is broken
+OpenSSHTerminalWidget::OpenSSHTerminalWidget(QWidget *parent) : QWidget{parent}
+{
+ QHBoxLayout *mainLayout = new QHBoxLayout(this);
+ mainLayout->setContentsMargins(2, 2, 2, 2);
+ mainLayout->setSpacing(2);
+
+ // Create responsive image label
+ ResponsiveQLabel *deviceImageLabel = new ResponsiveQLabel(this);
+ deviceImageLabel->setPixmap(QPixmap(":/resources/iphone.png"));
+ deviceImageLabel->setMinimumWidth(200);
+ deviceImageLabel->setSizePolicy(QSizePolicy::Ignored,
+ QSizePolicy::Expanding);
+ deviceImageLabel->setStyleSheet("background: transparent; border: none;");
+
+ mainLayout->addWidget(deviceImageLabel, 1);
+
+ // Connect to AppContext for device events
+ connect(AppContext::sharedInstance(), &AppContext::deviceAdded, this,
+ &OpenSSHTerminalWidget::onWiredDeviceAdded);
+ connect(AppContext::sharedInstance(), &AppContext::deviceRemoved, this,
+ &OpenSSHTerminalWidget::onWiredDeviceRemoved);
+
+#ifdef __linux__
+ m_wirelessProvider = new AvahiService(this);
+ connect(m_wirelessProvider, &AvahiService::deviceAdded, this,
+ &OpenSSHTerminalWidget::onWirelessDeviceAdded);
+ connect(m_wirelessProvider, &AvahiService::deviceRemoved, this,
+ &OpenSSHTerminalWidget::onWirelessDeviceRemoved);
+#else
+ m_wirelessProvider = new DnssdService(this);
+ connect(m_wirelessProvider, &DnssdService::deviceAdded, this,
+ &OpenSSHTerminalWidget::onWirelessDeviceAdded);
+ connect(m_wirelessProvider, &DnssdService::deviceRemoved, this,
+ &OpenSSHTerminalWidget::onWirelessDeviceRemoved);
+#endif
+
+ // Right side: Device selection and Terminal
+ QWidget *rightContainer = new QWidget();
+ rightContainer->setSizePolicy(QSizePolicy::Expanding,
+ QSizePolicy::Expanding);
+ rightContainer->setMinimumWidth(400);
+ QVBoxLayout *rightLayout = new QVBoxLayout(rightContainer);
+ rightLayout->setContentsMargins(15, 15, 15, 15);
+ rightLayout->setSpacing(10);
+
+ setupDeviceSelectionUI(rightLayout);
+
+ mainLayout->addWidget(rightContainer, 3);
+
+ // Start scanning for wireless devices
+ m_wirelessProvider->startBrowsing();
+
+ // Populate initial devices
+ updateDeviceList();
+}
+
+void OpenSSHTerminalWidget::setupDeviceSelectionUI(QVBoxLayout *layout)
+{
+ // Create scroll area for device selection
+ QScrollArea *scrollArea = new QScrollArea();
+ scrollArea->setWidgetResizable(true);
+ scrollArea->setMinimumHeight(200);
+ scrollArea->setMaximumHeight(300);
+ scrollArea->setObjectName("devicescrollArea");
+
+ scrollArea->setStyleSheet("QWidget#devicescrollArea {border: none;}");
+ QWidget *scrollContent = new QWidget();
+ m_deviceLayout = new QVBoxLayout(scrollContent);
+ m_deviceLayout->setContentsMargins(5, 5, 5, 5);
+ m_deviceLayout->setSpacing(10);
+
+ // Button group for device selection
+ m_deviceButtonGroup = new QButtonGroup(this);
+ connect(m_deviceButtonGroup,
+ QOverload::of(&QButtonGroup::buttonClicked),
+ this, &OpenSSHTerminalWidget::onDeviceSelected);
+
+ // Wired devices group
+ m_wiredDevicesGroup = new QGroupBox("Connected Devices");
+ m_wiredDevicesLayout = new QVBoxLayout(m_wiredDevicesGroup);
+ m_deviceLayout->addWidget(m_wiredDevicesGroup);
+
+ // Wireless devices group
+ m_wirelessDevicesGroup = new QGroupBox("Network Devices");
+ m_wirelessDevicesLayout = new QVBoxLayout(m_wirelessDevicesGroup);
+ m_deviceLayout->addWidget(m_wirelessDevicesGroup);
+
+ scrollArea->setWidget(scrollContent);
+ layout->addWidget(scrollArea);
+
+ // Info and connect button
+ m_infoLabel = new QLabel("Select a device to connect");
+ layout->addWidget(m_infoLabel);
+
+ m_connectButton = new QPushButton("Open SSH Terminal");
+ m_connectButton->setMaximumWidth(m_connectButton->sizeHint().width());
+ m_connectButton->setEnabled(false);
+ connect(m_connectButton, &QPushButton::clicked, this,
+ &OpenSSHTerminalWidget::onOpenSSHTerminal);
+ layout->addWidget(m_connectButton, 0, Qt::AlignCenter);
+}
+
+void OpenSSHTerminalWidget::updateDeviceList()
+{
+ // Clear existing devices
+ clearDeviceButtons();
+
+ // Add wired devices
+ QList wiredDevices =
+ AppContext::sharedInstance()->getAllDevices();
+ for (iDescriptorDevice *device : wiredDevices) {
+ addWiredDevice(device);
+ }
+
+ // Add wireless devices
+ QList wirelessDevices =
+ m_wirelessProvider->getNetworkDevices();
+ for (const NetworkDevice &device : wirelessDevices) {
+ addWirelessDevice(device);
+ }
+}
+
+void OpenSSHTerminalWidget::clearDeviceButtons()
+{
+ // Remove all buttons from button group and layouts
+ for (QAbstractButton *button : m_deviceButtonGroup->buttons()) {
+ m_deviceButtonGroup->removeButton(button);
+ button->deleteLater();
+ }
+
+ // Clear layouts
+ QLayoutItem *item;
+ while ((item = m_wiredDevicesLayout->takeAt(0)) != nullptr) {
+ delete item->widget();
+ delete item;
+ }
+ while ((item = m_wirelessDevicesLayout->takeAt(0)) != nullptr) {
+ delete item->widget();
+ delete item;
+ }
+}
+
+void OpenSSHTerminalWidget::addWiredDevice(iDescriptorDevice *device)
+{
+ QString deviceName = QString::fromStdString(device->deviceInfo.deviceName);
+ QString udid = QString::fromStdString(device->udid);
+ QString displayText = QString("%1\n%2").arg(deviceName, udid);
+
+ QRadioButton *radioButton = new QRadioButton(displayText);
+ radioButton->setProperty("deviceType", "wired");
+ radioButton->setProperty("devicePointer",
+ QVariant::fromValue(static_cast(device)));
+ radioButton->setProperty("udid", udid);
+
+ m_deviceButtonGroup->addButton(radioButton);
+ m_wiredDevicesLayout->addWidget(radioButton);
+}
+
+void OpenSSHTerminalWidget::addWirelessDevice(const NetworkDevice &device)
+{
+ QString displayText = QString("%1\n%2").arg(device.name, device.address);
+
+ QRadioButton *radioButton = new QRadioButton(displayText);
+ radioButton->setProperty("deviceType", "wireless");
+ radioButton->setProperty("deviceAddress", device.address);
+ radioButton->setProperty("deviceName", device.name);
+ radioButton->setProperty("devicePort", device.port);
+
+ m_deviceButtonGroup->addButton(radioButton);
+ m_wirelessDevicesLayout->addWidget(radioButton);
+}
+
+void OpenSSHTerminalWidget::onWiredDeviceAdded(iDescriptorDevice *device)
+{
+ addWiredDevice(device);
+}
+
+void OpenSSHTerminalWidget::onWiredDeviceRemoved(const std::string &udid)
+{
+ QString qudid = QString::fromStdString(udid);
+
+ // Find and remove the corresponding radio button
+ for (QAbstractButton *button : m_deviceButtonGroup->buttons()) {
+ if (button->property("deviceType").toString() == "wired" &&
+ button->property("udid").toString() == qudid) {
+ m_deviceButtonGroup->removeButton(button);
+ button->deleteLater();
+ break;
+ }
+ }
+
+ // Reset selection if this device was selected
+ if (m_selectedDeviceType == DeviceType::Wired && m_selectedWiredDevice &&
+ m_selectedWiredDevice->udid == udid) {
+ resetSelection();
+ }
+}
+
+void OpenSSHTerminalWidget::onWirelessDeviceAdded(const NetworkDevice &device)
+{
+ addWirelessDevice(device);
+}
+
+void OpenSSHTerminalWidget::onWirelessDeviceRemoved(const QString &deviceName)
+{
+ // Find and remove the corresponding radio button
+ for (QAbstractButton *button : m_deviceButtonGroup->buttons()) {
+ if (button->property("deviceType").toString() == "wireless" &&
+ button->property("deviceName").toString() == deviceName) {
+ m_deviceButtonGroup->removeButton(button);
+ button->deleteLater();
+ break;
+ }
+ }
+
+ // Reset selection if this device was selected
+ if (m_selectedDeviceType == DeviceType::Wireless &&
+ m_selectedNetworkDevice.name == deviceName) {
+ resetSelection();
+ }
+}
+
+void OpenSSHTerminalWidget::onDeviceSelected(QAbstractButton *button)
+{
+ QString deviceType = button->property("deviceType").toString();
+
+ if (deviceType == "wired") {
+ m_selectedDeviceType = DeviceType::Wired;
+ m_selectedWiredDevice = static_cast(
+ button->property("devicePointer").value());
+
+ if (m_selectedWiredDevice->deviceInfo.jailbroken) {
+ m_infoLabel->setText("Jailbroken device selected");
+ } else {
+ m_infoLabel->setText(
+ "Device selected (detected as non-jailbroken)");
+ }
+ } else if (deviceType == "wireless") {
+ m_selectedDeviceType = DeviceType::Wireless;
+ m_selectedNetworkDevice.name =
+ button->property("deviceName").toString();
+ m_selectedNetworkDevice.address =
+ button->property("deviceAddress").toString();
+ m_selectedNetworkDevice.port = button->property("devicePort").toUInt();
+
+ m_infoLabel->setText(
+ "Network device selected (jailbreak status unknown)");
+ }
+
+ m_connectButton->setEnabled(true);
+ m_connectButton->setText("Open SSH Terminal");
+}
+
+void OpenSSHTerminalWidget::resetSelection()
+{
+ m_selectedDeviceType = DeviceType::None;
+ m_selectedWiredDevice = nullptr;
+ m_selectedNetworkDevice = NetworkDevice{};
+ m_connectButton->setEnabled(false);
+ m_infoLabel->setText("Select a device to connect");
+
+ // Uncheck all radio buttons
+ if (m_deviceButtonGroup->checkedButton()) {
+ m_deviceButtonGroup->setExclusive(false);
+ m_deviceButtonGroup->checkedButton()->setChecked(false);
+ m_deviceButtonGroup->setExclusive(true);
+ }
+}
+
+void OpenSSHTerminalWidget::onOpenSSHTerminal()
+{
+ if (m_selectedDeviceType == DeviceType::None) {
+ m_infoLabel->setText("Please select a device first");
+ return;
+ }
+
+ // Prepare connection info
+ ConnectionInfo connectionInfo;
+
+ if (m_selectedDeviceType == DeviceType::Wired) {
+ if (!m_selectedWiredDevice) {
+ m_infoLabel->setText("No wired device selected");
+ return;
+ }
+
+ connectionInfo.type = ConnectionType::Wired;
+ connectionInfo.deviceName = QString::fromStdString(
+ m_selectedWiredDevice->deviceInfo.deviceName);
+ connectionInfo.deviceUdid =
+ QString::fromStdString(m_selectedWiredDevice->udid);
+ connectionInfo.hostAddress = "127.0.0.1";
+ connectionInfo.port = 22;
+
+ } else if (m_selectedDeviceType == DeviceType::Wireless) {
+ connectionInfo.type = ConnectionType::Wireless;
+ connectionInfo.deviceName = m_selectedNetworkDevice.name;
+ connectionInfo.deviceUdid = "";
+ connectionInfo.hostAddress = m_selectedNetworkDevice.address;
+ connectionInfo.port = m_selectedNetworkDevice.port;
+ }
+
+ // Create and show SSH terminal widget in a new window
+ SSHTerminalWidget *sshTerminal = new SSHTerminalWidget(connectionInfo);
+ sshTerminal->setAttribute(Qt::WA_DeleteOnClose);
+ sshTerminal->show();
+ sshTerminal->raise();
+ sshTerminal->activateWindow();
+}
+
+OpenSSHTerminalWidget::~OpenSSHTerminalWidget() {}
diff --git a/src/opensshterminalwidget.h b/src/opensshterminalwidget.h
new file mode 100644
index 0000000..7a04b21
--- /dev/null
+++ b/src/opensshterminalwidget.h
@@ -0,0 +1,99 @@
+/*
+ * iDescriptor: A free and open-source idevice management tool.
+ *
+ * Copyright (C) 2025 Uncore
+ *
+ * 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 .
+ */
+
+#ifndef OPENSSHTERMINALWIDGET_H
+#define OPENSSHTERMINALWIDGET_H
+
+#include
+#ifdef __linux__
+#include "core/services/avahi/avahi_service.h"
+#else
+#include "core/services/dnssd/dnssd_service.h"
+#endif
+
+#include "iDescriptor.h"
+#include "sshterminalwidget.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+enum class DeviceType { None, Wired, Wireless };
+
+class OpenSSHTerminalWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit OpenSSHTerminalWidget(QWidget *parent = nullptr);
+ ~OpenSSHTerminalWidget();
+private slots:
+ void onOpenSSHTerminal();
+ void onWiredDeviceAdded(iDescriptorDevice *device);
+ void onWiredDeviceRemoved(const std::string &udid);
+ void onWirelessDeviceAdded(const NetworkDevice &device);
+ void onWirelessDeviceRemoved(const QString &deviceName);
+ void onDeviceSelected(QAbstractButton *button);
+
+private:
+ void setupDeviceSelectionUI(QVBoxLayout *layout);
+ void updateDeviceList();
+ void clearDeviceButtons();
+ void addWiredDevice(iDescriptorDevice *device);
+ void addWirelessDevice(const NetworkDevice &device);
+ void resetSelection();
+
+ QLabel *m_infoLabel;
+ QPushButton *m_connectButton;
+
+ // Device selection UI
+ QVBoxLayout *m_deviceLayout;
+ QGroupBox *m_wiredDevicesGroup;
+ QGroupBox *m_wirelessDevicesGroup;
+ QVBoxLayout *m_wiredDevicesLayout;
+ QVBoxLayout *m_wirelessDevicesLayout;
+ QButtonGroup *m_deviceButtonGroup;
+
+#ifdef __linux__
+ AvahiService *m_wirelessProvider = nullptr;
+#else
+ DnssdService *m_wirelessProvider = nullptr;
+#endif
+
+ DeviceType m_selectedDeviceType = DeviceType::None;
+ iDescriptorDevice *m_selectedWiredDevice = nullptr;
+ NetworkDevice m_selectedNetworkDevice;
+
+ // Legacy device pointer (kept for compatibility)
+ iDescriptorDevice *m_device = nullptr;
+
+ // SSH components
+ ssh_session m_sshSession;
+ ssh_channel m_sshChannel;
+ QTimer *m_sshTimer;
+ QProcess *iproxyProcess = nullptr;
+
+ bool m_sshConnected = false;
+ bool m_isInitialized = false;
+signals:
+};
+
+#endif // OPENSSHTERMINALWIDGET_H
diff --git a/src/photoimportdialog.cpp b/src/photoimportdialog.cpp
index 8a7e8d9..89da104 100644
--- a/src/photoimportdialog.cpp
+++ b/src/photoimportdialog.cpp
@@ -135,13 +135,14 @@ void PhotoImportDialog::onServerStarted()
QString localIP = getLocalIP();
int port = m_httpServer->getPort();
QString jsonFileName = m_httpServer->getJsonFileName();
-
- generateQRCode(
- QString("http://192.168.1.149:5173/?local=%1&port=%2&file=%3")
- // QString("https://uncor3.github.io/test-2?local=%1&port=%2&file=%3")
+ QString url =
+ QString("https://idescriptor.github.io/import?local=%1&port=%2&file=%3")
.arg(localIP)
.arg(port)
- .arg(jsonFileName));
+ .arg(jsonFileName);
+ qDebug() << "Server url" << url;
+
+ generateQRCode(url);
instructionLabel->setText(
QString("Server started at %1:%2\n\n1. Scan the QR code to open the "
diff --git a/src/photomodel.cpp b/src/photomodel.cpp
index 00ea1ef..608c7c7 100644
--- a/src/photomodel.cpp
+++ b/src/photomodel.cpp
@@ -44,8 +44,8 @@ PhotoModel::PhotoModel(iDescriptorDevice *device, QObject *parent)
"/photo_thumbs";
QDir().mkpath(m_cacheDir);
- // Configure memory cache (50MB limit - much more reasonable)
- m_thumbnailCache.setMaxCost(50 * 1024 * 1024);
+ // Configure memory cache (150MB limit)
+ m_thumbnailCache.setMaxCost(150 * 1024 * 1024);
connect(this, &PhotoModel::thumbnailNeedsToBeLoaded, this,
&PhotoModel::requestThumbnail, Qt::QueuedConnection);
@@ -55,6 +55,7 @@ PhotoModel::PhotoModel(iDescriptorDevice *device, QObject *parent)
PhotoModel::~PhotoModel()
{
+ qDebug() << "PhotoModel destructor called";
// Clean up any active watchers
for (auto *watcher : m_activeLoaders.values()) {
if (watcher) {
@@ -64,6 +65,9 @@ PhotoModel::~PhotoModel()
}
}
m_activeLoaders.clear();
+ m_loadingPaths.clear();
+ m_thumbnailCache.clear();
+ QDir(m_cacheDir).removeRecursively();
}
QPixmap PhotoModel::generateVideoThumbnail(iDescriptorDevice *device,
@@ -262,12 +266,16 @@ void PhotoModel::requestThumbnail(int index)
// Remove from loading sets
m_loadingPaths.remove(filePath);
m_activeLoaders.remove(cacheKey);
-
+ // scale down and store in cache
if (!thumbnail.isNull()) {
// Cache the thumbnail (both memory and disk)
int cost = thumbnail.width() * thumbnail.height() * 4;
- m_thumbnailCache.insert(cacheKey, new QPixmap(thumbnail),
- cost);
+ m_thumbnailCache.insert(
+ cacheKey,
+ new QPixmap(thumbnail.scaled(m_thumbnailSize,
+ Qt::KeepAspectRatio,
+ Qt::SmoothTransformation)),
+ cost);
// Find the model index and emit dataChanged
for (int i = 0; i < m_photos.size(); ++i) {
@@ -714,6 +722,20 @@ PhotoInfo::FileType PhotoModel::determineFileType(const QString &fileName) const
void PhotoModel::setAlbumPath(const QString &albumPath)
{
if (m_albumPath != albumPath) {
+ // Clear cache when switching albums to prevent memory buildup
+ clearCache();
+
+ // Cancel any pending thumbnail requests
+ for (auto *watcher : m_activeLoaders.values()) {
+ if (watcher) {
+ watcher->cancel();
+ watcher->waitForFinished();
+ watcher->deleteLater();
+ }
+ }
+ m_activeLoaders.clear();
+ m_loadingPaths.clear();
+
m_albumPath = albumPath;
populatePhotoPaths();
}
diff --git a/src/sponsorwidget.cpp b/src/sponsorwidget.cpp
index 4cd1fdc..1754afd 100644
--- a/src/sponsorwidget.cpp
+++ b/src/sponsorwidget.cpp
@@ -26,6 +26,7 @@ SponsorWidget::SponsorWidget(QWidget *parent) : QWidget(parent)
{
setLayout(new QVBoxLayout(this));
QLabel *sponsorTitle = new QLabel("Would you like to sponsor us?");
+ sponsorTitle->setStyleSheet("font-weight: bold; font-size: 16pt;");
sponsorTitle->setAlignment(Qt::AlignCenter);
QLabel *sponsorDesc =
@@ -33,6 +34,7 @@ SponsorWidget::SponsorWidget(QWidget *parent) : QWidget(parent)
"And in order to keep it that way, we rely on donations. "
"Consider becoming a sponsor to support "
"and promote your app/brand here");
+ sponsorDesc->setStyleSheet("font-size: 10pt;");
sponsorDesc->setWordWrap(true);
layout()->addWidget(sponsorTitle);
layout()->addWidget(sponsorDesc);
diff --git a/src/toolboxwidget.cpp b/src/toolboxwidget.cpp
index d78d07b..a1d2f91 100644
--- a/src/toolboxwidget.cpp
+++ b/src/toolboxwidget.cpp
@@ -28,10 +28,10 @@
#ifndef __APPLE__
#include "ifusewidget.h"
#endif
+#include "livescreenwidget.h"
#include "querymobilegestaltwidget.h"
-#include "realtimescreenwidget.h"
#include "virtuallocationwidget.h"
-#include "wirelessphotoimportwidget.h"
+#include "wirelessgalleryimportwidget.h"
#include
#include
#include
@@ -138,17 +138,15 @@ void ToolboxWidget::setupUI()
{iDescriptorTool::Airplayer, "Cast your device screen ", false, ""});
mainToolWidgets.append({iDescriptorTool::VirtualLocation,
"Simulate GPS location on your device", true, ""});
- mainToolWidgets.append(
- {iDescriptorTool::RealtimeScreen,
- "View device screen in real-time (wired connection required)", true,
- ""});
+ mainToolWidgets.append({iDescriptorTool::LiveScreen,
+ "View device screen in real-time", true, ""});
mainToolWidgets.append({iDescriptorTool::QueryMobileGestalt,
"Query device hardware information", true, ""});
mainToolWidgets.append({iDescriptorTool::DeveloperDiskImages,
"Manage developer disk images", false, ""});
mainToolWidgets.append(
- {iDescriptorTool::WirelessPhotoImport,
- "Import photos wirelessly to your iDevice (requires Shortcut app)",
+ {iDescriptorTool::WirelessGalleryImport,
+ "Import photos wirelessly to your iDevice (requires Shortcuts app)",
false, ""});
#ifndef __APPLE__
mainToolWidgets.append({iDescriptorTool::iFuse,
@@ -222,59 +220,75 @@ ClickableWidget *ToolboxWidget::createToolbox(iDescriptorTool tool,
QVBoxLayout *layout = new QVBoxLayout(b);
- // Icon
- QLabel *iconLabel = new QLabel();
- QIcon icon =
- // TODO:icons
- this->style()->standardIcon(
- static_cast(QStyle::SP_DialogOkButton));
- iconLabel->setPixmap(icon.pixmap(32, 32));
- iconLabel->setAlignment(Qt::AlignCenter);
+ ZIconLabel *icon = new ZIconLabel(QIcon(), nullptr, this);
QString title;
switch (tool) {
case iDescriptorTool::Airplayer:
title = "Airplayer";
+ icon->setIcon(
+ QIcon(":/resources/icons/MaterialSymbolsLightAirplayOutline.png"));
break;
- case iDescriptorTool::RealtimeScreen:
- title = "Realtime Screen";
+ case iDescriptorTool::LiveScreen:
+ title = "Live Screen";
+ icon->setIcon(QIcon(":/resources/icons/PepiconsPrintCellphoneEye.png"));
break;
case iDescriptorTool::MountDevImage:
title = "Mount Dev Image";
+ icon->setIcon(QIcon(":/resources/icons/MdiDisk.png"));
break;
case iDescriptorTool::VirtualLocation:
title = "Virtual Location";
+ icon->setIcon(
+ QIcon(":/resources/icons/MaterialSymbolsLocationOnOutline.png"));
break;
case iDescriptorTool::Restart:
title = "Restart";
+ icon->setIcon(QIcon(":/resources/icons/IcTwotoneRestartAlt.png"));
break;
case iDescriptorTool::Shutdown:
title = "Shutdown";
+ icon->setIcon(QIcon(":/resources/icons/IcOutlinePowerSettingsNew.png"));
break;
case iDescriptorTool::RecoveryMode:
title = "Recovery Mode";
+ icon->setIcon(QIcon(":/resources/icons/HugeiconsWrench01.png"));
break;
case iDescriptorTool::QueryMobileGestalt:
title = "Query Mobile Gestalt";
+ icon->setIcon(
+ QIcon(":/resources/icons/"
+ "StreamlineProgrammingBrowserSearchSearchWindowGlassAppCod"
+ "eProgrammingQueryFindMagnifyingApps.png"));
break;
case iDescriptorTool::DeveloperDiskImages:
title = "Dev Disk Images";
+ icon->setIcon(QIcon(":/resources/icons/TablerDatabaseExport.png"));
break;
- case iDescriptorTool::WirelessPhotoImport:
- title = "Wireless Photo Import";
+ case iDescriptorTool::WirelessGalleryImport:
+ title = "Wireless Gallery Import";
+ icon->setIcon(
+ QIcon(":/resources/icons/MaterialSymbolsAndroidWifi3BarPlus.png"));
break;
case iDescriptorTool::iFuse:
title = "iFuse Mount";
+ icon->setIcon(QIcon(":/resources/icons/fuse.png"));
+ icon->setIconThemable(false);
break;
case iDescriptorTool::CableInfoWidget:
title = "Cable Info";
+ icon->setIcon(
+ QIcon(":/resources/icons/MaterialSymbolsLightCableRounded.png"));
break;
case iDescriptorTool::NetworkDevices:
title = "Network Devices";
+ icon->setIcon(QIcon(
+ ":/resources/icons/StreamlineUltimateMultipleUsersNetwork.png"));
break;
default:
title = "Unknown Tool";
break;
}
+
// Title
QLabel *titleLabel = new QLabel(title);
titleLabel->setAlignment(Qt::AlignCenter);
@@ -284,8 +298,10 @@ ClickableWidget *ToolboxWidget::createToolbox(iDescriptorTool tool,
descLabel->setWordWrap(true);
descLabel->setAlignment(Qt::AlignCenter);
descLabel->setStyleSheet("color: #666; font-size: 12px;");
+ icon->setFixedSize(60, 60);
+ icon->setIconSize(QSize(45, 45));
- layout->addWidget(iconLabel);
+ layout->addWidget(icon, 0, Qt::AlignCenter);
layout->addWidget(titleLabel);
layout->addWidget(descLabel);
@@ -321,8 +337,6 @@ void ToolboxWidget::updateDeviceList()
}
}
- // After rebuilding the list, explicitly sync the UI to match the
- // state from AppContext. This avoids creating a feedback loop.
onCurrentDeviceChanged(
AppContext::sharedInstance()->getCurrentDeviceSelection());
@@ -410,11 +424,10 @@ void ToolboxWidget::onToolboxClicked(iDescriptorTool tool)
}
} break;
- case iDescriptorTool::RealtimeScreen: {
- RealtimeScreenWidget *realtimeScreen =
- new RealtimeScreenWidget(m_currentDevice);
- realtimeScreen->setAttribute(Qt::WA_DeleteOnClose);
- realtimeScreen->show();
+ case iDescriptorTool::LiveScreen: {
+ LiveScreenWidget *liveScreen = new LiveScreenWidget(m_currentDevice);
+ liveScreen->setAttribute(Qt::WA_DeleteOnClose);
+ liveScreen->show();
} break;
case iDescriptorTool::RecoveryMode: {
// Handle entering recovery mode
@@ -498,18 +511,18 @@ void ToolboxWidget::onToolboxClicked(iDescriptorTool tool)
m_devDiskImagesWidget->activateWindow();
}
} break;
- case iDescriptorTool::WirelessPhotoImport: {
- if (!m_wirelessPhotoImportWidget) {
- m_wirelessPhotoImportWidget = new WirelessPhotoImportWidget();
- connect(m_wirelessPhotoImportWidget, &QObject::destroyed, this,
- [this]() { m_wirelessPhotoImportWidget = nullptr; });
- m_wirelessPhotoImportWidget->setAttribute(Qt::WA_DeleteOnClose);
- m_wirelessPhotoImportWidget->setWindowFlag(Qt::Window);
- // m_wirelessPhotoImportWidget->resize(800, 600);
- m_wirelessPhotoImportWidget->show();
+ case iDescriptorTool::WirelessGalleryImport: {
+ if (!m_wirelessGalleryImportWidget) {
+ m_wirelessGalleryImportWidget = new WirelessGalleryImportWidget();
+ connect(m_wirelessGalleryImportWidget, &QObject::destroyed, this,
+ [this]() { m_wirelessGalleryImportWidget = nullptr; });
+ m_wirelessGalleryImportWidget->setAttribute(Qt::WA_DeleteOnClose);
+ m_wirelessGalleryImportWidget->setWindowFlag(Qt::Window);
+ // m_wirelessGalleryImportWidget->resize(800, 600);
+ m_wirelessGalleryImportWidget->show();
} else {
- m_wirelessPhotoImportWidget->raise();
- m_wirelessPhotoImportWidget->activateWindow();
+ m_wirelessGalleryImportWidget->raise();
+ m_wirelessGalleryImportWidget->activateWindow();
}
} break;
#ifndef __APPLE__
diff --git a/src/toolboxwidget.h b/src/toolboxwidget.h
index cd5cc83..1aa65b6 100644
--- a/src/toolboxwidget.h
+++ b/src/toolboxwidget.h
@@ -26,7 +26,7 @@
#include "iDescriptor-ui.h"
#include "iDescriptor.h"
#include "networkdeviceswidget.h"
-#include "wirelessphotoimportwidget.h"
+#include "wirelessgalleryimportwidget.h"
#include
#include
#include
@@ -75,7 +75,7 @@ private:
#ifndef __APPLE__
iFuseWidget *m_ifuseWidget = nullptr;
#endif
- WirelessPhotoImportWidget *m_wirelessPhotoImportWidget = nullptr;
+ WirelessGalleryImportWidget *m_wirelessGalleryImportWidget = nullptr;
signals:
};
diff --git a/src/welcomewidget.cpp b/src/welcomewidget.cpp
index 338ffb0..ef22c9b 100644
--- a/src/welcomewidget.cpp
+++ b/src/welcomewidget.cpp
@@ -35,7 +35,7 @@ void WelcomeWidget::setupUI()
{
// Main layout with proper spacing and margins
m_mainLayout = new QVBoxLayout(this);
- m_mainLayout->setContentsMargins(0, 0, 0, 0);
+ m_mainLayout->setContentsMargins(0, 10, 0, 0);
m_mainLayout->setSpacing(0);
// Add top stretch
diff --git a/src/wirelessgalleryimportwidget.cpp b/src/wirelessgalleryimportwidget.cpp
index cc8dcbd..294e06c 100644
--- a/src/wirelessgalleryimportwidget.cpp
+++ b/src/wirelessgalleryimportwidget.cpp
@@ -87,7 +87,7 @@ void WirelessGalleryImportWidget::setupUI()
leftLayout->addWidget(m_scrollArea, 1);
// Import button
- m_importButton = new QPushButton("Import Photos to iOS");
+ m_importButton = new QPushButton("Import to Gallery");
m_importButton->setEnabled(false);
connect(m_importButton, &QPushButton::clicked, this,
&WirelessGalleryImportWidget::onImportPhotos);