diff --git a/resources.qrc b/resources.qrc index 0471523..5b98687 100644 --- a/resources.qrc +++ b/resources.qrc @@ -12,5 +12,28 @@ qml/MapView.qml resources/dump.js resources/iphone.png + resources/ios-wallpapers/iphone-ios4.png + resources/ios-wallpapers/iphone-ios5.png + resources/ios-wallpapers/iphone-ios6.png + resources/ios-wallpapers/iphone-ios7.png + resources/ios-wallpapers/iphone-ios8.png + resources/ios-wallpapers/iphone-ios9.png + resources/ios-wallpapers/iphone-ios10.png + resources/ios-wallpapers/iphone-ios11.png + resources/ios-wallpapers/iphone-ios12.png + resources/ios-wallpapers/iphone-ios13.png + resources/ios-wallpapers/iphone-ios14.png + resources/ios-wallpapers/iphone-ios15.png + resources/ios-wallpapers/iphone-ios16.png + resources/ios-wallpapers/iphone-ios17.png + resources/ios-wallpapers/iphone-ios18.png + resources/ios-wallpapers/iphone-ios26.png + resources/iphone-mockups/iphone-3.png + resources/iphone-mockups/iphone-4.png + resources/iphone-mockups/iphone-5.png + resources/iphone-mockups/iphone-6.png + resources/iphone-mockups/iphone-x.png + resources/iphone-mockups/iphone-15.png + resources/iphone-mockups/iphone-16.png \ No newline at end of file diff --git a/resources/ios-wallpapers/iphone-ios10.png b/resources/ios-wallpapers/iphone-ios10.png new file mode 100644 index 0000000..b221f16 Binary files /dev/null and b/resources/ios-wallpapers/iphone-ios10.png differ diff --git a/resources/ios-wallpapers/iphone-ios11.png b/resources/ios-wallpapers/iphone-ios11.png new file mode 100644 index 0000000..d8781c5 Binary files /dev/null and b/resources/ios-wallpapers/iphone-ios11.png differ diff --git a/resources/ios-wallpapers/iphone-ios12.png b/resources/ios-wallpapers/iphone-ios12.png new file mode 100644 index 0000000..7fc1379 Binary files /dev/null and b/resources/ios-wallpapers/iphone-ios12.png differ diff --git a/resources/ios-wallpapers/iphone-ios5.png b/resources/ios-wallpapers/iphone-ios5.png new file mode 100644 index 0000000..ca429fa Binary files /dev/null and b/resources/ios-wallpapers/iphone-ios5.png differ diff --git a/resources/iphone-mockups/iphone-15.png b/resources/iphone-mockups/iphone-15.png new file mode 100755 index 0000000..92e5680 Binary files /dev/null and b/resources/iphone-mockups/iphone-15.png differ diff --git a/resources/iphone-mockups/iphone-16.png b/resources/iphone-mockups/iphone-16.png new file mode 100755 index 0000000..2445a57 Binary files /dev/null and b/resources/iphone-mockups/iphone-16.png differ diff --git a/resources/iphone-mockups/iphone-3.png b/resources/iphone-mockups/iphone-3.png new file mode 100755 index 0000000..a788d2e Binary files /dev/null and b/resources/iphone-mockups/iphone-3.png differ diff --git a/resources/iphone-mockups/iphone-4.png b/resources/iphone-mockups/iphone-4.png new file mode 100755 index 0000000..7344ceb Binary files /dev/null and b/resources/iphone-mockups/iphone-4.png differ diff --git a/resources/iphone-mockups/iphone-5.png b/resources/iphone-mockups/iphone-5.png new file mode 100755 index 0000000..0b23128 Binary files /dev/null and b/resources/iphone-mockups/iphone-5.png differ diff --git a/resources/iphone-mockups/iphone-6.png b/resources/iphone-mockups/iphone-6.png new file mode 100755 index 0000000..b37bff6 Binary files /dev/null and b/resources/iphone-mockups/iphone-6.png differ diff --git a/resources/iphone-mockups/iphone-x.png b/resources/iphone-mockups/iphone-x.png new file mode 100755 index 0000000..f0cd464 Binary files /dev/null and b/resources/iphone-mockups/iphone-x.png differ diff --git a/src/deviceimagewidget.cpp b/src/deviceimagewidget.cpp new file mode 100644 index 0000000..3de8fc4 --- /dev/null +++ b/src/deviceimagewidget.cpp @@ -0,0 +1,297 @@ +#include "deviceimagewidget.h" +#include +#include +#include +#include +#include +#include + +DeviceImageWidget::DeviceImageWidget(iDescriptorDevice *device, QWidget *parent) + : QWidget(parent), m_device(device) +{ + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + + m_imageLabel = new ResponsiveQLabel(this); + m_imageLabel->setMinimumWidth(200); + m_imageLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + m_imageLabel->setStyleSheet("background: transparent; border: none;"); + + layout->addWidget(m_imageLabel); + + setupDeviceImage(); + m_timeUpdateTimer = new QTimer(this); + connect(m_timeUpdateTimer, &QTimer::timeout, this, + &DeviceImageWidget::updateTime); + m_timeUpdateTimer->start(60000); // Update every minute + + updateTime(); +} + +DeviceImageWidget::~DeviceImageWidget() +{ + if (m_timeUpdateTimer) { + m_timeUpdateTimer->stop(); + } +} + +void DeviceImageWidget::setupDeviceImage() +{ + m_mockupPath = getDeviceMockupPath(); + m_wallpaperPath = getWallpaperPath(); + + qDebug() << "Using mockup:" << m_mockupPath; + qDebug() << "Using wallpaper:" << m_wallpaperPath; +} + +QString DeviceImageWidget::getDeviceMockupPath() const +{ + QString displayName = + QString::fromStdString(m_device->deviceInfo.productType); + QString mockupName = getMockupNameFromDisplayName(displayName); + + return QString(":/resources/iphone-mockups/iphone-%1.png").arg(mockupName); +} + +QString DeviceImageWidget::getWallpaperPath() const +{ + int iosVersion = getIosVersionFromDevice(); + + // Map iOS version to available wallpapers + QString wallpaperVersion; + if (iosVersion >= 18) { + wallpaperVersion = "ios18"; + } else if (iosVersion >= 17) { + wallpaperVersion = "ios17"; + } else if (iosVersion >= 16) { + wallpaperVersion = "ios16"; + } else if (iosVersion >= 15) { + wallpaperVersion = "ios15"; + } else if (iosVersion >= 14) { + wallpaperVersion = "ios14"; + } else if (iosVersion >= 13) { + wallpaperVersion = "ios13"; + } else if (iosVersion >= 12) { + wallpaperVersion = "ios12"; + } else if (iosVersion >= 11) { + wallpaperVersion = "ios11"; + } else if (iosVersion >= 10) { + wallpaperVersion = "ios10"; + } else if (iosVersion >= 9) { + wallpaperVersion = "ios9"; + } else if (iosVersion >= 8) { + wallpaperVersion = "ios8"; + } else if (iosVersion >= 7) { + wallpaperVersion = "ios7"; + } else if (iosVersion >= 6) { + wallpaperVersion = "ios6"; + } else if (iosVersion >= 5) { + wallpaperVersion = "ios5"; + } else if (iosVersion >= 4) { + wallpaperVersion = "ios4"; + } else { + // Unknown version, use ios26 as fallback + wallpaperVersion = "ios26"; + } + + return QString(":/resources/ios-wallpapers/iphone-%1.png") + .arg(wallpaperVersion); +} + +QString DeviceImageWidget::getMockupNameFromDisplayName( + const QString &displayName) const +{ + // Map device names to mockup files + if (displayName.contains("iPhone 16", Qt::CaseInsensitive)) { + return "16"; + } else if (displayName.contains("iPhone 15", Qt::CaseInsensitive)) { + return "15"; + } else if (displayName.contains("iPhone X", Qt::CaseInsensitive) || + displayName.contains("iPhone 11", Qt::CaseInsensitive) || + displayName.contains("iPhone 12", Qt::CaseInsensitive) || + displayName.contains("iPhone 13", Qt::CaseInsensitive) || + displayName.contains("iPhone 14", Qt::CaseInsensitive)) { + return "x"; + } else if (displayName.contains("iPhone 6", Qt::CaseInsensitive) || + displayName.contains("iPhone 7", Qt::CaseInsensitive) || + displayName.contains("iPhone 8", Qt::CaseInsensitive)) { + return "6"; + } else if (displayName.contains("iPhone 5", Qt::CaseInsensitive) || + displayName.contains("iPhone SE", Qt::CaseInsensitive)) { + return "5"; + } else if (displayName.contains("iPhone 4", Qt::CaseInsensitive)) { + return "4"; + } else if (displayName.contains("iPhone 3", Qt::CaseInsensitive)) { + return "3"; + } else { + // Unknown device, use iPhone X as default + return "x"; + } +} + +int DeviceImageWidget::getIosVersionFromDevice() const +{ + unsigned int version = idevice_get_device_version(m_device->device); + + if (version > 0) { + int majorVersion = (version >> 16) & 0xFF; + return majorVersion; + } + + // Fallback: parse from productVersion string + QString versionString = + QString::fromStdString(m_device->deviceInfo.productVersion); + QStringList parts = versionString.split('.'); + if (!parts.isEmpty()) { + bool ok; + int majorVersion = parts.first().toInt(&ok); + if (ok) { + return majorVersion; + } + } + + // If all else fails, return unknown version (will use ios26 wallpaper) + return 0; +} + +/* + this method is only here to calculate the screen area + so that wallpaper perfectly fits to the screen size + it's costy so if you want to add a new mock run + through this method qDebug the result and add it to createCompositeImage + example : screenRect = QRect(152, 79, 195, 296); +*/ +QRect DeviceImageWidget::findScreenArea(const QPixmap &mockup) const +{ + QImage image = mockup.toImage().convertToFormat(QImage::Format_ARGB32); + if (image.isNull()) { + return QRect(); + } + + int width = image.width(); + int height = image.height(); + int centerX = width / 2; + int centerY = height / 2; + + if (qAlpha(image.pixel(centerX, centerY)) != 0) { + qWarning() << "Cannot find screen area: center pixel is not " + "transparent. Falling back to default."; + return QRect(width * 0.1, height * 0.1, width * 0.8, height * 0.8); + } + + int left = centerX; + int right = centerX; + int top = centerY; + int bottom = centerY; + + // Scan left from center + while (left > 0 && qAlpha(image.pixel(left, centerY)) == 0) { + left--; + } + + // Scan right from center + while (right < width - 1 && qAlpha(image.pixel(right, centerY)) == 0) { + right++; + } + + // Scan up from center + while (top > 0 && qAlpha(image.pixel(centerX, top)) == 0) { + top--; + } + + // Scan down from center + while (bottom < height - 1 && qAlpha(image.pixel(centerX, bottom)) == 0) { + bottom++; + } + + // Add a small margin to avoid drawing over the bezel anti-aliasing + int margin = 2; + + return QRect(left + 1 + margin, top + 1 + margin, + right - left - 2 - (margin * 2), + bottom - top - 2 - (margin * 2)); +} + +QPixmap DeviceImageWidget::createCompositeImage() const +{ + QPixmap mockup(m_mockupPath); + QPixmap wallpaper(m_wallpaperPath); + + if (mockup.isNull()) { + qWarning() << "Failed to load mockup:" << m_mockupPath; + return QPixmap(":/resources/iphone.png"); // Fallback + } + + if (wallpaper.isNull()) { + qWarning() << "Failed to load wallpaper:" << m_wallpaperPath; + return mockup; // Return just the mockup + } + + // Start with the mockup as the base layer + QPixmap composite = mockup.copy(); + QPainter painter(&composite); + painter.setRenderHint(QPainter::Antialiasing); + painter.setRenderHint(QPainter::SmoothPixmapTransform); + + // Use pre-calculated screen areas for optimal performance + QRect screenRect; + QString mockupName = getMockupNameFromDisplayName( + QString::fromStdString(m_device->deviceInfo.productType)); + + if (mockupName == "3") { + screenRect = QRect(152, 79, 195, 296); + } else if (mockupName == "4") { + screenRect = QRect(421, 188, 366, 534); + } else if (mockupName == "5") { + screenRect = QRect(34, 113, 290, 523); + } else if (mockupName == "6") { + screenRect = QRect(75, 355, 1265, 2256); + } else if (mockupName == "x") { + screenRect = QRect(252, 436, 2375, 4989); + } else if (mockupName == "15") { + screenRect = QRect(22, 56, 323, 674); + } else if (mockupName == "16") { + screenRect = QRect(24, 61, 319, 668); + } else { + // Fallback for unknown devices + screenRect = QRect(mockup.width() * 0.12, mockup.height() * 0.08, + mockup.width() * 0.76, mockup.height() * 0.84); + } + + // Draw wallpaper BEHIND the mockup (into the screen area) + QPixmap scaledWallpaper = wallpaper.scaled( + screenRect.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + painter.drawPixmap(screenRect, scaledWallpaper); + + // Draw current time in the center of the screen + QString currentTime = QDateTime::currentDateTime().toString("hh:mm"); + + // Setup text rendering with better font sizing + QFont timeFont; + timeFont.setFamily("SF Pro Display, Helvetica, Arial"); + + // Scale font size based on screen dimensions + int fontSize = screenRect.width() / 5; + timeFont.setPointSize(fontSize); + timeFont.setWeight(QFont::Light); + + painter.setFont(timeFont); + + // Draw text shadow for better readability + painter.setPen(QColor(0, 0, 0, 150)); + painter.drawText(screenRect.adjusted(2, 2, 2, 2), Qt::AlignCenter, + currentTime); + + // Draw main text - perfectly centered in the screen area + painter.setPen(QColor(255, 255, 255, 255)); + painter.drawText(screenRect, Qt::AlignCenter, currentTime); + + painter.end(); + return composite; +} + +void DeviceImageWidget::updateTime() +{ + QPixmap composite = createCompositeImage(); + m_imageLabel->setPixmap(composite); +} \ No newline at end of file diff --git a/src/deviceimagewidget.h b/src/deviceimagewidget.h new file mode 100644 index 0000000..a1bc10b --- /dev/null +++ b/src/deviceimagewidget.h @@ -0,0 +1,38 @@ +#ifndef DEVICEIMAGEWIDGET_H +#define DEVICEIMAGEWIDGET_H + +#include "iDescriptor.h" +#include "responsiveqlabel.h" +#include +#include + +class DeviceImageWidget : public QWidget +{ + Q_OBJECT + +public: + explicit DeviceImageWidget(iDescriptorDevice *device, + QWidget *parent = nullptr); + ~DeviceImageWidget(); + +private slots: + void updateTime(); + +private: + void setupDeviceImage(); + QString getDeviceMockupPath() const; + QString getWallpaperPath() const; + QString getMockupNameFromDisplayName(const QString &displayName) const; + int getIosVersionFromDevice() const; + QPixmap createCompositeImage() const; + QRect findScreenArea(const QPixmap &mockup) const; + + iDescriptorDevice *m_device; + ResponsiveQLabel *m_imageLabel; + QTimer *m_timeUpdateTimer; + + QString m_mockupPath; + QString m_wallpaperPath; +}; + +#endif // DEVICEIMAGEWIDGET_H \ No newline at end of file diff --git a/src/deviceinfowidget.cpp b/src/deviceinfowidget.cpp index 7d3dec0..731724e 100644 --- a/src/deviceinfowidget.cpp +++ b/src/deviceinfowidget.cpp @@ -35,16 +35,13 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent) // Left side container for image and actions QWidget *leftContainer = new QWidget(); + // leftContainer->setStyleSheet("margin-left: 100px"); QVBoxLayout *leftLayout = new QVBoxLayout(leftContainer); leftLayout->setContentsMargins(0, 0, 0, 0); leftLayout->setSpacing(1); - // Create responsive image label - m_deviceImageLabel = new ResponsiveQLabel(this); - m_deviceImageLabel->setPixmap(QPixmap(":/resources/iphone.png")); - m_deviceImageLabel->setMinimumWidth(200); - m_deviceImageLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - m_deviceImageLabel->setStyleSheet("background: transparent; border: none;"); + // Create responsive device image widget + m_deviceImageWidget = new DeviceImageWidget(device, this); // Actions group box QWidget *actionsWidget = new QWidget(); @@ -80,7 +77,7 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent) actionsLayout->addWidget(recoveryBtn); leftLayout->addStretch(); - leftLayout->addWidget(m_deviceImageLabel); + leftLayout->addWidget(m_deviceImageWidget); leftLayout->addWidget(actionsWidget, 0, Qt::AlignCenter); leftLayout->addStretch(); @@ -329,29 +326,6 @@ void DeviceInfoWidget::onBatteryMoreClicked() msgBox.exec(); } -QPixmap DeviceInfoWidget::getDeviceIcon(const std::string &productType) -{ - // Create a simple colored icon based on device type - QPixmap icon(16, 16); - icon.fill(Qt::transparent); - - QPainter painter(&icon); - painter.setRenderHint(QPainter::Antialiasing); - - if (productType.find("iPhone") != std::string::npos) { - painter.setBrush(QColor(0, 122, 255)); // iOS blue - painter.drawEllipse(2, 2, 12, 12); - } else if (productType.find("iPad") != std::string::npos) { - painter.setBrush(QColor(255, 149, 0)); // Orange - painter.drawRect(2, 2, 12, 12); - } else { - painter.setBrush(QColor(128, 128, 128)); // Gray for unknown - painter.drawEllipse(2, 2, 12, 12); - } - - return icon; -} - void DeviceInfoWidget::updateBatteryInfo() { qDebug() << "Updating battery info..."; diff --git a/src/deviceinfowidget.h b/src/deviceinfowidget.h index 2ef0538..5ab83df 100644 --- a/src/deviceinfowidget.h +++ b/src/deviceinfowidget.h @@ -1,8 +1,8 @@ #ifndef DEVICEINFOWIDGET_H #define DEVICEINFOWIDGET_H #include "batterywidget.h" +#include "deviceimagewidget.h" #include "iDescriptor.h" -#include "responsiveqlabel.h" #include #include #include @@ -18,7 +18,6 @@ private slots: void onBatteryMoreClicked(); private: - QPixmap getDeviceIcon(const std::string &productType); iDescriptorDevice *m_device; QTimer *m_updateTimer; void updateBatteryInfo(); @@ -28,7 +27,7 @@ private: BatteryWidget *m_batteryWidget; QLabel *m_lightningIconLabel; - ResponsiveQLabel *m_deviceImageLabel = nullptr; + DeviceImageWidget *m_deviceImageWidget; }; #endif // DEVICEINFOWIDGET_H diff --git a/src/toolboxwidget.h b/src/toolboxwidget.h index 72618f4..5bf98f5 100644 --- a/src/toolboxwidget.h +++ b/src/toolboxwidget.h @@ -22,8 +22,6 @@ public: static void shutdownDevice(iDescriptorDevice *device); static void _enterRecoveryMode(iDescriptorDevice *device); private slots: - void onDeviceAdded(); - void onDeviceRemoved(); void onDeviceSelectionChanged(); void onToolboxClicked(iDescriptorTool tool);