Introduce system based updates and add progress and changelog

This commit is contained in:
Simon Stürz 2026-02-03 12:56:23 +01:00
parent 8401af9529
commit 04bc050142
6 changed files with 442 additions and 145 deletions

View File

@ -25,20 +25,23 @@
#include "systemcontroller.h" #include "systemcontroller.h"
#include "types/package.h" #include "types/package.h"
#include "types/repository.h"
#include "types/packages.h" #include "types/packages.h"
#include "types/repositories.h" #include "types/repositories.h"
#include "types/repository.h"
#include <QTimeZone>
#include <QJsonDocument> #include <QJsonDocument>
#include <QMetaEnum>
#include <QTimeZone>
#include "logging.h" #include "logging.h"
NYMEA_LOGGING_CATEGORY(dcSystemController, "SystemController") NYMEA_LOGGING_CATEGORY(dcSystemController, "SystemController")
SystemController::SystemController(JsonRpcClient *jsonRpcClient, QObject *parent): SystemController::SystemController(JsonRpcClient *jsonRpcClient, QObject *parent)
QObject(parent), : QObject(parent)
m_jsonRpcClient(jsonRpcClient) , m_jsonRpcClient(jsonRpcClient)
{ {
m_jsonRpcClient->registerNotificationHandler(this, "System", "notificationReceived"); m_jsonRpcClient->registerNotificationHandler(this, "System", "notificationReceived");
m_packages = new Packages(this); m_packages = new Packages(this);
m_repositories = new Repositories(this); m_repositories = new Repositories(this);
@ -73,6 +76,11 @@ bool SystemController::updateManagementAvailable() const
return m_updateManagementAvailable; return m_updateManagementAvailable;
} }
SystemController::UpdateType SystemController::updateManagementType() const
{
return m_updateManagementType;
}
int SystemController::restart() int SystemController::restart()
{ {
return m_jsonRpcClient->sendCommand("System.Restart", this, "restartResponse"); return m_jsonRpcClient->sendCommand("System.Restart", this, "restartResponse");
@ -98,6 +106,11 @@ bool SystemController::updateRunning() const
return m_updateRunning; return m_updateRunning;
} }
int SystemController::updateProgress() const
{
return m_updateProgress;
}
void SystemController::checkForUpdates() void SystemController::checkForUpdates()
{ {
m_jsonRpcClient->sendCommand("System.CheckForUpdates"); m_jsonRpcClient->sendCommand("System.CheckForUpdates");
@ -172,7 +185,7 @@ QString SystemController::serverTimeZone() const
// NOTE: Ideally we'd just set the TimeZone of our serverTime prooperly, however, there's a bug on Android // NOTE: Ideally we'd just set the TimeZone of our serverTime prooperly, however, there's a bug on Android
// Which doesn't allow to create QTimeZone objects by IANA id.... So, let's keep that separated in a string // Which doesn't allow to create QTimeZone objects by IANA id.... So, let's keep that separated in a string
// https://bugreports.qt.io/browse/QTBUG-83438 // https://bugreports.qt.io/browse/QTBUG-83438
// return m_serverTime.timeZone().id(); // return m_serverTime.timeZone().id();
return m_serverTimeZone; return m_serverTimeZone;
} }
@ -207,12 +220,26 @@ QString SystemController::deviceSerialNumber() const
void SystemController::getCapabilitiesResponse(int /*commandId*/, const QVariantMap &data) void SystemController::getCapabilitiesResponse(int /*commandId*/, const QVariantMap &data)
{ {
qCDebug(dcSystemController()) << data;
m_powerManagementAvailable = data.value("powerManagement").toBool(); m_powerManagementAvailable = data.value("powerManagement").toBool();
emit powerManagementAvailableChanged(); emit powerManagementAvailableChanged();
m_updateManagementAvailable = data.value("updateManagement").toBool(); m_updateManagementAvailable = data.value("updateManagement").toBool();
emit updateManagementAvailableChanged(); emit updateManagementAvailableChanged();
// Since API version 8.5
if (data.contains("updateManagementType")) {
QMetaEnum updateTypeEnum = QMetaEnum::fromType<SystemController::UpdateType>();
m_updateManagementType = static_cast<SystemController::UpdateType>(updateTypeEnum.keyToValue(data.value("updateManagementType").toByteArray()));
} else {
// Property exists since API 8.5, if there is an update management available, default to UpdateTypePackageManager
if (m_updateManagementAvailable) {
m_updateManagementType = UpdateTypePackageManager;
} else {
m_updateManagementType = UpdateTypeNone;
}
}
m_timeManagementAvailable = data.value("timeManagement").toBool(); m_timeManagementAvailable = data.value("timeManagement").toBool();
emit timeManagementAvailableChanged(); emit timeManagementAvailableChanged();
@ -226,7 +253,15 @@ void SystemController::getCapabilitiesResponse(int /*commandId*/, const QVariant
m_jsonRpcClient->sendCommand("System.GetTime", this, "getServerTimeResponse"); m_jsonRpcClient->sendCommand("System.GetTime", this, "getServerTimeResponse");
} }
qCDebug(dcSystemController) << "nymea:core capabilities: Power management:" << m_powerManagementAvailable << "Update management:" << m_updateManagementAvailable << "Time management:" << m_timeManagementAvailable; qCDebug(dcSystemController())
<< "nymea:core capabilities: Power management:"
<< m_powerManagementAvailable
<< "Update management:"
<< m_updateManagementAvailable
<< "Update management type:"
<< m_updateManagementType
<< "Time management:"
<< m_timeManagementAvailable;
} }
void SystemController::getUpdateStatusResponse(int /*commandId*/, const QVariantMap &data) void SystemController::getUpdateStatusResponse(int /*commandId*/, const QVariantMap &data)
@ -234,13 +269,17 @@ void SystemController::getUpdateStatusResponse(int /*commandId*/, const QVariant
qCDebug(dcSystemController()) << "Update status:" << qUtf8Printable(QJsonDocument::fromVariant(data).toJson(QJsonDocument::Indented)); qCDebug(dcSystemController()) << "Update status:" << qUtf8Printable(QJsonDocument::fromVariant(data).toJson(QJsonDocument::Indented));
m_updateManagementBusy = data.value("busy").toBool(); m_updateManagementBusy = data.value("busy").toBool();
m_updateRunning = data.value("updateRunning").toBool(); m_updateRunning = data.value("updateRunning").toBool();
m_updateProgress = data.value("updateProgress", -1).toInt(); // Since API 8.5, optional
emit updateRunningChanged(); emit updateRunningChanged();
emit updateManagementBusyChanged();
emit updateProgressChanged();
} }
void SystemController::getPackagesResponse(int commandId, const QVariantMap &data) void SystemController::getPackagesResponse(int commandId, const QVariantMap &data)
{ {
Q_UNUSED(commandId) Q_UNUSED(commandId)
qCDebug(dcSystemController) << "Packages:" << qUtf8Printable(QJsonDocument::fromVariant(data).toJson(QJsonDocument::Indented)); qCDebug(dcSystemController()) << "Packages:" << qUtf8Printable(QJsonDocument::fromVariant(data).toJson(QJsonDocument::Indented));
foreach (const QVariant &packageVariant, data.value("packages").toList()) { foreach (const QVariant &packageVariant, data.value("packages").toList()) {
QString id = packageVariant.toMap().value("id").toString(); QString id = packageVariant.toMap().value("id").toString();
QString displayName = packageVariant.toMap().value("displayName").toString(); QString displayName = packageVariant.toMap().value("displayName").toString();
@ -269,12 +308,12 @@ void SystemController::getRepositoriesResponse(int /*commandId*/, const QVariant
void SystemController::removePackageResponse(int commandId, const QVariantMap &params) void SystemController::removePackageResponse(int commandId, const QVariantMap &params)
{ {
qCDebug(dcSystemController) << "Remove result" << commandId << params; qCDebug(dcSystemController()) << "Remove result" << commandId << params;
} }
void SystemController::enableRepositoryResponse(int commandId, const QVariantMap &params) void SystemController::enableRepositoryResponse(int commandId, const QVariantMap &params)
{ {
qCDebug(dcSystemController) << "Enable repo response" << params; qCDebug(dcSystemController()) << "Enable repo response" << params;
emit enableRepositoryFinished(commandId, params.value("success").toBool()); emit enableRepositoryFinished(commandId, params.value("success").toBool());
} }
@ -286,7 +325,7 @@ void SystemController::getServerTimeResponse(int commandId, const QVariantMap &p
// Which doesn't allow to create QTimeZone objects by IANA id.... So, let's keep that separated in a string // Which doesn't allow to create QTimeZone objects by IANA id.... So, let's keep that separated in a string
// https://bugreports.qt.io/browse/QTBUG-83438 // https://bugreports.qt.io/browse/QTBUG-83438
// m_serverTime.setTimeZone(QTimeZone(params.value("timeZone").toString().toUtf8())); // m_serverTime.setTimeZone(QTimeZone(params.value("timeZone").toString().toUtf8()));
m_serverTimeZone = params.value("timeZone").toString(); m_serverTimeZone = params.value("timeZone").toString();
emit serverTimeZoneChanged(); emit serverTimeZoneChanged();
@ -302,12 +341,12 @@ void SystemController::getServerTimeResponse(int commandId, const QVariantMap &p
emit automaticTimeAvailableChanged(); emit automaticTimeAvailableChanged();
m_automaticTime = params.value("automaticTime").toBool(); m_automaticTime = params.value("automaticTime").toBool();
emit automaticTimeChanged(); emit automaticTimeChanged();
qCDebug(dcSystemController) << "Server time:" << m_serverTime << "Automatic Time available:" << m_automaticTimeAvailable << "Automatic time:" << m_automaticTime; qCDebug(dcSystemController()) << "Server time:" << m_serverTime << "Automatic Time available:" << m_automaticTimeAvailable << "Automatic time:" << m_automaticTime;
} }
void SystemController::setTimeResponse(int commandId, const QVariantMap &params) void SystemController::setTimeResponse(int commandId, const QVariantMap &params)
{ {
qCDebug(dcSystemController) << "set time response" << commandId << params; qCDebug(dcSystemController()) << "set time response" << commandId << params;
} }
void SystemController::restartResponse(int commandId, const QVariantMap &params) void SystemController::restartResponse(int commandId, const QVariantMap &params)
@ -338,18 +377,26 @@ void SystemController::getSystemInfoResponse(int commandId, const QVariantMap &p
void SystemController::notificationReceived(const QVariantMap &data) void SystemController::notificationReceived(const QVariantMap &data)
{ {
QString notification = data.value("notification").toString(); QString notification = data.value("notification").toString();
const QVariantMap paramsMap = data.value("params").toMap();
if (notification == "System.UpdateStatusChanged") { if (notification == "System.UpdateStatusChanged") {
qCDebug(dcSystemController) << "System.UpdateStatusChanged:" << data.value("params").toMap(); qCDebug(dcSystemController()) << "System.UpdateStatusChanged:" << paramsMap;
if (m_updateManagementBusy != data.value("params").toMap().value("busy").toBool()) { if (m_updateManagementBusy != paramsMap.value("busy").toBool()) {
m_updateManagementBusy = data.value("params").toMap().value("busy").toBool(); m_updateManagementBusy = paramsMap.value("busy").toBool();
emit updateManagementBusyChanged(); emit updateManagementBusyChanged();
} }
if (m_updateRunning != data.value("params").toMap().value("updateRunning").toBool()) { if (m_updateRunning != paramsMap.value("updateRunning").toBool()) {
m_updateRunning = data.value("params").toMap().value("updateRunning").toBool(); m_updateRunning = paramsMap.value("updateRunning").toBool();
emit updateRunningChanged(); emit updateRunningChanged();
} }
// Since API 8.5, optional, not supported or not running = -1
if (m_updateProgress != paramsMap.value("updateProgress", -1).toInt()) {
m_updateProgress = paramsMap.value("updateProgress").toInt();
emit updateProgressChanged();
}
} else if (notification == "System.PackageAdded") { } else if (notification == "System.PackageAdded") {
QVariantMap packageMap = data.value("params").toMap().value("package").toMap(); QVariantMap packageMap = paramsMap.value("package").toMap();
QString id = packageMap.value("id").toString(); QString id = packageMap.value("id").toString();
QString displayName = packageMap.value("displayName").toString(); QString displayName = packageMap.value("displayName").toString();
Package *p = new Package(id, displayName); Package *p = new Package(id, displayName);
@ -362,7 +409,7 @@ void SystemController::notificationReceived(const QVariantMap &data)
p->setCanRemove(packageMap.value("canRemove").toBool()); p->setCanRemove(packageMap.value("canRemove").toBool());
m_packages->addPackage(p); m_packages->addPackage(p);
} else if (notification == "System.PackageChanged") { } else if (notification == "System.PackageChanged") {
QVariantMap packageMap = data.value("params").toMap().value("package").toMap(); QVariantMap packageMap = paramsMap.value("package").toMap();
QString id = packageMap.value("id").toString(); QString id = packageMap.value("id").toString();
Package *p = m_packages->getPackage(id); Package *p = m_packages->getPackage(id);
if (!p) { if (!p) {
@ -377,17 +424,17 @@ void SystemController::notificationReceived(const QVariantMap &data)
p->setRollbackAvailable(packageMap.value("rollbackAvailable").toBool()); p->setRollbackAvailable(packageMap.value("rollbackAvailable").toBool());
p->setCanRemove(packageMap.value("canRemove").toBool()); p->setCanRemove(packageMap.value("canRemove").toBool());
} else if (notification == "System.PackageRemoved") { } else if (notification == "System.PackageRemoved") {
QString packageId = data.value("params").toMap().value("packageId").toString(); QString packageId = paramsMap.value("packageId").toString();
m_packages->removePackage(packageId); m_packages->removePackage(packageId);
} else if (notification == "System.RepositoryAdded") { } else if (notification == "System.RepositoryAdded") {
QVariantMap repoMap = data.value("params").toMap().value("repository").toMap(); QVariantMap repoMap = paramsMap.value("repository").toMap();
QString id = repoMap.value("id").toString(); QString id = repoMap.value("id").toString();
QString displayName = repoMap.value("displayName").toString(); QString displayName = repoMap.value("displayName").toString();
Repository *repo = new Repository(id, displayName); Repository *repo = new Repository(id, displayName);
repo->setEnabled(repoMap.value("enabled").toBool()); repo->setEnabled(repoMap.value("enabled").toBool());
m_repositories->addRepository(repo); m_repositories->addRepository(repo);
} else if (notification == "System.RepositoryChanged") { } else if (notification == "System.RepositoryChanged") {
QVariantMap repoMap = data.value("params").toMap().value("repository").toMap(); QVariantMap repoMap = paramsMap.value("repository").toMap();
QString id = repoMap.value("id").toString(); QString id = repoMap.value("id").toString();
Repository *repo = m_repositories->getRepository(id); Repository *repo = m_repositories->getRepository(id);
if (!repo) { if (!repo) {
@ -396,16 +443,36 @@ void SystemController::notificationReceived(const QVariantMap &data)
} }
repo->setEnabled(repoMap.value("enabled").toBool()); repo->setEnabled(repoMap.value("enabled").toBool());
} else if (notification == "System.RepositoryRemoved") { } else if (notification == "System.RepositoryRemoved") {
QString repositoryId = data.value("params").toMap().value("repositoryId").toString(); QString repositoryId = paramsMap.value("repositoryId").toString();
m_repositories->removeRepository(repositoryId); m_repositories->removeRepository(repositoryId);
} else if (notification == "System.CapabilitiesChanged") { } else if (notification == "System.CapabilitiesChanged") {
m_powerManagementAvailable = data.value("params").toMap().value("powerManagement").toBool(); m_powerManagementAvailable = paramsMap.value("powerManagement").toBool();
m_updateManagementAvailable = data.value("params").toMap().value("updateManagement").toBool(); m_updateManagementAvailable = paramsMap.value("updateManagement").toBool();
qWarning() << "System capabilites changed: power management:" << m_powerManagementAvailable << "update management:" << m_updateManagementAvailable; if (paramsMap.contains("updateManagementType")) {
QMetaEnum updateTypeEnum = QMetaEnum::fromType<SystemController::UpdateType>();
m_updateManagementType = static_cast<SystemController::UpdateType>(updateTypeEnum.keyToValue(paramsMap.value("updateManagementType").toByteArray()));
} else {
// Property exists since API 8.5, if there is an update management available, default to UpdateTypePackageManager
if (m_updateManagementAvailable) {
m_updateManagementType = UpdateTypePackageManager;
} else {
m_updateManagementType = UpdateTypeNone;
}
}
qCDebug(dcSystemController())
<< "System capabilites changed: power management:"
<< m_powerManagementAvailable
<< "update management:"
<< m_updateManagementAvailable
<< "update management type:"
<< m_updateManagementType;
emit powerManagementAvailableChanged(); emit powerManagementAvailableChanged();
emit updateManagementAvailableChanged(); emit updateManagementAvailableChanged();
emit updateManagementTypeChanged();
} else if (notification == "System.TimeConfigurationChanged") { } else if (notification == "System.TimeConfigurationChanged") {
qCDebug(dcSystemController) << "System time configuration changed" << data.value("params").toMap().value("timeZone").toByteArray(); qCDebug(dcSystemController()) << "System time configuration changed" << data.value("params").toMap().value("timeZone").toByteArray();
// NOTE: Ideally we'd just set the TimeZone of our serverTime prooperly, however, there's a bug on Android // NOTE: Ideally we'd just set the TimeZone of our serverTime prooperly, however, there's a bug on Android
// Which doesn't allow to create QTimeZone objects by IANA id.... So, let's keep that separated in a string // Which doesn't allow to create QTimeZone objects by IANA id.... So, let's keep that separated in a string

View File

@ -35,14 +35,18 @@ class SystemController : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool powerManagementAvailable READ powerManagementAvailable NOTIFY powerManagementAvailableChanged) Q_PROPERTY(bool powerManagementAvailable READ powerManagementAvailable NOTIFY powerManagementAvailableChanged)
// Whether the update mechanism is available in the connected core // Whether the update mechanism is available in the connected core
Q_PROPERTY(bool updateManagementAvailable READ updateManagementAvailable NOTIFY updateManagementAvailableChanged) Q_PROPERTY(bool updateManagementAvailable READ updateManagementAvailable NOTIFY updateManagementAvailableChanged)
Q_PROPERTY(UpdateType updateManagementType READ updateManagementType NOTIFY updateManagementTypeChanged FINAL)
Q_PROPERTY(bool timeManagementAvailable READ timeManagementAvailable NOTIFY timeManagementAvailableChanged) Q_PROPERTY(bool timeManagementAvailable READ timeManagementAvailable NOTIFY timeManagementAvailableChanged)
Q_PROPERTY(bool updateManagementBusy READ updateManagementBusy NOTIFY updateManagementBusyChanged) Q_PROPERTY(bool updateManagementBusy READ updateManagementBusy NOTIFY updateManagementBusyChanged)
Q_PROPERTY(bool updateRunning READ updateRunning NOTIFY updateRunningChanged) Q_PROPERTY(bool updateRunning READ updateRunning NOTIFY updateRunningChanged)
Q_PROPERTY(Packages* packages READ packages CONSTANT) Q_PROPERTY(int updateProgress READ updateProgress NOTIFY updateProgressChanged)
Q_PROPERTY(Repositories* repositories READ repositories CONSTANT)
Q_PROPERTY(Packages *packages READ packages CONSTANT)
Q_PROPERTY(Repositories *repositories READ repositories CONSTANT)
Q_PROPERTY(QDateTime serverTime READ serverTime WRITE setServerTime NOTIFY serverTimeChanged) Q_PROPERTY(QDateTime serverTime READ serverTime WRITE setServerTime NOTIFY serverTimeChanged)
Q_PROPERTY(QString serverTimeZone READ serverTimeZone WRITE setServerTimeZone NOTIFY serverTimeZoneChanged) Q_PROPERTY(QString serverTimeZone READ serverTimeZone WRITE setServerTimeZone NOTIFY serverTimeZoneChanged)
@ -53,23 +57,34 @@ class SystemController : public QObject
Q_PROPERTY(QString deviceSerialNumber READ deviceSerialNumber NOTIFY deviceSerialNumberChanged) Q_PROPERTY(QString deviceSerialNumber READ deviceSerialNumber NOTIFY deviceSerialNumberChanged)
public: public:
enum UpdateType {
UpdateTypeNone,
UpdateTypeSystem,
UpdateTypePackageManager
};
Q_ENUM(UpdateType)
explicit SystemController(JsonRpcClient *jsonRpcClient, QObject *parent = nullptr); explicit SystemController(JsonRpcClient *jsonRpcClient, QObject *parent = nullptr);
void init(); void init();
bool powerManagementAvailable() const; bool powerManagementAvailable() const;
Q_INVOKABLE int restart(); Q_INVOKABLE int restart();
Q_INVOKABLE int reboot(); Q_INVOKABLE int reboot();
Q_INVOKABLE int shutdown(); Q_INVOKABLE int shutdown();
bool updateManagementAvailable() const; bool updateManagementAvailable() const;
UpdateType updateManagementType() const;
bool updateManagementBusy() const; bool updateManagementBusy() const;
bool updateRunning() const; bool updateRunning() const;
int updateProgress() const;
Q_INVOKABLE void checkForUpdates(); Q_INVOKABLE void checkForUpdates();
Packages* packages() const; Packages *packages() const;
Q_INVOKABLE void updatePackages(const QString packageId = QString()); Q_INVOKABLE void updatePackages(const QString packageId = QString());
Q_INVOKABLE void removePackages(const QString packageId = QString()); Q_INVOKABLE void removePackages(const QString packageId = QString());
Repositories* repositories() const; Repositories *repositories() const;
Q_INVOKABLE int enableRepository(const QString &id, bool enabled); Q_INVOKABLE int enableRepository(const QString &id, bool enabled);
bool timeManagementAvailable() const; bool timeManagementAvailable() const;
@ -87,9 +102,11 @@ public:
signals: signals:
void powerManagementAvailableChanged(); void powerManagementAvailableChanged();
void updateManagementAvailableChanged(); void updateManagementAvailableChanged();
void updateManagementTypeChanged();
void timeManagementAvailableChanged(); void timeManagementAvailableChanged();
void updateManagementBusyChanged(); void updateManagementBusyChanged();
void updateRunningChanged(); void updateRunningChanged();
void updateProgressChanged();
void enableRepositoryFinished(int id, bool success); void enableRepositoryFinished(int id, bool success);
void serverTimeChanged(); void serverTimeChanged();
void serverTimeZoneChanged(); void serverTimeZoneChanged();
@ -117,7 +134,6 @@ private slots:
void notificationReceived(const QVariantMap &data); void notificationReceived(const QVariantMap &data);
protected: protected:
void timerEvent(QTimerEvent *event) override; void timerEvent(QTimerEvent *event) override;
@ -126,10 +142,12 @@ private:
bool m_powerManagementAvailable = false; bool m_powerManagementAvailable = false;
bool m_updateManagementAvailable = false; bool m_updateManagementAvailable = false;
UpdateType m_updateManagementType = UpdateTypeNone;
bool m_timeManagementAvailable = false; bool m_timeManagementAvailable = false;
bool m_updateManagementBusy = false; bool m_updateManagementBusy = false;
bool m_updateRunning = false; bool m_updateRunning = false;
int m_updateProgress = -1;
Packages *m_packages = nullptr; Packages *m_packages = nullptr;
Repositories *m_repositories = nullptr; Repositories *m_repositories = nullptr;

View File

@ -69,12 +69,16 @@ SettingsPageBase {
Layout.fillWidth: true Layout.fillWidth: true
Layout.leftMargin: app.margins Layout.leftMargin: app.margins
Layout.rightMargin: app.margins Layout.rightMargin: app.margins
visible: !kioskMode && Qt.platform.os !== "ios" visible: !kioskMode && Qt.platform.os !== "ios"
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("View mode") text: qsTr("View mode")
} }
ComboBox { ComboBox {
Layout.minimumWidth: 200
model: [qsTr("Windowed"), qsTr("Maximized"), qsTr("Fullscreen"), qsTr("Automatic")] model: [qsTr("Windowed"), qsTr("Maximized"), qsTr("Fullscreen"), qsTr("Automatic")]
currentIndex: { currentIndex: {
switch (settings.viewMode) { switch (settings.viewMode) {

View File

@ -64,6 +64,15 @@ Rectangle {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
font.pixelSize: app.largeFont font.pixelSize: app.largeFont
} }
ProgressBar {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
visible: engine.systemController.updateProgress >= 0
value: engine.systemController.updateProgress / 100.0
}
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins * 2 Layout.margins: app.margins * 2

View File

@ -26,6 +26,7 @@ import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Controls.Material import QtQuick.Controls.Material
import QtQuick.Layouts import QtQuick.Layouts
import Nymea import Nymea
import "../components" import "../components"
@ -48,12 +49,12 @@ Page {
Connections { Connections {
target: engine.systemController target: engine.systemController
onEnableRepositoryFinished: { onEnableRepositoryFinished: (id, success) => {
if (!success) { if (!success) {
var popup = errorDialogComponent.createObject(app, {errorCode: qsTr("Failure adding repository.") }) var popup = errorDialogComponent.createObject(app, {errorCode: qsTr("Failure adding repository.") })
popup.open(); popup.open();
} }
} }
} }
PackagesFilterModel { PackagesFilterModel {
@ -62,151 +63,350 @@ Page {
updatesOnly: true updatesOnly: true
} }
ColumnLayout { Loader {
id: contentColumn id: updateTypeLoader
anchors.fill: parent anchors.fill: parent
sourceComponent: engine.systemController.updateManagementType === SystemController.UpdateTypeSystem ?
updateSystemComponent :
updatePackageManagerComponent
Item { }
Layout.fillHeight: true
Layout.fillWidth: true Component {
visible: updatesModel.count === 0 id: updateSystemComponent
ColumnLayout {
id: systemUpdateContentColumn
property Package systemPackage: engine.systemController.packages.get(0)
property bool changelogAvailable: systemUpdateContentColumn.systemPackage.changelog.length !== 0
anchors.fill: parent
anchors.margins: app.margins
Item {
Layout.fillHeight: true
Layout.fillWidth: true
visible: updatesModel.count === 0
ColumnLayout {
width: parent.width
anchors.centerIn: parent
spacing: app.margins * 2
ColorIcon {
Layout.preferredHeight: Style.iconSize * 4
Layout.preferredWidth: height
Layout.alignment: Qt.AlignHCenter
name: "qrc:/icons/system-update.svg"
color: Style.accentColor
RotationAnimation on rotation {
from: 0; to: 360
duration: 2000
running: engine.systemController.updateManagementBusy
loops: Animation.Infinite
}
}
Label {
Layout.fillWidth: true
Layout.leftMargin: Style.margins
Layout.rightMargin: Style.margins
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
text: engine.systemController.updateManagementBusy ? qsTr("Checking for updates...") : qsTr("Your system is up to date.")
}
Label {
id: versionLabel
Layout.alignment: Qt.AlignHCenter
wrapMode: Text.WordWrap
text: qsTr("Version:") + " " + systemUpdateContentColumn.systemPackage.installedVersion
MouseArea {
anchors.fill: parent
onClicked: {
PlatformHelper.toClipBoard(versionLabel.text);
ToolTip.show(qsTr("Version copied to clipboard"), 500);
}
}
}
Button {
Layout.fillWidth: true
Layout.leftMargin: Style.margins
Layout.rightMargin: Style.margins
text: qsTr("Check for updates")
enabled: !engine.systemController.updateManagementBusy
onClicked: {
engine.systemController.checkForUpdates()
}
}
}
}
ColumnLayout { ColumnLayout {
width: parent.width Layout.fillHeight: true
anchors.centerIn: parent Layout.fillWidth: true
spacing: app.margins * 2 visible: updatesModel.count > 0
ColorIcon { RowLayout {
Layout.preferredHeight: Style.iconSize * 4 Layout.margins: app.margins
Layout.preferredWidth: height spacing: app.margins
Layout.alignment: Qt.AlignHCenter
name: "qrc:/icons/system-update.svg" ColorIcon {
color: Style.accentColor Layout.preferredHeight: Style.iconSize * 2
RotationAnimation on rotation { Layout.preferredWidth: height
from: 0; to: 360 name: "qrc:/icons/system-update.svg"
duration: 2000 color: Style.accentColor
running: engine.systemController.updateManagementBusy RotationAnimation on rotation {
loops: Animation.Infinite from: 0; to: 360
duration: 2000
running: engine.systemController.updateManagementBusy
loops: Animation.Infinite
}
} }
Label {
Layout.fillWidth: true
text: engine.systemController.updateManagementBusy ? qsTr("Checking for updates...") : qsTr("%1 update available").arg(Configuration.systemName)
}
}
Button {
Layout.fillWidth: true
text: qsTr("Check again")
enabled: !engine.systemController.updateManagementBusy
onClicked: engine.systemController.checkForUpdates()
}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("Installed version:")
subText: systemUpdateContentColumn.systemPackage.installedVersion
progressive: false
}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("Candidate version:")
subText: systemUpdateContentColumn.systemPackage.candidateVersion
visible: systemUpdateContentColumn.systemPackage.updateAvailable || systemUpdateContentColumn.systemPackage.installedVersion.length === 0
progressive: false
}
ThinDivider {
visible: changelogAvailable
} }
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
Layout.margins: app.margins Layout.leftMargin: Style.margins
horizontalAlignment: Text.AlignHCenter Layout.rightMargin: Style.margins
visible: changelogAvailable
text: qsTr("Update changelog:")
}
Label {
Layout.fillWidth: true
Layout.leftMargin: Style.margins
Layout.rightMargin: Style.margins
Layout.alignment: Qt.AlignHCenter
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: engine.systemController.updateManagementBusy ? qsTr("Checking for updates...") : qsTr("Your system is up to date.") visible: changelogAvailable
text: systemPackage.changelog
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
} }
Button { Button {
Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true
text: qsTr("Check for updates") //Layout.leftMargin: Style.margins
//Layout.rightMargin: Style.margins
text: qsTr("Update")
visible: updatesModel.count > 0
enabled: !engine.systemController.updateManagementBusy enabled: !engine.systemController.updateManagementBusy
onClicked: { onClicked: {
engine.systemController.checkForUpdates() var dialog = Qt.createComponent(Qt.resolvedUrl("../components/NymeaDialog.qml"));
var text = qsTr("This will start a system update. Note that the update might take several minutes and your %1 system might not be functioning properly during this time and restart during the process.\nDo you want to proceed?").arg(Configuration.systemName)
var popup = dialog.createObject(app,
{
headerIcon: "qrc:/icons/system-update.svg",
title: qsTr("System update"),
text: text,
standardButtons: Dialog.Ok | Dialog.Cancel
});
popup.open();
popup.accepted.connect(function() {
engine.systemController.updatePackages()
})
} }
} }
} }
} }
}
Component {
id: updatePackageManagerComponent
ColumnLayout { ColumnLayout {
Layout.fillHeight: true id: contentColumn
Layout.fillWidth: true anchors.fill: parent
visible: updatesModel.count > 0
RowLayout { Item {
Layout.margins: app.margins Layout.fillHeight: true
spacing: app.margins Layout.fillWidth: true
Layout.leftMargin: Style.margins
Layout.rightMargin: Style.margins
ColorIcon { visible: updatesModel.count === 0
Layout.preferredHeight: Style.iconSize * 2
Layout.preferredWidth: height
name: "qrc:/icons/system-update.svg"
color: Style.accentColor
RotationAnimation on rotation {
from: 0; to: 360
duration: 2000
running: engine.systemController.updateManagementBusy
loops: Animation.Infinite
}
}
ColumnLayout { ColumnLayout {
width: parent.width
anchors.centerIn: parent
spacing: app.margins * 2
ColorIcon {
Layout.preferredHeight: Style.iconSize * 4
Layout.preferredWidth: height
Layout.alignment: Qt.AlignHCenter
name: "qrc:/icons/system-update.svg"
color: Style.accentColor
RotationAnimation on rotation {
from: 0; to: 360
duration: 2000
running: engine.systemController.updateManagementBusy
loops: Animation.Infinite
}
}
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: engine.systemController.updateManagementBusy ? qsTr("Checking for updates...") : qsTr("%n update(s) available", "", updatesModel.count) horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
text: engine.systemController.updateManagementBusy ? qsTr("Checking for updates...") : qsTr("Your system is up to date.")
} }
GridLayout {
columns: width > 250 ? 2 : 1 Button {
Button { Layout.fillWidth: true
text: qsTr("Check for updates")
enabled: !engine.systemController.updateManagementBusy
onClicked: engine.systemController.checkForUpdates()
}
}
}
ColumnLayout {
Layout.fillHeight: true
Layout.fillWidth: true
visible: updatesModel.count > 0
RowLayout {
spacing: Style.margins
Layout.leftMargin: Style.margins
Layout.rightMargin: Style.margins
ColorIcon {
Layout.preferredHeight: Style.iconSize * 2
Layout.preferredWidth: height
name: "qrc:/icons/system-update.svg"
color: Style.accentColor
RotationAnimation on rotation {
from: 0; to: 360
duration: 2000
running: engine.systemController.updateManagementBusy
loops: Animation.Infinite
}
}
ColumnLayout {
Label {
Layout.fillWidth: true Layout.fillWidth: true
text: qsTr("Check again") text: engine.systemController.updateManagementBusy ? qsTr("Checking for updates...") : qsTr("%n update(s) available", "", updatesModel.count)
enabled: !engine.systemController.updateManagementBusy }
onClicked: { GridLayout {
engine.systemController.checkForUpdates() columns: width > 250 ? 2 : 1
Button {
Layout.fillWidth: true
text: qsTr("Check again")
enabled: !engine.systemController.updateManagementBusy
onClicked: {
engine.systemController.checkForUpdates()
}
}
Button {
Layout.fillWidth: true
text: qsTr("Update all")
visible: updatesModel.count > 0
enabled: !engine.systemController.updateManagementBusy
onClicked: {
var dialog = Qt.createComponent(Qt.resolvedUrl("../components/NymeaDialog.qml"));
var text = qsTr("This will start a system update. Note that the update might take several minutes and your %1 system might not be functioning properly during this time and restart during the process.\nDo you want to proceed?").arg(Configuration.systemName)
var popup = dialog.createObject(app,
{
headerIcon: "qrc:/icons/system-update.svg",
title: qsTr("System update"),
text: text,
standardButtons: Dialog.Ok | Dialog.Cancel
});
popup.open();
popup.accepted.connect(function() {
engine.systemController.updatePackages()
})
}
} }
} }
Button { }
Layout.fillWidth: true
text: qsTr("Update all") }
visible: updatesModel.count > 0
enabled: !engine.systemController.updateManagementBusy ThinDivider {}
onClicked: {
var dialog = Qt.createComponent(Qt.resolvedUrl("../components/NymeaDialog.qml")); ListView {
var text = qsTr("This will start a system update. Note that the update might take several minutes and your %1 system might not be functioning properly during this time and restart during the process.\nDo you want to proceed?").arg(Configuration.systemName) Layout.fillWidth: true
var popup = dialog.createObject(app, Layout.fillHeight: true
{ visible: count > 0
headerIcon: "qrc:/icons/system-update.svg", model: updatesModel
title: qsTr("System update"), clip: true
text: text, delegate: NymeaSwipeDelegate {
standardButtons: Dialog.Ok | Dialog.Cancel width: parent.width
}); text: model.displayName
popup.open(); subText: model.candidateVersion
popup.accepted.connect(function() { prominentSubText: false
engine.systemController.updatePackages() iconName: model.updateAvailable
}) ? Qt.resolvedUrl("qrc:/icons/system-update.svg")
} : Qt.resolvedUrl("qrc:/icons/view-" + (model.installedVersion.length > 0 ? "expand" : "collapse") + ".svg")
iconColor: model.updateAvailable
? "green"
: model.installedVersion.length > 0 ? "blue" : Style.iconColor
onClicked: {
pageStack.push(Qt.resolvedUrl("PackageDetailsPage.qml"), {pkg: updatesModel.get(index)})
} }
} }
} }
} }
ThinDivider {} ThinDivider {}
ListView { NymeaSwipeDelegate {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true text: qsTr("Install or remove software")
visible: count > 0 onClicked: {
model: updatesModel pageStack.push("PackageListPage.qml")
clip: true
delegate: NymeaSwipeDelegate {
width: parent.width
text: model.displayName
subText: model.candidateVersion
prominentSubText: false
iconName: model.updateAvailable
? Qt.resolvedUrl("qrc:/icons/system-update.svg")
: Qt.resolvedUrl("qrc:/icons/view-" + (model.installedVersion.length > 0 ? "expand" : "collapse") + ".svg")
iconColor: model.updateAvailable
? "green"
: model.installedVersion.length > 0 ? "blue" : Style.iconColor
onClicked: {
pageStack.push(Qt.resolvedUrl("PackageDetailsPage.qml"), {pkg: updatesModel.get(index)})
}
} }
} }
} }
ThinDivider {}
NymeaSwipeDelegate {
Layout.fillWidth: true
text: qsTr("Install or remove software")
onClicked: {
pageStack.push("PackageListPage.qml")
}
}
} }
Component { Component {
@ -253,8 +453,7 @@ Page {
} }
} }
UpdateRunningOverlay { UpdateRunningOverlay { }
}
Component { Component {
id: errorDialogComponent id: errorDialogComponent

View File

@ -1,2 +1,2 @@
1.11.3 1.11.4
700 701