allow reordering of applications

This commit is contained in:
dries.k
2021-09-28 19:05:37 +02:00
parent 66bad86445
commit a036caaca6
6 changed files with 131 additions and 23 deletions

View File

@@ -1,6 +1,17 @@
import enum
from typing import Optional, Union from typing import Optional, Union
from PyQt6 import QtCore, QtGui from PyQt6 import QtCore, QtGui
from gotify_tray import gotify from gotify_tray import gotify
from gotify_tray.database import Settings
settings = Settings("gotify-tray")
class ApplicationItemDataRole(enum.IntEnum):
ApplicationRole = QtCore.Qt.ItemDataRole.UserRole + 1
IconRole = QtCore.Qt.ItemDataRole.UserRole + 2
class ApplicationModelItem(QtGui.QStandardItem): class ApplicationModelItem(QtGui.QStandardItem):
@@ -12,18 +23,39 @@ class ApplicationModelItem(QtGui.QStandardItem):
**kwargs **kwargs
): ):
super(ApplicationModelItem, self).__init__(application.name) super(ApplicationModelItem, self).__init__(application.name)
self.application = application self.setDropEnabled(False)
self.setData(application, ApplicationItemDataRole.ApplicationRole)
self.setData(icon, ApplicationItemDataRole.IconRole)
if icon: if icon:
self.setIcon(icon) self.setIcon(icon)
def clone(self):
return ApplicationModelItem(
self.data(ApplicationItemDataRole.ApplicationRole),
self.data(ApplicationItemDataRole.IconRole),
)
class ApplicationAllMessagesItem(QtGui.QStandardItem): class ApplicationAllMessagesItem(QtGui.QStandardItem):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ApplicationAllMessagesItem, self).__init__("ALL MESSAGES") super(ApplicationAllMessagesItem, self).__init__("ALL MESSAGES")
self.setDropEnabled(False)
self.setDragEnabled(False)
class ApplicationModel(QtGui.QStandardItemModel): class ApplicationModel(QtGui.QStandardItemModel):
def setItem(self, row: int, column: int, item: Union[ApplicationModelItem, ApplicationAllMessagesItem]) -> None: def __init__(self):
super(ApplicationModel, self).__init__()
self.setItemPrototype(
ApplicationModelItem(gotify.GotifyApplicationModel({"name": ""}), None)
)
def setItem(
self,
row: int,
column: int,
item: Union[ApplicationModelItem, ApplicationAllMessagesItem],
) -> None:
super(ApplicationModel, self).setItem(row, column, item) super(ApplicationModel, self).setItem(row, column, item)
def itemFromIndex( def itemFromIndex(
@@ -36,6 +68,17 @@ class ApplicationModel(QtGui.QStandardItemModel):
item = self.item(row, 0) item = self.item(row, 0)
if not isinstance(item, ApplicationModelItem): if not isinstance(item, ApplicationModelItem):
continue continue
if item.application.id == appid: if item.data(ApplicationItemDataRole.ApplicationRole).id == appid:
return item return item
return None return None
def save_order(self, *args):
try:
application_ids = [
self.item(i, 0).data(ApplicationItemDataRole.ApplicationRole).id
for i in range(1, self.rowCount())
]
except AttributeError:
return
settings.setValue("ApplicationModel/order", application_ids)

View File

@@ -18,13 +18,14 @@ from PyQt6 import QtCore, QtGui, QtWidgets
from ..__version__ import __title__ from ..__version__ import __title__
from .ApplicationModel import ( from .ApplicationModel import (
ApplicationItemDataRole,
ApplicationAllMessagesItem, ApplicationAllMessagesItem,
ApplicationModel, ApplicationModel,
ApplicationModelItem, ApplicationModelItem,
) )
from .designs.widget_main import Ui_Form as Ui_Main from .designs.widget_main import Ui_Form as Ui_Main
from .themes import set_theme from .themes import set_theme
from .MessagesModel import MessagesModel, MessagesModelItem from .MessagesModel import MessageItemDataRole, MessagesModel, MessagesModelItem
from .MessageWidget import MessageWidget from .MessageWidget import MessageWidget
from .SettingsDialog import SettingsDialog from .SettingsDialog import SettingsDialog
from .Tray import Tray from .Tray import Tray
@@ -126,7 +127,32 @@ class MainWindow(QtWidgets.QMainWindow):
def get_applications_callback( def get_applications_callback(
applications: List[gotify.GotifyApplicationModel], applications: List[gotify.GotifyApplicationModel],
): ):
for i, application in enumerate(applications): stored_application_ids_order = [
int(x) for x in settings.value("ApplicationModel/order", type=list)
]
fetched_application_ids = [application.id for application in applications]
# Remove ids from stored_application_ids that are not in fetched_application_ids
application_ids_order = list(
filter(
lambda x: x in fetched_application_ids, stored_application_ids_order
)
)
# Add new ids to the back of the list
application_ids_order += list(
filter(
lambda x: x not in stored_application_ids_order,
fetched_application_ids,
)
)
for i, application_id in enumerate(application_ids_order):
application = list(
filter(
lambda application: application.id == application_id,
applications,
)
)[0]
icon = ( icon = (
QtGui.QIcon( QtGui.QIcon(
downloader.get_filename( downloader.get_filename(
@@ -140,6 +166,8 @@ class MainWindow(QtWidgets.QMainWindow):
i + 1, 0, ApplicationModelItem(application, icon), i + 1, 0, ApplicationModelItem(application, icon),
) )
self.application_model.save_order()
self.get_applications_task = GetApplicationsTask(self.gotify_client) self.get_applications_task = GetApplicationsTask(self.gotify_client)
self.get_applications_task.success.connect(get_applications_callback) self.get_applications_task.success.connect(get_applications_callback)
self.get_applications_task.finished.connect( self.get_applications_task.finished.connect(
@@ -200,10 +228,15 @@ class MainWindow(QtWidgets.QMainWindow):
page: gotify.GotifyPagedMessagesModel, page: gotify.GotifyPagedMessagesModel,
): ):
for i, message in enumerate(page.messages): for i, message in enumerate(page.messages):
self.insert_message(i, message, item.application) self.insert_message(
i,
message,
item.data(ApplicationItemDataRole.ApplicationRole),
)
self.get_application_messages_task = GetApplicationMessagesTask( self.get_application_messages_task = GetApplicationMessagesTask(
item.application.id, self.gotify_client item.data(ApplicationItemDataRole.ApplicationRole).id,
self.gotify_client,
) )
self.get_application_messages_task.success.connect( self.get_application_messages_task.success.connect(
get_application_messages_callback get_application_messages_callback
@@ -215,16 +248,18 @@ class MainWindow(QtWidgets.QMainWindow):
def get_messages_callback(page: gotify.GotifyPagedMessagesModel): def get_messages_callback(page: gotify.GotifyPagedMessagesModel):
for i, message in enumerate(page.messages): for i, message in enumerate(page.messages):
if item := self.application_model.itemFromId(message.appid): if item := self.application_model.itemFromId(message.appid):
self.insert_message(i, message, item.application) 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(get_messages_callback)
self.get_messages_task.start() self.get_messages_task.start()
def refresh_callback(self): def refresh_callback(self):
self.application_model.clear() self.application_model.save_order()
self.messages_model.clear()
self.refresh_applications() self.refresh_applications()
if not self.gotify_client.listener.running: if not self.gotify_client.listener.running:
self.gotify_client.listener.reset_wait_time() self.gotify_client.listener.reset_wait_time()
@@ -239,7 +274,8 @@ class MainWindow(QtWidgets.QMainWindow):
if isinstance(item, ApplicationModelItem): if isinstance(item, ApplicationModelItem):
self.delete_application_messages_task = DeleteApplicationMessagesTask( self.delete_application_messages_task = DeleteApplicationMessagesTask(
item.application.id, self.gotify_client item.data(ApplicationItemDataRole.ApplicationRole).id,
self.gotify_client,
) )
self.delete_application_messages_task.start() self.delete_application_messages_task.start()
elif isinstance(item, ApplicationAllMessagesItem): elif isinstance(item, ApplicationAllMessagesItem):
@@ -254,13 +290,14 @@ class MainWindow(QtWidgets.QMainWindow):
logger.error( logger.error(
f"MainWindow.new_message_callback: App id {message.appid} could not be found. Refreshing applications." f"MainWindow.new_message_callback: App id {message.appid} could not be found. Refreshing applications."
) )
self.application_model.save_order()
self.refresh_applications() self.refresh_applications()
return return
if not self.isActiveWindow() and message.priority >= settings.value( if not self.isActiveWindow() and message.priority >= settings.value(
"tray/notifications/priority", type=int "tray/notifications/priority", type=int
): ):
image_url = f"{self.gotify_client.url}/{application_item.application.image}" image_url = f"{self.gotify_client.url}/{application_item.data(ApplicationItemDataRole.ApplicationRole).image}"
self.tray.showMessage( self.tray.showMessage(
message.title, message.title,
message.message, message.message,
@@ -279,17 +316,30 @@ class MainWindow(QtWidgets.QMainWindow):
): ):
if isinstance(selected_application_item, ApplicationModelItem): if isinstance(selected_application_item, ApplicationModelItem):
# A single application is selected # A single application is selected
if message.appid == selected_application_item.application.id: if (
self.insert_message(0, message, application_item.application) message.appid
== selected_application_item.data(
ApplicationItemDataRole.ApplicationRole
).id
):
self.insert_message(
0,
message,
application_item.data(ApplicationItemDataRole.ApplicationRole),
)
elif isinstance(selected_application_item, ApplicationAllMessagesItem): elif isinstance(selected_application_item, ApplicationAllMessagesItem):
# "All messages' is selected # "All messages' is selected
self.insert_message(0, message, application_item.application) self.insert_message(
0,
message,
application_item.data(ApplicationItemDataRole.ApplicationRole),
)
def message_deletion_requested_callback(self, message_item: MessagesModelItem): def message_deletion_requested_callback(self, message_item: MessagesModelItem):
self.messages_model.removeRow(message_item.row())
self.delete_message_task = DeleteMessageTask( self.delete_message_task = DeleteMessageTask(
message_item.message.id, self.gotify_client message_item.data(MessageItemDataRole.MessageRole).id, self.gotify_client
) )
self.messages_model.removeRow(message_item.row())
self.delete_message_task.start() self.delete_message_task.start()
def tray_activated_callback( def tray_activated_callback(
@@ -392,6 +442,7 @@ class MainWindow(QtWidgets.QMainWindow):
def closeEvent(self, e: QtGui.QCloseEvent) -> None: def closeEvent(self, e: QtGui.QCloseEvent) -> None:
self.save_window_state() self.save_window_state()
self.application_model.save_order()
if settings.value("tray/show", type=bool): if settings.value("tray/show", type=bool):
self.tray.hide() self.tray.hide()

View File

@@ -2,7 +2,7 @@ import re
from PyQt6 import QtCore, QtGui, QtWidgets from PyQt6 import QtCore, QtGui, QtWidgets
from .MessagesModel import MessagesModelItem from .MessagesModel import MessageItemDataRole, MessagesModelItem
from .designs.widget_message import Ui_Form from .designs.widget_message import Ui_Form
from gotify_tray.database import Settings from gotify_tray.database import Settings
@@ -36,7 +36,7 @@ class MessageWidget(QtWidgets.QWidget, Ui_Form):
self.setAutoFillBackground(True) self.setAutoFillBackground(True)
self.message_item = message_item self.message_item = message_item
message = self.message_item.message message = message_item.data(MessageItemDataRole.MessageRole)
# Fonts # Fonts
font_title = QtGui.QFont() font_title = QtGui.QFont()

View File

@@ -1,12 +1,18 @@
import enum
from typing import cast from typing import cast
from PyQt6 import QtCore, QtGui, QtWidgets from PyQt6 import QtCore, QtGui, QtWidgets
from gotify_tray import gotify from gotify_tray import gotify
class MessageItemDataRole(enum.IntEnum):
MessageRole = QtCore.Qt.ItemDataRole.UserRole + 1
class MessagesModelItem(QtGui.QStandardItem): class MessagesModelItem(QtGui.QStandardItem):
def __init__(self, message: gotify.GotifyMessageModel, *args, **kwargs): def __init__(self, message: gotify.GotifyMessageModel, *args, **kwargs):
super(MessagesModelItem, self).__init__() super(MessagesModelItem, self).__init__()
self.message = message self.setData(message, MessageItemDataRole.MessageRole)
class MessagesModel(QtGui.QStandardItemModel): class MessagesModel(QtGui.QStandardItemModel):

View File

@@ -25,6 +25,8 @@ class Ui_Form(object):
font.setPointSize(13) font.setPointSize(13)
self.listView_applications.setFont(font) self.listView_applications.setFont(font)
self.listView_applications.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers) self.listView_applications.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
self.listView_applications.setDragEnabled(True)
self.listView_applications.setDragDropMode(QtWidgets.QAbstractItemView.DragDropMode.InternalMove)
self.listView_applications.setWordWrap(True) self.listView_applications.setWordWrap(True)
self.listView_applications.setObjectName("listView_applications") self.listView_applications.setObjectName("listView_applications")
self.gridLayout_2.addWidget(self.listView_applications, 0, 0, 1, 1) self.gridLayout_2.addWidget(self.listView_applications, 0, 0, 1, 1)
@@ -45,6 +47,7 @@ class Ui_Form(object):
font.setPointSize(15) font.setPointSize(15)
font.setBold(True) font.setBold(True)
self.label_selected.setFont(font) self.label_selected.setFont(font)
self.label_selected.setText("")
self.label_selected.setObjectName("label_selected") self.label_selected.setObjectName("label_selected")
self.gridLayout.addWidget(self.label_selected, 0, 2, 1, 1) self.gridLayout.addWidget(self.label_selected, 0, 2, 1, 1)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
@@ -81,7 +84,6 @@ class Ui_Form(object):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form")) Form.setWindowTitle(_translate("Form", "Form"))
self.pb_delete_all.setText(_translate("Form", "Delete All")) self.pb_delete_all.setText(_translate("Form", "Delete All"))
self.label_selected.setText(_translate("Form", "TextLabel"))
self.pb_refresh.setText(_translate("Form", "Refresh")) self.pb_refresh.setText(_translate("Form", "Refresh"))

View File

@@ -30,6 +30,12 @@
<property name="editTriggers"> <property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set> <set>QAbstractItemView::NoEditTriggers</set>
</property> </property>
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
</property> </property>
@@ -83,7 +89,7 @@
</font> </font>
</property> </property>
<property name="text"> <property name="text">
<string>TextLabel</string> <string/>
</property> </property>
</widget> </widget>
</item> </item>