diff --git a/resources.qrc b/resources.qrc index 4b2c392..ab7ce47 100644 --- a/resources.qrc +++ b/resources.qrc @@ -71,6 +71,7 @@ DeveloperDiskImages.json resources/keychain.mp4 resources/wireless-gallery-import.mp4 + resources/dev-mode.mp4 resources/trust.png \ No newline at end of file diff --git a/resources/dev-mode.mp4 b/resources/dev-mode.mp4 new file mode 100755 index 0000000..5f9b72d Binary files /dev/null and b/resources/dev-mode.mp4 differ diff --git a/src/devdiskmanager.h b/src/devdiskmanager.h index 273dd84..28481f3 100644 --- a/src/devdiskmanager.h +++ b/src/devdiskmanager.h @@ -48,9 +48,6 @@ public: const QString &downloadPath) const; // Mount operations - - bool mountImage(const QString &version, const iDescriptorDevice *device); - bool unmountImage(); std::pair getPathsForVersion(const QString &version); // Signature comparison @@ -58,7 +55,6 @@ public: const char *mounted_sig, uint64_t mounted_sig_len); QByteArray getImageListData() const { return m_imageListJsonData; } - bool mountCompatibleImage(const iDescriptorDevice *device); QString downloadCompatibleImage( const std::shared_ptr device, std::function callback); diff --git a/src/devmodewidget.cpp b/src/devmodewidget.cpp new file mode 100644 index 0000000..225fa45 --- /dev/null +++ b/src/devmodewidget.cpp @@ -0,0 +1,83 @@ +#include "devmodewidget.h" + +DevModeWidget::DevModeWidget(std::shared_ptr device, + QWidget *parent) + : QDialog{parent} +{ + QVBoxLayout *mainLayout = new QVBoxLayout(this); + mainLayout->setContentsMargins(0, 20, 0, 0); + mainLayout->setSpacing(0); + + m_loadingWidget = new ZLoadingWidget(false, this); + mainLayout->addWidget(m_loadingWidget); + + QWidget *contentContainer = new QWidget(this); + QVBoxLayout *contentLayout = new QVBoxLayout(contentContainer); + contentLayout->setContentsMargins(0, 0, 0, 0); + contentLayout->setSpacing(0); + m_loadingWidget->setupContentWidget(contentContainer); + + m_mediaPlayer = new QMediaPlayer(this); + m_videoWidget = new QVideoWidget(this); + m_videoWidget->setMinimumSize(300, 500); + m_videoWidget->setSizePolicy(QSizePolicy::Expanding, + QSizePolicy::Expanding); + m_videoWidget->setAspectRatioMode(Qt::KeepAspectRatio); + m_mediaPlayer->setVideoOutput(m_videoWidget); + + connect(m_mediaPlayer, + QOverload::of( + &QMediaPlayer::mediaStatusChanged), + [this](QMediaPlayer::MediaStatus status) { + if (status == QMediaPlayer::EndOfMedia) { + m_mediaPlayer->setPosition(0); + m_mediaPlayer->play(); + } + }); + + QLabel *title = + new QLabel("Enable Developer Mode on your iOS device", this); + title->setAlignment(Qt::AlignCenter); + title->setStyleSheet("QLabel { font-size: 18px; font-weight: bold; }"); + + QLabel *description = new QLabel( + R"(In order to use this feature on your device, you need to enable Developer Mode in the Settings app. + This allows iDescriptor to access advanced features on your device. + Please follow the instructions in the video below to enable Developer Mode.)", + this); + description->setAlignment(Qt::AlignCenter); + description->setWordWrap(true); + + QVBoxLayout *textLayout = new QVBoxLayout(); + textLayout->setContentsMargins(20, 20, 20, 20); + textLayout->setSpacing(10); + contentLayout->addWidget(title); + textLayout->addWidget(description); + + contentLayout->addLayout(textLayout); + contentLayout->addWidget(m_videoWidget); + + m_mediaPlayer->setSource(QUrl("qrc:/resources/dev-mode.mp4")); + + connect( + device->service_manager, + &CXX::ServiceManager::developer_mode_option_revealed, this, + [this](bool revealed) { + if (revealed) { + QTimer::singleShot(500, this, &DevModeWidget::init); + } else { + m_loadingWidget->showError( + "Failed to reveal Developer Mode option in UI. Please try " + "again later."); + } + }, + Qt::SingleShotConnection); + + device->service_manager->reveal_developer_mode_option_in_ui(); +} + +void DevModeWidget::init() +{ + m_mediaPlayer->play(); + m_loadingWidget->stop(); +} diff --git a/src/devmodewidget.h b/src/devmodewidget.h new file mode 100644 index 0000000..7262993 --- /dev/null +++ b/src/devmodewidget.h @@ -0,0 +1,29 @@ +#ifndef DEVMODEWIDGET_H +#define DEVMODEWIDGET_H + +#include "iDescriptor-ui.h" +#include "iDescriptor.h" +#include "zloadingwidget.h" +#include +#include +#include +#include +#include +#include + +class DevModeWidget : public QDialog +{ + Q_OBJECT +public: + explicit DevModeWidget(std::shared_ptr device, + QWidget *parent = nullptr); + +private: + ZLoadingWidget *m_loadingWidget; + QMediaPlayer *m_mediaPlayer; + QVideoWidget *m_videoWidget; + + void init(); +}; + +#endif // DEVMODEWIDGET_H diff --git a/src/exportalbum.cpp b/src/exportalbum.cpp index 8d2dd6c..f9f3507 100644 --- a/src/exportalbum.cpp +++ b/src/exportalbum.cpp @@ -10,7 +10,7 @@ ExportAlbum::ExportAlbum(const std::shared_ptr device, setupWinWindow(this); #endif - m_loadingWidget = new ZLoadingWidget(true, this); + m_loadingWidget = new ZLoadingWidget(false, this); QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->addWidget(m_loadingWidget); @@ -99,6 +99,8 @@ void ExportAlbum::getTotalPhotoCount(const QStringList &paths) watcher->setFuture(QtConcurrent::run([this, paths]() { size_t count = 0; bool errorOccurred = false; + // FIXME: if a dir returns empty, it could be an error or just an empty + // dir, we should check that for (const QString &path : paths) { QList items = m_device->afc_backend->list_files_flat(path); diff --git a/src/virtuallocationwidget.cpp b/src/virtuallocationwidget.cpp index c4e12bb..7e37438 100644 --- a/src/virtuallocationwidget.cpp +++ b/src/virtuallocationwidget.cpp @@ -291,7 +291,7 @@ void VirtualLocation::updateInputsFromMap(const QString &latitude, qDebug() << "Updated inputs from map:" << latitude << "," << longitude; } -void VirtualLocation::handleEnable() +void VirtualLocation::restoreButtons() { QTimer::singleShot(1000, this, [this]() { m_applyButton->setText("Apply Location"); @@ -324,9 +324,8 @@ void VirtualLocation::onApplyClicked() this, [this, latitude, longitude, devDiskImageHelper](bool success) { if (!success) { - // mounter will show its own error message, just - // re-enable the button here - return handleEnable(); + // mounter will show its own error message + return; } u_int32_t set_location_success = @@ -344,17 +343,16 @@ void VirtualLocation::onApplyClicked() QMessageBox::information( this, "Success", "Location applied successfully!"); - // SettingsManager::sharedInstance()->saveRecentLocation( - // latitude, longitude); + SettingsManager::sharedInstance()->saveRecentLocation( + latitude, longitude); } - return handleEnable(); }); connect(devDiskImageHelper, &DevDiskImageHelper::destroyed, this, - &VirtualLocation::handleEnable, Qt::SingleShotConnection); + &VirtualLocation::restoreButtons, Qt::SingleShotConnection); return devDiskImageHelper->start(); } - // /* iOS 17 and above */ + /* iOS 17 and above */ int32_t set_location_res = m_device->service_manager->set_location(latitude, longitude); @@ -364,10 +362,7 @@ void VirtualLocation::onApplyClicked() "Location applied successfully"); break; case ServiceNotFoundErrorCode: - // TODO: create a widget for this - qDebug() << "Failed to set location simulation: service not found"; - QMessageBox::warning(this, "Error", - "Developer Mode is not enabled on the device."); + DevModeWidget(m_device, this).exec(); break; case TimeoutErrorCode: qDebug() << "Failed to set location simulation: timed out"; @@ -381,7 +376,7 @@ void VirtualLocation::onApplyClicked() QString::number(set_location_res)); } - handleEnable(); + restoreButtons(); } void VirtualLocation::loadRecentLocations(QVBoxLayout *layout) diff --git a/src/virtuallocationwidget.h b/src/virtuallocationwidget.h index cef1ed4..352c4c5 100644 --- a/src/virtuallocationwidget.h +++ b/src/virtuallocationwidget.h @@ -21,6 +21,7 @@ #define VIRTUAL_LOCATION_H #include "devdiskimagehelper.h" +#include "devmodewidget.h" #include "iDescriptor-ui.h" #include "iDescriptor.h" #include @@ -57,7 +58,7 @@ private: void addLocationButtons(QLayout *layout, QList recentLocations); - void handleEnable(); + void restoreButtons(); QQuickWidget *m_quickWidget; QLineEdit *m_latitudeEdit;