Browse Source

Add Install Pending Updates button to Account popup

CURA-7473
Nino van Hooff 4 years ago
parent
commit
4f1a18f102

+ 28 - 3
cura/API/Account.py

@@ -1,7 +1,7 @@
 # Copyright (c) 2018 Ultimaker B.V.
 # Cura is released under the terms of the LGPLv3 or higher.
 from datetime import datetime
-from typing import Optional, Dict, TYPE_CHECKING, Union
+from typing import Optional, Dict, TYPE_CHECKING, Callable
 
 from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty, QTimer, Q_ENUMS
 
@@ -56,6 +56,7 @@ class Account(QObject):
     lastSyncDateTimeChanged = pyqtSignal()
     syncStateChanged = pyqtSignal(int)  # because SyncState is an int Enum
     manualSyncEnabledChanged = pyqtSignal(bool)
+    updatePackagesEnabledChanged = pyqtSignal(bool)
 
     def __init__(self, application: "CuraApplication", parent = None) -> None:
         super().__init__(parent)
@@ -66,6 +67,8 @@ class Account(QObject):
         self._logged_in = False
         self._sync_state = SyncState.IDLE
         self._manual_sync_enabled = False
+        self._update_packages_enabled = False
+        self._update_packages_action = None  # type: Callable
         self._last_sync_str = "-"
 
         self._callback_port = 32118
@@ -143,6 +146,18 @@ class Account(QObject):
                 if not self._update_timer.isActive():
                     self._update_timer.start()
 
+    def setUpdatePackagesAction(self, action: Callable):
+        """ Set the callback which will be invoked when the user clicks the update packages button
+
+        Should be invoked after your service sets the sync state to SYNCING and before setting the
+        sync state to SUCCESS.
+
+        Action will be reset to None when the next sync starts
+        """
+        self._update_packages_action = action
+        self._update_packages_enabled = True
+        self.updatePackagesEnabledChanged.emit(self._update_packages_enabled)
+
     def _onAccessTokenChanged(self):
         self.accessTokenChanged.emit()
 
@@ -185,6 +200,9 @@ class Account(QObject):
         sync is currently running, a sync will be requested.
         """
 
+        self._update_packages_action = None
+        self._update_packages_enabled = False
+        self.updatePackagesEnabledChanged.emit(self._update_packages_enabled)
         if self._update_timer.isActive():
             self._update_timer.stop()
         elif self._sync_state == SyncState.SYNCING:
@@ -251,6 +269,10 @@ class Account(QObject):
     def manualSyncEnabled(self) -> bool:
         return self._manual_sync_enabled
 
+    @pyqtProperty(bool, notify=updatePackagesEnabledChanged)
+    def updatePackagesEnabled(self) -> bool:
+        return self._update_packages_enabled
+
     @pyqtSlot()
     @pyqtSlot(bool)
     def sync(self, user_initiated: bool = False) -> None:
@@ -259,11 +281,14 @@ class Account(QObject):
 
         self._sync()
 
+    @pyqtSlot()
+    def update_packages(self):
+        if self._update_packages_action is not None:
+            self._update_packages_action()
+
     @pyqtSlot()
     def popupOpened(self) -> None:
         self._setManualSyncEnabled(True)
-        self._sync_state = SyncState.IDLE
-        self.syncStateChanged.emit(self._sync_state)
 
     @pyqtSlot()
     def logout(self) -> None:

+ 11 - 6
plugins/Toolbox/src/CloudSync/CloudPackageChecker.py

@@ -95,10 +95,6 @@ class CloudPackageChecker(QObject):
         user_subscribed_packages = {plugin["package_id"] for plugin in subscribed_packages_payload}
         user_installed_packages = self._package_manager.getAllInstalledPackageIDs()
 
-        if user_subscribed_packages == self._last_notified_packages:
-            # already notified user about these
-            return
-
         # We need to re-evaluate the dismissed packages
         # (i.e. some package might got updated to the correct SDK version in the meantime,
         # hence remove them from the Dismissed Incompatible list)
@@ -109,7 +105,15 @@ class CloudPackageChecker(QObject):
 
         # We check if there are packages installed in Web Marketplace but not in Cura marketplace
         package_discrepancy = list(user_subscribed_packages.difference(user_installed_packages))
+
         if package_discrepancy:
+            account = self._application.getCuraAPI().account
+            account.setUpdatePackagesAction(lambda: self._onSyncButtonClicked(None, None))
+
+            if user_subscribed_packages == self._last_notified_packages:
+                # already notified user about these
+                return
+
             Logger.log("d", "Discrepancy found between Cloud subscribed packages and Cura installed packages")
             self._model.addDiscrepancies(package_discrepancy)
             self._model.initialize(self._package_manager, subscribed_packages_payload)
@@ -144,7 +148,8 @@ class CloudPackageChecker(QObject):
             self._message.hide()
             self._message = None
 
-    def _onSyncButtonClicked(self, sync_message: Message, sync_message_action: str) -> None:
-        sync_message.hide()
+    def _onSyncButtonClicked(self, sync_message: Optional[Message], sync_message_action: Optional[str]) -> None:
+        if sync_message is not None:
+            sync_message.hide()
         self._hideSyncMessage()  # Should be the same message, but also sets _message to None
         self.discrepancies.emit(self._model)

+ 25 - 3
resources/qml/Account/SyncState.qml

@@ -49,7 +49,7 @@ Row // Sync state icon + message
         width: 20 * screenScaleFactor
         height: width
 
-        source: Cura.API.account.manualSyncEnabled ? UM.Theme.getIcon("update") : UM.Theme.getIcon("checked")
+        // source is determined by State
         color: UM.Theme.getColor("account_sync_state_icon")
 
         RotationAnimator
@@ -80,14 +80,36 @@ Row // Sync state icon + message
         Label
         {
             id: stateLabel
-            text: catalog.i18nc("@state", catalog.i18nc("@label", "Account synced"))
+            // text is determined by State
             color: UM.Theme.getColor("text")
             font: UM.Theme.getFont("medium")
             renderType: Text.NativeRendering
             width: contentWidth + UM.Theme.getSize("default_margin").height
             height: contentHeight
             verticalAlignment: Text.AlignVCenter
-            visible: !Cura.API.account.manualSyncEnabled
+            visible: !Cura.API.account.manualSyncEnabled && !Cura.API.account.updatePackagesEnabled
+        }
+
+        Label
+        {
+            id: updatePackagesButton
+            text: catalog.i18nc("@button", "Install pending updates")
+            color: UM.Theme.getColor("secondary_button_text")
+            font: UM.Theme.getFont("medium")
+            renderType: Text.NativeRendering
+            verticalAlignment: Text.AlignVCenter
+            height: contentHeight
+            width: contentWidth + UM.Theme.getSize("default_margin").height
+            visible: Cura.API.account.updatePackagesEnabled
+
+            MouseArea
+            {
+                anchors.fill: parent
+                onClicked: Cura.API.account.update_packages()
+                hoverEnabled: true
+                onEntered: updatePackagesButton.font.underline = true
+                onExited: updatePackagesButton.font.underline = false
+            }
         }
 
         Label