config.py
1 import collections 2 import json 3 from pathlib import Path 4 from typing import Any, Iterable, List 5 6 from aqt import QComboBox, QPushButton, colors 7 from aqt.theme import theme_manager 8 from aqt.utils import openLink, tooltip 9 10 from .ankiaddonconfig import ConfigLayout, ConfigManager, ConfigWindow 11 from .colors import recolor_python, recolor_web 12 from .migrate import maybe_migrate_config 13 14 THEMES_DIR = Path(__file__).parent / "themes" 15 16 17 conf = ConfigManager() 18 19 20 def open_web(url: str) -> None: 21 openLink(f"https://{url}") 22 23 24 def on_save() -> None: 25 conf.save() 26 recolor_python() 27 recolor_web() 28 29 30 def with_window(conf_window: ConfigWindow) -> None: 31 conf_window.setWindowTitle("recolor-debloated Settings") 32 conf_window.setMinimumWidth(500) 33 conf_window.execute_on_save(on_save) 34 conf_window.after_advanced_save_hook.append(lambda: maybe_migrate_config(conf)) 35 36 37 def color_idx() -> int: 38 return 2 if theme_manager.night_mode else 1 39 40 41 def populate_tab(layout: ConfigLayout, conf_keys: List[str]) -> None: 42 for conf_key in conf_keys: 43 name = conf.get(f"colors.{conf_key}.0") 44 anki_color = getattr(colors, conf_key, None) 45 description = anki_color["comment"] if anki_color is not None else None 46 layout.color_input( 47 f"colors.{conf_key}.{color_idx()}", name, tooltip=description, opacity=True 48 ) 49 layout.stretch() 50 51 52 def main_tab(conf_window: ConfigWindow) -> None: 53 conf_keys = [ 54 "FG", 55 "FG_SUBTLE", 56 "FG_DISABLED", 57 "FG_FAINT", 58 "FG_LINK", 59 "CANVAS", 60 "CANVAS_ELEVATED", 61 "CANVAS_INSET", 62 "CANVAS_OVERLAY", 63 "CANVAS_CODE", 64 "BORDER", 65 "BORDER_SUBTLE", 66 "BORDER_STRONG", 67 "BORDER_FOCUS", 68 ] 69 tab = conf_window.add_tab("Main") 70 populate_tab(tab, conf_keys) 71 72 73 def buttons_tab(conf_window: ConfigWindow) -> None: 74 conf_keys = [ 75 "BUTTON_BG", 76 "BUTTON_HOVER", 77 "BUTTON_HOVER_BORDER", 78 "BUTTON_DISABLED", 79 ] 80 tab = conf_window.add_tab("Buttons") 81 populate_tab(tab, conf_keys) 82 83 84 def cards_tab(conf_window: ConfigWindow) -> None: 85 conf_keys = [ 86 "STATE_NEW", 87 "STATE_LEARN", 88 "STATE_REVIEW", 89 "STATE_SUSPENDED", 90 "STATE_BURIED", 91 "FLAG_1", 92 "FLAG_2", 93 "FLAG_3", 94 "FLAG_4", 95 "FLAG_5", 96 "FLAG_6", 97 "FLAG_7", 98 "ACCENT_CARD", 99 "ACCENT_NOTE", 100 ] 101 tab = conf_window.add_tab("Cards") 102 populate_tab(tab, conf_keys) 103 104 105 def misc_tab(conf_window: ConfigWindow) -> None: 106 conf_keys = [ 107 "HIGHLIGHT_BG", 108 "HIGHLIGHT_FG", 109 "SELECTED_BG", 110 "SELECTED_FG", 111 "ACCENT_DANGER", 112 "SHADOW", 113 "SHADOW_INSET", 114 "SHADOW_SUBTLE", 115 "SHADOW_FOCUS", 116 "SCROLLBAR_BG", 117 "SCROLLBAR_BG_ACTIVE", 118 "SCROLLBAR_BG_HOVER", 119 ] 120 tab = conf_window.add_tab("Misc") 121 populate_tab(tab, conf_keys) 122 123 124 def themes_list() -> list[str]: 125 themes: list[str] = [] 126 for child in sorted(THEMES_DIR.iterdir()): 127 if child.is_file() and child.suffix == ".json": 128 themes.append(child.stem) 129 return themes 130 131 132 def replace_conf_color(conf: ConfigManager, theme_json: Any, dark_mode: bool) -> None: 133 modeidx = 2 if dark_mode else 1 134 135 for color in theme_json["colors"]: 136 conf[f"colors.{color}.{modeidx}"] = theme_json["colors"][color][modeidx] 137 138 139 def apply_theme(conf_window: ConfigWindow, theme: str) -> None: 140 theme_path = THEMES_DIR / f"{theme}.json" 141 theme_json = json.loads(theme_path.read_text()) 142 143 # Dark mode or universal 144 if not theme.startswith("(dark)"): 145 replace_conf_color(conf, theme_json, False) 146 # Light mode or universal 147 if not theme.startswith("(light)"): 148 replace_conf_color(conf, theme_json, True) 149 150 conf_window.update_widgets() 151 conf_window.main_tab.setCurrentIndex(0) 152 153 tooltip(f"Applied theme: {theme}<br />Press save to save changes") 154 155 156 def themes_tab(conf_window: ConfigWindow) -> None: 157 tab = conf_window.add_tab("Themes") 158 tab.space(10) 159 160 tab.text( 161 "Note: You may need to toggle dark mode in Anki preferences to see changes", 162 multiline=True, 163 ) 164 165 apply_lay = tab.hlayout() 166 apply_lay.text("Themes:") 167 apply_lay.space(10) 168 169 combobox = QComboBox(conf_window) 170 combobox.insertItems(0, themes_list()) 171 172 apply_lay.addWidget(combobox) 173 174 btn = QPushButton("Apply theme", conf_window) 175 btn.clicked.connect(lambda _: apply_theme(conf_window, combobox.currentText())) 176 apply_lay.addWidget(btn) 177 apply_lay.stretch() 178 179 tab.stretch() 180 181 182 conf.use_custom_window() 183 conf.on_window_open(with_window) 184 conf.add_config_tab(main_tab) 185 conf.add_config_tab(buttons_tab) 186 conf.add_config_tab(cards_tab) 187 conf.add_config_tab(misc_tab) 188 conf.add_config_tab(themes_tab)