// ===== KIMI APPEARANCE MANAGER ===== class KimiAppearanceManager extends KimiBaseManager { constructor(database) { super(); this.db = database; this.currentTheme = "purple"; this.interfaceOpacity = 0.8; this.animationsEnabled = true; } async init() { try { await this.loadAppearanceSettings(); this.applyTheme(this.currentTheme); this.applyInterfaceOpacity(this.interfaceOpacity); this.applyAnimationSettings(this.animationsEnabled); this.setupAppearanceControls(); this.syncAnimationToggleState(); } catch (error) { console.error("KimiAppearanceManager initialization error:", error); } } syncAnimationToggleState() { const animationsToggle = document.getElementById("animations-toggle"); if (animationsToggle) { animationsToggle.classList.toggle("active", this.animationsEnabled); animationsToggle.setAttribute("aria-checked", this.animationsEnabled ? "true" : "false"); } } async loadAppearanceSettings() { if (!this.db) return; try { this.currentTheme = await this.db.getPreference("colorTheme", "purple"); this.interfaceOpacity = await this.db.getPreference("interfaceOpacity", 0.8); this.animationsEnabled = await this.db.getPreference("animationsEnabled", true); } catch (error) { console.error("Error loading appearance settings:", error); } } setupAppearanceControls() { try { this.setupThemeSelector(); this.setupOpacitySlider(); this.setupAnimationsToggle(); } catch (error) { console.error("Error setting up appearance controls:", error); } } setupThemeSelector() { const themeSelector = document.getElementById("color-theme"); if (!themeSelector) return; themeSelector.value = this.currentTheme; themeSelector.addEventListener("change", async e => { try { await this.changeTheme(e.target.value); } catch (error) { console.error("Error changing theme:", error); } }); } setupOpacitySlider() { const opacitySlider = document.getElementById("interface-opacity"); const opacityValue = document.getElementById("interface-opacity-value"); if (!opacitySlider || !opacityValue) return; opacitySlider.value = this.interfaceOpacity; opacityValue.textContent = this.interfaceOpacity; opacitySlider.addEventListener("input", async e => { try { const value = parseFloat(e.target.value); opacityValue.textContent = value; await this.changeInterfaceOpacity(value); } catch (error) { console.error("Error changing opacity:", error); } }); } setupAnimationsToggle() { const animationsToggle = document.getElementById("animations-toggle"); if (!animationsToggle) return; animationsToggle.classList.toggle("active", this.animationsEnabled); animationsToggle.setAttribute("aria-checked", this.animationsEnabled ? "true" : "false"); // Remove any existing listener to prevent conflicts if (this._animationsClickHandler) { animationsToggle.removeEventListener("click", this._animationsClickHandler); } this._animationsClickHandler = async () => { try { this.animationsEnabled = !this.animationsEnabled; animationsToggle.classList.toggle("active", this.animationsEnabled); animationsToggle.setAttribute("aria-checked", this.animationsEnabled ? "true" : "false"); await this.toggleAnimations(this.animationsEnabled); } catch (error) { console.error("Error toggling animations:", error); } }; animationsToggle.addEventListener("click", this._animationsClickHandler); } async changeTheme(theme) { try { this.currentTheme = theme; this.applyTheme(theme); if (this.db) { await this.db.setPreference("colorTheme", theme); } } catch (error) { console.error("Error changing theme:", error); } } async changeInterfaceOpacity(opacity) { try { const validatedOpacity = window.KimiValidationUtils?.validateRange(opacity, "interfaceOpacity"); const finalOpacity = validatedOpacity?.valid ? validatedOpacity.value : opacity; this.interfaceOpacity = finalOpacity; this.applyInterfaceOpacity(finalOpacity); if (this.db) { await this.db.setPreference("interfaceOpacity", finalOpacity); } } catch (error) { console.error("Error changing interface opacity:", error); } } async toggleAnimations(enabled) { try { this.animationsEnabled = enabled; this.applyAnimationSettings(enabled); if (this.db) { await this.db.setPreference("animationsEnabled", enabled); } } catch (error) { console.error("Error toggling animations:", error); } } applyTheme(theme) { document.documentElement.setAttribute("data-theme", theme); } applyInterfaceOpacity(opacity) { document.documentElement.style.setProperty("--interface-opacity", opacity); } applyAnimationSettings(enabled) { document.documentElement.setAttribute("data-animations", enabled ? "true" : "false"); document.documentElement.style.setProperty("--animations-enabled", enabled ? "1" : "0"); // Ensure body class reflects animation state if (enabled) { document.body.classList.remove("no-animations"); document.body.classList.add("animations-enabled"); } else { document.body.classList.remove("animations-enabled"); document.body.classList.add("no-animations"); } } cleanup() { const animationsToggle = document.getElementById("animations-toggle"); if (animationsToggle && this._animationsClickHandler) { animationsToggle.removeEventListener("click", this._animationsClickHandler); this._animationsClickHandler = null; } } getThemeName(theme) { const themeNames = { dark: "Dark Night", default: "Passionate Pink", blue: "Ocean Blue", purple: "Mystic Purple", green: "Emerald Forest" }; return themeNames[theme] || "Unknown"; } forceSyncUIState() { // Force synchronization of UI state to prevent inconsistencies const animationsToggle = document.getElementById("animations-toggle"); if (animationsToggle) { // Remove any conflicting classes or states animationsToggle.classList.remove("active"); // Re-apply correct state animationsToggle.classList.toggle("active", this.animationsEnabled); animationsToggle.setAttribute("aria-checked", this.animationsEnabled ? "true" : "false"); // Ensure CSS custom properties are in sync this.applyAnimationSettings(this.animationsEnabled); } } } window.KimiAppearanceManager = KimiAppearanceManager;