Browse Source

Expose Account.SyncState as an Enum to QML

Provides a single source of truth

CURA-7290
Nino van Hooff 4 years ago
parent
commit
1ae050bbc5

+ 22 - 22
cura/API/Account.py

@@ -1,10 +1,9 @@
 # Copyright (c) 2018 Ultimaker B.V.
 # Cura is released under the terms of the LGPLv3 or higher.
 from datetime import datetime
-from enum import Enum
 from typing import Optional, Dict, TYPE_CHECKING
 
-from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty, QTimer
+from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty, QTimer, Q_ENUMS
 
 from UM.Message import Message
 from UM.i18n import i18nCatalog
@@ -18,6 +17,13 @@ if TYPE_CHECKING:
 i18n_catalog = i18nCatalog("cura")
 
 
+class SyncState(QObject):
+    """QML: Cura.AccountSyncState"""
+    SYNCING = 0
+    SUCCESS = 1
+    ERROR = 2
+
+
 ##  The account API provides a version-proof bridge to use Ultimaker Accounts
 #
 #   Usage:
@@ -30,13 +36,7 @@ i18n_catalog = i18nCatalog("cura")
 class Account(QObject):
     # The interval with which the remote clusters are checked
     SYNC_INTERVAL = 30.0  # seconds
-
-    class SyncState(Enum):
-        """Caution: values used in qml (eg. SyncState.qml)"""
-
-        SYNCING = "syncing",
-        SUCCESS = "success",
-        ERROR = "error"
+    Q_ENUMS(SyncState)
 
     # Signal emitted when user logged in or out.
     loginStateChanged = pyqtSignal(bool)
@@ -44,7 +44,7 @@ class Account(QObject):
     cloudPrintersDetectedChanged = pyqtSignal(bool)
     syncRequested = pyqtSignal()
     lastSyncDateTimeChanged = pyqtSignal()
-    syncStateChanged = pyqtSignal(str)
+    syncStateChanged = pyqtSignal(int)  # because it's an int Enum
 
     def __init__(self, application: "CuraApplication", parent = None) -> None:
         super().__init__(parent)
@@ -53,7 +53,7 @@ class Account(QObject):
 
         self._error_message = None  # type: Optional[Message]
         self._logged_in = False
-        self._sync_state = self.SyncState.SUCCESS
+        self._sync_state = SyncState.SUCCESS
         self._last_sync_str = "-"
 
         self._callback_port = 32118
@@ -81,7 +81,7 @@ class Account(QObject):
         self._update_timer.setSingleShot(True)
         self._update_timer.timeout.connect(self.syncRequested)
 
-        self._sync_services = {}  # type: Dict[str, Account.SyncState]
+        self._sync_services = {}  # type: Dict[str, SyncState]
         """contains entries "service_name" : SyncState"""
 
     def initialize(self) -> None:
@@ -94,30 +94,30 @@ class Account(QObject):
     def setSyncState(self, service_name: str, state: SyncState) -> None:
         """ Can be used to register sync services and update account sync states
 
-        Example: `setSyncState("PluginSyncService", Account.SyncState.SYNCING)`
+        Example: `setSyncState("PluginSyncService", SyncState.SYNCING)`
         :param service_name: A unique name for your service, such as `plugins` or `backups`
-        :param state: One of Account.SyncState
+        :param state: One of SyncState
         """
 
         prev_state = self._sync_state
 
         self._sync_services[service_name] = state
 
-        if any(val == self.SyncState.SYNCING for val in self._sync_services.values()):
-            self._sync_state = self.SyncState.SYNCING
-        elif any(val == self.SyncState.ERROR for val in self._sync_services.values()):
-            self._sync_state = self.SyncState.ERROR
+        if any(val == SyncState.SYNCING for val in self._sync_services.values()):
+            self._sync_state = SyncState.SYNCING
+        elif any(val == SyncState.ERROR for val in self._sync_services.values()):
+            self._sync_state = SyncState.ERROR
         else:
-            self._sync_state = self.SyncState.SUCCESS
+            self._sync_state = SyncState.SUCCESS
 
         if self._sync_state != prev_state:
-            self.syncStateChanged.emit(self._sync_state.value[0])
+            self.syncStateChanged.emit(self._sync_state)
 
-            if self._sync_state == self.SyncState.SUCCESS:
+            if self._sync_state == SyncState.SUCCESS:
                 self._last_sync_str = datetime.now().strftime("%d/%m/%Y %H:%M")
                 self.lastSyncDateTimeChanged.emit()
 
-            if self._sync_state != self.SyncState.SYNCING:
+            if self._sync_state != SyncState.SYNCING:
                 # schedule new auto update after syncing completed (for whatever reason)
                 if not self._update_timer.isActive():
                     self._update_timer.start()

+ 2 - 0
cura/CuraApplication.py

@@ -48,6 +48,7 @@ from UM.Workspace.WorkspaceReader import WorkspaceReader
 from UM.i18n import i18nCatalog
 from cura import ApplicationMetadata
 from cura.API import CuraAPI
+from cura.API.Account import Account
 from cura.Arranging.Arrange import Arrange
 from cura.Arranging.ArrangeObjectsAllBuildPlatesJob import ArrangeObjectsAllBuildPlatesJob
 from cura.Arranging.ArrangeObjectsJob import ArrangeObjectsJob
@@ -1106,6 +1107,7 @@ class CuraApplication(QtApplication):
 
         from cura.API import CuraAPI
         qmlRegisterSingletonType(CuraAPI, "Cura", 1, 1, "API", self.getCuraAPI)
+        qmlRegisterUncreatableType(Account, "Cura", 1, 0, "AccountSyncState", "Could not create AccountSyncState")
 
         # As of Qt5.7, it is necessary to get rid of any ".." in the path for the singleton to work.
         actions_url = QUrl.fromLocalFile(os.path.abspath(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")))

+ 5 - 5
plugins/Toolbox/src/CloudSync/CloudPackageChecker.py

@@ -13,7 +13,7 @@ from UM.Logger import Logger
 from UM.Message import Message
 from UM.Signal import Signal
 from UM.TaskManagement.HttpRequestScope import JsonDecoratorScope
-from cura.API import Account
+from cura.API.Account import SyncState
 from cura.CuraApplication import CuraApplication, ApplicationMetadata
 from cura.UltimakerCloud.UltimakerCloudScope import UltimakerCloudScope
 from .SubscribedPackagesModel import SubscribedPackagesModel
@@ -62,7 +62,7 @@ class CloudPackageChecker(QObject):
             self._hideSyncMessage()
 
     def _getUserSubscribedPackages(self) -> None:
-        self._application.getCuraAPI().account.setSyncState(self.SYNC_SERVICE_NAME, Account.SyncState.SYNCING)
+        self._application.getCuraAPI().account.setSyncState(self.SYNC_SERVICE_NAME, SyncState.SYNCING)
         Logger.debug("Requesting subscribed packages metadata from server.")
         url = CloudApiModel.api_url_user_packages
         self._application.getHttpRequestManager().get(url,
@@ -75,7 +75,7 @@ class CloudPackageChecker(QObject):
             Logger.log("w",
                        "Requesting user packages failed, response code %s while trying to connect to %s",
                        reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), reply.url())
-            self._application.getCuraAPI().account.setSyncState(self.SYNC_SERVICE_NAME, "error")
+            self._application.getCuraAPI().account.setSyncState(self.SYNC_SERVICE_NAME, SyncState.ERROR)
             return
 
         try:
@@ -84,13 +84,13 @@ class CloudPackageChecker(QObject):
             if "errors" in json_data:
                 for error in json_data["errors"]:
                     Logger.log("e", "%s", error["title"])
-                    self._application.getCuraAPI().account.setSyncState(self.SYNC_SERVICE_NAME, "error")
+                    self._application.getCuraAPI().account.setSyncState(self.SYNC_SERVICE_NAME, SyncState.ERROR)
                 return
             self._handleCompatibilityData(json_data["data"])
         except json.decoder.JSONDecodeError:
             Logger.log("w", "Received invalid JSON for user subscribed packages from the Web Marketplace")
 
-        self._application.getCuraAPI().account.setSyncState(self.SYNC_SERVICE_NAME, "success")
+        self._application.getCuraAPI().account.setSyncState(self.SYNC_SERVICE_NAME, SyncState.SUCCESS)
 
     def _handleCompatibilityData(self, subscribed_packages_payload: List[Dict[str, Any]]) -> None:
         user_subscribed_packages = [plugin["package_id"] for plugin in subscribed_packages_payload]

+ 4 - 3
plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py

@@ -10,6 +10,7 @@ from UM.Logger import Logger  # To log errors talking to the API.
 from UM.Message import Message
 from UM.Signal import Signal
 from cura.API import Account
+from cura.API.Account import SyncState
 from cura.CuraApplication import CuraApplication
 from cura.Settings.CuraStackBuilder import CuraStackBuilder
 from cura.Settings.GlobalStack import GlobalStack
@@ -89,7 +90,7 @@ class CloudOutputDeviceManager:
         Logger.info("Syncing cloud printer clusters")
 
         self._syncing = True
-        self._account.setSyncState(self.SYNC_SERVICE_NAME, Account.SyncState.SYNCING)
+        self._account.setSyncState(self.SYNC_SERVICE_NAME, SyncState.SYNCING)
         self._api.getClusters(self._onGetRemoteClustersFinished, self._onGetRemoteClusterFailed)
 
     def _onGetRemoteClustersFinished(self, clusters: List[CloudClusterResponse]) -> None:
@@ -119,11 +120,11 @@ class CloudOutputDeviceManager:
             self._connectToActiveMachine()
 
         self._syncing = False
-        self._account.setSyncState(self.SYNC_SERVICE_NAME, Account.SyncState.SUCCESS)
+        self._account.setSyncState(self.SYNC_SERVICE_NAME, SyncState.SUCCESS)
 
     def _onGetRemoteClusterFailed(self):
         self._syncing = False
-        self._account.setSyncState(self.SYNC_SERVICE_NAME, Account.SyncState.ERROR)
+        self._account.setSyncState(self.SYNC_SERVICE_NAME, SyncState.ERROR)
 
     def _onDevicesDiscovered(self, clusters: List[CloudClusterResponse]) -> None:
         """**Synchronously** create machines for discovered devices

+ 5 - 5
resources/qml/Account/SyncState.qml

@@ -82,20 +82,20 @@ Row // sync state icon + message
     signal syncStateChanged(string newState)
 
     onSyncStateChanged: {
-        if(newState == "syncing"){
+        if(newState == Cura.AccountSyncState.SYNCING){
             syncRow.iconSource = UM.Theme.getIcon("update")
             syncRow.labelText = catalog.i18nc("@label", "Checking...")
-        } else if (newState == "success") {
+        } else if (newState == Cura.AccountSyncState.SUCCESS) {
             syncRow.iconSource = UM.Theme.getIcon("checked")
             syncRow.labelText = catalog.i18nc("@label", "You are up to date")
-        } else if (newState == "error") {
-            syncRow.iconSource = UM.Theme.getIcon("warning-light")
+        } else if (newState == Cura.AccountSyncState.ERROR) {
+            syncRow.iconSource = UM.Theme.getIcon("warning_light")
             syncRow.labelText = catalog.i18nc("@label", "Something went wrong...")
         } else {
             print("Error: unexpected sync state: " + newState)
         }
 
-        if(newState == "syncing"){
+        if(newState == Cura.AccountSyncState.SYNCING){
             syncRow.animateIconRotation = true
             syncRow.syncButtonVisible = false
         } else {