mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-04-26 09:20:18 +08:00
feat(迁移功能): 添加包迁移功能支持
实现从aptss到apm的包迁移功能 - 添加迁移包集合存储用户确认的迁移项 - 在数据模型中添加迁移相关字段 - 修改合并逻辑以识别迁移场景 - 添加迁移确认对话框 - 处理迁移安装时的特殊逻辑
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include <QMouseEvent>
|
||||
#include <QFile>
|
||||
#include <QEventLoop>
|
||||
#include <QMessageBox>
|
||||
|
||||
AppDelegate::AppDelegate(QObject *parent)
|
||||
: QStyledItemDelegate(parent), m_downloadManager(new DownloadManager(this)), m_installProcess(nullptr) {
|
||||
@@ -379,7 +380,24 @@ bool AppDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||
if (m_downloads.contains(packageName) && !m_downloads[packageName].isDownloading) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// 检查是否为迁移项
|
||||
bool isMigration = index.data(Qt::UserRole + 10).toBool();
|
||||
if (isMigration) {
|
||||
QString migrationTarget = index.data(Qt::UserRole + 12).toString();
|
||||
QMessageBox::StandardButton reply = QMessageBox::question(
|
||||
nullptr,
|
||||
"确认迁移",
|
||||
QString("此更新将把应用替换为 %1 版本,是否继续?").arg(migrationTarget.toUpper()),
|
||||
QMessageBox::Yes | QMessageBox::No
|
||||
);
|
||||
if (reply != QMessageBox::Yes) {
|
||||
return true; // 用户取消,不执行更新
|
||||
}
|
||||
// 用户确认,标记为迁移安装
|
||||
m_migrationPackages.insert(packageName);
|
||||
}
|
||||
|
||||
// 检查/tmp目录下是否已经存在deb包
|
||||
QDir tempDir(QDir::tempPath());
|
||||
QStringList debs = tempDir.entryList(QStringList() << QString("%1_*.deb").arg(packageName), QDir::Files);
|
||||
@@ -392,7 +410,7 @@ bool AppDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||
debPath = tempDir.absoluteFilePath(debs.first());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 触发下载流程(无论是否存在deb包,都尝试续传)
|
||||
QString downloadUrl = index.data(Qt::UserRole + 7).toString();
|
||||
QString outputPath = QString("%1/%2.metalink").arg(QDir::tempPath(), packageName);
|
||||
@@ -410,17 +428,77 @@ bool AppDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||
|
||||
void AppDelegate::startDownloadForAll() {
|
||||
if (!m_model) return;
|
||||
|
||||
// 收集所有迁移项,准备批量提示
|
||||
QStringList migrationPackages;
|
||||
for (int row = 0; row < m_model->rowCount(); ++row) {
|
||||
QModelIndex index = m_model->index(row, 0);
|
||||
|
||||
|
||||
// 检查应用是否被忽略
|
||||
bool isIgnored = index.data(Qt::UserRole + 8).toBool();
|
||||
if (isIgnored) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查是否为迁移项
|
||||
bool isMigration = index.data(Qt::UserRole + 10).toBool();
|
||||
if (isMigration) {
|
||||
QString packageName = index.data(Qt::UserRole + 1).toString();
|
||||
QString migrationTarget = index.data(Qt::UserRole + 12).toString();
|
||||
migrationPackages.append(QString("%1 → %2").arg(packageName, migrationTarget.toUpper()));
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有迁移项,弹出批量确认对话框
|
||||
if (!migrationPackages.isEmpty()) {
|
||||
QString message = "以下应用更新后将替换为新的版本来源:\n\n";
|
||||
message += migrationPackages.join("\n");
|
||||
message += "\n\n是否继续更新这些应用?";
|
||||
|
||||
QMessageBox::StandardButton reply = QMessageBox::question(
|
||||
nullptr,
|
||||
"确认迁移",
|
||||
message,
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel
|
||||
);
|
||||
|
||||
if (reply == QMessageBox::Cancel) {
|
||||
return; // 完全取消更新全部
|
||||
}
|
||||
|
||||
// 如果用户点击 Yes,将所有迁移项加入迁移集合
|
||||
if (reply == QMessageBox::Yes) {
|
||||
for (int row = 0; row < m_model->rowCount(); ++row) {
|
||||
QModelIndex index = m_model->index(row, 0);
|
||||
bool isMigration = index.data(Qt::UserRole + 10).toBool();
|
||||
if (isMigration) {
|
||||
QString packageName = index.data(Qt::UserRole + 1).toString();
|
||||
m_migrationPackages.insert(packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果用户点击 No,跳过迁移项,继续更新其他应用
|
||||
}
|
||||
|
||||
for (int row = 0; row < m_model->rowCount(); ++row) {
|
||||
QModelIndex index = m_model->index(row, 0);
|
||||
|
||||
// 检查应用是否被忽略
|
||||
bool isIgnored = index.data(Qt::UserRole + 8).toBool();
|
||||
if (isIgnored) {
|
||||
qDebug() << "跳过被忽略的应用:" << index.data(Qt::UserRole + 1).toString();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
QString packageName = index.data(Qt::UserRole + 1).toString();
|
||||
|
||||
// 检查是否为迁移项且用户未确认
|
||||
bool isMigration = index.data(Qt::UserRole + 10).toBool();
|
||||
if (isMigration && !m_migrationPackages.contains(packageName)) {
|
||||
qDebug() << "跳过未确认的迁移项:" << packageName;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_downloads.contains(packageName) && (m_downloads[packageName].isDownloading || m_downloads[packageName].isInstalled))
|
||||
continue;
|
||||
QString downloadUrl = index.data(Qt::UserRole + 7).toString();
|
||||
@@ -485,15 +563,18 @@ void AppDelegate::startNextInstall() {
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是APM包,先检查APM中是否存在对应的包,再卸载APTSS版本
|
||||
if (source == "apm") {
|
||||
// 检查是否为迁移场景
|
||||
bool isMigration = m_migrationPackages.contains(packageName);
|
||||
|
||||
// 如果是APM包或者是迁移场景,先检查APM中是否存在对应的包,再卸载APTSS版本
|
||||
if (source == "apm" || isMigration) {
|
||||
// 检查APM中是否存在对应的包
|
||||
QProcess checkProcess;
|
||||
QStringList checkArgs;
|
||||
checkArgs << "list" << packageName;
|
||||
checkProcess.start("apm", checkArgs);
|
||||
checkProcess.waitForFinished(30000); // 30秒超时
|
||||
|
||||
|
||||
QString checkOutput = checkProcess.readAllStandardOutput();
|
||||
if (checkOutput.contains(packageName)) {
|
||||
// APM中存在对应的包,卸载APTSS版本
|
||||
@@ -849,19 +930,75 @@ void AppDelegate::updateSpinner() {
|
||||
// 新增:更新选中应用的方法
|
||||
void AppDelegate::startDownloadForSelected() {
|
||||
if (!m_model) return;
|
||||
|
||||
// 首先检查选中的应用中是否有迁移项
|
||||
QStringList selectedMigrationPackages;
|
||||
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_selectedPackages.contains(packageName)) {
|
||||
bool isMigration = index.data(Qt::UserRole + 10).toBool();
|
||||
if (isMigration && !m_migrationPackages.contains(packageName)) {
|
||||
QString migrationTarget = index.data(Qt::UserRole + 12).toString();
|
||||
selectedMigrationPackages.append(QString("%1 → %2").arg(packageName, migrationTarget.toUpper()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有未确认的迁移项,弹出确认对话框
|
||||
if (!selectedMigrationPackages.isEmpty()) {
|
||||
QString message = "以下选中的应用更新后将替换为新的版本来源:\n\n";
|
||||
message += selectedMigrationPackages.join("\n");
|
||||
message += "\n\n是否继续更新这些应用?";
|
||||
|
||||
QMessageBox::StandardButton reply = QMessageBox::question(
|
||||
nullptr,
|
||||
"确认迁移",
|
||||
message,
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel
|
||||
);
|
||||
|
||||
if (reply == QMessageBox::Cancel) {
|
||||
return; // 完全取消更新
|
||||
}
|
||||
|
||||
// 如果用户点击 Yes,将选中的迁移项加入迁移集合
|
||||
if (reply == QMessageBox::Yes) {
|
||||
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_selectedPackages.contains(packageName)) {
|
||||
bool isMigration = index.data(Qt::UserRole + 10).toBool();
|
||||
if (isMigration) {
|
||||
m_migrationPackages.insert(packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果用户点击 No,继续更新其他应用,跳过未确认的迁移项
|
||||
}
|
||||
|
||||
for (int row = 0; row < m_model->rowCount(); ++row) {
|
||||
QModelIndex index = m_model->index(row, 0);
|
||||
QString packageName = index.data(Qt::UserRole + 1).toString();
|
||||
|
||||
// 检查应用是否被忽略
|
||||
bool isIgnored = index.data(Qt::UserRole + 8).toBool();
|
||||
if (isIgnored) {
|
||||
qDebug() << "跳过被忽略的应用:" << packageName;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// 只下载选中的应用
|
||||
if (m_selectedPackages.contains(packageName)) {
|
||||
// 检查是否为迁移项且用户未确认
|
||||
bool isMigration = index.data(Qt::UserRole + 10).toBool();
|
||||
if (isMigration && !m_migrationPackages.contains(packageName)) {
|
||||
qDebug() << "跳过未确认的迁移项:" << packageName;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_downloads.contains(packageName) && (m_downloads[packageName].isDownloading || m_downloads[packageName].isInstalled))
|
||||
continue;
|
||||
QString downloadUrl = index.data(Qt::UserRole + 7).toString();
|
||||
|
||||
@@ -58,6 +58,9 @@ private:
|
||||
// 复选框相关成员变量
|
||||
QSet<QString> m_selectedPackages;
|
||||
|
||||
// 迁移包集合(用户确认要迁移的包)
|
||||
QSet<QString> m_migrationPackages;
|
||||
|
||||
QQueue<QString> m_installQueue;
|
||||
bool m_isInstalling = false;
|
||||
QProcess *m_installProcess = nullptr;
|
||||
|
||||
@@ -36,6 +36,12 @@ QVariant AppListModel::data(const QModelIndex &index, int role) const
|
||||
return map.value("ignored");
|
||||
case Qt::UserRole + 9: // 包来源
|
||||
return map.value("source");
|
||||
case Qt::UserRole + 10: // 是否为迁移项
|
||||
return map.value("is_migration");
|
||||
case Qt::UserRole + 11: // 迁移源
|
||||
return map.value("migration_source");
|
||||
case Qt::UserRole + 12: // 迁移目标
|
||||
return map.value("migration_target");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
@@ -58,6 +64,9 @@ void AppListModel::setUpdateData(const QJsonArray &updateInfo)
|
||||
map["download_url"] = obj["download_url"].toString(); // 确保设置下载 URL
|
||||
map["ignored"] = obj["ignored"].toBool(); // 设置忽略状态
|
||||
map["source"] = obj["source"].toString(); // 设置包来源
|
||||
map["is_migration"] = obj["is_migration"].toBool(); // 设置是否为迁移项
|
||||
map["migration_source"] = obj["migration_source"].toString(); // 设置迁移源
|
||||
map["migration_target"] = obj["migration_target"].toString(); // 设置迁移目标
|
||||
m_data.append(map); // 添加到 QList<QVariantMap>
|
||||
|
||||
qDebug() << "设置到模型的包名:" << map["package"].toString() << "忽略状态:" << map["ignored"].toBool() << "来源:" << map["source"].toString();
|
||||
|
||||
@@ -603,7 +603,7 @@ QJsonArray aptssUpdater::mergeUpdateInfo()
|
||||
{
|
||||
QJsonArray aptssInfo = getUpdateInfoAsJson();
|
||||
QJsonArray apmInfo = getApmUpdateInfoAsJson();
|
||||
|
||||
|
||||
// 创建包名到更新信息的映射
|
||||
QHash<QString, QJsonObject> aptssMap;
|
||||
for (const QJsonValue &value : aptssInfo) {
|
||||
@@ -612,7 +612,7 @@ QJsonArray aptssUpdater::mergeUpdateInfo()
|
||||
obj["source"] = "aptss";
|
||||
aptssMap[packageName] = obj;
|
||||
}
|
||||
|
||||
|
||||
QHash<QString, QJsonObject> apmMap;
|
||||
for (const QJsonValue &value : apmInfo) {
|
||||
QJsonObject obj = value.toObject();
|
||||
@@ -620,44 +620,54 @@ QJsonArray aptssUpdater::mergeUpdateInfo()
|
||||
obj["source"] = "apm";
|
||||
apmMap[packageName] = obj;
|
||||
}
|
||||
|
||||
|
||||
QJsonArray mergedArray;
|
||||
|
||||
|
||||
// 处理只在aptss中存在的包
|
||||
for (const QString &packageName : aptssMap.keys()) {
|
||||
if (!apmMap.contains(packageName)) {
|
||||
mergedArray.append(aptssMap[packageName]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 处理只在apm中存在的包
|
||||
for (const QString &packageName : apmMap.keys()) {
|
||||
if (!aptssMap.contains(packageName)) {
|
||||
mergedArray.append(apmMap[packageName]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 处理在两者中都存在的包
|
||||
for (const QString &packageName : aptssMap.keys()) {
|
||||
if (apmMap.contains(packageName)) {
|
||||
QJsonObject aptssObj = aptssMap[packageName];
|
||||
QJsonObject apmObj = apmMap[packageName];
|
||||
|
||||
|
||||
// 比较版本
|
||||
QString aptssVersion = aptssObj["new_version"].toString();
|
||||
QString apmVersion = apmObj["new_version"].toString();
|
||||
|
||||
// 这里简化处理,实际应该使用版本比较函数
|
||||
|
||||
// 检查是否为迁移场景:APM版本更新,且当前包是通过aptss安装的
|
||||
// 通过检查aptss中是否有当前版本号来判断是否通过aptss安装
|
||||
if (apmVersion > aptssVersion) {
|
||||
// APM版本更高,使用APM版本
|
||||
mergedArray.append(apmObj);
|
||||
// 迁移场景:Spark -> APM
|
||||
QJsonObject migrationObj = apmObj;
|
||||
migrationObj["is_migration"] = true;
|
||||
migrationObj["migration_source"] = "aptss";
|
||||
migrationObj["migration_target"] = "apm";
|
||||
migrationObj["aptss_version"] = aptssVersion;
|
||||
mergedArray.append(migrationObj);
|
||||
|
||||
// 同时保留aptss的更新项(如果aptss也有更新)
|
||||
mergedArray.append(aptssObj);
|
||||
} else {
|
||||
// APTSS版本更高或相同,不展示该包
|
||||
qDebug() << "APTSS版本更高,不展示APM包:" << packageName;
|
||||
// 非迁移场景:同时展示两个来源的更新
|
||||
mergedArray.append(aptssObj);
|
||||
mergedArray.append(apmObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
qDebug()<<"合并后的更新信息:"<<mergedArray;
|
||||
return mergedArray;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user