From 750b90a70ede4eb5b048b93e604ea1328a7fd9c6 Mon Sep 17 00:00:00 2001 From: Axel Rafn Date: Sat, 13 Jul 2024 10:49:03 +0200 Subject: [PATCH] chore: Update search input layout in URLManager --- app.py | 186 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 115 insertions(+), 71 deletions(-) diff --git a/app.py b/app.py index 729aa10..8a46be9 100644 --- a/app.py +++ b/app.py @@ -5,7 +5,7 @@ from PyQt5.QtWidgets import ( QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLineEdit, QPushButton, QTextEdit, QComboBox, QMessageBox, QSpacerItem, QSizePolicy, QLabel, QFileDialog, QDialog, QFormLayout, QTableWidget, QTableWidgetItem, - QHeaderView, QDateTimeEdit # Import QDateTimeEdit for date formatting + QHeaderView, QDateTimeEdit ) from PyQt5.QtGui import QIcon, QPixmap from PyQt5.QtCore import Qt, QDateTime, QUrl @@ -16,9 +16,8 @@ class URLManager(QWidget): super().__init__() self.setWindowTitle('tabRemember - URL Manager') - self.setGeometry(100, 100, 600, 800) # Set a larger initial size + self.setGeometry(100, 100, 600, 800) - # Set the application icon self.setWindowIcon(QIcon('assets/logo.png')) self.layout = QVBoxLayout() @@ -29,43 +28,51 @@ class URLManager(QWidget): self.url_input.setPlaceholderText("URL") self.url_layout.addWidget(self.url_input) - # Settings button self.settings_button = QPushButton() - self.settings_button.setFixedSize(24, 24) # Set fixed size for icon button + self.settings_button.setFixedSize(24, 24) self.settings_button.clicked.connect(self.show_settings_dialog) self.url_layout.addWidget(self.settings_button) - # Info button self.info_button = QPushButton() - self.info_button.setFixedSize(24, 24) # Set fixed size for icon button + self.info_button.setFixedSize(24, 24) self.info_button.clicked.connect(self.show_info_dialog) self.url_layout.addWidget(self.info_button) self.layout.addLayout(self.url_layout) - # Update icons based on the color mode self.update_icon_color() - # Description/Thoughts input self.description_input = QTextEdit() self.description_input.setPlaceholderText("Enter Description or Thoughts") - self.description_input.setMaximumHeight(100) # Limit height to approximately 5 lines + self.description_input.setMaximumHeight(100) self.layout.addWidget(self.description_input) - # Group selection combobox - self.group_combobox = QComboBox() - self.group_combobox.addItem("Default Group") # Add default group option - self.layout.addWidget(self.group_combobox) + self.group_layout = QHBoxLayout() - # Add URL button - self.add_button = QPushButton("Save") + self.group_combobox = QComboBox() + self.group_combobox.addItem("All Categories") + self.group_combobox.addItem("Default Category") + self.group_combobox.currentTextChanged.connect(self.filter_urls_by_category) + self.group_layout.addWidget(self.group_combobox) + + self.category_input = QLineEdit() + self.category_input.setPlaceholderText("Category name") + self.category_input.setFixedWidth(3 * 100) # Fixed width for the text input box, assuming "Save" button width is 100 + self.group_layout.addWidget(self.category_input) + + self.save_category_button = QPushButton("Save Category") + self.save_category_button.setFixedWidth(100) # Fixed width for the "Save" button + self.save_category_button.clicked.connect(self.save_category) + self.group_layout.addWidget(self.save_category_button) + + self.layout.addLayout(self.group_layout) + + self.add_button = QPushButton("Save URL") self.add_button.clicked.connect(self.add_url) self.layout.addWidget(self.add_button) - # Add space between the Add URL button and URL list self.layout.addSpacerItem(QSpacerItem(0, 10, QSizePolicy.Minimum, QSizePolicy.Fixed)) - # Search input self.search_layout = QHBoxLayout() self.search_input = QLineEdit() self.search_input.setPlaceholderText("Search ...") @@ -73,16 +80,14 @@ class URLManager(QWidget): self.search_layout.addWidget(self.search_input) self.layout.addLayout(self.search_layout) - # Ensure the search input is full width self.search_input.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) - # URL list self.url_list = QTableWidget() self.url_list.setColumnCount(3) self.url_list.setHorizontalHeaderLabels(['URL', 'Date', 'Actions']) - self.url_list.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch) # Stretch first column - self.url_list.setColumnWidth(1, 150) # Set fixed width for Date column - self.url_list.setColumnWidth(2, 100) # Set fixed width for Actions column + self.url_list.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch) + self.url_list.setColumnWidth(1, 150) + self.url_list.setColumnWidth(2, 100) self.layout.addWidget(self.url_list) self.setLayout(self.layout) @@ -90,13 +95,11 @@ class URLManager(QWidget): self.urls = [] self.groups = set() - # Load settings self.load_settings() - # Load URLs + self.load_categories() self.load_urls() - # Search engines self.search_engines = { "Bing": "https://www.bing.com/search?q=", "Brave": "https://search.brave.com/search?q=", @@ -108,7 +111,6 @@ class URLManager(QWidget): } def update_icon_color(self): - # Heuristic to check if the application is in dark mode palette = self.palette() if palette.color(palette.Window).value() < 128: settings_icon_path = 'assets/cogwheel_dark.svg' @@ -133,15 +135,29 @@ class URLManager(QWidget): def add_url(self): url = self.url_input.text() description = self.description_input.toPlainText() - group = self.group_combobox.currentText() # Retrieve selected group + group = self.group_combobox.currentText() if url: date_added = QDateTime.currentDateTime().toString(Qt.ISODate) - self.urls.append({'url': url, 'description': description, 'date': date_added, 'group': group}) - self.save_urls() + url_data = {'url': url, 'description': description, 'date': date_added, 'group': group} + self.urls.append(url_data) + self.save_url(url_data) self.update_url_list() self.url_input.clear() self.description_input.clear() + def save_url(self, url_data): + category = url_data['group'] + category_filename = self.get_category_filename(category) + category_path = os.path.join(self.data_directory, category_filename) + if os.path.exists(category_path): + with open(category_path, 'r') as file: + category_urls = json.load(file) + else: + category_urls = [] + category_urls.append(url_data) + with open(category_path, 'w') as file: + json.dump(category_urls, file) + def update_url(self): selected_item = self.url_list.currentItem() if selected_item: @@ -166,24 +182,30 @@ class URLManager(QWidget): def filter_urls(self): search_term = self.search_input.text().strip().lower() if not search_term: - self.update_url_list() # Reset to show all URLs + self.update_url_list() return filtered_urls = [url for url in self.urls if search_term in url['url'].lower() or search_term in url['description'].lower()] self.update_url_list(filtered_urls) + def filter_urls_by_category(self): + selected_category = self.group_combobox.currentText() + if selected_category == "All Categories": + self.update_url_list(sorted(self.urls, key=lambda x: x['date'], reverse=True)) + else: + filtered_urls = [url for url in self.urls if url['group'] == selected_category] + self.update_url_list(filtered_urls) + def update_url_list(self, urls=None): if urls is None: urls = self.urls - # Fetch date format from settings date_format = self.date_format self.url_list.setRowCount(len(urls)) for row, url in enumerate(urls): self.url_list.setItem(row, 0, QTableWidgetItem(url['url'])) - # Format date according to selected date format if date_format == "Nerdy": date_str = url['date'] elif date_format == "Normal": @@ -193,35 +215,27 @@ class URLManager(QWidget): self.url_list.setItem(row, 1, QTableWidgetItem(date_str)) - # Action buttons actions_layout = QHBoxLayout() edit_button = QPushButton() edit_button.setIcon(QIcon(self.action_icons["edit"])) - edit_button.setFixedSize(18, 18) # Set smaller size for icon button + edit_button.setFixedSize(18, 18) edit_button.setStyleSheet("border: none; padding: 0px;") edit_button.clicked.connect(lambda _, row=row: self.edit_url(row)) + actions_layout.addWidget(edit_button) delete_button = QPushButton() delete_button.setIcon(QIcon(self.action_icons["delete"])) - delete_button.setFixedSize(18, 18) # Set smaller size for icon button + delete_button.setFixedSize(18, 18) delete_button.setStyleSheet("border: none; padding: 0px;") delete_button.clicked.connect(lambda _, row=row: self.delete_url(row)) - - search_button = QPushButton() - search_button.setIcon(QIcon(self.action_icons["search"])) - search_button.setFixedSize(18, 18) # Set smaller size for icon button - search_button.setStyleSheet("border: none; padding: 0px;") - search_button.clicked.connect(lambda _, row=row: self.search_url(row)) - - actions_layout.addWidget(edit_button) - actions_layout.addWidget(search_button) actions_layout.addWidget(delete_button) + actions_widget = QWidget() actions_widget.setLayout(actions_layout) + self.url_list.setCellWidget(row, 2, actions_widget) - # Hide row numbers in the table vertical_header = self.url_list.verticalHeader() vertical_header.setVisible(False) @@ -238,9 +252,8 @@ class URLManager(QWidget): settings = json.load(file) self.data_directory = settings['data_directory'] self.search_engine = settings['search_engine'] - self.date_format = settings.get('date_format', 'Nerdy') # Default to 'Nerdy' if not present + self.date_format = settings.get('date_format', 'Nerdy') else: - # Default settings self.data_directory = 'data/' self.search_engine = 'Google' self.date_format = 'Nerdy' @@ -253,22 +266,63 @@ class URLManager(QWidget): settings = { 'data_directory': self.data_directory, 'search_engine': self.search_engine, - 'date_format': self.date_format # Save date format setting + 'date_format': self.date_format } json.dump(settings, file) + def load_categories(self): + self.groups = set() + categories_path = os.path.join(self.data_directory, 'categories.json') + if os.path.exists(categories_path): + with open(categories_path, 'r') as file: + self.groups = set(json.load(file)) + self.update_group_combobox() + self.group_combobox.setCurrentText("Default Category") + + def save_categories(self): + categories_path = os.path.join(self.data_directory, 'categories.json') + os.makedirs(os.path.dirname(categories_path), exist_ok=True) + with open(categories_path, 'w') as file: + json.dump(list(self.groups), file) + + def update_group_combobox(self): + self.group_combobox.clear() + self.group_combobox.addItem("All Categories") + self.group_combobox.addItem("Default Category") + for group in sorted(self.groups): + self.group_combobox.addItem(group) + + def save_category(self): + new_category = self.category_input.text().strip() + if new_category and new_category not in self.groups: + self.groups.add(new_category) + self.save_categories() + self.update_group_combobox() + self.category_input.clear() + def load_urls(self): - urls_path = os.path.join(self.data_directory, 'urls.json') - if os.path.exists(urls_path): - with open(urls_path, 'r') as file: - self.urls = json.load(file) - self.update_url_list() + self.urls = [] + for group in self.groups: + category_filename = self.get_category_filename(group) + category_path = os.path.join(self.data_directory, category_filename) + if os.path.exists(category_path): + with open(category_path, 'r') as file: + self.urls.extend(json.load(file)) + self.update_url_list() def save_urls(self): - urls_path = os.path.join(self.data_directory, 'urls.json') - os.makedirs(os.path.dirname(urls_path), exist_ok=True) - with open(urls_path, 'w') as file: - json.dump(self.urls, file) + for group in self.groups: + group_urls = [url for url in self.urls if url['group'] == group] + category_filename = self.get_category_filename(group) + category_path = os.path.join(self.data_directory, category_filename) + with open(category_path, 'w') as file: + json.dump(group_urls, file) + + def get_category_filename(self, category): + if ' ' in category: + return category.replace(' ', '_').lower() + '.json' + else: + return category.lower() + '.json' def show_info_dialog(self): dialog = QDialog(self) @@ -276,16 +330,13 @@ class URLManager(QWidget): layout = QVBoxLayout() - # SVG logo svg_widget = QSvgWidget('assets/logo.svg') svg_widget.setFixedSize(256, 256) layout.addWidget(svg_widget, alignment=Qt.AlignCenter) - # Written by label written_by_label = QLabel("Developed by Axel Rafn") layout.addWidget(written_by_label, alignment=Qt.AlignCenter) - # Link label link_label = QLabel() link_label.setText('git.axelrafn.is') link_label.setOpenExternalLinks(True) @@ -297,25 +348,22 @@ class URLManager(QWidget): def show_settings_dialog(self): dialog = SettingsDialog(self) if dialog.exec_() == QDialog.Accepted: - self.load_settings() # Reload settings if they were updated - self.update_url_list() # Update URL list to reflect new date format - + self.load_settings() + self.update_url_list() class SettingsDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("Settings") - self.setFixedWidth(360) # Set the width of the window to 360 pixels + self.setFixedWidth(360) self.parent = parent layout = QVBoxLayout() - # Data Directory label directory_label = QLabel("Data Directory:") layout.addWidget(directory_label) - # File/Directory selection layout directory_layout = QHBoxLayout() self.directory_input = QLineEdit(self.parent.data_directory) self.browse_button = QPushButton("Browse...") @@ -324,10 +372,8 @@ class SettingsDialog(QDialog): directory_layout.addWidget(self.browse_button) layout.addLayout(directory_layout) - # Add 4 pixels of empty space layout.addSpacerItem(QSpacerItem(0, 4, QSizePolicy.Minimum, QSizePolicy.Fixed)) - # Search engine selection form_layout = QFormLayout() self.search_engine_combobox = QComboBox() search_engines = sorted(self.parent.search_engines.keys()) @@ -335,7 +381,6 @@ class SettingsDialog(QDialog): self.search_engine_combobox.setCurrentText(self.parent.search_engine) form_layout.addRow("Search Engine:", self.search_engine_combobox) - # Date format selection self.date_format_combobox = QComboBox() self.date_format_combobox.addItems(["Nerdy", "Normal", "Murica!"]) self.date_format_combobox.setCurrentText(self.parent.date_format) @@ -343,7 +388,6 @@ class SettingsDialog(QDialog): layout.addLayout(form_layout) - # Save button self.save_button = QPushButton("Save") self.save_button.clicked.connect(self.save_settings) layout.addWidget(self.save_button)