mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-04-23 22:29:41 +08:00
Merge pull request #7831 from Ultimaker/CURA-7437_no_internet_cloud_status
CURA-7437_no_internet_cloud_status
This commit is contained in:
commit
56e8827d00
64
cura/API/ConnectionStatus.py
Normal file
64
cura/API/ConnectionStatus.py
Normal file
@ -0,0 +1,64 @@
|
||||
from typing import Optional
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtSignal, QTimer, pyqtProperty
|
||||
from PyQt5.QtNetwork import QNetworkReply
|
||||
|
||||
from UM.TaskManagement.HttpRequestManager import HttpRequestManager
|
||||
from cura.UltimakerCloud import UltimakerCloudAuthentication
|
||||
|
||||
|
||||
class ConnectionStatus(QObject):
|
||||
"""Status info for some web services"""
|
||||
|
||||
UPDATE_INTERVAL = 10.0 # seconds
|
||||
ULTIMAKER_CLOUD_STATUS_URL = UltimakerCloudAuthentication.CuraCloudAPIRoot + "/connect/v1/"
|
||||
|
||||
__instance = None # type: Optional[ConnectionStatus]
|
||||
|
||||
internetReachableChanged = pyqtSignal()
|
||||
umCloudReachableChanged = pyqtSignal()
|
||||
|
||||
@classmethod
|
||||
def getInstance(cls, *args, **kwargs) -> "ConnectionStatus":
|
||||
if cls.__instance is None:
|
||||
cls.__instance = cls(*args, **kwargs)
|
||||
return cls.__instance
|
||||
|
||||
def __init__(self, parent: Optional["QObject"] = None):
|
||||
super().__init__(parent)
|
||||
|
||||
self._http = HttpRequestManager.getInstance()
|
||||
self._statuses = {
|
||||
self.ULTIMAKER_CLOUD_STATUS_URL: True,
|
||||
"http://example.com": True
|
||||
}
|
||||
|
||||
# Create a timer for automatic updates
|
||||
self._update_timer = QTimer()
|
||||
self._update_timer.setInterval(int(self.UPDATE_INTERVAL * 1000))
|
||||
# The timer is restarted automatically
|
||||
self._update_timer.setSingleShot(False)
|
||||
self._update_timer.timeout.connect(self._update)
|
||||
self._update_timer.start()
|
||||
|
||||
@pyqtProperty(bool, notify=internetReachableChanged)
|
||||
def isInternetReachable(self) -> bool:
|
||||
# Is any of the test urls reachable?
|
||||
return any(self._statuses.values())
|
||||
|
||||
def _update(self):
|
||||
for url in self._statuses.keys():
|
||||
self._http.get(
|
||||
url = url,
|
||||
callback = self._statusCallback,
|
||||
error_callback = self._statusCallback,
|
||||
timeout = 5
|
||||
)
|
||||
|
||||
def _statusCallback(self, reply: QNetworkReply, error: QNetworkReply.NetworkError = None):
|
||||
url = reply.request().url().toString()
|
||||
prev_statuses = self._statuses.copy()
|
||||
self._statuses[url] = HttpRequestManager.replyIndicatesSuccess(reply, error)
|
||||
|
||||
if any(self._statuses.values()) != any(prev_statuses.values()):
|
||||
self.internetReachableChanged.emit()
|
@ -5,6 +5,7 @@ from typing import Optional, TYPE_CHECKING
|
||||
from PyQt5.QtCore import QObject, pyqtProperty
|
||||
|
||||
from cura.API.Backups import Backups
|
||||
from cura.API.ConnectionStatus import ConnectionStatus
|
||||
from cura.API.Interface import Interface
|
||||
from cura.API.Account import Account
|
||||
|
||||
@ -45,6 +46,8 @@ class CuraAPI(QObject):
|
||||
# Backups API
|
||||
self._backups = Backups(self._application)
|
||||
|
||||
self._connectionStatus = ConnectionStatus()
|
||||
|
||||
# Interface API
|
||||
self._interface = Interface(self._application)
|
||||
|
||||
@ -55,6 +58,10 @@ class CuraAPI(QObject):
|
||||
def account(self) -> "Account":
|
||||
return self._account
|
||||
|
||||
@pyqtProperty(QObject, constant = True)
|
||||
def connectionStatus(self) -> "ConnectionStatus":
|
||||
return self._connectionStatus
|
||||
|
||||
@property
|
||||
def backups(self) -> "Backups":
|
||||
return self._backups
|
||||
|
@ -490,6 +490,10 @@ class MachineManager(QObject):
|
||||
def activeMachineHasCloudConnection(self) -> bool:
|
||||
# A cloud connection is only available if any output device actually is a cloud connected device.
|
||||
return any(d.connectionType == ConnectionType.CloudConnection for d in self._printer_output_devices)
|
||||
|
||||
@pyqtProperty(bool, notify = printerConnectedStatusChanged)
|
||||
def activeMachineHasCloudRegistration(self) -> bool:
|
||||
return self.activeMachine is not None and ConnectionType.CloudConnection in self.activeMachine.configuredConnectionTypes
|
||||
|
||||
@pyqtProperty(bool, notify = printerConnectedStatusChanged)
|
||||
def activeMachineIsUsingCloudConnection(self) -> bool:
|
||||
|
@ -265,7 +265,7 @@ class LocalClusterOutputDeviceManager:
|
||||
## Nudge the user to start using Ultimaker Cloud.
|
||||
@staticmethod
|
||||
def _showCloudFlowMessage(device: LocalClusterOutputDevice) -> None:
|
||||
if CuraApplication.getInstance().getMachineManager().activeMachineIsUsingCloudConnection:
|
||||
if CuraApplication.getInstance().getMachineManager().activeMachineHasCloudRegistration:
|
||||
# This printer is already cloud connected, so we do not bother the user anymore.
|
||||
return
|
||||
if not CuraApplication.getInstance().getCuraAPI().account.isLoggedIn:
|
||||
|
@ -35,7 +35,8 @@ Item
|
||||
property color headerActiveColor: UM.Theme.getColor("secondary")
|
||||
property color headerHoverColor: UM.Theme.getColor("action_button_hovered")
|
||||
|
||||
property alias enabled: mouseArea.enabled
|
||||
property alias mouseArea: headerMouseArea
|
||||
property alias enabled: headerMouseArea.enabled
|
||||
|
||||
// Text to show when this component is disabled
|
||||
property alias disabledText: disabledLabel.text
|
||||
@ -139,6 +140,16 @@ Item
|
||||
anchors.fill: parent
|
||||
visible: base.enabled
|
||||
|
||||
MouseArea
|
||||
{
|
||||
id: headerMouseArea
|
||||
anchors.fill: parent
|
||||
onClicked: toggleContent()
|
||||
hoverEnabled: true
|
||||
onEntered: background.color = headerHoverColor
|
||||
onExited: background.color = base.enabled ? headerBackgroundColor : UM.Theme.getColor("disabled")
|
||||
}
|
||||
|
||||
Loader
|
||||
{
|
||||
id: headerItemLoader
|
||||
@ -180,15 +191,6 @@ Item
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea
|
||||
{
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
onClicked: toggleContent()
|
||||
hoverEnabled: true
|
||||
onEntered: background.color = headerHoverColor
|
||||
onExited: background.color = base.enabled ? headerBackgroundColor : UM.Theme.getColor("disabled")
|
||||
}
|
||||
}
|
||||
|
||||
DropShadow
|
||||
|
@ -5,16 +5,49 @@ import QtQuick 2.7
|
||||
import QtQuick.Controls 2.3
|
||||
|
||||
import UM 1.2 as UM
|
||||
import Cura 1.0 as Cura
|
||||
import Cura 1.1 as Cura
|
||||
|
||||
Cura.ExpandablePopup
|
||||
{
|
||||
id: machineSelector
|
||||
|
||||
property bool isNetworkPrinter: Cura.MachineManager.activeMachineHasNetworkConnection
|
||||
property bool isCloudPrinter: Cura.MachineManager.activeMachineHasCloudConnection
|
||||
property bool isConnectedCloudPrinter: Cura.MachineManager.activeMachineHasCloudConnection
|
||||
property bool isCloudRegistered: Cura.MachineManager.activeMachineHasCloudRegistration
|
||||
property bool isGroup: Cura.MachineManager.activeMachineIsGroup
|
||||
|
||||
readonly property string connectionStatus: {
|
||||
if (isNetworkPrinter)
|
||||
{
|
||||
return "printer_connected"
|
||||
}
|
||||
else if (isConnectedCloudPrinter && Cura.API.connectionStatus.isInternetReachable)
|
||||
{
|
||||
return "printer_cloud_connected"
|
||||
}
|
||||
else if (isCloudRegistered)
|
||||
{
|
||||
return "printer_cloud_not_available"
|
||||
}
|
||||
else
|
||||
{
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
readonly property string connectionStatusMessage: {
|
||||
if (connectionStatus == "printer_cloud_not_available")
|
||||
{
|
||||
if(Cura.API.connectionStatus.isInternetReachable){
|
||||
return catalog.i18nc("@status", "The cloud connection is currently unavailable. Please check your internet connection and sign in to connect to the cloud printer.")
|
||||
} else {
|
||||
return catalog.i18nc("@status", "The cloud connection is currently unavailable. Please check your internet connection.")
|
||||
}
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
contentPadding: UM.Theme.getSize("default_lining").width
|
||||
contentAlignment: Cura.ExpandablePopup.ContentAlignment.AlignLeft
|
||||
|
||||
@ -44,7 +77,7 @@ Cura.ExpandablePopup
|
||||
{
|
||||
return UM.Theme.getIcon("printer_group")
|
||||
}
|
||||
else if (isNetworkPrinter || isCloudPrinter)
|
||||
else if (isNetworkPrinter || isCloudRegistered)
|
||||
{
|
||||
return UM.Theme.getIcon("printer_single")
|
||||
}
|
||||
@ -59,6 +92,7 @@ Cura.ExpandablePopup
|
||||
|
||||
UM.RecolorImage
|
||||
{
|
||||
id: connectionStatusImage
|
||||
anchors
|
||||
{
|
||||
bottom: parent.bottom
|
||||
@ -66,27 +100,14 @@ Cura.ExpandablePopup
|
||||
leftMargin: UM.Theme.getSize("thick_margin").width
|
||||
}
|
||||
|
||||
source:
|
||||
{
|
||||
if (isNetworkPrinter)
|
||||
{
|
||||
return UM.Theme.getIcon("printer_connected")
|
||||
}
|
||||
else if (isCloudPrinter)
|
||||
{
|
||||
return UM.Theme.getIcon("printer_cloud_connected")
|
||||
}
|
||||
else
|
||||
{
|
||||
return ""
|
||||
}
|
||||
}
|
||||
source: UM.Theme.getIcon(connectionStatus)
|
||||
|
||||
width: UM.Theme.getSize("printer_status_icon").width
|
||||
height: UM.Theme.getSize("printer_status_icon").height
|
||||
|
||||
color: UM.Theme.getColor("primary")
|
||||
visible: isNetworkPrinter || isCloudPrinter
|
||||
color: connectionStatus == "printer_cloud_not_available" ? UM.Theme.getColor("cloud_unavailable") : UM.Theme.getColor("primary")
|
||||
|
||||
visible: isNetworkPrinter || isCloudRegistered
|
||||
|
||||
// Make a themable circle in the background so we can change it in other themes
|
||||
Rectangle
|
||||
@ -100,6 +121,38 @@ Cura.ExpandablePopup
|
||||
color: UM.Theme.getColor("main_background")
|
||||
z: parent.z - 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea // Connection status tooltip hover area
|
||||
{
|
||||
id: connectionStatusTooltipHoverArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: connectionStatusMessage !== ""
|
||||
acceptedButtons: Qt.NoButton // react to hover only, don't steal clicks
|
||||
|
||||
onEntered:
|
||||
{
|
||||
machineSelector.mouseArea.entered() // we want both this and the outer area to be entered
|
||||
tooltip.show()
|
||||
}
|
||||
onExited: { tooltip.hide() }
|
||||
}
|
||||
|
||||
Cura.ToolTip
|
||||
{
|
||||
id: tooltip
|
||||
|
||||
width: 250 * screenScaleFactor
|
||||
tooltipText: connectionStatusMessage
|
||||
arrowSize: UM.Theme.getSize("button_tooltip_arrow").width
|
||||
x: connectionStatusImage.x - UM.Theme.getSize("narrow_margin").width
|
||||
y: connectionStatusImage.y + connectionStatusImage.height + UM.Theme.getSize("narrow_margin").height
|
||||
z: popup.z + 1
|
||||
targetPoint: Qt.point(
|
||||
connectionStatusImage.x + Math.round(connectionStatusImage.width / 2),
|
||||
connectionStatusImage.y
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,12 +19,20 @@ ToolTip
|
||||
property int contentAlignment: Cura.ToolTip.ContentAlignment.AlignRight
|
||||
|
||||
property alias tooltipText: tooltip.text
|
||||
property alias arrowSize: backgroundRect.arrowSize
|
||||
property var targetPoint: Qt.point(parent.x, y + Math.round(height/2))
|
||||
|
||||
id: tooltip
|
||||
text: ""
|
||||
delay: 500
|
||||
font: UM.Theme.getFont("default")
|
||||
visible: opacity != 0.0
|
||||
opacity: 0.0 // initially hidden
|
||||
|
||||
Behavior on opacity
|
||||
{
|
||||
NumberAnimation { duration: 100; }
|
||||
}
|
||||
|
||||
// If the text is not set, just set the height to 0 to prevent it from showing
|
||||
height: text != "" ? label.contentHeight + 2 * UM.Theme.getSize("thin_margin").width: 0
|
||||
@ -60,4 +68,12 @@ ToolTip
|
||||
color: UM.Theme.getColor("tooltip_text")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
function show() {
|
||||
opacity = 1
|
||||
}
|
||||
|
||||
function hide() {
|
||||
opacity = 0
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
|
||||
<title>Artboard Copy 4</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<path d="M6,0 C9.3137085,0 12,2.6862915 12,6 C12,9.3137085 9.3137085,12 6,12 C2.6862915,12 0,9.3137085 0,6 C0,2.6862915 2.6862915,0 6,0 Z M5.2,3 C4.08,3 3.2,3.91666667 3.2,5.08333333 L3.2,5.125 L3.2,5.125 C2.52,5.20833333 2,5.83333333 2,6.54166667 C2,7.33333333 2.64,8 3.4,8 L8.6,8 L8.6,8 C9.36,8 10,7.33333333 10,6.54166667 C10,5.79166667 9.48,5.20833333 8.8,5.08333333 C8.72,4.375 8.12,3.83333333 7.4,3.83333333 C7.2,3.83333333 7.04,3.875 6.88,3.95833333 C6.52,3.375 5.88,3 5.2,3 Z" id="path-1"></path>
|
||||
</defs>
|
||||
<g id="Artboard-Copy-4" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<rect id="Rectangle" fill="#999999" transform="translate(7.187184, 7.187184) scale(-1, 1) rotate(45.000000) translate(-7.187184, -7.187184) " x="6.43718434" y="-0.812815665" width="1.5" height="16" rx="0.75"></rect>
|
||||
<g id="Path" transform="translate(1.000000, 1.000000)">
|
||||
<mask id="mask-2" fill="white">
|
||||
<use xlink:href="#path-1"></use>
|
||||
</mask>
|
||||
<use id="Combined-Shape" fill="#999999" xlink:href="#path-1"></use>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
@ -438,7 +438,9 @@
|
||||
"monitor_shadow": [200, 200, 200, 255],
|
||||
|
||||
"monitor_carousel_dot": [216, 216, 216, 255],
|
||||
"monitor_carousel_dot_current": [119, 119, 119, 255]
|
||||
"monitor_carousel_dot_current": [119, 119, 119, 255],
|
||||
|
||||
"cloud_unavailable": [153, 153, 153, 255]
|
||||
},
|
||||
|
||||
"sizes": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user