feat: refactor settings UI with category navigation and add Delimiters page

Closes #640

## Changes

### UI Refactoring
- Replace monolithic settings dialog with category-based navigation
- Add QListWidget (lw_categories) for category selection on the left
- Add QStackedWidget (sw_categories) for content pages on the right
- Organize settings into 5 distinct pages:
  - Flags (14 checkboxes)
  - Quality (3 combo boxes)
  - Numbers (2 spin boxes)
  - Paths & Formats (7 line edits + 2 browse buttons)
  - Delimiters (4 line edits) — NEW

### New Feature: Delimiters Category
- Add customizable separators for artists in metadata and filenames:
  - metadata_delimiter_artist
  - metadata_delimiter_album_artist
  - filename_delimiter_artist
  - filename_delimiter_album_artist
- Auto-integration with DialogPreferences via parameters_line_edit
- Line edits with max width 100px for compact display

### Styling
- Apply dark theme to settings dialog:
  - Category list: #2b2b2b background, #3d5a80 selection, #3a3a3a hover
  - Settings area: #333333 background, styled GroupBoxes (#3a3a3a)
  - Light text (#e0e0e0) for better contrast
- Add spacing property (6px) to category list for better readability
- Style QListWidget items with padding (4px 3px) and margin (2px 0px)

### Testing
- Add comprehensive test suite (61 tests total):
  - test_settings_ui.py: UI and basic integration (14 tests)
  - test_settings_dialog_structure.py: detailed structure validation (20 tests)
  - test_dialog_preferences_integration.py: DialogPreferences integration (14 tests)
  - test_delimiters_category.py: new Delimiters page validation (13 tests)
- Fix ruff issues (F841, S108) in test files
- All tests passing with 100% success rate

### Documentation
- Add docs/refactor_settings_ui.md: comprehensive refactor overview
- Add docs/delimiters_category.md: Delimiters feature documentation
- Add docs/ui_styles.md: dark theme style guide
- Add docs/testing_summary.md: testing overview and commands

### Code Quality
- Apply ruff/black/pyupgrade via pre-commit hooks
- Fix F841 (unused variable) in test_dialog_preferences_integration.py
- Fix S108 (insecure temp path) using Path.home() in test_settings_ui.py
- End-of-file fixes applied automatically

## Files Modified
- tidal_dl_ng/ui/dialog_settings.ui (complete restructure)
- tidal_dl_ng/ui/dialog_settings.py (auto-generated from .ui)
- tidal_dl_ng/dialog.py (add 4 delimiter params + Delimiters category)
- tests/* (4 new test files with 61 tests)
- docs/* (4 new documentation files)

## Impact
- Improved UX: intuitive category navigation, better visual organization
- Extensibility: easy to add new settings pages/categories
- Quality: comprehensive test coverage ensures robustness
- User flexibility: customizable separators for metadata and filenames

## Technical Notes
- QStackedWidget pages indexed 0-4 matching category list order
- Navigation via QListWidget::currentRowChanged signal
- Automatic save/load through existing DialogPreferences methods
- No breaking changes to existing settings or configuration

## Testing Commands
```powershell
poetry run pre-commit run -a
poetry run pytest -q
This commit is contained in:
Warry
2025-11-30 15:37:32 +01:00
parent 28a6fe5a7d
commit 121dbb788d
13 changed files with 3057 additions and 847 deletions
+27
View File
@@ -144,6 +144,10 @@ class DialogPreferences(QtWidgets.QDialog):
# Run the .setupUi() method to show the GUI
self.ui.setupUi(self)
# Initialize categories
self._init_categories()
# Set data.
self.gui_populate()
# Post setup
@@ -159,6 +163,10 @@ class DialogPreferences(QtWidgets.QDialog):
"format_track",
"format_video",
"path_binary_ffmpeg",
"metadata_delimiter_artist",
"metadata_delimiter_album_artist",
"filename_delimiter_artist",
"filename_delimiter_album_artist",
]
def _init_spin_box(self):
@@ -189,6 +197,25 @@ class DialogPreferences(QtWidgets.QDialog):
"playlist_create",
]
def _init_categories(self):
"""Initialize the categories list and connect to page switching."""
# Add categories to the list
self.ui.lw_categories.addItem("Flags")
self.ui.lw_categories.addItem("Quality")
self.ui.lw_categories.addItem("Numbers")
self.ui.lw_categories.addItem("Paths & Formats")
self.ui.lw_categories.addItem("Delimiters")
# Set the first category as selected
self.ui.lw_categories.setCurrentRow(0)
# Connect category selection to page switching
self.ui.lw_categories.currentRowChanged.connect(self._on_category_changed)
def _on_category_changed(self, index: int):
"""Handle category change to switch pages."""
self.ui.sw_categories.setCurrentIndex(index)
def gui_populate(self):
self.populate_checkboxes()
self.populate_combo()