Merge branch 'render-images' into develop
This commit is contained in:
@@ -32,6 +32,9 @@ class Cache(object):
|
|||||||
self.cache_dir = os.path.join(path, "cache")
|
self.cache_dir = os.path.join(path, "cache")
|
||||||
os.makedirs(self.cache_dir, exist_ok=True)
|
os.makedirs(self.cache_dir, exist_ok=True)
|
||||||
|
|
||||||
|
def directory(self) -> str:
|
||||||
|
return self.cache_dir
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
self.cursor.execute("DELETE FROM cache")
|
self.cursor.execute("DELETE FROM cache")
|
||||||
self.database.commit()
|
self.database.commit()
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ DEFAULT_SETTINGS = {
|
|||||||
"tray/icon/unread": False,
|
"tray/icon/unread": False,
|
||||||
"watchdog/interval/s": 60,
|
"watchdog/interval/s": 60,
|
||||||
"MessageWidget/image/size": 33,
|
"MessageWidget/image/size": 33,
|
||||||
|
"MessageWidget/content_image/W_percentage": 1.0,
|
||||||
|
"MessageWidget/content_image/H_percentage": 0.5,
|
||||||
"MainWindow/label/size": 25,
|
"MainWindow/label/size": 25,
|
||||||
"MainWindow/button/size": 33,
|
"MainWindow/button/size": 33,
|
||||||
"MainWindow/application/icon/size": 40,
|
"MainWindow/application/icon/size": 40,
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ from gotify_tray.tasks import (
|
|||||||
GetApplicationsTask,
|
GetApplicationsTask,
|
||||||
GetApplicationMessagesTask,
|
GetApplicationMessagesTask,
|
||||||
GetMessagesTask,
|
GetMessagesTask,
|
||||||
|
ProcessMessageTask,
|
||||||
|
ProcessMessagesTask,
|
||||||
ServerConnectionWatchdogTask,
|
ServerConnectionWatchdogTask,
|
||||||
)
|
)
|
||||||
from gotify_tray.gui.themes import set_theme
|
from gotify_tray.gui.themes import set_theme
|
||||||
@@ -74,6 +76,8 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
self.application_model = ApplicationModel()
|
self.application_model = ApplicationModel()
|
||||||
|
|
||||||
self.main_window = MainWindow(self.application_model, self.messages_model)
|
self.main_window = MainWindow(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)
|
||||||
|
|
||||||
self.refresh_applications()
|
self.refresh_applications()
|
||||||
|
|
||||||
@@ -195,43 +199,39 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_messages_finished_callback(self, page: gotify.GotifyPagedMessagesModel):
|
||||||
|
"""Process messages before inserting them into the main window
|
||||||
|
"""
|
||||||
|
|
||||||
|
def insert_helper(row: int, message: gotify.GotifyMessageModel):
|
||||||
|
if item := self.application_model.itemFromId(message.appid):
|
||||||
|
self.insert_message(
|
||||||
|
row, message, item.data(ApplicationItemDataRole.ApplicationRole),
|
||||||
|
)
|
||||||
|
self.processEvents()
|
||||||
|
|
||||||
|
self.process_messages_task = ProcessMessagesTask(page)
|
||||||
|
self.process_messages_task.message_processed.connect(insert_helper)
|
||||||
|
self.process_messages_task.start()
|
||||||
|
|
||||||
def application_selection_changed_callback(
|
def application_selection_changed_callback(
|
||||||
self, item: Union[ApplicationModelItem, ApplicationAllMessagesItem]
|
self, item: Union[ApplicationModelItem, ApplicationAllMessagesItem]
|
||||||
):
|
):
|
||||||
self.messages_model.clear()
|
self.messages_model.clear()
|
||||||
|
|
||||||
if isinstance(item, ApplicationModelItem):
|
if isinstance(item, ApplicationModelItem):
|
||||||
|
|
||||||
def get_application_messages_callback(
|
|
||||||
page: gotify.GotifyPagedMessagesModel,
|
|
||||||
):
|
|
||||||
for i, message in enumerate(page.messages):
|
|
||||||
self.insert_message(
|
|
||||||
i, message, item.data(ApplicationItemDataRole.ApplicationRole),
|
|
||||||
)
|
|
||||||
|
|
||||||
self.get_application_messages_task = GetApplicationMessagesTask(
|
self.get_application_messages_task = GetApplicationMessagesTask(
|
||||||
item.data(ApplicationItemDataRole.ApplicationRole).id,
|
item.data(ApplicationItemDataRole.ApplicationRole).id,
|
||||||
self.gotify_client,
|
self.gotify_client,
|
||||||
)
|
)
|
||||||
self.get_application_messages_task.success.connect(
|
self.get_application_messages_task.success.connect(
|
||||||
get_application_messages_callback
|
self.get_messages_finished_callback
|
||||||
)
|
)
|
||||||
self.get_application_messages_task.start()
|
self.get_application_messages_task.start()
|
||||||
|
|
||||||
elif isinstance(item, ApplicationAllMessagesItem):
|
elif isinstance(item, ApplicationAllMessagesItem):
|
||||||
|
|
||||||
def get_messages_callback(page: gotify.GotifyPagedMessagesModel):
|
|
||||||
for i, message in enumerate(page.messages):
|
|
||||||
if item := self.application_model.itemFromId(message.appid):
|
|
||||||
self.insert_message(
|
|
||||||
i,
|
|
||||||
message,
|
|
||||||
item.data(ApplicationItemDataRole.ApplicationRole),
|
|
||||||
)
|
|
||||||
|
|
||||||
self.get_messages_task = GetMessagesTask(self.gotify_client)
|
self.get_messages_task = GetMessagesTask(self.gotify_client)
|
||||||
self.get_messages_task.success.connect(get_messages_callback)
|
self.get_messages_task.success.connect(self.get_messages_finished_callback)
|
||||||
self.get_messages_task.start()
|
self.get_messages_task.start()
|
||||||
|
|
||||||
def add_message_to_model(self, message: gotify.GotifyMessageModel):
|
def add_message_to_model(self, message: gotify.GotifyMessageModel):
|
||||||
@@ -240,14 +240,27 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
if selected_application_item := self.application_model.itemFromIndex(
|
if selected_application_item := self.application_model.itemFromIndex(
|
||||||
application_index
|
application_index
|
||||||
):
|
):
|
||||||
if isinstance(selected_application_item, ApplicationModelItem):
|
|
||||||
# A single application is selected
|
def insert_message_helper():
|
||||||
if (
|
if isinstance(selected_application_item, ApplicationModelItem):
|
||||||
message.appid
|
# A single application is selected
|
||||||
== selected_application_item.data(
|
if (
|
||||||
ApplicationItemDataRole.ApplicationRole
|
message.appid
|
||||||
).id
|
== selected_application_item.data(
|
||||||
|
ApplicationItemDataRole.ApplicationRole
|
||||||
|
).id
|
||||||
|
):
|
||||||
|
self.insert_message(
|
||||||
|
0,
|
||||||
|
message,
|
||||||
|
application_item.data(
|
||||||
|
ApplicationItemDataRole.ApplicationRole
|
||||||
|
),
|
||||||
|
)
|
||||||
|
elif isinstance(
|
||||||
|
selected_application_item, ApplicationAllMessagesItem
|
||||||
):
|
):
|
||||||
|
# "All messages' is selected
|
||||||
self.insert_message(
|
self.insert_message(
|
||||||
0,
|
0,
|
||||||
message,
|
message,
|
||||||
@@ -255,13 +268,15 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
ApplicationItemDataRole.ApplicationRole
|
ApplicationItemDataRole.ApplicationRole
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
elif isinstance(selected_application_item, ApplicationAllMessagesItem):
|
|
||||||
# "All messages' is selected
|
self.process_message_task = ProcessMessageTask(message)
|
||||||
self.insert_message(
|
self.process_message_task.finished.connect(insert_message_helper)
|
||||||
0,
|
self.process_message_task.start()
|
||||||
message,
|
else:
|
||||||
application_item.data(ApplicationItemDataRole.ApplicationRole),
|
logger.error(
|
||||||
)
|
f"App id {message.appid} could not be found. Refreshing applications."
|
||||||
|
)
|
||||||
|
self.refresh_applications()
|
||||||
|
|
||||||
def new_message_callback(self, message: gotify.GotifyMessageModel):
|
def new_message_callback(self, message: gotify.GotifyMessageModel):
|
||||||
self.add_message_to_model(message)
|
self.add_message_to_model(message)
|
||||||
@@ -335,11 +350,6 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
if image_popup := getattr(self, "image_popup", None):
|
if image_popup := getattr(self, "image_popup", None):
|
||||||
image_popup.close()
|
image_popup.close()
|
||||||
|
|
||||||
def refresh_callback(self):
|
|
||||||
# Manual refresh -> also reset the image cache
|
|
||||||
Cache().clear()
|
|
||||||
self.refresh_applications()
|
|
||||||
|
|
||||||
def theme_change_requested_callback(self, theme: str):
|
def theme_change_requested_callback(self, theme: str):
|
||||||
# Set the theme
|
# Set the theme
|
||||||
set_theme(self, theme)
|
set_theme(self, theme)
|
||||||
@@ -400,7 +410,7 @@ class MainApplication(QtWidgets.QApplication):
|
|||||||
self.tray.messageClicked.connect(self.tray_notification_clicked_callback)
|
self.tray.messageClicked.connect(self.tray_notification_clicked_callback)
|
||||||
self.tray.activated.connect(self.tray_activated_callback)
|
self.tray.activated.connect(self.tray_activated_callback)
|
||||||
|
|
||||||
self.main_window.refresh.connect(self.refresh_callback)
|
self.main_window.refresh.connect(self.refresh_applications)
|
||||||
self.main_window.delete_all.connect(self.delete_all_messages_callback)
|
self.main_window.delete_all.connect(self.delete_all_messages_callback)
|
||||||
self.main_window.application_selection_changed.connect(
|
self.main_window.application_selection_changed.connect(
|
||||||
self.application_selection_changed_callback
|
self.application_selection_changed_callback
|
||||||
|
|||||||
@@ -171,6 +171,22 @@ class Ui_Dialog(object):
|
|||||||
self.horizontalLayout_4.addItem(spacerItem5)
|
self.horizontalLayout_4.addItem(spacerItem5)
|
||||||
self.gridLayout_2.addLayout(self.horizontalLayout_4, 0, 0, 1, 1)
|
self.gridLayout_2.addLayout(self.horizontalLayout_4, 0, 0, 1, 1)
|
||||||
self.verticalLayout.addWidget(self.groupbox_image_popup)
|
self.verticalLayout.addWidget(self.groupbox_image_popup)
|
||||||
|
self.groupBox_cache = QtWidgets.QGroupBox(self.tab_advanced)
|
||||||
|
self.groupBox_cache.setObjectName("groupBox_cache")
|
||||||
|
self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.groupBox_cache)
|
||||||
|
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
|
||||||
|
self.pb_clear_cache = QtWidgets.QPushButton(self.groupBox_cache)
|
||||||
|
self.pb_clear_cache.setObjectName("pb_clear_cache")
|
||||||
|
self.horizontalLayout_6.addWidget(self.pb_clear_cache)
|
||||||
|
self.pb_open_cache_dir = QtWidgets.QPushButton(self.groupBox_cache)
|
||||||
|
self.pb_open_cache_dir.setObjectName("pb_open_cache_dir")
|
||||||
|
self.horizontalLayout_6.addWidget(self.pb_open_cache_dir)
|
||||||
|
self.label_cache = QtWidgets.QLabel(self.groupBox_cache)
|
||||||
|
self.label_cache.setObjectName("label_cache")
|
||||||
|
self.horizontalLayout_6.addWidget(self.label_cache)
|
||||||
|
spacerItem6 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
||||||
|
self.horizontalLayout_6.addItem(spacerItem6)
|
||||||
|
self.verticalLayout.addWidget(self.groupBox_cache)
|
||||||
self.groupBox_logging = QtWidgets.QGroupBox(self.tab_advanced)
|
self.groupBox_logging = QtWidgets.QGroupBox(self.tab_advanced)
|
||||||
self.groupBox_logging.setObjectName("groupBox_logging")
|
self.groupBox_logging.setObjectName("groupBox_logging")
|
||||||
self.gridLayout_6 = QtWidgets.QGridLayout(self.groupBox_logging)
|
self.gridLayout_6 = QtWidgets.QGridLayout(self.groupBox_logging)
|
||||||
@@ -178,8 +194,8 @@ class Ui_Dialog(object):
|
|||||||
self.combo_logging = QtWidgets.QComboBox(self.groupBox_logging)
|
self.combo_logging = QtWidgets.QComboBox(self.groupBox_logging)
|
||||||
self.combo_logging.setObjectName("combo_logging")
|
self.combo_logging.setObjectName("combo_logging")
|
||||||
self.gridLayout_6.addWidget(self.combo_logging, 0, 1, 1, 1)
|
self.gridLayout_6.addWidget(self.combo_logging, 0, 1, 1, 1)
|
||||||
spacerItem6 = QtWidgets.QSpacerItem(190, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
spacerItem7 = QtWidgets.QSpacerItem(190, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
|
||||||
self.gridLayout_6.addItem(spacerItem6, 0, 3, 1, 1)
|
self.gridLayout_6.addItem(spacerItem7, 0, 3, 1, 1)
|
||||||
self.pb_open_log = QtWidgets.QPushButton(self.groupBox_logging)
|
self.pb_open_log = QtWidgets.QPushButton(self.groupBox_logging)
|
||||||
self.pb_open_log.setMaximumSize(QtCore.QSize(30, 16777215))
|
self.pb_open_log.setMaximumSize(QtCore.QSize(30, 16777215))
|
||||||
self.pb_open_log.setObjectName("pb_open_log")
|
self.pb_open_log.setObjectName("pb_open_log")
|
||||||
@@ -188,8 +204,8 @@ class Ui_Dialog(object):
|
|||||||
self.label_logging.setObjectName("label_logging")
|
self.label_logging.setObjectName("label_logging")
|
||||||
self.gridLayout_6.addWidget(self.label_logging, 0, 0, 1, 1)
|
self.gridLayout_6.addWidget(self.label_logging, 0, 0, 1, 1)
|
||||||
self.verticalLayout.addWidget(self.groupBox_logging)
|
self.verticalLayout.addWidget(self.groupBox_logging)
|
||||||
spacerItem7 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
|
spacerItem8 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
|
||||||
self.verticalLayout.addItem(spacerItem7)
|
self.verticalLayout.addItem(spacerItem8)
|
||||||
self.tabWidget.addTab(self.tab_advanced, "")
|
self.tabWidget.addTab(self.tab_advanced, "")
|
||||||
self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1)
|
self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1)
|
||||||
|
|
||||||
@@ -238,6 +254,10 @@ class Ui_Dialog(object):
|
|||||||
self.label_2.setToolTip(_translate("Dialog", "Maximum pop-up height"))
|
self.label_2.setToolTip(_translate("Dialog", "Maximum pop-up height"))
|
||||||
self.label_2.setText(_translate("Dialog", "Height"))
|
self.label_2.setText(_translate("Dialog", "Height"))
|
||||||
self.spin_popup_h.setToolTip(_translate("Dialog", "Maximum pop-up height"))
|
self.spin_popup_h.setToolTip(_translate("Dialog", "Maximum pop-up height"))
|
||||||
|
self.groupBox_cache.setTitle(_translate("Dialog", "Cache"))
|
||||||
|
self.pb_clear_cache.setText(_translate("Dialog", "Clear"))
|
||||||
|
self.pb_open_cache_dir.setText(_translate("Dialog", "Open"))
|
||||||
|
self.label_cache.setText(_translate("Dialog", "TextLabel"))
|
||||||
self.groupBox_logging.setTitle(_translate("Dialog", "Logging"))
|
self.groupBox_logging.setTitle(_translate("Dialog", "Logging"))
|
||||||
self.pb_open_log.setToolTip(_translate("Dialog", "Open logfile"))
|
self.pb_open_log.setToolTip(_translate("Dialog", "Open logfile"))
|
||||||
self.pb_open_log.setText(_translate("Dialog", "..."))
|
self.pb_open_log.setText(_translate("Dialog", "..."))
|
||||||
|
|||||||
@@ -400,6 +400,49 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_cache">
|
||||||
|
<property name="title">
|
||||||
|
<string>Cache</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pb_clear_cache">
|
||||||
|
<property name="text">
|
||||||
|
<string>Clear</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pb_open_cache_dir">
|
||||||
|
<property name="text">
|
||||||
|
<string>Open</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_cache">
|
||||||
|
<property name="text">
|
||||||
|
<string>TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_6">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox_logging">
|
<widget class="QGroupBox" name="groupBox_logging">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
|
|||||||
@@ -104,7 +104,9 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
def insert_message_widget(
|
def insert_message_widget(
|
||||||
self, message_item: MessagesModelItem, image_path: str = ""
|
self, message_item: MessagesModelItem, image_path: str = ""
|
||||||
):
|
):
|
||||||
message_widget = MessageWidget(message_item, image_path=image_path)
|
message_widget = MessageWidget(
|
||||||
|
self.listView_messages, message_item, image_path=image_path
|
||||||
|
)
|
||||||
self.listView_messages.setIndexWidget(
|
self.listView_messages.setIndexWidget(
|
||||||
self.messages_model.indexFromItem(message_item), message_widget
|
self.messages_model.indexFromItem(message_item), message_widget
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ from PyQt6 import QtCore, QtGui, QtWidgets
|
|||||||
|
|
||||||
from ..models.MessagesModel import MessageItemDataRole, MessagesModelItem
|
from ..models.MessagesModel import MessageItemDataRole, MessagesModelItem
|
||||||
from ..designs.widget_message import Ui_Form
|
from ..designs.widget_message import Ui_Form
|
||||||
|
from gotify_tray.database import Downloader
|
||||||
from gotify_tray.database import Settings
|
from gotify_tray.database import Settings
|
||||||
from gotify_tray.utils import convert_links
|
from gotify_tray.utils import convert_links, get_image
|
||||||
from gotify_tray.gui.themes import get_theme_file
|
from gotify_tray.gui.themes import get_theme_file
|
||||||
|
from gotify_tray.gotify.models import GotifyMessageModel
|
||||||
|
|
||||||
|
|
||||||
settings = Settings("gotify-tray")
|
settings = Settings("gotify-tray")
|
||||||
@@ -16,13 +18,18 @@ class MessageWidget(QtWidgets.QWidget, Ui_Form):
|
|||||||
deletion_requested = QtCore.pyqtSignal(MessagesModelItem)
|
deletion_requested = QtCore.pyqtSignal(MessagesModelItem)
|
||||||
image_popup = QtCore.pyqtSignal(str, QtCore.QPoint)
|
image_popup = QtCore.pyqtSignal(str, QtCore.QPoint)
|
||||||
|
|
||||||
def __init__(self, message_item: MessagesModelItem, image_path: str = ""):
|
def __init__(
|
||||||
|
self,
|
||||||
|
parent: QtWidgets.QWidget,
|
||||||
|
message_item: MessagesModelItem,
|
||||||
|
image_path: str = "",
|
||||||
|
):
|
||||||
super(MessageWidget, self).__init__()
|
super(MessageWidget, self).__init__()
|
||||||
|
self.parent = parent
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self.setAutoFillBackground(True)
|
self.setAutoFillBackground(True)
|
||||||
|
|
||||||
self.message_item = message_item
|
self.message_item = message_item
|
||||||
message = message_item.data(MessageItemDataRole.MessageRole)
|
message: GotifyMessageModel = message_item.data(MessageItemDataRole.MessageRole)
|
||||||
|
|
||||||
# Fonts
|
# Fonts
|
||||||
self.set_fonts()
|
self.set_fonts()
|
||||||
@@ -31,14 +38,20 @@ class MessageWidget(QtWidgets.QWidget, Ui_Form):
|
|||||||
self.label_title.setText(message.title)
|
self.label_title.setText(message.title)
|
||||||
self.label_date.setText(message.date.strftime("%Y-%m-%d, %H:%M"))
|
self.label_date.setText(message.date.strftime("%Y-%m-%d, %H:%M"))
|
||||||
|
|
||||||
if (
|
if markdown := (
|
||||||
markdown := message.get("extras", {})
|
message.get("extras", {}).get("client::display", {}).get("contentType")
|
||||||
.get("client::display", {})
|
== "text/markdown"
|
||||||
.get("contentType")
|
):
|
||||||
) == "text/markdown":
|
|
||||||
self.label_message.setTextFormat(QtCore.Qt.TextFormat.MarkdownText)
|
self.label_message.setTextFormat(QtCore.Qt.TextFormat.MarkdownText)
|
||||||
|
|
||||||
self.label_message.setText(convert_links(message.message))
|
# If the message is only an image URL, then instead of showing the message,
|
||||||
|
# download the image and show it in the message label
|
||||||
|
if image_url := get_image(message.message):
|
||||||
|
downloader = Downloader()
|
||||||
|
filename = downloader.get_filename(image_url)
|
||||||
|
self.set_message_image(filename)
|
||||||
|
else:
|
||||||
|
self.label_message.setText(convert_links(message.message))
|
||||||
|
|
||||||
# Show the application icon
|
# Show the application icon
|
||||||
if image_path:
|
if image_path:
|
||||||
@@ -91,6 +104,27 @@ class MessageWidget(QtWidgets.QWidget, Ui_Form):
|
|||||||
self.pb_delete.setIcon(QtGui.QIcon(get_theme_file("trashcan.svg")))
|
self.pb_delete.setIcon(QtGui.QIcon(get_theme_file("trashcan.svg")))
|
||||||
self.pb_delete.setIconSize(QtCore.QSize(24, 24))
|
self.pb_delete.setIconSize(QtCore.QSize(24, 24))
|
||||||
|
|
||||||
|
def set_message_image(self, filename: str):
|
||||||
|
pixmap = QtGui.QPixmap(filename)
|
||||||
|
|
||||||
|
# Make sure the image fits within the listView
|
||||||
|
W = settings.value("MessageWidget/content_image/W_percentage", type=float) * (
|
||||||
|
self.parent.width() - self.label_image.width()
|
||||||
|
)
|
||||||
|
H = (
|
||||||
|
settings.value("MessageWidget/content_image/H_percentage", type=float)
|
||||||
|
* self.parent.height()
|
||||||
|
)
|
||||||
|
|
||||||
|
if pixmap.width() > W or pixmap.height() > H:
|
||||||
|
pixmap = pixmap.scaled(
|
||||||
|
QtCore.QSize(int(W), int(H)),
|
||||||
|
aspectRatioMode=QtCore.Qt.AspectRatioMode.KeepAspectRatio,
|
||||||
|
transformMode=QtCore.Qt.TransformationMode.SmoothTransformation,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.label_message.setPixmap(pixmap)
|
||||||
|
|
||||||
def link_hovered_callback(self, link: str):
|
def link_hovered_callback(self, link: str):
|
||||||
if not settings.value("ImagePopup/enabled", type=bool):
|
if not settings.value("ImagePopup/enabled", type=bool):
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import logging
|
|||||||
import platform
|
import platform
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from gotify_tray.database import Settings
|
from gotify_tray.database import Cache, Settings
|
||||||
from gotify_tray.gotify import GotifyMessageModel
|
from gotify_tray.gotify import GotifyMessageModel
|
||||||
from gotify_tray.gui.models import MessagesModelItem
|
from gotify_tray.gui.models import MessagesModelItem
|
||||||
from . import MessageWidget
|
from . import MessageWidget
|
||||||
from gotify_tray.utils import get_icon, verify_server, open_file
|
from gotify_tray.utils import get_icon, verify_server, open_file
|
||||||
from gotify_tray.tasks import ExportSettingsTask, ImportSettingsTask
|
from gotify_tray.tasks import ExportSettingsTask, ImportSettingsTask, CacheSizeTask, ClearCacheTask
|
||||||
from gotify_tray.gui.themes import get_themes
|
from gotify_tray.gui.themes import get_themes
|
||||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
@@ -91,9 +91,12 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
)
|
)
|
||||||
self.spin_popup_w.setValue(settings.value("ImagePopup/w", type=int))
|
self.spin_popup_w.setValue(settings.value("ImagePopup/w", type=int))
|
||||||
self.spin_popup_h.setValue(settings.value("ImagePopup/h", type=int))
|
self.spin_popup_h.setValue(settings.value("ImagePopup/h", type=int))
|
||||||
|
self.label_cache.setText("0 MB")
|
||||||
|
self.compute_cache_size()
|
||||||
|
|
||||||
def add_message_widget(self):
|
def add_message_widget(self):
|
||||||
self.message_widget = MessageWidget(
|
self.message_widget = MessageWidget(
|
||||||
|
self,
|
||||||
MessagesModelItem(
|
MessagesModelItem(
|
||||||
GotifyMessageModel(
|
GotifyMessageModel(
|
||||||
{
|
{
|
||||||
@@ -107,6 +110,11 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
)
|
)
|
||||||
self.layout_fonts_message.addWidget(self.message_widget)
|
self.layout_fonts_message.addWidget(self.message_widget)
|
||||||
|
|
||||||
|
def compute_cache_size(self):
|
||||||
|
self.cache_size_task = CacheSizeTask()
|
||||||
|
self.cache_size_task.size.connect(lambda size: self.label_cache.setText(f"{round(size/1e6, 1)} MB"))
|
||||||
|
self.cache_size_task.start()
|
||||||
|
|
||||||
def change_server_info_callback(self):
|
def change_server_info_callback(self):
|
||||||
self.server_changed = verify_server(force_new=True, enable_import=False)
|
self.server_changed = verify_server(force_new=True, enable_import=False)
|
||||||
|
|
||||||
@@ -179,6 +187,11 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
settings.clear()
|
settings.clear()
|
||||||
self.quit_requested.emit()
|
self.quit_requested.emit()
|
||||||
|
|
||||||
|
def clear_cache_callback(self):
|
||||||
|
self.clear_cache_task = ClearCacheTask()
|
||||||
|
self.clear_cache_task.start()
|
||||||
|
self.label_cache.setText("0 MB")
|
||||||
|
|
||||||
def link_callbacks(self):
|
def link_callbacks(self):
|
||||||
self.buttonBox.button(
|
self.buttonBox.button(
|
||||||
QtWidgets.QDialogButtonBox.StandardButton.Apply
|
QtWidgets.QDialogButtonBox.StandardButton.Apply
|
||||||
@@ -223,6 +236,8 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog):
|
|||||||
self.groupbox_image_popup.toggled.connect(self.settings_changed_callback)
|
self.groupbox_image_popup.toggled.connect(self.settings_changed_callback)
|
||||||
self.spin_popup_w.valueChanged.connect(self.settings_changed_callback)
|
self.spin_popup_w.valueChanged.connect(self.settings_changed_callback)
|
||||||
self.spin_popup_h.valueChanged.connect(self.settings_changed_callback)
|
self.spin_popup_h.valueChanged.connect(self.settings_changed_callback)
|
||||||
|
self.pb_clear_cache.clicked.connect(self.clear_cache_callback)
|
||||||
|
self.pb_open_cache_dir.clicked.connect(lambda: open_file(Cache().directory()))
|
||||||
|
|
||||||
def apply_settings(self):
|
def apply_settings(self):
|
||||||
# Priority
|
# Priority
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
import abc
|
import abc
|
||||||
|
import glob
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
|
from functools import reduce
|
||||||
from PyQt6 import QtCore
|
from PyQt6 import QtCore
|
||||||
from PyQt6.QtCore import pyqtSignal
|
from PyQt6.QtCore import pyqtSignal
|
||||||
|
|
||||||
from gotify_tray.database import Settings
|
from gotify_tray.database import Cache, Downloader, Settings
|
||||||
from gotify_tray.gotify.api import GotifyClient
|
from gotify_tray.gotify.api import GotifyClient
|
||||||
from gotify_tray.gotify.models import GotifyVersionModel
|
from gotify_tray.gotify.models import GotifyVersionModel
|
||||||
|
from gotify_tray.utils import get_image
|
||||||
|
|
||||||
from . import gotify
|
from . import gotify
|
||||||
|
|
||||||
@@ -199,3 +203,48 @@ class ImportSettingsTask(BaseTask):
|
|||||||
def task(self):
|
def task(self):
|
||||||
settings.load(self.path)
|
settings.load(self.path)
|
||||||
self.success.emit()
|
self.success.emit()
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessMessageTask(BaseTask):
|
||||||
|
def __init__(self, message: gotify.GotifyMessageModel):
|
||||||
|
super(ProcessMessageTask, self).__init__()
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
def task(self):
|
||||||
|
if image_url := get_image(self.message.message):
|
||||||
|
downloader = Downloader()
|
||||||
|
downloader.get_filename(image_url)
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessMessagesTask(BaseTask):
|
||||||
|
message_processed = pyqtSignal(int, gotify.GotifyMessageModel)
|
||||||
|
|
||||||
|
def __init__(self, page: gotify.GotifyPagedMessagesModel):
|
||||||
|
super(ProcessMessagesTask, self).__init__()
|
||||||
|
self.page = page
|
||||||
|
|
||||||
|
def task(self):
|
||||||
|
downloader = Downloader()
|
||||||
|
for i, message in enumerate(self.page.messages):
|
||||||
|
if image_url := get_image(message.message):
|
||||||
|
downloader.get_filename(image_url)
|
||||||
|
self.message_processed.emit(i, message)
|
||||||
|
|
||||||
|
# Prevent locking up the UI when there are a lot of messages with images ready at the same time
|
||||||
|
time.sleep(0.001)
|
||||||
|
|
||||||
|
|
||||||
|
class CacheSizeTask(BaseTask):
|
||||||
|
size = pyqtSignal(int)
|
||||||
|
|
||||||
|
def task(self):
|
||||||
|
cache_dir = Cache().directory()
|
||||||
|
if os.path.exists(cache_dir):
|
||||||
|
cache_size_bytes = reduce(lambda x, f: x + os.path.getsize(f), glob.glob(os.path.join(cache_dir, "*")), 0)
|
||||||
|
self.size.emit(cache_size_bytes)
|
||||||
|
|
||||||
|
class ClearCacheTask(BaseTask):
|
||||||
|
def task(self):
|
||||||
|
cache = Cache()
|
||||||
|
cache.clear()
|
||||||
|
|
||||||
@@ -4,6 +4,7 @@ import re
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
def verify_server(force_new: bool = False, enable_import: bool = True) -> bool:
|
def verify_server(force_new: bool = False, enable_import: bool = True) -> bool:
|
||||||
@@ -44,6 +45,25 @@ def convert_links(text):
|
|||||||
return _link.sub(replace, text)
|
return _link.sub(replace, text)
|
||||||
|
|
||||||
|
|
||||||
|
def get_image(s: str) -> Optional[str]:
|
||||||
|
"""If `s` contains only an image URL, this function returns that URL.
|
||||||
|
This function also extracts a URL in the `` markdown image format.
|
||||||
|
"""
|
||||||
|
s = s.strip()
|
||||||
|
|
||||||
|
# Return True if 's' is a url and has an image extension
|
||||||
|
RE = r'(?:(https://|http://)|(www\.))(\S+\b/?)([!"#$%&\'()*+,\-./:;<=>?@[\\\]^_`{|}~]*).(jpg|jpeg|png|bmp|gif)(\s|$)'
|
||||||
|
if re.compile(RE, re.I).fullmatch(s) is not None:
|
||||||
|
return s
|
||||||
|
|
||||||
|
# Return True if 's' has the markdown image format
|
||||||
|
RE = r'!\[[^\]]*\]\((.*?)\s*("(?:.*[^"])")?\s*\)'
|
||||||
|
if re.compile(RE, re.I).fullmatch(s) is not None:
|
||||||
|
return re.compile(RE, re.I).findall(s)[0][0]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_abs_path(s) -> str:
|
def get_abs_path(s) -> str:
|
||||||
h = Path(__file__).parent.parent
|
h = Path(__file__).parent.parent
|
||||||
p = Path(s)
|
p = Path(s)
|
||||||
|
|||||||
Reference in New Issue
Block a user