File size: 5,062 Bytes
3d50167
 
 
 
 
b0c5e01
3d50167
a9d1590
3d50167
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b0c5e01
8c89f37
 
 
 
a9d1590
3d50167
 
 
 
 
 
 
 
 
a9d1590
3d50167
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a40f14d
 
 
3d50167
 
 
a9d1590
3d50167
 
 
 
 
b0c5e01
3d50167
 
 
 
 
 
 
 
 
a40f14d
 
3d50167
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// ===== KIMI APPEARANCE MANAGER =====
class KimiAppearanceManager extends KimiBaseManager {
    constructor(database) {
        super();
        this.db = database;
        this.currentTheme = "dark";
        this.interfaceOpacity = 0.8;
        // Animations are enabled by default; the UI no longer exposes a toggle
        this.animationsEnabled = true;
    }

    async init() {
        try {
            await this.loadAppearanceSettings();
            this.applyTheme(this.currentTheme);
            this.applyInterfaceOpacity(this.interfaceOpacity);
            this.applyAnimationSettings(this.animationsEnabled);
            this.setupAppearanceControls();
        } catch (error) {
            console.error("KimiAppearanceManager initialization error:", error);
        }
    }

    async loadAppearanceSettings() {
        if (!this.db) return;

        try {
            this.currentTheme = await this.db.getPreference("colorTheme", window.KIMI_CONFIG?.DEFAULTS?.THEME ?? "dark");
            this.interfaceOpacity = await this.db.getPreference(
                "interfaceOpacity",
                window.KIMI_CONFIG?.DEFAULTS?.INTERFACE_OPACITY ?? 0.8
            );
            // Animations preference is not configurable via UI and remain enabled
        } catch (error) {
            console.error("Error loading appearance settings:", error);
        }
    }

    setupAppearanceControls() {
        try {
            this.setupThemeSelector();
            this.setupOpacitySlider();
            // No animations toggle in appearance controls
        } 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);
            }
        });
    }

    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);
        }
    }

    applyTheme(theme) {
        document.documentElement.setAttribute("data-theme", theme);
    }

    applyInterfaceOpacity(opacity) {
        document.documentElement.style.setProperty("--interface-opacity", opacity);
    }

    applyAnimationSettings(enabled) {
        // Force-enable animations by default; CSS now respects prefers-reduced-motion.
        document.documentElement.style.setProperty("--animations-enabled", "1");
        document.body.classList.add("animations-enabled");
    }

    cleanup() {
        // No animations toggle to clean up
    }

    getThemeName(theme) {
        const themeNames = {
            dark: "Dark Night",
            pink: "Passionate Pink",
            blue: "Ocean Blue",
            purple: "Mystic Purple",
            green: "Emerald Forest"
        };
        return themeNames[theme] || "Unknown";
    }

    forceSyncUIState() {
        // Force synchronization of UI state to prevent inconsistencies
        // Ensure CSS custom properties are in sync
        this.applyAnimationSettings(this.animationsEnabled);
    }
}

window.KimiAppearanceManager = KimiAppearanceManager;