Repository: spyder-ide/spyder

Issue:
New update status bar default message, visibility behavior and update process for the Windows standalone installer
As part of #18619 a new status bar to handle the Spyder update state was proposed (initially for the Windows standalone installer). Talking with @ccordoba12 some discussion regarding what the default message should be (currently the Spyder version installed: ![imagen](https://user-images.githubusercontent.com/16781833/185672676-6e048de6-9560-4a6a-a85d-2d528cb551d0.png)) and if the status bar should only be shown for the update process (to show for example only if an update is available, is the update is being downloaded or installed, or if ti was cancelled) and hide it otherwise (instead of showing the status bar always) raised.

Currently at [#18619](https://github.com/spyder-ide/spyder/pull/18619/commits/98ec631729e94bdd3cc1f2f628eab4f9b94e0c38) the status bar always is visible and it shows these possible states:

* Spyder current version (for example 5.3.1): ![imagen](https://user-images.githubusercontent.com/16781833/185673326-f1d19dbd-3cb6-44a2-9c83-4281c3688637.png)
* Checking for updates: ![imagen](https://user-images.githubusercontent.com/16781833/185673473-aadcc918-a118-4add-a1d7-c4f37a91030e.png)

* An update is pending: ![imagen](https://user-images.githubusercontent.com/16781833/185673687-c22e8661-d9cb-4465-b4b0-f1e7eedeb046.png)

* Downloading the new version installer: ![imagen](https://user-images.githubusercontent.com/16781833/185673571-e2560a33-3bbe-423b-91ff-dc6db80b21d1.png)

* Installing new version: ![imagen](https://user-images.githubusercontent.com/16781833/185674647-72e4fd6b-82ab-4774-ba41-a85094043162.png)

Thinking about it probably the messages for the different states could be improved too.

So to discuss and make a decision without having to extend further the comments at the PR this issue is created.

Pinging @CAM-Gerlach since he could contribute to the discussion





Discussion:
Thanks @dalthviz . I looked over at the issue, but as the one demo video did not appear to actually show the status bar at all, I had trouble getting a good sense for what all the current interaction patterns are here. (I did immediately notice some bad grammar and confusing phrasing in the dialog box shown in the demo video, which I submitted a suggestion to fix).

In particular, how do you get from one state to another? Presumably the first three are automatic, but what about the last two? Does the user right-click on it to select "Install update" or similar? Also, can the user right-click to select "Check for updates"? Anything else? It wasn't immediately clear to be skimming the PR comments and content.

Some initial comments:

> An update is pending:

`Update available` would be both clearer and generally more idiomatic for this situation (assuming that's what this actually means); update pending typically means the update is waiting on something else, such as a download, another update to install, or the like, whereas "Update available" makes much more clear what this is indicating (again, assuming I have interpreted it correctly).

> Downloading the new version installer: imagen

`Downloading update` would be a bit more clear, obvious and idiomatic, and a touch shorter

> Installing new version:

`Installing update` would follow the pattern of the others, and be more clear _what_ is being installed.
Thanks for checking @CAM-Gerlach ! Regarding the questions

> In particular, how do you get from one state to another? Presumably the first three are automatic, but what about the last two? Does the user right-click on it to select "Install update" or similar? Also, can the user right-click to select "Check for updates"? Anything else? It wasn't immediately clear to be skimming the PR comments and content.

For any installation medium states:

* The `5.3.1` (current version, showing 5.3.1 just for testing) state is like a default state if no check for updates/new version is done or no update was found that is what the users will see.
*  The `Checking for updates` state is shown when the validation for updates is done either automatically when Spyder is launched (and the option to check updates automatically is enabled) or by manually clicking from the `About` menu the action `Check for updates...`
* The  `Pending update` state is shown when an update/new Spyder version was found and the user doesn't proceed to install it right away or if the user needs to do something else outside Spyder (runnig conda/pip commands for example). For the Windows standalone version if the user clicks the status bar with this state a dialog asking if the user wants to download and install the update appears.

Windows standalone (and maybe MacOS standalone in the future):

* The `Downloading installer` state is shown when the user accepts to download and install an update for the Windows standalone version (either accepting the dialog after the check for updates finds an update or when clicking the status bar with the `Peding update` state and accepting the update). If the user clicks the status bar a dialog showing the download progress is shown. Currently is shown only if the user clicks the status bar).
     * From the download progress dialog you can cancel the download which ends up changing again the status bar to the `Pending update` state.
* The `Installing` state is shown when the new Windows standalone version installer was downloaded an launched

A preview of the functionality:

* Starting Spyder with  the `check for updates` option enabled and using the dialog to trigger the download and installation from the status bar:
   
![state1](https://user-images.githubusercontent.com/16781833/185958464-e8e22061-252b-4882-aa53-b3bd7c9cb7af.gif)
 
* Cancelling download:

![state2](https://user-images.githubusercontent.com/16781833/185958868-52cbd8ec-48b5-4ca7-9633-985f0a434f39.gif)

* Running the installer:

https://user-images.githubusercontent.com/16781833/185960732-b2367292-d844-46f4-aee5-4e992213b5f3.mp4



Regarding your suggestion, I think you got the idea of the states so I would say that we will change them to use the suggested text :+1:

If you have any other suggestion taking into account the above explanation let me know!

Thanks for the detailed explanations and the throughout videos, @dalthviz ! That is extremely helpful showing how this new feature works, and would be great to include or at least mention in a prominent place on #18619 for others curious.

As you mentioned, it seemed from your initial descriptions I had a fairly good grasp of what the states were; most of my uncertainty concerned the interaction with the status bar widget and the transition between states, and it seems the scope of the change UI/UX wise went well beyond what I was initially expecting.

Overall, the UX looks quite good overall, and covers most of the basics. One thing that would be nice to see is to trigger an update check when clicking the status bar icon in the "up to date" state, as this would seem to be a natural parallel to the other actions (given they are all involve a click of the status bar item to trigger a transition between states), rather than requiring the user to find the update item in the menu.

Also, one followup question—what does the transition look like between the "downloading" and "installing" states? Is it just automatic (I'm guessing?), or does it require user confirmation? Does the dialog box for downloading, if opened, get replaced by or transition to the update one?
Thanks for the new feedback @CAM-Gerlach !

> One thing that would be nice to see is to trigger an update check when clicking the status bar icon in the "up to date" state, as this would seem to be a natural parallel to the other actions (given they are all involve a click of the status bar item to trigger a transition between states), rather than requiring the user to find the update item in the menu.

I think that is a quite nice idea. We will try to incorporate it :+1:

> Also, one followup question—what does the transition look like between the "downloading" and "installing" states? Is it just automatic (I'm guessing?), or does it require user confirmation? Does the dialog box for downloading, if opened, get replaced by or transition to the update one?

Yep is automatic and yes the dialog that can be opened to see the download progress changes to be an indertermined progress bar informing that now the new version/update is being installed.
Just in case, some ideas discussed to improve the last part of the update flow and reusage of the widgets by the MacOS installer and the information displayed to the users:

* [x] Show by default the download/installation progress dialog (currently it is only shown if the user clicks the status bar) and add a note in it saying that the dialog can be closed without affecting the download/installation and be shown again by clicking the status bar (to be done at #18619)

* [x] Reuse and validate previously downloaded executables: Check if there is an already downloaded executable and check if it corresponds with the latest release to use it and skip the download. Handle the removal of outdated executables too (to be done at #18619)

* [x] Add an extra dialog to confirm installation: Add a dialog asking users if the want to run/install inmediatly the new executable (triggering a way to start again Spyder after the installation is done), to run the executable after Spyder closes or to not run at all the installation after the executable download finishes (to be done after #18619)

 

Resolving patch:
diff --git a/spyder/plugins/application/widgets/status.py b/spyder/plugins/application/widgets/status.py
--- a/spyder/plugins/application/widgets/status.py
+++ b/spyder/plugins/application/widgets/status.py
@@ -13,8 +13,8 @@
 import os
 
 # Third party imports
-from qtpy.QtCore import QPoint, Signal, Slot
-from qtpy.QtWidgets import QMenu
+from qtpy.QtCore import QPoint, Qt, Signal, Slot
+from qtpy.QtWidgets import QMenu, QLabel
 
 # Local imports
 from spyder.api.translations import get_translation
@@ -53,6 +53,8 @@ class ApplicationUpdateStatus(StatusBarWidget):
         Path to instal
     """
 
+    CUSTOM_WIDGET_CLASS = QLabel
+
     def __init__(self, parent):
 
         self.tooltip = self.BASE_TOOLTIP
@@ -60,11 +62,21 @@ def __init__(self, parent):
 
         # Installation dialog
         self.installer = UpdateInstallerDialog(self)
+
         # Check for updates action menu
         self.menu = QMenu(self)
 
+        # Set font size and aligment attributes fro custom widget to
+        # match default label values
+        self.custom_widget.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
+        self.custom_widget.setFont(self.text_font)
+
+        # Signals
         self.sig_clicked.connect(self.show_installation_dialog_or_menu)
 
+        # Installer widget signals
+        self.installer.sig_download_progress.connect(
+            self.set_download_progress)
         self.installer.sig_installation_status.connect(
             self.set_value)
         self.installer.sig_install_on_close_requested.connect(
@@ -77,16 +89,24 @@ def set_value(self, value):
                              "background.\n"
                              "Click here to show the installation "
                              "dialog again.")
-            self.spinner.show()
-            self.spinner.start()
+            if value == DOWNLOADING_INSTALLER:
+                self.spinner.hide()
+                self.spinner.stop()
+                self.custom_widget.show()
+            else:
+                self.custom_widget.hide()
+                self.spinner.show()
+                self.spinner.start()
             self.installer.show()
-
         elif value == PENDING:
             self.tooltip = value
+            self.custom_widget.hide()
             self.spinner.hide()
             self.spinner.stop()
         else:
             self.tooltip = self.BASE_TOOLTIP
+            if self.custom_widget:
+                self.custom_widget.hide()
             if self.spinner:
                 self.spinner.hide()
                 self.spinner.stop()
@@ -106,11 +126,15 @@ def get_icon(self):
     def start_installation(self, latest_release):
         self.installer.start_installation(latest_release)
 
+    def set_download_progress(self, current_value, total):
+        percentage_progress = 0
+        if total > 0:
+            percentage_progress = round((current_value/total) * 100)
+        self.custom_widget.setText(f"{percentage_progress}%")
+
     def set_status_pending(self, latest_release):
         self.set_value(PENDING)
         self.installer.save_latest_release(latest_release)
-        self.spinner.hide()
-        self.spinner.stop()
 
     def set_status_checking(self):
         self.set_value(CHECKING)


Test patch: