From 7a902f8314873336ea4f9a0ff65893e53e580850 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 6 Dec 2021 11:28:06 +0100 Subject: [PATCH 1/8] Add restart required banner CURA-8587 --- .../Marketplace/resources/qml/Marketplace.qml | 47 +++++++++++++++++++ resources/themes/cura-light/theme.json | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/plugins/Marketplace/resources/qml/Marketplace.qml b/plugins/Marketplace/resources/qml/Marketplace.qml index 44f7777b35..98de8b0534 100644 --- a/plugins/Marketplace/resources/qml/Marketplace.qml +++ b/plugins/Marketplace/resources/qml/Marketplace.qml @@ -228,4 +228,51 @@ Window } } } + + Rectangle + { + height: quitButton.height + 2 * UM.Theme.getSize("default_margin").width + color: UM.Theme.getColor("primary") + visible: false // TODO: enable this when restart is required + anchors + { + left: parent.left + right: parent.right + bottom: parent.bottom + } + + RowLayout + { + anchors + { + left: parent.left + right: parent.right + verticalCenter: parent.verticalCenter + margins: UM.Theme.getSize("default_margin").width + } + spacing: UM.Theme.getSize("default_margin").width + UM.RecolorImage + { + id: bannerIcon + source: UM.Theme.getIcon("Plugin") + + color: UM.Theme.getColor("primary_button_text") + implicitWidth: UM.Theme.getSize("banner_icon_size").width + implicitHeight: UM.Theme.getSize("banner_icon_size").height + } + Text + { + color: UM.Theme.getColor("primary_button_text") + text: catalog.i18nc("@button", "In order to use the package you will need to restart Cura") + font: UM.Theme.getFont("default") + renderType: Text.NativeRendering + Layout.fillWidth: true + } + Cura.SecondaryButton + { + id: quitButton + text: catalog.i18nc("@button", "Quit Ultimaker Cura") + } + } + } } diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 8ca9f72ca8..149bfab308 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -179,7 +179,7 @@ "lining": [192, 193, 194, 255], "viewport_overlay": [246, 246, 246, 255], - "primary": [50, 130, 255, 255], + "primary": [25, 110, 240, 255], "primary_shadow": [64, 47, 205, 255], "primary_hover": [48, 182, 231, 255], "primary_text": [255, 255, 255, 255], From de0dc568cded847c6eb99fa7f328edb8ba760c27 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 6 Dec 2021 11:30:27 +0100 Subject: [PATCH 2/8] Change rectangle into item It had no color, so it doesn't need to be a rectangle Cura-8587 --- plugins/Marketplace/resources/qml/Marketplace.qml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/Marketplace/resources/qml/Marketplace.qml b/plugins/Marketplace/resources/qml/Marketplace.qml index 98de8b0534..62f9673072 100644 --- a/plugins/Marketplace/resources/qml/Marketplace.qml +++ b/plugins/Marketplace/resources/qml/Marketplace.qml @@ -106,9 +106,8 @@ Window height: UM.Theme.getSize("button_icon").height + UM.Theme.getSize("default_margin").height spacing: UM.Theme.getSize("thin_margin").width - Rectangle + Item { - color: "transparent" Layout.preferredHeight: parent.height Layout.preferredWidth: searchBar.visible ? UM.Theme.getSize("thin_margin").width : 0 Layout.fillWidth: ! searchBar.visible From ea85e59e501710478b592064420a183ecbac33b0 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 6 Dec 2021 11:34:19 +0100 Subject: [PATCH 3/8] Fix margin CURA-8587 --- plugins/Marketplace/resources/qml/PackageCard.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/Marketplace/resources/qml/PackageCard.qml b/plugins/Marketplace/resources/qml/PackageCard.qml index 89ae6091fc..31716ed005 100644 --- a/plugins/Marketplace/resources/qml/PackageCard.qml +++ b/plugins/Marketplace/resources/qml/PackageCard.qml @@ -94,7 +94,7 @@ Rectangle left: packageItem.right leftMargin: UM.Theme.getSize("default_margin").width right: parent.right - rightMargin: UM.Theme.getSize("thick_margin").width + rightMargin: UM.Theme.getSize("default_margin").width top: parent.top topMargin: UM.Theme.getSize("narrow_margin").height } From 579cc7bdbc582687ce73efc1b0ac26b9da93a788 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 6 Dec 2021 11:34:23 +0100 Subject: [PATCH 4/8] Enable or disable a plugin functionality added Contributes to: CURA-8587 --- plugins/Marketplace/PackageList.py | 8 ++++++-- plugins/Marketplace/PackageModel.py | 12 ++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/plugins/Marketplace/PackageList.py b/plugins/Marketplace/PackageList.py index 301f765dab..965484faff 100644 --- a/plugins/Marketplace/PackageList.py +++ b/plugins/Marketplace/PackageList.py @@ -11,6 +11,7 @@ from UM.Qt.ListModel import ListModel from UM.TaskManagement.HttpRequestScope import JsonDecoratorScope from UM.TaskManagement.HttpRequestManager import HttpRequestData, HttpRequestManager from UM.Logger import Logger +from UM import PluginRegistry from cura.CuraApplication import CuraApplication from cura import CuraPackageManager @@ -35,6 +36,7 @@ class PackageList(ListModel): def __init__(self, parent: Optional["QObject"] = None) -> None: super().__init__(parent) self._manager: CuraPackageManager = CuraApplication.getInstance().getPackageManager() + self._plugin_registry: PluginRegistry = CuraApplication.getInstance().getPluginRegistry() self._account = CuraApplication.getInstance().getCuraAPI().account self._error_message = "" self.addRoleName(self.PackageRole, "package") @@ -229,7 +231,8 @@ class PackageList(ListModel): package = self.getPackageModel(package_id) package.is_enabling = True Logger.debug(f"Enabling {package_id}") - # TODO: implement enabling functionality + self._plugin_registry.enablePlugin(package_id) + package.is_active = True package.is_enabling = False @pyqtSlot(str) @@ -237,5 +240,6 @@ class PackageList(ListModel): package = self.getPackageModel(package_id) package.is_enabling = True Logger.debug(f"Disabling {package_id}") - # TODO: implement disabling functionality + self._plugin_registry.disablePlugin(package_id) + package.is_active = False package.is_enabling = False diff --git a/plugins/Marketplace/PackageModel.py b/plugins/Marketplace/PackageModel.py index 58184ac1c3..f1b5b202a3 100644 --- a/plugins/Marketplace/PackageModel.py +++ b/plugins/Marketplace/PackageModel.py @@ -287,8 +287,6 @@ class PackageModel(QObject): if self._is_recently_managed: return "hidden" if self._package_type == "material": - if self._is_bundled: # TODO: Check if a bundled material can/should be un-/install en-/disabled - return "secondary" return "hidden" if not self._is_installed: return "hidden" @@ -306,6 +304,16 @@ class PackageModel(QObject): self._is_enabling = value self.stateManageButtonChanged.emit() + @property + def is_active(self) -> bool: + return self._is_active + + @is_active.setter + def is_active(self, value: bool) -> None: + if value != self._is_active: + self._is_active = value + self.stateManageButtonChanged.emit() + # --- Installing --- @pyqtProperty(str, notify = stateManageButtonChanged) From 18837a32b8e4a23abae31eb4190074aef81932bf Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 6 Dec 2021 11:54:14 +0100 Subject: [PATCH 5/8] Move verifiedIcon to it's own file Cleaning up the size of the package card a bit --- .../Marketplace/resources/qml/PackageCard.qml | 38 +--------------- .../resources/qml/VerifiedIcon.qml | 45 +++++++++++++++++++ 2 files changed, 47 insertions(+), 36 deletions(-) create mode 100644 plugins/Marketplace/resources/qml/VerifiedIcon.qml diff --git a/plugins/Marketplace/resources/qml/PackageCard.qml b/plugins/Marketplace/resources/qml/PackageCard.qml index 31716ed005..e4f56632df 100644 --- a/plugins/Marketplace/resources/qml/PackageCard.qml +++ b/plugins/Marketplace/resources/qml/PackageCard.qml @@ -114,47 +114,13 @@ Rectangle color: UM.Theme.getColor("text") verticalAlignment: Text.AlignTop } - - Control + VerifiedIcon { - Layout.preferredWidth: UM.Theme.getSize("card_tiny_icon").width - Layout.preferredHeight: UM.Theme.getSize("card_tiny_icon").height - enabled: packageData.isCheckedByUltimaker visible: packageData.isCheckedByUltimaker - - Cura.ToolTip - { - tooltipText: - { - switch(packageData.packageType) - { - case "plugin": return catalog.i18nc("@info", "Ultimaker Verified Plug-in"); - case "material": return catalog.i18nc("@info", "Ultimaker Certified Material"); - default: return catalog.i18nc("@info", "Ultimaker Verified Package"); - } - } - visible: parent.hovered - targetPoint: Qt.point(0, Math.round(parent.y + parent.height / 4)) - } - - Rectangle - { - anchors.fill: parent - color: UM.Theme.getColor("action_button_hovered") - radius: width - UM.RecolorImage - { - anchors.fill: parent - color: UM.Theme.getColor("primary") - source: packageData.packageType == "plugin" ? UM.Theme.getIcon("CheckCircle") : UM.Theme.getIcon("Certified") - } - } - - //NOTE: Can we link to something here? (Probably a static link explaining what verified is): - // onClicked: Qt.openUrlExternally( XXXXXX ) } + Control { Layout.preferredWidth: UM.Theme.getSize("card_tiny_icon").width diff --git a/plugins/Marketplace/resources/qml/VerifiedIcon.qml b/plugins/Marketplace/resources/qml/VerifiedIcon.qml new file mode 100644 index 0000000000..30ef3080a0 --- /dev/null +++ b/plugins/Marketplace/resources/qml/VerifiedIcon.qml @@ -0,0 +1,45 @@ +// Copyright (c) 2021 Ultimaker B.V. +// Cura is released under the terms of the LGPLv3 or higher. + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.1 + +import UM 1.6 as UM +import Cura 1.6 as Cura +Control +{ + implicitWidth: UM.Theme.getSize("card_tiny_icon").width + implicitHeight: UM.Theme.getSize("card_tiny_icon").height + + Cura.ToolTip + { + tooltipText: + { + switch(packageData.packageType) + { + case "plugin": return catalog.i18nc("@info", "Ultimaker Verified Plug-in"); + case "material": return catalog.i18nc("@info", "Ultimaker Certified Material"); + default: return catalog.i18nc("@info", "Ultimaker Verified Package"); + } + } + visible: parent.hovered + targetPoint: Qt.point(0, Math.round(parent.y + parent.height / 4)) + } + + Rectangle + { + anchors.fill: parent + color: UM.Theme.getColor("action_button_hovered") + radius: width + UM.RecolorImage + { + anchors.fill: parent + color: UM.Theme.getColor("primary") + source: packageData.packageType == "plugin" ? UM.Theme.getIcon("CheckCircle") : UM.Theme.getIcon("Certified") + } + } + + //NOTE: Can we link to something here? (Probably a static link explaining what verified is): + // onClicked: Qt.openUrlExternally( XXXXXX ) +} \ No newline at end of file From 09710c2d9f8b51bcc330e2d27a53af925102181a Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Mon, 6 Dec 2021 12:02:14 +0100 Subject: [PATCH 6/8] Remove unneeded connection The connection isn't needed to handle a signal. There is an easier shorthand CURA-8587 --- .../Marketplace/resources/qml/PackageCard.qml | 23 ++++--------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/plugins/Marketplace/resources/qml/PackageCard.qml b/plugins/Marketplace/resources/qml/PackageCard.qml index e4f56632df..bf0dda217b 100644 --- a/plugins/Marketplace/resources/qml/PackageCard.qml +++ b/plugins/Marketplace/resources/qml/PackageCard.qml @@ -328,12 +328,8 @@ Rectangle secondaryText: catalog.i18nc("@button", "Disable") busySecondaryText: catalog.i18nc("@button", "disabling...") enabled: !(installManageButton.busy || updateManageButton.busy) - } - Connections - { - target: enableManageButton - function onClicked(primary_action) - { + + onClicked: { if (primary_action) { packageData.enablePackageTriggered(packageData.packageId) @@ -355,11 +351,7 @@ Rectangle secondaryText: catalog.i18nc("@button", "Uninstall") busySecondaryText: catalog.i18nc("@button", "uninstalling...") enabled: !(enableManageButton.busy || updateManageButton.busy) - } - Connections - { - target: installManageButton - function onClicked(primary_action) + onClicked: { if (primary_action) { @@ -380,14 +372,7 @@ Rectangle primaryText: catalog.i18nc("@button", "Update") busyPrimaryText: catalog.i18nc("@button", "updating...") enabled: !(installManageButton.busy || enableManageButton.busy) - } - Connections - { - target: updateManageButton - function onClicked(primary_action) - { - packageData.updatePackageTriggered(packageData.packageId) - } + onClicked: packageData.updatePackageTriggered(packageData.packageId) } } } From 28b6bfb72906057cbc5368494dc582c30e25bbf0 Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 6 Dec 2021 13:53:44 +0100 Subject: [PATCH 7/8] Fixed the update button busy state Contributes to: CURA-8587 --- plugins/Marketplace/LocalPackageList.py | 17 ++--- plugins/Marketplace/PackageList.py | 3 +- plugins/Marketplace/PackageModel.py | 75 ------------------- .../resources/qml/ManageButton.qml | 5 +- 4 files changed, 11 insertions(+), 89 deletions(-) diff --git a/plugins/Marketplace/LocalPackageList.py b/plugins/Marketplace/LocalPackageList.py index e6ad425954..5b3c05609e 100644 --- a/plugins/Marketplace/LocalPackageList.py +++ b/plugins/Marketplace/LocalPackageList.py @@ -68,15 +68,14 @@ class LocalPackageList(PackageList): return package def checkForUpdates(self, packages: List[Dict[str, Any]]): - if self._account.isLoggedIn: - installed_packages = "installed_packages=".join([f"{package['package_id']}:{package['package_version']}&" for package in packages]) - request_url = f"{PACKAGE_UPDATES_URL}?installed_packages={installed_packages[:-1]}" + installed_packages = "installed_packages=".join([f"{package['package_id']}:{package['package_version']}&" for package in packages]) + request_url = f"{PACKAGE_UPDATES_URL}?installed_packages={installed_packages[:-1]}" - self._ongoing_request = HttpRequestManager.getInstance().get( - request_url, - scope = self._scope, - callback = self._parseResponse - ) + self._ongoing_request = HttpRequestManager.getInstance().get( + request_url, + scope = self._scope, + callback = self._parseResponse + ) def _parseResponse(self, reply: "QNetworkReply") -> None: """ @@ -95,6 +94,6 @@ class LocalPackageList(PackageList): for package_data in response_data["data"]: package = self.getPackageModel(package_data["package_id"]) package.download_url = package_data.get("download_url", "") - package.canUpdate = True + package.can_update = True self.sort(attrgetter("sectionTitle", "can_update", "displayName"), key = "package", reverse = True) diff --git a/plugins/Marketplace/PackageList.py b/plugins/Marketplace/PackageList.py index 965484faff..6a931c1e4b 100644 --- a/plugins/Marketplace/PackageList.py +++ b/plugins/Marketplace/PackageList.py @@ -131,7 +131,6 @@ class PackageList(ListModel): if update: package.is_updating = False else: - Logger.debug(f"Setting recently installed for package: {package_id}") package.is_recently_managed = True package.is_installing = False self.subscribeUserToPackage(package_id, str(package.sdk_version)) @@ -195,7 +194,7 @@ class PackageList(ListModel): def _connectManageButtonSignals(self, package: PackageModel) -> None: package.installPackageTriggered.connect(self.installPackage) package.uninstallPackageTriggered.connect(self.uninstallPackage) - package.updatePackageTriggered.connect(self.installPackage) + package.updatePackageTriggered.connect(self.updatePackage) package.enablePackageTriggered.connect(self.enablePackage) package.disablePackageTriggered.connect(self.disablePackage) diff --git a/plugins/Marketplace/PackageModel.py b/plugins/Marketplace/PackageModel.py index f1b5b202a3..5251f03524 100644 --- a/plugins/Marketplace/PackageModel.py +++ b/plugins/Marketplace/PackageModel.py @@ -379,78 +379,3 @@ class PackageModel(QObject): if value != self._can_update: self._can_update = value self.stateManageButtonChanged.emit() - - # ---- - - - - - - - - - - - # isInstalledChanged = pyqtSignal() - # - # @pyqtProperty(bool, notify = isInstalledChanged) - # def isInstalled(self): - # return self._is_installed - # - # isEnabledChanged = pyqtSignal() - # - # - #f - # @pyqtProperty(bool, notify = isEnabledChanged) - # def isEnabled(self) -> bool: - # return self._is_active - # - # - # - # isManageEnableStateChanged = pyqtSignalf() - # - # @pyqtProperty(str, notify = isManageEnableStateChanged) - # def isManageEnableState(self) -> str: - # if self.isEnabling: - # return "busy" - # if self. - # - # manageEnableStateChanged = pyqtSignal() - # - # @pyqtProperty(str, notify = manageEnableStateChanged) - # def manageEnableState(self) -> str: - # # TODO: Handle manual installed packages - # if self._is_installed: - # if self._is_active: - # return "secondary" - # else: - # return "primary" - # else: - # return "hidden" - # - # manageInstallStateChanged = pyqtSignal() - # - # def setManageInstallState(self, value: bool) -> None: - # if value != self._is_installed: - # self._is_installed = value - # self.manageInstallStateChanged.emit() - # self.manageEnableStateChanged.emit() - # - # @pyqtProperty(str, notify = manageInstallStateChanged) - # def manageInstallState(self) -> str: - # if self._is_installed: - # if self._is_bundled: - # return "hidden" - # else: - # return "secondary" - # else: - # return "primary" - # - # manageUpdateStateChanged = pyqtSignal() - # - # @pyqtProperty(str, notify = manageUpdateStateChanged) - # def manageUpdateState(self) -> str: - # if self._can_update: - # return "primary" - # return "hidden" - # diff --git a/plugins/Marketplace/resources/qml/ManageButton.qml b/plugins/Marketplace/resources/qml/ManageButton.qml index cdd52c9b90..323fea03f1 100644 --- a/plugins/Marketplace/resources/qml/ManageButton.qml +++ b/plugins/Marketplace/resources/qml/ManageButton.qml @@ -15,9 +15,8 @@ RowLayout property alias secondaryText: secondaryButton.text property string busyPrimaryText: busyMessageText.text property string busySecondaryText: busyMessageText.text - property string mainState: "primary" property bool enabled: true - property bool busy + property bool busy: state == "busy" signal clicked(bool primary_action) @@ -77,7 +76,7 @@ RowLayout { id: busyMessageText visible: parent.visible - text: manageButton.mainState == "primary" ? manageButton.busyPrimaryText : manageButton.busySecondaryText + text: manageButton.state == "primary" ? manageButton.busyPrimaryText : manageButton.busySecondaryText anchors.left: busyIndicator.right anchors.verticalCenter: parent.verticalCenter From 1cc3d374a02ef3bbc4140b6b1916b41e3013bb6f Mon Sep 17 00:00:00 2001 From: Jelle Spijker Date: Mon, 6 Dec 2021 14:11:31 +0100 Subject: [PATCH 8/8] Show the uninstall button for packages which can be downgraded to the bundled version Contributes to: CURA-8587 --- plugins/Marketplace/LocalPackageList.py | 6 ++++-- plugins/Marketplace/PackageModel.py | 13 ++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/plugins/Marketplace/LocalPackageList.py b/plugins/Marketplace/LocalPackageList.py index 5b3c05609e..a1f3f45e7e 100644 --- a/plugins/Marketplace/LocalPackageList.py +++ b/plugins/Marketplace/LocalPackageList.py @@ -58,12 +58,14 @@ class LocalPackageList(PackageList): def _makePackageModel(self, package_info: Dict[str, Any]) -> PackageModel: """ Create a PackageModel from the package_info and determine its section_title""" - bundled_or_installed = "bundled" if self._manager.isBundledPackage(package_info["package_id"]) else "installed" + package_id = package_info["package_id"] + bundled_or_installed = "bundled" if self._manager.isBundledPackage(package_id) else "installed" package_type = package_info["package_type"] section_title = self.PACKAGE_CATEGORIES[bundled_or_installed][package_type] package = PackageModel(package_info, section_title = section_title, parent = self) - if package_info["package_id"] in self._manager.getPackagesToRemove() or package_info["package_id"] in self._manager.getPackagesToInstall(): + if package_id in self._manager.getPackagesToRemove() or package_id in self._manager.getPackagesToInstall(): package.is_recently_managed = True + package.can_downgrade = self._manager.canDowngrade(package_id) self._connectManageButtonSignals(package) return package diff --git a/plugins/Marketplace/PackageModel.py b/plugins/Marketplace/PackageModel.py index 5251f03524..92daf310a3 100644 --- a/plugins/Marketplace/PackageModel.py +++ b/plugins/Marketplace/PackageModel.py @@ -66,6 +66,7 @@ class PackageModel(QObject): self._can_update = False self._is_updating = False self._is_enabling = False + self._can_downgrade = False self._section_title = section_title self.sdk_version = package_data.get("sdk_version_semver", "") # Note that there's a lot more info in the package_data than just these specified here. @@ -323,7 +324,7 @@ class PackageModel(QObject): if self._is_recently_managed: return "hidden" if self._is_installed: - if self._is_bundled: + if self._is_bundled and not self._can_downgrade: return "hidden" else: return "secondary" @@ -350,6 +351,16 @@ class PackageModel(QObject): self._is_installing = value self.stateManageButtonChanged.emit() + @property + def can_downgrade(self) -> bool: + return self._can_downgrade + + @can_downgrade.setter + def can_downgrade(self, value: bool) -> None: + if value != self._can_downgrade: + self._can_downgrade = value + self.stateManageButtonChanged.emit() + # --- Updating --- @pyqtProperty(str, notify = stateManageButtonChanged)