Skip to content

Commit 0a2db78

Browse files
committed
Show update progress in launcher window
1 parent 7553c91 commit 0a2db78

File tree

4 files changed

+105
-47
lines changed

4 files changed

+105
-47
lines changed

res/layout/window_launcher.ui

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<x>0</x>
88
<y>0</y>
99
<width>697</width>
10-
<height>565</height>
10+
<height>629</height>
1111
</rect>
1212
</property>
1313
<property name="windowTitle">
@@ -70,36 +70,43 @@
7070
<number>100</number>
7171
</property>
7272
<property name="bottomMargin">
73-
<number>0</number>
73+
<number>20</number>
7474
</property>
7575
<item>
76-
<layout class="QHBoxLayout" name="horizontalLayout_10">
77-
<property name="sizeConstraint">
78-
<enum>QLayout::SetDefaultConstraint</enum>
79-
</property>
76+
<layout class="QVBoxLayout" name="verticalLayout_3">
77+
<item>
78+
<widget class="QProgressBar" name="progress_updating">
79+
<property name="maximum">
80+
<number>0</number>
81+
</property>
82+
<property name="value">
83+
<number>0</number>
84+
</property>
85+
</widget>
86+
</item>
8087
<item>
81-
<widget class="QLabel" name="lbl_update">
82-
<property name="font">
83-
<font>
84-
<weight>50</weight>
85-
<italic>false</italic>
86-
<bold>false</bold>
87-
<underline>false</underline>
88-
<strikeout>false</strikeout>
89-
</font>
88+
<widget class="QLabel" name="lbl_updating">
89+
<property name="enabled">
90+
<bool>true</bool>
9091
</property>
9192
<property name="text">
92-
<string>Updates are available.</string>
93+
<string>PyMODA is updating. It's safe to exit while the update is in progress.</string>
9394
</property>
9495
<property name="alignment">
95-
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
96+
<set>Qt::AlignCenter</set>
9697
</property>
9798
</widget>
9899
</item>
99100
<item>
100-
<widget class="QPushButton" name="btn_update">
101+
<widget class="QLabel" name="lbl_update_complete">
102+
<property name="styleSheet">
103+
<string notr="true">color:blue;</string>
104+
</property>
101105
<property name="text">
102-
<string>Update now</string>
106+
<string>Update complete! Restart PyMODA to finish the process.</string>
107+
</property>
108+
<property name="alignment">
109+
<set>Qt::AlignCenter</set>
103110
</property>
104111
</widget>
105112
</item>

src/gui/windows/launcher/LauncherWindow.py

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from PyQt5 import uic
2727
from PyQt5.QtCore import Qt
2828
from PyQt5.QtGui import QPixmap, QKeySequence
29-
from PyQt5.QtWidgets import QMessageBox, QShortcut, QLabel
29+
from PyQt5.QtWidgets import QMessageBox, QShortcut, QLabel, QProgressBar
3030
from pymodalib.utils.matlab_runtime import RuntimeStatus
3131

3232
import utils
@@ -40,7 +40,6 @@
4040
from updater.check import is_version_newer
4141
from utils import args
4242
from utils.os_utils import OS
43-
from utils.qutils import retain_size_when_hidden
4443
from utils.settings import Settings
4544
from utils.shortcuts import create_shortcut
4645

@@ -68,6 +67,7 @@ def __init__(self, parent):
6867
self.update_thread.extracting_signal.connect(self.on_extract_finished)
6968
self.update_thread.copy_finished_signal.connect(self.on_copy_finished)
7069
self.update_thread.error_signal.connect(self.on_update_error)
70+
self.update_thread.download_progress_signal.connect(self.on_download_progress)
7171

7272
super(LauncherWindow, self).__init__(parent)
7373

@@ -84,8 +84,8 @@ def __init__(self, parent):
8484
self.update_shortcut_force.activated.connect(self.force_show_update)
8585

8686
self.updating = False
87-
self.update_status = UpdateStatus.NOT_AVAILABLE
88-
self.update_statusbar()
87+
self.current_update_status = UpdateStatus.NOT_AVAILABLE
88+
self.update_status_ui()
8989

9090
self.pymoda_has_set_cache_var = False
9191
self.reload_settings()
@@ -119,17 +119,15 @@ def setup_ui(self) -> None:
119119
# TODO: check for Matlab runtime, but show less intrusive message.
120120
# self.check_matlab_runtime()
121121

122-
self.lbl_update.hide()
122+
self.lbl_updating.setVisible(False)
123+
self.progress_updating.setVisible(False)
124+
self.lbl_update_complete.setVisible(False)
123125

124-
self.btn_update.hide()
125-
self.btn_update.clicked.connect(self.on_update_clicked)
126126
self.btn_settings.clicked.connect(self.on_settings_clicked)
127127

128128
self.lbl_update_status = QLabel("")
129129
self.statusBar().addPermanentWidget(self.lbl_update_status)
130130

131-
retain_size_when_hidden(self.btn_update)
132-
133131
if args.create_shortcut():
134132
logging.info("Creating desktop shortcut silently.")
135133
self.create_shortcut(silent=True)
@@ -167,19 +165,43 @@ async def check_if_updated(self) -> None:
167165

168166
msgbox.exec()
169167

170-
def update_statusbar(self) -> None:
171-
status = self.update_status
168+
def update_status_ui(self) -> None:
169+
status = self.current_update_status
172170

173171
if status is UpdateStatus.NOT_AVAILABLE:
174172
self.lbl_update_status.setText("No updates available.")
173+
self.progress_updating.setVisible(False)
174+
self.lbl_updating.setVisible(False)
175+
self.lbl_update_complete.setVisible(False)
175176
elif status is UpdateStatus.DOWNLOADING:
176177
self.lbl_update_status.setText("Downloading update...")
178+
self.lbl_updating.setVisible(True)
179+
self.progress_updating.setVisible(True)
177180
elif status is UpdateStatus.FINISHED:
178181
self.lbl_update_status.setText(
179182
"Update installed, will activate on next launch."
180183
)
184+
self.lbl_updating.setVisible(False)
185+
self.progress_updating.setVisible(False)
186+
self.lbl_update_complete.setVisible(True)
181187
elif status is UpdateStatus.ERROR:
182188
self.lbl_update_status.setText("Error while updating; see log for details.")
189+
self.lbl_updating.setVisible(False)
190+
self.progress_updating.setVisible(False)
191+
192+
def on_download_progress(self, value: float) -> None:
193+
"""
194+
Called to update the download progress bar.
195+
"""
196+
progress: QProgressBar = self.progress_updating
197+
198+
progress.setVisible(True)
199+
progress.setRange(0, 100)
200+
progress.setValue(value)
201+
202+
if value > 100:
203+
progress.setRange(0, 0)
204+
progress.setValue(0)
183205

184206
def check_matlab_runtime(self) -> None:
185207
"""
@@ -370,28 +392,28 @@ def start_background_update(self) -> None:
370392
self.updating = True
371393
self.settings.set_update_in_progress(True)
372394

373-
self.update_statusbar()
395+
self.update_status_ui()
374396
except:
375397
warnings.warn("Cannot start update thread more than once.", RuntimeWarning)
376398

377399
def on_download_finished(self) -> None:
378-
self.update_status = UpdateStatus.DOWNLOADING
379-
self.update_statusbar()
400+
self.current_update_status = UpdateStatus.DOWNLOADING
401+
self.update_status_ui()
380402

381403
def on_extract_finished(self) -> None:
382-
self.update_statusbar()
404+
self.update_status_ui()
383405

384406
def on_copy_finished(self) -> None:
385-
self.update_status = UpdateStatus.FINISHED
407+
self.current_update_status = UpdateStatus.FINISHED
386408

387409
self.settings.set_update_in_progress(False)
388410
self.updating = False
389411

390-
self.update_statusbar()
412+
self.update_status_ui()
391413

392414
def on_update_error(self) -> None:
393415
self.updating = False
394416
self.settings.set_update_in_progress(False)
395417

396-
self.update_status = UpdateStatus.ERROR
397-
self.update_statusbar()
418+
self.current_update_status = UpdateStatus.ERROR
419+
self.update_status_ui()

src/updater/UpdateThread.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ def do_update(self) -> None:
5454
if not self.release_tag:
5555
return logging.error("No release tag.")
5656

57-
self.updater = Updater.get_instance(self.release_tag)
57+
self.updater = Updater.get_instance(
58+
self.release_tag, self.download_progress_signal
59+
)
5860

5961
if self.updater.is_version_present():
6062
return logging.warning(

src/updater/Updater.py

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131

3232

3333
class Updater(ABC):
34-
def __init__(self, tag: str):
34+
def __init__(self, tag: str, progress_signal):
35+
self.progress_signal = progress_signal
3536
self.tag = tag
3637

3738
@abstractmethod
@@ -91,7 +92,11 @@ def download_archive(self, release_tag: str) -> None:
9192

9293
url = self._download_url()
9394
with urlopen(url) as response:
94-
chunked_download(filename="pymoda-temp.zip", response=response)
95+
chunked_download(
96+
filename="pymoda-temp.zip",
97+
response=response,
98+
progress_signal=self.progress_signal,
99+
)
95100

96101
def extract_archive(self) -> None:
97102
try:
@@ -108,6 +113,10 @@ def move_files(self) -> None:
108113
launcher_dir = launcher.get_launcher_directory()
109114

110115
os.rename(join("pymoda-temp", "PyMODA"), join("pymoda-temp", self.tag))
116+
117+
if self.tag in os.listdir(launcher_dir):
118+
shutil.rmtree(join(launcher_dir, self.tag))
119+
111120
shutil.move(join("pymoda-temp", self.tag), launcher_dir)
112121

113122

@@ -123,7 +132,11 @@ def download_launcher(self) -> None:
123132

124133
if url:
125134
with urlopen(url) as response:
126-
chunked_download(filename="launcher-temp", response=response)
135+
chunked_download(
136+
filename="launcher-temp",
137+
response=response,
138+
progress_signal=self.progress_signal,
139+
)
127140

128141
try:
129142
os.remove(join(launcher_dir, "launcher"))
@@ -145,7 +158,11 @@ def download_archive(self, release_tag: str) -> None:
145158
url = self._download_url()
146159

147160
with urlopen(url) as response:
148-
chunked_download(filename="pymoda-temp.tar.gz", response=response)
161+
chunked_download(
162+
filename="pymoda-temp.tar.gz",
163+
response=response,
164+
progress_signal=self.progress_signal,
165+
)
149166

150167
def extract_archive(self) -> None:
151168
try:
@@ -162,32 +179,42 @@ def extract_archive(self) -> None:
162179
class LinuxUpdater(NixUpdater):
163180
def move_files(self) -> None:
164181
launcher_dir = launcher.get_launcher_directory()
182+
183+
if self.tag in os.listdir(launcher_dir):
184+
shutil.rmtree(join(launcher_dir, self.tag))
185+
165186
shutil.move(join("pymoda-temp", "PyMODA"), join(launcher_dir, self.tag))
166187

167188

168189
class MacUpdater(NixUpdater):
169190
def move_files(self) -> None:
170191
launcher_dir = launcher.get_launcher_directory()
192+
193+
if self.tag in os.listdir(launcher_dir):
194+
shutil.rmtree(join(launcher_dir, self.tag))
195+
171196
shutil.move("pymoda-temp", join(launcher_dir, self.tag))
172197

173198

174-
def get_instance(tag) -> Updater:
199+
def get_instance(tag, progress_signal) -> Updater:
175200
"""
176201
Creates the Updater for the current OS.
177202
178203
Parameters
179204
----------
180205
tag : str
181206
The release tag of the latest release.
207+
progress_signal : pyqtSignal
208+
Signal which emits the download progress.
182209
183210
Returns
184211
-------
185212
Updater
186213
The Updater for the current OS.
187214
"""
188215
if OS.is_windows():
189-
return WindowsUpdater(tag)
216+
return WindowsUpdater(tag, progress_signal)
190217
elif OS.is_linux():
191-
return LinuxUpdater(tag)
218+
return LinuxUpdater(tag, progress_signal)
192219
else:
193-
return MacUpdater(tag)
220+
return MacUpdater(tag, progress_signal)

0 commit comments

Comments
 (0)