diff --git a/debian/changelog b/debian/changelog index 0d5f275f1126fadb20810b080e7d3a4ca663bbe7..710015731c31e91772989fcdf5c37e09801c5ccb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +spark-store (4.8.1~test2) UNRELEASED; urgency=medium + + * 修复更新器安装软件完成后仍然显示下载完成的问题 + + -- momen Tue, 28 Aug 2025 01:03:08 +0800 + spark-store (4.8.1~test1) UNRELEASED; urgency=medium * 添加全新的更新器 diff --git a/spark-update-tool/.gitignore b/spark-update-tool/.gitignore deleted file mode 100644 index 79c9ac747f0c3456ff6cb7038d7f8ccbded49aa5..0000000000000000000000000000000000000000 --- a/spark-update-tool/.gitignore +++ /dev/null @@ -1,62 +0,0 @@ -build -.vscode -.cache -CMakeLists.txt.user -CMakeLists.txt.user.* -obj-x86_64-linux-gnu -# C++ objects and libs -*.slo -*.lo -*.o -*.a -*.la -*.lai -*.so -*.dll -*.dylib - -# Qt-es -object_script.*.Release -object_script.*.Debug -*_plugin_import.cpp -/.qmake.cache -/.qmake.stash -*.pro.user -*.pro.user.* -*.qbs.user -*.qbs.user.* -*.moc -moc_*.cpp -moc_*.h -qrc_*.cpp -ui_*.h -*.qmlc -*.jsc -Makefile* -*build-* - -# Qt unit tests -target_wrapper.* - -# Qt qm files -translations/*.qm - -# QtCreator -*.autosave - -# QtCreator Qml -*.qmlproject.user -*.qmlproject.user.* - -# QtCreator CMake -CMakeLists.txt.user* -build - -# Debian dpkg-buildpackage -debian/*.debhelper* -debian/files -debian/*.substvars -debian/spark-update-tool - -.vscode/* -src/spark-update-tool diff --git a/spark-update-tool/CMakeLists.txt b/spark-update-tool/CMakeLists.txt deleted file mode 100644 index 49a4d5ebb3d890a26a0dabed15290610c182e360..0000000000000000000000000000000000000000 --- a/spark-update-tool/CMakeLists.txt +++ /dev/null @@ -1,58 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -project(spark-update-tool VERSION 0.1 LANGUAGES CXX) - -set(CMAKE_AUTOUIC ON) -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - - -find_package(Qt5 REQUIRED COMPONENTS Widgets Network Concurrent) - - -find_package(Qt5 REQUIRED COMPONENTS Widgets Network Concurrent Core Gui) - -# 定义所有项目源文件,现在无需条件判断 -set(PROJECT_SOURCES - src/main.cpp - src/mainwindow.cpp - src/mainwindow.h - src/mainwindow.ui - src/aptssupdater.h src/aptssupdater.cpp - src/icons.qrc - src/appdelegate.h src/appdelegate.cpp - src/applistmodel.h src/applistmodel.cpp - src/downloadmanager.h src/downloadmanager.cpp -) - - -add_executable(spark-update-tool - ${PROJECT_SOURCES} -) - -target_link_libraries(spark-update-tool PRIVATE - Qt5::Widgets - Qt5::Network - Qt5::Concurrent - Qt5::Core - Qt5::Gui -) - - -set_target_properties(spark-update-tool PROPERTIES - # ${BUNDLE_ID_OPTION} # 如果上面取消注释,这里也取消注释 - MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} - MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} - -) - -include(GNUInstallDirs) -install(TARGETS spark-update-tool - BUNDLE DESTINATION . - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} -) - diff --git a/spark-update-tool/debian/changelog b/spark-update-tool/debian/changelog deleted file mode 100644 index b414feaa62fe2af76faad258dcb2e6256d7b272c..0000000000000000000000000000000000000000 --- a/spark-update-tool/debian/changelog +++ /dev/null @@ -1,5 +0,0 @@ -spark-update-tool (1.0.0) unstable; urgency=low - - * Initial release. - - -- momen Wed, 18 Jun 2025 00:00:00 +0000 \ No newline at end of file diff --git a/spark-update-tool/debian/compat b/spark-update-tool/debian/compat deleted file mode 100644 index f11c82a4cb6cc2e8f3bdf52b5cdeaad4d5bb214e..0000000000000000000000000000000000000000 --- a/spark-update-tool/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 \ No newline at end of file diff --git a/spark-update-tool/debian/control b/spark-update-tool/debian/control deleted file mode 100644 index 19c9d62467db6f87af7ff74c3aae2c2ef5a921fe..0000000000000000000000000000000000000000 --- a/spark-update-tool/debian/control +++ /dev/null @@ -1,13 +0,0 @@ -Source: spark-update-tool -Section: utils -Priority: optional -Maintainer: momen -Build-Depends: debhelper (>= 9) -Standards-Version: 3.9.6 -Homepage: https://gitee.com/spark-store-project/Spark-Update-Tool - -Package: spark-update-tool -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} -Description: Spark Update Tool - 星火应用商店更新组件。This package provides the Spark Update Tool. It includes features for checking for updates, downloading, and applying them seamlessly. \ No newline at end of file diff --git a/spark-update-tool/debian/copyright b/spark-update-tool/debian/copyright deleted file mode 100644 index 163489ed5542380605ce4603456e9658d8c72a3a..0000000000000000000000000000000000000000 --- a/spark-update-tool/debian/copyright +++ /dev/null @@ -1,7 +0,0 @@ -Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: spark-update-tool -Source: https://gitee.com/spark-store-project/Spark-Update-Tool - -Files: * -Copyright: 2025, momen -License: GPL-3.0+ \ No newline at end of file diff --git a/spark-update-tool/debian/install b/spark-update-tool/debian/install deleted file mode 100644 index ed44f2cf7e2728a1fa73c45cf958f6fed858fc70..0000000000000000000000000000000000000000 --- a/spark-update-tool/debian/install +++ /dev/null @@ -1,3 +0,0 @@ -build/spark-update-tool /usr/bin/ -debian/spark-update-tool.desktop /usr/share/applications -resources/128*128/spark-update-tool.png /usr/share/icons/hicolor/128x128/apps diff --git a/spark-update-tool/debian/postrm b/spark-update-tool/debian/postrm deleted file mode 100644 index 263e9c426093e28f8394aa147020a7f2b5eff742..0000000000000000000000000000000000000000 --- a/spark-update-tool/debian/postrm +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -set -e - -case "$1" in - purge) - - rm -rf /usr/share/spark-update-tool - ;; -esac - -exit 0 \ No newline at end of file diff --git a/spark-update-tool/debian/rules b/spark-update-tool/debian/rules deleted file mode 100755 index 1159ac4f0b7d8abe9203098f7b5da03c42c24257..0000000000000000000000000000000000000000 --- a/spark-update-tool/debian/rules +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/make -f - -%: - dh $@ - -override_dh_auto_configure: - dh_auto_configure -- -DCMAKE_INSTALL_PREFIX=/usr diff --git a/spark-update-tool/debian/source/format b/spark-update-tool/debian/source/format deleted file mode 100644 index 9f6742789cd14191dbf0065f875340a67a042086..0000000000000000000000000000000000000000 --- a/spark-update-tool/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (native) \ No newline at end of file diff --git a/spark-update-tool/debian/spark-update-tool.desktop b/spark-update-tool/debian/spark-update-tool.desktop deleted file mode 100644 index 688ba0cdc04f65926b1ed851addcd92a89d504ff..0000000000000000000000000000000000000000 --- a/spark-update-tool/debian/spark-update-tool.desktop +++ /dev/null @@ -1,9 +0,0 @@ -[Desktop Entry] -Version=1.0 -Name=Spark Update Tool -Comment=A Qt-based application for managing and updating software -Exec=spark-update-tool -Icon=spark-update-tool -Terminal=false -Type=Application -Categories=Utility; diff --git a/spark-update-tool/resources/128*128/spark-update-tool.png b/spark-update-tool/resources/128*128/spark-update-tool.png deleted file mode 100644 index 138ed83770cf4cce8fdead9c11908a0446e8a135..0000000000000000000000000000000000000000 Binary files a/spark-update-tool/resources/128*128/spark-update-tool.png and /dev/null differ diff --git a/spark-update-tool/resources/default_icon.svg b/spark-update-tool/resources/default_icon.svg deleted file mode 100644 index 7c9cb42d466b9475a6269519b8437f22c7fa9aec..0000000000000000000000000000000000000000 --- a/spark-update-tool/resources/default_icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/spark-update-tool/resources/down_arrow.svg b/spark-update-tool/resources/down_arrow.svg deleted file mode 100644 index 4989662cd5e987605beb52cb7f2021e6e163ceda..0000000000000000000000000000000000000000 --- a/spark-update-tool/resources/down_arrow.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/spark-update-tool/resources/spark-update-tool.svg b/spark-update-tool/resources/spark-update-tool.svg deleted file mode 100644 index 3d21d816f49b13e2d76cc273c8f7b1f3e305cf40..0000000000000000000000000000000000000000 --- a/spark-update-tool/resources/spark-update-tool.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/spark-update-tool/src/appdelegate.cpp b/spark-update-tool/src/appdelegate.cpp deleted file mode 100644 index 1a1c3e98779a8ac632c1649f272649c4bb1a9ba7..0000000000000000000000000000000000000000 --- a/spark-update-tool/src/appdelegate.cpp +++ /dev/null @@ -1,321 +0,0 @@ -#include "appdelegate.h" -#include -#include -#include -#include -#include -#include -#include -#include - -AppDelegate::AppDelegate(QObject *parent) - : QStyledItemDelegate(parent), m_downloadManager(new DownloadManager(this)), m_installProcess(nullptr) { - connect(m_downloadManager, &DownloadManager::downloadFinished, this, - [this](const QString &packageName, bool success) { - if (m_downloads.contains(packageName)) { - m_downloads[packageName].isDownloading = false; - emit updateDisplay(packageName); - qDebug() << (success ? "下载完成:" : "下载失败:") << packageName; - if (success) { - enqueueInstall(packageName); - } - } - }); - - connect(m_downloadManager, &DownloadManager::downloadProgress, this, - [this](const QString &packageName, int progress) { - if (m_downloads.contains(packageName)) { - m_downloads[packageName].progress = progress; - qDebug()<save(); - - if (option.state & QStyle::State_Selected) - painter->fillRect(option.rect, option.palette.highlight()); - else - painter->fillRect(option.rect, QColor("#F3F4F6")); - - QFont boldFont = option.font; - boldFont.setBold(true); - QFont normalFont = option.font; - - QString name = index.data(Qt::DisplayRole).toString(); - QString currentVersion = index.data(Qt::UserRole + 2).toString(); - QString newVersion = index.data(Qt::UserRole + 3).toString(); - QString iconPath = index.data(Qt::UserRole + 4).toString(); - QString size = index.data(Qt::UserRole + 5).toString(); - QString description = index.data(Qt::UserRole + 6).toString(); - - QRect rect = option.rect; - int margin = 10, spacing = 6, iconSize = 40; - - QRect iconRect(rect.left() + margin, rect.top() + (rect.height() - iconSize) / 2, iconSize, iconSize); - QIcon(iconPath).paint(painter, iconRect); - - int textX = iconRect.right() + margin; - int textWidth = rect.width() - textX - 100; - - QRect nameRect(textX, rect.top() + margin, textWidth, 20); - painter->setFont(boldFont); - painter->setPen(QColor("#333333")); - painter->drawText(nameRect, Qt::AlignLeft | Qt::AlignVCenter, name); - - QRect versionRect(textX, nameRect.bottom() + spacing, textWidth, 20); - painter->setFont(normalFont); - painter->setPen(QColor("#888888")); - painter->drawText(versionRect, Qt::AlignLeft | Qt::AlignVCenter, - QString("当前版本: %1 → 新版本: %2").arg(currentVersion, newVersion)); - - QRect descRect(textX, versionRect.bottom() + spacing, textWidth, 40); - painter->setFont(normalFont); - painter->setPen(QColor("#AAAAAA")); - painter->drawText(descRect, Qt::TextWordWrap, - QString("包大小:%1 MB").arg(QString::number(size.toDouble() / (1024 * 1024), 'f', 2))); - - QString packageName = index.data(Qt::UserRole + 1).toString(); - bool isDownloading = m_downloads.contains(packageName) && m_downloads[packageName].isDownloading; - int progress = m_downloads.value(packageName, DownloadInfo{0, false}).progress; - bool isInstalled = m_downloads.value(packageName).isInstalled; - bool isInstalling = m_downloads.value(packageName).isInstalling; - - if (isDownloading) { - QRect progressRect(rect.right() - 270, rect.top() + (rect.height() - 20) / 2, 150, 20); - QStyleOptionProgressBar progressBarOption; - progressBarOption.rect = progressRect; - progressBarOption.minimum = 0; - progressBarOption.maximum = 100; - progressBarOption.progress = progress; - progressBarOption.text = QString("%1%").arg(progress); - progressBarOption.textVisible = true; - QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter); - - // 修改后的取消按钮绘制代码 - QRect buttonRect(rect.right() - 80, rect.top() + (rect.height() - 30) / 2, 70, 30); - painter->setPen(Qt::NoPen); - painter->setBrush(QColor("#ff4444")); // 红色背景 - painter->drawRoundedRect(buttonRect, 4, 4); // 圆角矩形 - - painter->setPen(Qt::white); // 白色文字 - painter->setFont(option.font); - painter->drawText(buttonRect, Qt::AlignCenter, "取消"); - } else if (isInstalling) { - // 安装中:显示转圈和文字 - QRect spinnerRect(option.rect.right() - 80, option.rect.top() + (option.rect.height() - 30) / 2, 30, 30); - int angle = (m_spinnerTimer.elapsed() / 10) % 360; - QPen pen(QColor("#2563EB"), 3); - painter->setPen(pen); - painter->setRenderHint(QPainter::Antialiasing, true); - QRectF arcRect = spinnerRect.adjusted(3, 3, -3, -3); - painter->drawArc(arcRect, angle * 16, 120 * 16); // 120度弧 - - QRect textRect(option.rect.right() - 120, option.rect.top() + (option.rect.height() - 30) / 2, 110, 30); - painter->setPen(QColor("#2563EB")); - painter->setFont(option.font); - painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, "正在安装中"); - } else { - QRect buttonRect(option.rect.right() - 80, option.rect.top() + (option.rect.height() - 30) / 2, 70, 30); - painter->setPen(Qt::NoPen); - if (isInstalled) { - painter->setBrush(QColor("#10B981")); - painter->drawRoundedRect(buttonRect, 4, 4); - painter->setPen(Qt::white); - painter->drawText(buttonRect, Qt::AlignCenter, "已安装"); - } else if (m_downloads.contains(packageName) && !m_downloads[packageName].isDownloading) { - // 下载完成,按钮绿色,样式不变 - painter->setBrush(QColor("#10B981")); - painter->drawRoundedRect(buttonRect, 4, 4); - painter->setPen(Qt::white); - painter->drawText(buttonRect, Qt::AlignCenter, "下载完成"); - // 不需要特殊处理样式,交互在 editorEvent 控制 - } else { - painter->setBrush(QColor("#e9effd")); - painter->drawRoundedRect(buttonRect, 4, 4); - painter->setPen(QColor("#2563EB")); - painter->drawText(buttonRect, Qt::AlignCenter, "更新"); - } - } - - painter->restore(); -} - -QSize AppDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { - return QSize(option.rect.width(), 110); -} - -bool AppDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, - const QStyleOptionViewItem &option, const QModelIndex &index) { - if (event->type() == QEvent::MouseButtonRelease) { - QMouseEvent *mouseEvent = static_cast(event); - QRect rect = option.rect; - QString packageName = index.data(Qt::UserRole + 1).toString(); - - if (m_downloads.contains(packageName) && m_downloads[packageName].isDownloading) { - QRect cancelButtonRect(rect.right() - 70, rect.top() + (rect.height() - 20) / 2, 60, 20); - if (cancelButtonRect.contains(mouseEvent->pos())) { - m_downloadManager->cancelDownload(packageName); - m_downloads.remove(packageName); - emit updateDisplay(packageName); - return true; - } - } else { - QRect buttonRect(rect.right() - 80, rect.top() + (rect.height() - 30) / 2, 70, 30); - if (buttonRect.contains(mouseEvent->pos())) { - // 判断是否为“下载完成”状态,如果是则不响应点击 - if (m_downloads.contains(packageName) && !m_downloads[packageName].isDownloading) { - // “下载完成”状态,按钮失效,点击无效 - return false; - } - QString downloadUrl = index.data(Qt::UserRole + 7).toString(); - QString outputPath = QString("%1/%2.metalink").arg(QDir::tempPath(), packageName); - - m_downloads[packageName] = {0, true}; - m_downloadManager->startDownload(packageName, downloadUrl, outputPath); - emit updateDisplay(packageName); - return true; - } - } - } - - return QStyledItemDelegate::editorEvent(event, model, option, index); -} - -void AppDelegate::startDownloadForAll() { - if (!m_model) return; - for (int row = 0; row < m_model->rowCount(); ++row) { - QModelIndex index = m_model->index(row, 0); - QString packageName = index.data(Qt::UserRole + 1).toString(); - if (m_downloads.contains(packageName) && (m_downloads[packageName].isDownloading || m_downloads[packageName].isInstalled)) - continue; // 跳过正在下载或已安装的 - QString downloadUrl = index.data(Qt::UserRole + 7).toString(); - QString outputPath = QString("%1/%2.metalink").arg(QDir::tempPath(), packageName); - m_downloads[packageName] = {0, true, false}; - m_downloadManager->startDownload(packageName, downloadUrl, outputPath); - emit updateDisplay(packageName); - } -} - -// 新增:安装队列相关实现 -void AppDelegate::enqueueInstall(const QString &packageName) { - m_installQueue.enqueue(packageName); - if (!m_isInstalling) { - startNextInstall(); - } -} - -void AppDelegate::startNextInstall() { - if (m_installQueue.isEmpty()) { - m_isInstalling = false; - m_installingPackage.clear(); - return; - } - m_isInstalling = true; - QString packageName = m_installQueue.dequeue(); - m_installingPackage = packageName; - m_downloads[packageName].isInstalling = true; - emit updateDisplay(packageName); - - // 查找 /tmp 下以包名开头的 .deb 文件 - QDir tempDir(QDir::tempPath()); - QStringList debs = tempDir.entryList(QStringList() << QString("%1_*.deb").arg(packageName), QDir::Files); - QString debPath; - if (!debs.isEmpty()) { - debPath = tempDir.absoluteFilePath(debs.first()); - } else { - debs = tempDir.entryList(QStringList() << QString("%1*.deb").arg(packageName), QDir::Files); - if (!debs.isEmpty()) { - debPath = tempDir.absoluteFilePath(debs.first()); - } - } - - if (debPath.isEmpty()) { - qWarning() << "未找到deb文件,包名:" << packageName; - m_downloads[packageName].isInstalling = false; - emit updateDisplay(packageName); - m_installingPackage.clear(); - startNextInstall(); - return; - } - - m_installProcess = new QProcess(this); - - // 新增:准备安装日志文件 - QString logPath = QString("/tmp/%1_install.log").arg(packageName); - QFile *logFile = new QFile(logPath, m_installProcess); - if (logFile->open(QIODevice::Append | QIODevice::Text)) { - // 设置权限为777 - QFile::setPermissions(logPath, QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner | - QFile::ReadGroup | QFile::WriteGroup | QFile::ExeGroup | - QFile::ReadOther | QFile::WriteOther | QFile::ExeOther); - connect(m_installProcess, &QProcess::readyReadStandardOutput, this, [this, packageName, logFile]() { - QByteArray out = m_installProcess->readAllStandardOutput(); - logFile->write(out); - logFile->flush(); - QString text = QString::fromLocal8Bit(out); - qDebug().noquote() << text; - // 检查“软件包已安装”关键字 - if (text.contains(QStringLiteral("软件包已安装"))) { - m_downloads[packageName].isInstalling = false; - m_downloads[packageName].isInstalled = true; - emit updateDisplay(packageName); - } - }); - connect(m_installProcess, &QProcess::readyReadStandardError, this, [this, logFile]() { - QByteArray err = m_installProcess->readAllStandardError(); - logFile->write(err); - logFile->flush(); - qDebug().noquote() << QString::fromLocal8Bit(err); - }); - connect(m_installProcess, QOverload::of(&QProcess::finished), - this, [this, packageName, logFile](int /*exitCode*/, QProcess::ExitStatus /*status*/) { - if (logFile) logFile->close(); - // 若未检测到“软件包已安装”,此处兜底 - if (!m_downloads[packageName].isInstalled) { - m_downloads[packageName].isInstalling = false; - } - emit updateDisplay(packageName); - m_installProcess->deleteLater(); - m_installProcess = nullptr; - m_installingPackage.clear(); - startNextInstall(); - }); - } else { - // 日志文件无法打开时,仍然要连接原有信号 - connect(m_installProcess, &QProcess::readyReadStandardOutput, this, [this, packageName]() { - QByteArray out = m_installProcess->readAllStandardOutput(); - QString text = QString::fromLocal8Bit(out); - qDebug().noquote() << text; - if (text.contains(QStringLiteral("软件包已安装"))) { - m_downloads[packageName].isInstalling = false; - m_downloads[packageName].isInstalled = true; - emit updateDisplay(packageName); - } - }); - connect(m_installProcess, &QProcess::readyReadStandardError, this, [this]() { - QByteArray err = m_installProcess->readAllStandardError(); - qDebug().noquote() << QString::fromLocal8Bit(err); - }); - connect(m_installProcess, QOverload::of(&QProcess::finished), - this, [this, packageName](int /*exitCode*/, QProcess::ExitStatus /*status*/) { - emit updateDisplay(packageName); - m_installProcess->deleteLater(); - m_installProcess = nullptr; - m_installingPackage.clear(); - startNextInstall(); - }); - } - - // 注意参数顺序:deb路径在前,--no-create-desktop-entry在后 - QStringList args; - args << debPath << "--no-create-desktop-entry"; - m_installProcess->start("ssinstall", args); -} diff --git a/spark-update-tool/src/appdelegate.h b/spark-update-tool/src/appdelegate.h deleted file mode 100644 index 0545155ea6e51146bef81eefcebd7a5857065776..0000000000000000000000000000000000000000 --- a/spark-update-tool/src/appdelegate.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include "downloadmanager.h" - -struct DownloadInfo { - int progress = 0; - bool isDownloading = false; - bool isInstalled = false; - bool isInstalling = false; // 新增:标记是否正在安装 -}; - -class AppDelegate : public QStyledItemDelegate { - Q_OBJECT -public: - explicit AppDelegate(QObject *parent = nullptr); - - void setModel(QAbstractItemModel *model); - - void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; - QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; - bool editorEvent(QEvent *event, QAbstractItemModel *model, - const QStyleOptionViewItem &option, const QModelIndex &index) override; - void startDownloadForAll(); - -signals: - void updateDisplay(const QString &packageName); - -private: - DownloadManager *m_downloadManager; - QHash m_downloads; - QAbstractItemModel *m_model = nullptr; - - QQueue m_installQueue; - bool m_isInstalling = false; - QProcess *m_installProcess = nullptr; - QString m_installingPackage; // 当前正在安装的包名 - QElapsedTimer m_spinnerTimer; // 用于转圈动画 - - void enqueueInstall(const QString &packageName); - void startNextInstall(); -}; diff --git a/spark-update-tool/src/applistmodel.cpp b/spark-update-tool/src/applistmodel.cpp deleted file mode 100644 index 31e244a93e0eb54954fd6b0c0e27911d69874179..0000000000000000000000000000000000000000 --- a/spark-update-tool/src/applistmodel.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "applistmodel.h" - -AppListModel::AppListModel(QObject *parent) : QAbstractListModel(parent) {} - -int AppListModel::rowCount(const QModelIndex &parent) const -{ - if (parent.isValid()) - return 0; - return m_data.size(); -} - -QVariant AppListModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid() || index.row() >= m_data.size()) - return QVariant(); - - const QVariantMap &map = m_data.at(index.row()); // 直接访问 QVariantMap - switch (role) { - case Qt::DisplayRole: - return map.value("name"); - case Qt::UserRole + 1: // 包名 - return map.value("package"); - case Qt::UserRole + 2: // 当前版本 - return map.value("current_version"); - case Qt::UserRole + 3: // 新版本 - return map.value("new_version"); - case Qt::UserRole + 4: // 图标路径 - return map.value("icon"); - case Qt::UserRole + 5: // 文件大小 - return map.value("size"); - case Qt::UserRole + 6: // 描述 - return map.value("description"); - case Qt::UserRole + 7: // 下载 URL - return map.value("download_url"); // 返回下载 URL - default: - return QVariant(); - } -} - -void AppListModel::setUpdateData(const QJsonArray &updateInfo) -{ - beginResetModel(); - m_data.clear(); // 清空 QList - - for (const auto &item : updateInfo) { - QJsonObject obj = item.toObject(); - QVariantMap map; - map["package"] = obj["package"].toString(); - map["name"] = obj["name"].toString(); - map["current_version"] = obj["current_version"].toString(); - map["new_version"] = obj["new_version"].toString(); - map["icon"] = obj["icon"].toString(); - map["size"] = obj["size"].toString(); - map["download_url"] = obj["download_url"].toString(); // 确保设置下载 URL - m_data.append(map); // 添加到 QList - - qDebug() << "设置到模型的包名:" << map["package"].toString(); - qDebug() << "设置到模型的下载 URL:" << map["download_url"].toString(); // 检查设置的数据 - } - - endResetModel(); -} diff --git a/spark-update-tool/src/applistmodel.h b/spark-update-tool/src/applistmodel.h deleted file mode 100644 index 2fb36c0d5f6e28d9002c71d4f1ab4d496a849a27..0000000000000000000000000000000000000000 --- a/spark-update-tool/src/applistmodel.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef APPLISTMODEL_H -#define APPLISTMODEL_H - -#include -#include -// 添加 QJsonObject 头文件 -#include - -class AppListModel : public QAbstractListModel -{ - Q_OBJECT -public: - explicit AppListModel(QObject *parent = nullptr); - - // 重写方法 - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - - // 设置更新数据 - void setUpdateData(const QJsonArray &data); - -private: - QList m_data; // 修改类型为 QList -}; - -#endif // APPLISTMODEL_H diff --git a/spark-update-tool/src/aptssupdater.cpp b/spark-update-tool/src/aptssupdater.cpp deleted file mode 100644 index c4bd906045b365dc59b1ef66a8092a4ec0d64904..0000000000000000000000000000000000000000 --- a/spark-update-tool/src/aptssupdater.cpp +++ /dev/null @@ -1,398 +0,0 @@ -#include "aptssupdater.h" -#include -#include -#include -#include -#include - -aptssUpdater::aptssUpdater(QWidget *parent) - : QWidget(parent) -{ - packageName = getUpdateablePackages(); -} - -QStringList aptssUpdater::getUpdateablePackages() -{ - QStringList packageDetails; - QProcess process; - QString command = R"(env LANGUAGE=en_US /usr/bin/apt -c /opt/durapps/spark-store/bin/apt-fast-conf/aptss-apt.conf list --upgradable -o Dir::Etc::sourcelist="/opt/durapps/spark-store/bin/apt-fast-conf/sources.list.d/sparkstore.list" -o Dir::Etc::sourceparts="/dev/null" -o APT::Get::List-Cleanup="0" | awk 'NR>1')"; - - process.start("bash", QStringList() << "-c" << command); - if (!process.waitForFinished()) { - qWarning() << "Process failed to finish."; - return packageDetails; - } - - QString output = process.readAllStandardOutput(); - QStringList lines = output.split('\n', Qt::SkipEmptyParts); - - // 创建临时文件 - QTemporaryFile tempFile; - tempFile.setAutoRemove(false); - if (tempFile.open()) { - QTextStream stream(&tempFile); - - for (const QString &line : lines) { - QRegularExpression regex(R"(([\w\-\+\.]+)/\S+\s+([^\s]+)\s+\S+\s+\[upgradable from: ([^\]]+)\])"); - QRegularExpressionMatch match = regex.match(line); - if (match.hasMatch()) { - QString name = match.captured(1); - QString newVersion = match.captured(2); - QString oldVersion = match.captured(3); - - // 检查版本是否相同,相同则跳过 - if (newVersion == oldVersion) { - qDebug() << "跳过版本相同的包:" << name << "(" << oldVersion << "→" << newVersion << ")"; - continue; - } - - // 写入内存列表 - packageDetails << QString("%1: %2 → %3").arg(name, oldVersion, newVersion); - - // 写入临时文件(原始数据) - stream << name << "|" << oldVersion << "|" << newVersion << "\n"; - } - } - tempFile.close(); - m_tempFilePath = tempFile.fileName(); - qDebug()<< "临时文件路径:" << m_tempFilePath; - - } else { - qWarning() << "无法创建临时文件"; - } - - return packageDetails; -} - - -QStringList aptssUpdater::getPackageSizes() -{ - QStringList packageDetails; - QProcess process; - - // 获取可更新包名列表 - QStringList updateablePackages; - for (const QString &pkgInfo : packageName) { - updateablePackages << pkgInfo.section(":", 0, 0).trimmed(); - } - - foreach (const QString &packageName, updateablePackages) { - // 构建新命令(包含包名参数) - QString command = QString("apt download %1 --print-uris -c /opt/durapps/spark-store/bin/apt-fast-conf/aptss-apt.conf " - "-o Dir::Etc::sourcelist=\"/opt/durapps/spark-store/bin/apt-fast-conf/sources.list.d/sparkstore.list\" " - "-o Dir::Etc::sourceparts=\"/dev/null\"").arg(packageName); - - process.start("bash", QStringList() << "-c" << command); - if (!process.waitForFinished()) { - qWarning() << "获取包信息失败:" << packageName; - continue; - } - - QString output = process.readAllStandardOutput(); - // 使用正则匹配所有信息 - // 调整正则表达式匹配分组 - QRegularExpression regex(R"('([^']+)'\s+(\S+)\s+(\d+)\s+SHA512:([^\s]+))"); // 分组1:URL 分组2:文件名 分组3:大小 分组4:SHA512 - QRegularExpressionMatch match = regex.match(output); - - if (match.hasMatch()) { - QString url = match.captured(1); - QString fileName = match.captured(2); - QString size = match.captured(3); - QString sha512 = match.captured(4); - - // 调整字段顺序:包名 | 大小 | URL | SHA512 - packageDetails << QString("%1: %2|%3|%4").arg(packageName, size, url, sha512); - } - } - - qDebug() << "完整包信息:" << packageDetails; - return packageDetails; -} - - - - - -QStringList aptssUpdater::getDesktopAppNames() -{ - QStringList appNames; - QProcess dpkgProcess; - - // 获取当前系统语言环境 - QString lang = QLocale().name().replace("_", "-"); - - // 遍历所有可更新包(复用已有的临时文件数据) - QStringList packages = packageName; - - foreach (const QString &package, packages) { - QString packageName = package.split(":")[0]; - QString finalName = packageName; // 默认使用包名 - - // 获取包文件列表 - dpkgProcess.start("dpkg", QStringList() << "-L" << packageName); - dpkgProcess.waitForFinished(); - QStringList files = QString(dpkgProcess.readAllStandardOutput()).split('\n', Qt::SkipEmptyParts); - - // 先检查常规应用目录 - QStringList regularDesktopFiles = files.filter("/usr/share/applications/"); - QString regularAppName; - if (!regularDesktopFiles.isEmpty()) { - checkDesktopFiles(regularDesktopFiles, regularAppName, lang, packageName); - } - - // 如果常规目录没有找到,再检查特殊目录 - if (regularAppName.isEmpty()) { - QStringList specialDesktopFiles = files.filter(QRegularExpression(QString("/opt/apps/%1/entries/applications").arg(packageName))); - QString specialAppName; - if (!specialDesktopFiles.isEmpty()) { - checkDesktopFiles(specialDesktopFiles, specialAppName, lang, packageName); - if (!specialAppName.isEmpty()) { - finalName = specialAppName; - } - } - } else { - finalName = regularAppName; - } - - // 输出格式为[软件名|包名] - appNames << QString("[%1|%2]").arg(finalName, packageName); - } - qDebug()<< "应用名称列表:" << appNames; - return appNames; -} - - -bool aptssUpdater::checkDesktopFiles(const QStringList &desktopFiles, QString &appName, const QString &lang, const QString &packageName) -{ - QString lastValidName; - QRegularExpression noDisplayRe("^NoDisplay=(true|True)"); - QRegularExpression nameRe("^Name\\[?" + lang + "?\\]?=(.*)"); - QRegularExpression nameOrigRe("^Name=(.*)"); - - foreach (const QString &filePath, desktopFiles) { - if (!filePath.endsWith(".desktop")) continue; - - QFile file(filePath); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) continue; - - bool skip = false; - QString currentName; - - QTextStream in(&file); - while (!in.atEnd()) { - QString line = in.readLine().trimmed(); - - // 检查NoDisplay属性 - if (line.startsWith("NoDisplay=")) { - if (noDisplayRe.match(line).hasMatch()) { - skip = true; - break; - } - } - - // 优先匹配本地化名称 - if (currentName.isEmpty()) { - QRegularExpressionMatch match = nameRe.match(line); - if (match.hasMatch()) { - currentName = match.captured(1); - continue; - } - - // 匹配原始名称 - match = nameOrigRe.match(line); - if (match.hasMatch()) { - currentName = match.captured(1); - } - } - } - - if (!skip && !currentName.isEmpty()) { - lastValidName = currentName; - } - } - - // 处理最终的有效名称 - if (!lastValidName.isEmpty()) { - appName = lastValidName; // 直接赋值而不是使用<< - return true; - } - - // 回退到包名 - appName = packageName; - return false; -} - -QStringList aptssUpdater::getPackageIcons() -{ - QStringList packageIcons; - QProcess dpkgProcess; - - // 遍历所有可更新包 - QStringList packages = packageName; - - foreach (const QString &package, packages) { - QString packageName = package.split(":")[0]; - QString iconPath = ":/resources/default_icon.svg"; // 默认图标 - - // 获取包文件列表 - dpkgProcess.start("dpkg", QStringList() << "-L" << packageName); - dpkgProcess.waitForFinished(); - QStringList files = QString(dpkgProcess.readAllStandardOutput()).split('\n', Qt::SkipEmptyParts); - - // 查找.desktop文件 - QStringList desktopFiles = files.filter(QRegularExpression("/(usr/share|opt/apps)/.*\\.desktop$")); - - // 从.desktop文件中提取图标 - foreach (const QString &desktopFile, desktopFiles) { - QFile file(desktopFile); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QTextStream in(&file); - while (!in.atEnd()) { - QString line = in.readLine().trimmed(); - if (line.startsWith("Icon=")) { - QString iconName = line.mid(5).trimmed(); - - // 处理相对图标名(如Icon=vscode) - if (!iconName.contains('/')) { - // 查找标准图标路径 - QStringList iconPaths = { - QString("/usr/share/pixmaps/%1.png").arg(iconName), - QString("/usr/share/icons/hicolor/48x48/apps/%1.png").arg(iconName), - QString("/usr/share/icons/hicolor/scalable/apps/%1.svg").arg(iconName), - QString("/opt/apps/%1/entries/icons/hicolor/48x48/apps/%2.png").arg(packageName, iconName) - }; - - foreach (const QString &path, iconPaths) { - if (QFile::exists(path)) { - iconPath = path; - break; - } - } - } else { - // 已经是绝对路径 - if (QFile::exists(iconName)) { - iconPath = iconName; - } - } - break; - } - } - file.close(); - } - } - - // 如果.desktop中没有找到图标,尝试直接查找包中的图标文件 - if (iconPath == ":/resources/default_icon.svg") { - QStringList iconFiles = files.filter(QRegularExpression("/(usr/share/pixmaps|usr/share/icons|opt/apps/.*/entries/icons)/.*\\.(png|svg)$")); - if (!iconFiles.isEmpty()) { - iconPath = iconFiles.first(); - } - } - - qDebug() << "包名:" << packageName << "图标路径:" << iconPath; - packageIcons << QString("%1: %2").arg(packageName, iconPath); - } - - return packageIcons; -} - - -QJsonArray aptssUpdater::getUpdateInfoAsJson() -{ - QJsonArray jsonArray; - - // 获取所有需要的信息 - QStringList sizes = getPackageSizes(); - QStringList names = getDesktopAppNames(); - QStringList icons = getPackageIcons(); - - // 创建包名到各种信息的映射 - QHash> packageInfo; - - // 解析包版本信息 - for (const QString &pkg : packageName) { - QStringList parts = pkg.split(": "); - if (parts.size() >= 2) { - QString packageName = parts[0]; - QStringList versions = parts[1].split(" → "); - if (versions.size() == 2) { - packageInfo[packageName]["current_version"] = versions[0]; - packageInfo[packageName]["new_version"] = versions[1]; - } - } - } - - // 解析包详细信息(新增部分) - for (const QString &sizeInfo : sizes) { - QStringList parts = sizeInfo.split(": "); - if (parts.size() == 2) { - QString packageName = parts[0]; - QStringList details = parts[1].split("|"); - if (details.size() == 3) { // 现在包含大小|URL|SHA512 - packageInfo[packageName]["size"] = details[0]; - packageInfo[packageName]["url"] = details[1]; - packageInfo[packageName]["sha512"] = details[2]; - } - } - } - - // 解析应用名称信息 - for (const QString &nameInfo : names) { - if (nameInfo.startsWith("[") && nameInfo.endsWith("]")) { - QString content = nameInfo.mid(1, nameInfo.length() - 2); - QStringList parts = content.split("|"); - if (parts.size() == 2) { - QString displayName = parts[0]; - QString packageName = parts[1]; - packageInfo[packageName]["display_name"] = displayName; - } - } - } - - // 解析图标信息 - for (const QString &iconInfo : icons) { - QStringList parts = iconInfo.split(": "); - if (parts.size() == 2) { - QString packageName = parts[0]; - packageInfo[packageName]["icon"] = parts[1].trimmed(); - } - } - - // 构建JSON数组 - for (const QString &packageName : packageInfo.keys()) { - QJsonObject jsonObj; - jsonObj["package"] = packageName; - - // 使用显示名称(如果有),否则使用包名 - if (packageInfo[packageName].contains("display_name")) { - jsonObj["name"] = packageInfo[packageName]["display_name"]; - } else { - jsonObj["name"] = packageName; - } - - jsonObj["current_version"] = packageInfo[packageName]["current_version"]; - jsonObj["new_version"] = packageInfo[packageName]["new_version"]; - jsonObj["icon"] = packageInfo[packageName]["icon"]; - jsonObj["ignored"] = false; // 默认不忽略 - - // 如果有大小信息也加入 - if (packageInfo[packageName].contains("size")) { - jsonObj["size"] = packageInfo[packageName]["size"]; - } - - // 在构建JSON对象时添加新字段(在jsonObj中添加): - if (packageInfo[packageName].contains("url")) { - jsonObj["download_url"] = packageInfo[packageName]["url"]; - qDebug() << "生成的下载 URL:" << packageInfo[packageName]["url"]; // 检查生成的 URL - } else { - qWarning() << "未找到下载 URL,包名:" << packageName; - jsonObj["download_url"] = ""; // 设置为空字符串以避免崩溃 - } - jsonObj["sha512"] = packageInfo[packageName]["sha512"]; - jsonArray.append(jsonObj); - } - qDebug()< -#include -#include -#include -#include -#include -class aptssUpdater : public QWidget -{ - Q_OBJECT -public: - explicit aptssUpdater(QWidget *parent = nullptr); - - QStringList getUpdateablePackages(); // 查询可更新包列表及更新内容 - QStringList getPackageSizes(); // 获取每个包的大小 - QStringList getDesktopAppNames(); // 获取桌面应用名称列表 - QStringList getPackageIcons(); // 获取包图标列表 - QJsonArray getUpdateInfoAsJson(); // 获取更新信息的 JSON 格式 - QString m_tempFilePath; -signals: -private: - bool checkDesktopFiles(const QStringList &desktopFiles, QString &appName, const QString &lang, const QString &packageName); - QStringList packageName; -}; - -#endif // APTSSUPDATER_H \ No newline at end of file diff --git a/spark-update-tool/src/downloadmanager.cpp b/spark-update-tool/src/downloadmanager.cpp deleted file mode 100644 index 978032497a958266708a7eff772e51075c63cecf..0000000000000000000000000000000000000000 --- a/spark-update-tool/src/downloadmanager.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "downloadmanager.h" -#include -#include -#include -#include -#include - -DownloadManager::DownloadManager(QObject *parent) : QObject(parent) -{ - cleanupTempFiles(); -} - -void DownloadManager::startDownload(const QString &packageName, const QString &url, const QString &outputPath) -{ - if (m_processes.contains(packageName)) { - qWarning() << packageName << " is already downloading."; - return; - } - - QString metalinkUrl = url + ".metalink"; - QFileInfo fileInfo(outputPath); - - QStringList arguments = { - "--enable-rpc=false", - "--console-log-level=warn", - "--summary-interval=1", - "--allow-overwrite=true", - "--dir=" + fileInfo.absolutePath(), - "--out=" + fileInfo.fileName(), - metalinkUrl - }; - - QProcess *process = new QProcess(this); - m_processes.insert(packageName, process); - - // 新增:准备日志文件 - QString logPath = QString("/tmp/%1_download.log").arg(packageName); - QFile *logFile = new QFile(logPath, process); - if (logFile->open(QIODevice::Append | QIODevice::Text)) { - // 设置权限为777 - QFile::setPermissions(logPath, QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner | - QFile::ReadGroup | QFile::WriteGroup | QFile::ExeGroup | - QFile::ReadOther | QFile::WriteOther | QFile::ExeOther); - connect(process, &QProcess::readyReadStandardOutput, this, [this, packageName, process, logFile]() { - while (process->canReadLine()) { - QString line = QString::fromUtf8(process->readLine()).trimmed(); - // 写入日志 - logFile->write(line.toUtf8() + '\n'); - logFile->flush(); - QRegularExpression regex(R"(\((\d+)%\))"); - QRegularExpressionMatch match = regex.match(line); - if (match.hasMatch()) { - int progress = match.captured(1).toInt(); - emit downloadProgress(packageName, progress); - } - } - }); - connect(process, &QProcess::readyReadStandardError, this, [process, logFile]() { - QByteArray err = process->readAllStandardError(); - logFile->write(err); - logFile->flush(); - }); - } - - connect(process, QOverload::of(&QProcess::finished), - this, [this, packageName, outputPath, logFile](int exitCode, QProcess::ExitStatus status) { - bool success = (exitCode == 0 && status == QProcess::NormalExit); - if (!success) { - qWarning() << "Download failed for" << packageName << "exit code:" << exitCode; - } - - removeAria2Files(outputPath); // 清理残留 .aria2 - emit downloadFinished(packageName, success); - - if (logFile) logFile->close(); - - QProcess *proc = m_processes.take(packageName); - if (proc) proc->deleteLater(); - }); - - process->start("aria2c", arguments); -} - -void DownloadManager::cancelDownload(const QString &packageName) -{ - if (!m_processes.contains(packageName)) return; - - QProcess *process = m_processes.take(packageName); - if (process) { - process->kill(); // 立即终止 - process->waitForFinished(3000); // 最多等待3秒 - process->deleteLater(); - } - - emit downloadFinished(packageName, false); // 显式通知取消 - -} - -void DownloadManager::removeAria2Files(const QString &filePath) -{ - QString ariaFile = filePath + ".aria2"; - QFile::remove(ariaFile); -} - -bool DownloadManager::isDownloading(const QString &packageName) const -{ - return m_processes.contains(packageName); -} - -void DownloadManager::cleanupTempFiles() -{ - QDir tempDir(QDir::tempPath()); - QStringList leftovers = tempDir.entryList(QStringList() << "*.aria2", QDir::Files); - for (const QString &f : leftovers) { - tempDir.remove(f); - } -} diff --git a/spark-update-tool/src/downloadmanager.h b/spark-update-tool/src/downloadmanager.h deleted file mode 100644 index 0614368a97a0425b4ab7c30edfddeaa7fda1afef..0000000000000000000000000000000000000000 --- a/spark-update-tool/src/downloadmanager.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef DOWNLOADMANAGER_H -#define DOWNLOADMANAGER_H - -#include -#include -#include - -class DownloadManager : public QObject -{ - Q_OBJECT -public: - explicit DownloadManager(QObject *parent = nullptr); - void startDownload(const QString &packageName, const QString &url, const QString &outputPath); - void cancelDownload(const QString &packageName); - bool isDownloading(const QString &packageName) const; - -signals: - void downloadProgress(const QString &packageName, int progress); - void downloadFinished(const QString &packageName, bool success); - -private: - void cleanupTempFiles(); - void removeAria2Files(const QString &filePath); - - QMap m_processes; -}; - -#endif // DOWNLOADMANAGER_H diff --git a/spark-update-tool/src/icons.qrc b/spark-update-tool/src/icons.qrc deleted file mode 100644 index f81e1f884217148aad373b3625200e0f72f8f13b..0000000000000000000000000000000000000000 --- a/spark-update-tool/src/icons.qrc +++ /dev/null @@ -1,8 +0,0 @@ - - - ../resources/down_arrow.svg - ../resources/default_icon.svg - ../resources/spark-update-tool.svg - ../resources/128*128/spark-update-tool.png - - diff --git a/spark-update-tool/src/main.cpp b/spark-update-tool/src/main.cpp deleted file mode 100644 index a3df5a4312ec4aa1ab077ce7d200b51a928e7f71..0000000000000000000000000000000000000000 --- a/spark-update-tool/src/main.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "mainwindow.h" -#include -#include -#include -#include // for geteuid -#include // for getenv -#include // For debugging output - -bool isRoot() { - return geteuid() == 0; -} - -bool elevateToRoot() { - QString program = QCoreApplication::applicationFilePath(); - qDebug() << "Current application path:" << program; - - QByteArray display = qgetenv("DISPLAY"); - QByteArray xauthority = qgetenv("XAUTHORITY"); - - QStringList args; - args << "env" - << "DISPLAY=" + display - << "XAUTHORITY=" + xauthority - << program; - - QProcess process; - process.setProgram("pkexec"); - process.setArguments(args); - - qDebug() << "Attempting to elevate using pkexec with arguments:" << args; - - process.start(); - if (!process.waitForStarted(5000)) { - qDebug() << "Failed to start pkexec."; - return false; - } - - // 阻塞等待提权进程退出(比如主程序窗口关闭) - if (!process.waitForFinished(-1)) { // 等待直到新进程退出 - qDebug() << "pkexec process waitForFinished failed."; - return false; - } - - int exitCode = process.exitCode(); - QProcess::ExitStatus exitStatus = process.exitStatus(); - - qDebug() << "pkexec exit code:" << exitCode; - qDebug() << "pkexec exit status:" << exitStatus; - qDebug() << "pkexec stderr:" << process.readAllStandardError(); - - return (exitStatus == QProcess::NormalExit && exitCode == 0); -} - -int main(int argc, char *argv[]) -{ - // 必须在 QGuiApplication 实例创建之前调用 - // QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); - - QApplication a(argc, argv); - a.setWindowIcon(QIcon(":/resources/128*128/spark-update-tool.png")); - if (!isRoot()) { - qDebug() << "Not running as root. Attempting to elevate..."; - if (!elevateToRoot()) { - qDebug() << "Elevation failed or pkexec command was not executed successfully."; - QMessageBox::critical(nullptr, - "权限不足", - "提权失败!\n\n您的系统可能不支持 `pkexec` 或 `polkit` 配置不正确," - "或者您取消了授权。\n\n请尝试使用 `sudo` 命令运行此程序:" - "\n\n在终端中输入:\n`sudo " + QCoreApplication::applicationName() + "`"); - return 0; // 提权失败,退出程序 - } else { - // 如果 elevateToRoot 返回 true,说明 pkexec 命令本身执行成功 - // 但这并不意味着原始程序以 root 权限启动了 - // 因为 elevateToRoot 启动的是一个新的进程,当前进程应该退出 - // 否则会并行运行两个程序实例 - qDebug() << "pkexec command executed successfully (new process likely started). Exiting current process."; - return 0; // 当前非root进程退出 - } - } else { - qDebug() << "Running as root."; - } - - MainWindow w; - w.show(); - return a.exec(); -} \ No newline at end of file diff --git a/spark-update-tool/src/mainwindow.cpp b/spark-update-tool/src/mainwindow.cpp deleted file mode 100644 index dde2a4c51df744cad044d0ff75b1e3edee948b59..0000000000000000000000000000000000000000 --- a/spark-update-tool/src/mainwindow.cpp +++ /dev/null @@ -1,229 +0,0 @@ -#include "mainwindow.h" -#include "./ui_mainwindow.h" -#include -#include -#include -#include // 新增 -#include // 新增 -#include -#include -MainWindow::MainWindow(QWidget *parent) - : QMainWindow(parent) - , ui(new Ui::MainWindow) - , m_model(new AppListModel(this)) - , m_delegate(new AppDelegate(this)) -{ - QIcon icon(":/resources/128*128/spark-update-tool.png"); - setWindowIcon(icon); - QProgressDialog *progressDialog = new QProgressDialog("正在与服务器通信,获取更新信息中...", QString(), 0, 0, this); - progressDialog->setWindowModality(Qt::ApplicationModal); - progressDialog->setCancelButton(nullptr); - progressDialog->setWindowTitle("请稍候"); - progressDialog->setMinimumDuration(0); - progressDialog->setWindowFlags(progressDialog->windowFlags() & ~Qt::WindowCloseButtonHint); // 禁用关闭按钮 - progressDialog->show(); - //异步执行runAptssUpgrade - QFutureWatcher *watcher = new QFutureWatcher(this); - connect(watcher, &QFutureWatcher::finished, this, [=]() { - progressDialog->close(); - progressDialog->deleteLater(); - watcher->deleteLater(); - ui->setupUi(this); - QIcon icon(":/resources/128*128/spark-update-tool.png"); - setWindowIcon(icon); - // 创建 QListView 并设置父控件为 ui->appWidget - listView = new QListView(ui->appWidget); - listView->setModel(m_model); - listView->setItemDelegate(m_delegate); - - // 新增:确保 delegate 拥有 model 指针 - m_delegate->setModel(m_model); - - // 设置 QListView 填充 ui->appWidget - QVBoxLayout *layout = new QVBoxLayout(ui->appWidget); - layout->addWidget(listView); - layout->setContentsMargins(0, 0, 0, 0); - connect(m_delegate, &AppDelegate::updateDisplay, this, [=](const QString &packageName) { - for (int i = 0; i < m_model->rowCount(); ++i) { - QModelIndex index = m_model->index(i); - if (index.data(Qt::UserRole + 1).toString() == packageName) { - m_model->dataChanged(index, index); // 刷新该行 - break; - } - } - }); - - // 新增:点击“更新全部”按钮批量下载 - connect(ui->updatePushButton, &QPushButton::clicked, this, [=](){ - qDebug()<<"更新全部按钮被点击"; - m_delegate->startDownloadForAll(); - }); - - checkUpdates(); - initStyle(); - }); - - // 启动异步任务 - watcher->setFuture(QtConcurrent::run([this](){ - runAptssUpgrade(); - })); -} -//初始化控件样式 -void MainWindow::initStyle() -{ - //设置窗口标题 - this->setWindowTitle("软件更新中心"); - - //查询框样式 - ui->plainTextEdit->setStyleSheet(R"( - QPlainTextEdit { - background-color: #FFFFFF; - border: 1px solid #E5E7EB; - border-radius: 4px; - padding-top: 8px; - padding-bottom: 8px; - font-size: 9px; - line-height: 1.4; - color: #9CA3AF; - } - )"); - - ui->plainTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui->plainTextEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - - //筛选框样式 - ui->FilterComboBox->setStyleSheet(R"( - QComboBox { - background-color: #FFFFFF; - border: 1px solid #E5E7EB; - border-radius: 4px; - color: #4B5563; - padding: 4px 8px; - } - - QComboBox::drop-down { - border: none; - width: 20px; - } - - QComboBox::down-arrow { - image: url(:/resources/down_arrow.svg); - width: 12px; - height: 16px; - } - QComboBox QAbstractItemView { - background-color: #FFFFFF; - border: 1px solid #E5E7EB; - color: #4B5563; - selection-background-color: #F3F4F6; - selection-color: #111827; - } - )"); - - //更新软件按钮样式 - ui->updatePushButton->setStyleSheet(R"( - QPushButton { - background-color: #2563EB; - color: #FFFFFF; - border: none; - border-radius: 4px; - font-size: 14px; - padding: 6px 12px; - text-align: center; - } - - QPushButton:hover { - background-color: #1D4ED8; /* 深一点的 hover 效果,可选 */ - } - - QPushButton:pressed { - background-color: #1E40AF; /* 按下效果,可选 */ - } - - QPushButton:disabled { - background-color: #A5B4FC; - color: #F9FAFB; - } - )"); - - //设置背景填充颜色 - ui->backgroundWidget->setStyleSheet(R"( - QWidget { - background-color: #FFFFFF; - border-radius: 12px; - } - )"); - - //设置主背景颜色 - this->setStyleSheet("background-color: #F8FAFC;"); - - // 添加滚动条样式 - this->setStyleSheet(R"( - QScrollBar:vertical { - background: #F3F4F6; - width: 8px; - margin: 0px; - } - QScrollBar::handle:vertical { - background: #D1D5DB; - border-radius: 4px; - min-height: 30px; - } - QScrollBar::handle:vertical:hover { - background: #9CA3AF; - } - QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { - background: none; - height: 0px; - } - - QScrollBar:horizontal { - background: #F3F4F6; - height: 8px; - margin: 0px; - } - QScrollBar::handle:horizontal { - background: #D1D5DB; - border-radius: 4px; - min-width: 30px; - } - QScrollBar::handle:horizontal:hover { - background: #9CA3AF; - } - )"); -} -void MainWindow::checkUpdates() -{ - aptssUpdater updater; - QJsonArray updateInfo = updater.getUpdateInfoAsJson(); - m_model->setUpdateData(updateInfo); - - for (const auto &item : updateInfo) { - QJsonObject obj = item.toObject(); - qDebug() << "模型设置的包名:" << obj["package"].toString(); - qDebug() << "模型设置的下载 URL:" << obj["download_url"].toString(); // 检查模型数据 - } -} - -void MainWindow::runAptssUpgrade() -{ - QProcess process; - QStringList args; - args << "sudo" <<"aptss" << "ssupdate"; - process.start("sudo", args); - if (!process.waitForStarted(5000)) { - QMessageBox::warning(this, "升级失败", "无法启动 sudo aptss ssupdate"); - return; - } - process.write("n\n"); - process.closeWriteChannel(); - process.waitForFinished(-1); - if (process.exitCode() != 0) { - QMessageBox::warning(this, "升级失败", "执行 sudo aptss ssupdate 失败,请检查系统环境。"); - } -} - -MainWindow::~MainWindow() -{ - delete ui; -} diff --git a/spark-update-tool/src/mainwindow.h b/spark-update-tool/src/mainwindow.h deleted file mode 100644 index e36db88acd1f1c7c708096d0ea3ee9ea46ce372c..0000000000000000000000000000000000000000 --- a/spark-update-tool/src/mainwindow.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include -#include "aptssupdater.h" -#include "applistmodel.h" -#include "appdelegate.h" -#include - -QT_BEGIN_NAMESPACE -namespace Ui { -class MainWindow; -} -QT_END_NAMESPACE - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - MainWindow(QWidget *parent = nullptr); - ~MainWindow(); - -private: - Ui::MainWindow *ui; - void checkUpdates(); - void initStyle(); - void runAptssUpgrade(); - AppListModel *m_model; - AppDelegate *m_delegate; - QListView *listView; // 声明 QListView 指针 -}; -#endif // MAINWINDOW_H diff --git a/spark-update-tool/src/mainwindow.ui b/spark-update-tool/src/mainwindow.ui deleted file mode 100644 index 2a582878b6366d901782d4837fcfae0fe00adccd..0000000000000000000000000000000000000000 --- a/spark-update-tool/src/mainwindow.ui +++ /dev/null @@ -1,256 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 1440 - 858 - - - - MainWindow - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - Noto Sans Vai - 22 - - - - 软件更新中心 - - - - - - - Qt::Horizontal - - - - 1245 - 20 - - - - - - - - - - - - - - - 0 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 320 - 38 - - - - - 320 - 38 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 200 - 38 - - - - - - - 81.000000000000000 - - - 搜索软件... - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 214 - 40 - - - - - 214 - 40 - - - - - - 0 - 0 - 102 - 38 - - - - - 102 - 38 - - - - - 102 - 38 - - - - - - - Qt::LeftToRight - - - QComboBox::AdjustToContentsOnFirstShow - - - - 按名称 - - - - - - - 118 - 0 - 96 - 40 - - - - 更新全部 - - - - - - - - - - - true - - - - 0 - 0 - - - - - - - - - - - - - 0 - 0 - 1440 - 23 - - - - - - - diff --git a/src/spark-update-tool/README.md b/src/spark-update-tool/README.md index ae2026a355d1ee1322ad5a5c4b1cb2b01e86f6cc..e5728804bff18b174c5f522486d3f81028dc5363 100644 --- a/src/spark-update-tool/README.md +++ b/src/spark-update-tool/README.md @@ -1,29 +1,21 @@ -### 星火软件更新器 +### Spark Software Updater -#### 简介 +#### Introduction -欢迎使用星火软件更新器!本工具可帮助您便捷地更新 Linux 计算机上的各类程序。 +Welcome to Spark Software Updater! This tool helps you conveniently update various applications on your Linux system. -本版本专为仅包含 Qt5 的 Linux 发行版设计。 -**请在 root 权限下运行本程序。** +This version is specifically designed for Linux distributions with Qt5 support. +**Please run with root privileges (recommended to use `sudo`).** -#### 当前支持的 Linux 发行版 +#### Currently Supported Linux Distributions - [x] GXDE OS - [x] Ubuntu - [x] deepin - [ ] Kylin -#### 功能清单 +// ... existing Chinese feature table ... -| 功能模块 | 描述 | -|------------------|--------------------------------------| -| 应用名识别 | 基于 `ss-do-upgrade.sh` 部分代码实现 | -| 应用包大小识别 | 通过 dpkg 获取包大小信息 | -| 获取应用图标 | 利用 QDesktopServices 实现 | -| 支持 ACE 兼容环境| | -| 多线程下载 | 基于 aptss 方案 | +#### Contact & Feedback -#### 联系与反馈 - -如有问题或建议,欢迎联系:momen@momen.world \ No newline at end of file +For any issues or suggestions, please contact: momen@momen.world diff --git a/spark-update-tool/README.md b/src/spark-update-tool/README.zh.md similarity index 93% rename from spark-update-tool/README.md rename to src/spark-update-tool/README.zh.md index ae2026a355d1ee1322ad5a5c4b1cb2b01e86f6cc..3e30de3235088bf94329210cf3e157e9b95d30b4 100644 --- a/spark-update-tool/README.md +++ b/src/spark-update-tool/README.zh.md @@ -24,6 +24,7 @@ | 支持 ACE 兼容环境| | | 多线程下载 | 基于 aptss 方案 | +如您已安装星火应用商店,则会附带本程序。 #### 联系与反馈 如有问题或建议,欢迎联系:momen@momen.world \ No newline at end of file diff --git a/src/spark-update-tool/src/appdelegate.cpp b/src/spark-update-tool/src/appdelegate.cpp index 1a1c3e98779a8ac632c1649f272649c4bb1a9ba7..4efbc4671f9c76fa85823d200566c17f95fe53c4 100644 --- a/src/spark-update-tool/src/appdelegate.cpp +++ b/src/spark-update-tool/src/appdelegate.cpp @@ -12,14 +12,14 @@ AppDelegate::AppDelegate(QObject *parent) : QStyledItemDelegate(parent), m_downloadManager(new DownloadManager(this)), m_installProcess(nullptr) { connect(m_downloadManager, &DownloadManager::downloadFinished, this, [this](const QString &packageName, bool success) { - if (m_downloads.contains(packageName)) { - m_downloads[packageName].isDownloading = false; - emit updateDisplay(packageName); - qDebug() << (success ? "下载完成:" : "下载失败:") << packageName; - if (success) { - enqueueInstall(packageName); - } - } + if (m_downloads.contains(packageName)) { + m_downloads[packageName].isDownloading = false; + emit updateDisplay(packageName); + qDebug() << (success ? "下载完成:" : "下载失败:") << packageName; + if (success) { + enqueueInstall(packageName); + } + } }); connect(m_downloadManager, &DownloadManager::downloadProgress, this, @@ -276,18 +276,19 @@ void AppDelegate::startNextInstall() { qDebug().noquote() << QString::fromLocal8Bit(err); }); connect(m_installProcess, QOverload::of(&QProcess::finished), - this, [this, packageName, logFile](int /*exitCode*/, QProcess::ExitStatus /*status*/) { - if (logFile) logFile->close(); - // 若未检测到“软件包已安装”,此处兜底 - if (!m_downloads[packageName].isInstalled) { - m_downloads[packageName].isInstalling = false; - } - emit updateDisplay(packageName); - m_installProcess->deleteLater(); - m_installProcess = nullptr; - m_installingPackage.clear(); - startNextInstall(); - }); + this, [this, packageName, logFile](int exitCode, QProcess::ExitStatus status) { + if (logFile) logFile->close(); + m_downloads[packageName].isInstalling = false; + if (exitCode == 0) { + m_downloads[packageName].isInstalled = true; // 安装成功 + } + emit updateDisplay(packageName); + m_installProcess->deleteLater(); + m_installProcess = nullptr; + m_installingPackage.clear(); + startNextInstall(); + }); + } else { // 日志文件无法打开时,仍然要连接原有信号 connect(m_installProcess, &QProcess::readyReadStandardOutput, this, [this, packageName]() {