copy just enough gstreamer plugins and handle deps for Windows build

- Added custom command to copy libZUpdater.dll for deployment
- Updated win-deploy.cmake to copy specific GStreamer plugins
- Introduced install scripts for Apple drivers and WinFsp
- Improved DiagnoseWidget UI with scroll area and process indicators
- Adjusted WelcomeWidget to include DiagnoseWidget on non-Apple platforms
This commit is contained in:
uncor3
2025-11-02 11:39:17 -08:00
parent d3f4c74fbc
commit 7eaed96a85
11 changed files with 367 additions and 106 deletions
-31
View File
@@ -28,10 +28,6 @@
#include <QMenuBar>
#include <QMessageBox>
#ifdef WIN32
#include "platform/windows/diagnose_widget.h"
#endif
void handleCallback(const idevice_event_t *event, void *userData)
{
printf("Device event received: ");
@@ -79,7 +75,6 @@ void handleCallback(const idevice_event_t *event, void *userData)
default:
qDebug() << "Unhandled event: " << event->event;
}
// return;
}
void handleCallbackRecovery(const irecv_device_event_t *event, void *userData)
@@ -117,10 +112,7 @@ MainWindow::MainWindow(QWidget *parent)
const QSize minSize(900, 600);
setMinimumSize(minSize);
resize(minSize);
// TODO
// setWindowIcon(QIcon(":/resources/icons/icon.png"));
// Create custom tab widget
m_ZTabWidget = new ZTabWidget(this);
m_ZTabWidget->setAttribute(Qt::WA_ContentsMarginsRespectsSafeArea, false);
@@ -131,31 +123,8 @@ MainWindow::MainWindow(QWidget *parent)
#endif
setCentralWidget(m_ZTabWidget);
// Create device manager and stacked widget for main tab
m_mainStackedWidget = new QStackedWidget();
// Welcome page (shown when no devices are connected)
WelcomeWidget *welcomePage = new WelcomeWidget(this);
// No devices page
QWidget *noDevicesPage = new QWidget();
QVBoxLayout *noDeviceLayout = new QVBoxLayout(noDevicesPage);
noDeviceLayout->addStretch();
QHBoxLayout *labelLayout = new QHBoxLayout();
labelLayout->addStretch();
QLabel *noDeviceLabel = new QLabel("No devices detected");
noDeviceLabel->setAlignment(Qt::AlignCenter);
labelLayout->addWidget(noDeviceLabel);
labelLayout->addStretch();
noDeviceLayout->addLayout(labelLayout);
#ifdef WIN32
// Add diagnose widget to check dependencies
// DiagnoseWidget *diagnoseWidget = new DiagnoseWidget();
// noDeviceLayout->addWidget(diagnoseWidget);
#endif
noDeviceLayout->addStretch();
m_deviceManager = new DeviceManagerWidget(this);
m_mainStackedWidget->addWidget(welcomePage);
+6 -1
View File
@@ -16,10 +16,15 @@ DiagnoseDialog::DiagnoseDialog(QWidget *parent) : QDialog(parent)
void DiagnoseDialog::setupUI()
{
QVBoxLayout *mainLayout = new QVBoxLayout(this);
QScrollArea *scrollArea = new QScrollArea(this);
scrollArea->setWidgetResizable(true);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
mainLayout->setContentsMargins(10, 10, 10, 10);
// Add the main diagnose widget
m_diagnoseWidget = new DiagnoseWidget();
scrollArea->setWidget(m_diagnoseWidget);
// Close button
QHBoxLayout *buttonLayout = new QHBoxLayout();
@@ -33,7 +38,7 @@ void DiagnoseDialog::setupUI()
buttonLayout->addWidget(m_closeButton);
// Layout assembly
mainLayout->addWidget(m_diagnoseWidget, 1);
mainLayout->addWidget(scrollArea);
mainLayout->addLayout(buttonLayout);
}
+176 -46
View File
@@ -1,12 +1,15 @@
#include "diagnose_widget.h"
#ifdef WIN32
#include "check_deps.h"
#endif
#include <QApplication>
#include <QCoreApplication>
#include <QDesktopServices>
#include <QMessageBox>
#include <QProcess>
#include <QTimer>
#include <QUrl>
DependencyItem::DependencyItem(const QString &name, const QString &description,
QWidget *parent)
: QWidget(parent), m_name(name)
@@ -37,7 +40,8 @@ DependencyItem::DependencyItem(const QString &name, const QString &description,
m_statusLabel->setAlignment(Qt::AlignCenter);
// Right side - actions
QVBoxLayout *actionLayout = new QVBoxLayout();
QHBoxLayout *actionLayout = new QHBoxLayout();
actionLayout->setContentsMargins(0, 0, 0, 0);
m_installButton = new QPushButton("Install");
m_installButton->setMinimumWidth(80);
@@ -45,13 +49,13 @@ DependencyItem::DependencyItem(const QString &name, const QString &description,
connect(m_installButton, &QPushButton::clicked, this,
&DependencyItem::onInstallClicked);
m_progressBar = new QProgressBar();
m_progressBar->setRange(0, 0); // Indeterminate
m_progressBar->setVisible(false);
m_progressBar->setMaximumHeight(20);
m_processIndicator = new QProcessIndicator();
m_processIndicator->setType(QProcessIndicator::line_rotate);
m_processIndicator->setFixedSize(24, 24);
m_processIndicator->setVisible(false);
actionLayout->addWidget(m_processIndicator);
actionLayout->addWidget(m_installButton);
actionLayout->addWidget(m_progressBar);
actionLayout->addStretch();
layout->addLayout(infoLayout, 1);
@@ -80,28 +84,47 @@ void DependencyItem::setChecking(bool checking)
m_statusLabel->setText("Checking...");
m_statusLabel->setStyleSheet("color: gray;");
m_installButton->setVisible(false);
m_progressBar->setVisible(false);
m_processIndicator->setVisible(false);
m_processIndicator->stop();
}
}
void DependencyItem::setInstalling(bool installing)
{
if (installing) {
m_statusLabel->setText("Installing...");
m_statusLabel->setStyleSheet("color: gray;");
m_installButton->setVisible(false);
m_processIndicator->setVisible(true);
m_processIndicator->start();
} else {
m_processIndicator->stop();
m_processIndicator->setVisible(false);
}
}
void DependencyItem::onInstallClicked() { emit installRequested(m_name); }
DiagnoseWidget::DiagnoseWidget(QWidget *parent) : QWidget(parent)
DiagnoseWidget::DiagnoseWidget(QWidget *parent)
: QWidget(parent), m_isExpanded(false)
{
setupUI();
#ifdef WIN32
// Add dependency items
addDependencyItem("Apple Mobile Device Support",
"Required for iOS device communication");
addDependencyItem("WinFsp",
"Required for filesystem operations and mounting");
#endif
// Auto-check on startup
QTimer::singleShot(100, this, &DiagnoseWidget::checkDependencies);
QTimer::singleShot(100, this, [this]() { checkDependencies(); });
}
void DiagnoseWidget::setupUI()
{
setAutoFillBackground(true);
m_mainLayout = new QVBoxLayout(this);
m_mainLayout->setSpacing(10);
@@ -115,40 +138,43 @@ void DiagnoseWidget::setupUI()
m_summaryLabel = new QLabel("Checking system dependencies...");
// Check button
m_checkButton = new QPushButton("Refresh Check");
m_checkButton = new QPushButton("Refresh Check(s)");
m_checkButton->setMaximumWidth(150);
connect(m_checkButton, &QPushButton::clicked, this,
&DiagnoseWidget::checkDependencies);
[this]() { checkDependencies(false); });
// Scroll area for dependency items
m_scrollArea = new QScrollArea();
m_scrollArea->setWidgetResizable(true);
// m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarNever);
m_scrollArea->setMinimumHeight(200);
// Toggle button
m_toggleButton = new QPushButton("");
m_toggleButton->setFixedSize(24, 24);
m_toggleButton->setCheckable(true);
connect(m_toggleButton, &QPushButton::clicked, this,
&DiagnoseWidget::onToggleExpand);
m_itemsWidget = new QWidget();
// m_itemsWidget->setSizePolicy(QSizePolicy::Expanding,
// QSizePolicy::Preferred);
m_itemsWidget->setFixedHeight(400);
m_itemsLayout = new QVBoxLayout(m_itemsWidget);
m_itemsLayout->setSpacing(5);
m_itemsLayout->addStretch();
m_scrollArea->setWidget(m_itemsWidget);
m_itemsWidget->setVisible(m_isExpanded);
// Layout assembly
QHBoxLayout *headerLayout = new QHBoxLayout();
headerLayout->addWidget(titleLabel);
headerLayout->addStretch();
headerLayout->addWidget(m_checkButton);
headerLayout->addWidget(m_toggleButton);
m_mainLayout->addLayout(headerLayout);
m_mainLayout->addWidget(m_summaryLabel);
m_mainLayout->addWidget(m_scrollArea, 1);
m_mainLayout->addWidget(m_itemsWidget);
}
void DiagnoseWidget::addDependencyItem(const QString &name,
const QString &description)
{
DependencyItem *item = new DependencyItem(name, description);
item->setProperty("name", name); // Set the name property for identification
item->setProperty("name", name);
connect(item, &DependencyItem::installRequested, this,
&DiagnoseWidget::onInstallRequested);
@@ -158,18 +184,16 @@ void DiagnoseWidget::addDependencyItem(const QString &name,
m_itemsLayout->insertWidget(m_itemsLayout->count() - 1, item);
}
void DiagnoseWidget::checkDependencies()
void DiagnoseWidget::checkDependencies(bool autoExpand)
{
m_summaryLabel->setText("Checking system dependencies...");
m_checkButton->setEnabled(false);
// Reset all items to checking state
for (DependencyItem *item : m_dependencyItems) {
item->setChecking(true);
}
// Simulate async checking with timer
QTimer::singleShot(500, [this]() {
QTimer::singleShot(500, [this, autoExpand]() {
int installedCount = 0;
int totalCount = m_dependencyItems.size();
@@ -177,30 +201,37 @@ void DiagnoseWidget::checkDependencies()
bool installed = false;
QString itemName = item->property("name").toString();
#ifdef WIN32
if (itemName == "Apple Mobile Device Support") {
installed = IsAppleMobileDeviceSupportInstalled();
} else if (itemName == "WinFsp") {
installed = IsWinFspInstalled();
}
#endif
item->setInstalled(installed);
if (installed)
installedCount++;
}
// Update summary
if (installedCount == totalCount) {
m_summaryLabel->setText(
QString("All dependencies are installed (%1/%2)")
.arg(installedCount)
.arg(totalCount));
m_summaryLabel->setStyleSheet("color: green; font-weight: bold;");
if (m_isExpanded && autoExpand) {
onToggleExpand();
}
} else {
m_summaryLabel->setText(
QString("Missing dependencies (%1/%2 installed)")
.arg(installedCount)
.arg(totalCount));
m_summaryLabel->setStyleSheet("color: red; font-weight: bold;");
if (!m_isExpanded && autoExpand) {
onToggleExpand();
}
}
m_checkButton->setEnabled(true);
@@ -209,26 +240,125 @@ void DiagnoseWidget::checkDependencies()
void DiagnoseWidget::onInstallRequested(const QString &name)
{
QString url;
QString message;
#ifdef WIN32
if (name == "Apple Mobile Device Support") {
url = "https://support.apple.com/downloads/itunes";
message = "Apple Mobile Device Support is typically installed with "
"iTunes.\n\n"
"Would you like to open the iTunes download page?";
} else if (name == "WinFsp") {
url = "https://winfsp.dev/rel/";
message = "WinFsp can be downloaded from the official website.\n\n"
"Would you like to open the WinFsp download page?";
}
if (!url.isEmpty()) {
int ret = QMessageBox::question(this, "Install " + name, message,
QMessageBox::Yes | QMessageBox::No);
if (ret == QMessageBox::Yes) {
QDesktopServices::openUrl(QUrl(url));
DependencyItem *itemToInstall = nullptr;
for (DependencyItem *item : m_dependencyItems) {
if (item->property("name").toString() == name) {
itemToInstall = item;
break;
}
}
if (!itemToInstall)
return;
itemToInstall->setInstalling(true);
QString scriptPath = QCoreApplication::applicationDirPath() +
"/install-apple-drivers.ps1";
QProcess *installProcess = new QProcess(this);
connect(
installProcess, &QProcess::finished, this,
[this, installProcess,
itemToInstall](int exitCode, QProcess::ExitStatus exitStatus) {
if (exitStatus != QProcess::NormalExit || exitCode != 0) {
QString errorOutput =
installProcess->readAllStandardError();
if (errorOutput.isEmpty()) {
errorOutput = installProcess->readAllStandardOutput();
}
QMessageBox::warning(
this, "Installation Failed",
"Failed to launch the installation script. This "
"might be a "
"permissions issue or an internal error.\n\n"
"Details: " +
errorOutput.trimmed());
checkDependencies(false); // Revert UI on failure
} else {
// FIXME: we need to track process completion
QMessageBox::information(
this, "Installation Started",
"The installation process has been started.\n"
"Please approve the administrator prompt (UAC) if it "
"appears.\n"
"After installation, please re-run the dependency "
"check");
itemToInstall->setInstalling(false);
}
installProcess->deleteLater();
});
// Correctly launch powershell.exe elevated, and pass the script to it.
// The -Wait parameter is removed as it does not work with -Verb RunAs.
QString command =
QString("Start-Process -FilePath powershell.exe -Verb RunAs "
"-ArgumentList '-NoProfile -ExecutionPolicy Bypass -File "
"\"%1\"'")
.arg(scriptPath);
QStringList args;
args << "-NoProfile"
<< "-ExecutionPolicy"
<< "Bypass"
<< "-Command" << command;
installProcess->start("powershell.exe", args);
return;
}
if (name == "WinFsp") {
DependencyItem *itemToInstall = nullptr;
for (DependencyItem *item : m_dependencyItems) {
if (item->property("name").toString() == name) {
itemToInstall = item;
break;
}
}
if (!itemToInstall)
return;
itemToInstall->setInstalling(true);
QString scriptPath = QCoreApplication::applicationDirPath() +
"/install-win-fsp.silent.bat";
QProcess *installProcess = new QProcess(this);
connect(
installProcess, &QProcess::finished, this,
[this, installProcess](int exitCode,
QProcess::ExitStatus exitStatus) {
if (exitStatus != QProcess::NormalExit || exitCode != 0) {
QMessageBox::warning(
this, "Installation Failed",
"The installation script failed to run correctly. "
"This might be because the action was cancelled or an "
"error occurred.\n\nPlease try again.");
}
checkDependencies(false);
installProcess->deleteLater();
});
QStringList args;
args << "-NoProfile"
<< "-ExecutionPolicy"
<< "Bypass"
<< "-Command"
<< QString("Start-Process -FilePath \"%1\" -Verb RunAs -Wait;")
.arg(scriptPath);
installProcess->start("powershell.exe", args);
}
#endif
}
void DiagnoseWidget::onToggleExpand()
{
m_isExpanded = !m_isExpanded;
m_itemsWidget->setVisible(m_isExpanded);
m_toggleButton->setText(m_isExpanded ? "" : "");
}
+7 -3
View File
@@ -10,6 +10,7 @@
#include <QVBoxLayout>
#include <QWidget>
#include "../../qprocessindicator.h"
class DependencyItem : public QWidget
{
@@ -20,6 +21,7 @@ public:
QWidget *parent = nullptr);
void setInstalled(bool installed);
void setChecking(bool checking);
void setInstalling(bool installing);
signals:
void installRequested(const QString &name);
@@ -33,7 +35,7 @@ private:
QLabel *m_descriptionLabel;
QLabel *m_statusLabel;
QPushButton *m_installButton;
QProgressBar *m_progressBar;
QProcessIndicator *m_processIndicator;
};
class DiagnoseWidget : public QWidget
@@ -44,10 +46,11 @@ public:
explicit DiagnoseWidget(QWidget *parent = nullptr);
public slots:
void checkDependencies();
void checkDependencies(bool autoExpand = true);
private slots:
void onInstallRequested(const QString &name);
void onToggleExpand();
private:
void setupUI();
@@ -56,9 +59,10 @@ private:
QVBoxLayout *m_mainLayout;
QVBoxLayout *m_itemsLayout;
QPushButton *m_checkButton;
QPushButton *m_toggleButton;
QLabel *m_summaryLabel;
QScrollArea *m_scrollArea;
QWidget *m_itemsWidget;
bool m_isExpanded;
QList<DependencyItem *> m_dependencyItems;
};
+11 -5
View File
@@ -9,13 +9,17 @@
#include <QPalette>
#include <QUrl>
#ifdef WIN32
#include "platform/windows/diagnose_widget.h"
#endif
WelcomeWidget::WelcomeWidget(QWidget *parent) : QWidget(parent) { setupUI(); }
void WelcomeWidget::setupUI()
{
// Main layout with proper spacing and margins
m_mainLayout = new QVBoxLayout(this);
m_mainLayout->setContentsMargins(5, 5, 5, 5);
m_mainLayout->setContentsMargins(0, 0, 0, 0);
m_mainLayout->setSpacing(0);
// Add top stretch
@@ -85,11 +89,13 @@ void WelcomeWidget::setupUI()
m_mainLayout->addWidget(m_githubLabel);
// Add bottom stretch
m_mainLayout->addStretch(1);
// no additional deps needed on macOS
#ifndef __APPLE__
DiagnoseWidget *diagnoseWidget = new DiagnoseWidget();
m_mainLayout->addWidget(diagnoseWidget);
#endif
// Set minimum size
// setMinimumSize(600, 500);
m_mainLayout->addStretch(1);
}
ZLabel *WelcomeWidget::createStyledLabel(const QString &text, int fontSize,
+9
View File
@@ -9,7 +9,12 @@
ZTab::ZTab(const QString &text, QWidget *parent) : QPushButton(text, parent)
{
setCheckable(true);
#ifndef WIN32
setFixedHeight(50);
#else
setFixedHeight(40);
#endif
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
}
@@ -21,7 +26,11 @@ ZTabWidget::ZTabWidget(QWidget *parent) : QWidget(parent), m_currentIndex(0)
// Create tab bar container
m_tabBar = new QWidget();
#ifndef WIN32
m_tabBar->setFixedHeight(50);
#else
m_tabBar->setFixedHeight(40);
#endif
m_tabBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_tabLayout = new QHBoxLayout(m_tabBar);
m_tabLayout->setSpacing(0);