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