diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 986608cd49..1bdb32f4ac 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -183,10 +183,16 @@ class MachineManager(QObject): self.setActiveMachine(active_machine_id) def _onOutputDevicesChanged(self) -> None: + for printer_output_device in self._printer_output_devices: + if hasattr(printer_output_device, "cloudActiveChanged"): + printer_output_device.cloudActiveChanged.disconnect(self.printerConnectedStatusChanged) + self._printer_output_devices = [] for printer_output_device in self._application.getOutputDeviceManager().getOutputDevices(): if isinstance(printer_output_device, PrinterOutputDevice): self._printer_output_devices.append(printer_output_device) + if hasattr(printer_output_device, "cloudActiveChanged"): + printer_output_device.cloudActiveChanged.connect(self.printerConnectedStatusChanged) self.outputDevicesChanged.emit() @@ -569,6 +575,14 @@ class MachineManager(QObject): def activeMachineIsUsingCloudConnection(self) -> bool: return self.activeMachineHasCloudConnection and not self.activeMachineHasNetworkConnection + @pyqtProperty(bool, notify = printerConnectedStatusChanged) + def activeMachineIsCloudActive(self) -> bool: + if not self._printer_output_devices: + return True + + first_printer = self._printer_output_devices[0] + return True if not hasattr(first_printer, 'cloudActive') else first_printer.cloudActive + def activeMachineNetworkKey(self) -> str: if self._global_container_stack: return self._global_container_stack.getMetaDataEntry("um_network_key", "") diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py index df486822b7..020cafacd8 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDevice.py @@ -65,6 +65,8 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice): # Therefore, we create a private signal used to trigger the printersChanged signal. _cloudClusterPrintersChanged = pyqtSignal() + cloudActiveChanged = pyqtSignal() + def __init__(self, api_client: CloudApiClient, cluster: CloudClusterResponse, parent: QObject = None) -> None: """Creates a new cloud output device @@ -113,6 +115,9 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice): self._pre_upload_print_job = None # type: Optional[CloudPrintJobResponse] self._uploaded_print_job = None # type: Optional[CloudPrintJobResponse] + # Whether the printer is active, i.e. authorized for use i.r.t to workspace limitations + self._active = cluster.display_status != "inactive" + CuraApplication.getInstance().getBackend().backendDone.connect(self._resetPrintJob) CuraApplication.getInstance().getController().getScene().sceneChanged.connect(self._onSceneChanged) @@ -192,6 +197,10 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice): self._received_print_jobs = status.print_jobs self._updatePrintJobs(status.print_jobs) + if status.active != self._active: + self._active = status.active + self.cloudActiveChanged.emit() + def requestWrite(self, nodes: List[SceneNode], file_name: Optional[str] = None, limit_mimetypes: bool = False, file_handler: Optional[FileHandler] = None, filter_by_machine: bool = False, **kwargs) -> None: @@ -436,6 +445,10 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice): root_url_prefix = "-staging" if self._account.is_staging else "" return f"https://digitalfactory{root_url_prefix}.ultimaker.com/app/jobs/{self.clusterData.cluster_id}" + @pyqtProperty(bool, notify = cloudActiveChanged) + def cloudActive(self) -> bool: + return self._active + def __del__(self): CuraApplication.getInstance().getBackend().backendDone.disconnect(self._resetPrintJob) CuraApplication.getInstance().getController().getScene().sceneChanged.disconnect(self._onSceneChanged) diff --git a/plugins/UM3NetworkPrinting/src/Models/Http/CloudClusterResponse.py b/plugins/UM3NetworkPrinting/src/Models/Http/CloudClusterResponse.py index 713582b8ad..a1f22f7b36 100644 --- a/plugins/UM3NetworkPrinting/src/Models/Http/CloudClusterResponse.py +++ b/plugins/UM3NetworkPrinting/src/Models/Http/CloudClusterResponse.py @@ -10,7 +10,7 @@ class CloudClusterResponse(BaseModel): """Class representing a cloud connected cluster.""" def __init__(self, cluster_id: str, host_guid: str, host_name: str, is_online: bool, status: str, - host_internal_ip: Optional[str] = None, host_version: Optional[str] = None, + display_status: str, host_internal_ip: Optional[str] = None, host_version: Optional[str] = None, friendly_name: Optional[str] = None, printer_type: str = "ultimaker3", printer_count: int = 1, capabilities: Optional[List[str]] = None, **kwargs) -> None: """Creates a new cluster response object. @@ -20,6 +20,7 @@ class CloudClusterResponse(BaseModel): :param host_name: The name of the printer as configured during the Wi-Fi setup. Used as identifier for end users. :param is_online: Whether this cluster is currently connected to the cloud. :param status: The status of the cluster authentication (active or inactive). + :param display_status: The display status of the cluster. :param host_version: The firmware version of the cluster host. This is where the Stardust client is running on. :param host_internal_ip: The internal IP address of the host printer. :param friendly_name: The human readable name of the host printer. @@ -31,6 +32,7 @@ class CloudClusterResponse(BaseModel): self.host_guid = host_guid self.host_name = host_name self.status = status + self.display_status = display_status self.is_online = is_online self.host_version = host_version self.host_internal_ip = host_internal_ip @@ -51,5 +53,5 @@ class CloudClusterResponse(BaseModel): Convenience function for printing when debugging. :return: A human-readable representation of the data in this object. """ - return str({k: v for k, v in self.__dict__.items() if k in {"cluster_id", "host_guid", "host_name", "status", "is_online", "host_version", "host_internal_ip", "friendly_name", "printer_type", "printer_count", "capabilities"}}) + return str({k: v for k, v in self.__dict__.items() if k in {"cluster_id", "host_guid", "host_name", "status", "display_status", "is_online", "host_version", "host_internal_ip", "friendly_name", "printer_type", "printer_count", "capabilities"}}) diff --git a/plugins/UM3NetworkPrinting/src/Models/Http/CloudClusterStatus.py b/plugins/UM3NetworkPrinting/src/Models/Http/CloudClusterStatus.py index 5cd151d8ef..34249dc67a 100644 --- a/plugins/UM3NetworkPrinting/src/Models/Http/CloudClusterStatus.py +++ b/plugins/UM3NetworkPrinting/src/Models/Http/CloudClusterStatus.py @@ -14,6 +14,7 @@ class CloudClusterStatus(BaseModel): def __init__(self, printers: List[Union[ClusterPrinterStatus, Dict[str, Any]]], print_jobs: List[Union[ClusterPrintJobStatus, Dict[str, Any]]], generated_time: Union[str, datetime], + unavailable: bool = False, **kwargs) -> None: """Creates a new cluster status model object. @@ -23,6 +24,7 @@ class CloudClusterStatus(BaseModel): """ self.generated_time = self.parseDate(generated_time) + self.active = not unavailable self.printers = self.parseModels(ClusterPrinterStatus, printers) self.print_jobs = self.parseModels(ClusterPrintJobStatus, print_jobs) super().__init__(**kwargs) diff --git a/resources/qml/PrinterSelector/MachineSelector.qml b/resources/qml/PrinterSelector/MachineSelector.qml index 1bad1d70bc..7acdd9573b 100644 --- a/resources/qml/PrinterSelector/MachineSelector.qml +++ b/resources/qml/PrinterSelector/MachineSelector.qml @@ -16,6 +16,7 @@ Cura.ExpandablePopup property bool isConnectedCloudPrinter: machineManager.activeMachineHasCloudConnection property bool isCloudRegistered: machineManager.activeMachineHasCloudRegistration property bool isGroup: machineManager.activeMachineIsGroup + property bool isCloudActive: machineManager.activeMachineIsCloudActive property string machineName: { if (isNetworkPrinter && machineManager.activeMachineNetworkGroupName != "") { @@ -40,7 +41,14 @@ Cura.ExpandablePopup } else if (isConnectedCloudPrinter && Cura.API.connectionStatus.isInternetReachable) { - return "printer_cloud_connected" + if (isCloudActive) + { + return "printer_cloud_connected" + } + else + { + return "printer_cloud_inactive" + } } else if (isCloudRegistered) { @@ -53,7 +61,7 @@ Cura.ExpandablePopup } function getConnectionStatusMessage() { - if (connectionStatus == "printer_cloud_not_available") + if (connectionStatus === "printer_cloud_not_available") { if(Cura.API.connectionStatus.isInternetReachable) { @@ -78,6 +86,10 @@ Cura.ExpandablePopup return catalog.i18nc("@status", "The cloud connection is currently unavailable. Please check your internet connection.") } } + else if(connectionStatus === "printer_cloud_inactive") + { + return catalog.i18nc("@status", "This printer is deactivated and can not accept commands or jobs.") + } else { return "" @@ -130,14 +142,18 @@ Cura.ExpandablePopup source: { - if (connectionStatus == "printer_connected") + if (connectionStatus === "printer_connected") { return UM.Theme.getIcon("CheckBlueBG", "low") } - else if (connectionStatus == "printer_cloud_connected" || connectionStatus == "printer_cloud_not_available") + else if (connectionStatus === "printer_cloud_connected" || connectionStatus === "printer_cloud_not_available") { return UM.Theme.getIcon("CloudBadge", "low") } + else if (connectionStatus === "printer_cloud_inactive") + { + return UM.Theme.getIcon("WarningBadge", "low") + } else { return "" @@ -147,7 +163,21 @@ Cura.ExpandablePopup width: UM.Theme.getSize("printer_status_icon").width height: UM.Theme.getSize("printer_status_icon").height - color: connectionStatus == "printer_cloud_not_available" ? UM.Theme.getColor("cloud_unavailable") : UM.Theme.getColor("primary") + color: + { + if (connectionStatus === "printer_cloud_not_available") + { + return UM.Theme.getColor("cloud_unavailable") + } + else if(connectionStatus === "printer_cloud_inactive") + { + return UM.Theme.getColor("cloud_inactive") + } + else + { + return UM.Theme.getColor("primary") + } + } visible: (isNetworkPrinter || isCloudRegistered) && source != "" diff --git a/resources/themes/cura-light/theme.json b/resources/themes/cura-light/theme.json index 1ae316f96c..8d09d7837d 100644 --- a/resources/themes/cura-light/theme.json +++ b/resources/themes/cura-light/theme.json @@ -496,6 +496,7 @@ "monitor_carousel_dot_current": [119, 119, 119, 255], "cloud_unavailable": [153, 153, 153, 255], + "cloud_inactive": "warning", "connection_badge_background": [255, 255, 255, 255], "warning_badge_background": [0, 0, 0, 255], "error_badge_background": [255, 255, 255, 255],