mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-08 07:27:29 -06:00
Show cloud connection flow message when adding local network device
This commit is contained in:
parent
d280252437
commit
52a5a43fe2
4 changed files with 66 additions and 152 deletions
38
plugins/UM3NetworkPrinting/src/CloudFlowMessage.py
Normal file
38
plugins/UM3NetworkPrinting/src/CloudFlowMessage.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
import os
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QUrl
|
||||||
|
from PyQt5.QtGui import QDesktopServices
|
||||||
|
|
||||||
|
from UM import i18nCatalog
|
||||||
|
from UM.Message import Message
|
||||||
|
from cura.CuraApplication import CuraApplication
|
||||||
|
|
||||||
|
|
||||||
|
I18N_CATALOG = i18nCatalog("cura")
|
||||||
|
|
||||||
|
|
||||||
|
class CloudFlowMessage(Message):
|
||||||
|
|
||||||
|
def __init__(self, address: str) -> None:
|
||||||
|
super().__init__(
|
||||||
|
text=I18N_CATALOG.i18nc("@info:status",
|
||||||
|
"Send and monitor print jobs from anywhere using your Ultimaker account."),
|
||||||
|
lifetime=0,
|
||||||
|
dismissable=True,
|
||||||
|
option_state=False,
|
||||||
|
image_source=QUrl.fromLocalFile(os.path.join(
|
||||||
|
CuraApplication.getInstance().getPluginRegistry().getPluginPath("UM3NetworkPrinting"),
|
||||||
|
"resources", "svg", "cloud-flow-start.svg"
|
||||||
|
)),
|
||||||
|
image_caption=I18N_CATALOG.i18nc("@info:status Ultimaker Cloud should not be translated.",
|
||||||
|
"Connect to Ultimaker Cloud"),
|
||||||
|
)
|
||||||
|
self._address = address
|
||||||
|
self.addAction("", I18N_CATALOG.i18nc("@action", "Get started"), "", "")
|
||||||
|
self.actionTriggered.connect(self._onCloudFlowStarted)
|
||||||
|
|
||||||
|
def _onCloudFlowStarted(self, messageId: str, actionId: str) -> None:
|
||||||
|
QDesktopServices.openUrl(QUrl("http://{}/cloud_connect".format(self._address)))
|
||||||
|
self.hide()
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
from ..BaseModel import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
## Class representing the system status of a printer.
|
||||||
|
class PrinterSystemStatus(BaseModel):
|
||||||
|
|
||||||
|
def __init__(self, guid: str, firmware: str, hostname: str, name: str, platform: str, variant: str, **kwargs
|
||||||
|
) -> None:
|
||||||
|
self.guid = guid
|
||||||
|
self.firmware = firmware
|
||||||
|
self.hostname = hostname
|
||||||
|
self.name = name
|
||||||
|
self.platform = platform
|
||||||
|
self.variant = variant
|
||||||
|
super().__init__(**kwargs)
|
|
@ -3,7 +3,6 @@
|
||||||
from typing import Dict, Optional, Callable
|
from typing import Dict, Optional, Callable
|
||||||
|
|
||||||
from UM import i18nCatalog
|
from UM import i18nCatalog
|
||||||
from UM.Logger import Logger
|
|
||||||
from UM.Signal import Signal
|
from UM.Signal import Signal
|
||||||
from UM.Version import Version
|
from UM.Version import Version
|
||||||
|
|
||||||
|
@ -14,9 +13,13 @@ from cura.Settings.GlobalStack import GlobalStack
|
||||||
from .ZeroConfClient import ZeroConfClient
|
from .ZeroConfClient import ZeroConfClient
|
||||||
from .ClusterApiClient import ClusterApiClient
|
from .ClusterApiClient import ClusterApiClient
|
||||||
from .NetworkOutputDevice import NetworkOutputDevice
|
from .NetworkOutputDevice import NetworkOutputDevice
|
||||||
|
from ..CloudFlowMessage import CloudFlowMessage
|
||||||
from ..Models.Http.PrinterSystemStatus import PrinterSystemStatus
|
from ..Models.Http.PrinterSystemStatus import PrinterSystemStatus
|
||||||
|
|
||||||
|
|
||||||
|
I18N_CATALOG = i18nCatalog("cura")
|
||||||
|
|
||||||
|
|
||||||
## The NetworkOutputDeviceManager is responsible for discovering and managing local networked clusters.
|
## The NetworkOutputDeviceManager is responsible for discovering and managing local networked clusters.
|
||||||
class NetworkOutputDeviceManager:
|
class NetworkOutputDeviceManager:
|
||||||
|
|
||||||
|
@ -65,7 +68,7 @@ class NetworkOutputDeviceManager:
|
||||||
self._manual_instances[address] = callback
|
self._manual_instances[address] = callback
|
||||||
new_manual_devices = ",".join(self._manual_instances.keys())
|
new_manual_devices = ",".join(self._manual_instances.keys())
|
||||||
CuraApplication.getInstance().getPreferences().setValue(self.MANUAL_DEVICES_PREFERENCE_KEY, new_manual_devices)
|
CuraApplication.getInstance().getPreferences().setValue(self.MANUAL_DEVICES_PREFERENCE_KEY, new_manual_devices)
|
||||||
api_client = ClusterApiClient(address, self._onApiError)
|
api_client = ClusterApiClient(address, lambda error: print(error))
|
||||||
api_client.getSystem(lambda status: self._onCheckManualDeviceResponse(address, status))
|
api_client.getSystem(lambda status: self._onCheckManualDeviceResponse(address, status))
|
||||||
|
|
||||||
## Remove a manually added networked printer.
|
## Remove a manually added networked printer.
|
||||||
|
@ -103,13 +106,6 @@ class NetworkOutputDeviceManager:
|
||||||
# Remove device if it is not meant for the active machine.
|
# Remove device if it is not meant for the active machine.
|
||||||
CuraApplication.getInstance().getOutputDeviceManager().removeOutputDevice(device.key)
|
CuraApplication.getInstance().getOutputDeviceManager().removeOutputDevice(device.key)
|
||||||
|
|
||||||
## Add a device to the current active machine.
|
|
||||||
@staticmethod
|
|
||||||
def _connectToOutputDevice(device: PrinterOutputDevice, active_machine: GlobalStack) -> None:
|
|
||||||
device.connect()
|
|
||||||
active_machine.addConfiguredConnectionType(device.connectionType.value)
|
|
||||||
CuraApplication.getInstance().getOutputDeviceManager().addOutputDevice(device)
|
|
||||||
|
|
||||||
## Callback for when a manual device check request was responded to.
|
## Callback for when a manual device check request was responded to.
|
||||||
def _onCheckManualDeviceResponse(self, address: str, status: PrinterSystemStatus) -> None:
|
def _onCheckManualDeviceResponse(self, address: str, status: PrinterSystemStatus) -> None:
|
||||||
callback = self._manual_instances.get(address, None)
|
callback = self._manual_instances.get(address, None)
|
||||||
|
@ -191,6 +187,7 @@ class NetworkOutputDeviceManager:
|
||||||
active_machine.setMetaDataEntry(self.META_NETWORK_KEY, device.key)
|
active_machine.setMetaDataEntry(self.META_NETWORK_KEY, device.key)
|
||||||
active_machine.setMetaDataEntry("group_name", device.name)
|
active_machine.setMetaDataEntry("group_name", device.name)
|
||||||
self._connectToOutputDevice(device, active_machine)
|
self._connectToOutputDevice(device, active_machine)
|
||||||
|
CloudFlowMessage(device.ipAddress).show() # Nudge the user to start using Ultimaker Cloud.
|
||||||
|
|
||||||
## Load the user-configured manual devices from Cura preferences.
|
## Load the user-configured manual devices from Cura preferences.
|
||||||
def _getStoredManualInstances(self) -> Dict[str, Optional[Callable]]:
|
def _getStoredManualInstances(self) -> Dict[str, Optional[Callable]]:
|
||||||
|
@ -199,8 +196,9 @@ class NetworkOutputDeviceManager:
|
||||||
manual_instances = preferences.getValue(self.MANUAL_DEVICES_PREFERENCE_KEY).split(",")
|
manual_instances = preferences.getValue(self.MANUAL_DEVICES_PREFERENCE_KEY).split(",")
|
||||||
return {address: None for address in manual_instances}
|
return {address: None for address in manual_instances}
|
||||||
|
|
||||||
## Handles an API error received from the cloud.
|
## Add a device to the current active machine.
|
||||||
# \param errors: The errors received
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _onApiError(errors) -> None:
|
def _connectToOutputDevice(device: PrinterOutputDevice, active_machine: GlobalStack) -> None:
|
||||||
Logger.log("w", str(errors))
|
device.connect()
|
||||||
|
active_machine.addConfiguredConnectionType(device.connectionType.value)
|
||||||
|
CuraApplication.getInstance().getOutputDeviceManager().addOutputDevice(device)
|
||||||
|
|
|
@ -53,142 +53,3 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
|
||||||
## Remove a manually connected networked printer.
|
## Remove a manually connected networked printer.
|
||||||
def removeManualDevice(self, key: str, address: Optional[str] = None) -> None:
|
def removeManualDevice(self, key: str, address: Optional[str] = None) -> None:
|
||||||
self._network_output_device_manager.removeManualDevice(key, address)
|
self._network_output_device_manager.removeManualDevice(key, address)
|
||||||
|
|
||||||
# ## Check if the prerequsites are in place to start the cloud flow
|
|
||||||
# def checkCloudFlowIsPossible(self, cluster: Optional[CloudOutputDevice]) -> None:
|
|
||||||
# Logger.log("d", "Checking if cloud connection is possible...")
|
|
||||||
#
|
|
||||||
# # Pre-Check: Skip if active machine already has been cloud connected or you said don't ask again
|
|
||||||
# active_machine = self._application.getMachineManager().activeMachine # type: Optional[GlobalStack]
|
|
||||||
# if active_machine:
|
|
||||||
# # Check 1A: Printer isn't already configured for cloud
|
|
||||||
# if ConnectionType.CloudConnection.value in active_machine.configuredConnectionTypes:
|
|
||||||
# Logger.log("d", "Active machine was already configured for cloud.")
|
|
||||||
# return
|
|
||||||
#
|
|
||||||
# # Check 1B: Printer isn't already configured for cloud
|
|
||||||
# if active_machine.getMetaDataEntry("cloud_flow_complete", False):
|
|
||||||
# Logger.log("d", "Active machine was already configured for cloud.")
|
|
||||||
# return
|
|
||||||
#
|
|
||||||
# # Check 2: User did not already say "Don't ask me again"
|
|
||||||
# if active_machine.getMetaDataEntry("do_not_show_cloud_message", False):
|
|
||||||
# Logger.log("d", "Active machine shouldn't ask about cloud anymore.")
|
|
||||||
# return
|
|
||||||
#
|
|
||||||
# # Check 3: User is logged in with an Ultimaker account
|
|
||||||
# if not self._account.isLoggedIn:
|
|
||||||
# Logger.log("d", "Cloud Flow not possible: User not logged in!")
|
|
||||||
# return
|
|
||||||
#
|
|
||||||
# # Check 4: Machine is configured for network connectivity
|
|
||||||
# if not self._application.getMachineManager().activeMachineHasNetworkConnection:
|
|
||||||
# Logger.log("d", "Cloud Flow not possible: Machine is not connected!")
|
|
||||||
# return
|
|
||||||
#
|
|
||||||
# # Check 5: Machine has correct firmware version
|
|
||||||
# firmware_version = self._application.getMachineManager().activeMachineFirmwareVersion # type: str
|
|
||||||
# if not Version(firmware_version) > self._min_cloud_version:
|
|
||||||
# Logger.log("d", "Cloud Flow not possible: Machine firmware (%s) is too low! (Requires version %s)",
|
|
||||||
# firmware_version,
|
|
||||||
# self._min_cloud_version)
|
|
||||||
# return
|
|
||||||
#
|
|
||||||
# Logger.log("d", "Cloud flow is possible!")
|
|
||||||
# self.cloudFlowIsPossible.emit()
|
|
||||||
|
|
||||||
# def _onCloudFlowPossible(self) -> None:
|
|
||||||
# # Cloud flow is possible, so show the message
|
|
||||||
# if not self._start_cloud_flow_message:
|
|
||||||
# self._createCloudFlowStartMessage()
|
|
||||||
# if self._start_cloud_flow_message and not self._start_cloud_flow_message.visible:
|
|
||||||
# self._start_cloud_flow_message.show()
|
|
||||||
|
|
||||||
# def _onCloudPrintingConfigured(self, device) -> None:
|
|
||||||
# # Hide the cloud flow start message if it was hanging around already
|
|
||||||
# # For example: if the user already had the browser openen and made the association themselves
|
|
||||||
# if self._start_cloud_flow_message and self._start_cloud_flow_message.visible:
|
|
||||||
# self._start_cloud_flow_message.hide()
|
|
||||||
#
|
|
||||||
# # Cloud flow is complete, so show the message
|
|
||||||
# if not self._cloud_flow_complete_message:
|
|
||||||
# self._createCloudFlowCompleteMessage()
|
|
||||||
# if self._cloud_flow_complete_message and not self._cloud_flow_complete_message.visible:
|
|
||||||
# self._cloud_flow_complete_message.show()
|
|
||||||
#
|
|
||||||
# # Set the machine's cloud flow as complete so we don't ask the user again and again for cloud connected printers
|
|
||||||
# active_machine = self._application.getMachineManager().activeMachine
|
|
||||||
# if active_machine:
|
|
||||||
#
|
|
||||||
# # The active machine _might_ not be the machine that was in the added cloud cluster and
|
|
||||||
# # then this will hide the cloud message for the wrong machine. So we only set it if the
|
|
||||||
# # host names match between the active machine and the newly added cluster
|
|
||||||
# saved_host_name = active_machine.getMetaDataEntry("um_network_key", "").split('.')[0]
|
|
||||||
# added_host_name = device.toDict()["host_name"]
|
|
||||||
#
|
|
||||||
# if added_host_name == saved_host_name:
|
|
||||||
# active_machine.setMetaDataEntry("do_not_show_cloud_message", True)
|
|
||||||
#
|
|
||||||
# return
|
|
||||||
|
|
||||||
# def _onDontAskMeAgain(self, checked: bool) -> None:
|
|
||||||
# active_machine = self._application.getMachineManager().activeMachine # type: Optional[GlobalStack]
|
|
||||||
# if active_machine:
|
|
||||||
# active_machine.setMetaDataEntry("do_not_show_cloud_message", checked)
|
|
||||||
# if checked:
|
|
||||||
# Logger.log("d", "Will not ask the user again to cloud connect for current printer.")
|
|
||||||
# return
|
|
||||||
|
|
||||||
# def _onCloudFlowStarted(self, messageId: str, actionId: str) -> None:
|
|
||||||
# address = self._application.getMachineManager().activeMachineAddress # type: str
|
|
||||||
# if address:
|
|
||||||
# QDesktopServices.openUrl(QUrl("http://" + address + "/cloud_connect"))
|
|
||||||
# if self._start_cloud_flow_message:
|
|
||||||
# self._start_cloud_flow_message.hide()
|
|
||||||
# self._start_cloud_flow_message = None
|
|
||||||
# return
|
|
||||||
|
|
||||||
# def _onReviewCloudConnection(self, messageId: str, actionId: str) -> None:
|
|
||||||
# address = self._application.getMachineManager().activeMachineAddress # type: str
|
|
||||||
# if address:
|
|
||||||
# QDesktopServices.openUrl(QUrl("http://" + address + "/settings"))
|
|
||||||
# return
|
|
||||||
|
|
||||||
# def _onMachineSwitched(self) -> None:
|
|
||||||
# # Hide any left over messages
|
|
||||||
# if self._start_cloud_flow_message is not None and self._start_cloud_flow_message.visible:
|
|
||||||
# self._start_cloud_flow_message.hide()
|
|
||||||
# if self._cloud_flow_complete_message is not None and self._cloud_flow_complete_message.visible:
|
|
||||||
# self._cloud_flow_complete_message.hide()
|
|
||||||
#
|
|
||||||
# # Check for cloud flow again with newly selected machine
|
|
||||||
# self.checkCloudFlowIsPossible(None)
|
|
||||||
|
|
||||||
# def _createCloudFlowStartMessage(self):
|
|
||||||
# self._start_cloud_flow_message = Message(
|
|
||||||
# text = i18n_catalog.i18nc("@info:status", "Send and monitor print jobs from anywhere using your Ultimaker account."),
|
|
||||||
# lifetime = 0,
|
|
||||||
# image_source = QUrl.fromLocalFile(os.path.join(
|
|
||||||
# PluginRegistry.getInstance().getPluginPath("UM3NetworkPrinting"),
|
|
||||||
# "resources", "svg", "cloud-flow-start.svg"
|
|
||||||
# )),
|
|
||||||
# image_caption = i18n_catalog.i18nc("@info:status Ultimaker Cloud is a brand name and shouldn't be translated.", "Connect to Ultimaker Cloud"),
|
|
||||||
# option_text = i18n_catalog.i18nc("@action", "Don't ask me again for this printer."),
|
|
||||||
# option_state = False
|
|
||||||
# )
|
|
||||||
# self._start_cloud_flow_message.addAction("", i18n_catalog.i18nc("@action", "Get started"), "", "")
|
|
||||||
# self._start_cloud_flow_message.optionToggled.connect(self._onDontAskMeAgain)
|
|
||||||
# self._start_cloud_flow_message.actionTriggered.connect(self._onCloudFlowStarted)
|
|
||||||
|
|
||||||
# def _createCloudFlowCompleteMessage(self):
|
|
||||||
# self._cloud_flow_complete_message = Message(
|
|
||||||
# text = i18n_catalog.i18nc("@info:status", "You can now send and monitor print jobs from anywhere using your Ultimaker account."),
|
|
||||||
# lifetime = 30,
|
|
||||||
# image_source = QUrl.fromLocalFile(os.path.join(
|
|
||||||
# PluginRegistry.getInstance().getPluginPath("UM3NetworkPrinting"),
|
|
||||||
# "resources", "svg", "cloud-flow-completed.svg"
|
|
||||||
# )),
|
|
||||||
# image_caption = i18n_catalog.i18nc("@info:status", "Connected!")
|
|
||||||
# )
|
|
||||||
# self._cloud_flow_complete_message.addAction("", i18n_catalog.i18nc("@action", "Review your connection"), "", "", 1) # TODO: Icon
|
|
||||||
# self._cloud_flow_complete_message.actionTriggered.connect(self._onReviewCloudConnection)
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue