refactor: wirelessgalleryimportwidget, introduce new wirelessFileServerPort setting

This commit is contained in:
uncor3
2026-01-31 22:19:48 +00:00
parent 4df3c1d7a8
commit dcef84a1a6
9 changed files with 178 additions and 142 deletions
+8 -3
View File
@@ -19,6 +19,7 @@
#include "httpserver.h"
#include "iDescriptor.h"
#include "settingsmanager.h"
#include <QDateTime>
#include <QFile>
#include <QFileInfo>
@@ -48,8 +49,10 @@ void HttpServer::start(const QStringList &files)
QDateTime::currentDateTime().toString("yyyyMMdd-hhmmss");
jsonFileName = QString("%1-idescriptor-import.json").arg(timestamp);
// Try to bind to port 8080, if fails try other ports
for (int tryPort = 8080; tryPort <= 8090; ++tryPort) {
// Try to bind to port from settings, if fails try other ports
int startPort = SettingsManager::sharedInstance()->wirelessFileServerPort();
qDebug() << "Starting HTTP server on port" << startPort;
for (int tryPort = startPort; tryPort <= startPort + 10; ++tryPort) {
if (server->listen(QHostAddress::Any, tryPort)) {
port = tryPort;
emit serverStarted();
@@ -57,7 +60,9 @@ void HttpServer::start(const QStringList &files)
}
}
emit serverError("Could not bind to any port between 8080-8090");
emit serverError(QString("Could not bind to any port between %1-%2")
.arg(startPort)
.arg(startPort + 10));
}
void HttpServer::stop()
+114 -28
View File
@@ -27,21 +27,28 @@
#include <QPainter>
#include <QPixmap>
#include <QRandomGenerator>
#include <QTimer>
#include <QUrl>
#include <qrencode.h>
PhotoImportDialog::PhotoImportDialog(const QStringList &files,
bool hasDirectories, QWidget *parent)
: QDialog(parent), selectedFiles(files),
containsDirectories(hasDirectories), m_httpServer(nullptr)
containsDirectories(hasDirectories), m_httpServer(nullptr),
m_mediaPlayer(nullptr)
{
setupUI();
setModal(true);
resize(600, 500);
resize(600, 700);
setWindowTitle("Import Photos to iDevice - iDescriptor");
}
PhotoImportDialog::~PhotoImportDialog()
{
if (m_mediaPlayer) {
m_mediaPlayer->stop();
delete m_mediaPlayer;
}
if (m_httpServer) {
m_httpServer->stop();
delete m_httpServer;
@@ -76,26 +83,73 @@ void PhotoImportDialog::setupUI()
}
mainLayout->addWidget(fileList);
// Horizontal layout for QR code and instructions
QHBoxLayout *contentLayout = new QHBoxLayout();
// QR Code area
qrCodeLabel = new QLabel(this);
qrCodeLabel->setAlignment(Qt::AlignCenter);
qrCodeLabel->setMinimumSize(200, 200);
qrCodeLabel->setMaximumSize(200, 200);
qrCodeLabel->setText("QR Code will appear here after starting server");
mainLayout->addWidget(qrCodeLabel);
contentLayout->addWidget(qrCodeLabel);
// Instructions
instructionLabel = new QLabel("Loading", this);
mainLayout->addWidget(instructionLabel);
// Instructions container
QVBoxLayout *instructionContainer = new QVBoxLayout();
// Stacked widget for switchable instructions
m_instructionStack = new QStackedWidget(this);
m_instructionStack->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
// Text instructions
m_instructionLabel = new QLabel("Loading", this);
m_instructionLabel->setWordWrap(true);
m_instructionStack->addWidget(m_instructionLabel);
// Video instructions
m_instructionVideo = new QVideoWidget(this);
m_instructionVideo->setMinimumSize(300, 500);
m_instructionVideo->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
m_mediaPlayer = new QMediaPlayer(this);
m_mediaPlayer->setVideoOutput(m_instructionVideo);
m_instructionStack->addWidget(m_instructionVideo);
m_instructionVideo->setAspectRatioMode(
Qt::AspectRatioMode::KeepAspectRatioByExpanding);
m_instructionVideo->setStyleSheet(
"QVideoWidget { background-color: transparent; }");
instructionContainer->addWidget(m_instructionStack);
// Toggle button
m_toggleInstructionButton =
new QPushButton("Show Video Instructions", this);
connect(m_toggleInstructionButton, &QPushButton::clicked, this,
&PhotoImportDialog::toggleInstructionMode);
instructionContainer->addSpacing(10);
QHBoxLayout *buttonContainer = new QHBoxLayout();
buttonContainer->addStretch();
buttonContainer->addWidget(m_toggleInstructionButton);
buttonContainer->addStretch();
instructionContainer->addLayout(buttonContainer);
contentLayout->addLayout(instructionContainer);
mainLayout->addLayout(contentLayout);
// Progress tracking
progressLabel = new QLabel("Download progress will appear here", this);
progressLabel->setVisible(false);
mainLayout->addWidget(progressLabel);
m_progressLabel = new QLabel("Download progress will appear here", this);
m_progressLabel->setVisible(false);
mainLayout->addWidget(m_progressLabel, Qt::AlignCenter);
// Progress bar
progressBar = new QProgressBar(this);
progressBar->setVisible(false);
mainLayout->addWidget(progressBar);
mainLayout->addSpacing(5);
m_serverAddress = new QLabel("", this);
m_serverAddress->setVisible(false);
mainLayout->addWidget(m_serverAddress, Qt::AlignCenter);
// Buttons
QHBoxLayout *buttonLayout = new QHBoxLayout();
@@ -108,13 +162,22 @@ void PhotoImportDialog::setupUI()
connect(m_cancelButton, &QPushButton::clicked, this, &QDialog::reject);
// Setup video looping
connect(m_mediaPlayer,
QOverload<QMediaPlayer::MediaStatus>::of(
&QMediaPlayer::mediaStatusChanged),
[this](QMediaPlayer::MediaStatus status) {
if (status == QMediaPlayer::EndOfMedia) {
m_mediaPlayer->setPosition(0);
m_mediaPlayer->play();
}
});
QTimer::singleShot(0, this, &PhotoImportDialog::init);
}
void PhotoImportDialog::init()
{
progressBar->setVisible(true);
progressBar->setRange(0, 0); // Indeterminate progress
// Create and start HTTP server
m_httpServer = new HttpServer(this);
@@ -130,7 +193,6 @@ void PhotoImportDialog::init()
void PhotoImportDialog::onServerStarted()
{
progressBar->setVisible(false);
QString localIP = getLocalIP();
int port = m_httpServer->getPort();
@@ -144,28 +206,37 @@ void PhotoImportDialog::onServerStarted()
generateQRCode(url);
instructionLabel->setText(
QString("Server started at %1:%2\n\n1. Scan the QR code to open the "
"web interface\n2. Copy the server address and download the "
"shortcut\n3. Run the shortcut on your iOS device")
.arg(localIP)
.arg(port));
m_instructionLabel->setText(
"Instructions on How to Import\n\n1.Scan the QR code to open the "
"web interface\n2.Click on \"Copy Server Address\"\n3.Click on "
"\"Import and Run Shortcut\" if you have not installed the "
"shortcut before or \"Run Shortcut\" if you have installed it "
"before. \n4.Run the shortcut in the Shortcuts app. Once the "
"shortcut imports to your device, it will automatically run "
"\"Photos app\" \n\n Switch to video tutorial if you want to see a "
"video tutorial.");
progressLabel->setVisible(true);
progressLabel->setText("Waiting for downloads...");
m_mediaPlayer->setSource(
QUrl("qrc:/resources/wireless-gallery-import.mp4"));
m_progressLabel->setText("Waiting for downloads...");
m_progressLabel->setVisible(true);
m_serverAddress->setText(
QString("Server started at %1:%2").arg(localIP).arg(port));
m_serverAddress->setVisible(true);
}
void PhotoImportDialog::onDownloadProgress(const QString &fileName,
int bytesDownloaded, int totalBytes)
{
progressLabel->setText(QString("Downloaded: %1 (%2 KB)")
.arg(fileName)
.arg(bytesDownloaded / 1024));
m_progressLabel->setText(QString("Downloaded: %1 (%2 KB)")
.arg(fileName)
.arg(bytesDownloaded / 1024));
}
void PhotoImportDialog::onServerError(const QString &error)
{
progressBar->setVisible(false);
m_cancelButton->setEnabled(true);
QMessageBox::critical(this, "Server Error",
@@ -224,3 +295,18 @@ QString PhotoImportDialog::getLocalIP() const
}
return "127.0.0.1";
}
void PhotoImportDialog::toggleInstructionMode()
{
if (m_instructionStack->currentIndex() == 0) {
// Switch to video
m_instructionStack->setCurrentIndex(1);
m_toggleInstructionButton->setText("Show Text Instructions");
m_mediaPlayer->play();
} else {
// Switch to text
m_instructionStack->setCurrentIndex(0);
m_toggleInstructionButton->setText("Show Video Instructions");
m_mediaPlayer->stop();
}
}
+11 -3
View File
@@ -29,6 +29,9 @@
#include <QPushButton>
#include <QStringList>
#include <QVBoxLayout>
#include <QStackedWidget>
#include <QVideoWidget>
#include <QMediaPlayer>
class PhotoImportDialog : public QDialog
{
@@ -45,6 +48,7 @@ private slots:
void onServerError(const QString &error);
void onDownloadProgress(const QString &fileName, int bytesDownloaded,
int totalBytes);
void toggleInstructionMode();
private:
QStringList selectedFiles;
@@ -53,10 +57,14 @@ private:
QListWidget *fileList;
QLabel *warningLabel;
QLabel *qrCodeLabel;
QLabel *instructionLabel;
QStackedWidget *m_instructionStack;
QLabel *m_instructionLabel;
QVideoWidget *m_instructionVideo;
QMediaPlayer *m_mediaPlayer;
QPushButton *m_toggleInstructionButton;
QPushButton *m_cancelButton;
QProgressBar *progressBar;
QLabel *progressLabel;
QLabel *m_progressLabel;
QLabel *m_serverAddress;
HttpServer *m_httpServer;
+12
View File
@@ -168,6 +168,17 @@ void SettingsManager::setConnectionTimeout(int seconds)
m_settings->sync();
}
int SettingsManager::wirelessFileServerPort() const
{
return m_settings->value("wirelessFileServerPort", 8080).toInt();
}
void SettingsManager::setWirelessFileServerPort(int port)
{
m_settings->setValue("wirelessFileServerPort", port);
m_settings->sync();
}
bool SettingsManager::showKeychainDialog() const
{
return m_settings->value("showKeychainDialog", true).toBool();
@@ -238,6 +249,7 @@ void SettingsManager::resetToDefaults()
setIconSizeBaseMultiplier(1.0);
setAirplayFps(60);
setAirplayNoHold(true);
setWirelessFileServerPort(8080);
#ifdef __linux__
setShowV4L2(false);
#endif
+3
View File
@@ -86,6 +86,9 @@ public:
int connectionTimeout() const;
void setConnectionTimeout(int seconds);
int wirelessFileServerPort() const;
void setWirelessFileServerPort(int port);
bool showKeychainDialog() const;
void setShowKeychainDialog(bool show);
+17
View File
@@ -75,6 +75,18 @@ void SettingsWidget::setupUI()
downloadLayout->addWidget(browseButton);
generalLayout->addLayout(downloadLayout);
// Wireless file server port
auto *portLayout = new QHBoxLayout();
portLayout->addWidget(new QLabel("Wireless File Server Port:"));
m_wirelessFileServerPort = new QSpinBox();
m_wirelessFileServerPort->setRange(1024, 65535);
m_wirelessFileServerPort->setToolTip(
"The starting port for the wireless file server. If this port is "
"unavailable, it will try the next 10 ports.");
portLayout->addWidget(m_wirelessFileServerPort);
portLayout->addStretch();
generalLayout->addLayout(portLayout);
// Unmount iFuse drives on exit (not implemented on macOS)
// TODO: Implement
#ifndef __APPLE__
@@ -262,6 +274,7 @@ void SettingsWidget::loadSettings()
m_autoUpdateCheck->setChecked(sm->autoCheckUpdates());
m_autoRaiseWindow->setChecked(sm->autoRaiseWindow());
m_switchToNewDevice->setChecked(sm->switchToNewDevice());
m_wirelessFileServerPort->setValue(sm->wirelessFileServerPort());
#ifndef __APPLE__
m_unmount_iFuseDrives->setChecked(sm->unmountiFuseOnExit());
@@ -307,6 +320,9 @@ void SettingsWidget::connectSignals()
this, &SettingsWidget::onSettingChanged);
connect(m_connectionTimeout, QOverload<int>::of(&QSpinBox::valueChanged),
this, &SettingsWidget::onSettingChanged);
connect(m_wirelessFileServerPort,
QOverload<int>::of(&QSpinBox::valueChanged), this,
&SettingsWidget::onSettingChanged);
connect(m_iconSizeBaseMultiplier,
QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
@@ -420,6 +436,7 @@ void SettingsWidget::saveSettings()
sm->setAutoCheckUpdates(m_autoUpdateCheck->isChecked());
sm->setAutoRaiseWindow(m_autoRaiseWindow->isChecked());
sm->setSwitchToNewDevice(m_switchToNewDevice->isChecked());
sm->setWirelessFileServerPort(m_wirelessFileServerPort->value());
#ifndef __APPLE__
sm->setUnmountiFuseOnExit(m_unmount_iFuseDrives->isChecked());
+1
View File
@@ -52,6 +52,7 @@ private:
// UI Elements
// General
QLineEdit *m_downloadPathEdit;
QSpinBox *m_wirelessFileServerPort;
QCheckBox *m_autoUpdateCheck;
QComboBox *m_themeCombo;
QCheckBox *m_autoRaiseWindow;
+12 -96
View File
@@ -29,25 +29,13 @@
#include <QTimer>
WirelessGalleryImportWidget::WirelessGalleryImportWidget(QWidget *parent)
: QWidget(parent), m_leftPanel(nullptr), m_scrollArea(nullptr),
m_scrollContent(nullptr), m_fileListLayout(nullptr),
m_browseButton(nullptr), m_importButton(nullptr), m_statusLabel(nullptr),
m_rightPanel(nullptr), m_tutorialPlayer(nullptr),
m_tutorialVideoWidget(nullptr), m_loadingIndicator(nullptr),
m_loadingLabel(nullptr), m_tutorialLayout(nullptr)
: QWidget(parent), m_scrollArea(nullptr), m_scrollContent(nullptr),
m_fileListLayout(nullptr), m_browseButton(nullptr),
m_importButton(nullptr), m_statusLabel(nullptr)
{
setupUI();
setMinimumSize(800, 600);
setMinimumSize(400, 600);
setWindowTitle("Wireless Gallery Import - iDescriptor");
QTimer::singleShot(100, this,
&WirelessGalleryImportWidget::setupTutorialVideo);
}
WirelessGalleryImportWidget::~WirelessGalleryImportWidget()
{
if (m_tutorialPlayer) {
m_tutorialPlayer->stop();
}
}
void WirelessGalleryImportWidget::setupUI()
@@ -57,21 +45,20 @@ void WirelessGalleryImportWidget::setupUI()
mainLayout->setSpacing(10);
// Left panel - file selection
m_leftPanel = new QWidget();
QVBoxLayout *leftLayout = new QVBoxLayout(m_leftPanel);
leftLayout->setContentsMargins(0, 0, 0, 0);
leftLayout->setSpacing(10);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(10);
// Browse button
m_browseButton = new QPushButton("Select Files");
connect(m_browseButton, &QPushButton::clicked, this,
&WirelessGalleryImportWidget::onBrowseFiles);
leftLayout->addWidget(m_browseButton);
layout->addWidget(m_browseButton);
// Status label
m_statusLabel = new QLabel("No files selected");
m_statusLabel->setWordWrap(true);
leftLayout->addWidget(m_statusLabel);
layout->addWidget(m_statusLabel);
// Scroll area for file list
m_scrollArea = new QScrollArea();
@@ -86,87 +73,16 @@ void WirelessGalleryImportWidget::setupUI()
m_fileListLayout->addStretch();
m_scrollArea->setWidget(m_scrollContent);
leftLayout->addWidget(m_scrollArea, 1);
layout->addWidget(m_scrollArea, 1);
// Import button
m_importButton = new QPushButton("Import to Gallery");
m_importButton->setEnabled(false);
connect(m_importButton, &QPushButton::clicked, this,
&WirelessGalleryImportWidget::onImportPhotos);
leftLayout->addWidget(m_importButton);
layout->addWidget(m_importButton);
mainLayout->addWidget(m_leftPanel, 1);
// Right panel - tutorial video
m_rightPanel = new QWidget();
m_tutorialLayout = new QVBoxLayout(m_rightPanel);
m_tutorialLayout->setContentsMargins(0, 0, 0, 0);
m_tutorialLayout->setSpacing(10);
// Loading indicator
m_loadingIndicator = new QProcessIndicator();
m_loadingIndicator->setType(QProcessIndicator::line_rotate);
m_loadingIndicator->setFixedSize(64, 32);
m_loadingIndicator->start();
QHBoxLayout *loadingLayout = new QHBoxLayout();
m_loadingLabel = new QLabel("Loading tutorial...");
m_loadingLabel->setAlignment(Qt::AlignCenter);
loadingLayout->addWidget(m_loadingLabel);
loadingLayout->addWidget(m_loadingIndicator);
loadingLayout->setAlignment(Qt::AlignCenter);
m_tutorialLayout->addStretch();
m_tutorialLayout->addLayout(loadingLayout);
m_tutorialLayout->addStretch();
mainLayout->addWidget(m_rightPanel, 1);
}
void WirelessGalleryImportWidget::setupTutorialVideo()
{
m_tutorialPlayer = new QMediaPlayer(this);
m_tutorialVideoWidget = new QVideoWidget();
m_tutorialVideoWidget->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
m_tutorialPlayer->setVideoOutput(m_tutorialVideoWidget);
m_tutorialPlayer->setSource(
QUrl("qrc:/resources/wireless-gallery-import.mp4"));
m_tutorialVideoWidget->setAspectRatioMode(
Qt::AspectRatioMode::KeepAspectRatioByExpanding);
// Loop the tutorial video
connect(m_tutorialPlayer, &QMediaPlayer::mediaStatusChanged, this,
[this](QMediaPlayer::MediaStatus status) {
if (status == QMediaPlayer::EndOfMedia) {
m_tutorialPlayer->setPosition(0);
m_tutorialPlayer->play();
}
});
// Auto-play when ready and hide loading indicator
connect(m_tutorialPlayer, &QMediaPlayer::mediaStatusChanged, this,
[this](QMediaPlayer::MediaStatus status) {
if (status == QMediaPlayer::LoadedMedia) {
m_loadingIndicator->stop();
m_loadingIndicator->setVisible(false);
m_loadingLabel->setVisible(false);
m_tutorialPlayer->play();
}
});
// Clear the loading layout and add video widget
QLayoutItem *child;
while ((child = m_tutorialLayout->takeAt(0)) != nullptr) {
if (child->widget()) {
child->widget()->setParent(nullptr);
}
delete child;
}
m_tutorialLayout->addWidget(m_tutorialVideoWidget);
mainLayout->addLayout(layout);
}
void WirelessGalleryImportWidget::onBrowseFiles()
-12
View File
@@ -38,7 +38,6 @@ class WirelessGalleryImportWidget : public QWidget
public:
explicit WirelessGalleryImportWidget(QWidget *parent = nullptr);
~WirelessGalleryImportWidget();
QStringList getSelectedFiles() const;
@@ -46,11 +45,8 @@ private slots:
void onBrowseFiles();
void onImportPhotos();
void onRemoveFile(int index);
void setupTutorialVideo();
private:
// Left panel - file selection
QWidget *m_leftPanel;
QScrollArea *m_scrollArea;
QWidget *m_scrollContent;
QVBoxLayout *m_fileListLayout;
@@ -58,14 +54,6 @@ private:
QPushButton *m_importButton;
QLabel *m_statusLabel;
// Right panel - tutorial video
QWidget *m_rightPanel;
QMediaPlayer *m_tutorialPlayer;
QVideoWidget *m_tutorialVideoWidget;
QProcessIndicator *m_loadingIndicator;
QLabel *m_loadingLabel;
QVBoxLayout *m_tutorialLayout;
QStringList m_selectedFiles;
void setupUI();