| # 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. |
|
|