Expose Account.SyncState as an Enum to QML

Provides a single source of truth

CURA-7290
This commit is contained in:
Nino van Hooff 2020-05-08 11:09:48 +02:00
parent 8937c63219
commit 1ae050bbc5
5 changed files with 38 additions and 35 deletions

View file

@ -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()

View file

@ -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")))

View file

@ -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]

View file

@ -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

View file

@ -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 {