Added progress bar to show download progress

This commit is contained in:
Campbell 2025-05-25 00:58:55 -04:00
parent 4a08bd47cd
commit 811e2ef01f
Signed by: NinjaCheetah
GPG Key ID: B547958AF96ED344
10 changed files with 144 additions and 60 deletions

View File

@ -36,7 +36,7 @@ from modules.download_batch import run_nus_download_batch
from modules.download_wii import run_nus_download_wii
from modules.download_dsi import run_nus_download_dsi
nusget_version = "1.4.0"
nusget_version = "1.4.1"
regions = {"World": ["41"], "USA/NTSC": ["45"], "Europe/PAL": ["50"], "Japan": ["4A"], "Korea": ["4B"], "China": ["43"],
"Australia/NZ": ["55"]}
@ -45,7 +45,7 @@ regions = {"World": ["41"], "USA/NTSC": ["45"], "Europe/PAL": ["50"], "Japan": [
# Signals needed for the worker used for threading the downloads.
class WorkerSignals(QObject):
result = Signal(object)
progress = Signal(str)
progress = Signal(int, int, str)
# Worker class used to thread the downloads.
@ -81,6 +81,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.ui.download_btn.clicked.connect(self.download_btn_pressed)
self.ui.script_btn.clicked.connect(self.script_btn_pressed)
self.ui.custom_out_dir_btn.clicked.connect(self.choose_output_dir)
self.ui.progress_bar.setRange(0, 0)
# About and About Qt Buttons
self.ui.actionAbout.triggered.connect(self.about_nusget)
self.ui.actionAbout_Qt.triggered.connect(lambda: QMessageBox.aboutQt(self))
@ -230,6 +231,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
return
self.ui.patch_ios_checkbox.setEnabled(False)
def download_progress_update(self, done, total, log_text):
if done == 0 and total == 0:
self.ui.progress_bar.setRange(0, 0)
elif done == -1 and total == -1:
pass
else:
self.ui.progress_bar.setRange(0, total)
self.ui.progress_bar.setValue(done)
# Pass the text on to the log text updater, if it was provided.
if log_text:
self.update_log_text(log_text)
def update_log_text(self, new_text):
# This method primarily exists to be the handler for the progress signal emitted by the worker thread.
self.log_text += new_text + "\n"
@ -385,7 +398,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.ui.pack_vwii_mode_checkbox.isChecked(), self.ui.patch_ios_checkbox.isChecked(),
self.ui.archive_file_entry.text())
worker.signals.result.connect(self.check_download_result)
worker.signals.progress.connect(self.update_log_text)
worker.signals.progress.connect(self.download_progress_update)
self.threadpool.start(worker)
def check_download_result(self, result):
@ -552,7 +565,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.ui.use_wiiu_nus_checkbox.isChecked(), self.ui.use_local_checkbox.isChecked(),
self.ui.pack_vwii_mode_checkbox.isChecked(), self.ui.patch_ios_checkbox.isChecked())
worker.signals.result.connect(self.check_batch_result)
worker.signals.progress.connect(self.update_log_text)
worker.signals.progress.connect(self.download_progress_update)
self.threadpool.start(worker)
def choose_output_dir(self):
@ -657,16 +670,10 @@ if __name__ == "__main__":
# NUSGet look nice and pretty.
app.setStyle("fusion")
theme_sheet = "style_dark.qss"
try:
# Check for an environment variable overriding the theme. This is mostly for theme testing but would also allow
# you to force a theme.
if os.environ["THEME"].lower() == "light":
theme_sheet = "style_light.qss"
except KeyError:
if is_dark_theme():
theme_sheet = "style_dark.qss"
else:
theme_sheet = "style_light.qss"
if is_dark_theme():
theme_sheet = "style_dark.qss"
else:
theme_sheet = "style_light.qss"
stylesheet = open(os.path.join(os.path.dirname(__file__), "resources", theme_sheet)).read()
image_path_prefix = pathlib.Path(os.path.join(os.path.dirname(__file__), "resources")).resolve().as_posix()
stylesheet = stylesheet.replace("{IMAGE_PREFIX}", image_path_prefix)

View File

@ -53,5 +53,5 @@ def run_nus_download_batch(out_folder: pathlib.Path, titles: List[BatchTitleData
# failed title.
result = 1
failed_titles.append(title.tid)
progress_callback.emit(f"Batch download finished.")
progress_callback.emit(0, 1, f"Batch download finished.")
return BatchResults(result, warning_titles, failed_titles)

View File

@ -29,10 +29,10 @@ def run_nus_download_dsi(out_folder: pathlib.Path, tid: str, version: str, pack_
title_dir.mkdir(exist_ok=True)
# Announce the title being downloaded, and the version if applicable.
if title_version is not None:
progress_callback.emit(f"Downloading title {tid} v{title_version}, please wait...")
progress_callback.emit(0, 0, f"Downloading title {tid} v{title_version}, please wait...")
else:
progress_callback.emit(f"Downloading title {tid} vLatest, please wait...")
progress_callback.emit(" - Downloading and parsing TMD...")
progress_callback.emit(0, 0, f"Downloading title {tid} vLatest, please wait...")
progress_callback.emit(-1, -1, " - Downloading and parsing TMD...")
# Download a specific TMD version if a version was specified, otherwise just download the latest TMD.
try:
if title_version is not None:
@ -50,17 +50,17 @@ def run_nus_download_dsi(out_folder: pathlib.Path, tid: str, version: str, pack_
version_dir.joinpath(f"tmd.{title_version}").write_bytes(title.tmd.dump())
# Use a local ticket, if one exists and "use local files" is enabled.
if use_local_chkbox and version_dir.joinpath("tik").exists():
progress_callback.emit(" - Parsing local copy of Ticket...")
progress_callback.emit(-1, -1, " - Parsing local copy of Ticket...")
title.load_ticket(version_dir.joinpath("tik").read_bytes())
else:
progress_callback.emit(" - Downloading and parsing Ticket...")
progress_callback.emit(-1, -1, " - Downloading and parsing Ticket...")
try:
title.load_ticket(libTWLPy.download_ticket(tid))
version_dir.joinpath("tik").write_bytes(title.ticket.dump())
except ValueError:
# If libTWLPy returns an error, then no ticket is available. Log this, and disable options requiring a
# ticket so that they aren't attempted later.
progress_callback.emit(" - No Ticket is available!")
progress_callback.emit(-1, -1, " - No Ticket is available!")
pack_tad_enabled = False
decrypt_contents_enabled = False
# Load the content record from the TMD, and download the content it lists. DSi titles only have one content.
@ -68,13 +68,13 @@ def run_nus_download_dsi(out_folder: pathlib.Path, tid: str, version: str, pack_
content_file_name = f"{title.tmd.content_record.content_id:08X}"
# Check for a local copy of the current content if "use local files" is enabled, and use it.
if use_local_chkbox and version_dir.joinpath(content_file_name).exists():
progress_callback.emit(" - Using local copy of content")
progress_callback.emit(-1, -1, " - Using local copy of content")
content = version_dir.joinpath(content_file_name).read_bytes()
else:
progress_callback.emit(f" - Downloading content (Content ID: {title.tmd.content_record.content_id}, Size: "
progress_callback.emit(-1, -1, f" - Downloading content (Content ID: {title.tmd.content_record.content_id}, Size: "
f"{title.tmd.content_record.content_size} bytes)...")
content = libTWLPy.download_content(tid, title.tmd.content_record.content_id)
progress_callback.emit(" - Done!")
progress_callback.emit(-1, -1, " - Done!")
# If keep encrypted contents is on, write out the content after its downloaded.
if keep_enc_chkbox is True:
version_dir.joinpath(content_file_name).write_bytes(content)
@ -82,7 +82,7 @@ def run_nus_download_dsi(out_folder: pathlib.Path, tid: str, version: str, pack_
# If decrypt local contents is still true, decrypt the content and write out the decrypted file.
if decrypt_contents_enabled is True:
try:
progress_callback.emit(f" - Decrypting content (Content ID: {title.tmd.content_record.content_id})...")
progress_callback.emit(-1, -1, f" - Decrypting content (Content ID: {title.tmd.content_record.content_id})...")
dec_content = title.get_content()
content_file_name = f"{title.tmd.content_record.content_id:08X}.app"
version_dir.joinpath(content_file_name).write_bytes(dec_content)
@ -93,10 +93,10 @@ def run_nus_download_dsi(out_folder: pathlib.Path, tid: str, version: str, pack_
# If pack TAD is still true, pack the TMD, ticket, and content into a TAD.
if pack_tad_enabled is True:
# Get the TAD certificate chain, courtesy of libTWLPy.
progress_callback.emit(" - Building certificate...")
progress_callback.emit(-1, -1, " - Building certificate...")
title.tad.set_cert_data(libTWLPy.download_cert())
# Use a typed TAD name if there is one, and auto generate one based on the TID and version if there isn't.
progress_callback.emit("Packing TAD...")
progress_callback.emit(-1, -1, "Packing TAD...")
if tad_file_name != "" and tad_file_name is not None:
# Batch downloads may insert -vLatest, so if it did we can fill in the real number now.
tad_file_name = tad_file_name.replace("-vLatest", f"-v{title_version}")
@ -110,7 +110,7 @@ def run_nus_download_dsi(out_folder: pathlib.Path, tid: str, version: str, pack_
tad_file_name = tad_file_name.translate({ord(c): None for c in '/\\:*"?<>|'})
# Have libTWLPy dump the TAD, and write that data out.
version_dir.joinpath(tad_file_name).write_bytes(title.dump_tad())
progress_callback.emit("Download complete!")
progress_callback.emit(0, 1, "Download complete!")
# This is where the variables come in. If the state of these variables doesn't match the user's choice by this
# point, it means that they enabled decryption or TAD packing for a title that doesn't have a ticket. Return
# code 1 so that a warning popup is shown informing them of this.

View File

@ -9,6 +9,8 @@ import libWiiPy
def run_nus_download_wii(out_folder: pathlib.Path, tid: str, version: str, pack_wad_chkbox: bool, keep_enc_chkbox: bool,
decrypt_contents_chkbox: bool, wiiu_nus_chkbox: bool, use_local_chkbox: bool,
repack_vwii_chkbox: bool, patch_ios: bool, wad_file_name: str, progress_callback=None):
def progress_update(done, total):
progress_callback.emit(done, total, None)
# Actual NUS download function that runs in a separate thread.
# Immediately knock out any invalidly formatted Title IDs.
if len(tid) != 16:
@ -31,16 +33,16 @@ def run_nus_download_wii(out_folder: pathlib.Path, tid: str, version: str, pack_
title_dir.mkdir(exist_ok=True)
# Announce the title being downloaded, and the version if applicable.
if title_version is not None:
progress_callback.emit(f"Downloading title {tid} v{title_version}, please wait...")
progress_callback.emit(0, 0, f"Downloading title {tid} v{title_version}, please wait...")
else:
progress_callback.emit(f"Downloading title {tid} vLatest, please wait...")
progress_callback.emit(" - Downloading and parsing TMD...")
progress_callback.emit(-1, -1, f"Downloading title {tid} vLatest, please wait...")
progress_callback.emit(-1, -1, " - Downloading and parsing TMD...")
# Download a specific TMD version if a version was specified, otherwise just download the latest TMD.
try:
if title_version is not None:
title.load_tmd(libWiiPy.title.download_tmd(tid, title_version, wiiu_endpoint=wiiu_nus_enabled))
title.load_tmd(libWiiPy.title.download_tmd(tid, title_version, wiiu_endpoint=wiiu_nus_enabled, progress=progress_update))
else:
title.load_tmd(libWiiPy.title.download_tmd(tid, wiiu_endpoint=wiiu_nus_enabled))
title.load_tmd(libWiiPy.title.download_tmd(tid, wiiu_endpoint=wiiu_nus_enabled, progress=progress_update))
title_version = title.tmd.title_version
# If libWiiPy returns an error, that means that either the TID or version doesn't exist, so return code -2.
except ValueError:
@ -52,17 +54,17 @@ def run_nus_download_wii(out_folder: pathlib.Path, tid: str, version: str, pack_
version_dir.joinpath(f"tmd.{title_version}").write_bytes(title.tmd.dump())
# Use a local ticket, if one exists and "use local files" is enabled.
if use_local_chkbox and version_dir.joinpath("tik").exists():
progress_callback.emit(" - Parsing local copy of Ticket...")
progress_callback.emit(-1, -1, " - Parsing local copy of Ticket...")
title.load_ticket(version_dir.joinpath("tik").read_bytes())
else:
progress_callback.emit(" - Downloading and parsing Ticket...")
progress_callback.emit(-1, -1, " - Downloading and parsing Ticket...")
try:
title.load_ticket(libWiiPy.title.download_ticket(tid, wiiu_endpoint=wiiu_nus_enabled))
title.load_ticket(libWiiPy.title.download_ticket(tid, wiiu_endpoint=wiiu_nus_enabled, progress=progress_update))
version_dir.joinpath("tik").write_bytes(title.ticket.dump())
except ValueError:
# If libWiiPy returns an error, then no ticket is available. Log this, and disable options requiring a
# ticket so that they aren't attempted later.
progress_callback.emit(" - No Ticket is available!")
progress_callback.emit(0, 0, " - No Ticket is available!")
pack_wad_enabled = False
decrypt_contents_enabled = False
# Load the content records from the TMD, and begin iterating over the records.
@ -73,15 +75,15 @@ def run_nus_download_wii(out_folder: pathlib.Path, tid: str, version: str, pack_
content_file_name = f"{title.tmd.content_records[content].content_id:08X}"
# Check for a local copy of the current content if "use local files" is enabled, and use it.
if use_local_chkbox is True and version_dir.joinpath(content_file_name).exists():
progress_callback.emit(f" - Using local copy of content {content + 1} of {len(title.tmd.content_records)}")
progress_callback.emit(-1, -1, f" - Using local copy of content {content + 1} of {len(title.tmd.content_records)}")
content_list.append(version_dir.joinpath(content_file_name).read_bytes())
else:
progress_callback.emit(f" - Downloading content {content + 1} of {len(title.tmd.content_records)} "
progress_callback.emit(0, 0, f" - Downloading content {content + 1} of {len(title.tmd.content_records)} "
f"(Content ID: {title.tmd.content_records[content].content_id}, Size: "
f"{title.tmd.content_records[content].content_size} bytes)...")
content_list.append(libWiiPy.title.download_content(tid, title.tmd.content_records[content].content_id,
wiiu_endpoint=wiiu_nus_enabled))
progress_callback.emit(" - Done!")
wiiu_endpoint=wiiu_nus_enabled, progress=progress_update))
progress_callback.emit(-1, -1, " - Done!")
# If keep encrypted contents is on, write out each content after its downloaded.
if keep_enc_chkbox is True:
version_dir.joinpath(content_file_name).write_bytes(content_list[content])
@ -90,7 +92,7 @@ def run_nus_download_wii(out_folder: pathlib.Path, tid: str, version: str, pack_
if decrypt_contents_enabled is True:
try:
for content in range(len(title.tmd.content_records)):
progress_callback.emit(f" - Decrypting content {content + 1} of {len(title.tmd.content_records)} "
progress_callback.emit(-1, -1, f" - Decrypting content {content + 1} of {len(title.tmd.content_records)} "
f"(Content ID: {title.tmd.content_records[content].content_id})...")
dec_content = title.get_content_by_index(content)
content_file_name = f"{title.tmd.content_records[content].content_id:08X}.app"
@ -105,15 +107,15 @@ def run_nus_download_wii(out_folder: pathlib.Path, tid: str, version: str, pack_
# re-encrypted with the common key instead of the vWii key, so that the title can be installed from within
# vWii mode. (vWii mode does not have access to the vWii key, only Wii U mode has that.)
if repack_vwii_chkbox is True and (tid[3] == "7" or tid[7] == "7"):
progress_callback.emit(" - Re-encrypting Title Key with the common key...")
progress_callback.emit(-1, -1, " - Re-encrypting Title Key with the common key...")
title_key_common = libWiiPy.title.encrypt_title_key(title.ticket.get_title_key(), 0, title.tmd.title_id)
title.ticket.common_key_index = 0
title.ticket.title_key_enc = title_key_common
# Get the WAD certificate chain, courtesy of libWiiPy.
progress_callback.emit(" - Building certificate...")
progress_callback.emit(-1, -1, " - Building certificate...")
title.load_cert_chain(libWiiPy.title.download_cert_chain(wiiu_endpoint=wiiu_nus_enabled))
# Use a typed WAD name if there is one, and auto generate one based on the TID and version if there isn't.
progress_callback.emit(" - Packing WAD...")
progress_callback.emit(-1, -1, " - Packing WAD...")
if wad_file_name != "" and wad_file_name is not None:
# Batch downloads may insert -vLatest, so if it did we can fill in the real number now.
wad_file_name = wad_file_name.replace("-vLatest", f"-v{title_version}")
@ -123,14 +125,14 @@ def run_nus_download_wii(out_folder: pathlib.Path, tid: str, version: str, pack_
wad_file_name = f"{tid}-v{title_version}.wad"
# If enabled (after we make sure it's an IOS), apply all main IOS patches.
if patch_ios and (tid[:8] == "00000001" and int(tid[-2:], 16) > 2):
progress_callback.emit(" - Patching IOS...")
progress_callback.emit(-1, -1, " - Patching IOS...")
ios_patcher = libWiiPy.title.IOSPatcher()
ios_patcher.load(title)
patch_count = ios_patcher.patch_all()
if patch_count > 0:
progress_callback.emit(f" - Applied {patch_count} patches!")
progress_callback.emit(-1, -1, f" - Applied {patch_count} patches!")
else:
progress_callback.emit(" - No patches could be applied! Is this a stub IOS?")
progress_callback.emit(-1, -1, " - No patches could be applied! Is this a stub IOS?")
title = ios_patcher.dump()
# Append "-PATCHED" to the end of the WAD file name to make it clear that it was modified.
wad_file_name = wad_file_name[:-4] + "-PATCHED" + wad_file_name[-4:]
@ -140,7 +142,7 @@ def run_nus_download_wii(out_folder: pathlib.Path, tid: str, version: str, pack_
wad_file_name = wad_file_name.translate({ord(c): None for c in '/\\:*"?<>|'})
# Have libWiiPy dump the WAD, and write that data out.
version_dir.joinpath(wad_file_name).write_bytes(title.dump_wad())
progress_callback.emit("Download complete!")
progress_callback.emit(0, 1, "Download complete!")
# This is where the variables come in. If the state of these variables doesn't match the user's choice by this
# point, it means that they enabled decryption or WAD packing for a title that doesn't have a ticket. Return
# code 1 so that a warning popup is shown informing them of this.

View File

@ -1,6 +1,7 @@
# "modules/theme.py", licensed under the MIT license
# Copyright 2024-2025 NinjaCheetah & Contributors
import os
import platform
import subprocess
@ -43,6 +44,17 @@ def is_dark_theme_linux():
return False
def is_dark_theme():
# First, check for an environment variable overriding the theme, and use that if it exists.
try:
if os.environ["THEME"].lower() == "light":
return False
elif os.environ["THEME"].lower() == "dark":
return True
else:
print(f"Unknown theme specified: \"{os.environ['THEME']}\"")
except KeyError:
pass
# If the theme wasn't overridden, then check the current system theme.
system = platform.system()
if system == "Windows":
return is_dark_theme_windows()

View File

@ -18,9 +18,9 @@ from PySide6.QtGui import (QAction, QBrush, QColor, QConicalGradient,
QTransform)
from PySide6.QtWidgets import (QApplication, QComboBox, QHBoxLayout, QHeaderView,
QLabel, QLayout, QLineEdit, QMainWindow,
QMenu, QMenuBar, QPushButton, QSizePolicy,
QSpacerItem, QTabWidget, QTextBrowser, QTreeView,
QVBoxLayout, QWidget)
QMenu, QMenuBar, QProgressBar, QPushButton,
QSizePolicy, QSpacerItem, QTabWidget, QTextBrowser,
QTreeView, QVBoxLayout, QWidget)
from qt.py.ui_WrapCheckboxWidget import WrapCheckboxWidget
@ -308,17 +308,25 @@ class Ui_MainWindow(object):
self.log_text_browser = QTextBrowser(self.centralwidget)
self.log_text_browser.setObjectName(u"log_text_browser")
self.log_text_browser.setMinimumSize(QSize(0, 247))
self.log_text_browser.setMinimumSize(QSize(0, 222))
self.vertical_layout_controls.addWidget(self.log_text_browser)
self.progress_bar = QProgressBar(self.centralwidget)
self.progress_bar.setObjectName(u"progress_bar")
self.progress_bar.setMinimumSize(QSize(0, 25))
self.progress_bar.setMaximumSize(QSize(16777215, 30))
self.progress_bar.setValue(0)
self.vertical_layout_controls.addWidget(self.progress_bar)
self.horizontalLayout_3.addLayout(self.vertical_layout_controls)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(MainWindow)
self.menubar.setObjectName(u"menubar")
self.menubar.setGeometry(QRect(0, 0, 1010, 21))
self.menubar.setGeometry(QRect(0, 0, 1010, 30))
self.menuHelp = QMenu(self.menubar)
self.menuHelp.setObjectName(u"menuHelp")
MainWindow.setMenuBar(self.menubar)
@ -367,7 +375,7 @@ class Ui_MainWindow(object):
"hr { height: 1px; border-width: 0; }\n"
"li.unchecked::marker { content: \"\\2610\"; }\n"
"li.checked::marker { content: \"\\2612\"; }\n"
"</style></head><body style=\" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;\">\n"
"</style></head><body style=\" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;\">\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;\"><br /></p></body></html>", None))
self.menuHelp.setTitle(QCoreApplication.translate("MainWindow", u"Help", None))
# retranslateUi

View File

@ -422,7 +422,7 @@
<property name="minimumSize">
<size>
<width>0</width>
<height>247</height>
<height>222</height>
</size>
</property>
<property name="markdown">
@ -435,11 +435,30 @@ p, li { white-space: pre-wrap; }
hr { height: 1px; border-width: 0; }
li.unchecked::marker { content: &quot;\2610&quot;; }
li.checked::marker { content: &quot;\2612&quot;; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progress_bar">
<property name="minimumSize">
<size>
<width>0</width>
<height>25</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>30</height>
</size>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
@ -450,7 +469,7 @@ li.checked::marker { content: &quot;\2612&quot;; }
<x>0</x>
<y>0</y>
<width>1010</width>
<height>21</height>
<height>30</height>
</rect>
</property>
<widget class="QMenu" name="menuHelp">

View File

@ -1,7 +1,7 @@
pyside6
nuitka~=2.6.0
libWiiPy
git+https://github.com/NinjaCheetah/libWiiPy
libTWLPy
zstandard
requests
imageio
imageio

View File

@ -369,6 +369,24 @@ QMessageBox QLabel {
color: white;
}
QProgressBar {
border: 1px solid rgba(70, 70, 70, 1);
border-radius: 8px;
background-color: #1a1a1a;
text-align: center;
color: white;
padding-left: 1px;
}
QProgressBar::chunk {
background-color: qlineargradient(
x1: 0, y1: 0, x2: 1, y2: 0,
stop: 0 #1a73e8, stop: 1 #5596f4
);
border-radius: 5px;
margin: 0.5px;
}
WrapCheckboxWidget {
show-decoration-selected: 1;
outline: 0;

View File

@ -377,6 +377,24 @@ QMessageBox QLabel {
color: #000000;
}
QProgressBar {
border: 1px solid rgb(163, 163, 163);
border-radius: 8px;
background-color: #ececec;
text-align: center;
padding: 1px;
color: black;
}
QProgressBar::chunk {
background-color: qlineargradient(
x1: 0, y1: 0, x2: 1, y2: 0,
stop: 0 #1a73e8, stop: 1 #5596f4
);
border-radius: 5px;
margin: 0.5px;
}
WrapCheckboxWidget {
show-decoration-selected: 1;
outline: 0;