From 2c42c88555b0ce654720b4b1243a8aa130025876 Mon Sep 17 00:00:00 2001 From: "N0\\A" Date: Fri, 31 Oct 2025 17:16:52 +0100 Subject: [PATCH] config window --- strings/en.json | 14 ++++++ strings/personality_en.json | 14 ++++++ windows/config_window.py | 88 +++++++++++++++++++++++++++++++++++++ windows/main_window.py | 6 +++ 4 files changed, 122 insertions(+) create mode 100644 windows/config_window.py diff --git a/strings/en.json b/strings/en.json index 9bb7739..3cd350d 100644 --- a/strings/en.json +++ b/strings/en.json @@ -51,6 +51,7 @@ "share_files_submenu": "File(s)", "share_text_submenu": "Text", "via_browser": "Via Browser...", + "settings": "Settings", "check_updates": "Check for updates", "restart": "Restart", "toggle_visibility": "Hide/Show", @@ -108,5 +109,18 @@ "update_failed_title": "Update Failed", "update_failed_text": "{message}" } + }, + "config_window": { + "title": "Settings", + "hotkey_label": "Global Hotkey:", + "discord_presence_label": "Enable Discord Presence:", + "auto_update_label": "Enable Auto-Update:", + "http_share_port_label": "HTTP Share Port:", + "dukto_udp_port_label": "Dukto UDP Port:", + "dukto_tcp_port_label": "Dukto TCP Port:", + "search_engine_label": "Web Search Engine:", + "restart_note": "Note: Some changes (like ports or hotkey) may require a restart to take effect.", + "reset_title": "Confirm Reset", + "reset_text": "Are you sure you want to reset all settings to their default values?" } } \ No newline at end of file diff --git a/strings/personality_en.json b/strings/personality_en.json index 33a819f..2ae5c03 100644 --- a/strings/personality_en.json +++ b/strings/personality_en.json @@ -51,6 +51,7 @@ "share_files_submenu": "File(s)", "share_text_submenu": "Message", "via_browser": "Via Browser...", + "settings": "Preferences", "check_updates": "Check for Updates", "restart": "Restart", "toggle_visibility": "Hide/Show", @@ -108,5 +109,18 @@ "update_failed_title": "Update Failed", "update_failed_text": "{message}" } + }, + "config_window": { + "title": "Preferences", + "hotkey_label": "Global Hotkey:", + "discord_presence_label": "Show CLARA on your Discord status:", + "auto_update_label": "Update Automatically:", + "http_share_port_label": "Browser Sharing Port:", + "dukto_udp_port_label": "Dukto Discovery Port (UDP):", + "dukto_tcp_port_label": "Dukto Transfer Port (TCP):", + "search_engine_label": "Search Engine:", + "restart_note": "Just a heads-up: some changes (like ports or the hotkey) will need a restart to work.", + "reset_title": "Reset Settings?", + "reset_text": "Are you sure you want to go back to the default settings?" } } \ No newline at end of file diff --git a/windows/config_window.py b/windows/config_window.py new file mode 100644 index 0000000..67d3780 --- /dev/null +++ b/windows/config_window.py @@ -0,0 +1,88 @@ +from PySide6 import QtWidgets +from core.config import Config + +class ConfigWindow(QtWidgets.QDialog): + def __init__(self, strings, config: Config, parent=None): + super().__init__(parent) + self.strings = strings.get("config_window", {}) + self.config = config + self.setWindowTitle(self.strings.get("title", "Settings")) + self.setMinimumWidth(400) + + self.layout = QtWidgets.QVBoxLayout(self) # type: ignore + self.form_layout = QtWidgets.QFormLayout() + + # Create widgets for each setting + self.hotkey_input = QtWidgets.QLineEdit() + self.discord_presence_check = QtWidgets.QCheckBox() + self.auto_update_check = QtWidgets.QCheckBox() + self.http_port_spin = QtWidgets.QSpinBox() + self.http_port_spin.setRange(1024, 65535) + self.dukto_udp_port_spin = QtWidgets.QSpinBox() + self.dukto_udp_port_spin.setRange(1024, 65535) + self.dukto_tcp_port_spin = QtWidgets.QSpinBox() + self.dukto_tcp_port_spin.setRange(1024, 65535) + self.search_engine_combo = QtWidgets.QComboBox() + self.search_engine_combo.addItems(["brave", "google"]) + + # Add widgets to layout + self.form_layout.addRow(self.strings.get("hotkey_label", "Global Hotkey:"), self.hotkey_input) + self.form_layout.addRow(self.strings.get("discord_presence_label", "Enable Discord Presence:"), self.discord_presence_check) + self.form_layout.addRow(self.strings.get("auto_update_label", "Enable Auto-Update:"), self.auto_update_check) + self.form_layout.addRow(self.strings.get("http_share_port_label", "HTTP Share Port:"), self.http_port_spin) + self.form_layout.addRow(self.strings.get("dukto_udp_port_label", "Dukto UDP Port:"), self.dukto_udp_port_spin) + self.form_layout.addRow(self.strings.get("dukto_tcp_port_label", "Dukto TCP Port:"), self.dukto_tcp_port_spin) + self.form_layout.addRow(self.strings.get("search_engine_label", "Web Search Engine:"), self.search_engine_combo) + + self.layout.addLayout(self.form_layout) #type: ignore + + # Info label + self.info_label = QtWidgets.QLabel(self.strings.get("restart_note", "Note: Some changes may require a restart.")) + self.info_label.setStyleSheet("font-style: italic; color: grey;") + self.info_label.setWordWrap(True) + self.layout.addWidget(self.info_label) #type: ignore + + # Buttons + self.button_box = QtWidgets.QDialogButtonBox( + QtWidgets.QDialogButtonBox.Save | QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Reset # type: ignore + ) + self.button_box.accepted.connect(self.save_config) + self.button_box.rejected.connect(self.reject) + reset_button = self.button_box.button(QtWidgets.QDialogButtonBox.Reset) # type: ignore + if reset_button: + reset_button.clicked.connect(self.reset_to_defaults) + + self.layout.addWidget(self.button_box) #type: ignore + + self.load_config() + + def load_config(self): + self.hotkey_input.setText(self.config.get("hotkey", "")) + self.discord_presence_check.setChecked(self.config.get("discord_presence", True)) + self.auto_update_check.setChecked(self.config.get("auto_update", True)) + self.http_port_spin.setValue(self.config.get("http_share_port", 8080)) + self.dukto_udp_port_spin.setValue(self.config.get("dukto_udp_port", 4644)) + self.dukto_tcp_port_spin.setValue(self.config.get("dukto_tcp_port", 4644)) + self.search_engine_combo.setCurrentText(self.config.get("search_engine", "brave")) + + def save_config(self): + self.config.set("hotkey", self.hotkey_input.text()) + self.config.set("discord_presence", self.discord_presence_check.isChecked()) + self.config.set("auto_update", self.auto_update_check.isChecked()) + self.config.set("http_share_port", self.http_port_spin.value()) + self.config.set("dukto_udp_port", self.dukto_udp_port_spin.value()) + self.config.set("dukto_tcp_port", self.dukto_tcp_port_spin.value()) + self.config.set("search_engine", self.search_engine_combo.currentText()) + self.accept() + + def reset_to_defaults(self): + reply = QtWidgets.QMessageBox.question( + self, + self.strings.get("reset_title", "Confirm Reset"), + self.strings.get("reset_text", "Are you sure?"), + QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, # type: ignore + QtWidgets.QMessageBox.No # type: ignore + ) + if reply == QtWidgets.QMessageBox.Yes: # type: ignore + self.config.reset() + self.load_config() \ No newline at end of file diff --git a/windows/main_window.py b/windows/main_window.py index 3c89cd7..9319664 100644 --- a/windows/main_window.py +++ b/windows/main_window.py @@ -17,6 +17,7 @@ from windows.file_search import FileSearchResults from windows.web_results import WebSearchResults from windows.text_viewer import TextViewerDialog from windows.calculator import CalculatorDialog +from windows.config_window import ConfigWindow ASSET = Path(__file__).parent.parent / "assets" / "2ktan.png" @@ -146,6 +147,7 @@ class MainWindow(QtWidgets.QMainWindow): self.share_text_submenu_right = share_menu_right.addMenu(s["share_text_submenu"]) self.stop_share_action_right = share_menu_right.addAction("Stop Browser Share", self.stop_browser_share) right_menu.addSeparator() + right_menu.addAction(s.get("settings", "Settings"), self.start_config_window) right_menu.addAction(s["check_updates"], self.update_git) if self.restart: @@ -493,6 +495,10 @@ class MainWindow(QtWidgets.QMainWindow): self.calculator_dialog.move(QtGui.QCursor.pos()) self.calculator_dialog.show() + def start_config_window(self): + self.config_dialog = ConfigWindow(self.strings, self.config, self) + self.config_dialog.show() + def start_file_search(self): s = self.strings["file_search"] dialog = QtWidgets.QInputDialog(self)