diff --git a/gotify_tray/database/default_settings.py b/gotify_tray/database/default_settings.py
index fa980e2..0b951cc 100644
--- a/gotify_tray/database/default_settings.py
+++ b/gotify_tray/database/default_settings.py
@@ -5,7 +5,7 @@ from ..__version__ import __title__
DEFAULT_SETTINGS = {
- "theme": "default",
+ "theme": "automatic",
"message/check_missed/notify": True,
"logging/level": "Disabled",
"export/path": os.path.join(
diff --git a/gotify_tray/gui/MainApplication.py b/gotify_tray/gui/MainApplication.py
index 63adcbf..c36115d 100644
--- a/gotify_tray/gui/MainApplication.py
+++ b/gotify_tray/gui/MainApplication.py
@@ -76,7 +76,7 @@ class MainApplication(QtWidgets.QApplication):
self.messages_model = MessagesModel()
self.application_model = ApplicationModel()
- self.main_window = MainWindow(self.application_model, self.messages_model)
+ self.main_window = MainWindow(self, self.application_model, self.messages_model)
self.main_window.show() # The initial .show() is necessary to get the correct sizes when adding MessageWigets
QtCore.QTimer.singleShot(0, self.main_window.hide)
@@ -381,7 +381,7 @@ class MainApplication(QtWidgets.QApplication):
message_widget.set_icons()
def settings_callback(self):
- settings_dialog = SettingsDialog()
+ settings_dialog = SettingsDialog(self)
settings_dialog.quit_requested.connect(self.quit)
settings_dialog.theme_change_requested.connect(
self.theme_change_requested_callback
@@ -435,6 +435,8 @@ class MainApplication(QtWidgets.QApplication):
self.main_window.image_popup.connect(self.image_popup_callback)
self.main_window.hidden.connect(self.main_window_hidden_callback)
self.main_window.activated.connect(self.tray.revert_icon)
+
+ self.styleHints().colorSchemeChanged.connect(lambda _: self.theme_change_requested_callback(settings.value("theme", type=str)))
self.watchdog.closed.connect(lambda: self.listener_closed_callback(None, None))
diff --git a/gotify_tray/gui/themes/__init__.py b/gotify_tray/gui/themes/__init__.py
index 822b575..c4565db 100644
--- a/gotify_tray/gui/themes/__init__.py
+++ b/gotify_tray/gui/themes/__init__.py
@@ -1,5 +1,5 @@
import logging
-from PyQt6 import QtGui, QtWidgets
+from PyQt6 import QtCore, QtGui, QtWidgets
from gotify_tray.utils import get_abs_path
from . import default, dark_purple, light_purple
from gotify_tray.database import Settings
@@ -9,28 +9,50 @@ settings = Settings("gotify-tray")
logger = logging.getLogger("gotify-tray")
-styles = {
+themes = {
"default": default,
+ "automatic": None,
"dark purple": dark_purple,
"light purple": light_purple,
}
-def set_theme(app: QtWidgets.QApplication, style: str = "default"):
- if style not in styles.keys():
- logger.error(f"set_style: style {style} is unsupported.")
- return
+def get_themes():
+ return themes.keys()
+
+
+def is_dark_mode(app: QtWidgets.QApplication) -> bool:
+ return app.styleHints().colorScheme() == QtCore.Qt.ColorScheme.Dark
+
+
+def is_valid_theme(theme: str) -> bool:
+ return theme in get_themes()
+
+
+def set_theme(app: QtWidgets.QApplication, theme: str = "automatic"):
+ if not is_valid_theme(theme):
+ logger.warning(f"set_theme: theme {theme} is unsupported.")
+ theme = "automatic"
+
+ if theme == "automatic":
+ theme = "dark purple" if is_dark_mode(app) else "light purple"
stylesheet = ""
- with open(get_abs_path(f"gotify_tray/gui/themes/{style.replace(' ', '_')}/style.qss"), "r") as f:
+ with open(get_abs_path(f"gotify_tray/gui/themes/{theme.replace(' ', '_')}/style.qss"), "r") as f:
stylesheet += f.read()
- app.setPalette(styles[style].get_palette())
+ app.setPalette(themes[theme].get_palette())
app.setStyleSheet(stylesheet)
-def get_themes():
- return styles.keys()
-
-def get_theme_file(file: str, theme: str = None) -> str:
+
+def get_theme_file(app: QtWidgets.QApplication, file: str, theme: str = None) -> str:
theme = settings.value("theme", type=str) if not theme else theme
+
+ if not is_valid_theme(theme):
+ logger.warning(f"set_theme: theme {theme} is unsupported.")
+ theme = "automatic"
+
+ if theme in ("automatic", "default"):
+ theme = "dark purple" if is_dark_mode(app) else "light purple"
+
return get_abs_path(f"gotify_tray/gui/themes/{theme.replace(' ', '_')}/{file}")
diff --git a/gotify_tray/gui/themes/dark_purple/style.qss b/gotify_tray/gui/themes/dark_purple/style.qss
index c2d5162..d33b80c 100644
--- a/gotify_tray/gui/themes/dark_purple/style.qss
+++ b/gotify_tray/gui/themes/dark_purple/style.qss
@@ -6,6 +6,22 @@ QPushButton:default:hover, QPushButton:checked:hover {
background: #441b85;
}
+QPushButton[state="success"] {
+ background-color: #960b7a0b;
+ color: white;
+}
+
+QPushButton[state="failed"] {
+ background-color: #8ebb2929;
+ color: white;
+}
+
+QLineEdit[state="success"] {}
+
+QLineEdit[state="failed"] {
+ border: 1px solid red;
+}
+
QToolTip {
color: #BFBFBF;
background-color: #5522a8;
diff --git a/gotify_tray/gui/themes/default/refresh.svg b/gotify_tray/gui/themes/default/refresh.svg
deleted file mode 100644
index 3257974..0000000
--- a/gotify_tray/gui/themes/default/refresh.svg
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
diff --git a/gotify_tray/gui/themes/default/status_active.svg b/gotify_tray/gui/themes/default/status_active.svg
deleted file mode 100644
index 7af0e8e..0000000
--- a/gotify_tray/gui/themes/default/status_active.svg
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
diff --git a/gotify_tray/gui/themes/default/status_connecting.svg b/gotify_tray/gui/themes/default/status_connecting.svg
deleted file mode 100644
index 8b1a364..0000000
--- a/gotify_tray/gui/themes/default/status_connecting.svg
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
diff --git a/gotify_tray/gui/themes/default/status_error.svg b/gotify_tray/gui/themes/default/status_error.svg
deleted file mode 100644
index 2f89ca1..0000000
--- a/gotify_tray/gui/themes/default/status_error.svg
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
diff --git a/gotify_tray/gui/themes/default/status_inactive.svg b/gotify_tray/gui/themes/default/status_inactive.svg
deleted file mode 100644
index 2d0eba9..0000000
--- a/gotify_tray/gui/themes/default/status_inactive.svg
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
diff --git a/gotify_tray/gui/themes/default/trashcan.svg b/gotify_tray/gui/themes/default/trashcan.svg
deleted file mode 100644
index 94b811f..0000000
--- a/gotify_tray/gui/themes/default/trashcan.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/gotify_tray/gui/themes/light_purple/style.qss b/gotify_tray/gui/themes/light_purple/style.qss
index 196a85c..5e811b2 100644
--- a/gotify_tray/gui/themes/light_purple/style.qss
+++ b/gotify_tray/gui/themes/light_purple/style.qss
@@ -6,6 +6,22 @@ QPushButton:default:hover, QPushButton:checked:hover {
background: #5c24b6;
}
+QPushButton[state="success"] {
+ background-color: #6400FF00;
+ color: black;
+}
+
+QPushButton[state="failed"] {
+ background-color: #64FF0000;
+ color: black;
+}
+
+QLineEdit[state="success"] {}
+
+QLineEdit[state="failed"] {
+ border: 1px solid red;
+}
+
QToolTip {
color: #BFBFBF;
background-color: #5522a8;
diff --git a/gotify_tray/gui/widgets/MainWindow.py b/gotify_tray/gui/widgets/MainWindow.py
index a4c095b..e502949 100644
--- a/gotify_tray/gui/widgets/MainWindow.py
+++ b/gotify_tray/gui/widgets/MainWindow.py
@@ -26,7 +26,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
activated = QtCore.pyqtSignal()
def __init__(
- self, application_model: ApplicationModel, messages_model: MessagesModel
+ self, app: QtWidgets.QApplication,
+ application_model: ApplicationModel, messages_model: MessagesModel
):
super(MainWindow, self).__init__()
self.setupUi(self)
@@ -35,6 +36,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.setWindowTitle(__title__)
+ self.app = app
+
self.application_model = application_model
self.messages_model = messages_model
@@ -47,7 +50,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
# Do not collapse the message list
self.splitter.setCollapsible(1, False)
- self.status_widget = StatusWidget()
+ self.status_widget = StatusWidget(app)
self.horizontalLayout.insertWidget(0, self.status_widget)
self.set_icons()
@@ -70,8 +73,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def set_icons(self):
# Set button icons
- self.pb_refresh.setIcon(QtGui.QIcon(get_theme_file("refresh.svg")))
- self.pb_delete_all.setIcon(QtGui.QIcon(get_theme_file("trashcan.svg")))
+ self.pb_refresh.setIcon(QtGui.QIcon(get_theme_file(self.app, "refresh.svg")))
+ self.pb_delete_all.setIcon(QtGui.QIcon(get_theme_file(self.app, "trashcan.svg")))
# Resize the labels and icons
size = settings.value("MainWindow/label/size", type=int)
@@ -105,7 +108,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self, message_item: MessagesModelItem, image_path: str = ""
):
message_widget = MessageWidget(
- self.listView_messages, message_item, image_path=image_path
+ self.app, self.listView_messages, message_item, image_path=image_path
)
self.listView_messages.setIndexWidget(
self.messages_model.indexFromItem(message_item), message_widget
diff --git a/gotify_tray/gui/widgets/MessageWidget.py b/gotify_tray/gui/widgets/MessageWidget.py
index 4147e6f..0f87eae 100644
--- a/gotify_tray/gui/widgets/MessageWidget.py
+++ b/gotify_tray/gui/widgets/MessageWidget.py
@@ -20,11 +20,13 @@ class MessageWidget(QtWidgets.QWidget, Ui_Form):
def __init__(
self,
+ app: QtWidgets.QApplication,
parent: QtWidgets.QWidget,
message_item: MessagesModelItem,
image_path: str = "",
):
super(MessageWidget, self).__init__()
+ self.app = app
self.parent = parent
self.setupUi(self)
self.setAutoFillBackground(True)
@@ -104,7 +106,7 @@ class MessageWidget(QtWidgets.QWidget, Ui_Form):
self.label_message.setFont(font_content)
def set_icons(self):
- self.pb_delete.setIcon(QtGui.QIcon(get_theme_file("trashcan.svg")))
+ self.pb_delete.setIcon(QtGui.QIcon(get_theme_file(self.app, "trashcan.svg")))
self.pb_delete.setIconSize(QtCore.QSize(24, 24))
def set_message_image(self, filename: str):
diff --git a/gotify_tray/gui/widgets/ServerInfoDialog.py b/gotify_tray/gui/widgets/ServerInfoDialog.py
index b87e039..aac812a 100644
--- a/gotify_tray/gui/widgets/ServerInfoDialog.py
+++ b/gotify_tray/gui/widgets/ServerInfoDialog.py
@@ -47,10 +47,18 @@ class ServerInfoDialog(QtWidgets.QDialog, Ui_Dialog):
self.task.incorrect_url.connect(self.incorrect_url_callback)
self.task.start()
+ def update_widget_state(self, widget: QtWidgets.QWidget, state: str):
+ widget.setProperty("state", state)
+ widget.style().unpolish(widget)
+ widget.style().polish(widget)
+ widget.update()
+
def server_info_success(self, version: GotifyVersionModel):
self.pb_test.setEnabled(True)
self.label_server_info.setText(f"Version: {version.version}")
- self.pb_test.setStyleSheet("background-color: rgba(0, 255, 0, 100);")
+ self.update_widget_state(self.pb_test, "success")
+ self.update_widget_state(self.line_token, "success")
+ self.update_widget_state(self.line_url, "success")
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Ok).setEnabled(
True
)
@@ -59,15 +67,17 @@ class ServerInfoDialog(QtWidgets.QDialog, Ui_Dialog):
def incorrect_token_callback(self, version: GotifyVersionModel):
self.pb_test.setEnabled(True)
self.label_server_info.setText(f"Version: {version.version}")
- self.pb_test.setStyleSheet("background-color: rgba(255, 0, 0, 100);")
- self.line_token.setStyleSheet("border: 1px solid red;")
+ self.update_widget_state(self.pb_test, "failed")
+ self.update_widget_state(self.line_token, "failed")
+ self.update_widget_state(self.line_url, "success")
self.line_token.setFocus()
def incorrect_url_callback(self):
self.pb_test.setEnabled(True)
self.label_server_info.clear()
- self.pb_test.setStyleSheet("background-color: rgba(255, 0, 0, 100);")
- self.line_url.setStyleSheet("border: 1px solid red;")
+ self.update_widget_state(self.pb_test, "failed")
+ self.update_widget_state(self.line_token, "success")
+ self.update_widget_state(self.line_url, "failed")
self.line_url.setFocus()
def import_success_callback(self):
diff --git a/gotify_tray/gui/widgets/SettingsDialog.py b/gotify_tray/gui/widgets/SettingsDialog.py
index 7dded76..10c47db 100644
--- a/gotify_tray/gui/widgets/SettingsDialog.py
+++ b/gotify_tray/gui/widgets/SettingsDialog.py
@@ -27,10 +27,12 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog):
quit_requested = QtCore.pyqtSignal()
theme_change_requested = QtCore.pyqtSignal(str)
- def __init__(self):
+ def __init__(self, app: QtWidgets.QApplication):
super(SettingsDialog, self).__init__()
self.setupUi(self)
self.setWindowTitle("Settings")
+
+ self.app = app
self.settings_changed = False
self.changes_applied = False
@@ -104,6 +106,7 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog):
def add_message_widget(self):
self.message_widget = MessageWidget(
+ self.app,
self,
MessagesModelItem(
GotifyMessageModel(
diff --git a/gotify_tray/gui/widgets/StatusWidget.py b/gotify_tray/gui/widgets/StatusWidget.py
index b16938a..2d57bd0 100644
--- a/gotify_tray/gui/widgets/StatusWidget.py
+++ b/gotify_tray/gui/widgets/StatusWidget.py
@@ -8,8 +8,9 @@ settings = Settings("gotify-tray")
class StatusWidget(QtWidgets.QLabel):
- def __init__(self):
+ def __init__(self, app: QtWidgets.QApplication):
super(StatusWidget, self).__init__()
+ self.app = app
self.setFixedSize(QtCore.QSize(20, 20))
self.setScaledContents(True)
self.set_connecting()
@@ -17,7 +18,7 @@ class StatusWidget(QtWidgets.QLabel):
def set_status(self, image: str):
self.image = image
- self.setPixmap(QtGui.QPixmap(get_theme_file(image)))
+ self.setPixmap(QtGui.QPixmap(get_theme_file(self.app, image)))
def set_active(self):
self.setToolTip("Listening for new messages")
diff --git a/requirements.txt b/requirements.txt
index b4d1061..ecb2b9f 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
requests==2.28.2
websocket-client==1.5.1
-pyqt6==6.4.2
+pyqt6==6.5.0
python-dateutil==2.8.2