/* * 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 "appdownloadbasedialog.h" #include "appstoremanager.h" #include #include #include #include #include #include #include #include #include void AppDownloadBaseDialog::updateProgressBar(int percentage) { if (m_progressBar) { m_progressBar->setValue(percentage); } } void AppDownloadBaseDialog::addProgressBar(int index) { m_progressBar = new QProgressBar(); m_progressBar->setRange(0, 100); m_progressBar->setValue(0); m_progressBar->setTextVisible(true); m_progressBar->setFixedHeight(25); m_progressBar->setStyleSheet( "QProgressBar { border-radius: 6px; background: #eee; } " "QProgressBar::chunk { background: #34C759; }"); m_layout->insertWidget(index, m_progressBar); } AppDownloadBaseDialog::AppDownloadBaseDialog(const QString &appName, const QString &bundleId, QWidget *parent) : QDialog(parent), m_appName(appName), m_downloadProcess(nullptr), m_progressTimer(nullptr) { // Common UI: progress bar and action button m_layout = new QVBoxLayout(this); m_layout->setSpacing(20); m_layout->setContentsMargins(30, 30, 30, 30); QLabel *nameLabel = new QLabel(appName); nameLabel->setStyleSheet("font-size: 20px; font-weight: bold;"); m_layout->addWidget(nameLabel); m_actionButton = nullptr; // Derived classes set this } void AppDownloadBaseDialog::startDownloadProcess(const QString &bundleId, const QString &outputDir, int index, bool promptToOpenDir) { bool acquireLicense = true; if (bundleId.isEmpty()) { QMessageBox::critical(this, "Error", "Bundle ID not provided."); reject(); return; } addProgressBar(index); if (m_actionButton) m_actionButton->setEnabled(false); m_operationInProgress = true; AppStoreManager *manager = AppStoreManager::sharedInstance(); if (!manager) { QMessageBox::critical(this, "Error", "Failed to initialize App Store manager."); reject(); return; } auto progressCallback = [this](long long current, long long total) { int percentage = 0; if (total > 0) { percentage = static_cast((current * 100) / total); } updateProgressBar(percentage); }; manager->downloadApp( bundleId, outputDir, "", acquireLicense, [this, promptToOpenDir, outputDir](int result) { m_operationInProgress = false; if (result == 0) { // Success emit downloadFinished(true, "Success"); m_progressBar->setValue(100); if (promptToOpenDir) { if (QMessageBox::Yes == QMessageBox::question( this, "Download Successful", QString("Successfully downloaded. Would you like " "to open the output directory: %1?") .arg(outputDir))) { QDir dir(outputDir); if (!dir.exists()) { QMessageBox::warning( this, "Directory Not Found", QString("The directory %1 does not exist.") .arg(outputDir)); } else { QDesktopServices::openUrl( QUrl::fromLocalFile(outputDir)); } } accept(); } } else { // Failure emit downloadFinished(false, "Failed"); // if (promptToOpenDir) QMessageBox::critical( this, "Download Failed", QString("Failed to download %1. Try signing out and back " "in. Error code: %2") .arg(m_appName) .arg(result)); reject(); } }, progressCallback); } void AppDownloadBaseDialog::reject() { // FIXME: we need to cancel download if it gets closed // if (m_operationInProgress) { // AppStoreManager *manager = AppStoreManager::sharedInstance(); // m_operationInProgress = false; // } cleanup(); QDialog::reject(); } void AppDownloadBaseDialog::cleanup() { if (m_progressTimer && m_progressTimer->isActive()) { m_progressTimer->stop(); } }