/ src / ThemeManager.h
ThemeManager.h
  1  #pragma once
  2  
  3  #include <string>
  4  #include <unordered_map>
  5  #include <vector>
  6  
  7  #include "Theme.h"
  8  
  9  /// Maximum number of themes that can be loaded/displayed
 10  constexpr int MAX_CACHED_THEMES = 16;
 11  
 12  /**
 13   * Singleton manager for theme loading and application.
 14   *
 15   * Loads themes from /themes/*.theme files on SD card.
 16   * Falls back to builtin themes when files are missing.
 17   *
 18   * Usage:
 19   *   THEME_MANAGER.loadTheme("dark");
 20   *   renderer.fillRect(x, y, w, h, THEME.selectionFillBlack);
 21   */
 22  class ThemeManager {
 23   public:
 24    static ThemeManager& instance();
 25  
 26    /**
 27     * Load a theme by name.
 28     * Looks for /themes/<name>.theme on SD card.
 29     * Falls back to builtin theme if file not found.
 30     *
 31     * @param themeName Name of the theme (without .theme extension)
 32     * @return true if loaded from file, false if using builtin fallback
 33     */
 34    bool loadTheme(const char* themeName);
 35  
 36    /**
 37     * Save current theme to file.
 38     * @param themeName Name for the theme file
 39     * @return true if saved successfully
 40     */
 41    bool saveTheme(const char* themeName);
 42  
 43    /**
 44     * Get the currently active theme.
 45     */
 46    const Theme& current() const { return activeTheme; }
 47  
 48    /**
 49     * Get mutable reference to current theme for modifications.
 50     */
 51    Theme& mutableCurrent() { return activeTheme; }
 52  
 53    /**
 54     * Apply builtin light theme.
 55     */
 56    void applyLightTheme();
 57  
 58    /**
 59     * Apply builtin dark theme.
 60     */
 61    void applyDarkTheme();
 62  
 63    /**
 64     * List available theme files on SD card.
 65     * Also pre-caches theme configurations for instant switching.
 66     * @param forceRefresh If true, clears cache and reloads all themes from disk
 67     * @return Vector of theme names (without .theme extension)
 68     */
 69    std::vector<std::string> listAvailableThemes(bool forceRefresh = false);
 70  
 71    /**
 72     * Apply a cached theme instantly (no file I/O).
 73     * Use after listAvailableThemes() has been called.
 74     * @param themeName Name of the theme
 75     * @return true if theme was found in cache and applied
 76     */
 77    bool applyCachedTheme(const char* themeName);
 78  
 79    /**
 80     * Check if a theme is cached.
 81     */
 82    bool isThemeCached(const char* themeName) const;
 83  
 84    /**
 85     * Clear the theme cache to free memory.
 86     * Call before entering memory-intensive states.
 87     */
 88    void clearCache() { themeCache.clear(); }
 89  
 90    /**
 91     * Create default theme files on SD card if they don't exist.
 92     * Called during boot to give users template files to edit.
 93     */
 94    void createDefaultThemeFiles();
 95  
 96    /**
 97     * Get the current theme name.
 98     */
 99    const char* currentThemeName() const { return themeName; }
100  
101   private:
102    ThemeManager();
103    ~ThemeManager() = default;
104    ThemeManager(const ThemeManager&) = delete;
105    ThemeManager& operator=(const ThemeManager&) = delete;
106  
107    bool loadFromFile(const char* path);
108    bool loadFromFileToTheme(const char* path, Theme& theme);
109    bool saveToFile(const char* path, const Theme& theme);
110  
111    Theme activeTheme;
112    char themeName[32];
113    std::unordered_map<std::string, Theme> themeCache;
114  };
115  
116  // Convenience macros
117  #define THEME_MANAGER ThemeManager::instance()
118  #define THEME ThemeManager::instance().current()