Compare commits
3 Commits
efdc63e1ab
...
7b695d7b7f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b695d7b7f | ||
|
|
2b3d9eb07f | ||
|
|
d0941fd7ab |
10
BUILDING.md
10
BUILDING.md
@@ -7,6 +7,16 @@ $ pip install -r requirements.txt
|
|||||||
$ pip install pyinstaller
|
$ 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:
|
Currently it's only possible to create installer packages from the pyinstaller output. For any target platform, first create the executable with pyinstaller:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ logo = "gotify_tray/gui/images/logo.ico" if platform.system() != "Darwin" else "
|
|||||||
|
|
||||||
a = Analysis(['gotify_tray/__main__.py'],
|
a = Analysis(['gotify_tray/__main__.py'],
|
||||||
pathex=[os.getcwd()],
|
pathex=[os.getcwd()],
|
||||||
binaries=[],
|
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')],
|
datas=[('gotify_tray/gui/images', 'gotify_tray/gui/images'), ('gotify_tray/gui/themes', 'gotify_tray/gui/themes')],
|
||||||
hiddenimports=[],
|
hiddenimports=[],
|
||||||
hookspath=[],
|
hookspath=[],
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
def main():
|
def main():
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
if "--version" in sys.argv:
|
if "--version" in sys.argv:
|
||||||
from gotify_tray.__version__ import __version__
|
from gotify_tray.__version__ import __version__
|
||||||
|
|
||||||
print(__version__)
|
print(__version__)
|
||||||
else:
|
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
|
from gotify_tray.gui import start_gui
|
||||||
|
|
||||||
start_gui()
|
start_gui()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -459,6 +459,7 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
self.main_window.hidden.connect(self.main_window_hidden_callback)
|
self.main_window.hidden.connect(self.main_window_hidden_callback)
|
||||||
self.main_window.activated.connect(self.tray.revert_icon)
|
self.main_window.activated.connect(self.tray.revert_icon)
|
||||||
|
|
||||||
|
if hasattr(self.styleHints(), "colorSchemeChanged"):
|
||||||
self.styleHints().colorSchemeChanged.connect(
|
self.styleHints().colorSchemeChanged.connect(
|
||||||
self.theme_change_requested_callback
|
self.theme_change_requested_callback
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Form implementation generated from reading ui file 'gotify_tray/gui/designs/widget_main.ui'
|
# 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
|
# 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.
|
# 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.setChecked(True)
|
||||||
self.pb_critical.setObjectName("pb_critical")
|
self.pb_critical.setObjectName("pb_critical")
|
||||||
self.filtersLayout.addWidget(self.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)
|
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
||||||
self.filtersLayout.addItem(spacerItem2)
|
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 = QtWidgets.QPushButton(parent=self.verticalLayoutWidget)
|
||||||
self.pb_remove_filters.setObjectName("pb_remove_filters")
|
self.pb_remove_filters.setObjectName("pb_remove_filters")
|
||||||
self.filtersLayout.addWidget(self.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_normal.setText(_translate("MainWindow", "NORMAL"))
|
||||||
self.pb_high.setText(_translate("MainWindow", "HIGH"))
|
self.pb_high.setText(_translate("MainWindow", "HIGH"))
|
||||||
self.pb_critical.setText(_translate("MainWindow", "CRITICAL"))
|
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"))
|
self.pb_remove_filters.setText(_translate("MainWindow", "Remove Filters"))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -151,6 +151,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="le_search">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Search messages...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_3">
|
<spacer name="horizontalSpacer_3">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
@@ -164,13 +171,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_subject">
|
|
||||||
<property name="text">
|
|
||||||
<string>Subject:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pb_remove_filters">
|
<widget class="QPushButton" name="pb_remove_filters">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Form implementation generated from reading ui file 'gotify_tray/gui/designs/widget_message.ui'
|
# 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
|
# 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.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Form implementation generated from reading ui file 'gotify_tray/gui/designs/widget_server.ui'
|
# 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
|
# 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.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Form implementation generated from reading ui file 'gotify_tray/gui/designs/widget_settings.ui'
|
# 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
|
# 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.
|
# run again. Do not edit this file unless you know what you are doing.
|
||||||
|
|||||||
@@ -44,11 +44,16 @@ class MessagesProxyModel(QtCore.QSortFilterProxyModel):
|
|||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.allowed_priorities = set(range(11)) # 0-10
|
self.allowed_priorities = set(range(11)) # 0-10
|
||||||
|
self.text_filter = ""
|
||||||
|
|
||||||
def set_allowed_priorities(self, priorities: set[int]):
|
def set_allowed_priorities(self, priorities: set[int]):
|
||||||
self.allowed_priorities = priorities
|
self.allowed_priorities = priorities
|
||||||
self.invalidateFilter()
|
self.invalidateFilter()
|
||||||
|
|
||||||
|
def set_text_filter(self, text: str):
|
||||||
|
self.text_filter = text.lower()
|
||||||
|
self.invalidateFilter()
|
||||||
|
|
||||||
def filterAcceptsRow(
|
def filterAcceptsRow(
|
||||||
self, source_row: int, source_parent: QtCore.QModelIndex
|
self, source_row: int, source_parent: QtCore.QModelIndex
|
||||||
) -> bool:
|
) -> bool:
|
||||||
@@ -58,4 +63,9 @@ class MessagesProxyModel(QtCore.QSortFilterProxyModel):
|
|||||||
priority = message.priority if message.priority is not None else 0
|
priority = message.priority if message.priority is not None else 0
|
||||||
if self.allowed_priorities and priority not in self.allowed_priorities:
|
if self.allowed_priorities and priority not in self.allowed_priorities:
|
||||||
return False
|
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
|
return True
|
||||||
|
|||||||
@@ -3,14 +3,21 @@ from gotify_tray.utils import get_abs_path
|
|||||||
|
|
||||||
|
|
||||||
themes = {
|
themes = {
|
||||||
QtCore.Qt.ColorScheme.Dark: "dark",
|
2: "dark", # Dark
|
||||||
QtCore.Qt.ColorScheme.Light: "light",
|
1: "light", # Light
|
||||||
QtCore.Qt.ColorScheme.Unknown: "light",
|
0: "light", # Unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def set_theme(app: QtWidgets.QApplication):
|
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 = ""
|
stylesheet = ""
|
||||||
with open(get_abs_path(f"gotify_tray/gui/themes/base.qss"), "r") as f:
|
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:
|
def get_theme_file(file: str) -> str:
|
||||||
app = QtCore.QCoreApplication.instance()
|
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}")
|
return get_abs_path(f"gotify_tray/gui/themes/{theme}/{file}")
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
self.pb_critical.setCheckable(False)
|
self.pb_critical.setCheckable(False)
|
||||||
|
|
||||||
self.pb_remove_filters.clicked.connect(self.on_remove_filters_clicked)
|
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)
|
# set refresh shortcut (usually ctrl-r)
|
||||||
# unfortunately this cannot be done with designer
|
# unfortunately this cannot be done with designer
|
||||||
@@ -281,3 +282,10 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
self.pb_normal.setChecked(True)
|
self.pb_normal.setChecked(True)
|
||||||
self.pb_high.setChecked(True)
|
self.pb_high.setChecked(True)
|
||||||
# Critical is always on
|
# 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
15
run.sh
Executable 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
|
||||||
Reference in New Issue
Block a user