diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b1feea..b93d4af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## 0.12.x +### 0.12.0: New Settings Menu & Patches + +- **New Settings Window:** + - The updater window has been reworked into a settings window. + - **Initial settings (first tab) include:** + 1. Option to change the theme (with an optional dependency installation). + 2. Reset selectable EXIF data to default. + - The updater UI has been moved to the second tab. + - Added a link to the changelog for easier access to update details. + +- **Patches:** + - Fixed an issue where links in labels (About window) did not open a browser. + - Added a changelog link in the About window. + - Minor changes to `utility.py` to handle settings. +--- + ## 0.11.x ### 0.11.1: Fixed pipeline - Fixed pipeline publish error diff --git a/src/OptimaLab35/gui.py b/src/OptimaLab35/gui.py index 81b2ba6..5f9a54f 100644 --- a/src/OptimaLab35/gui.py +++ b/src/OptimaLab35/gui.py @@ -13,14 +13,14 @@ from optima35.core import OptimaManager from OptimaLab35.utils.utility import Utilities from OptimaLab35.ui.main_window import Ui_MainWindow from OptimaLab35.ui.preview_window import Ui_Preview_Window -from OptimaLab35.ui.updater_window import Ui_Updater_Window +from OptimaLab35.ui.settings_window import Ui_Settings_Window from OptimaLab35.ui.exif_handler_window import ExifEditor from OptimaLab35.ui.simple_dialog import SimpleDialog # Import the SimpleDialog class from OptimaLab35 import __version__ from PySide6.QtCore import QRunnable, QThreadPool, Signal, QObject, QRegularExpression, Qt, QTimer, Slot, QDir -from PySide6 import QtWidgets +from PySide6 import QtWidgets, QtCore from PySide6.QtWidgets import ( QMessageBox, QApplication, @@ -45,8 +45,10 @@ class OptimaLab35(QMainWindow, Ui_MainWindow): self.name = "OptimaLab35" self.version = __version__ self.o = OptimaManager() - self.u = Utilities() - self.u.program_configs() + self.u = Utilities(os.path.expanduser("~/.config/OptimaLab35")) + self.app_settings = self.u.load_settings() + print(self.app_settings) + self.thread_pool = QThreadPool() # multi thread ChatGPT # Initiate internal object self.exif_file = os.path.expanduser("~/.config/OptimaLab35/exif.yaml") @@ -98,7 +100,7 @@ class OptimaLab35(QMainWindow, Ui_MainWindow): self.ui.actionAbout.triggered.connect(self.info_window) self.ui.preview_Button.clicked.connect(self.open_preview_window) - self.ui.actionUpdate.triggered.connect(self.open_updater_window) + self.ui.actionSettings.triggered.connect(self.open_updater_window) regex = QRegularExpression(r"^\d{1,2}\.\d{1,6}$") validator = QRegularExpressionValidator(regex) @@ -114,7 +116,7 @@ class OptimaLab35(QMainWindow, Ui_MainWindow): self.preview_window.showMaximized() def open_updater_window(self): - self.updater_window = UpdaterWindow(self.version, self.o.version) + self.updater_window = SettingsWindow(self.version, self.o.version) self.updater_window.show() def update_values(self, value1, value2, checkbox_state): @@ -140,6 +142,7 @@ class OptimaLab35(QMainWindow, Ui_MainWindow):

For more details, visit:

@@ -486,14 +489,15 @@ class OptimaLab35(QMainWindow, Ui_MainWindow): QApplication.closeAllWindows() event.accept() -class UpdaterWindow(QMainWindow, Ui_Updater_Window): +class SettingsWindow(QMainWindow, Ui_Settings_Window): # Mixture of code by me, code/functions refactored by ChatGPT and code directly from ChatGPT def __init__(self, optimalab35_localversion, optima35_localversion): - super(UpdaterWindow, self).__init__() - self.ui = Ui_Updater_Window() + super(SettingsWindow, self).__init__() + self.ui = Ui_Settings_Window() self.ui.setupUi(self) + self.u = Utilities(os.path.expanduser("~/.config/OptimaLab35")) + self.app_settings = self.u.load_settings() self.dev_mode = True if optimalab35_localversion == "0.0.1" else False - #self.set_dev_ui() from PyPiUpdater import PyPiUpdater # Update log file location self.update_log_file = os.path.expanduser("~/.config/OptimaLab35/update_log.json") @@ -512,25 +516,9 @@ class UpdaterWindow(QMainWindow, Ui_Updater_Window): self.define_gui_interaction() - def start_long_press(self): - """Start the timer when button is pressed.""" - # brave AI - self.timer.start(1000) # 1-second long press - - def cancel_long_press(self): - """Cancel long press if released early.""" - # brave AI - self.timer.stop() - - def toggle_dev_ui(self): - """Show or hide the hidden UI when long press is detected.""" - self.ui.dev_widget.setVisible(True) - - self.ui.check_local_Button.clicked.connect(self.local_check_for_updates) - self.ui.update_local_Button.clicked.connect(self.local_update) - def define_gui_interaction(self): """Setup UI interactions.""" + # Updater related self.ui.label_optimalab35_localversion.setText(self.optimalab35_localversion) self.ui.label_optima35_localversion.setText(self.optima35_localversion) @@ -554,6 +542,115 @@ class UpdaterWindow(QMainWindow, Ui_Updater_Window): # Connect button press/release self.ui.check_for_update_Button.pressed.connect(self.start_long_press) self.ui.check_for_update_Button.released.connect(self.cancel_long_press) + self.ui.label_5.setText('
  • Changelog
  • ') + self.ui.label_5.setOpenExternalLinks(True) + #settings related + self.load_settings_into_ui() + self.ui.reset_exif_Button.clicked.connect(self.ask_reset_exif) + self.ui.save_and_close_Button.clicked.connect(self.save_and_close) + self.ui.save_and_restart_Button.clicked.connect(self.save_and_restart) +# setting related + + def load_settings_into_ui(self): + """Loads the settings into the UI elements.""" + settings = self.app_settings + theme_mode = settings["theme"]["mode"] + use_custom_theme = settings["theme"]["use_custom_theme"] + pkg_available = settings["theme"]["theme_pkg"] + + if pkg_available: + index = self.ui.theme_selection_comboBox.findText(theme_mode, QtCore.Qt.MatchFlag.MatchExactly) + if index != -1: + self.ui.theme_selection_comboBox.setCurrentIndex(index) + self.ui.enable_theme_checkBox.setChecked(use_custom_theme) + self.ui.install_pkg_Button.setVisible(False) + self.ui.enable_theme_checkBox.setEnabled(True) + else: + self.ui.enable_theme_checkBox.setEnabled(False) + self.ui.install_pkg_Button.clicked.connect(self.install_theme_pkg) + + + def install_theme_pkg(self): + a = self.ppu_ol35.install_package("PyQtDarkTheme-fork") + self.ui.install_pkg_Button.setEnabled(False) + self.ui.install_pkg_Button.setText("Please wait...") + + msg_box = QMessageBox() + msg_box.setIcon(QMessageBox.Information) + msg_box.setWindowTitle("Message") + msg_box.setText(a[1]) + msg_box.setStandardButtons(QMessageBox.Ok) + msg_box.exec() + if a[0]: + print("before", self.app_settings) + self.app_settings["theme"]["theme_pkg"] = True + print("After:::", self.app_settings) + self.load_settings_into_ui() + else: + self.ui.install_pkg_Button.setEnabled(True) + self.ui.install_pkg_Button.setText("Try again?") + + def save_settings(self): + self.app_settings["theme"]["mode"] = self.ui.theme_selection_comboBox.currentText() + self.app_settings["theme"]["use_custom_theme"] = self.ui.enable_theme_checkBox.isChecked() + self.u.save_settings(self.app_settings) + + def save_and_close(self): + self.save_settings() + self.close() + + def save_and_restart(self): + msg = QMessageBox() + msg.setIcon(QMessageBox.Icon.Question) + msg.setWindowTitle("Confirm Reset") + msg.setText("Are you sure you want to restart the app?") + msg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + + # Show the message box and wait for the user's response + response = msg.exec() + + # Check response and perform action + if response == QMessageBox.StandardButton.Yes: + self.save_settings() + self.restart_program() + else: + pass # Do nothing if "No" is selected + + def ask_reset_exif(self): + """Shows a dialog to ask the user if they are sure about resetting EXIF options to default.""" + # Create a QMessageBox with a Yes/No question + msg = QMessageBox() + msg.setIcon(QMessageBox.Icon.Question) + msg.setWindowTitle("Confirm Reset") + msg.setText("Are you sure you want to reset the EXIF options to default?") + msg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) + + # Show the message box and wait for the user's response + response = msg.exec() + + # Check response and perform action + if response == QMessageBox.StandardButton.Yes: + self.u.default_exif() # Reset EXIF options to default + else: + pass # Do nothing if "No" is selected + +# update related parts + def start_long_press(self): + """Start the timer when button is pressed.""" + # brave AI + self.timer.start(1000) # 1-second long press + + def cancel_long_press(self): + """Cancel long press if released early.""" + # brave AI + self.timer.stop() + + def toggle_dev_ui(self): + """Show or hide the hidden UI when long press is detected.""" + self.ui.dev_widget.setVisible(True) + + self.ui.check_local_Button.clicked.connect(self.local_check_for_updates) + self.ui.update_local_Button.clicked.connect(self.local_update) def local_check_for_updates(self): dist_folder = os.path.expanduser("~/.config/OptimaLab35/dist/") @@ -881,7 +978,21 @@ class ImageProcessorWorker(QRunnable): self.callback(None) def main(): + u = Utilities(os.path.expanduser("~/.config/OptimaLab35")) + app_settings = u.load_settings() app = QtWidgets.QApplication(sys.argv) + + try: + import qdarktheme + app_settings["theme"]["theme_pkg"] = True + except Exception: + app_settings["theme"]["theme_pkg"] = False + + if app_settings["theme"]["use_custom_theme"] and app_settings["theme"]["theme_pkg"]: + app.setStyleSheet(qdarktheme.load_stylesheet(app_settings["theme"]["mode"].lower())) + + u.save_settings(app_settings) + del u window = OptimaLab35() window.show() app.exec() diff --git a/src/OptimaLab35/ui/main_window.py b/src/OptimaLab35/ui/main_window.py index d19d062..03c3ee6 100644 --- a/src/OptimaLab35/ui/main_window.py +++ b/src/OptimaLab35/ui/main_window.py @@ -37,8 +37,8 @@ class Ui_MainWindow(object): self.actionPreview.setObjectName(u"actionPreview") self.actionAbout = QAction(MainWindow) self.actionAbout.setObjectName(u"actionAbout") - self.actionUpdate = QAction(MainWindow) - self.actionUpdate.setObjectName(u"actionUpdate") + self.actionSettings = QAction(MainWindow) + self.actionSettings.setObjectName(u"actionSettings") self.centralwidget = QWidget(MainWindow) self.centralwidget.setObjectName(u"centralwidget") self.gridLayout = QGridLayout(self.centralwidget) @@ -567,7 +567,7 @@ class Ui_MainWindow(object): self.menuBar.addAction(self.menuSettings.menuAction()) self.menuBar.addAction(self.menuHelp.menuAction()) self.menuHelp.addAction(self.actionAbout) - self.menuSettings.addAction(self.actionUpdate) + self.menuSettings.addAction(self.actionSettings) self.retranslateUi(MainWindow) self.rename_checkbox.toggled.connect(self.filename.setEnabled) @@ -605,7 +605,7 @@ class Ui_MainWindow(object): self.actionInfo.setText(QCoreApplication.translate("MainWindow", u"About", None)) self.actionPreview.setText(QCoreApplication.translate("MainWindow", u"Preview image", None)) self.actionAbout.setText(QCoreApplication.translate("MainWindow", u"About", None)) - self.actionUpdate.setText(QCoreApplication.translate("MainWindow", u"Update", None)) + self.actionSettings.setText(QCoreApplication.translate("MainWindow", u"Preferences...", None)) #if QT_CONFIG(tooltip) self.input_folder_button.setToolTip(QCoreApplication.translate("MainWindow", u"Open a file browser to select a folder for loading images.", None)) #endif // QT_CONFIG(tooltip) diff --git a/src/OptimaLab35/ui/main_window.ui b/src/OptimaLab35/ui/main_window.ui index 57986b7..bb7cc28 100644 --- a/src/OptimaLab35/ui/main_window.ui +++ b/src/OptimaLab35/ui/main_window.ui @@ -928,7 +928,7 @@ Settings - + @@ -948,9 +948,9 @@ About - + - Update + Preferences... diff --git a/src/OptimaLab35/ui/settings_window.py b/src/OptimaLab35/ui/settings_window.py new file mode 100644 index 0000000..9e25439 --- /dev/null +++ b/src/OptimaLab35/ui/settings_window.py @@ -0,0 +1,306 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'settings_window.ui' +## +## Created by: Qt User Interface Compiler version 6.8.1 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, + QFont, QFontDatabase, QGradient, QIcon, + QImage, QKeySequence, QLinearGradient, QPainter, + QPalette, QPixmap, QRadialGradient, QTransform) +from PySide6.QtWidgets import (QApplication, QCheckBox, QComboBox, QGridLayout, + QHBoxLayout, QLabel, QMainWindow, QPushButton, + QSizePolicy, QSpacerItem, QTabWidget, QVBoxLayout, + QWidget) + +class Ui_Settings_Window(object): + def setupUi(self, Settings_Window): + if not Settings_Window.objectName(): + Settings_Window.setObjectName(u"Settings_Window") + Settings_Window.setEnabled(True) + Settings_Window.resize(400, 300) + Settings_Window.setMinimumSize(QSize(400, 300)) + Settings_Window.setMaximumSize(QSize(500, 500)) + self.centralwidget = QWidget(Settings_Window) + self.centralwidget.setObjectName(u"centralwidget") + self.verticalLayout = QVBoxLayout(self.centralwidget) + self.verticalLayout.setObjectName(u"verticalLayout") + self.tabWidget = QTabWidget(self.centralwidget) + self.tabWidget.setObjectName(u"tabWidget") + self.tabWidgetPage1 = QWidget() + self.tabWidgetPage1.setObjectName(u"tabWidgetPage1") + self.verticalLayout_2 = QVBoxLayout(self.tabWidgetPage1) + self.verticalLayout_2.setObjectName(u"verticalLayout_2") + self.widget_3 = QWidget(self.tabWidgetPage1) + self.widget_3.setObjectName(u"widget_3") + self.gridLayout_3 = QGridLayout(self.widget_3) + self.gridLayout_3.setObjectName(u"gridLayout_3") + self.label_3 = QLabel(self.widget_3) + self.label_3.setObjectName(u"label_3") + + self.gridLayout_3.addWidget(self.label_3, 0, 0, 1, 3) + + self.theme_selection_comboBox = QComboBox(self.widget_3) + self.theme_selection_comboBox.addItem("") + self.theme_selection_comboBox.addItem("") + self.theme_selection_comboBox.setObjectName(u"theme_selection_comboBox") + self.theme_selection_comboBox.setEnabled(False) + self.theme_selection_comboBox.setMinimumSize(QSize(100, 0)) + self.theme_selection_comboBox.setMaximumSize(QSize(100, 16777215)) + + self.gridLayout_3.addWidget(self.theme_selection_comboBox, 1, 2, 1, 1) + + self.enable_theme_checkBox = QCheckBox(self.widget_3) + self.enable_theme_checkBox.setObjectName(u"enable_theme_checkBox") + self.enable_theme_checkBox.setChecked(False) + + self.gridLayout_3.addWidget(self.enable_theme_checkBox, 1, 0, 1, 1) + + self.horizontalSpacer_2 = QSpacerItem(98, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + + self.gridLayout_3.addItem(self.horizontalSpacer_2, 1, 1, 1, 1) + + self.install_pkg_Button = QPushButton(self.widget_3) + self.install_pkg_Button.setObjectName(u"install_pkg_Button") + + self.gridLayout_3.addWidget(self.install_pkg_Button, 2, 0, 1, 3) + + + self.verticalLayout_2.addWidget(self.widget_3) + + self.widget_4 = QWidget(self.tabWidgetPage1) + self.widget_4.setObjectName(u"widget_4") + self.horizontalLayout_3 = QHBoxLayout(self.widget_4) + self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") + self.label_4 = QLabel(self.widget_4) + self.label_4.setObjectName(u"label_4") + self.label_4.setWordWrap(True) + + self.horizontalLayout_3.addWidget(self.label_4) + + self.reset_exif_Button = QPushButton(self.widget_4) + self.reset_exif_Button.setObjectName(u"reset_exif_Button") + self.reset_exif_Button.setMinimumSize(QSize(100, 0)) + self.reset_exif_Button.setMaximumSize(QSize(100, 16777215)) + + self.horizontalLayout_3.addWidget(self.reset_exif_Button) + + + self.verticalLayout_2.addWidget(self.widget_4) + + self.verticalSpacer = QSpacerItem(20, 237, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + + self.verticalLayout_2.addItem(self.verticalSpacer) + + self.widget_5 = QWidget(self.tabWidgetPage1) + self.widget_5.setObjectName(u"widget_5") + self.horizontalLayout_4 = QHBoxLayout(self.widget_5) + self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") + self.save_and_close_Button = QPushButton(self.widget_5) + self.save_and_close_Button.setObjectName(u"save_and_close_Button") + + self.horizontalLayout_4.addWidget(self.save_and_close_Button) + + self.save_and_restart_Button = QPushButton(self.widget_5) + self.save_and_restart_Button.setObjectName(u"save_and_restart_Button") + + self.horizontalLayout_4.addWidget(self.save_and_restart_Button) + + + self.verticalLayout_2.addWidget(self.widget_5) + + self.tabWidget.addTab(self.tabWidgetPage1, "") + self.tabWidgetPage2 = QWidget() + self.tabWidgetPage2.setObjectName(u"tabWidgetPage2") + self.verticalLayout_3 = QVBoxLayout(self.tabWidgetPage2) + self.verticalLayout_3.setObjectName(u"verticalLayout_3") + self.widget_6 = QWidget(self.tabWidgetPage2) + self.widget_6.setObjectName(u"widget_6") + self.label_last_check = QLabel(self.widget_6) + self.label_last_check.setObjectName(u"label_last_check") + self.label_last_check.setGeometry(QRect(0, 10, 131, 22)) + self.label_last_check_2 = QLabel(self.widget_6) + self.label_last_check_2.setObjectName(u"label_last_check_2") + self.label_last_check_2.setEnabled(True) + self.label_last_check_2.setGeometry(QRect(190, 10, 67, 22)) + self.label_last_check_2.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) + + self.verticalLayout_3.addWidget(self.widget_6) + + self.widget_2 = QWidget(self.tabWidgetPage2) + self.widget_2.setObjectName(u"widget_2") + self.gridLayout = QGridLayout(self.widget_2) + self.gridLayout.setObjectName(u"gridLayout") + self.label_optima35_latestversion = QLabel(self.widget_2) + self.label_optima35_latestversion.setObjectName(u"label_optima35_latestversion") + self.label_optima35_latestversion.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) + + self.gridLayout.addWidget(self.label_optima35_latestversion, 2, 2, 1, 1) + + self.label_latest_version = QLabel(self.widget_2) + self.label_latest_version.setObjectName(u"label_latest_version") + self.label_latest_version.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) + + self.gridLayout.addWidget(self.label_latest_version, 0, 2, 1, 1) + + self.label = QLabel(self.widget_2) + self.label.setObjectName(u"label") + + self.gridLayout.addWidget(self.label, 1, 0, 1, 1) + + self.label_optimalab35_latestversion = QLabel(self.widget_2) + self.label_optimalab35_latestversion.setObjectName(u"label_optimalab35_latestversion") + self.label_optimalab35_latestversion.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) + + self.gridLayout.addWidget(self.label_optimalab35_latestversion, 1, 2, 1, 1) + + self.label_9 = QLabel(self.widget_2) + self.label_9.setObjectName(u"label_9") + + self.gridLayout.addWidget(self.label_9, 0, 0, 1, 1) + + self.label_optimalab35_localversion = QLabel(self.widget_2) + self.label_optimalab35_localversion.setObjectName(u"label_optimalab35_localversion") + self.label_optimalab35_localversion.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) + + self.gridLayout.addWidget(self.label_optimalab35_localversion, 1, 1, 1, 1) + + self.label_6 = QLabel(self.widget_2) + self.label_6.setObjectName(u"label_6") + self.label_6.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) + + self.gridLayout.addWidget(self.label_6, 0, 1, 1, 1) + + self.label_2 = QLabel(self.widget_2) + self.label_2.setObjectName(u"label_2") + + self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1) + + self.label_optima35_localversion = QLabel(self.widget_2) + self.label_optima35_localversion.setObjectName(u"label_optima35_localversion") + self.label_optima35_localversion.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) + + self.gridLayout.addWidget(self.label_optima35_localversion, 2, 1, 1, 1) + + + self.verticalLayout_3.addWidget(self.widget_2) + + self.dev_widget = QWidget(self.tabWidgetPage2) + self.dev_widget.setObjectName(u"dev_widget") + self.horizontalLayout_2 = QHBoxLayout(self.dev_widget) + self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.check_local_Button = QPushButton(self.dev_widget) + self.check_local_Button.setObjectName(u"check_local_Button") + + self.horizontalLayout_2.addWidget(self.check_local_Button) + + self.update_local_Button = QPushButton(self.dev_widget) + self.update_local_Button.setObjectName(u"update_local_Button") + + self.horizontalLayout_2.addWidget(self.update_local_Button) + + + self.verticalLayout_3.addWidget(self.dev_widget) + + self.verticalSpacer_2 = QSpacerItem(20, 9, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) + + self.verticalLayout_3.addItem(self.verticalSpacer_2) + + self.label_5 = QLabel(self.tabWidgetPage2) + self.label_5.setObjectName(u"label_5") + + self.verticalLayout_3.addWidget(self.label_5) + + self.widget = QWidget(self.tabWidgetPage2) + self.widget.setObjectName(u"widget") + self.horizontalLayout = QHBoxLayout(self.widget) + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.check_for_update_Button = QPushButton(self.widget) + self.check_for_update_Button.setObjectName(u"check_for_update_Button") + + self.horizontalLayout.addWidget(self.check_for_update_Button) + + self.update_and_restart_Button = QPushButton(self.widget) + self.update_and_restart_Button.setObjectName(u"update_and_restart_Button") + + self.horizontalLayout.addWidget(self.update_and_restart_Button) + + self.restart_checkBox = QCheckBox(self.widget) + self.restart_checkBox.setObjectName(u"restart_checkBox") + self.restart_checkBox.setChecked(True) + + self.horizontalLayout.addWidget(self.restart_checkBox) + + + self.verticalLayout_3.addWidget(self.widget) + + self.tabWidget.addTab(self.tabWidgetPage2, "") + + self.verticalLayout.addWidget(self.tabWidget) + + Settings_Window.setCentralWidget(self.centralwidget) + + self.retranslateUi(Settings_Window) + self.enable_theme_checkBox.toggled.connect(self.theme_selection_comboBox.setEnabled) + + self.tabWidget.setCurrentIndex(0) + + + QMetaObject.connectSlotsByName(Settings_Window) + # setupUi + + def retranslateUi(self, Settings_Window): + Settings_Window.setWindowTitle(QCoreApplication.translate("Settings_Window", u"Settings", None)) + self.label_3.setText(QCoreApplication.translate("Settings_Window", u"Change theme from OS to PyQT Dark or Light", None)) + self.theme_selection_comboBox.setItemText(0, QCoreApplication.translate("Settings_Window", u"Dark", None)) + self.theme_selection_comboBox.setItemText(1, QCoreApplication.translate("Settings_Window", u"Light", None)) + +#if QT_CONFIG(tooltip) + self.theme_selection_comboBox.setToolTip(QCoreApplication.translate("Settings_Window", u"App needs to restart before changes take effect.", None)) +#endif // QT_CONFIG(tooltip) +#if QT_CONFIG(tooltip) + self.enable_theme_checkBox.setToolTip(QCoreApplication.translate("Settings_Window", u"App needs to restart before changes take effect.", None)) +#endif // QT_CONFIG(tooltip) + self.enable_theme_checkBox.setText(QCoreApplication.translate("Settings_Window", u"Custom theme", None)) + self.install_pkg_Button.setText(QCoreApplication.translate("Settings_Window", u"Install package for custom theme", None)) + self.label_4.setText(QCoreApplication.translate("Settings_Window", u"Reset selectable EXIF data to default", None)) + self.reset_exif_Button.setText(QCoreApplication.translate("Settings_Window", u"Reset", None)) + self.save_and_close_Button.setText(QCoreApplication.translate("Settings_Window", u"Save and close", None)) + self.save_and_restart_Button.setText(QCoreApplication.translate("Settings_Window", u"Save and restart", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabWidgetPage1), QCoreApplication.translate("Settings_Window", u"Preferences", None)) + self.label_last_check.setText(QCoreApplication.translate("Settings_Window", u"Last update check:", None)) + self.label_last_check_2.setText(QCoreApplication.translate("Settings_Window", u"TextLabel", None)) + self.label_optima35_latestversion.setText(QCoreApplication.translate("Settings_Window", u"unknown", None)) + self.label_latest_version.setText(QCoreApplication.translate("Settings_Window", u"Latest version", None)) + self.label.setText(QCoreApplication.translate("Settings_Window", u"OptimaLab35", None)) + self.label_optimalab35_latestversion.setText(QCoreApplication.translate("Settings_Window", u"unknown", None)) + self.label_9.setText(QCoreApplication.translate("Settings_Window", u"Package", None)) + self.label_optimalab35_localversion.setText(QCoreApplication.translate("Settings_Window", u"0.0.0", None)) + self.label_6.setText(QCoreApplication.translate("Settings_Window", u"Local Version", None)) + self.label_2.setText(QCoreApplication.translate("Settings_Window", u"optima35", None)) + self.label_optima35_localversion.setText(QCoreApplication.translate("Settings_Window", u"0.0.0", None)) +#if QT_CONFIG(tooltip) + self.check_local_Button.setToolTip(QCoreApplication.translate("Settings_Window", u"FOR DEVELOPER", None)) +#endif // QT_CONFIG(tooltip) + self.check_local_Button.setText(QCoreApplication.translate("Settings_Window", u"Check local", None)) +#if QT_CONFIG(tooltip) + self.update_local_Button.setToolTip(QCoreApplication.translate("Settings_Window", u"FOR DEVELOPER", None)) +#endif // QT_CONFIG(tooltip) + self.update_local_Button.setText(QCoreApplication.translate("Settings_Window", u"Update local", None)) + self.label_5.setText(QCoreApplication.translate("Settings_Window", u"TextLabel", None)) + self.check_for_update_Button.setText(QCoreApplication.translate("Settings_Window", u"Check for update", None)) + self.update_and_restart_Button.setText(QCoreApplication.translate("Settings_Window", u"Update", None)) +#if QT_CONFIG(tooltip) + self.restart_checkBox.setToolTip(QCoreApplication.translate("Settings_Window", u"Restarts the app after update.", None)) +#endif // QT_CONFIG(tooltip) + self.restart_checkBox.setText(QCoreApplication.translate("Settings_Window", u"Restart", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabWidgetPage2), QCoreApplication.translate("Settings_Window", u"Updater", None)) + # retranslateUi + diff --git a/src/OptimaLab35/ui/settings_window.ui b/src/OptimaLab35/ui/settings_window.ui new file mode 100644 index 0000000..a30edf8 --- /dev/null +++ b/src/OptimaLab35/ui/settings_window.ui @@ -0,0 +1,424 @@ + + + Settings_Window + + + true + + + + 0 + 0 + 400 + 300 + + + + + 400 + 300 + + + + + 500 + 500 + + + + Settings + + + + + + + 0 + + + + Preferences + + + + + + + + + Change theme from OS to PyQT Dark or Light + + + + + + + false + + + + 100 + 0 + + + + + 100 + 16777215 + + + + App needs to restart before changes take effect. + + + + Dark + + + + + Light + + + + + + + + App needs to restart before changes take effect. + + + Custom theme + + + false + + + + + + + Qt::Horizontal + + + + 98 + 20 + + + + + + + + Install package for custom theme + + + + + + + + + + + + + Reset selectable EXIF data to default + + + true + + + + + + + + 100 + 0 + + + + + 100 + 16777215 + + + + Reset + + + + + + + + + + Qt::Vertical + + + + 20 + 237 + + + + + + + + + + + Save and close + + + + + + + Save and restart + + + + + + + + + + + Updater + + + + + + + + 0 + 10 + 131 + 22 + + + + Last update check: + + + + + true + + + + 190 + 10 + 67 + 22 + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + unknown + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Latest version + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + OptimaLab35 + + + + + + + unknown + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Package + + + + + + + 0.0.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Local Version + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + optima35 + + + + + + + 0.0.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + FOR DEVELOPER + + + Check local + + + + + + + FOR DEVELOPER + + + Update local + + + + + + + + + + Qt::Vertical + + + + 20 + 9 + + + + + + + + TextLabel + + + + + + + + + + Check for update + + + + + + + Update + + + + + + + Restarts the app after update. + + + Restart + + + true + + + + + + + + + + + + + + + + + enable_theme_checkBox + toggled(bool) + theme_selection_comboBox + setEnabled(bool) + + + 112 + 103 + + + 286 + 103 + + + + + diff --git a/src/OptimaLab35/ui/simple_dialog.py b/src/OptimaLab35/ui/simple_dialog.py index 019877a..5410dc7 100644 --- a/src/OptimaLab35/ui/simple_dialog.py +++ b/src/OptimaLab35/ui/simple_dialog.py @@ -17,6 +17,7 @@ class SimpleDialog(QDialog): self.message_label.setWordWrap(True) # Enable word wrapping self.message_label.setAlignment(Qt.AlignLeft | Qt.AlignTop) # Align text self.message_label.setMaximumWidth(400) # Set max width so it wraps text + self.message_label.setOpenExternalLinks(True) # Create the close button close_button = QPushButton("Close", self) diff --git a/src/OptimaLab35/ui/updater_window.py b/src/OptimaLab35/ui/updater_window.py deleted file mode 100644 index eba411a..0000000 --- a/src/OptimaLab35/ui/updater_window.py +++ /dev/null @@ -1,179 +0,0 @@ -# -*- coding: utf-8 -*- - -################################################################################ -## Form generated from reading UI file 'updater_window.ui' -## -## Created by: Qt User Interface Compiler version 6.8.1 -## -## WARNING! All changes made in this file will be lost when recompiling UI file! -################################################################################ - -from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, - QMetaObject, QObject, QPoint, QRect, - QSize, QTime, QUrl, Qt) -from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, - QFont, QFontDatabase, QGradient, QIcon, - QImage, QKeySequence, QLinearGradient, QPainter, - QPalette, QPixmap, QRadialGradient, QTransform) -from PySide6.QtWidgets import (QApplication, QCheckBox, QGridLayout, QHBoxLayout, - QLabel, QMainWindow, QPushButton, QSizePolicy, - QWidget) - -class Ui_Updater_Window(object): - def setupUi(self, Updater_Window): - if not Updater_Window.objectName(): - Updater_Window.setObjectName(u"Updater_Window") - Updater_Window.setEnabled(True) - Updater_Window.resize(340, 200) - Updater_Window.setMinimumSize(QSize(336, 200)) - Updater_Window.setMaximumSize(QSize(340, 300)) - self.centralwidget = QWidget(Updater_Window) - self.centralwidget.setObjectName(u"centralwidget") - self.gridLayout_2 = QGridLayout(self.centralwidget) - self.gridLayout_2.setObjectName(u"gridLayout_2") - self.widget_2 = QWidget(self.centralwidget) - self.widget_2.setObjectName(u"widget_2") - self.gridLayout = QGridLayout(self.widget_2) - self.gridLayout.setObjectName(u"gridLayout") - self.label = QLabel(self.widget_2) - self.label.setObjectName(u"label") - - self.gridLayout.addWidget(self.label, 1, 0, 1, 1) - - self.label_optima35_localversion = QLabel(self.widget_2) - self.label_optima35_localversion.setObjectName(u"label_optima35_localversion") - self.label_optima35_localversion.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) - - self.gridLayout.addWidget(self.label_optima35_localversion, 2, 1, 1, 1) - - self.label_9 = QLabel(self.widget_2) - self.label_9.setObjectName(u"label_9") - - self.gridLayout.addWidget(self.label_9, 0, 0, 1, 1) - - self.label_optima35_latestversion = QLabel(self.widget_2) - self.label_optima35_latestversion.setObjectName(u"label_optima35_latestversion") - self.label_optima35_latestversion.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) - - self.gridLayout.addWidget(self.label_optima35_latestversion, 2, 2, 1, 1) - - self.label_optimalab35_localversion = QLabel(self.widget_2) - self.label_optimalab35_localversion.setObjectName(u"label_optimalab35_localversion") - self.label_optimalab35_localversion.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) - - self.gridLayout.addWidget(self.label_optimalab35_localversion, 1, 1, 1, 1) - - self.label_6 = QLabel(self.widget_2) - self.label_6.setObjectName(u"label_6") - self.label_6.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) - - self.gridLayout.addWidget(self.label_6, 0, 1, 1, 1) - - self.label_optimalab35_latestversion = QLabel(self.widget_2) - self.label_optimalab35_latestversion.setObjectName(u"label_optimalab35_latestversion") - self.label_optimalab35_latestversion.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) - - self.gridLayout.addWidget(self.label_optimalab35_latestversion, 1, 2, 1, 1) - - self.label_latest_version = QLabel(self.widget_2) - self.label_latest_version.setObjectName(u"label_latest_version") - self.label_latest_version.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) - - self.gridLayout.addWidget(self.label_latest_version, 0, 2, 1, 1) - - self.label_2 = QLabel(self.widget_2) - self.label_2.setObjectName(u"label_2") - - self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1) - - - self.gridLayout_2.addWidget(self.widget_2, 1, 0, 1, 2) - - self.widget = QWidget(self.centralwidget) - self.widget.setObjectName(u"widget") - self.horizontalLayout = QHBoxLayout(self.widget) - self.horizontalLayout.setObjectName(u"horizontalLayout") - self.check_for_update_Button = QPushButton(self.widget) - self.check_for_update_Button.setObjectName(u"check_for_update_Button") - - self.horizontalLayout.addWidget(self.check_for_update_Button) - - self.update_and_restart_Button = QPushButton(self.widget) - self.update_and_restart_Button.setObjectName(u"update_and_restart_Button") - - self.horizontalLayout.addWidget(self.update_and_restart_Button) - - self.restart_checkBox = QCheckBox(self.widget) - self.restart_checkBox.setObjectName(u"restart_checkBox") - self.restart_checkBox.setChecked(True) - - self.horizontalLayout.addWidget(self.restart_checkBox) - - - self.gridLayout_2.addWidget(self.widget, 2, 0, 1, 2) - - self.label_last_check = QLabel(self.centralwidget) - self.label_last_check.setObjectName(u"label_last_check") - - self.gridLayout_2.addWidget(self.label_last_check, 0, 0, 1, 1) - - self.label_last_check_2 = QLabel(self.centralwidget) - self.label_last_check_2.setObjectName(u"label_last_check_2") - self.label_last_check_2.setEnabled(True) - self.label_last_check_2.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) - - self.gridLayout_2.addWidget(self.label_last_check_2, 0, 1, 1, 1) - - self.dev_widget = QWidget(self.centralwidget) - self.dev_widget.setObjectName(u"dev_widget") - self.horizontalLayout_2 = QHBoxLayout(self.dev_widget) - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.check_local_Button = QPushButton(self.dev_widget) - self.check_local_Button.setObjectName(u"check_local_Button") - - self.horizontalLayout_2.addWidget(self.check_local_Button) - - self.update_local_Button = QPushButton(self.dev_widget) - self.update_local_Button.setObjectName(u"update_local_Button") - - self.horizontalLayout_2.addWidget(self.update_local_Button) - - - self.gridLayout_2.addWidget(self.dev_widget, 3, 0, 1, 2) - - Updater_Window.setCentralWidget(self.centralwidget) - - self.retranslateUi(Updater_Window) - - QMetaObject.connectSlotsByName(Updater_Window) - # setupUi - - def retranslateUi(self, Updater_Window): - Updater_Window.setWindowTitle(QCoreApplication.translate("Updater_Window", u"Updater", None)) - self.label.setText(QCoreApplication.translate("Updater_Window", u"OptimaLab35", None)) - self.label_optima35_localversion.setText(QCoreApplication.translate("Updater_Window", u"0.0.0", None)) - self.label_9.setText(QCoreApplication.translate("Updater_Window", u"Package", None)) - self.label_optima35_latestversion.setText(QCoreApplication.translate("Updater_Window", u"unknown", None)) - self.label_optimalab35_localversion.setText(QCoreApplication.translate("Updater_Window", u"0.0.0", None)) - self.label_6.setText(QCoreApplication.translate("Updater_Window", u"Local Version", None)) - self.label_optimalab35_latestversion.setText(QCoreApplication.translate("Updater_Window", u"unknown", None)) - self.label_latest_version.setText(QCoreApplication.translate("Updater_Window", u"Latest version", None)) - self.label_2.setText(QCoreApplication.translate("Updater_Window", u"optima35", None)) - self.check_for_update_Button.setText(QCoreApplication.translate("Updater_Window", u"Check for update", None)) - self.update_and_restart_Button.setText(QCoreApplication.translate("Updater_Window", u"Update", None)) -#if QT_CONFIG(tooltip) - self.restart_checkBox.setToolTip(QCoreApplication.translate("Updater_Window", u"Restarts the app after update.", None)) -#endif // QT_CONFIG(tooltip) - self.restart_checkBox.setText(QCoreApplication.translate("Updater_Window", u"Restart", None)) - self.label_last_check.setText(QCoreApplication.translate("Updater_Window", u"Last update check:", None)) - self.label_last_check_2.setText(QCoreApplication.translate("Updater_Window", u"TextLabel", None)) -#if QT_CONFIG(tooltip) - self.check_local_Button.setToolTip(QCoreApplication.translate("Updater_Window", u"FOR DEVELOPER", None)) -#endif // QT_CONFIG(tooltip) - self.check_local_Button.setText(QCoreApplication.translate("Updater_Window", u"Check local", None)) -#if QT_CONFIG(tooltip) - self.update_local_Button.setToolTip(QCoreApplication.translate("Updater_Window", u"FOR DEVELOPER", None)) -#endif // QT_CONFIG(tooltip) - self.update_local_Button.setText(QCoreApplication.translate("Updater_Window", u"Update local", None)) - # retranslateUi - diff --git a/src/OptimaLab35/ui/updater_window.ui b/src/OptimaLab35/ui/updater_window.ui deleted file mode 100644 index 7f17bf0..0000000 --- a/src/OptimaLab35/ui/updater_window.ui +++ /dev/null @@ -1,204 +0,0 @@ - - - Updater_Window - - - true - - - - 0 - 0 - 340 - 200 - - - - - 336 - 200 - - - - - 340 - 300 - - - - Updater - - - - - - - - - - OptimaLab35 - - - - - - - 0.0.0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Package - - - - - - - unknown - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 0.0.0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Local Version - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - unknown - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Latest version - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - optima35 - - - - - - - - - - - - - Check for update - - - - - - - Update - - - - - - - Restarts the app after update. - - - Restart - - - true - - - - - - - - - - Last update check: - - - - - - - true - - - TextLabel - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - FOR DEVELOPER - - - Check local - - - - - - - FOR DEVELOPER - - - Update local - - - - - - - - - - - - diff --git a/src/OptimaLab35/utils/utility.py b/src/OptimaLab35/utils/utility.py index d7673f5..1db2060 100644 --- a/src/OptimaLab35/utils/utility.py +++ b/src/OptimaLab35/utils/utility.py @@ -2,8 +2,12 @@ import yaml import os class Utilities: - def __init__(self): - pass + def __init__(self, app_folder_path): + self.folder_path = app_folder_path + self._ensure_program_folder_exists() + self.exif_path = os.path.expanduser(f"{app_folder_path}/exif.yaml") + self.settings_path = os.path.expanduser(f"{app_folder_path}/settings.yaml") + self._prepear_exif_config() def read_yaml(self, yaml_file): try: @@ -12,29 +16,38 @@ class Utilities: return data except (FileNotFoundError, PermissionError) as e: print(f"Error loading settings file: {e}") - return + return None def write_yaml(self, yaml_file, data): try: with open(yaml_file, "w") as file: yaml.dump(data, file) + return True except PermissionError as e: print(f"Error saving setings: {e}") + return False - def program_configs(self): + def _prepear_exif_config(self): """Prepear folder for config and generate default exif if non aviable""" - program_folder = self._ensure_program_folder_exists() - if not os.path.isfile(f"{program_folder}/exif.yaml"): - self._default_exif(f"{program_folder}/exif.yaml") + if not os.path.isfile(self.exif_path): + self.default_exif(self.exif_path) def _ensure_program_folder_exists(self): - program_folder = os.path.expanduser("~/.config/OptimaLab35") - if not os.path.exists(program_folder): - print("in not, make folder") - os.makedirs(program_folder) - return program_folder + if not os.path.exists(self.folder_path): + os.makedirs(self.folder_path) - def _default_exif(self, file): + def load_settings(self): + """Loads settings from file, or creates default settings if missing.""" + if os.path.exists(self.settings_path): + settings = self.read_yaml(self.settings_path) + return settings if settings else self._default_settings() + return self._default_settings() + + def save_settings(self, settings): + if not self.write_yaml(self.settings_path, settings): + print("Error writing file") + + def default_exif(self): """Makes a default exif file.""" print("Making default") def_exif = { @@ -78,7 +91,19 @@ class Utilities: "Scanner: NA" ] } - self.write_yaml(file, def_exif) + self.write_yaml(self.exif_path, def_exif) + + def _default_settings(self): + """Returns default settings and writes them if the settings file does not exist.""" + settings = { + "theme": { + "theme_pkg": False, + "use_custom_theme": False, + "mode": "Dark" + } + } + self.write_yaml(self.settings_path, settings) + return settings def append_number_to_name(self, base_name: str, current_image: int, total_images: int, invert: bool): """"Returns name, combination of base_name and ending number.""" diff --git a/src/pyproject.toml b/src/pyproject.toml index 9e88304..903108e 100644 --- a/src/pyproject.toml +++ b/src/pyproject.toml @@ -11,11 +11,14 @@ readme = "../pip_README.md" requires-python = ">=3.8" dependencies = [ "optima35>=1.0.0, <2.0.0", - "PyPiUpdater>=0.6.0, <1.0.0", + "PyPiUpdater>=0.7.0, <1.0.0", "pyside6", "PyYAML", ] classifiers = [ + "Development Status :: 4 - Beta", + "Environment :: X11 Applications :: Qt", + "Topic :: Multimedia :: Graphics :: Editors", "Programming Language :: Python :: 3", "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)", "Operating System :: OS Independent", diff --git a/src/update_ui.sh b/src/update_ui.sh index 95cda5f..3b50769 100755 --- a/src/update_ui.sh +++ b/src/update_ui.sh @@ -4,5 +4,5 @@ echo "Update main window." pyside6-uic OptimaLab35/ui/main_window.ui -o OptimaLab35/ui/main_window.py echo "Update preview window." pyside6-uic OptimaLab35/ui/preview_window.ui -o OptimaLab35/ui/preview_window.py -echo "Update updater window." -pyside6-uic OptimaLab35/ui/updater_window.ui -o OptimaLab35/ui/updater_window.py +echo "Update settings window." +pyside6-uic OptimaLab35/ui/settings_window.ui -o OptimaLab35/ui/settings_window.py