diff --git a/cura/API/Account.py b/cura/API/Account.py index d4cf1f7106..eae59e8a71 100644 --- a/cura/API/Account.py +++ b/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() diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 993bb15ae2..4355bc5450 100755 --- a/cura/CuraApplication.py +++ b/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"))) diff --git a/plugins/Toolbox/src/CloudSync/CloudPackageChecker.py b/plugins/Toolbox/src/CloudSync/CloudPackageChecker.py index 0c51b7ff8b..4444900e36 100644 --- a/plugins/Toolbox/src/CloudSync/CloudPackageChecker.py +++ b/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] diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py index 10ef460044..381d01e56a 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py +++ b/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 diff --git a/resources/qml/Account/SyncState.qml b/resources/qml/Account/SyncState.qml index 20c0ca9032..7126aec314 100644 --- a/resources/qml/Account/SyncState.qml +++ b/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 {