diff --git a/gotify_tray/database/default_settings.py b/gotify_tray/database/default_settings.py index acc6935..4376c1b 100644 --- a/gotify_tray/database/default_settings.py +++ b/gotify_tray/database/default_settings.py @@ -1,14 +1,22 @@ +import os +from pathlib import Path + +from ..__version__ import __title__ + + DEFAULT_SETTINGS = { "message/check_missed/notify": True, - "message/last_id": 0, "logging/level": "Disabled", + "export/path": os.path.join( + Path.home(), f"{__title__.replace(' ', '-').lower()}-settings.bytes" + ), "shortcuts/quit": "Ctrl+Q", "tray/notifications/priority": 5, "tray/notifications/duration_ms": 5000, "tray/notifications/icon/show": True, "watchdog/interval/s": 60, "MessageWidget/image/size": 33, - "MessageWidget/font/title": "Noto Sans,17,-1,5,75,0,0,0,0,0,Bold", + "MessageWidget/font/title": "Noto Sans,12,-1,5,75,0,0,0,0,0,Bold", "MessageWidget/font/date": "Noto Sans,11,-1,5,50,1,0,0,0,0,Italic", "MessageWidget/font/message": "Noto Sans,11,-1,5,50,0,0,0,0,0,Regular", "ApplicationItem/font": "Noto Sans,10,-1,5,50,0,0,0,0,0,Regular", diff --git a/gotify_tray/database/settings.py b/gotify_tray/database/settings.py index a14e474..27eb5da 100644 --- a/gotify_tray/database/settings.py +++ b/gotify_tray/database/settings.py @@ -1,3 +1,4 @@ +import pickle from typing import Any from .default_settings import DEFAULT_SETTINGS @@ -8,6 +9,33 @@ from PyQt6 import QtCore class Settings(QtCore.QSettings): def value(self, key: str, defaultValue: Any = None, type: Any = None) -> Any: if type: - return super().value(key, defaultValue=defaultValue or DEFAULT_SETTINGS.get(key), type=type) + return super().value( + key, defaultValue=defaultValue or DEFAULT_SETTINGS.get(key), type=type + ) else: - return super().value(key, defaultValue=defaultValue or DEFAULT_SETTINGS.get(key)) + return super().value( + key, defaultValue=defaultValue or DEFAULT_SETTINGS.get(key) + ) + + def export(self, path: str): + data = { + key: self.value(key) + for key in self.allKeys() + if not ( # skip settings that might not translate well between platforms + isinstance(self.value(key), QtCore.QByteArray) + or key == "export/path" + or key == "message/last" + ) + } + + with open(path, "wb") as f: + pickle.dump(data, f) + + def load(self, path: str): + with open(path, "rb") as f: + data = pickle.load(f) + + self.clear() + + for key in data: + self.setValue(key, data[key]) diff --git a/gotify_tray/gui/MainApplication.py b/gotify_tray/gui/MainApplication.py index d2329a1..d8a626b 100644 --- a/gotify_tray/gui/MainApplication.py +++ b/gotify_tray/gui/MainApplication.py @@ -127,8 +127,8 @@ class MainApplication(QtWidgets.QApplication): ) def update_last_id(self, i: int): - if i > settings.value("message/last_id", type=int): - settings.setValue("message/last_id", i) + if i > settings.value("message/last", type=int): + settings.setValue("message/last", i) def listener_opened_callback(self): self.main_window.set_active() @@ -140,7 +140,7 @@ class MainApplication(QtWidgets.QApplication): return def get_missed_messages_callback(page: gotify.GotifyPagedMessagesModel): - last_id = settings.value("message/last_id", type=int) + last_id = settings.value("message/last", type=int) ids = [] page.messages.reverse() @@ -315,6 +315,7 @@ class MainApplication(QtWidgets.QApplication): def settings_callback(self): settings_dialog = SettingsDialog() + settings_dialog.quit_requested.connect(self.quit) accepted = settings_dialog.exec() if accepted and settings_dialog.settings_changed: diff --git a/gotify_tray/gui/designs/widget_message.py b/gotify_tray/gui/designs/widget_message.py index 2001a89..8c2c14f 100644 --- a/gotify_tray/gui/designs/widget_message.py +++ b/gotify_tray/gui/designs/widget_message.py @@ -12,7 +12,7 @@ from PyQt6 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): Form.setObjectName("Form") - Form.resize(454, 122) + Form.resize(454, 90) self.gridLayout = QtWidgets.QGridLayout(Form) self.gridLayout.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetMinimumSize) self.gridLayout.setContentsMargins(0, 0, 0, 0) @@ -25,8 +25,15 @@ class Ui_Form(object): self.gridLayout_frame.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetMinimumSize) self.gridLayout_frame.setContentsMargins(-1, 0, -1, 0) self.gridLayout_frame.setObjectName("gridLayout_frame") + self.pb_delete = QtWidgets.QPushButton(self.frame) + self.pb_delete.setText("") + self.pb_delete.setFlat(True) + self.pb_delete.setObjectName("pb_delete") + self.gridLayout_frame.addWidget(self.pb_delete, 0, 4, 1, 1) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Maximum, QtWidgets.QSizePolicy.Policy.Minimum) + self.gridLayout_frame.addItem(spacerItem, 0, 2, 1, 1) self.label_title = QtWidgets.QLabel(self.frame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Minimum) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.label_title.sizePolicy().hasHeightForWidth()) @@ -36,9 +43,14 @@ class Ui_Form(object): font.setBold(False) font.setWeight(50) self.label_title.setFont(font) + self.label_title.setWordWrap(True) self.label_title.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_title.setObjectName("label_title") self.gridLayout_frame.addWidget(self.label_title, 0, 1, 1, 1) + self.label_image = QtWidgets.QLabel(self.frame) + self.label_image.setText("") + self.label_image.setObjectName("label_image") + self.gridLayout_frame.addWidget(self.label_image, 0, 0, 1, 1) self.label_message = QtWidgets.QLabel(self.frame) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.MinimumExpanding) sizePolicy.setHorizontalStretch(0) @@ -52,25 +64,14 @@ class Ui_Form(object): self.label_message.setOpenExternalLinks(True) self.label_message.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_message.setObjectName("label_message") - self.gridLayout_frame.addWidget(self.label_message, 3, 1, 1, 3) + self.gridLayout_frame.addWidget(self.label_message, 3, 1, 1, 4) self.label_date = QtWidgets.QLabel(self.frame) font = QtGui.QFont() font.setPointSize(11) self.label_date.setFont(font) self.label_date.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse) self.label_date.setObjectName("label_date") - self.gridLayout_frame.addWidget(self.label_date, 2, 1, 1, 1) - self.pb_delete = QtWidgets.QPushButton(self.frame) - self.pb_delete.setText("") - self.pb_delete.setFlat(True) - self.pb_delete.setObjectName("pb_delete") - self.gridLayout_frame.addWidget(self.pb_delete, 0, 3, 1, 1) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - self.gridLayout_frame.addItem(spacerItem, 0, 2, 1, 1) - self.label_image = QtWidgets.QLabel(self.frame) - self.label_image.setText("") - self.label_image.setObjectName("label_image") - self.gridLayout_frame.addWidget(self.label_image, 0, 0, 1, 1) + self.gridLayout_frame.addWidget(self.label_date, 0, 3, 1, 1) self.gridLayout.addWidget(self.frame, 0, 0, 1, 1) self.retranslateUi(Form) diff --git a/gotify_tray/gui/designs/widget_message.ui b/gotify_tray/gui/designs/widget_message.ui index a2ba26d..74d453b 100644 --- a/gotify_tray/gui/designs/widget_message.ui +++ b/gotify_tray/gui/designs/widget_message.ui @@ -7,7 +7,7 @@ 0 0 454 - 122 + 90 @@ -47,10 +47,36 @@ 0 + + + + + + + true + + + + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 40 + 20 + + + + - + 0 0 @@ -65,12 +91,22 @@ Title + + true + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - + + + + + + + + @@ -97,7 +133,7 @@ - + @@ -112,36 +148,6 @@ - - - - - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - diff --git a/gotify_tray/gui/designs/widget_server.py b/gotify_tray/gui/designs/widget_server.py index faab5ea..d58e3b7 100644 --- a/gotify_tray/gui/designs/widget_server.py +++ b/gotify_tray/gui/designs/widget_server.py @@ -15,9 +15,10 @@ class Ui_Dialog(object): Dialog.resize(300, 130) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") - self.pb_test = QtWidgets.QPushButton(Dialog) - self.pb_test.setObjectName("pb_test") - self.gridLayout.addWidget(self.pb_test, 1, 4, 1, 1) + self.label_server_info = QtWidgets.QLabel(Dialog) + self.label_server_info.setText("") + self.label_server_info.setObjectName("label_server_info") + self.gridLayout.addWidget(self.label_server_info, 1, 1, 1, 2) self.formLayout = QtWidgets.QFormLayout() self.formLayout.setObjectName("formLayout") self.label = QtWidgets.QLabel(Dialog) @@ -32,30 +33,35 @@ class Ui_Dialog(object): self.line_token = QtWidgets.QLineEdit(Dialog) self.line_token.setObjectName("line_token") self.formLayout.setWidget(1, QtWidgets.QFormLayout.ItemRole.FieldRole, self.line_token) - self.gridLayout.addLayout(self.formLayout, 0, 1, 1, 4) + self.gridLayout.addLayout(self.formLayout, 0, 1, 1, 5) + self.pb_test = QtWidgets.QPushButton(Dialog) + self.pb_test.setObjectName("pb_test") + self.gridLayout.addWidget(self.pb_test, 1, 5, 1, 1) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") - self.gridLayout.addWidget(self.buttonBox, 2, 4, 1, 1) + self.gridLayout.addWidget(self.buttonBox, 2, 5, 1, 1) spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.gridLayout.addItem(spacerItem, 1, 3, 1, 1) - self.label_server_info = QtWidgets.QLabel(Dialog) - self.label_server_info.setText("") - self.label_server_info.setObjectName("label_server_info") - self.gridLayout.addWidget(self.label_server_info, 1, 1, 1, 2) + self.pb_import = QtWidgets.QPushButton(Dialog) + self.pb_import.setMaximumSize(QtCore.QSize(30, 16777215)) + self.pb_import.setObjectName("pb_import") + self.gridLayout.addWidget(self.pb_import, 1, 4, 1, 1) self.retranslateUi(Dialog) - self.buttonBox.accepted.connect(Dialog.accept) - self.buttonBox.rejected.connect(Dialog.reject) + self.buttonBox.accepted.connect(Dialog.accept) # type: ignore + self.buttonBox.rejected.connect(Dialog.reject) # type: ignore QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Dialog")) - self.pb_test.setText(_translate("Dialog", "Test")) self.label.setText(_translate("Dialog", "Server url:")) self.label_2.setText(_translate("Dialog", "Client token:")) + self.pb_test.setText(_translate("Dialog", "Test")) + self.pb_import.setToolTip(_translate("Dialog", "Import settings")) + self.pb_import.setText(_translate("Dialog", "...")) if __name__ == "__main__": diff --git a/gotify_tray/gui/designs/widget_server.ui b/gotify_tray/gui/designs/widget_server.ui index 547e08e..64cf6ec 100644 --- a/gotify_tray/gui/designs/widget_server.ui +++ b/gotify_tray/gui/designs/widget_server.ui @@ -14,14 +14,14 @@ Dialog - - + + - Test + - + @@ -45,7 +45,14 @@ - + + + + Test + + + + Qt::Horizontal @@ -68,10 +75,19 @@ - - + + + + + 30 + 16777215 + + + + Import settings + - + ... diff --git a/gotify_tray/gui/designs/widget_settings.py b/gotify_tray/gui/designs/widget_settings.py index 310a6ab..633c1b8 100644 --- a/gotify_tray/gui/designs/widget_settings.py +++ b/gotify_tray/gui/designs/widget_settings.py @@ -12,16 +12,12 @@ from PyQt6 import QtCore, QtGui, QtWidgets class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") - Dialog.resize(384, 391) + Dialog.resize(384, 274) self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout.setObjectName("gridLayout") self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal) - self.buttonBox.setStandardButtons( - QtWidgets.QDialogButtonBox.StandardButton.Apply - | QtWidgets.QDialogButtonBox.StandardButton.Cancel - | QtWidgets.QDialogButtonBox.StandardButton.Ok - ) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Apply|QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 1) self.tabWidget = QtWidgets.QTabWidget(Dialog) @@ -34,12 +30,7 @@ class Ui_Dialog(object): self.groupBox_5.setObjectName("groupBox_5") self.gridLayout_4 = QtWidgets.QGridLayout(self.groupBox_5) self.gridLayout_4.setObjectName("gridLayout_4") - spacerItem = QtWidgets.QSpacerItem( - 40, - 20, - QtWidgets.QSizePolicy.Policy.Expanding, - QtWidgets.QSizePolicy.Policy.Minimum, - ) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) self.gridLayout_4.addItem(spacerItem, 0, 2, 1, 1) self.label_6 = QtWidgets.QLabel(self.groupBox_5) self.label_6.setObjectName("label_6") @@ -73,43 +64,11 @@ class Ui_Dialog(object): self.pb_change_server_info = QtWidgets.QPushButton(self.groupBox_4) self.pb_change_server_info.setObjectName("pb_change_server_info") self.gridLayout_3.addWidget(self.pb_change_server_info, 0, 0, 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) self.gridLayout_3.addItem(spacerItem1, 0, 1, 1, 1) self.verticalLayout_4.addWidget(self.groupBox_4) - self.groupBox_7 = QtWidgets.QGroupBox(self.tab_general) - self.groupBox_7.setObjectName("groupBox_7") - self.gridLayout_6 = QtWidgets.QGridLayout(self.groupBox_7) - self.gridLayout_6.setObjectName("gridLayout_6") - self.label_7 = QtWidgets.QLabel(self.groupBox_7) - self.label_7.setObjectName("label_7") - self.gridLayout_6.addWidget(self.label_7, 0, 0, 1, 1) - self.combo_logging = QtWidgets.QComboBox(self.groupBox_7) - self.combo_logging.setObjectName("combo_logging") - self.gridLayout_6.addWidget(self.combo_logging, 0, 1, 1, 1) - self.pb_open_log = QtWidgets.QPushButton(self.groupBox_7) - self.pb_open_log.setMaximumSize(QtCore.QSize(30, 16777215)) - self.pb_open_log.setObjectName("pb_open_log") - self.gridLayout_6.addWidget(self.pb_open_log, 0, 2, 1, 1) - spacerItem2 = QtWidgets.QSpacerItem( - 190, - 20, - QtWidgets.QSizePolicy.Policy.Expanding, - QtWidgets.QSizePolicy.Policy.Minimum, - ) - self.gridLayout_6.addItem(spacerItem2, 0, 3, 1, 1) - self.verticalLayout_4.addWidget(self.groupBox_7) - spacerItem3 = QtWidgets.QSpacerItem( - 20, - 40, - QtWidgets.QSizePolicy.Policy.Minimum, - QtWidgets.QSizePolicy.Policy.Expanding, - ) - self.verticalLayout_4.addItem(spacerItem3) + spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_4.addItem(spacerItem2) self.tabWidget.addTab(self.tab_general, "") self.tab_fonts = QtWidgets.QWidget() self.tab_fonts.setObjectName("tab_fonts") @@ -134,28 +93,59 @@ class Ui_Dialog(object): self.horizontalLayout.addWidget(self.pb_font_message_content) self.layout_fonts_message.addLayout(self.horizontalLayout) self.verticalLayout_5.addWidget(self.groupBox_2) - spacerItem4 = QtWidgets.QSpacerItem( - 20, - 40, - QtWidgets.QSizePolicy.Policy.Minimum, - QtWidgets.QSizePolicy.Policy.Expanding, - ) - self.verticalLayout_5.addItem(spacerItem4) + spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout_5.addItem(spacerItem3) self.tabWidget.addTab(self.tab_fonts, "") + self.tab_advanced = QtWidgets.QWidget() + self.tab_advanced.setObjectName("tab_advanced") + self.verticalLayout = QtWidgets.QVBoxLayout(self.tab_advanced) + self.verticalLayout.setObjectName("verticalLayout") + self.groupBox = QtWidgets.QGroupBox(self.tab_advanced) + self.groupBox.setObjectName("groupBox") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.pb_export = QtWidgets.QPushButton(self.groupBox) + self.pb_export.setObjectName("pb_export") + self.verticalLayout_2.addWidget(self.pb_export) + self.pb_import = QtWidgets.QPushButton(self.groupBox) + self.pb_import.setObjectName("pb_import") + self.verticalLayout_2.addWidget(self.pb_import) + self.pb_reset = QtWidgets.QPushButton(self.groupBox) + self.pb_reset.setObjectName("pb_reset") + self.verticalLayout_2.addWidget(self.pb_reset) + self.verticalLayout.addWidget(self.groupBox) + self.groupBox_7 = QtWidgets.QGroupBox(self.tab_advanced) + self.groupBox_7.setObjectName("groupBox_7") + self.gridLayout_6 = QtWidgets.QGridLayout(self.groupBox_7) + self.gridLayout_6.setObjectName("gridLayout_6") + self.label_7 = QtWidgets.QLabel(self.groupBox_7) + self.label_7.setObjectName("label_7") + self.gridLayout_6.addWidget(self.label_7, 0, 0, 1, 1) + self.combo_logging = QtWidgets.QComboBox(self.groupBox_7) + self.combo_logging.setObjectName("combo_logging") + self.gridLayout_6.addWidget(self.combo_logging, 0, 1, 1, 1) + self.pb_open_log = QtWidgets.QPushButton(self.groupBox_7) + self.pb_open_log.setMaximumSize(QtCore.QSize(30, 16777215)) + self.pb_open_log.setObjectName("pb_open_log") + self.gridLayout_6.addWidget(self.pb_open_log, 0, 2, 1, 1) + spacerItem4 = QtWidgets.QSpacerItem(190, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.gridLayout_6.addItem(spacerItem4, 0, 3, 1, 1) + self.verticalLayout.addWidget(self.groupBox_7) + spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) + self.verticalLayout.addItem(spacerItem5) + self.tabWidget.addTab(self.tab_advanced, "") self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1) self.retranslateUi(Dialog) self.tabWidget.setCurrentIndex(0) - self.buttonBox.accepted.connect(Dialog.accept) - self.buttonBox.rejected.connect(Dialog.reject) + self.buttonBox.accepted.connect(Dialog.accept) # type: ignore + self.buttonBox.rejected.connect(Dialog.reject) # type: ignore QtCore.QMetaObject.connectSlotsByName(Dialog) Dialog.setTabOrder(self.tabWidget, self.spin_priority) Dialog.setTabOrder(self.spin_priority, self.spin_duration) Dialog.setTabOrder(self.spin_duration, self.cb_notify) Dialog.setTabOrder(self.cb_notify, self.pb_change_server_info) - Dialog.setTabOrder(self.pb_change_server_info, self.combo_logging) - Dialog.setTabOrder(self.combo_logging, self.pb_open_log) - Dialog.setTabOrder(self.pb_open_log, self.pb_font_message_title) + Dialog.setTabOrder(self.pb_change_server_info, self.pb_font_message_title) Dialog.setTabOrder(self.pb_font_message_title, self.pb_font_message_date) Dialog.setTabOrder(self.pb_font_message_date, self.pb_font_message_content) @@ -164,37 +154,30 @@ class Ui_Dialog(object): Dialog.setWindowTitle(_translate("Dialog", "Dialog")) self.groupBox_5.setTitle(_translate("Dialog", "Notifications")) self.label_6.setText(_translate("Dialog", "ms")) - self.label_4.setText( - _translate("Dialog", "Minimum priority to show notifications:") - ) + self.label_4.setText(_translate("Dialog", "Minimum priority to show notifications:")) self.label_5.setText(_translate("Dialog", "Notification duration:")) - self.cb_notify.setText( - _translate( - "Dialog", - "Show a notification for missed messages after reconnecting", - ) - ) + self.cb_notify.setText(_translate("Dialog", "Show a notification for missed messages after reconnecting")) self.groupBox_4.setTitle(_translate("Dialog", "Server info")) self.pb_change_server_info.setText(_translate("Dialog", "Change server info")) - self.groupBox_7.setTitle(_translate("Dialog", "Logging")) - self.label_7.setText(_translate("Dialog", "Level")) - self.pb_open_log.setToolTip(_translate("Dialog", "Open logfile")) - self.pb_open_log.setText(_translate("Dialog", "...")) - self.tabWidget.setTabText( - self.tabWidget.indexOf(self.tab_general), _translate("Dialog", "General") - ) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_general), _translate("Dialog", "General")) self.groupBox_2.setTitle(_translate("Dialog", "Message")) self.pb_font_message_title.setText(_translate("Dialog", "Title")) self.pb_font_message_date.setText(_translate("Dialog", "Date")) self.pb_font_message_content.setText(_translate("Dialog", "Message")) - self.tabWidget.setTabText( - self.tabWidget.indexOf(self.tab_fonts), _translate("Dialog", "Fonts") - ) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_fonts), _translate("Dialog", "Fonts")) + self.groupBox.setTitle(_translate("Dialog", "Settings")) + self.pb_export.setText(_translate("Dialog", "Export")) + self.pb_import.setText(_translate("Dialog", "Import")) + self.pb_reset.setText(_translate("Dialog", "Reset")) + self.groupBox_7.setTitle(_translate("Dialog", "Logging")) + self.label_7.setText(_translate("Dialog", "Level")) + self.pb_open_log.setToolTip(_translate("Dialog", "Open logfile")) + self.pb_open_log.setText(_translate("Dialog", "...")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_advanced), _translate("Dialog", "Advanced")) if __name__ == "__main__": import sys - app = QtWidgets.QApplication(sys.argv) Dialog = QtWidgets.QDialog() ui = Ui_Dialog() diff --git a/gotify_tray/gui/designs/widget_settings.ui b/gotify_tray/gui/designs/widget_settings.ui index cda48fe..003949e 100644 --- a/gotify_tray/gui/designs/widget_settings.ui +++ b/gotify_tray/gui/designs/widget_settings.ui @@ -7,7 +7,7 @@ 0 0 384 - 391 + 274 @@ -139,54 +139,6 @@ - - - - Logging - - - - - - Level - - - - - - - - - - - 30 - 16777215 - - - - Open logfile - - - ... - - - - - - - Qt::Horizontal - - - - 190 - 20 - - - - - - - @@ -271,6 +223,104 @@ + + + Advanced + + + + + + Settings + + + + + + Export + + + + + + + Import + + + + + + + Reset + + + + + + + + + + Logging + + + + + + Level + + + + + + + + + + + 30 + 16777215 + + + + Open logfile + + + ... + + + + + + + Qt::Horizontal + + + + 190 + 20 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + @@ -281,8 +331,6 @@ spin_duration cb_notify pb_change_server_info - combo_logging - pb_open_log pb_font_message_title pb_font_message_date pb_font_message_content diff --git a/gotify_tray/gui/widgets/MainWindow.py b/gotify_tray/gui/widgets/MainWindow.py index c0294cf..b76edd1 100644 --- a/gotify_tray/gui/widgets/MainWindow.py +++ b/gotify_tray/gui/widgets/MainWindow.py @@ -40,6 +40,9 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): self.splitter.setStretchFactor(0, 0) self.splitter.setStretchFactor(1, 1) + # Do not collapse the message list + self.splitter.setCollapsible(1, False) + self.status_widget = StatusWidget() self.horizontalLayout.insertWidget(0, self.status_widget) diff --git a/gotify_tray/gui/widgets/MessageWidget.py b/gotify_tray/gui/widgets/MessageWidget.py index 4ee0e64..8e737f9 100644 --- a/gotify_tray/gui/widgets/MessageWidget.py +++ b/gotify_tray/gui/widgets/MessageWidget.py @@ -37,35 +37,44 @@ class MessageWidget(QtWidgets.QWidget, Ui_Form): self.label_title.setText(message.title) self.label_date.setText(message.date.strftime("%Y-%m-%d, %H:%M")) - if markdown := message.get("extras", {}).get("client::display", {}).get("contentType") == "text/markdown": + if ( + markdown := message.get("extras", {}) + .get("client::display", {}) + .get("contentType") + ) == "text/markdown": self.label_message.setTextFormat(QtCore.Qt.TextFormat.MarkdownText) + self.label_message.setText(convert_links(message.message)) # Show the application icon if image_path: image_size = settings.value("MessageWidget/image/size", type=int) self.label_image.setFixedSize(QtCore.QSize(image_size, image_size)) - pixmap = QtGui.QPixmap(image_path).scaled(image_size, image_size, aspectRatioMode=QtCore.Qt.AspectRatioMode.KeepAspectRatioByExpanding) + pixmap = QtGui.QPixmap(image_path).scaled( + image_size, + image_size, + aspectRatioMode=QtCore.Qt.AspectRatioMode.KeepAspectRatioByExpanding, + transformMode=QtCore.Qt.TransformationMode.SmoothTransformation, + ) self.label_image.setPixmap(pixmap) else: self.label_image.hide() # Set MessagesModelItem's size hint based on the size of this widget - self.gridLayout_frame.setContentsMargins(10, 5, 10, 5) - self.gridLayout.setContentsMargins(5, 15, 5, 15) + self.gridLayout_frame.setContentsMargins(5, 5, 5, 5) + self.gridLayout.setContentsMargins(4, 5, 4, 0) self.adjustSize() size_hint = self.message_item.sizeHint() - self.message_item.setSizeHint( - QtCore.QSize( - size_hint.width(), - self.height() - ) + self.message_item.setSizeHint(QtCore.QSize(size_hint.width(), self.height())) + + self.pb_delete.setIcon( + QtGui.QIcon(get_abs_path("gotify_tray/gui/images/trashcan.svg")) ) - - self.pb_delete.setIcon(QtGui.QIcon(get_abs_path("gotify_tray/gui/images/trashcan.svg"))) self.pb_delete.setIconSize(QtCore.QSize(24, 24)) self.link_callbacks() def link_callbacks(self): - self.pb_delete.clicked.connect(lambda: self.deletion_requested.emit(self.message_item)) \ No newline at end of file + self.pb_delete.clicked.connect( + lambda: self.deletion_requested.emit(self.message_item) + ) diff --git a/gotify_tray/gui/widgets/ServerInfoDialog.py b/gotify_tray/gui/widgets/ServerInfoDialog.py index 3c30ac3..9c74d16 100644 --- a/gotify_tray/gui/widgets/ServerInfoDialog.py +++ b/gotify_tray/gui/widgets/ServerInfoDialog.py @@ -1,12 +1,18 @@ +import os + +from gotify_tray.database import Settings from gotify_tray.gotify.models import GotifyVersionModel -from gotify_tray.tasks import VerifyServerInfoTask +from gotify_tray.tasks import ImportSettingsTask, VerifyServerInfoTask from PyQt6 import QtWidgets from ..designs.widget_server import Ui_Dialog +settings = Settings("gotify-tray") + + class ServerInfoDialog(QtWidgets.QDialog, Ui_Dialog): - def __init__(self, url: str = "", token: str = ""): + def __init__(self, url: str = "", token: str = "", enable_import: bool = True): super(ServerInfoDialog, self).__init__() self.setupUi(self) self.setWindowTitle("Server info") @@ -16,6 +22,7 @@ class ServerInfoDialog(QtWidgets.QDialog, Ui_Dialog): self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Ok).setDisabled( True ) + self.pb_import.setVisible(enable_import) self.link_callbacks() def test_server_info(self): @@ -60,6 +67,19 @@ class ServerInfoDialog(QtWidgets.QDialog, Ui_Dialog): self.pb_test.setStyleSheet("background-color: rgba(255, 0, 0, 100);") self.line_url.setStyleSheet("border: 1px solid red;") + def import_success_callback(self): + self.line_url.setText(settings.value("Server/url", type=str)) + self.line_token.setText(settings.value("Server/client_token")) + + def import_callback(self): + fname = QtWidgets.QFileDialog.getOpenFileName( + self, "Import Settings", settings.value("export/path", type=str), "*", + )[0] + if fname and os.path.exists(fname): + self.import_settings_task = ImportSettingsTask(fname) + self.import_settings_task.success.connect(self.import_success_callback) + self.import_settings_task.start() + def link_callbacks(self): self.pb_test.clicked.connect(self.test_server_info) self.line_url.textChanged.connect( @@ -72,3 +92,4 @@ class ServerInfoDialog(QtWidgets.QDialog, Ui_Dialog): QtWidgets.QDialogButtonBox.StandardButton.Ok ).setDisabled(True) ) + self.pb_import.clicked.connect(self.import_callback) diff --git a/gotify_tray/gui/widgets/SettingsDialog.py b/gotify_tray/gui/widgets/SettingsDialog.py index b1f08c1..652ff62 100644 --- a/gotify_tray/gui/widgets/SettingsDialog.py +++ b/gotify_tray/gui/widgets/SettingsDialog.py @@ -1,4 +1,5 @@ import logging +import os import webbrowser from gotify_tray.database import Settings @@ -6,6 +7,7 @@ from gotify_tray.gotify import GotifyMessageModel from gotify_tray.gui.models import MessagesModelItem from . import MessageWidget from gotify_tray.utils import verify_server +from gotify_tray.tasks import ExportSettingsTask, ImportSettingsTask from PyQt6 import QtCore, QtGui, QtWidgets from ..designs.widget_settings import Ui_Dialog @@ -16,6 +18,8 @@ settings = Settings("gotify-tray") class SettingsDialog(QtWidgets.QDialog, Ui_Dialog): + quit_requested = QtCore.pyqtSignal() + def __init__(self): super(SettingsDialog, self).__init__() self.setupUi(self) @@ -74,7 +78,7 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog): self.layout_fonts_message.addWidget(self.message_widget) def change_server_info_callback(self): - self.server_changed = verify_server(force_new=True) + self.server_changed = verify_server(force_new=True, enable_import=False) def settings_changed_callback(self, *args, **kwargs): self.settings_changed = True @@ -93,6 +97,44 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog): self.settings_changed_callback() label.setFont(font) + def export_callback(self): + fname = QtWidgets.QFileDialog.getSaveFileName( + self, "Export Settings", settings.value("export/path", type=str), "*", + )[0] + if fname and os.path.exists(os.path.dirname(fname)): + self.export_settings_task = ExportSettingsTask(fname) + self.export_settings_task.start() + settings.setValue("export/path", fname) + + def import_success_callback(self): + response = QtWidgets.QMessageBox.information( + self, "Restart to apply settings", "Restart to apply settings" + ) + if response == QtWidgets.QMessageBox.StandardButton.Ok: + self.quit_requested.emit() + + def import_callback(self): + fname = QtWidgets.QFileDialog.getOpenFileName( + self, "Import Settings", settings.value("export/path", type=str), "*", + )[0] + if fname and os.path.exists(fname): + self.import_settings_task = ImportSettingsTask(fname) + self.import_settings_task.success.connect(self.import_success_callback) + self.import_settings_task.start() + + def reset_callback(self): + response = QtWidgets.QMessageBox.warning( + self, + "Are you sure?", + "Reset all settings?", + QtWidgets.QMessageBox.StandardButton.Ok + | QtWidgets.QMessageBox.StandardButton.Cancel, + defaultButton=QtWidgets.QMessageBox.StandardButton.Cancel, + ) + if response == QtWidgets.QMessageBox.StandardButton.Ok: + settings.clear() + self.quit_requested.emit() + def link_callbacks(self): self.buttonBox.button( QtWidgets.QDialogButtonBox.StandardButton.Apply @@ -123,6 +165,11 @@ class SettingsDialog(QtWidgets.QDialog, Ui_Dialog): lambda: self.change_font_callback("message") ) + # Advanced + self.pb_export.clicked.connect(self.export_callback) + self.pb_import.clicked.connect(self.import_callback) + self.pb_reset.clicked.connect(self.reset_callback) + def apply_settings(self): # Priority settings.setValue("tray/notifications/priority", self.spin_priority.value()) diff --git a/gotify_tray/tasks.py b/gotify_tray/tasks.py index b74c81b..d8a821d 100644 --- a/gotify_tray/tasks.py +++ b/gotify_tray/tasks.py @@ -175,3 +175,27 @@ class ServerConnectionWatchdogTask(BaseTask): logger.debug( "ServerConnectionWatchdogTask: gotify_client is not listening" ) + + +class ExportSettingsTask(BaseTask): + success = pyqtSignal() + + def __init__(self, path: str): + super(ExportSettingsTask, self).__init__() + self.path = path + + def task(self): + settings.export(self.path) + self.success.emit() + + +class ImportSettingsTask(BaseTask): + success = pyqtSignal() + + def __init__(self, path: str): + super(ImportSettingsTask, self).__init__() + self.path = path + + def task(self): + settings.load(self.path) + self.success.emit() diff --git a/gotify_tray/utils.py b/gotify_tray/utils.py index 46935ef..dbcbb30 100644 --- a/gotify_tray/utils.py +++ b/gotify_tray/utils.py @@ -4,7 +4,7 @@ import re from pathlib import Path -def verify_server(force_new: bool = False) -> bool: +def verify_server(force_new: bool = False, enable_import: bool = True) -> bool: from gotify_tray.gui import ServerInfoDialog from gotify_tray.database import Settings @@ -14,7 +14,7 @@ def verify_server(force_new: bool = False) -> bool: token = settings.value("Server/client_token", type=str) if not url or not token or force_new: - dialog = ServerInfoDialog(url, token) + dialog = ServerInfoDialog(url, token, enable_import) if dialog.exec(): settings.setValue("Server/url", dialog.line_url.text()) settings.setValue("Server/client_token", dialog.line_token.text())