Compare commits

..

2 Commits

Author SHA1 Message Date
kdusek
7b695d7b7f Fix compatibility issues with Qt/PyQt6 versions
Some checks failed
build / build-win64 (push) Waiting to run
build / build-macos (push) Waiting to run
build / build-pip (push) Failing after 11s
- Add null check for message.message in search filter
- Handle missing colorScheme/colorSchemeChanged methods for older Qt versions
- Add display check to prevent hanging in headless environments
- Update build documentation with system package alternative
- Update PyInstaller spec for Python 3.12
- Improve run.sh script with venv management
2025-12-06 04:00:10 +01:00
kdusek
2b3d9eb07f Add search feature for Gotify alerts
Some checks failed
build / build-win64 (push) Waiting to run
build / build-macos (push) Waiting to run
build / build-pip (push) Failing after 12s
2025-12-06 03:10:41 +01:00
13 changed files with 92 additions and 24 deletions

View File

@@ -7,6 +7,16 @@ $ pip install -r requirements.txt
$ pip install pyinstaller
```
**Alternative: System packages (Debian/Ubuntu)**
If you prefer to use system packages instead of pip, install the required PyQt6 packages:
```shell
$ apt install python3-pyqt6 python3-pyqt6.qtwebsockets python3-pyqt6.qtmultimedia
```
Note: This may require specific Python versions and may not include the latest features.
Currently it's only possible to create installer packages from the pyinstaller output. For any target platform, first create the executable with pyinstaller:
```shell

View File

@@ -8,7 +8,7 @@ logo = "gotify_tray/gui/images/logo.ico" if platform.system() != "Darwin" else "
a = Analysis(['gotify_tray/__main__.py'],
pathex=[os.getcwd()],
binaries=[('/lib/x86_64-linux-gnu/libpython3.10.so', '.'), ('/lib/x86_64-linux-gnu/libpython3.10.so.1', '.')],
binaries=[('/lib/x86_64-linux-gnu/libpython3.12.so', '.'), ('/lib/x86_64-linux-gnu/libpython3.12.so.1', '.')],
datas=[('gotify_tray/gui/images', 'gotify_tray/gui/images'), ('gotify_tray/gui/themes', 'gotify_tray/gui/themes')],
hiddenimports=[],
hookspath=[],

View File

@@ -1,11 +1,21 @@
def main():
import os
import sys
if "--version" in sys.argv:
from gotify_tray.__version__ import __version__
print(__version__)
else:
# Check for display before importing GUI modules
if not os.environ.get("DISPLAY"):
print(
"Error: No display environment detected. This application requires a graphical desktop environment to run.",
file=sys.stderr,
)
sys.exit(1)
from gotify_tray.gui import start_gui
start_gui()

View File

@@ -459,9 +459,10 @@ class MainApplication(QtWidgets.QApplication):
self.main_window.hidden.connect(self.main_window_hidden_callback)
self.main_window.activated.connect(self.tray.revert_icon)
self.styleHints().colorSchemeChanged.connect(
self.theme_change_requested_callback
)
if hasattr(self.styleHints(), "colorSchemeChanged"):
self.styleHints().colorSchemeChanged.connect(
self.theme_change_requested_callback
)
self.messages_model.rowsInserted.connect(
self.main_window.display_message_widgets

View File

@@ -1,6 +1,6 @@
# Form implementation generated from reading ui file 'gotify_tray/gui/designs/widget_main.ui'
#
# Created by: PyQt6 UI code generator 6.9.1
# Created by: PyQt6 UI code generator 6.10.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
@@ -72,11 +72,11 @@ class Ui_MainWindow(object):
self.pb_critical.setChecked(True)
self.pb_critical.setObjectName("pb_critical")
self.filtersLayout.addWidget(self.pb_critical)
self.le_search = QtWidgets.QLineEdit(parent=self.verticalLayoutWidget)
self.le_search.setObjectName("le_search")
self.filtersLayout.addWidget(self.le_search)
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
self.filtersLayout.addItem(spacerItem2)
self.label_subject = QtWidgets.QLabel(parent=self.verticalLayoutWidget)
self.label_subject.setObjectName("label_subject")
self.filtersLayout.addWidget(self.label_subject)
self.pb_remove_filters = QtWidgets.QPushButton(parent=self.verticalLayoutWidget)
self.pb_remove_filters.setObjectName("pb_remove_filters")
self.filtersLayout.addWidget(self.pb_remove_filters)
@@ -105,7 +105,7 @@ class Ui_MainWindow(object):
self.pb_normal.setText(_translate("MainWindow", "NORMAL"))
self.pb_high.setText(_translate("MainWindow", "HIGH"))
self.pb_critical.setText(_translate("MainWindow", "CRITICAL"))
self.label_subject.setText(_translate("MainWindow", "Subject:"))
self.le_search.setPlaceholderText(_translate("MainWindow", "Search messages..."))
self.pb_remove_filters.setText(_translate("MainWindow", "Remove Filters"))

View File

@@ -151,6 +151,13 @@
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="le_search">
<property name="placeholderText">
<string>Search messages...</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
@@ -164,13 +171,6 @@
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_subject">
<property name="text">
<string>Subject:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pb_remove_filters">
<property name="text">

View File

@@ -1,6 +1,6 @@
# Form implementation generated from reading ui file 'gotify_tray/gui/designs/widget_message.ui'
#
# Created by: PyQt6 UI code generator 6.9.1
# Created by: PyQt6 UI code generator 6.10.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.

View File

@@ -1,6 +1,6 @@
# Form implementation generated from reading ui file 'gotify_tray/gui/designs/widget_server.ui'
#
# Created by: PyQt6 UI code generator 6.9.1
# Created by: PyQt6 UI code generator 6.10.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.

View File

@@ -1,6 +1,6 @@
# Form implementation generated from reading ui file 'gotify_tray/gui/designs/widget_settings.ui'
#
# Created by: PyQt6 UI code generator 6.9.1
# Created by: PyQt6 UI code generator 6.10.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.

View File

@@ -44,11 +44,16 @@ class MessagesProxyModel(QtCore.QSortFilterProxyModel):
def __init__(self, parent=None):
super().__init__(parent)
self.allowed_priorities = set(range(11)) # 0-10
self.text_filter = ""
def set_allowed_priorities(self, priorities: set[int]):
self.allowed_priorities = priorities
self.invalidateFilter()
def set_text_filter(self, text: str):
self.text_filter = text.lower()
self.invalidateFilter()
def filterAcceptsRow(
self, source_row: int, source_parent: QtCore.QModelIndex
) -> bool:
@@ -58,4 +63,9 @@ class MessagesProxyModel(QtCore.QSortFilterProxyModel):
priority = message.priority if message.priority is not None else 0
if self.allowed_priorities and priority not in self.allowed_priorities:
return False
if self.text_filter:
title = (message.title or "").lower()
msg = (message.message or "").lower()
if self.text_filter not in title and self.text_filter not in msg:
return False
return True

View File

@@ -3,14 +3,21 @@ from gotify_tray.utils import get_abs_path
themes = {
QtCore.Qt.ColorScheme.Dark: "dark",
QtCore.Qt.ColorScheme.Light: "light",
QtCore.Qt.ColorScheme.Unknown: "light",
2: "dark", # Dark
1: "light", # Light
0: "light", # Unknown
}
def set_theme(app: QtWidgets.QApplication):
theme = themes.get(app.styleHints().colorScheme(), "light")
if hasattr(app.styleHints(), "colorScheme"):
color_scheme = app.styleHints().colorScheme()
theme = themes.get(
color_scheme.value if hasattr(color_scheme, "value") else color_scheme,
"light",
)
else:
theme = "light" # Default to light theme if colorScheme not available
stylesheet = ""
with open(get_abs_path(f"gotify_tray/gui/themes/base.qss"), "r") as f:
@@ -23,5 +30,12 @@ def set_theme(app: QtWidgets.QApplication):
def get_theme_file(file: str) -> str:
app = QtCore.QCoreApplication.instance()
theme = themes.get(app.styleHints().colorScheme(), "light")
if hasattr(app.styleHints(), "colorScheme"):
color_scheme = app.styleHints().colorScheme()
theme = themes.get(
color_scheme.value if hasattr(color_scheme, "value") else color_scheme,
"light",
)
else:
theme = "light" # Default to light theme if colorScheme not available
return get_abs_path(f"gotify_tray/gui/themes/{theme}/{file}")

View File

@@ -100,6 +100,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.pb_critical.setCheckable(False)
self.pb_remove_filters.clicked.connect(self.on_remove_filters_clicked)
self.le_search.returnPressed.connect(self.on_search_return_pressed)
# set refresh shortcut (usually ctrl-r)
# unfortunately this cannot be done with designer
@@ -281,3 +282,10 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.pb_normal.setChecked(True)
self.pb_high.setChecked(True)
# Critical is always on
# Clear search
self.le_search.clear()
self.messages_proxy_model.set_text_filter("")
def on_search_return_pressed(self):
text = self.le_search.text()
self.messages_proxy_model.set_text_filter(text)

15
run.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/bash
# Check if virtual environment exists
if [ ! -d "venv" ]; then
echo "Creating virtual environment..."
python3 -m venv venv
echo "Installing dependencies..."
source venv/bin/activate
pip install -r requirements.txt
else
source venv/bin/activate
fi
# Run the application
python -m gotify_tray