Add Install Pending Updates button to Account popup

CURA-7473
This commit is contained in:
Nino van Hooff 2020-06-26 11:37:01 +02:00
parent f35ca0eb7d
commit 4f1a18f102
3 changed files with 64 additions and 12 deletions

View file

@ -1,7 +1,7 @@
# Copyright (c) 2018 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from datetime import datetime from datetime import datetime
from typing import Optional, Dict, TYPE_CHECKING, Union from typing import Optional, Dict, TYPE_CHECKING, Callable
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty, QTimer, Q_ENUMS from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty, QTimer, Q_ENUMS
@ -56,6 +56,7 @@ class Account(QObject):
lastSyncDateTimeChanged = pyqtSignal() lastSyncDateTimeChanged = pyqtSignal()
syncStateChanged = pyqtSignal(int) # because SyncState is an int Enum syncStateChanged = pyqtSignal(int) # because SyncState is an int Enum
manualSyncEnabledChanged = pyqtSignal(bool) manualSyncEnabledChanged = pyqtSignal(bool)
updatePackagesEnabledChanged = pyqtSignal(bool)
def __init__(self, application: "CuraApplication", parent = None) -> None: def __init__(self, application: "CuraApplication", parent = None) -> None:
super().__init__(parent) super().__init__(parent)
@ -66,6 +67,8 @@ class Account(QObject):
self._logged_in = False self._logged_in = False
self._sync_state = SyncState.IDLE self._sync_state = SyncState.IDLE
self._manual_sync_enabled = False self._manual_sync_enabled = False
self._update_packages_enabled = False
self._update_packages_action = None # type: Callable
self._last_sync_str = "-" self._last_sync_str = "-"
self._callback_port = 32118 self._callback_port = 32118
@ -143,6 +146,18 @@ class Account(QObject):
if not self._update_timer.isActive(): if not self._update_timer.isActive():
self._update_timer.start() self._update_timer.start()
def setUpdatePackagesAction(self, action: Callable):
""" Set the callback which will be invoked when the user clicks the update packages button
Should be invoked after your service sets the sync state to SYNCING and before setting the
sync state to SUCCESS.
Action will be reset to None when the next sync starts
"""
self._update_packages_action = action
self._update_packages_enabled = True
self.updatePackagesEnabledChanged.emit(self._update_packages_enabled)
def _onAccessTokenChanged(self): def _onAccessTokenChanged(self):
self.accessTokenChanged.emit() self.accessTokenChanged.emit()
@ -185,6 +200,9 @@ class Account(QObject):
sync is currently running, a sync will be requested. sync is currently running, a sync will be requested.
""" """
self._update_packages_action = None
self._update_packages_enabled = False
self.updatePackagesEnabledChanged.emit(self._update_packages_enabled)
if self._update_timer.isActive(): if self._update_timer.isActive():
self._update_timer.stop() self._update_timer.stop()
elif self._sync_state == SyncState.SYNCING: elif self._sync_state == SyncState.SYNCING:
@ -251,6 +269,10 @@ class Account(QObject):
def manualSyncEnabled(self) -> bool: def manualSyncEnabled(self) -> bool:
return self._manual_sync_enabled return self._manual_sync_enabled
@pyqtProperty(bool, notify=updatePackagesEnabledChanged)
def updatePackagesEnabled(self) -> bool:
return self._update_packages_enabled
@pyqtSlot() @pyqtSlot()
@pyqtSlot(bool) @pyqtSlot(bool)
def sync(self, user_initiated: bool = False) -> None: def sync(self, user_initiated: bool = False) -> None:
@ -259,11 +281,14 @@ class Account(QObject):
self._sync() self._sync()
@pyqtSlot()
def update_packages(self):
if self._update_packages_action is not None:
self._update_packages_action()
@pyqtSlot() @pyqtSlot()
def popupOpened(self) -> None: def popupOpened(self) -> None:
self._setManualSyncEnabled(True) self._setManualSyncEnabled(True)
self._sync_state = SyncState.IDLE
self.syncStateChanged.emit(self._sync_state)
@pyqtSlot() @pyqtSlot()
def logout(self) -> None: def logout(self) -> None:

View file

@ -95,10 +95,6 @@ class CloudPackageChecker(QObject):
user_subscribed_packages = {plugin["package_id"] for plugin in subscribed_packages_payload} user_subscribed_packages = {plugin["package_id"] for plugin in subscribed_packages_payload}
user_installed_packages = self._package_manager.getAllInstalledPackageIDs() user_installed_packages = self._package_manager.getAllInstalledPackageIDs()
if user_subscribed_packages == self._last_notified_packages:
# already notified user about these
return
# We need to re-evaluate the dismissed packages # We need to re-evaluate the dismissed packages
# (i.e. some package might got updated to the correct SDK version in the meantime, # (i.e. some package might got updated to the correct SDK version in the meantime,
# hence remove them from the Dismissed Incompatible list) # hence remove them from the Dismissed Incompatible list)
@ -109,7 +105,15 @@ class CloudPackageChecker(QObject):
# We check if there are packages installed in Web Marketplace but not in Cura marketplace # We check if there are packages installed in Web Marketplace but not in Cura marketplace
package_discrepancy = list(user_subscribed_packages.difference(user_installed_packages)) package_discrepancy = list(user_subscribed_packages.difference(user_installed_packages))
if package_discrepancy: if package_discrepancy:
account = self._application.getCuraAPI().account
account.setUpdatePackagesAction(lambda: self._onSyncButtonClicked(None, None))
if user_subscribed_packages == self._last_notified_packages:
# already notified user about these
return
Logger.log("d", "Discrepancy found between Cloud subscribed packages and Cura installed packages") Logger.log("d", "Discrepancy found between Cloud subscribed packages and Cura installed packages")
self._model.addDiscrepancies(package_discrepancy) self._model.addDiscrepancies(package_discrepancy)
self._model.initialize(self._package_manager, subscribed_packages_payload) self._model.initialize(self._package_manager, subscribed_packages_payload)
@ -144,7 +148,8 @@ class CloudPackageChecker(QObject):
self._message.hide() self._message.hide()
self._message = None self._message = None
def _onSyncButtonClicked(self, sync_message: Message, sync_message_action: str) -> None: def _onSyncButtonClicked(self, sync_message: Optional[Message], sync_message_action: Optional[str]) -> None:
sync_message.hide() if sync_message is not None:
sync_message.hide()
self._hideSyncMessage() # Should be the same message, but also sets _message to None self._hideSyncMessage() # Should be the same message, but also sets _message to None
self.discrepancies.emit(self._model) self.discrepancies.emit(self._model)

View file

@ -49,7 +49,7 @@ Row // Sync state icon + message
width: 20 * screenScaleFactor width: 20 * screenScaleFactor
height: width height: width
source: Cura.API.account.manualSyncEnabled ? UM.Theme.getIcon("update") : UM.Theme.getIcon("checked") // source is determined by State
color: UM.Theme.getColor("account_sync_state_icon") color: UM.Theme.getColor("account_sync_state_icon")
RotationAnimator RotationAnimator
@ -80,14 +80,36 @@ Row // Sync state icon + message
Label Label
{ {
id: stateLabel id: stateLabel
text: catalog.i18nc("@state", catalog.i18nc("@label", "Account synced")) // text is determined by State
color: UM.Theme.getColor("text") color: UM.Theme.getColor("text")
font: UM.Theme.getFont("medium") font: UM.Theme.getFont("medium")
renderType: Text.NativeRendering renderType: Text.NativeRendering
width: contentWidth + UM.Theme.getSize("default_margin").height width: contentWidth + UM.Theme.getSize("default_margin").height
height: contentHeight height: contentHeight
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
visible: !Cura.API.account.manualSyncEnabled visible: !Cura.API.account.manualSyncEnabled && !Cura.API.account.updatePackagesEnabled
}
Label
{
id: updatePackagesButton
text: catalog.i18nc("@button", "Install pending updates")
color: UM.Theme.getColor("secondary_button_text")
font: UM.Theme.getFont("medium")
renderType: Text.NativeRendering
verticalAlignment: Text.AlignVCenter
height: contentHeight
width: contentWidth + UM.Theme.getSize("default_margin").height
visible: Cura.API.account.updatePackagesEnabled
MouseArea
{
anchors.fill: parent
onClicked: Cura.API.account.update_packages()
hoverEnabled: true
onEntered: updatePackagesButton.font.underline = true
onExited: updatePackagesButton.font.underline = false
}
} }
Label Label