diff --git a/CMakeLists.txt b/CMakeLists.txt index 35f2fe3db..0d3e74800 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd. +# SPDX-FileCopyrightText: 2025-2026 UnionTech Software Technology Co., Ltd. # # SPDX-License-Identifier: CC0-1.0 @@ -40,4 +40,5 @@ add_subdirectory("src/dde-update") add_subdirectory("src/dde-abrecovery") add_subdirectory("src/dcc-update-plugin") add_subdirectory("src/dock-update-plugin") +add_subdirectory("src/private-lastore-tray") diff --git a/src/common/dbus/updateassistant.cpp b/src/common/dbus/updateassistant.cpp new file mode 100644 index 000000000..d4c0cba93 --- /dev/null +++ b/src/common/dbus/updateassistant.cpp @@ -0,0 +1,63 @@ +// // SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later +#include "updateassistant.h" + +UpdateAssistant::UpdateAssistant(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) + , d_ptr(new UpdateAssistantPrivate) +{ + QDBusConnection::systemBus().connect("org.deepin.upgradedelivery", "/org/deepin/upgradedelivery", "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(onPropertyChanged(QString, QVariantMap, QStringList))); +} + +UpdateAssistant::~UpdateAssistant() +{ +} + +void UpdateAssistant::onPropertyChanged(const QString& interfaceName, + const QVariantMap& changedProperties, + const QStringList& invalidatedProperties) +{ + if (interfaceName != staticInterfaceName()) + return; + + if (changedProperties.contains("UploadLimitSpeed")) { + Q_EMIT UploadLimitSpeedChanged(uploadLimitSpeed()); + } + if (changedProperties.contains("DownloadLimitSpeed")) { + Q_EMIT DownloadLimitSpeedChanged(downloadLimitSpeed()); + } + + return; +} + +void UpdateAssistant::CallQueued(const QString &callName, const QList &args) +{ + if (d_ptr->m_waittingCalls.contains(callName)) { + d_ptr->m_waittingCalls[callName] = args; + return; + } + if (d_ptr->m_processingCalls.contains(callName)) { + d_ptr->m_waittingCalls.insert(callName, args); + } else { + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(asyncCallWithArgumentList(callName, args)); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &UpdateAssistant::onPendingCallFinished); + d_ptr->m_processingCalls.insert(callName, watcher); + } +} + +void UpdateAssistant::onPendingCallFinished(QDBusPendingCallWatcher *w) +{ + if (!w) + return; + w->deleteLater(); + const auto callName = d_ptr->m_processingCalls.key(w); + Q_ASSERT(!callName.isEmpty()); + if (callName.isEmpty()) + return; + d_ptr->m_processingCalls.remove(callName); + if (!d_ptr->m_waittingCalls.contains(callName)) + return; + const auto args = d_ptr->m_waittingCalls.take(callName); + CallQueued(callName, args); +} \ No newline at end of file diff --git a/src/common/dbus/updateassistant.h b/src/common/dbus/updateassistant.h new file mode 100644 index 000000000..f404af316 --- /dev/null +++ b/src/common/dbus/updateassistant.h @@ -0,0 +1,84 @@ +// // SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later +#ifndef UPDATEASSISTANT_H +#define UPDATEASSISTANT_H + +#include +#include +#include +#include +#include +#include +#include +#include + +class UpdateAssistantPrivate +{ +public: + UpdateAssistantPrivate() = default; + +public: + QMap m_processingCalls; + QMap> m_waittingCalls; +}; + +/* + * Proxy class for interface org.deepin.updateassistant + */ +class UpdateAssistant: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "org.deepin.upgradedelivery"; } + +public: + UpdateAssistant(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr); + + ~UpdateAssistant(); + + Q_PROPERTY(QString UploadLimitSpeed READ uploadLimitSpeed NOTIFY UploadLimitSpeedChanged) + inline QString uploadLimitSpeed() const + { return qvariant_cast(internalPropGet("UploadLimitSpeed")); } + + Q_PROPERTY(QString DownloadLimitSpeed READ downloadLimitSpeed NOTIFY DownloadLimitSpeedChanged) + inline QString downloadLimitSpeed() const + { return qvariant_cast(internalPropGet("DownloadLimitSpeed")); } + +public Q_SLOTS: // METHODS + + inline QDBusPendingReply SetUploadRateLimit(int speed) + { + QList argumentList; + argumentList << QVariant::fromValue(speed); + return asyncCallWithArgumentList(QStringLiteral("SetUploadRateLimit"), argumentList); + } + + inline QDBusPendingReply SetDownloadRateLimit(int speed) + { + QList argumentList; + argumentList << QVariant::fromValue(speed); + return asyncCallWithArgumentList(QStringLiteral("SetDownloadRateLimit"), argumentList); + } + +Q_SIGNALS: // SIGNALS + // begin property changed signals + void propertyChanged(const QString &propertyName, const QVariant &value); + void UploadLimitSpeedChanged(const QString & speed) const; + void DownloadLimitSpeedChanged(const QString & speed) const; + +public Q_SLOTS: + void CallQueued(const QString &callName, const QList &args); + +private Q_SLOTS: + void onPendingCallFinished(QDBusPendingCallWatcher *w); + void onPropertyChanged(const QString& interfaceName, + const QVariantMap& changedProperties, + const QStringList& invalidatedProperties); + +private: + UpdateAssistantPrivate *d_ptr; +}; + +#endif // UPDATEASSISTANT_H diff --git a/src/common/dbus/updatedbusproxy.cpp b/src/common/dbus/updatedbusproxy.cpp index e582a2271..436b6ba18 100644 --- a/src/common/dbus/updatedbusproxy.cpp +++ b/src/common/dbus/updatedbusproxy.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later #include "updatedbusproxy.h" @@ -207,6 +207,16 @@ QString UpdateDBusProxy::updateStatus() return qvariant_cast(m_managerInter->property("UpdateStatus")); } +bool UpdateDBusProxy::p2PUpdateEnable() +{ + return qvariant_cast(m_managerInter->property("P2PUpdateEnable")); +} + +bool UpdateDBusProxy::p2PUpdateSupport() +{ + return qvariant_cast(m_managerInter->property("P2PUpdateSupport")); +} + bool UpdateDBusProxy::immutableAutoRecovery() { return qvariant_cast(m_managerInter->property("ImmutableAutoRecovery")); @@ -387,6 +397,36 @@ QDBusPendingReply UpdateDBusProxy::GetUpdateLogs(int updateType) return m_managerInter->asyncCallWithArgumentList(QStringLiteral("GetUpdateLogs"), argumentList); } +QDBusPendingReply UpdateDBusProxy::SetUpgradeDeliveryEnable(bool enable) +{ + qCDebug(logCommon) << "Setting upgrade delivery enable :" << enable; + QList argumentList; + argumentList << QVariant::fromValue(enable); + return m_updateInter->asyncCallWithArgumentList(QStringLiteral("SetP2PUpdateEnable"), argumentList); +} + +QDBusPendingReply UpdateDBusProxy::SetUpgradeDeliveryDownloadSpeedLimit(const QString& downloadLimit) +{ + qCDebug(logCommon) << "Setting upgrade delivery download speed limit : " << downloadLimit; + QList argumentList; + argumentList << QVariant::fromValue(downloadLimit); + return m_updateInter->asyncCallWithArgumentList(QStringLiteral("SetDeliveryDownloadSpeedLimit"), argumentList); +} + +QDBusPendingReply UpdateDBusProxy::SetUpgradeDeliveryUploadSpeedLimit(const QString& uploadLimit) +{ + qCDebug(logCommon) << "Setting upgrade delivery upload speed limit : " << uploadLimit; + QList argumentList; + argumentList << QVariant::fromValue(uploadLimit); + return m_updateInter->asyncCallWithArgumentList(QStringLiteral("SetDeliveryUploadSpeedLimit"), argumentList); +} + +QDBusPendingReply UpdateDBusProxy::ClearUpgradeDeliveryCache() +{ + qCDebug(logCommon) << "Clearing upgrade delivery cache"; + return m_updateInter->asyncCall(QStringLiteral("CleanTransmissionFiles")); +} + QDBusPendingReply UpdateDBusProxy::SetIdleDownloadConfig(const QString& config) { qCDebug(logCommon) << "Setting idle download config:" << config; @@ -428,6 +468,14 @@ QDBusPendingReply UpdateDBusProxy::GetUpdateDetails(int fd, bool realtime) return m_managerInter->asyncCallWithArgumentList(QStringLiteral("GetUpdateDetails"), argumentList); } +QDBusPendingReply UpdateDBusProxy::SetShutdownForceUpdate(bool isShutdownUpdate) +{ + qCDebug(logCommon) << "Setting shutdown force update , isShutdownUpdate:" << isShutdownUpdate; + QList argumentList; + argumentList << QVariant::fromValue(isShutdownUpdate); + return m_managerInter->asyncCallWithArgumentList(QStringLiteral("SetShutdownForceUpdate"), argumentList); +} + bool UpdateDBusProxy::onBattery() { return qvariant_cast(m_powerInter->property("OnBattery")); diff --git a/src/common/dbus/updatedbusproxy.h b/src/common/dbus/updatedbusproxy.h index cce6ae314..32263948d 100644 --- a/src/common/dbus/updatedbusproxy.h +++ b/src/common/dbus/updatedbusproxy.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2018 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later #ifndef UPDATEDBUSPROXY_H @@ -70,6 +70,12 @@ class UpdateDBusProxy : public QObject Q_PROPERTY(bool ImmutableAutoRecovery READ immutableAutoRecovery NOTIFY ImmutableAutoRecoveryChanged) bool immutableAutoRecovery(); + Q_PROPERTY(bool P2PUpdateEnable READ p2PUpdateEnable NOTIFY P2PUpdateEnableChanged) + bool p2PUpdateEnable(); + + Q_PROPERTY(bool P2PUpdateSupport READ p2PUpdateSupport NOTIFY P2PUpdateSupportChanged) + bool p2PUpdateSupport(); + QString hardwareId(); quint64 checkUpdateMode(); @@ -103,12 +109,16 @@ class UpdateDBusProxy : public QObject QDBusPendingReply SetDownloadSpeedLimit(const QString &config); QDBusPendingReply QueryAllSizeWithSource(int updateType); QDBusPendingReply GetUpdateLogs(int updateType); + QDBusPendingReply SetUpgradeDeliveryEnable(bool enable); + QDBusPendingReply SetUpgradeDeliveryDownloadSpeedLimit(const QString& downloadLimit); + QDBusPendingReply SetUpgradeDeliveryUploadSpeedLimit(const QString& uploadLimit); + QDBusPendingReply ClearUpgradeDeliveryCache(); QDBusPendingReply SetIdleDownloadConfig(const QString &config); QDBusPendingReply PrepareDistUpgradePartly(int updateMode); QDBusPendingReply fixError(const QString &errorType); QDBusPendingCall CheckUpgrade(int checkMode, int checkOrder); QDBusPendingReply GetUpdateDetails(int fd, bool realtime); - + QDBusPendingReply SetShutdownForceUpdate(bool isShutdownUpdate); // Power bool onBattery(); @@ -137,6 +147,7 @@ class UpdateDBusProxy : public QObject void AutoInstallUpdatesChanged(bool value) const; void AutoInstallUpdateTypeChanged(qulonglong value) const; void MirrorSourceChanged(const QString &value) const; + void UpgradeDeliveryEnabledChanged(bool value) const; void AutoCheckUpdatesChanged(bool value) const; void ClassifiedUpdatablePackagesChanged(LastoreUpdatePackagesInfo value) const; @@ -146,6 +157,8 @@ class UpdateDBusProxy : public QObject void UpdateModeChanged(qulonglong value) const; void UpdateStatusChanged(QString value) const; void ImmutableAutoRecoveryChanged(bool value) const; + void P2PUpdateEnableChanged(bool value) const; + void P2PUpdateSupportChanged(bool value) const; void managerInterServiceValidChanged(bool value) const; // Power diff --git a/src/dcc-update-plugin/operation/updatedatastructs.h b/src/dcc-update-plugin/operation/updatedatastructs.h index abd00dcae..d82ad99c5 100644 --- a/src/dcc-update-plugin/operation/updatedatastructs.h +++ b/src/dcc-update-plugin/operation/updatedatastructs.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2011 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2011-2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -65,12 +65,14 @@ struct IdleDownloadConfig { struct DownloadSpeedLimitConfig { bool downloadSpeedLimitEnabled = false; QString limitSpeed = "10240"; + bool isOnlineSpeedLimit = false; QString toJson() const { QJsonObject obj; obj.insert("DownloadSpeedLimitEnabled", downloadSpeedLimitEnabled); obj.insert("LimitSpeed", limitSpeed); + obj.insert("IsOnlineSpeedLimit", isOnlineSpeedLimit); QJsonDocument doc; doc.setObject(obj); return doc.toJson(); @@ -89,11 +91,130 @@ struct DownloadSpeedLimitConfig { QJsonObject obj = doc.object(); config.downloadSpeedLimitEnabled = obj.contains("DownloadSpeedLimitEnabled") ? obj.value("DownloadSpeedLimitEnabled").toBool() : false; config.limitSpeed = obj.contains("LimitSpeed") ? obj.value("LimitSpeed").toString() : "10240"; + config.isOnlineSpeedLimit = obj.contains("IsOnlineSpeedLimit") ? obj.value("IsOnlineSpeedLimit").toBool() : false; return config; } }; +/** + * @brief 通过lastore修改upgrade服务限速配置的数据结构 + */ +struct LastoreUpgradeSpeedLimitConfig { + bool speedLimitEnabled = false; + QString limitSpeed = "10240"; + bool isOnlineSpeedLimit = false; + + QString toJson() const + { + QJsonObject obj; + obj.insert("SpeedLimitEnabled", speedLimitEnabled); + obj.insert("LimitSpeed", limitSpeed); + obj.insert("IsOnlineSpeedLimit", isOnlineSpeedLimit); + QJsonDocument doc; + doc.setObject(obj); + return doc.toJson(); + } + + static LastoreUpgradeSpeedLimitConfig fromJson(const QByteArray& configStr) + { + LastoreUpgradeSpeedLimitConfig config; + QJsonParseError jsonParseError; + const QJsonDocument doc = QJsonDocument::fromJson(configStr, &jsonParseError); + if (jsonParseError.error != QJsonParseError::NoError || doc.isEmpty()) { + qWarning() << "Parse download speed limit config failed: " << jsonParseError.errorString(); + return config; + } + + QJsonObject obj = doc.object(); + config.speedLimitEnabled = obj.contains("SpeedLimitEnabled") ? obj.value("SpeedLimitEnabled").toBool() : false; + config.limitSpeed = obj.contains("LimitSpeed") ? obj.value("LimitSpeed").toString() : "10240"; + config.isOnlineSpeedLimit = obj.contains("IsOnlineSpeedLimit") ? obj.value("IsOnlineSpeedLimit").toBool() : false; + + return config; + } +}; + +/** + * @brief 传递优化upgrade服务上传下载限速配置 + */ +struct UpgradeSpeedLimitConfig { + int currentRate = 102400; + int limitRate = 102400; + int limitType = 0; // 限速类型 + int rateType = 0; // 速率类型 + int speed = 10240; // 速度值 + QDateTime startTime; // 开始时间 + QDateTime endTime; // 结束时间 + + bool ifInOnlineLimit() const { + if (limitType != 3) { + return false; + } + + if (!startTime.isValid() || !endTime.isValid()) { + return false; + } + + QDateTime currentTime = QDateTime::currentDateTime(); + return currentTime >= startTime && currentTime <= endTime; + } + + bool shouldLimitRate() const { + if (ifInOnlineLimit()) { + return true; + } + return limitType == 1; + } + + QString toJson() const + { + QJsonObject obj; + obj.insert("CurrentRate", currentRate); + obj.insert("LimitRate", limitRate); + obj.insert("LimitType", limitType); + obj.insert("RateType", rateType); + obj.insert("Speed", speed); + obj.insert("StartTime", startTime.toString(Qt::ISODate)); + obj.insert("EndTime", endTime.toString(Qt::ISODate)); + + QJsonDocument doc; + doc.setObject(obj); + return doc.toJson(); + } + + static UpgradeSpeedLimitConfig fromJson(const QByteArray& configStr) + { + UpgradeSpeedLimitConfig config; + QJsonParseError jsonParseError; + const QJsonDocument doc = QJsonDocument::fromJson(configStr, &jsonParseError); + + if (jsonParseError.error != QJsonParseError::NoError || doc.isEmpty()) { + // qCWarning(logDccUpdatePlugin) << "Parse upgrade speed limit config failed: " << jsonParseError.errorString(); + return config; + } + + QJsonObject obj = doc.object(); + config.currentRate = obj.contains("CurrentRate") ? obj.value("CurrentRate").toInt() : 10240; + config.limitRate = obj.contains("LimitRate") ? obj.value("LimitRate").toInt() : 10240; + config.limitType = obj.contains("LimitType") ? obj.value("LimitType").toInt() : 0; + config.rateType = obj.contains("RateType") ? obj.value("RateType").toInt() : 0; + config.speed = obj.contains("Speed") ? obj.value("Speed").toInt() : 10240; + + if (obj.contains("StartTime") && obj.value("StartTime").isString()) { + QString startTimeStr = obj.value("StartTime").toString(); + config.startTime = QDateTime::fromString(startTimeStr, Qt::ISODate); + } + + if (obj.contains("EndTime") && obj.value("EndTime").isString()) { + QString endTimeStr = obj.value("EndTime").toString(); + config.endTime = QDateTime::fromString(endTimeStr, Qt::ISODate); + } + + return config; + } +}; + struct LastoreDaemonUpdateStatus { UpdatesStatus backupStatus = UpdatesStatus::Default; UpdateErrorType backupError = UpdateErrorType::NoError; diff --git a/src/dcc-update-plugin/operation/updatelistmodel.cpp b/src/dcc-update-plugin/operation/updatelistmodel.cpp index b5fbdc7a1..bd040b991 100644 --- a/src/dcc-update-plugin/operation/updatelistmodel.cpp +++ b/src/dcc-update-plugin/operation/updatelistmodel.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd. // SPDX-License-Identifier: GPL-3.0-or-later #include "updatelistmodel.h" #include diff --git a/src/dcc-update-plugin/operation/updatelistmodel.h b/src/dcc-update-plugin/operation/updatelistmodel.h index 1d26b8b37..51d3c9f53 100644 --- a/src/dcc-update-plugin/operation/updatelistmodel.h +++ b/src/dcc-update-plugin/operation/updatelistmodel.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd. // SPDX-License-Identifier: GPL-3.0-or-later #ifndef UPDATELISTMODEL_H #define UPDATELISTMODEL_H diff --git a/src/dcc-update-plugin/operation/updatemodel.cpp b/src/dcc-update-plugin/operation/updatemodel.cpp index b7a7dcb5e..8a1a538b8 100644 --- a/src/dcc-update-plugin/operation/updatemodel.cpp +++ b/src/dcc-update-plugin/operation/updatemodel.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2011 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2011 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -72,6 +72,7 @@ UpdateModel::UpdateModel(QObject* parent) , m_backupFailedTips("") , m_installLog("") , m_isUpdatable(false) + , m_isPrivateUpdate(false) , m_securityUpdateEnabled(false) , m_thirdPartyUpdateEnabled(false) , m_updateMode(UpdateType::Invalid) @@ -969,6 +970,17 @@ void UpdateModel::setIsUpdatable(bool isUpdatable) Q_EMIT isUpdatableChanged(isUpdatable); } +void UpdateModel::setIsPrivateUpdate(bool isPrivateUpdate) +{ + qCDebug(logDccUpdatePlugin) << "Setting is private update: " << isPrivateUpdate; + if (m_isPrivateUpdate == isPrivateUpdate) { + return; + } + + m_isPrivateUpdate = isPrivateUpdate; + Q_EMIT isPrivateUpdateChanged(isPrivateUpdate); +} + UpdatesStatus UpdateModel::updateStatus(ControlPanelType type) const { qCDebug(logDccUpdatePlugin) << "Getting update status for control panel type:" << type; @@ -1101,6 +1113,11 @@ bool UpdateModel::downloadSpeedLimitEnabled() const return DownloadSpeedLimitConfig::fromJson(m_speedLimitConfig).downloadSpeedLimitEnabled; } +bool UpdateModel::downloadIsOnlineSpeedLimit() const +{ + return DownloadSpeedLimitConfig::fromJson(m_speedLimitConfig).isOnlineSpeedLimit; +} + QString UpdateModel::downloadSpeedLimitSize() const { return DownloadSpeedLimitConfig::fromJson(m_speedLimitConfig).limitSpeed; @@ -1121,6 +1138,95 @@ void UpdateModel::setSpeedLimitConfig(const QByteArray& config) Q_EMIT downloadSpeedLimitConfigChanged(); } +void UpdateModel::setUpgradeDownloadSpeedLimitConfig(const QByteArray& config) +{ + qCInfo(logDccUpdatePlugin) << "setUpgradeDownloadSpeedLimitConfig" << config; + // if (m_upgradeDownloadSpeedLimitConfig == config) + // return; + + m_upgradeDownloadSpeedLimitConfig = config; + Q_EMIT upgradeDownloadSpeedLimitConfigChanged(); +} + +QString UpdateModel::upgradeDownloadSpeedCurrentRate() const +{ + qCInfo(logDccUpdatePlugin) << "upgradeDownloadSpeedCurrentRate " << UpgradeSpeedLimitConfig::fromJson(m_upgradeDownloadSpeedLimitConfig).currentRate; + return QString::number(UpgradeSpeedLimitConfig::fromJson(m_upgradeDownloadSpeedLimitConfig).currentRate / 1024); +} + +QString UpdateModel::upgradeDownloadSpeedLimitRate() const +{ + qCInfo(logDccUpdatePlugin) << "upgradeDownloadSpeedCurrentRate " << UpgradeSpeedLimitConfig::fromJson(m_upgradeDownloadSpeedLimitConfig).currentRate; + return QString::number(UpgradeSpeedLimitConfig::fromJson(m_upgradeDownloadSpeedLimitConfig).limitRate / 1024); +} + +bool UpdateModel::upgradeDownloadSpeedEnable() const +{ + qCInfo(logDccUpdatePlugin) << "xiongbo111 upgradeDownloadSpeedCurrentRate " << m_upgradeDownloadSpeedLimitConfig; + return UpgradeSpeedLimitConfig::fromJson(m_upgradeDownloadSpeedLimitConfig).shouldLimitRate(); +} + +bool UpdateModel::upgradeDownloadSpeedIsOnline() const +{ + return UpgradeSpeedLimitConfig::fromJson(m_upgradeDownloadSpeedLimitConfig).ifInOnlineLimit(); +} + +UpgradeSpeedLimitConfig UpdateModel::upgradeDownloadSpeedLimitConfig() const +{ + return UpgradeSpeedLimitConfig::fromJson(m_upgradeDownloadSpeedLimitConfig); +} + +void UpdateModel::setUpgradeUploadSpeedLimitConfig(const QByteArray& config) +{ + m_upgradeUploadSpeedLimitConfig = config; + Q_EMIT upgradeUploadSpeedLimitConfigChanged(); +} + +QString UpdateModel::upgradeUploadSpeedCurrentRate() const +{ + return QString::number(UpgradeSpeedLimitConfig::fromJson(m_upgradeUploadSpeedLimitConfig).currentRate / 1024); +} + +QString UpdateModel::upgradeUploadSpeedLimitRate() const +{ + return QString::number(UpgradeSpeedLimitConfig::fromJson(m_upgradeUploadSpeedLimitConfig).limitRate / 1024); +} + +bool UpdateModel::upgradeUploadSpeedEnable() const +{ + return UpgradeSpeedLimitConfig::fromJson(m_upgradeUploadSpeedLimitConfig).shouldLimitRate(); +} + +bool UpdateModel::upgradeUploadSpeedIsOnline() const +{ + return UpgradeSpeedLimitConfig::fromJson(m_upgradeUploadSpeedLimitConfig).ifInOnlineLimit(); +} + +UpgradeSpeedLimitConfig UpdateModel::upgradeUploadSpeedLimitConfig() const +{ + return UpgradeSpeedLimitConfig::fromJson(m_upgradeUploadSpeedLimitConfig); +} + +bool UpdateModel::upgradeDeliveryEnable() const +{ + return m_isUpgradeDeliveryEnable; +} + +void UpdateModel::setUpgradeDeliveryEnable(bool enable) +{ + m_isUpgradeDeliveryEnable = enable; + Q_EMIT upgradeDeliveryEnableChanged(); +} + +void UpdateModel::refreshUpgradeDeliveryEnable(bool enable) +{ + m_isUpgradeDeliveryEnable = enable; + if (enable) { + Q_EMIT upgradeDownloadSpeedLimitConfigChanged(); + Q_EMIT upgradeUploadSpeedLimitConfigChanged(); + } +} + void UpdateModel::setAutoDownloadUpdates(bool autoDownloadUpdates) { qCDebug(logDccUpdatePlugin) << "Set auto download updates:" << autoDownloadUpdates; diff --git a/src/dcc-update-plugin/operation/updatemodel.h b/src/dcc-update-plugin/operation/updatemodel.h index 6e8bede2c..52c9997c7 100644 --- a/src/dcc-update-plugin/operation/updatemodel.h +++ b/src/dcc-update-plugin/operation/updatemodel.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2011 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2011 - 2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -29,6 +29,7 @@ class UpdateModel : public QObject Q_PROPERTY(bool batterIsOK READ batterIsOK NOTIFY batterIsOKChanged FINAL) Q_PROPERTY(int lastStatus READ lastStatus NOTIFY lastStatusChanged FINAL) Q_PROPERTY(bool isUpdatable READ isUpdatable NOTIFY isUpdatableChanged FINAL) + Q_PROPERTY(bool isPrivateUpdate READ isPrivateUpdate NOTIFY isPrivateUpdateChanged FINAL) // ---------------检查更新页面数据--------------- Q_PROPERTY(bool showCheckUpdate READ showCheckUpdate NOTIFY showCheckUpdateChanged FINAL) @@ -72,6 +73,7 @@ class UpdateModel : public QObject Q_PROPERTY(bool thirdPartyUpdate READ thirdPartyUpdate NOTIFY updateModeChanged FINAL) Q_PROPERTY(bool updateModeDisabled READ updateModeDisabled NOTIFY updateModeChanged FINAL) Q_PROPERTY(bool downloadSpeedLimitEnabled READ downloadSpeedLimitEnabled NOTIFY downloadSpeedLimitConfigChanged FINAL) + Q_PROPERTY(bool downloadIsOnlineSpeedLimit READ downloadIsOnlineSpeedLimit NOTIFY downloadIsOnlineSpeedLimitChanged FINAL) Q_PROPERTY(QString downloadSpeedLimitSize READ downloadSpeedLimitSize NOTIFY downloadSpeedLimitConfigChanged FINAL) Q_PROPERTY(bool autoDownloadUpdates READ autoDownloadUpdates WRITE setAutoDownloadUpdates NOTIFY autoDownloadUpdatesChanged FINAL) Q_PROPERTY(bool idleDownloadEnabled READ idleDownloadEnabled NOTIFY idleDownloadConfigChanged FINAL) @@ -81,7 +83,13 @@ class UpdateModel : public QObject Q_PROPERTY(bool autoCleanCache READ autoCleanCache WRITE setAutoCleanCache NOTIFY autoCleanCacheChanged FINAL) Q_PROPERTY(bool smartMirrorSwitch READ smartMirrorSwitch WRITE setSmartMirrorSwitch NOTIFY smartMirrorSwitchChanged FINAL) Q_PROPERTY(TestingChannelStatus testingChannelStatus READ testingChannelStatus WRITE setTestingChannelStatus NOTIFY testingChannelStatusChanged FINAL) - + Q_PROPERTY(QString upgradeDownloadSpeedCurrentRate READ upgradeDownloadSpeedCurrentRate NOTIFY upgradeDownloadSpeedLimitConfigChanged FINAL) + Q_PROPERTY(QString upgradeDownloadSpeedLimitRate READ upgradeDownloadSpeedLimitRate NOTIFY upgradeDownloadSpeedLimitConfigChanged FINAL) + Q_PROPERTY(bool upgradeDownloadSpeedEnable READ upgradeDownloadSpeedEnable NOTIFY upgradeDownloadSpeedLimitConfigChanged FINAL) + Q_PROPERTY(QString upgradeUploadSpeedCurrentRate READ upgradeUploadSpeedCurrentRate NOTIFY upgradeUploadSpeedLimitConfigChanged FINAL) + Q_PROPERTY(QString upgradeUploadSpeedLimitRate READ upgradeUploadSpeedLimitRate NOTIFY upgradeUploadSpeedLimitConfigChanged FINAL) + Q_PROPERTY(bool upgradeUploadSpeedEnable READ upgradeUploadSpeedEnable NOTIFY upgradeUploadSpeedLimitConfigChanged FINAL) + Q_PROPERTY(bool upgradeDeliveryEnable READ upgradeDeliveryEnable NOTIFY upgradeDeliveryEnableChanged FINAL) Q_PROPERTY(UpdateHistoryModel *historyModel READ historyModel NOTIFY historyModelChanged FINAL) @@ -234,6 +242,9 @@ class UpdateModel : public QObject bool isUpdatable() const { return m_isUpdatable; } void setIsUpdatable(bool isUpdatable); + bool isPrivateUpdate() const { return m_isPrivateUpdate; } + void setIsPrivateUpdate(bool isPrivateUpdate); + UpdatesStatus updateStatus(ControlPanelType type) const; UpdatesStatus updateStatus(UpdateType type) const; QList updateTypesList(ControlPanelType type) const; @@ -258,10 +269,28 @@ class UpdateModel : public QObject void setUpdateItemEnabled(); bool downloadSpeedLimitEnabled() const; + bool downloadIsOnlineSpeedLimit() const; QString downloadSpeedLimitSize() const; DownloadSpeedLimitConfig speedLimitConfig() const; void setSpeedLimitConfig(const QByteArray &config); + void setUpgradeDownloadSpeedLimitConfig(const QByteArray& config); + QString upgradeDownloadSpeedCurrentRate() const; + QString upgradeDownloadSpeedLimitRate() const; + bool upgradeDownloadSpeedEnable() const; + bool upgradeDownloadSpeedIsOnline() const; + UpgradeSpeedLimitConfig upgradeDownloadSpeedLimitConfig() const; + void setUpgradeUploadSpeedLimitConfig(const QByteArray& config); + QString upgradeUploadSpeedCurrentRate() const; + QString upgradeUploadSpeedLimitRate() const; + bool upgradeUploadSpeedEnable() const; + bool upgradeUploadSpeedIsOnline() const; + UpgradeSpeedLimitConfig upgradeUploadSpeedLimitConfig() const; + bool upgradeDeliveryEnable() const; + + void setUpgradeDeliveryEnable(bool enable); + void refreshUpgradeDeliveryEnable(bool enable); + bool autoDownloadUpdates() const { return m_autoDownloadUpdates; } void setAutoDownloadUpdates(bool autoDownloadUpdates); @@ -369,6 +398,7 @@ public slots: void updateInfoChanged(UpdateType); void isUpdatableChanged(const bool isUpdatablePackages); + void isPrivateUpdateChanged(const bool isPrivateUpdate); void updateStatusChanged(ControlPanelType, UpdatesStatus); void controlTypeChanged(); void lastErrorChanged(UpdatesStatus, UpdateErrorType); @@ -378,7 +408,11 @@ public slots: void securityUpdateEnabledChanged(bool enable); void thirdPartyUpdateEnabledChanged(bool enable); void updateModeChanged(quint64 updateMode); + void upgradeDeliveryEnableChanged(); void downloadSpeedLimitConfigChanged(); + void downloadIsOnlineSpeedLimitChanged(); + void upgradeDownloadSpeedLimitConfigChanged(); + void upgradeUploadSpeedLimitConfigChanged(); void autoDownloadUpdatesChanged(bool autoDownloadUpdates); void idleDownloadConfigChanged(); void updateNotifyChanged(const bool notify); @@ -443,6 +477,7 @@ public slots: QByteArray m_updateStatus; // lastore daemon发上来的原始json数据 bool m_isUpdatable; // 是否有包可更新 + bool m_isPrivateUpdate; //当前是否接入私有化更新 QMap>> m_controlStatusMap; QMap m_waitingStatusMap; @@ -451,6 +486,9 @@ public slots: bool m_thirdPartyUpdateEnabled; quint64 m_updateMode; QByteArray m_speedLimitConfig; + bool m_isUpgradeDeliveryEnable; + QByteArray m_upgradeDownloadSpeedLimitConfig; + QByteArray m_upgradeUploadSpeedLimitConfig; bool m_autoDownloadUpdates; IdleDownloadConfig m_idleDownloadConfig; bool m_updateNotify; diff --git a/src/dcc-update-plugin/operation/updatework.cpp b/src/dcc-update-plugin/operation/updatework.cpp index 2a8c04feb..c67fa3540 100644 --- a/src/dcc-update-plugin/operation/updatework.cpp +++ b/src/dcc-update-plugin/operation/updatework.cpp @@ -6,6 +6,7 @@ #include "common/common/logwatcherhelper.h" #include "utils.h" #include "dconfigwatcher.h" +#include "common/common/dconfig_helper.h" #include "updateloghelper.h" #include @@ -28,7 +29,6 @@ #include Q_DECLARE_LOGGING_CATEGORY(logDccUpdatePlugin) - using namespace DCC_NAMESPACE; const QString TestingChannel = "testing Channel"; @@ -128,6 +128,7 @@ UpdateWorker::UpdateWorker(UpdateModel* model, QObject* parent) , m_backupJob(nullptr) , m_installPackageJob(nullptr) , m_removePackageJob(nullptr) + , m_updateAssistant(nullptr) { qCDebug(logDccUpdatePlugin) << "Initializing UpdateWorker"; qRegisterMetaType("UpdatesStatus"); @@ -208,6 +209,15 @@ void UpdateWorker::initConnect() // m_model->setP2PUpdateEnabled(DConfigWatcher::instance()->getValue(DConfigWatcher::update, configName).toBool()); } }); + + m_updateAssistant = new UpdateAssistant("org.deepin.upgradedelivery", "/org/deepin/upgradedelivery", QDBusConnection::systemBus(), this); + connect(m_updateInter, &UpdateDBusProxy::AutoDownloadUpdatesChanged, m_model, &UpdateModel::setAutoDownloadUpdates); + connect(m_updateInter, &UpdateDBusProxy::MirrorSourceChanged, m_model, &UpdateModel::setDefaultMirror); + QDBusConnection::systemBus().connect("org.deepin.upgradedelivery", + "/org/deepin/upgradedelivery", + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + m_model, SLOT(onUpdatePropertiesChanged(QString, QVariantMap, QStringList))); } void UpdateWorker::activate() @@ -220,7 +230,9 @@ void UpdateWorker::activate() updateSystemVersion(); refreshLastTimeAndCheckCircle(); initTestingChannel(); + refreshUpgradeDeliveryInfo(); + m_model->setIsPrivateUpdate(DConfigHelper::instance()->getConfig("org.deepin.dde.lastore", "org.deepin.dde.lastore", "","intranet-update", false).toString() == "true"); m_model->setUpdateMode(m_updateInter->updateMode()); m_model->setCheckUpdateMode(m_updateInter->checkUpdateMode()); m_model->setSecurityUpdateEnabled(DConfigWatcher::instance()->getValue(DConfigWatcher::update, "updateSafety").toString() != "Hidden"); @@ -494,6 +506,12 @@ void UpdateWorker::doCheckUpdates() }); } +void UpdateWorker::reCheckWithUi() +{ + m_model->setShowCheckUpdate(true); + doCheckUpdates(); +} + void UpdateWorker::setCheckUpdatesJob(const QString& jobPath) { qCInfo(logDccUpdatePlugin) << "Set check updates job"; @@ -787,6 +805,12 @@ void UpdateWorker::modalUpgrade(bool rebootAfterUpgrade) } } +void UpdateWorker::setShutdownAndUpgrade(bool isShutdownUpdate) +{ + qCInfo(logDccUpdatePlugin) << "request shutdown upgrade, upgrade after shutdown:" << isShutdownUpdate; + m_updateInter->SetShutdownForceUpdate(isShutdownUpdate); +} + void UpdateWorker::setBackupJob(const QString& jobPath) { qCInfo(logDccUpdatePlugin) << "Create backup upgrade job, path:" << jobPath; @@ -891,6 +915,7 @@ void UpdateWorker::setDownloadSpeedLimitEnabled(bool enable) qCDebug(logDccUpdatePlugin) << "Set download speed limit enabled:" << enable; auto config = m_model->speedLimitConfig(); config.downloadSpeedLimitEnabled = enable; + config.isOnlineSpeedLimit = false; // dbus返回需要1s,导致界面更新慢,这里直接先更新model m_model->setSpeedLimitConfig(config.toJson().toUtf8()); setDownloadSpeedLimitConfig(config.toJson()); @@ -901,6 +926,7 @@ void UpdateWorker::setDownloadSpeedLimitSize(const QString& size) qCDebug(logDccUpdatePlugin) << "set download speed limit size" << size; auto config = m_model->speedLimitConfig(); config.limitSpeed = size; + config.isOnlineSpeedLimit = false; setDownloadSpeedLimitConfig(config.toJson()); } @@ -1257,6 +1283,14 @@ void UpdateWorker::initTestingChannel() }); } +void UpdateWorker::refreshUpgradeDeliveryInfo() +{ + qCDebug(logDccUpdatePlugin) << "Refresh upgrade delivery info"; + m_model->setUpgradeDownloadSpeedLimitConfig(m_updateAssistant->downloadLimitSpeed().toUtf8()); + m_model->setUpgradeUploadSpeedLimitConfig(m_updateAssistant->uploadLimitSpeed().toUtf8()); + m_model->setUpgradeDeliveryEnable(m_updateInter->p2pUpdateEnable()); +} + void UpdateWorker::checkTestingChannelStatus() { // Leave page @@ -1692,3 +1726,94 @@ void UpdateWorker::onRemovePackageStatusChanged(const QString& value) } } +//更新传递总开关 +void UpdateWorker::setUpgradeDeliveryEnabled(bool enabled) +{ + if (enabled == m_model->upgradeDeliveryEnable()) { + return; + } + + qCDebug(logDccUpdatePlugin) << "Set update assistant service, enabled: " << enabled; + auto func_set_success = [=](bool enabled) { + qCDebug(logDccUpdatePlugin) << "Set update assistant service succeed, enabled " << enabled; + if (m_updateAssistant && m_model) { + m_model->setUpgradeDownloadSpeedLimitConfig(m_updateAssistant->downloadLimitSpeed().toUtf8()); + m_model->setUpgradeUploadSpeedLimitConfig(m_updateAssistant->uploadLimitSpeed().toUtf8()); + m_model->setUpgradeDeliveryEnable(enabled); + } + }; + auto watcher = new QDBusPendingCallWatcher(m_updateInter->SetUpgradeDeliveryEnable(enabled), this); + connect(watcher, &QDBusPendingCallWatcher::finished, [this, watcher, enabled, func_set_success] { + watcher->deleteLater(); + if (watcher->isError()) { + qCWarning(logDccUpdatePlugin) << "Set update assistant service failed, enabled " << enabled << " error: " << watcher->error().message(); + m_model->setUpgradeDeliveryEnable(!enabled); + return; + } + func_set_success(enabled); + }); +} + +//设置更新传递下载限速 +void UpdateWorker::setUpgradeDeliveryDownloadLimitSpeed(const QString& speed, bool enable) +{ + LastoreUpgradeSpeedLimitConfig downloadSpeedLimitConfig; + downloadSpeedLimitConfig.isOnlineSpeedLimit = false; + downloadSpeedLimitConfig.speedLimitEnabled = enable; + downloadSpeedLimitConfig.limitSpeed = speed; + qCInfo(logDccUpdatePlugin) << "Set upgrade download speed limit: " << downloadSpeedLimitConfig.toJson(); + auto watcher = new QDBusPendingCallWatcher(m_updateInter->SetUpgradeDeliveryDownloadSpeedLimit(downloadSpeedLimitConfig.toJson()), this); + connect(watcher, &QDBusPendingCallWatcher::finished, [watcher, this] { + watcher->deleteLater(); + if (watcher->isError()) { + qCWarning(logDccUpdatePlugin) << "Set upgrade download speed limit config error: " << watcher->error().message(); + getUpgradeDeliveryDownloadLimitSpeed(); + } + }); +} + +//设置更新传递上传限速 +void UpdateWorker::setUpgradeDeliveryUploadLimitSpeed(const QString& speed, bool enable) +{ + LastoreUpgradeSpeedLimitConfig uploadSpeedLimitConfig; + uploadSpeedLimitConfig.isOnlineSpeedLimit = false; + uploadSpeedLimitConfig.speedLimitEnabled = enable; + uploadSpeedLimitConfig.limitSpeed = speed; + qCInfo(logDccUpdatePlugin) << "Set upgrade upload speed limit: " << uploadSpeedLimitConfig.toJson(); + auto watcher = new QDBusPendingCallWatcher(m_updateInter->SetUpgradeDeliveryUploadSpeedLimit(uploadSpeedLimitConfig.toJson()), this); + connect(watcher, &QDBusPendingCallWatcher::finished, [watcher, this] { + watcher->deleteLater(); + if (watcher->isError()) { + qCWarning(logDccUpdatePlugin) << "Set upgrade upload speed limit config error: " << watcher->error().message(); + getUpgradeDeliveryUploadLimitSpeed(); + } + }); +} + +void UpdateWorker::getUpgradeDeliveryDownloadLimitSpeed() +{ + if (m_updateAssistant && m_model) { + m_model->setUpgradeDownloadSpeedLimitConfig(m_updateAssistant->downloadLimitSpeed().toUtf8()); + } +} + +void UpdateWorker::getUpgradeDeliveryUploadLimitSpeed() +{ + if (m_updateAssistant && m_model) { + m_model->setUpgradeUploadSpeedLimitConfig(m_updateAssistant->uploadLimitSpeed().toUtf8()); + } +} + +void UpdateWorker::cleanUpgradeDeliveryCache() +{ + qCDebug(logDccUpdatePlugin) << "Clean update assistant cache succeed"; + auto watcher = new QDBusPendingCallWatcher(m_updateInter->ClearUpgradeDeliveryCache(), this); + connect(watcher, &QDBusPendingCallWatcher::finished, [this, watcher] { + watcher->deleteLater(); + if (watcher->isError()) { + qCWarning(logDccUpdatePlugin) << "Clean update assistant cache failed"; + return; + } + }); +} + diff --git a/src/dcc-update-plugin/operation/updatework.h b/src/dcc-update-plugin/operation/updatework.h index 571de400e..35c623ee0 100644 --- a/src/dcc-update-plugin/operation/updatework.h +++ b/src/dcc-update-plugin/operation/updatework.h @@ -10,6 +10,7 @@ #include "common/common/logwatcherhelper.h" #include "common/dbus/updatedbusproxy.h" #include "common/dbus/updatejobdbusproxy.h" +#include "common/dbus/updateassistant.h" #include #include @@ -37,6 +38,7 @@ class UpdateWorker : public QObject // 检查更新 Q_INVOKABLE void checkNeedDoUpdates(); Q_INVOKABLE void doCheckUpdates(); + Q_INVOKABLE void reCheckWithUi(); void setCheckUpdatesJob(const QString& jobPath); void createCheckUpdateJob(const QString& jobPath); void refreshLastTimeAndCheckCircle(); @@ -54,6 +56,7 @@ class UpdateWorker : public QObject Q_INVOKABLE void doUpgrade(int updateTypes, bool doBackup); Q_INVOKABLE void reStart(); Q_INVOKABLE void modalUpgrade(bool rebootAfterUpgrade = true); + Q_INVOKABLE void setShutdownAndUpgrade(bool isShutdownUpdate = false); void setBackupJob(const QString& jobPath); void setDistUpgradeJob(const QString& jobPath); void updateSystemVersion(); @@ -71,7 +74,13 @@ class UpdateWorker : public QObject Q_INVOKABLE void setIdleDownloadEnabled(bool enable); Q_INVOKABLE void setIdleDownloadBeginTime(QString time); Q_INVOKABLE void setIdleDownloadEndTime(QString time); - void setIdleDownloadConfig(const IdleDownloadConfig& config); + Q_INVOKABLE void setUpgradeDeliveryEnabled(bool enabled); + Q_INVOKABLE void setUpgradeDeliveryDownloadLimitSpeed(const QString& speed, bool enable); + Q_INVOKABLE void setUpgradeDeliveryUploadLimitSpeed(const QString& speed, bool enable); + Q_INVOKABLE void getUpgradeDeliveryDownloadLimitSpeed(); + Q_INVOKABLE void getUpgradeDeliveryUploadLimitSpeed(); + Q_INVOKABLE void cleanUpgradeDeliveryCache(); + Q_INVOKABLE void setIdleDownloadConfig(const IdleDownloadConfig& config); QString adjustTimeFunc(const QString& start, const QString& end, bool returnEndTime); // 更新设置-更新提醒 @@ -99,6 +108,7 @@ class UpdateWorker : public QObject void setInstallPackageJob(const QString& jobPath); void setRemovePackageJob(const QString& jobPath); QString getServiceUrlByRegion(); + void refreshUpgradeDeliveryInfo(); Q_INVOKABLE bool openUrl(const QString& url); Q_INVOKABLE void onRequestRetry(int type, int updateTypes); @@ -131,6 +141,7 @@ public Q_SLOTS: Dtk::Core::DConfig *m_lastoreDConfig; UpdateModel* m_model; UpdateDBusProxy *m_updateInter; + UpdateAssistant* m_updateAssistant; QTimer *m_lastoreHeartBeatTimer; // lastore-daemon 心跳信号,防止lastore-daemon自动退出 LogWatcherHelper *m_logWatcherHelper; diff --git a/src/dcc-update-plugin/operation/utils.h b/src/dcc-update-plugin/operation/utils.h index 44ad9696b..65e7448d2 100644 --- a/src/dcc-update-plugin/operation/utils.h +++ b/src/dcc-update-plugin/operation/utils.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2011 - 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2011-2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later diff --git a/src/dcc-update-plugin/qml/UpdateControl.qml b/src/dcc-update-plugin/qml/UpdateControl.qml index da873075c..156336e40 100644 --- a/src/dcc-update-plugin/qml/UpdateControl.qml +++ b/src/dcc-update-plugin/qml/UpdateControl.qml @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd. // SPDX-License-Identifier: GPL-3.0-or-later import QtQuick import QtQuick.Controls @@ -180,7 +180,7 @@ ColumnLayout { icon.height: 24 implicitWidth: 24 implicitHeight: 24 - visible: isDownloading + visible: isDownloading && !dccData.model().isPrivateUpdate onClicked: { rootLayout.closeDownload() diff --git a/src/dcc-update-plugin/qml/UpdateMain.qml b/src/dcc-update-plugin/qml/UpdateMain.qml index ef79567a7..c4db54eac 100644 --- a/src/dcc-update-plugin/qml/UpdateMain.qml +++ b/src/dcc-update-plugin/qml/UpdateMain.qml @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 - 2027 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd. // SPDX-License-Identifier: GPL-3.0-or-later import QtQuick 2.15 @@ -291,7 +291,10 @@ DccObject { page: UpdateControl { updateListModels: dccData.model().preInstallListModel updateTitle: qsTr("Update download completed") - btnActions: [ qsTr("Install updates") ] + btnActions: dccData.model().isPrivateUpdate ? [ + qsTr("Install Now"), + qsTr("Check Again") + ] : [qsTr("Install updates")] updateTips: { if (!dccData.model().batterIsOK) { return qsTr("The battery capacity is lower than 60%. To get successful updates, please plug in.") @@ -302,8 +305,16 @@ DccObject { updateListEnable: !dccData.model().upgradeWaiting onBtnClicked: function(index, updateType) { - updateSelectDialog.updateType = updateType - updateSelectDialog.show() + if (index === 0) { + if (dccData.model().isPrivateUpdate) { + dccData.work().doUpgrade(updateListModels.getAllUpdateType(), true) + } else { + updateSelectDialog.updateType = updateType + updateSelectDialog.show() + } + } else if (index === 1) { + dccData.work().reCheckWithUi(); + } } UpdateSelectDialog { @@ -367,7 +378,7 @@ DccObject { page: UpdateControl { updateListModels: dccData.model().preUpdatelistModel - updateTitle: !dccData.model().downloadWaiting ? qsTr("Updates Available") : qsTr("Downloading updates...") + updateTitle: !dccData.model().downloadWaiting || dccData.model().isPrivateUpdate ? qsTr("Updates Available") : qsTr("Downloading updates...") btnActions: [ qsTr("Download") ] updateTips: qsTr("Update size: ") + dccData.model().preUpdatelistModel.downloadSize busyState: dccData.model().downloadWaiting @@ -376,6 +387,12 @@ DccObject { onBtnClicked: function(index, updateType) { dccData.work().startDownload(updateType) } + + Component.onCompleted: { + if (dccData.model().isPrivateUpdate) { + dccData.work().startDownload(1) + } + } } } diff --git a/src/dcc-update-plugin/qml/UpdateSetting.qml b/src/dcc-update-plugin/qml/UpdateSetting.qml index 2f6ac9768..8652379dc 100644 --- a/src/dcc-update-plugin/qml/UpdateSetting.qml +++ b/src/dcc-update-plugin/qml/UpdateSetting.qml @@ -161,10 +161,221 @@ DccObject { } } + DccObject { + name: "upgradeDeliveryGrp" + parentName: "advancedSettingGroup" + weight: 40 + pageType: DccObject.Item + page: DccGroupView { + height: implicitHeight + 10 + spacing: 0 + } + + DccObject { + name: "upgradeDeliverySwitch" + parentName: "upgradeDeliveryGrp" + displayName: qsTr("Upgrade Delivery") + weight: 10 + enabled: !dccData.model().updateProhibited + pageType: DccObject.Editor + page: D.Switch { + id: upgradeDeliverySwitch + checked: dccData.model().upgradeDeliveryEnable + onCheckedChanged: { + dccData.work().setUpgradeDeliveryEnabled(checked) + } + Connections { + target: dccData.model() + function onUpgradeDeliveryEnableChanged() { + upgradeDeliverySwitch.checked = dccData.model().upgradeDeliveryEnable + } + } + } + } + + DccObject { + name: "upgradeDeliveryDownloadLimitSetting" + parentName: "upgradeDeliveryGrp" + displayName: qsTr("Upgrade Delivery Download Limit Setting") + visible: dccData.model().upgradeDeliveryEnable + weight: 20 + enabled: !dccData.model().upgradeDownloadSpeedIsOnline + pageType: DccObject.Item + property bool isInitializing: true + page: RowLayout { + D.CheckBox { + id: limitCheckBox + Layout.leftMargin: 14 + Layout.fillWidth: true + text: dccObj.displayName + checked: dccData.model().upgradeDownloadSpeedEnable + Connections { + target: dccData.model() + function onUpgradeDownloadSpeedLimitConfigChanged() { + limitCheckBox.checked = dccData.model().upgradeDownloadSpeedEnable + } + } + onCheckedChanged: { + if (dccObj.isInitializing) { + dccObj.isInitializing = false + return + } + if (limitCheckBox.checked) { + dccData.work().setUpgradeDeliveryDownloadLimitSpeed(lineEdit.text, limitCheckBox.checked) + } else { + dccData.work().setUpgradeDeliveryDownloadLimitSpeed("102400", limitCheckBox.checked) + } + } + } + + RowLayout { + spacing: 10 + Layout.topMargin: 5 + Layout.bottomMargin: 5 + Layout.rightMargin: 10 + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + D.LineEdit { + id: lineEdit + maximumLength: 5 + validator: RegularExpressionValidator { regularExpression: /^\d*$/ } + alertText: qsTr("Only numbers between 1-99999 are allowed") + alertDuration: 3000 + clearButton.active: lineEdit.activeFocus && (text.length !== 0) + text: dccData.model().upgradeDownloadSpeedCurrentRate + + onTextChanged: { + // 如果输入不为空且数字为0的情况,需要弹出提示且阻止继续输入 + if (lineEdit.text.length !== 0 && lineEdit.text[0] === "0") { + lineEdit.text = "" + lineEdit.showAlert = true + } else if (lineEdit.showAlert) { + lineEdit.showAlert = false + } + } + onEditingFinished: { + if (lineEdit.text.length === 0) { + lineEdit.text = dccData.model().upgradeDownloadSpeedLimitSize + return + } + dccData.work().setUpgradeDeliveryDownloadLimitSpeed(lineEdit.text, limitCheckBox.checked) + } + Keys.onPressed: { + if (event.key === Qt.Key_Return) { + lineEdit.forceActiveFocus(false); + } + } + Connections { + target: dccData.model() + function onUpgradeDownloadSpeedLimitConfigChanged() { + lineEdit.text = dccData.model().upgradeDownloadSpeedCurrentRate + } + } + } + + D.Label { + text: "KB/S" + } + } + } + } + + DccObject { + name: "upgradeDeliveryUploadLimitSetting" + parentName: "upgradeDeliveryGrp" + displayName: qsTr("Upgrade Delivery Upload Limit Setting") + visible: dccData.model().upgradeDeliveryEnable + weight: 20 + enabled: !dccData.model().upgradeUploadSpeedIsOnline + pageType: DccObject.Item + property bool isInitializing: true + page: RowLayout { + D.CheckBox { + id: limitCheckBox + Layout.leftMargin: 14 + Layout.fillWidth: true + text: dccObj.displayName + checked: dccData.model().upgradeUploadSpeedEnable + Connections { + target: dccData.model() + function onUpgradeUploadSpeedLimitConfigChanged() { + limitCheckBox.checked = dccData.model().upgradeUploadSpeedEnable + } + } + onCheckedChanged: { + console.log("xiongbo111") + if (dccObj.isInitializing) { + console.log("xiongbo222") + dccObj.isInitializing = false + return + } + console.log("xiongbo333") + if (limitCheckBox.checked) { + console.log("xiongbo444") + dccData.work().setUpgradeDeliveryUploadLimitSpeed(lineEdit.text, limitCheckBox.checked) + } else { + console.log("xiongbo555") + dccData.work().setUpgradeDeliveryUploadLimitSpeed("102400", limitCheckBox.checked) + } + } + } + + RowLayout { + spacing: 10 + Layout.topMargin: 5 + Layout.bottomMargin: 5 + Layout.rightMargin: 10 + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + D.LineEdit { + id: lineEdit + maximumLength: 5 + validator: RegularExpressionValidator { regularExpression: /^\d*$/ } + alertText: qsTr("Only numbers between 1-99999 are allowed") + alertDuration: 3000 + clearButton.active: lineEdit.activeFocus && (text.length !== 0) + text: dccData.model().upgradeUploadSpeedCurrentRate + + onTextChanged: { + // 如果输入不为空且数字为0的情况,需要弹出提示且阻止继续输入 + if (lineEdit.text.length !== 0 && lineEdit.text[0] === "0") { + lineEdit.text = "" + lineEdit.showAlert = true + } else if (lineEdit.showAlert) { + lineEdit.showAlert = false + } + } + onEditingFinished: { + if (lineEdit.text.length === 0) { + lineEdit.text = dccData.model().upgradeUploadSpeedLimitSize + return + } + dccData.work().setUpgradeDeliveryUploadLimitSpeed(lineEdit.text, limitCheckBox.checked) + } + Keys.onPressed: { + if (event.key === Qt.Key_Return) { + lineEdit.forceActiveFocus(false); + } + } + Connections { + target: dccData.model() + function onUpgradeUploadSpeedLimitConfigChanged() { + lineEdit.text = dccData.model().upgradeUploadSpeedCurrentRate + } + } + } + + D.Label { + text: "KB/S" + } + } + } + } + } + DccObject { name: "downloadLimitGrp" parentName: "advancedSettingGroup" weight: 40 + enabled: !dccData.model().downloadIsOnlineSpeedLimit pageType: DccObject.Item page: DccGroupView { height: implicitHeight + 10 @@ -179,7 +390,7 @@ DccObject { enabled: !dccData.model().updateProhibited pageType: DccObject.Editor page: D.Switch { - checked: dccData.model().downloadSpeedLimitEnabled + checked: dccData.model().downloadSpeedLimitEnabled || dccData.model().downloadIsOnlineSpeedLimit onCheckedChanged: { dccData.work().setDownloadSpeedLimitEnabled(checked) } @@ -238,6 +449,7 @@ DccObject { name: "autoDownloadGrp" parentName: "advancedSettingGroup" weight: 50 + visible: !dccData.model().isPrivateUpdate pageType: DccObject.Item page: DccGroupView { height: implicitHeight + 10 @@ -263,7 +475,7 @@ DccObject { name: "limitSetting" parentName: "autoDownloadGrp" displayName: qsTr("Download when Inactive") - visible: dccData.model().autoDownloadUpdates + visible: dccData.model().autoDownloadUpdates && !dccData.model().isPrivateUpdate weight: 20 enabled: !dccData.model().updateProhibited && !dccData.model().updateModeDisabled pageType: DccObject.Item @@ -346,6 +558,7 @@ DccObject { displayName: qsTr("Updates Notification") weight: 10 pageType: DccObject.Editor + visible: !dccData.model().isPrivateUpdate enabled: !dccData.model().updateProhibited && !dccData.model().updateModeDisabled page: D.Switch { checked: dccData.model().updateNotify @@ -360,6 +573,7 @@ DccObject { parentName: "advancedSettingGrp" displayName: qsTr("Clear Package Cache") weight: 20 + visible: !dccData.model().isPrivateUpdate pageType: DccObject.Editor page: D.Switch { checked: dccData.model().autoCleanCache @@ -374,6 +588,7 @@ DccObject { parentName: "advancedSettingGrp" displayName: qsTr("Update History") weight: 40 + visible: !dccData.model().isPrivateUpdate backgroundType: DccObject.Normal pageType: DccObject.Editor page: D.Button { @@ -403,7 +618,7 @@ DccObject { DccObject { name: "mirrorSettingGrp" parentName: "advancedSettingGroup" - visible: dccData.model().isCommunitySystem() + visible: dccData.model().isCommunitySystem() && !dccData.model().isPrivateUpdate weight: 70 pageType: DccObject.Item page: DccGroupView { diff --git a/src/dcc-update-plugin/translations/update_zh_CN.ts b/src/dcc-update-plugin/translations/update_zh_CN.ts index 451293140..e87eea2e2 100644 --- a/src/dcc-update-plugin/translations/update_zh_CN.ts +++ b/src/dcc-update-plugin/translations/update_zh_CN.ts @@ -249,6 +249,14 @@ Install updates 安装更新 + + Install Now + 立即更新 + + + Check Again + 重新检查更新 + Update download failed 更新下载失败 @@ -414,6 +422,18 @@ Delivers updates for additional repository sources 提供额外添加的仓库源更新内容 + + Upgrade Delivery + 更新传递 + + + Upgrade Delivery Download Limit Setting + 更新传递-下载限速 + + + Upgrade Delivery Upload Limit Setting + 更新传递-上传限速 + Limit Speed 下载限速 diff --git a/src/dcc-update-plugin/translations/update_zh_HK.ts b/src/dcc-update-plugin/translations/update_zh_HK.ts index 2cadcf187..037d968cd 100644 --- a/src/dcc-update-plugin/translations/update_zh_HK.ts +++ b/src/dcc-update-plugin/translations/update_zh_HK.ts @@ -249,6 +249,14 @@ Install updates 安裝更新 + + Install Now + 立即更新 + + + Check Again + 重新檢查更新 + Update download failed 更新下載失敗 @@ -414,6 +422,18 @@ Delivers updates for additional repository sources 提供額外添加的倉庫源更新內容 + + Upgrade Delivery + 更新傳遞 + + + Upgrade Delivery Download Limit Setting + 更新傳遞-下載限速 + + + Upgrade Delivery Upload Limit Setting + 更新傳遞-上傳限速 + Limit Speed 下載限速 diff --git a/src/dcc-update-plugin/translations/update_zh_TW.ts b/src/dcc-update-plugin/translations/update_zh_TW.ts index d23421439..238dedeeb 100644 --- a/src/dcc-update-plugin/translations/update_zh_TW.ts +++ b/src/dcc-update-plugin/translations/update_zh_TW.ts @@ -249,6 +249,14 @@ Install updates 安裝更新 + + Install Now + 立即更新 + + + Check Again + 重新檢查更新 + Update download failed 更新下載失敗 @@ -414,6 +422,18 @@ Delivers updates for additional repository sources 提供額外新增的倉庫源更新內容 + + Upgrade Delivery + 更新傳遞 + + + Upgrade Delivery Download Limit Setting + 更新傳遞-下載限速 + + + Upgrade Delivery Upload Limit Setting + 更新傳遞-上傳限速 + Limit Speed 下載限速 diff --git a/src/private-lastore-tray/CMakeLists.txt b/src/private-lastore-tray/CMakeLists.txt new file mode 100644 index 000000000..2441277fa --- /dev/null +++ b/src/private-lastore-tray/CMakeLists.txt @@ -0,0 +1,57 @@ +# SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +# +# SPDX-License-Identifier: CC0-1.0 + +set(PLUGIN_NAME "private-lastore-tray") + +project(${PLUGIN_NAME}) +include(GNUInstallDirs) +# 启用 qt moc 的支持 +set(CMAKE_AUTOMOC ON) +# 启用 qrc 资源文件的支持 +set(CMAKE_AUTORCC ON) +# Sources files +file(GLOB_RECURSE SRCS + "*.h" + "*.cpp" + "../common/*.h" + "../common/*.cpp" + #"../common/global_util/*.h" + #"../common/global_util/*.cpp" + "resources/private-lastore-tray.qrc" +) + +set(QT_VERSION_MAJOR 6) +set(DTK_VERSION_MAJOR 6) + +find_package(PkgConfig REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Widgets Core LinguistTools) +find_package(Dtk${DTK_VERSION_MAJOR} REQUIRED COMPONENTS Widget Core Gui) +find_package(DdeDock REQUIRED) + +add_library(${PLUGIN_NAME} SHARED ${SRCS}) +set_target_properties(${PLUGIN_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../) + +target_link_libraries(${PLUGIN_NAME} PRIVATE + Dtk${DTK_VERSION_MAJOR}::Widget + Dtk${DTK_VERSION_MAJOR}::Core + Dtk${DTK_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::Core +) + +file(GLOB TS_FILES "translations/*.ts") + +qt_add_translations(${PLUGIN_NAME}_language + TS_FILES ${TS_FILES} + SOURCES ${SRCS} + LUPDATE_OPTIONS -no-obsolete -no-ui-lines -locations none + QM_FILES_OUTPUT_VARIABLE QM_FILES +) +add_custom_target(${PLUGIN_NAME}_language ALL DEPENDS ${QM_FILES}) + +install(FILES ${QM_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/${PLUGIN_NAME}/translations) + +install(TARGETS ${PLUGIN_NAME} LIBRARY DESTINATION lib/dde-dock/plugins) +install(FILES "resources/private-lastore-sleep_16px.svg" DESTINATION share/dde-dock/icons/dcc-setting) +install(FILES "resources/private-lastore-active_16px.svg" DESTINATION share/dde-dock/icons/dcc-setting) diff --git a/src/private-lastore-tray/commoniconbutton.cpp b/src/private-lastore-tray/commoniconbutton.cpp new file mode 100644 index 000000000..b4044c458 --- /dev/null +++ b/src/private-lastore-tray/commoniconbutton.cpp @@ -0,0 +1,220 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later +#include "commoniconbutton.h" +#include "constants.h" + +#include +#include +#include + +#include + +DGUI_USE_NAMESPACE + +CommonIconButton::CommonIconButton(QWidget *parent) + : QWidget(parent) + , m_refreshTimer(nullptr) + , m_clickable(false) + , m_hover(false) + , m_state(Default) + , m_lightThemeColor(Qt::black) + , m_darkThemeColor(Qt::white) + , m_activeState(false) + , m_hoverEnable(true) + , m_iconSize(QSize()) + , m_rotation(0) +{ + setAccessibleName("IconButton"); + setFixedSize(Dock::DOCK_PLUGIN_ITEM_FIXED_SIZE); + if (parent) + setForegroundRole(parent->foregroundRole()); + + m_defaultPalette = palette(); + + connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::themeTypeChanged, this, &CommonIconButton::refreshIcon); +} + +void CommonIconButton::setStateIconMapping(QMap> mapping) +{ + m_fileMapping = mapping; +} + +void CommonIconButton::setState(State state) +{ + m_state = state; + if (m_fileMapping.contains(state)) { + auto pair = m_fileMapping.value(state); + setIcon(pair.first, pair.second); + } + if (!m_icon.isNull()) { + updatePalette(); + } +} + +void CommonIconButton::startRotate() +{ + if (!m_refreshTimer) { + m_refreshTimer = new QTimer(this); + m_refreshTimer->setInterval(70); + connect(m_refreshTimer, &QTimer::timeout, this, &CommonIconButton::startRotate); + } + m_refreshTimer->start(); + m_rotation += 54; + update(); +} + +void CommonIconButton::stopRotate() +{ + m_refreshTimer->stop(); + m_rotation = 0; + update(); +} + +void CommonIconButton::setIcon(const QIcon &icon, QColor lightThemeColor, QColor darkThemeColor) +{ + m_icon = icon; + if (lightThemeColor.isValid() && darkThemeColor.isValid()) { + m_lightThemeColor = lightThemeColor; + m_darkThemeColor = darkThemeColor; + } + + updatePalette(); +} + +void CommonIconButton::updatePalette() +{ + if (isEnabled()) { + if (m_lightThemeColor.isValid() && m_darkThemeColor.isValid()) { + QColor color = DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType ? m_lightThemeColor : m_darkThemeColor; + if (m_activeState) + color = palette().color(QPalette::Highlight); + auto pa = palette(); + pa.setColor(QPalette::WindowText, color); + setPalette(pa); + } + } else { + setPalette(m_defaultPalette); + } + + update(); +} + +void CommonIconButton::setActiveState(bool state) +{ + m_activeState = state; + if (m_lightThemeColor.isValid() && m_darkThemeColor.isValid()) { + updatePalette(); + } else { + setForegroundRole(state ? QPalette::Highlight : QPalette::NoRole); + } +} + +void CommonIconButton::setHoverEnable(bool enable) +{ + m_hoverEnable = enable; +} + +void CommonIconButton::setIcon(const QString &icon, const QString &fallback, const QString &suffix) +{ + if (!m_fileMapping.contains(Default)) { + m_fileMapping.insert(Default, QPair(icon, fallback)); + } + + QString tmp = icon; + QString tmpFallback = fallback; + + static auto addDarkMark = [suffix] (QString &file) { + if (file.contains(suffix)) { + file.replace(suffix, "-dark" + suffix); + } else { + file.append("-dark"); + } + }; + if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType) { + addDarkMark(tmp); + addDarkMark(tmpFallback); + } + m_icon = QIcon::fromTheme(tmp, QIcon::fromTheme(tmpFallback)); + update(); +} + +void CommonIconButton::setHoverIcon(const QIcon &icon) +{ + m_hoverIcon = icon; +} + +void CommonIconButton::setClickable(bool clickable) +{ + m_clickable = clickable; +} + +bool CommonIconButton::event(QEvent *e) +{ + switch (e->type()) { + case QEvent::Leave: + case QEvent::Enter: + m_hover = e->type() == QEvent::Enter; + update(); + break; + default: + break; + } + return QWidget::event(e); +} + +void CommonIconButton::paintEvent(QPaintEvent *e) +{ + QWidget::paintEvent(e); + QPainter painter(this); + painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); + + if (m_rotation != 0) { + painter.translate(this->width() / 2, this->height() / 2); + painter.rotate(m_rotation); + painter.translate(-(this->width() / 2), -(this->height() / 2)); + } + + if (m_hoverEnable && m_hover && !m_hoverIcon.isNull()) { + m_hoverIcon.paint(&painter, rect()); + } else if (!m_icon.isNull()) { + if (!m_iconSize.isEmpty()) { + const int left = (width() - m_iconSize.width()) / 2; + const int top = (height() - m_iconSize.height()) / 2; + m_icon.paint(&painter, rect().marginsRemoved(QMargins(left, top, left, top))); + } else { + m_icon.paint(&painter, rect()); + } + } +} + +void CommonIconButton::mousePressEvent(QMouseEvent *event) +{ + m_pressPos = event->pos(); + return QWidget::mousePressEvent(event); +} + +void CommonIconButton::mouseReleaseEvent(QMouseEvent *event) +{ + if (m_clickable && rect().contains(m_pressPos) && rect().contains(event->pos()) && (!m_refreshTimer || !m_refreshTimer->isActive())) { + Q_EMIT clicked(); + return; + } + return QWidget::mouseReleaseEvent(event); +} + +void CommonIconButton::refreshIcon() +{ + setState(m_state); +} + +void CommonIconButton::setIconSize(const QSize &size) +{ + m_iconSize = size; +} + +void CommonIconButton::setAllEnabled(bool enable) +{ + setEnabled(enable); + updatePalette(); +} diff --git a/src/private-lastore-tray/commoniconbutton.h b/src/private-lastore-tray/commoniconbutton.h new file mode 100644 index 000000000..f4aec45ab --- /dev/null +++ b/src/private-lastore-tray/commoniconbutton.h @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later +#ifndef ICONBUTTON_H +#define ICONBUTTON_H + +#include +#include +#include + +class CommonIconButton : public QWidget +{ +public: + enum State { + Default, + On, + Off + }; + + Q_OBJECT +public: + Q_PROPERTY(qreal rotation READ rotation WRITE setRotation) + + explicit CommonIconButton(QWidget *parent = nullptr); + + void setStateIconMapping(QMap> mapping); + void setState(State state); + void setActiveState(bool state); + bool activeState() const { return m_activeState; } + void setHoverEnable(bool enable); + void setIconSize(const QSize &size); + void setAllEnabled(bool enable); + + void startRotate(); + void stopRotate(); + + inline void setRotation(qreal rotation) { m_rotation = rotation; update(); } + inline qreal rotation() const { return m_rotation;} + +public Q_SLOTS: + void setIcon(const QString &icon, const QString &fallback = "", const QString &suffix = ".svg"); + void setIcon(const QIcon &icon, QColor lightThemeColor = QColor(QColor::Invalid), QColor darkThemeColor = QColor(QColor::Invalid)); + void setHoverIcon(const QIcon &icon); + + void setClickable(bool clickable); + +signals: + void clicked(); + +protected: + bool event(QEvent *e) override; + void paintEvent(QPaintEvent *e) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + +private: + void refreshIcon(); + void updatePalette(); + +private: + QTimer *m_refreshTimer; + QIcon m_icon; + QIcon m_hoverIcon; + QPoint m_pressPos; + bool m_clickable; + bool m_hover; + QMap> m_fileMapping; + State m_state; + QColor m_lightThemeColor; + QColor m_darkThemeColor; + bool m_activeState; + bool m_hoverEnable; + QSize m_iconSize; + qreal m_rotation; + QPalette m_defaultPalette; +}; + +#endif // DOCKICONBUTTON_H diff --git a/src/private-lastore-tray/constants.h b/src/private-lastore-tray/constants.h new file mode 100644 index 000000000..dfe8e503f --- /dev/null +++ b/src/private-lastore-tray/constants.h @@ -0,0 +1,255 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef CONSTANTS_H +#define CONSTANTS_H + +#include + +#define DOCK_API_VERSION_MAJOR 2 +#define DOCK_API_VERSION_MINOR 0 +#define DOCK_API_VERSION_PATCH 0 + +// 以下为插件适配会用到的常量 +namespace Dock { + +#define DOCK_PLUGIN_MIME "dock/plugin" +#define DOCK_PLUGIN_API_VERSION "2.0.0" // Deprecated, use DOCK_API_VERSION_CHECK + +#define PROP_DISPLAY_MODE "DisplayMode" + +#define PLUGIN_BACKGROUND_MAX_SIZE 40 // Deprecated, use DOCK_PLUGIN_ITEM_FIXED_SIZE +#define PLUGIN_BACKGROUND_MIN_SIZE 16 // Deprecated, use DOCK_PLUGIN_ITEM_FIXED_SIZE + +#define PLUGIN_ITEM_WIDTH 300 +#define PLUGIN_ICON_MAX_SIZE 16 // Deprecated, use DOCK_PLUGIN_ITEM_FIXED_SIZE +#define PLUGIN_ICON_MIN_SIZE 16 // Deprecated, use DOCK_PLUGIN_ITEM_FIXED_SIZE + +// 插件最小尺寸,图标采用深色 +#define PLUGIN_MIN_ICON_NAME "-dark" + +// dock最大尺寸 +#define DOCK_MAX_SIZE 100 +/// +/// \brief The DisplayMode enum +/// spec dock display mode +/// +enum DisplayMode { + Fashion = 0, + Efficient = 1, +}; + +#define PROP_HIDE_MODE "HideMode" +/// +/// \brief The HideMode enum +/// spec dock hide behavior +/// +enum HideMode { + KeepShowing = 0, + KeepHidden = 1, + SmartHide = 3, +}; + +#define PROP_POSITION "Position" +/// +/// \brief The Position enum +/// spec dock position, dock always placed at primary screen, +/// so all position is the primary screen edge. +/// +enum Position { + Top = 0, + Right = 1, + Bottom = 2, + Left = 3, +}; + +#define PROP_HIDE_STATE "HideState" +/// +/// \brief The HideState enum +/// spec current dock should hide or shown. +/// this argument works only HideMode is SmartHide +/// +enum HideState { + Unknown = 0, + Show = 1, + Hide = 2, +}; + +#define IS_TOUCH_STATE "isTouchState" + + +/** + * @brief 任务栏 API 版本号,插件在编译期可以通过比对版本号判断接口是否兼容 + * DOCK_API_VERSION_VERSION is (major << 16) + (minor << 8) + patch. + * @since 2.0.0 + */ +#define DOCK_API_VERSION DOCK_API_VERSION_CHECK(DOCK_API_VERSION_MAJOR, DOCK_API_VERSION_MINOR, DOCK_API_VERSION_PATCH) + +/** + * @brief 用来和 DOCK_API_VERSION 进行比对 + * can be used like #if (DOCK_API_VERSION >= DOCK_API_VERSION_CHECK(2, 0, 0)) + * @since 2.0.0 + */ +#define DOCK_API_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) + +/** + * @brief 插件的标志位 + * @since 2.0.0 + */ +enum PluginFlag { + Type_None = 0x00, // 默认值,插件无需关注 + Type_Unadapted = 0x01, // 插件类型-未适配,插件适配时勿使用这个flag + Type_Quick = 0x02, // 插件类型-快捷插件区 + Type_Tool = 0x04, // 插件类型-工具插件,例如回收站 + Type_System = 0x08, // 插件类型-系统插件,例如关机插件 + Type_Tray = 0x10, // 插件类型-托盘区,例如U盘插件 + Type_Fixed = 0x20, // 插件类型-固定区域,例如多任务视图和显示桌面 + + Quick_Panel_Single = 0x40, // 当插件类型为Common时,快捷插件区域只有一列的那种插件 + Quick_Panel_Multi = 0x80, // 当插件类型为Common时,快捷插件区占两列的那种插件 + Quick_Panel_Full = 0x100, // 当插件类型为Common时,快捷插件区占用4列的那种插件,例如声音、亮度设置和音乐等 + + Attribute_CanDrag = 0x200, // 插件属性-是否支持拖动 + Attribute_CanInsert = 0x400, // 插件属性-是否支持在其前面插入其他的插件,普通的快捷插件是支持的 + Attribute_CanSetting = 0x800, // 插件属性-是否可以在控制中心设置显示或隐藏,如果设置了这个属性,请实现PluginsItemInterfaceV2::icon 接口,并返回在`控制中心-个性化-任务栏-插件区域`中显示的图标 + Attribute_ForceDock = 0x1000, // 插件属性-强制显示在任务栏上 + + Attribute_Normal = Attribute_CanDrag | Attribute_CanInsert | Attribute_CanSetting, // 普通插件 + + FlagMask = 0xffffffff // 掩码 +}; +Q_DECLARE_FLAGS(PluginFlags, PluginFlag) +Q_DECLARE_OPERATORS_FOR_FLAGS(PluginFlags) + +/** + * @brief 图标的类型 + * @since 2.0.0 + */ +enum IconType +{ + IconType_None = 0, // 默认,无实际意义 +}; + +/** + * @brief 主题类型,和 dtk 的标志位对应 + * @since 2.0.0 + */ +enum ThemeType { + ThemeType_None, // 不涉及 + ThemeType_Light, // 亮色 + ThemeType_Dark // 暗色 +}; + +/** + * @brief 2.0.0 新增常量 + * @since 2.0.0 + */ +const QString QUICK_TOP_ACTION = QStringLiteral("quick_top_action"); // 快捷面板子页面右上角控件 +const QString QUICK_ITEM_KEY = QStringLiteral("quick_item_key"); // 快捷面板详情页面的itemWidget对应的itemKey +// 在 QApplication 设置的属性,插件可以在运行时获取API版本号,可以通过 qApp->property(DOCK_API_VERSION_PROPERTY) 获取版本号 +// 然后是同DOCK_API_VERSION_CHECK的方法去比较版本大小 +const QByteArray DOCK_API_VERSION_PROPERTY = "dock_api_version"; +const int DOCK_PLUGIN_ITEM_FIXED_WIDTH = 16; // 插件在任务栏上面的固定宽度 +const int DOCK_PLUGIN_ITEM_FIXED_HEIGHT = 16; // 插件在任务栏上面的固定高度 +const QSize DOCK_PLUGIN_ITEM_FIXED_SIZE(DOCK_PLUGIN_ITEM_FIXED_WIDTH, DOCK_PLUGIN_ITEM_FIXED_HEIGHT); // 插件在任务栏上面的固定大小 +const int TRAY_PLUGIN_ITEM_FIXED_WIDTH = 16; // 托盘插件的固定宽度 +const int TRAY_PLUGIN_ITEM_FIXED_HEIGHT = 16; // 托盘插件的固定高度 +const QSize TRAY_PLUGIN_ITEM_FIXED_SIZE(TRAY_PLUGIN_ITEM_FIXED_WIDTH, TRAY_PLUGIN_ITEM_FIXED_HEIGHT); // 托盘插件的固定大小 +const int DOCK_POPUP_WIDGET_WIDTH = 330; // 任务栏弹窗的宽度 +const int DOCK_POPUP_WIDGET_MAX_HEIGHT = 600; // 任务栏弹窗的最大高度 +const int QUICK_PANEL_ICON_WIDTH = 24; // 快捷面板中插件图标的宽度 +const int QUICK_PANEL_ICON_HEIGHT = 24; // 快捷面板中插件图标的高度 +const QSize QUICK_PANEL_ICON_SIZE(QUICK_PANEL_ICON_WIDTH, QUICK_PANEL_ICON_HEIGHT); // 快捷面板中插件图标的大小 +const int QUICK_ITEM_HEIGHT = 60; // 快捷面板插件高度 +const int QUICK_ITEM_SINGLE_WIDTH = 70; // 单格快捷面板插件宽度 +const int QUICK_ITEM_MULTI_WIDTH = 150; // 双格快捷面板插件宽度 +const int QUICK_ITEM_FULL_WIDTH = 310; // 整行快捷面板插件宽度 + +/** + * @brief 用于在插件的 message 和 MessageCallbackFunc 方法中解析 json格式 数据。 + * 详细的说明见 plugins-developer-guide.md 文档 + * @since 2.0.0 + */ +const QString MSG_TYPE = QStringLiteral("msgType"); // 固定 key 值,表明当前消息类型是什么 +const QString MSG_DATA = QStringLiteral("data"); // 固定 key 值,从该字段中获取具体数据 + +/** + * @brief 插件功能是否可用 + * eg:蓝牙被拔掉后,蓝牙插件的 support 的状态应该是 false,任务栏会把蓝牙的图标从控制中心-个性化-任务栏-插件区域中移除 + */ +const QString MSG_GET_SUPPORT_FLAG = QStringLiteral("getSupportFlag"); +const QString MSG_SUPPORT_FLAG = QStringLiteral("supportFlag"); +const QString MSG_SUPPORT_FLAG_CHANGED = QStringLiteral("supportFlagChanged"); + +/** + * @brief 任务栏应用溢出状态 + */ +const QString MSG_UPDATE_OVERFLOW_STATE = QStringLiteral("updateOverflowState"); +const int OVERFLOW_STATE_NOT_EXIST = 0; // 没有溢出区 +const int OVERFLOW_STATE_EXIST = 1; // 有溢出区 +const int OVERFLOW_STATE_ALL = 2; // 所有应用都在溢出区 + +/** + * @brief 最小弹窗高度,根据快捷面板的高度动态变化 + * 任务栏主动发送给插件,只会给快捷插件发送 + */ +const QString MSG_SET_APPLET_MIN_HEIGHT = QStringLiteral("setAppletMinHeight"); + +/** + * @brief 插件自行决定是否要被任务栏加载,不发送此消息默认被加载 + * ture: 希望被加载,false: 不希望被加载 + */ +const QString MSG_WHETHER_WANT_TO_BE_LOADED = QStringLiteral("whetherWantToBeLoaded"); + +/** + * @brief 弹窗是在任务栏上直接显示还是快捷面板的二级页面显示 + * 插件可以根据显示的位置做一些样式调整 + */ +const QString MSG_APPLET_CONTAINER = QStringLiteral("appletContainer"); +const int APPLET_CONTAINER_DOCK = 0; // 任务栏 +const int APPLET_CONTAINER_QUICK_PANEL = 1; // 快捷面板 + +/** + * @brief 插件图标的激活状态;当状态发生变化时,插件需要主动把状态发送给任务栏 + * true: 插件处于激活状态,false:插件出于失活状态 + */ +const QString MSG_ITEM_ACTIVE_STATE = QStringLiteral("itemActiveState"); +/** + * @brief 插件请求任务栏更新插件的 tooltips + * 任务栏收到请求后会主动调用 itemTips() 方法。 + * 一般用于一个插件里面含有多个图标,鼠标 hover 到不同图标上时显示不同 tooltips 的场景。 + */ +const QString MSG_UPDATE_TOOLTIPS_VISIBLE = QStringLiteral("updateTooltipsVisible"); + +/** + * @brief 任务栏面板Size;当任务栏size发生改变时,通知插件 + * 插件根据任务栏size做出大小调整,例如时间日期插件 + */ +const QString MSG_DOCK_PANEL_SIZE_CHANGED = QStringLiteral("dockPanelSizeChanged"); + +/** + * @brief 插件属性,MSG_TYPE + * 任务栏通过获取插件属性来确定插件状态,例如是否需要变色龙效果 + * 返回的MSG_DATA类型为QMap,其中QString为属性名称,QVariant为对应值 + */ +const QString MSG_PLUGIN_PROPERTY = QStringLiteral("pluginProperty"); + +/** + * @brief 属性 - 需要变色龙,即插件需要hover、press样式 + * true: 需要;false: 不需要; + */ +const QString PLUGIN_PROP_NEED_CHAMELEON = QStringLiteral("needChameleon"); + +/** + * @brief 属性 - 变色龙边距 + * 返回需要设置的QMargin() + */ +const QString PLUGIN_PROP_CHAMELEON_MARGIN = QStringLiteral("chameleonMargin"); +} + +Q_DECLARE_METATYPE(Dock::DisplayMode) +Q_DECLARE_METATYPE(Dock::Position) + + +#endif // CONSTANTS_H diff --git a/src/private-lastore-tray/pluginproxyinterface.h b/src/private-lastore-tray/pluginproxyinterface.h new file mode 100644 index 000000000..c88817cdd --- /dev/null +++ b/src/private-lastore-tray/pluginproxyinterface.h @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef PLUGINPROXYINTERFACE_H +#define PLUGINPROXYINTERFACE_H + +#include "constants.h" + +#include + +class PluginsItemInterface; +class PluginProxyInterface +{ +public: + /// + /// \brief itemAdded + /// add a new dock item + /// if itemkey of this plugin inter already exist, the new item + /// will be ignored, so if you need to add multiple item, you need + /// to ensure all itemKey is different. + /// \param itemInter + /// your plugin interface + /// \param itemKey + /// your item unique key + /// + virtual void itemAdded(PluginsItemInterface * const itemInter, const QString &itemKey) = 0; + /// + /// \brief itemUpdate + /// update(repaint) spec item + /// \param itemInter + /// \param itemKey + /// + virtual void itemUpdate(PluginsItemInterface * const itemInter, const QString &itemKey) = 0; + /// + /// \brief itemRemoved + /// remove spec item, if spec item is not exist, dock will to nothing. + /// dock will NOT delete your object, you should manage memory by your self. + /// \param itemInter + /// \param itemKey + /// + virtual void itemRemoved(PluginsItemInterface * const itemInter, const QString &itemKey) = 0; + /// + /// \brief requestContextMenu + /// request show context menu + /// + //virtual void requestContextMenu(PluginsItemInterface * const itemInter, const QString &itemKey) = 0; + + virtual void requestWindowAutoHide(PluginsItemInterface * const itemInter, const QString &itemKey, const bool autoHide) = 0; + virtual void requestRefreshWindowVisible(PluginsItemInterface * const itemInter, const QString &itemKey) = 0; + + virtual void requestSetAppletVisible(PluginsItemInterface * const itemInter, const QString &itemKey, const bool visible) = 0; + + /// + /// \brief saveValue + /// save module config to .config/deepin/dde-dock.conf + /// all key-values of all plugins will be save to that file + /// and grouped by the returned value of pluginName() function which is defined in PluginsItemInterface + /// \param itemInter the plugin object + /// \param key the key of data + /// \param value the data + /// + virtual void saveValue(PluginsItemInterface * const itemInter, const QString &key, const QVariant &value) = 0; + + /// + /// \brief getValue + /// SeeAlse: saveValue + /// return value from .config/deepin/dde-dock.conf + /// + virtual const QVariant getValue(PluginsItemInterface *const itemInter, const QString &key, const QVariant& fallback = QVariant()) = 0; + + /// + /// \brief removeValue + /// remove the values specified by keyList + /// remove all values of itemInter if keyList is empty + /// SeeAlse: saveValue + /// + virtual void removeValue(PluginsItemInterface *const itemInter, const QStringList &keyList) = 0; +}; + +#endif // PLUGINPROXYINTERFACE_H diff --git a/src/private-lastore-tray/plugins-logging-category.h b/src/private-lastore-tray/plugins-logging-category.h new file mode 100644 index 000000000..43b226fa9 --- /dev/null +++ b/src/private-lastore-tray/plugins-logging-category.h @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#pragma once + +#include + +Q_DECLARE_LOGGING_CATEGORY(APP) +Q_DECLARE_LOGGING_CATEGORY(DOCK_DATETIME) +Q_DECLARE_LOGGING_CATEGORY(SHUTDOWN) +Q_DECLARE_LOGGING_CATEGORY(DOCK_POWER) +Q_DECLARE_LOGGING_CATEGORY(DOCK_SOUND) +Q_DECLARE_LOGGING_CATEGORY(TRAY) +Q_DECLARE_LOGGING_CATEGORY(TRASH) +Q_DECLARE_LOGGING_CATEGORY(KEYBOARD_LAYOUT) +Q_DECLARE_LOGGING_CATEGORY(OVERLAY_WARNING) +Q_DECLARE_LOGGING_CATEGORY(SHOW_DESKTOP) +Q_DECLARE_LOGGING_CATEGORY(MULTI_TASK) +Q_DECLARE_LOGGING_CATEGORY(BLUETOOTH) +Q_DECLARE_LOGGING_CATEGORY(AIRPLANE) +Q_DECLARE_LOGGING_CATEGORY(QUICK_PANEL) +Q_DECLARE_LOGGING_CATEGORY(DND) +Q_DECLARE_LOGGING_CATEGORY(EYE_COMFORT) +Q_DECLARE_LOGGING_CATEGORY(MEDIA) +Q_DECLARE_LOGGING_CATEGORY(BRIGHTNESS) +Q_DECLARE_LOGGING_CATEGORY(PERFORMANCE) + +Q_DECLARE_LOGGING_CATEGORY(DCC_DOCK_SETTING) + diff --git a/src/private-lastore-tray/pluginsiteminterface.h b/src/private-lastore-tray/pluginsiteminterface.h new file mode 100644 index 000000000..604a0a107 --- /dev/null +++ b/src/private-lastore-tray/pluginsiteminterface.h @@ -0,0 +1,247 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef PLUGINSITEMINTERFACE_H +#define PLUGINSITEMINTERFACE_H + +#include "pluginproxyinterface.h" + +#include +#include + +/// +/// \brief The PluginsItemInterface class +/// the dock plugins item interface, all dock plugins should +/// inheirt this class and override all pure virtual function. +/// +class PluginsItemInterface +{ +public: + enum PluginType { + Normal, + Fixed + }; + + /** + * @brief Plugin size policy + */ + enum PluginSizePolicy { + System = 1 << 0, // Follow the system + Custom = 1 << 1 // The custom + }; + + /// + /// \brief ~PluginsItemInterface + /// DON'T try to delete m_proxyInter. + /// + virtual ~PluginsItemInterface() {} + + /// + /// \brief pluginName + /// tell dock the unique plugin id + /// \return + /// + virtual const QString pluginName() const = 0; + virtual const QString pluginDisplayName() const { return QString(); } + + /// + /// \brief init + /// init your plugins, you need to save proxyInter to m_proxyInter + /// member variable. but you shouldn't free this pointer. + /// \param proxyInter + /// DON'T try to delete this pointer. + /// + virtual void init(PluginProxyInterface *proxyInter) = 0; + /// + /// \brief itemWidget + /// your plugin item widget, each item should have a unique key. + /// \param itemKey + /// your widget' unique key. + /// \return + /// + virtual QWidget *itemWidget(const QString &itemKey) = 0; + + /// + /// \brief itemTipsWidget + /// override this function if your item want to have a tips. + /// the tips will shown when user hover your item. + /// nullptr will be ignored. + /// \param itemKey + /// \return + /// + virtual QWidget *itemTipsWidget(const QString &itemKey) {Q_UNUSED(itemKey); return nullptr;} + /// + /// \brief itemPopupApplet + /// override this function if your item wants to have an popup applet. + /// the popup applet will shown when user click your item. + /// + /// Tips: + /// dock should receive mouse press/release event to check user mouse operate, + /// if your item filter mouse event, this function will not be called. + /// so if you override mouse event and want to use popup applet, you + /// should pass event to your parent use QWidget::someEvent(e); + /// \param itemKey + /// \return + /// + virtual QWidget *itemPopupApplet(const QString &itemKey) {Q_UNUSED(itemKey); return nullptr;} + /// + /// \brief itemCommand + /// execute spec command when user clicked your item. + /// ensure your command do not get user input. + /// + /// empty string will be ignored. + /// \param itemKey + /// \return + /// + virtual const QString itemCommand(const QString &itemKey) {Q_UNUSED(itemKey); return QString();} + + /// + /// \brief itemContextMenu + /// context menu is shown when RequestPopupMenu called. + /// \param itemKey + /// \return + /// + virtual const QString itemContextMenu(const QString &itemKey) {Q_UNUSED(itemKey); return QString();} + /// + /// \brief invokedMenuItem + /// call if context menu item is clicked + /// \param itemKey + /// \param itemId + /// menu item id + /// \param checked + /// + virtual void invokedMenuItem(const QString &itemKey, const QString &menuId, const bool checked) {Q_UNUSED(itemKey); Q_UNUSED(menuId); Q_UNUSED(checked);} + + /// + /// \brief itemSortKey + /// tell dock where your item wants to put on. + /// + /// this index is start from 1 and + /// 0 for left side + /// -1 for right side + /// \param itemKey + /// \return + /// + virtual int itemSortKey(const QString &itemKey) {Q_UNUSED(itemKey); return 1;} + /// + /// \brief setSortKey + /// save your item new position + /// sort key will be changed when plugins order + /// changed(by user drag-drop) + /// \param itemKey + /// \param order + /// + virtual void setSortKey(const QString &itemKey, const int order) {Q_UNUSED(itemKey); Q_UNUSED(order);} + + /// + /// \brief itemAllowContainer + /// tell dock is your item allow to move into container + /// + /// if your item placed into container, popup tips and popup + /// applet will be disabled. + /// \param itemKey + /// \return + /// + virtual bool itemAllowContainer(const QString &itemKey) {Q_UNUSED(itemKey); return false;} + /// + /// \brief itemIsInContainer + /// tell dock your item is in container, this function + /// called at item init and if your item enable container. + /// \param itemKey + /// \return + /// + virtual bool itemIsInContainer(const QString &itemKey) {Q_UNUSED(itemKey); return false;} + /// + /// \brief setItemIsInContainer + /// save your item new state. + /// this function called when user drag out your item from + /// container or user drop item into container(if your item + /// allow drop into container). + /// \param itemKey + /// \param container + /// + virtual void setItemIsInContainer(const QString &itemKey, const bool container) {Q_UNUSED(itemKey); Q_UNUSED(container);} + + virtual bool pluginIsAllowDisable() { return false; } + virtual bool pluginIsDisable() { return false; } + virtual void pluginStateSwitched() {} + + /// + /// \brief displayModeChanged + /// override this function to receive display mode changed signal + /// \param displayMode + /// + virtual void displayModeChanged(const Dock::DisplayMode displayMode) {Q_UNUSED(displayMode);} + /// + /// \brief positionChanged + /// override this function to receive dock position changed signal + /// \param position + /// + virtual void positionChanged(const Dock::Position position) {Q_UNUSED(position);} + + /// + /// \brief refreshIcon + /// refresh item icon, its triggered when system icon theme changed. + /// \param itemKey + /// item key + /// + virtual void refreshIcon(const QString &itemKey) { Q_UNUSED(itemKey); } + + /// + /// \brief displayMode + /// get current dock display mode + /// \return + /// + inline Dock::DisplayMode displayMode() const + { + return qApp->property(PROP_DISPLAY_MODE).value(); + } + + /// + /// \brief position + /// get current dock position + /// \return + /// + inline Dock::Position position() const + { + return qApp->property(PROP_POSITION).value(); + } + + /// + /// \brief settingsChanged + /// override this function to receive plugin settings changed signal(DeepinSync) + /// + virtual void pluginSettingsChanged() {} + + /// + /// \brief type + /// Default plugin add dock right, fixed plugin add to dock fixed area + /// + /// This function is deprecated, please use `flags()` instead of it + /// + QT_DEPRECATED_X("Use flags()") + virtual PluginType type() { return Normal; } + + /// + /// \brief plugin size policy + /// default plugin size policy + /// + virtual PluginSizePolicy pluginSizePolicy() const { return System; } + +protected: + /// + /// \brief m_proxyInter + /// NEVER delete this object. + /// + PluginProxyInterface *m_proxyInter = nullptr; +}; + +QT_BEGIN_NAMESPACE + +#define ModuleInterface_iid "com.deepin.dock.PluginsItemInterface" + +Q_DECLARE_INTERFACE(PluginsItemInterface, ModuleInterface_iid) +QT_END_NAMESPACE + +#endif // PLUGINSITEMINTERFACE_H diff --git a/src/private-lastore-tray/privatelastoreitem.cpp b/src/private-lastore-tray/privatelastoreitem.cpp new file mode 100644 index 000000000..45166c7e9 --- /dev/null +++ b/src/private-lastore-tray/privatelastoreitem.cpp @@ -0,0 +1,97 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "privatelastoreitem.h" +#include "constants.h" +#include "tipswidget.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +DGUI_USE_NAMESPACE + +PrivateLastoreItem::PrivateLastoreItem(QWidget* parent) + : QWidget(parent) + , m_tipsLabel(new TipsWidget(this)) + , m_icon(new CommonIconButton(this)) + , m_managerInter(new UpdateDBusProxy(this)) + , m_controlCenterInterface(new QDBusInterface("com.deepin.dde.ControlCenter", "/com/deepin/dde/ControlCenter", "com.deepin.dde.ControlCenter", QDBusConnection::sessionBus())) +{ + m_tipsLabel->setVisible(false); + auto vLayout = new QVBoxLayout(this); + vLayout->setSpacing(0); + vLayout->setContentsMargins(0, 0, 0, 0); + vLayout->addWidget(m_icon, 0, Qt::AlignCenter); + m_icon->setFixedSize(Dock::DOCK_PLUGIN_ITEM_FIXED_SIZE); + m_icon->setIcon(QIcon(":resources/private-lastore-sleep_16px.svg")); + m_icon->setContentsMargins(0, 0, 0, 0); + connect(m_managerInter, &UpdateDBusProxy::JobListChanged, this, &PrivateLastoreItem::onRefreshIcon); +} + +QWidget* PrivateLastoreItem::tipsWidget() +{ + m_tipsLabel->refreshContent(); + return m_tipsLabel; +} + +void PrivateLastoreItem::onRefreshIcon(const QList &jobs) +{ + qInfo() << "Job list changed"; + + for (const auto &job : jobs) { + const QString &jobPath = job.path(); + qInfo() << "Path : " << jobPath; + UpdateJobDBusProxy jobInter(jobPath, this); + if (!jobInter.isValid()) { + qWarning() << "Job is invalid"; + continue; + } + + const QString &id = jobInter.id(); + qInfo() << "Job id : " << id; + if (id == "dist_upgrade" || id == "prepare_dist_upgrade") { + m_icon->setIcon(QIcon(":resources/private-lastore-active_16px.svg")); + return; + } + } + m_icon->setIcon(QIcon(":resources/private-lastore-sleep_16px.svg")); +} + +void PrivateLastoreItem::resizeEvent(QResizeEvent* e) +{ + QWidget::resizeEvent(e); + + const Dock::Position position = qApp->property(PROP_POSITION).value(); + if (position == Dock::Bottom || position == Dock::Top) { + setMaximumWidth(height()); + setMaximumHeight(QWIDGETSIZE_MAX); + } else { + setMaximumHeight(width()); + setMaximumWidth(QWIDGETSIZE_MAX); + } +} + +void PrivateLastoreItem::mouseReleaseEvent(QMouseEvent *event) { + if (event->button() == Qt::LeftButton && m_controlCenterInterface) { + DDBusSender() + .service("org.deepin.dde.ControlCenter1") + .interface("org.deepin.dde.ControlCenter1") + .path("/org/deepin/dde/ControlCenter1") + .method("ShowModule") + .arg(QString("update")) + .call(); + } + QWidget::mouseReleaseEvent(event); +} + diff --git a/src/private-lastore-tray/privatelastoreitem.h b/src/private-lastore-tray/privatelastoreitem.h new file mode 100644 index 000000000..258748d50 --- /dev/null +++ b/src/private-lastore-tray/privatelastoreitem.h @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef PRIVATELASTOREITEM_H +#define PRIVATELASTOREITEM_H + +#include "commoniconbutton.h" +#include "common/dbus/updatedbusproxy.h" +#include "common/dbus/updatejobdbusproxy.h" +#include "tipswidget.h" + +#include +#include + +namespace Dock { +class TipsWidget; +} + +class AirplaneModeApplet; +class PrivateLastoreItem : public QWidget +{ + Q_OBJECT + +public: + explicit PrivateLastoreItem(QWidget *parent = nullptr); + + QWidget *tipsWidget(); + +protected: + void resizeEvent(QResizeEvent *e); + void mouseReleaseEvent(QMouseEvent *event) override; + +private slots: + void onRefreshIcon(const QList &jobs); + +private: + TipsWidget *m_tipsLabel; + CommonIconButton *m_icon; + UpdateDBusProxy *m_managerInter = nullptr; + QDBusInterface *m_controlCenterInterface = nullptr; +}; + +#endif // PRIVATELASTOREITEM_H diff --git a/src/private-lastore-tray/privatelastoremode.json b/src/private-lastore-tray/privatelastoremode.json new file mode 100644 index 000000000..bec81f0da --- /dev/null +++ b/src/private-lastore-tray/privatelastoremode.json @@ -0,0 +1,3 @@ +{ + "api": "2.0.0" +} diff --git a/src/private-lastore-tray/privatelastoreplugin.cpp b/src/private-lastore-tray/privatelastoreplugin.cpp new file mode 100644 index 000000000..18052e47c --- /dev/null +++ b/src/private-lastore-tray/privatelastoreplugin.cpp @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "privatelastoreplugin.h" +#include "privatelastoreitem.h" +#include "qdbusconnection.h" +#include "common/global_util/public_func.h" + +#include +#include + +#define PRIVATE_LASTORE_KEY "private-lastore-key" +#define STATE_KEY "enabled" + +DCORE_USE_NAMESPACE +DGUI_USE_NAMESPACE +Q_LOGGING_CATEGORY(dockPrivateUpdatePlugin, "org.deepin.dde.dock.update") + +PrivateLastorePlugin::PrivateLastorePlugin(QObject *parent) + : QObject(parent) + , m_item(new PrivateLastoreItem) +{ + QTranslator *translator = new QTranslator(this); + translator->load(QLocale(), "private-lastore-tray", "_", "/usr/share/private-lastore-tray/translations"); + QCoreApplication::installTranslator(translator); +} + +PrivateLastorePlugin::~PrivateLastorePlugin() +{ + if (m_item) { + delete m_item; + m_item = nullptr; + } +} + +void PrivateLastorePlugin::loadPlugin() +{ + m_proxyInter->itemAdded(this, PRIVATE_LASTORE_KEY); + displayModeChanged(displayMode()); +} + +const QString PrivateLastorePlugin::pluginName() const +{ + return "private-lastore"; +} + +const QString PrivateLastorePlugin::pluginDisplayName() const +{ + return tr("Private Lastore"); +} + +void PrivateLastorePlugin::init(PluginProxyInterface *proxyInter) +{ + m_proxyInter = proxyInter; + + m_proxyInter->itemAdded(this, pluginName()); + m_proxyInter->saveValue(this, STATE_KEY, true); +} + +QWidget *PrivateLastorePlugin::itemWidget(const QString &itemKey) +{ + return m_item; +} + +QWidget *PrivateLastorePlugin::itemTipsWidget(const QString &itemKey) +{ + return m_item->tipsWidget(); +} diff --git a/src/private-lastore-tray/privatelastoreplugin.h b/src/private-lastore-tray/privatelastoreplugin.h new file mode 100644 index 000000000..2359264c7 --- /dev/null +++ b/src/private-lastore-tray/privatelastoreplugin.h @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef PRIVATELASTOREPLUGIN_H +#define PRIVATELASTOREPLUGIN_H + +#include "pluginsiteminterface_v2.h" +#include "plugins-logging-category.h" + +#include + +#include "dtkcore_global.h" + +class PrivateLastoreItem; +class PrivateLastorePlugin : public QObject, public PluginsItemInterfaceV2 +{ + Q_OBJECT + Q_INTERFACES(PluginsItemInterfaceV2) + Q_PLUGIN_METADATA(IID "com.deepin.dock.PluginsItemInterface" FILE "privatelastoremode.json") + +public: + explicit PrivateLastorePlugin(QObject *parent = nullptr); + ~PrivateLastorePlugin(); + + const QString pluginName() const Q_DECL_OVERRIDE; + const QString pluginDisplayName() const Q_DECL_OVERRIDE; + void init(PluginProxyInterface *proxyInter) override; + + bool pluginIsAllowDisable() override { return true; } + QWidget *itemWidget(const QString &itemKey) Q_DECL_OVERRIDE; + QWidget *itemTipsWidget(const QString &itemKey) Q_DECL_OVERRIDE; + +private: + void loadPlugin(); + +private: + PrivateLastoreItem *m_item; +}; + +#endif // PRIVATELASTOREPLUGIN_H diff --git a/src/private-lastore-tray/resources/private-lastore-active_16px.svg b/src/private-lastore-tray/resources/private-lastore-active_16px.svg new file mode 100644 index 000000000..42699c403 --- /dev/null +++ b/src/private-lastore-tray/resources/private-lastore-active_16px.svg @@ -0,0 +1,7 @@ + + + status-intranet-update-platform + + + + \ No newline at end of file diff --git a/src/private-lastore-tray/resources/private-lastore-sleep_16px.svg b/src/private-lastore-tray/resources/private-lastore-sleep_16px.svg new file mode 100644 index 000000000..881ee6e39 --- /dev/null +++ b/src/private-lastore-tray/resources/private-lastore-sleep_16px.svg @@ -0,0 +1,7 @@ + + + status-intranet-update-platform-dark + + + + \ No newline at end of file diff --git a/src/private-lastore-tray/resources/private-lastore-tray.qrc b/src/private-lastore-tray/resources/private-lastore-tray.qrc new file mode 100644 index 000000000..9e5b0841f --- /dev/null +++ b/src/private-lastore-tray/resources/private-lastore-tray.qrc @@ -0,0 +1,6 @@ + + + private-lastore-active_16px.svg + private-lastore-sleep_16px.svg + + diff --git a/src/private-lastore-tray/tipswidget.cpp b/src/private-lastore-tray/tipswidget.cpp new file mode 100644 index 000000000..68a4a63eb --- /dev/null +++ b/src/private-lastore-tray/tipswidget.cpp @@ -0,0 +1,323 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "tipswidget.h" +#include "privatelastoreplugin.h" +#include "common/common/dconfig_helper.h" + +#include +#include +#include +#include + +Q_LOGGING_CATEGORY(dockUpdatePlugin, "org.deepin.dde.dock.update") +#define PADDING 4 +#define SHUTDOWNUPDATESTATUS 5 +static const int BACKUP_START_PROGRESS = 20; +static const int BACKUP_SUCCESS_PROGRESS = 50; + +TipsWidget::TipsWidget(QWidget *parent) + : QFrame(parent) + , m_managerInter(new UpdateDBusProxy(this)) +{ + m_type = TipsWidget::MultiLine; + if (m_managerInter) { + connect(m_managerInter, &UpdateDBusProxy::JobListChanged, this, &TipsWidget::onRefreshJobList); + } +} + +void TipsWidget::setText(const QString &text) +{ + m_text = text; + setFixedSize(fontMetrics().boundingRect(m_text).width() + 20, fontMetrics().boundingRect(m_text).height() + PADDING); + update(); + +#ifndef QT_NO_ACCESSIBILITY + if (accessibleName().isEmpty()) { + QAccessibleEvent event(this, QAccessible::NameChanged); + QAccessible::updateAccessibility(&event); + } +#endif +} + +void TipsWidget::setTextList(const QStringList &textList) +{ + m_type = TipsWidget::MultiLine; + m_textList = textList; + + int width = 0; + int height = 0; + for (const QString& text : m_textList) { + width = qMax(width, fontMetrics().boundingRect(text).width()); + height += fontMetrics().boundingRect(text).height(); + } + + setFixedSize(width + 20, height + PADDING); + + update(); +} + +bool TipsWidget::checkShutdownUpdate() +{ + int lastoreStatus = DConfigHelper::instance()->getConfig("org.deepin.dde.lastore", "org.deepin.dde.lastore", "","lastore-daemon-status", 0).toInt(); + if (lastoreStatus == SHUTDOWNUPDATESTATUS) { + m_textList.append(tr("Download complete")); + m_textList.append(tr("shutdown update")); + return true; + } else { + return false; + } +} + +bool TipsWidget::checkRegularlyUpdate() +{ + QString updateTime = DConfigHelper::instance()->getConfig("org.deepin.dde.lastore", "org.deepin.dde.lastore", "","update-time", "").toString(); + + if (!updateTime.isEmpty()) { + QDateTime dateTime = QDateTime::fromString(updateTime, Qt::ISODate); + if (dateTime.isValid()) { + QString formattedDateTime = dateTime.toString("HH:mm:ss"); + m_textList.append(tr("Download complete")); + QString info = tr("will upgrade at %1"); + m_textList.append(info.arg(formattedDateTime)); + return true; + } + return false; + } + return false; +} + +void TipsWidget::onUpdatePropertiesChanged(const QString& interfaceName, const QVariantMap& changedProperties, const QStringList& invalidatedProperties) +{ + Q_UNUSED(invalidatedProperties) + + if (interfaceName == "org.deepin.dde.Lastore1.Job") { + if (changedProperties.contains("Speed")) { + m_speed = changedProperties.value("Speed").toULongLong(); + } + + if (changedProperties.contains("Proto")) { + m_proto = changedProperties.value("Proto").toString(); + } + } + refreshContent(); + update(); +} + +void TipsWidget::onSetUpdateProgress(double progress) +{ + m_updateProgress = progress; + refreshContent(); + update(); +} + +void TipsWidget::onSetBackUpProgress(double progress) +{ + m_backupProgress = progress; + refreshContent(); + update(); +} + +void TipsWidget::refreshContent() +{ + m_textList.clear(); + if (m_downloadLimitOnChanging) { + m_textList.append(tr("Is changing download speed limit. Please wait")); + return; + } + if (m_managerInter) { + QList jobList = m_managerInter->jobList(); + if (jobList.isEmpty()) { + //当前无任务,需检测是否为任务执行完成状态 + //检查当前是否为关机更新状态 + if (checkShutdownUpdate()) return; + //检查当前是否为定时更新状态 + if (checkRegularlyUpdate()) return; + //检查是否有可更新内容 + QString systemUpgradeStatus = checkHasSystemUpdate(m_managerInter->updateStatus()); + if (systemUpgradeStatus == "downloaded") { + m_textList.append(tr("Download complete.Please go to control-center to check.")); + } else if (systemUpgradeStatus == "notDownload" || systemUpgradeStatus == "isDownloading"|| + systemUpgradeStatus == "downloadPause" || systemUpgradeStatus == "upgradeReady" + || systemUpgradeStatus == "upgrading") { + m_textList.append(tr("Has new version.Please go to check.")); + return; + } + } else { + for (const auto &job : jobList) { + const QString &jobPath = job.path(); + qInfo() << "Path : " << jobPath; + UpdateJobDBusProxy jobInter(jobPath, this); + if (!jobInter.isValid()) { + qWarning() << "Job is invalid"; + continue; + } + QString curJobStatus = jobInter.status(); + QString curJobId = jobInter.id(); + QString curStatus; + if (curJobStatus == "running" || curJobStatus == "ready") { + //当前有任务在进行 + if (curJobId == "backup" && m_backupJobInter) { + QString curProgress = tr("current upgrade process"); + curStatus = tr("backing up"); + m_textList.append(curStatus); + m_textList.append(QString("%1: %2%") + .arg(curProgress) + .arg(QString::number(qRound(m_backupProgress / 0.01)))); + } else if (curJobId == "prepare_dist_upgrade" && m_updateJobInter) { + //任务类型为下载任务,展示下载信息 + curStatus = tr("download"); + QString curProgress = tr("current download process"); + QString curSpeed = tr("current speed"); + m_textList.append(QString("%1, %2: %3%") + .arg(curStatus) + .arg(curProgress) + .arg(QString::number(qRound(m_updateProgress / 0.01)))); + m_textList.append(QString("%1: %2(%3)") + .arg(curSpeed) + .arg(regulateSpeed()) + .arg(m_proto)); + } else if (curJobId == "dist_upgrade" && m_updateJobInter) { + //任务类型为更新任务,展示更新信息 + QString curProgress = tr("current upgrade process"); + curStatus = tr("install"); + m_textList.append(curStatus); + m_textList.append(QString("%1: %2%") + .arg(curProgress) + .arg(QString::number(qRound(m_updateProgress / 0.01)))); + } else if (curJobId == "update_source" && m_updateJobInter) { + QString systemUpgradeStatus = checkHasSystemUpdate(m_managerInter->updateStatus()); + if (systemUpgradeStatus == "notDownload" || systemUpgradeStatus == "isDownloading"|| + systemUpgradeStatus == "downloadPause" || systemUpgradeStatus == "upgradeReady" + || systemUpgradeStatus == "upgrading" || systemUpgradeStatus == "downloaded") { + // 由于每次打开控制中心都会触发检查更新,此时有可能已经是downloaded状态且也有job + m_textList.append(tr("Has new version.Please go to check.")); + } + } + } else { + //无running任务状态下没有监控任务状态的必要,展示标题文案,防止出现空白气泡 + m_speed = 0.0; + if (m_textList.length() != 0) + m_textList.clear(); + continue; + } + } + } + } +} + +QString TipsWidget::regulateSpeed() +{ + QString unitName; + double regulatedProcess; + bool needDecimal = false; //是否需要保留一位小数 + + if (m_speed >= 1024 * 1024) { + regulatedProcess = static_cast(m_speed) / (1024 * 1024); + regulatedProcess = qRound(regulatedProcess * 10) / 10.0; + needDecimal = true; + unitName = "MB/s"; + } else if (m_speed >= 1024) { + regulatedProcess = static_cast(m_speed) / 1024; + regulatedProcess = qRound(regulatedProcess); + unitName = "KB/s"; + } else { + regulatedProcess = static_cast(m_speed); + unitName = "B/s"; + } + return QString("%1%2").arg(regulatedProcess, 0, 'f', needDecimal ? 1 : 0).arg(unitName); +} + +void TipsWidget::onDownloadLimitChanged(bool value) { + m_downloadLimitOnChanging = value; +} + +void TipsWidget::onRefreshJobList(const QList &jobs) +{ + qInfo() << "Job list changed"; + + for (const auto &job : jobs) { + const QString &jobPath = job.path(); + UpdateJobDBusProxy jobInter(jobPath, this); + + //检测到有更新任务 + const QString &id = jobInter.id(); + if (id == "dist_upgrade" || id == "prepare_dist_upgrade") { + m_updateJobInter = new UpdateJobDBusProxy(jobPath, this); + connect(m_updateJobInter, &UpdateJobDBusProxy::ProgressChanged, this, &TipsWidget::onSetUpdateProgress); + } else if (id == "backup") { + m_backupJobInter = new UpdateJobDBusProxy(jobPath, this); + connect(m_backupJobInter, &UpdateJobDBusProxy::ProgressChanged, this, &TipsWidget::onSetBackUpProgress); + } + } +} + + +/** + * @brief TipsWidget::paintEvent 任务栏插件提示信息绘制 + * @param event + */ +void TipsWidget::paintEvent(QPaintEvent *event) +{ + QFrame::paintEvent(event); + + QPainter painter(this); + painter.setPen(QPen(palette().brightText(), 1)); + + QTextOption option; + option.setAlignment(Qt::AlignCenter); + + switch (m_type) { + case SingleLine: { + painter.drawText(rect(), m_text, option); + } + break; + case MultiLine: { + if (m_textList.size() == 0) { + m_textList.append(tr("Enterprise-level Upgrade Management System")); + } + + int x = rect().x(); + int y = rect().y(); + if (m_textList.size() != 1) { + x += 10; + option.setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + } + + int width = 0; + int height = 0; + for (const QString& text : m_textList) { + int lineHeight = fontMetrics().boundingRect(text).height(); + painter.drawText(QRect(x, y, rect().width(), lineHeight), text, option); + y += lineHeight; + + width = qMax(width, fontMetrics().boundingRect(text).width()); + height += fontMetrics().boundingRect(text).height(); + } + setFixedSize(width + 20, height + PADDING); + } break; + } +} + +bool TipsWidget::event(QEvent *event) +{ + if (event->type() == QEvent::FontChange) { + switch (m_type) { + case SingleLine: + { + setText(m_text); + break; + } + case MultiLine: + { + setTextList(m_textList); + break; + } + } + } else if (event->type() == QEvent::MouseButtonRelease + && static_cast(event)->button() == Qt::RightButton) { + return true; + } + return QFrame::event(event); +} diff --git a/src/private-lastore-tray/tipswidget.h b/src/private-lastore-tray/tipswidget.h new file mode 100644 index 000000000..6854a493d --- /dev/null +++ b/src/private-lastore-tray/tipswidget.h @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef TIPSWIDGET_H +#define TIPSWIDGET_H + +#include +#include +#include +#include +#include +#include "common/dbus/updatedbusproxy.h" +#include "common/dbus/updatejobdbusproxy.h" + +inline QString checkHasSystemUpdate(const QString& updateStatus) +{ + QJsonParseError parseError; + QJsonDocument doc = QJsonDocument::fromJson(updateStatus.toUtf8(), &parseError); + if (parseError.error != QJsonParseError::NoError) { + qWarning() << "JSON parse error:" << parseError.errorString(); + return ""; + } + if (!doc.isObject()) { + qWarning() << "JSON is not an object"; + return ""; + } + QJsonObject rootObj = doc.object(); + QJsonObject updateStatusObj = rootObj.value("UpdateStatus").toObject(); + QString systemUpgradeStatus = updateStatusObj.value("system_upgrade").toString(); + return systemUpgradeStatus; +} + +class TipsWidget : public QFrame +{ + Q_OBJECT + enum ShowType + { + SingleLine, + MultiLine + }; +public: + explicit TipsWidget(QWidget *parent = nullptr); + + void setText(const QString &text); + void setTextList(const QStringList &textList); + void refreshContent(); + +protected: + void paintEvent(QPaintEvent *event) override; + bool event(QEvent *event) override; + +private: + bool checkShutdownUpdate(); + bool checkRegularlyUpdate(); + QString regulateSpeed(); + +private slots: + void onDownloadLimitChanged(bool value); + void onRefreshJobList(const QList &jobs); + void onUpdatePropertiesChanged(const QString& interfaceName, + const QVariantMap& changedProperties, + const QStringList& invalidatedProperties); + void onSetUpdateProgress(double progress); + void onSetBackUpProgress(double progress); + +private: + UpdateDBusProxy *m_managerInter = nullptr; + UpdateJobDBusProxy *m_updateJobInter = nullptr; + UpdateJobDBusProxy *m_backupJobInter = nullptr; + QString m_text; + QStringList m_textList; + ShowType m_type; + qulonglong m_speed = 0; + QString m_proto = ""; + bool m_downloadLimitOnChanging = false; + double m_updateProgress = 0.0; + double m_backupProgress = 0.0; +}; + +#endif // TIPSWIDGET_H diff --git a/src/private-lastore-tray/translations/private-lastore-tray.ts b/src/private-lastore-tray/translations/private-lastore-tray.ts new file mode 100644 index 000000000..0e07b6063 --- /dev/null +++ b/src/private-lastore-tray/translations/private-lastore-tray.ts @@ -0,0 +1,83 @@ + + + + + PrivateLastorePlugin + + + Private Lastore + 更新独立客户端 + + + + TipsWidget + + + + Download complete + 更新包下载完成 + + + + shutdown update + 将在下次关机/重启时开始更新 + + + + will upgrade at %1 + 将于%1开始系统更新 + + + + Download complete.Please go to control-center to check. + 更新包下载完成,点击图标进入更新界面进行查看与安装更新 + + + + Is changing download speed limit. Please wait + 下载限速配置切换中,切换完成后将会继续下载更新资源 + + + + + Has new version.Please go to check. + 有新版本,点击图标查看 + + + + + current upgrade process + 更新进度 + + + + backing up + 备份中 + + + + download + 更新包下载中 + + + + current download process + 已下载 + + + + current speed + 下载速度 + + + + install + 系统更新中,请勿关闭计算机 + + + + Enterprise-level Upgrade Management System + 企业级更新管理系统 + + + diff --git a/src/private-lastore-tray/translations/private-lastore-tray_zh_CN.ts b/src/private-lastore-tray/translations/private-lastore-tray_zh_CN.ts new file mode 100644 index 000000000..0e07b6063 --- /dev/null +++ b/src/private-lastore-tray/translations/private-lastore-tray_zh_CN.ts @@ -0,0 +1,83 @@ + + + + + PrivateLastorePlugin + + + Private Lastore + 更新独立客户端 + + + + TipsWidget + + + + Download complete + 更新包下载完成 + + + + shutdown update + 将在下次关机/重启时开始更新 + + + + will upgrade at %1 + 将于%1开始系统更新 + + + + Download complete.Please go to control-center to check. + 更新包下载完成,点击图标进入更新界面进行查看与安装更新 + + + + Is changing download speed limit. Please wait + 下载限速配置切换中,切换完成后将会继续下载更新资源 + + + + + Has new version.Please go to check. + 有新版本,点击图标查看 + + + + + current upgrade process + 更新进度 + + + + backing up + 备份中 + + + + download + 更新包下载中 + + + + current download process + 已下载 + + + + current speed + 下载速度 + + + + install + 系统更新中,请勿关闭计算机 + + + + Enterprise-level Upgrade Management System + 企业级更新管理系统 + + +