Show cloud connection flow message when adding local network device

This commit is contained in:
ChrisTerBeke 2019-07-30 22:44:45 +02:00
parent d280252437
commit 52a5a43fe2
No known key found for this signature in database
GPG key ID: A49F1AB9D7E0C263
4 changed files with 66 additions and 152 deletions

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

View file

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

View file

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

View file

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