File size: 2,852 Bytes
a5784e9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
GUI Launcher Theme Manager

Handles light/dark mode switching with persistence.
"""

from typing import Callable, List, Literal

import customtkinter as ctk

# Type alias for appearance modes
AppearanceMode = Literal["dark", "light", "system"]

# Module-level state
_current_mode: AppearanceMode = "dark"
_on_change_callbacks: List[Callable[[AppearanceMode], None]] = []


def get_appearance_mode() -> AppearanceMode:
    """Get the current appearance mode."""
    return _current_mode


def set_appearance_mode(mode: AppearanceMode) -> None:
    """
    Set the appearance mode and apply it.

    Args:
        mode: One of "dark", "light", or "system"
    """
    global _current_mode

    if mode not in ("dark", "light", "system"):
        mode = "dark"  # Default fallback

    _current_mode = mode
    ctk.set_appearance_mode(mode)

    # Notify listeners
    for callback in _on_change_callbacks:
        try:
            callback(mode)
        except Exception:
            pass


def toggle_appearance_mode() -> AppearanceMode:
    """
    Toggle between dark and light mode.

    Returns:
        The new appearance mode after toggle
    """
    if _current_mode == "dark":
        set_appearance_mode("light")
    else:
        set_appearance_mode("dark")

    return _current_mode


def is_dark_mode() -> bool:
    """Check if currently in dark mode."""
    if _current_mode == "system":
        # Check actual system setting
        return ctk.get_appearance_mode().lower() == "dark"
    return _current_mode == "dark"


def on_theme_change(callback: Callable[[AppearanceMode], None]) -> None:
    """
    Register a callback to be called when theme changes.

    Args:
        callback: Function that takes the new mode as argument
    """
    if callback not in _on_change_callbacks:
        _on_change_callbacks.append(callback)


def remove_theme_callback(callback: Callable[[AppearanceMode], None]) -> None:
    """Remove a previously registered callback."""
    if callback in _on_change_callbacks:
        _on_change_callbacks.remove(callback)


def get_mode_display_name(mode: AppearanceMode) -> str:
    """
    Get a user-friendly display name for the mode.

    Args:
        mode: The appearance mode

    Returns:
        Display name with emoji
    """
    names = {
        "dark": "🌙 Dark",
        "light": "☀️ Light",
        "system": "💻 System",
    }
    return names.get(mode, mode)


def get_available_modes() -> List[AppearanceMode]:
    """Get list of available appearance modes."""
    return ["dark", "light", "system"]


# Initialize with CustomTkinter's default
def init_theme(mode: AppearanceMode = "dark") -> None:
    """
    Initialize the theme system.

    Should be called once at application startup.

    Args:
        mode: Initial appearance mode
    """
    set_appearance_mode(mode)