wrdler / specs /settings.md
Surn's picture
v0.2.8 Settings Page fixed
f0df64e
# Settings Page Refactoring Plan
## Goal
Move the sidebar configuration controls (`_render_sidebar`) from `wrdler/ui.py` to a dedicated Settings page (`wrdler/settings_page.py`), accessible via the footer navigation.
## Files to Create
1. `wrdler/settings_page.py`
## Files to Modify
1. `wrdler/ui.py`
## Detailed Steps
### 1. Create `wrdler/settings_page.py`
This file will encapsulate the rendering logic for the settings.
- **Imports**:
- `streamlit as st`
- `os`
- `time`
- From `wrdler.word_loader`: `get_wordlist_files`, `get_wordlist_info`
- From `wrdler.generator`: `sort_word_file`, `filter_word_file`
- From `wrdler.audio`: `get_audio_tracks`, `_inject_audio_control_sync`
- From `wrdler.version_info`: `versions_html`
- **Functions**:
- `render_settings_page(new_game_callback)`:
- Renders the title "Settings".
- Contains the logic previously in `_render_sidebar` (Game Mode, Wordlist Controls, Grid Options, Audio Controls).
- **Important**: Does *not* include `_mount_background_audio` (this will be global).
- Uses `st.container` or main layout instead of `st.sidebar`.
- Accepts `new_game_callback` to trigger a game reset when settings change.
- `_sort_wordlist(filename)`: Moved from `ui.py`.
- `_filter_wordlist(filename)`: Moved from `ui.py`.
- `_filter_results_dialog`: Moved from `ui.py` (if used by `_filter_wordlist`).
- Local callbacks `_on_wordlist_change` and `_on_ai_generate` that utilize `new_game_callback`.
### 2. Modify `wrdler/ui.py`
- **Extract Audio Logic**:
- Create a helper function `_handle_audio()` that contains the audio initialization and mounting logic previously in `_render_sidebar`.
- This ensures audio persists across pages.
- **Update `run_app()`**:
- Call `_handle_audio()` at the top level (before page routing).
- Add routing logic for `page="settings"`:
- Import `render_settings_page`.
- Render background.
- Call `render_settings_page(_on_game_option_change)`.
- Render footer with `current_page="settings"`.
- Return (stop execution of main game).
- Remove `_render_sidebar()` call.
- **Update `_render_footer()`**:
- Add a link to `?page=settings` with label "?? Settings".
- Highlight it when `current_page="settings"`.
- **Cleanup**:
- Remove `_render_sidebar` function.
- Remove `_sort_wordlist`, `_filter_wordlist` (moved to settings page).
## Implementation Notes
- **Audio**: The audio *controls* (volume, track) will be in the Settings page, but the audio *player* (hidden HTML/JS) must be mounted on every page load via `_handle_audio()` in `run_app` to ensure continuous playback or proper state.
- **Callbacks**: `_on_game_option_change` in `ui.py` calls `_new_game`. This callback will be passed to `render_settings_page` so that changing settings triggers the necessary state resets.
- **Navigation**: The footer will serve as the primary navigation between "Play", "Leaderboard", and "Settings".
---
## Settings Persistence Guidance (UPDATED)
- **Each settings configuration is saved as a separate JSON file in `wrdler/settings/`, not as a single large file.**
- **File naming convention:** Use a unique, human-readable key based on the main settings (e.g., `classic-classic-0.json`).
- Example: `wrdler/settings/classic-classic-0.json`
- This mirrors the leaderboard's convention (e.g., `weekly/2025-W51/classic-classic-0/settings.json`), but is local and not required to match challenge/leaderboard config structure.
- **Settings files should use the same layout as the current settings.json, but each file only contains one configuration.**
- **No need to match leaderboard or challenge settings.json structure exactly.**
- **When saving settings, only the relevant configuration for that file is written.**
- **When loading, look up the file by its unique key.**
- **This approach supports local wordlists and ensures settings are unique per instance.**
---
## Plan: Local Settings File Storage and Loading (Implemented in v0.2.8)
1. **Settings File Naming**
- For each unique settings configuration, generate a filename like `classic-classic-0.json` based on the main settings (e.g., game mode, wordlist, spacer).
- Store these files in `wrdler/settings/`.
2. **Saving Settings**
- When the user clicks "Save Settings" in the settings page:
- Gather all relevant settings from `st.session_state`.
- Generate the unique filename for the current configuration.
- Save the settings as a JSON file in `wrdler/settings/` using the generated filename.
- Use the same JSON structure as the current settings.json, but only for this configuration.
3. **Loading Settings in `wrdler/ui.py`**
- On app startup (in `_init_session()` or before applying defaults):
- Determine the intended settings file (e.g., from defaults or user selection).
- If the file exists in `wrdler/settings/`, load it and update `st.session_state` with its values (only for keys not already set).
- If not, proceed with defaults.
4. **Settings Page Integration**
- The settings page should allow users to select, save, and load settings configurations by their unique keys.
- Optionally, provide a dropdown or list of available settings files for quick switching.
5. **Directory Management**
- Ensure the `wrdler/settings/` directory is created if it does not exist.
- Handle file I/O errors gracefully and inform the user if saving/loading fails.
6. **Extensibility**
- When new settings are added, include them in the filename generation and JSON structure as needed.
- This approach allows for easy expansion as more settings or wordlists are introduced.