diff options
author | Thanos Apollo <[email protected]> | 2022-08-04 09:50:48 +0300 |
---|---|---|
committer | Thanos Apollo <[email protected]> | 2022-08-04 09:50:48 +0300 |
commit | 4ddb7273098bee179bb77e0937e560fc0100960c (patch) | |
tree | cebc2f9412e45910408a7885ca78d7dedb77de78 /.local/share/Anki2/addons21/anki_reworked | |
parent | e83759ae9d0513024e390810ddcb18ffdd84675e (diff) |
Add anki addons
Diffstat (limited to '.local/share/Anki2/addons21/anki_reworked')
33 files changed, 1931 insertions, 0 deletions
diff --git a/.local/share/Anki2/addons21/anki_reworked/__init__.py b/.local/share/Anki2/addons21/anki_reworked/__init__.py new file mode 100644 index 0000000..81b2627 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/__init__.py @@ -0,0 +1,705 @@ +import json +### Custom util functions +from .utils.modules import * +### Logger for debuging +from .utils.logger import logger + +from typing import Any, List, Optional +from PyQt5.QtWidgets import QWidget +from platform import system, version, release +from ctypes import * +# import the main window object (mw) from aqt +from aqt import AnkiQt, DialogManager, mw +from aqt.theme import theme_manager, colors +from aqt import gui_hooks +## QT dialog windows +# Browser import legacy check (2.1.22) +if module_exists("aqt.browser.browser"): + from aqt.browser.browser import Browser +else: + from aqt.browser import Browser +# DeckStats import legacy check +if module_has_attribute("aqt.stats", "NewDeckStats"): + from aqt.stats import DeckStats, NewDeckStats +else: + from aqt.stats import DeckStats +from aqt.addcards import AddCards +from aqt.editcurrent import EditCurrent +from aqt.about import ClosableQDialog +from aqt.preferences import Preferences +from aqt.addons import AddonsDialog +# FilteredDeckConfigDialog import non-legacy check +if module_exists("aqt.filtered_deck"): + from aqt.filtered_deck import FilteredDeckConfigDialog +# QT page views +from aqt.toolbar import Toolbar, TopToolbar +from aqt.deckbrowser import DeckBrowser, DeckBrowserBottomBar +from aqt.overview import Overview, OverviewBottomBar +from aqt.editor import Editor +from aqt.reviewer import Reviewer, ReviewerBottomBar +from aqt.webview import AnkiWebView, WebContent + +### Load config data here +from .config import config, write_config, get_config + +## Addon compatibility fixes +# More Overview Stats 2.1 addon compatibility fix +addon_more_overview_stats_fix = config['addon_more_overview_stats'] +addon_advanced_review_bottom_bar = config['addon_advanced_review_bottom_bar'] + +## Customization +theme = config['theme'] +# Init script/file path +from .utils.css_files import css_files_dir +from .utils.themes import themes, write_theme, get_theme +logger.debug(css_files_dir) +logger.debug(themes) +themes_parsed = get_theme(theme) +color_mode = 2 if theme_manager.get_night_mode() else 1 # 1 = light and 2 = dark + +dwmapi = None +## Darkmode windows titlebar thanks to miere43 +def set_dark_titlebar(window, dwmapi) -> None: + if dwmapi: + handler_window = c_void_p(int(window.winId())) + DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = c_int(19) + DWMWA_USE_IMMERSIVE_DARK_MODE = c_int(20) + windows_version = int(version().split('.')[2]) + attribute = DWMWA_USE_IMMERSIVE_DARK_MODE if windows_version >= 18985 else DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 + if windows_version >= 17763 and int(release()) >= 10: + dwmapi.DwmSetWindowAttribute(handler_window, attribute, byref(c_int(1)), c_size_t(4)) +def set_dark_titlebar_qt(obj, dwmapi, fix=True) -> None: + if dwmapi and theme_manager.get_night_mode(): + set_dark_titlebar(obj, dwmapi) + # Trick to refresh the titlebar after dark titlebar is set + if fix: + obj.showFullScreen() + obj.showNormal() +if system() == "Windows" and theme_manager.get_night_mode(): + dwmapi = WinDLL("dwmapi") + if dwmapi: + dwmapi.DwmSetWindowAttribute.argtypes = [c_void_p, c_int, c_void_p, c_size_t] + dwmapi.DwmSetWindowAttribute.restype = c_int + set_dark_titlebar(mw, dwmapi) +logger.debug(dwmapi) + +### CSS injections +def load_custom_style(): + theme_colors = "" + for color_name in themes_parsed.get("colors"): + color = themes_parsed.get("colors").get(color_name) + if color[3]: + theme_colors += f"{color[3]}: {color[color_mode]};\n " + else: + theme_colors += f"--{color_name.lower().replace('_','-')}: {color[color_mode]};\n " + custom_style = """ +<style> + :root, + :root .isMac, + :root .isWin, + :root .isLin { + %s + } + html { + font-family: %s; + font-size: %spx; + } +</style> + """ % (theme_colors, config["font"], config["font_size"]) + return custom_style + +## Adds styling on the different webview contents, before the content is set +def on_webview_will_set_content(web_content: WebContent, context: Optional[Any]) -> None: + logger.debug(context) # Logs content being loaded, find out the instance + web_content.css.append(css_files_dir['global']) # Global css + web_content.head += load_custom_style() # Custom styling + # Deckbrowser + if isinstance(context, DeckBrowser): + web_content.css.append(css_files_dir['DeckBrowser']) + # TopToolbar + elif isinstance(context, TopToolbar): + web_content.css.append(css_files_dir['TopToolbar']) + # BottomToolbar (Buttons) + elif isinstance(context, DeckBrowserBottomBar) or isinstance(context, OverviewBottomBar): + web_content.css.append(css_files_dir['BottomBar']) + # Overview + elif isinstance(context, Overview): + if addon_more_overview_stats_fix: + web_content.head += "<style>center > table tr:first-of-type {display: table-row; flex-direction: unset;}</style>" + web_content.css.append(css_files_dir['Overview']) + # Editor + elif isinstance(context, Editor): + web_content.css.append(css_files_dir['Editor']) + # Reviewer + elif isinstance(context, Reviewer): + web_content.css.append(css_files_dir['Reviewer']) + elif isinstance(context, ReviewerBottomBar): + if addon_advanced_review_bottom_bar: + #web_content.head += "<style>td.stat[align='left']:nth-of-type(2) {position: absolute; z-index: 1;}</style>" + web_content.body += "<script>const center = document.getElementById('outer');center.classList.add('arbb');</script>" + else: + web_content.css.append(css_files_dir['BottomBar']) + web_content.css.append(css_files_dir['ReviewerBottomBar']) + # Button padding bottom + web_content.body += "<div style='height: 9px; opacity: 0; pointer-events: none;'></div>" + web_content.body += "<div id='padFix' style='height: 30px; opacity: 0; pointer-events: none;'><script>const e = document.getElementById('padFix');e.parentElement.removeChild(e);</script></div>" + mw.bottomWeb.adjustHeightToFit() + # CardLayout + elif context_name_includes(context, "aqt.clayout.CardLayout"): + web_content.css.append(css_files_dir['CardLayout']) + ## Legacy webviews + # ResetRequired on card edit (legacy) + elif context_name_includes(context, "aqt.main.ResetRequired"): + web_content.css.append(css_files_dir['legacy']) +gui_hooks.webview_will_set_content.append(on_webview_will_set_content) + +# TopToolbar styling fix through height change by adding <br> tag +def redraw_toolbar() -> None: + # Reload the webview content with added <br/> tag, making the bar larger in height + mw.toolbar.web.setFixedHeight(60) + mw.toolbar.web.eval(""" + var br = document.createElement("br"); + document.body.appendChild(br); + """) + + if 'Qt6' in QPalette.ColorRole.__module__: + mw.toolbar.web.eval(""" + var div = document.createElement("div"); + div.style.width = "5px"; + div.style.height = "10px"; + document.body.appendChild(div); + """) + # Auto adjust the height, then redraw the toolbar + mw.toolbar.web.adjustHeightToFit() + mw.toolbar.redraw() + +def redraw_toolbar_legacy(links: List[str], _: Toolbar) -> None: + # Utilizing the link hook, we inject <br/> tag through javascript + inject_br = """ + <script> + while (document.body.querySelectorAll("br").length > 1) + document.body.querySelectorAll("br")[0].remove(); + var br = document.createElement("br"); + document.body.appendChild(br); + </script> + """ + mw.toolbar.web.setFixedHeight(60) + links.append(inject_br) + mw.toolbar.web.adjustHeightToFit() + +if attribute_exists(gui_hooks, "main_window_did_init"): + pass + #gui_hooks.main_window_did_init.append(redraw_toolbar) +elif attribute_exists(gui_hooks, "top_toolbar_did_init_links"): + gui_hooks.top_toolbar_did_init_links.append(redraw_toolbar_legacy) + pass + +# Dialog window styling +def on_dialog_manager_did_open_dialog(dialog_manager: DialogManager, dialog_name: str, dialog_instance: QWidget) -> None: + logger.debug(dialog_name) + dialog: AnkiQt = dialog_manager._dialogs[dialog_name][1] + # If dwmapi found and nightmode is enabled, set dark titlebar to dialog window + set_dark_titlebar_qt(dialog, dwmapi) + # AddCards + if dialog_name == "AddCards": + context: AddCards = dialog_manager._dialogs[dialog_name][1] + context.setStyleSheet(open(css_files_dir['QAddCards'], encoding='utf-8').read()) + # Addons popup + elif dialog_name == "AddonsDialog": + context: AddonsDialog = dialog_manager._dialogs[dialog_name][1] + context.setStyleSheet(open(css_files_dir['QAddonsDialog'], encoding='utf-8').read()) + # Browser + elif dialog_name == "Browser": + context: Browser = dialog_manager._dialogs[dialog_name][1] + context.setStyleSheet(open(css_files_dir['QBrowser'], encoding='utf-8').read()) + pass + # EditCurrent + elif dialog_name == "EditCurrent": + context: EditCurrent = dialog_manager._dialogs[dialog_name][1] + context.setStyleSheet(open(css_files_dir['QEditCurrent'], encoding='utf-8').read()) + # FilteredDeckConfigDialog + elif module_exists("aqt.filtered_deck") and dialog_name == "FilteredDeckConfigDialog": + context: FilteredDeckConfigDialog = dialog_manager._dialogs[dialog_name][1] + context.setStyleSheet(open(css_files_dir['QFilteredDeckConfigDialog'], encoding='utf-8').read()) + # Statistics / NewDeckStats + elif dialog_name == "NewDeckStats": + context: NewDeckStats = dialog_manager._dialogs[dialog_name][1] + context.setStyleSheet(open(css_files_dir['QNewDeckStats'], encoding='utf-8').read()) + # About + elif dialog_name == "About": + context: ClosableQDialog = dialog_manager._dialogs[dialog_name][1] + context.setStyleSheet(open(css_files_dir['QAbout'], encoding='utf-8').read()) + # Preferences + elif dialog_name == "Preferences": + context: Preferences = dialog_manager._dialogs[dialog_name][1] + context.setStyleSheet(open(css_files_dir['QPreferences'], encoding='utf-8').read()) + # sync_log - kore ha nani desu??? + elif dialog_name == "sync_log": + pass + +if attribute_exists(gui_hooks, "dialog_manager_did_open_dialog"): + gui_hooks.dialog_manager_did_open_dialog.append(on_dialog_manager_did_open_dialog) +else: + ## Legacy dialog window styling + # Sad monkey patch, instead of hooks :c + # setupDialogGC is being called on almost all dialog windows, utilizing this, the + # function is used as a type of hook to inject CSS styling on the QT instances + def monkey_setup_dialog_gc(obj: Any) -> None: + obj.finished.connect(lambda: mw.gcWindow(obj)) + logger.debug(obj) + set_dark_titlebar_qt(obj, dwmapi) + # AddCards + if isinstance(obj, AddCards): + obj.setStyleSheet(open(css_files_dir['QAddCards'], encoding='utf-8').read()) + # EditCurrent + elif isinstance(obj, EditCurrent): + obj.setStyleSheet(open(css_files_dir['QEditCurrent'], encoding='utf-8').read()) + # Statistics / DeckStats + elif isinstance(obj, DeckStats): + obj.setStyleSheet(open(css_files_dir['QNewDeckStats'], encoding='utf-8').read()) + # About + elif isinstance(obj, ClosableQDialog): + obj.setStyleSheet(open(css_files_dir['QAbout'], encoding='utf-8').read()) + # Preferences + ## Haven't found a solution for preferences yet :c + mw.setupDialogGC = monkey_setup_dialog_gc # Should be rare enough for other addons to also patch this I hope. + + # Addons popup + if attribute_exists(gui_hooks, "addons_dialog_will_show"): + def on_addons_dialog_will_show(dialog: AddonsDialog) -> None: + logger.debug(dialog) + set_dark_titlebar_qt(dialog, dwmapi) + dialog.setStyleSheet(open(css_files_dir['QAddonsDialog'], encoding='utf-8').read()) + gui_hooks.addons_dialog_will_show.append(on_addons_dialog_will_show) + # Browser + if attribute_exists(gui_hooks, "browser_will_show"): + def on_browser_will_show(browser: Browser) -> None: + logger.debug(browser) + set_dark_titlebar_qt(browser, dwmapi) + browser.setStyleSheet(open(css_files_dir['QBrowser'], encoding='utf-8').read()) + gui_hooks.browser_will_show.append(on_browser_will_show) + +## CONFIG DIALOG +from aqt import mw, gui_hooks +from aqt.qt import * +from .config import config +from aqt.utils import showInfo +from aqt.webview import AnkiWebView + +class ThemeEditor(QDialog): + def __init__(self, parent, *args, **kwargs): + super().__init__(parent=parent or mw, *args, **kwargs) + self.config_editor = parent + self.setWindowModality(Qt.ApplicationModal) + self.setWindowTitle(f'Anki-redesign Advanced Editor') + self.setSizePolicy(self.make_size_policy()) + self.setMinimumSize(420, 420) + self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose) + set_dark_titlebar_qt(self, dwmapi, fix=False) + # Root layout + self.root_layout = QVBoxLayout(self) + # Main layout + self.layout = QVBoxLayout() + self.textedit = QTextEdit() + themes_plaintext = open(themes[theme], encoding='utf-8').read() + self.textedit.setPlainText(themes_plaintext) + self.layout.addWidget(self.textedit) + self.root_layout.addLayout(self.layout) + self.root_layout.addLayout(self.make_button_box()) + + def save_edit(self) -> None: + themes_parsed = json.loads(self.textedit.toPlainText()) + write_theme(themes[theme], themes_parsed) + self.config_editor.update() + self.accept() + + def make_button_box(self) -> QWidget: + def cancel(): + button = QPushButton('Cancel') + button.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + qconnect(button.clicked, self.accept) + return button + def save(): + button = QPushButton('Save') + button.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + button.setDefault(True) + button.setShortcut("Ctrl+Return") + button.clicked.connect(lambda _: self.save_edit()) + return button + + button_box = QHBoxLayout() + button_box.addStretch() + button_box.addWidget(cancel()) + button_box.addWidget(save()) + return button_box + + def make_size_policy(self) -> QSizePolicy: + size_policy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum) + size_policy.setHorizontalStretch(0) + size_policy.setVerticalStretch(0) + size_policy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) + return size_policy + +class ConfigDialog(QDialog): + def __init__(self, parent: QWidget, *args, **kwargs): + super().__init__(parent=parent or mw, *args, **kwargs) + self.setWindowModality(Qt.ApplicationModal) + self.setWindowTitle(f'Anki-redesign Configuration') + self.setSizePolicy(self.make_size_policy()) + self.setMinimumSize(420, 580) + self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose) + set_dark_titlebar_qt(self, dwmapi, fix=False) + + # Color/theme + ## Loads theme color + self.theme_colors = themes_parsed.get("colors") + self.updates = [] + self.theme_general = ["TEXT_FG", "WINDOW_BG", "FRAME_BG", "BUTTON_BG", "TOOLTIP_BG", "BORDER", "MEDIUM_BORDER", "FAINT_BORDER", "HIGHLIGHT_BG", "HIGHLIGHT_FG" , "LINK", "DISABLED", "SLIGHTLY_GREY_TEXT", "PRIMARY_COLOR"] + self.theme_decks = ["CURRENT_DECK", "NEW_COUNT", "LEARN_COUNT", "REVIEW_COUNT", "ZERO_COUNT"] + self.theme_browse = ["BURIED_FG", "SUSPENDED_FG", "MARKED_BG", "FLAG1_BG", "FLAG1_FG", "FLAG2_BG", "FLAG2_FG", "FLAG3_BG", "FLAG3_FG", "FLAG4_BG", "FLAG4_FG", "FLAG5_BG", "FLAG5_FG", "FLAG6_BG", "FLAG6_FG", "FLAG7_BG", "FLAG7_FG"] + self.theme_extra = [] + + # Root layout + self.root_layout = QVBoxLayout(self) + # Main layout + self.layout = QVBoxLayout() + ## Initialize tab screen + self.tabs = QTabWidget(objectName="tabs") + self.tabs.setFocusPolicy(Qt.FocusPolicy.StrongFocus) + self.tab_general = QWidget(objectName="general") + self.tab_general.setLayout(self.create_color_picker_layout(self.theme_general)) + self.tab_decks = QWidget(objectName="decks") + self.tab_decks.setLayout(self.create_color_picker_layout(self.theme_decks)) + self.tab_browse = QWidget(objectName="browse") + self.tab_browse.setLayout(self.create_color_picker_layout(self.theme_browse)) + self.tab_extra = QWidget(objectName="extra") + self.tab_extra.setLayout(self.create_color_picker_layout(self.theme_extra)) + + self.tab_settings = QWidget(objectName="settings") + self.settings_layout = QFormLayout() + self.theme_label = QLabel("Theme:") + self.theme_label.setStyleSheet('QLabel { font-size: 14px; font-weight: bold }') + self.settings_layout.addRow(self.theme_label) + for key in themes: + self.radio = self.radio_button(key) + self.settings_layout.addRow(key, self.radio) + self.settings_layout.addRow(QLabel()) + + self.font_label = QLabel("Font:") + self.font_label.setStyleSheet('QLabel { font-size: 14px; font-weight: bold }') + self.settings_layout.addRow(self.font_label) + self.interface_font = QFontComboBox() + self.interface_font.setFixedWidth(200) + self.interface_font.setCurrentFont(QFont(config["font"])) + self.settings_layout.addRow(self.interface_font) + + self.font_size = QSpinBox() + self.font_size.setFixedWidth(200) + self.font_size.setValue(config["font_size"]) + self.font_size.setSuffix("px") + self.settings_layout.addRow(self.font_size) + + self.settings_layout.addRow(QLabel()) + + + self.fix_label = QLabel("Addon-Compatibility Fixes: ") + self.fix_label.setStyleSheet('QLabel { font-size: 14px; font-weight: bold }') + self.settings_layout.addRow(self.fix_label) + self.reload_theme = self.checkbox("theme_reload") + self.settings_layout.addRow("QT6 theme on-start reload fix", self.reload_theme) + self.addon_more_overview_stats_check = self.checkbox("addon_more_overview_stats") + self.settings_layout.addRow("More Overview Stats 21", self.addon_more_overview_stats_check) + self.addon_advanced_review_bottom_bar_check = self.checkbox("addon_advanced_review_bottom_bar") + self.settings_layout.addRow("Advanced Review Bottom Bar", self.addon_advanced_review_bottom_bar_check) + + self.tab_settings.setLayout(self.settings_layout) + + ## Add tabs + self.tabs.resize(300,200) + self.tabs.addTab(self.tab_settings,"Settings") + self.tabs.addTab(self.tab_general,"General") + self.tabs.addTab(self.tab_decks,"Decks") + self.tabs.addTab(self.tab_browse,"Browse") + #self.tabs.addTab(self.tab_extra,"Extra") + + ## Add tabs to widget + self.layout.addWidget(self.tabs) + + self.root_layout.addLayout(self.layout) + self.root_layout.addLayout(self.make_button_box()) + self.setLayout(self.root_layout) + self.show() + + def update(self) -> None: + global themes_parsed + themes_parsed = get_theme(theme) + self.theme_colors = themes_parsed.get("colors") + for update in self.updates: + update() + + def checkbox(self, key: str) -> QCheckBox: + checkbox = QCheckBox() + + def update() -> None: + value = config[key] + checkbox.setChecked(value) + + self.updates.append(update) + update() + return checkbox + + def radio_button(self, key: str) -> QRadioButton: + radio = QRadioButton() + + def update() -> None: + if theme == key: + radio.setChecked(True) + elif radio.isChecked(): + radio.setChecked(False) + + def toggle(checked) -> None: + global theme + if checked: + theme = key + self.update() + + self.updates.append(update) + radio.toggled.connect(lambda checked: toggle(checked)) + update() + return radio + + def color_input(self, key: str) -> QPushButton: + button = QPushButton() + button.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + button.setFixedWidth(25) + button.setFixedHeight(25) + + color_dialog = QColorDialog(self) + + def set_color(rgb: str) -> None: + # Check for valid color + color = QColor() + color.setNamedColor(rgb) + if not color.isValid(): + return + # Update color + color_dialog.setCurrentColor(color) + button.setStyleSheet('QPushButton{ background-color: "%s"; border: none; border-radius: 2px}' % rgb) + + def update() -> None: + rgb = self.theme_colors.get(key)[color_mode] + set_color(rgb) + + def save(color: QColor) -> None: + rgb = color.name(QColor.NameFormat.HexRgb) + self.theme_colors[key][color_mode] = rgb + set_color(rgb) + + self.updates.append(update) + color_dialog.colorSelected.connect(lambda color: save(color)) + button.clicked.connect(lambda _: color_dialog.exec()) + return button + + def create_color_picker_layout(self, colors) -> None: + layout = QFormLayout() + for key in colors: + self.test = self.color_input(key) + layout.addRow(self.theme_colors.get(key)[0], self.test) + return layout + + def theme_file_editor(self) -> None: + diag = ThemeEditor(self) + diag.show() + + def make_button_box(self) -> QWidget: + def advanced(): + button = QPushButton('Advanced') + button.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + qconnect(button.clicked, self.theme_file_editor) + return button + def cancel(): + button = QPushButton('Cancel') + button.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + qconnect(button.clicked, self.accept) + return button + def save(): + button = QPushButton('Save') + button.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) + button.setDefault(True) + button.setShortcut("Ctrl+Return") + button.clicked.connect(lambda _: self.save()) + return button + + button_box = QHBoxLayout() + button_box.addWidget(advanced()) + button_box.addStretch() + button_box.addWidget(cancel()) + button_box.addWidget(save()) + return button_box + + def make_size_policy(self) -> QSizePolicy: + size_policy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum) + size_policy.setHorizontalStretch(0) + size_policy.setVerticalStretch(0) + size_policy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) + return size_policy + + def save(self) -> None: + # Save settings and update config + global config, color_mode + config["font"] = self.interface_font.currentFont().family() + config["font_size"] = self.font_size.value() + config['addon_more_overview_stats'] = self.addon_more_overview_stats_check.isChecked() + config['addon_advanced_review_bottom_bar'] = self.addon_advanced_review_bottom_bar_check.isChecked() + config['theme_reload'] = self.reload_theme.isChecked() + config["theme"] = theme + write_config(config) + config = get_config() + + # Write and update theme + color_mode = 2 if theme_manager.get_night_mode() else 1 # 1 = light and 2 = dark + themes_parsed["colors"] = self.theme_colors + write_theme(themes[theme], themes_parsed) + update_theme() + + # mw.reset() + # ShowInfo for both new and legacy support + showInfo(_("Changes will take effect when you restart Anki.")) + #showInfo(tr.preferences_changes_will_take_effect_when_you()) + self.accept() + +def check_legacy_colors() -> None: + try: + _ = colors.items() + except: + return False + return True + +def refresh_all_windows() -> None: + # Redraw top toolbar + mw.toolbar.draw() + if attribute_exists(gui_hooks, "top_toolbar_did_init_links"): + gui_hooks.top_toolbar_did_init_links.append(lambda a,b: [redraw_toolbar_legacy(a,b), gui_hooks.top_toolbar_did_init_links.remove(print)]) + + # Redraw main body + if mw.state == "review": + mw.reviewer._initWeb() + if mw.reviewer.state == "question": + mw.reviewer._showQuestion() + else: + mw.reviewer._showAnswer() + elif mw.state == "overview": + mw.overview.refresh() + elif mw.state == "deckBrowser": + mw.deckBrowser.show() + + if attribute_exists(gui_hooks, "top_toolbar_did_init_links"): + gui_hooks.top_toolbar_did_init_links.remove(redraw_toolbar) + +def update_theme() -> None: + themes_parsed = get_theme(theme) + theme_colors = themes_parsed.get("colors") + # Apply theme on colors + ncolors = {} + # Legacy color check + logger.debug(dir(colors)) + legacy = check_legacy_colors() + for color_name in theme_colors: + c = theme_colors.get(color_name) + ncolors[color_name] = c[color_mode] + if legacy: + colors[f"day{c[3].replace('--','-')}"] = c[1] + colors[f"night{c[3].replace('--','-')}"] = c[2] + # Potentially add fusion fixes too? + else: + logger.debug(getattr(colors, color_name, False)) + if getattr(colors, color_name, False): + setattr(colors, color_name, (c[1], c[2])) + # Apply theme on palette + apply_theme(ncolors) + refresh_all_windows() + +def apply_theme(colors) -> None: + # Load palette + palette = QPalette() + # QT mappings + #logger.debug(QPalette.ColorRole.__dict__) + color_map = { + QPalette.ColorRole.Window: "WINDOW_BG", + QPalette.ColorRole.WindowText: "TEXT_FG", + QPalette.ColorRole.Base: "FRAME_BG", + QPalette.ColorRole.AlternateBase: "WINDOW_BG", + QPalette.ColorRole.ToolTipBase: "TOOLTIP_BG", + QPalette.ColorRole.ToolTipText: "TEXT_FG", + QPalette.ColorRole.Text: "TEXT_FG", + QPalette.ColorRole.Button: "BUTTON_BG", + QPalette.ColorRole.ButtonText: "TEXT_FG", + QPalette.ColorRole.BrightText: "HIGHLIGHT_FG", + QPalette.ColorRole.HighlightedText: "HIGHLIGHT_FG", + QPalette.ColorRole.Link: "LINK", + QPalette.ColorRole.NoRole: "WINDOW_BG", + } + for color_role in color_map: + palette.setColor(color_role, QColor(colors[color_map[color_role]])) + + highlight_bg = QColor(colors["HIGHLIGHT_BG"]) + highlight_bg.setAlpha(64) + palette.setColor(QPalette.ColorRole.Highlight, highlight_bg) + + disabled_color = QColor(colors["DISABLED"]) + palette.setColor(QPalette.ColorRole.PlaceholderText, disabled_color) + palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Text, disabled_color) + palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.ButtonText, disabled_color) + palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.HighlightedText, disabled_color) + + # Update palette + mw.app.setPalette(palette) + theme_manager.default_palette = palette + theme_manager._apply_style(mw.app) + + # Update webview bg + AnkiWebView._getWindowColor = lambda *args: QColor(colors["WINDOW_BG"]) + AnkiWebView.get_window_bg_color = lambda *args: QColor(colors["WINDOW_BG"]) + +# Create menu actions +def create_menu_action(parent: QWidget, dialog_class: QDialog, dialog_name: str) -> QAction: + def open_dialog(): + dialog = dialog_class(mw) + return dialog.exec() + + action = QAction(dialog_name, parent) + #qconnect(action.triggered, open_dialog) + action.triggered.connect(open_dialog) + return action + +# Load in the Anki-redesign menu +if not hasattr(mw, 'anki_redesign'): + mw.anki_redesign = QMenu("&Anki-redesign", mw) + mw.form.menubar.insertMenu(mw.form.menuHelp.menuAction(), mw.anki_redesign) + + mw.anki_redesign.addAction(create_menu_action(mw.anki_redesign, ConfigDialog, "&Config")) + mw.anki_redesign.addSeparator() + mw.reset() + update_theme() + mw.reset() + + # Rereload view to fix theme change on startup + if 'Qt6' in QPalette.ColorRole.__module__: + logger.debug('QT6 DETECTED....') + config = get_config() + if config["theme_reload"]: + update_theme() + +def on_theme_did_change() -> None: + global color_mode + color_mode = 2 if theme_manager.get_night_mode() else 1 # 1 = light and 2 = dark + update_theme() + logger.debug("THEME CHANGEEEED") + refresh_all_windows() + mw.reset() + update_theme() + + +if attribute_exists(gui_hooks, "theme_did_change"): + gui_hooks.theme_did_change.append(on_theme_did_change) + logger.debug("YEP")
\ No newline at end of file diff --git a/.local/share/Anki2/addons21/anki_reworked/config.json b/.local/share/Anki2/addons21/anki_reworked/config.json new file mode 100644 index 0000000..b1e6ac5 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/config.json @@ -0,0 +1,8 @@ +{ + "addon_more_overview_stats": "false", + "addon_advanced_review_bottom_bar": "false", + "font": "Segoe UI", + "font_size": "12", + "theme": "Catppuccin", + "theme_reload": "false" +} diff --git a/.local/share/Anki2/addons21/anki_reworked/config.md b/.local/share/Anki2/addons21/anki_reworked/config.md new file mode 100644 index 0000000..33498b4 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/config.md @@ -0,0 +1,9 @@ +This is the advanced documentation for Anki-redesign's configuration: +Use the built-in config at the menu (Anki-redesign > Config) for a better user experience. + +- addon_more_overview_stats: either `true` or `false` +- addon_advanced_review_bottom_bar: either `true` or `false` +- font: customize own font here +- font_size: customize own font size here +- theme: customize theme here +- theme_reload: either `true` or `false` diff --git a/.local/share/Anki2/addons21/anki_reworked/config.py b/.local/share/Anki2/addons21/anki_reworked/config.py new file mode 100644 index 0000000..9e508f8 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/config.py @@ -0,0 +1,22 @@ +from aqt import mw + +def get_config() -> dict: + config: dict = mw.addonManager.getConfig(__name__) or dict() + ## Addon fix + config['addon_more_overview_stats'] = True if config.get('addon_more_overview_stats', "false").lower() == "true" else False + config['addon_advanced_review_bottom_bar'] = True if config.get('addon_advanced_review_bottom_bar', "false").lower() == "true" else False + ## Customization + config['font'] = config.get('font', "Segoe UI") + config['font_size'] = int(config.get('font_size', "12")) + config['theme'] = config.get('theme', 'Anki') + config['theme_reload'] = True if config.get('theme_reload', "false").lower() == "true" else False + + return config + +def write_config(config): + for key in config.keys(): + if not isinstance(config[key], str): + config[key] = str(config[key]) + mw.addonManager.writeConfig(__name__, config) + +config = get_config() diff --git a/.local/share/Anki2/addons21/anki_reworked/files/BottomBar.css b/.local/share/Anki2/addons21/anki_reworked/files/BottomBar.css new file mode 100644 index 0000000..1e07817 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/BottomBar.css @@ -0,0 +1,40 @@ +body #outer button { + color: var(--text-fg, var(--legacy-text-fg)); + border: none; + border-radius: 15px; + padding: 6px 24px; + margin: 0 5px; + cursor: pointer; + font-weight: 500; + font-size: 0.875rem; + line-height: 1.75; + letter-spacing: 0.02857em; + text-transform: uppercase; + min-width: 64px; + background-color: var(--frame-bg, var(--legacy-frame-bg)); + transition: background 0.2s linear, color 0.3s ease-out; + box-shadow: rgb(0 0 0 / 20%) 0px 3px 7px -2px, + rgb(0 0 0 / 5%) 0px 5px 10px 0px, rgb(0 0 0 / 12%) 0px 1px 5px 0px; +} +body.nightMode #outer button { + background: initial; + background-color: var(--frame-bg, var(--legacy-frame-bg)); +} + +body #outer button:focus, +body #outer button.focus { + background-color: var(--primary-color); + color: var(--frame-bg, var(--legacy-frame-bg)); + outline: none; +} +body.nightMode #outer button:focus, +body.nightMode #outer button.focus { + color: var(--text-fg, var(--legacy-text-fg)); +} + +body #outer button:hover { + background-color: rgba(0, 0, 0, 0.05); +} +body.nightMode #outer button:hover { + background-color: rgba(255, 255, 255, 0.1); +} diff --git a/.local/share/Anki2/addons21/anki_reworked/files/CardLayout.css b/.local/share/Anki2/addons21/anki_reworked/files/CardLayout.css new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/CardLayout.css @@ -0,0 +1 @@ + diff --git a/.local/share/Anki2/addons21/anki_reworked/files/DeckBrowser.css b/.local/share/Anki2/addons21/anki_reworked/files/DeckBrowser.css new file mode 100644 index 0000000..0b8f82c --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/DeckBrowser.css @@ -0,0 +1,48 @@ +body table:first-of-type { + width: 90%; + max-width: 600px; +} +body table:first-of-type th { + padding: 0 6px; +} +body table:first-of-type td { + padding: 6px; +} +body table:first-of-type tr.deck td { + border-bottom: none; +} +body table:first-of-type tr.deck td.opts { + padding-left: 20px; +} +body table:first-of-type tr.deck td.opts > a { + display: flex; +} +body table:first-of-type tr.current { + background-color: transparent; +} +body table:first-of-type tr.current td { + background-color: var(--faint-border, var(--legacy-faint-border)); +} +body table:first-of-type tr.current td:first-of-type { + border-radius: 10px 0 0 10px; +} +body table:first-of-type tr.current td:last-of-type { + border-radius: 0 10px 10px 0; +} +body table:first-of-type tr a { + color: var(--text-fg, var(--legacy-text-fg)) !important; +} +body table:first-of-type tr a.filtered { + color: var(--link, var(--legacy-link)) !important; +} +a.deck { + padding: 5px 10px 5px 5px; + transition: padding 1s, background-color 0.5s, margin-right 1s; + border-radius: 6px; + margin-right: 5px; +} +body table:first-of-type tr a.deck:hover { + padding: 5px 10px 5px 10px; + background-color: rgba(0, 0, 0, 0.1); + margin-right: 0; +} diff --git a/.local/share/Anki2/addons21/anki_reworked/files/Editor.css b/.local/share/Anki2/addons21/anki_reworked/files/Editor.css new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/Editor.css @@ -0,0 +1 @@ + diff --git a/.local/share/Anki2/addons21/anki_reworked/files/Overview.css b/.local/share/Anki2/addons21/anki_reworked/files/Overview.css new file mode 100644 index 0000000..7c7571a --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/Overview.css @@ -0,0 +1,59 @@ +body .descmid { + text-align: center; +} +center > table tr:first-of-type { + display: flex; + flex-direction: column; +} +td table { + width: 50%; +} +td table tr:first-of-type { + display: table-row; + flex-direction: unset; +} +td table tr td:last-of-type { + text-align: right; +} +button#study.but, +button#main.but { + padding: 10px 27px; + box-sizing: border-box; + width: 100%; + margin-bottom: 20px; + + color: var(--text-fg, var(--legacy-text-fg)); + border: none; + border-radius: 15px; + margin: 0 5px; + cursor: pointer; + font-weight: 500; + font-size: 0.875rem; + line-height: 1.75; + letter-spacing: 0.02857em; + text-transform: uppercase; + min-width: 64px; + background: initial; + background-color: var(--frame-bg, var(--legacy-frame-bg)); + transition: background 0.2s linear, color 0.3s ease-out; + box-shadow: rgb(0 0 0 / 20%) 0px 3px 7px -2px, + rgb(0 0 0 / 5%) 0px 5px 10px 0px, rgb(0 0 0 / 12%) 0px 1px 5px 0px; +} +body.nightMode button#study.but:hover, +body.nightMode button#main.but:hover { + background-color: rgba(255, 255, 255, 0.1); +} +button#study.but:focus, +button#main.but:focus { + background-color: var(--primary-color) !important; + color: var(--frame-bg, var(--legacy-frame-bg)); + outline: none; +} +body.nightMode button#study.but:focus, +body.nightMode button#main.but:focus { + color: var(--text-fg); +} +button#study.but:hover, +button#main.but:hover { + background-color: rgba(0, 0, 0, 0.05); +} diff --git a/.local/share/Anki2/addons21/anki_reworked/files/QAbout.css b/.local/share/Anki2/addons21/anki_reworked/files/QAbout.css new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/QAbout.css diff --git a/.local/share/Anki2/addons21/anki_reworked/files/QAddCards.css b/.local/share/Anki2/addons21/anki_reworked/files/QAddCards.css new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/QAddCards.css @@ -0,0 +1 @@ + diff --git a/.local/share/Anki2/addons21/anki_reworked/files/QAddonsDialog.css b/.local/share/Anki2/addons21/anki_reworked/files/QAddonsDialog.css new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/QAddonsDialog.css diff --git a/.local/share/Anki2/addons21/anki_reworked/files/QBrowser.css b/.local/share/Anki2/addons21/anki_reworked/files/QBrowser.css new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/QBrowser.css diff --git a/.local/share/Anki2/addons21/anki_reworked/files/QEditCurrent.css b/.local/share/Anki2/addons21/anki_reworked/files/QEditCurrent.css new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/QEditCurrent.css diff --git a/.local/share/Anki2/addons21/anki_reworked/files/QFilteredDeckConfigDialog.css b/.local/share/Anki2/addons21/anki_reworked/files/QFilteredDeckConfigDialog.css new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/QFilteredDeckConfigDialog.css diff --git a/.local/share/Anki2/addons21/anki_reworked/files/QNewDeckStats.css b/.local/share/Anki2/addons21/anki_reworked/files/QNewDeckStats.css new file mode 100644 index 0000000..88cb00c --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/QNewDeckStats.css @@ -0,0 +1,3 @@ +body { + background-color: red; +}
\ No newline at end of file diff --git a/.local/share/Anki2/addons21/anki_reworked/files/QPreferences.css b/.local/share/Anki2/addons21/anki_reworked/files/QPreferences.css new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/QPreferences.css diff --git a/.local/share/Anki2/addons21/anki_reworked/files/Reviewer.css b/.local/share/Anki2/addons21/anki_reworked/files/Reviewer.css new file mode 100644 index 0000000..9e47f09 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/Reviewer.css @@ -0,0 +1,9 @@ +body #typeans { + padding: 8px 12px; + border-radius: 5px; +} +body.card { + width: 90%; + margin: 20px auto; + max-width: 1080px; +} diff --git a/.local/share/Anki2/addons21/anki_reworked/files/ReviewerBottomBar.css b/.local/share/Anki2/addons21/anki_reworked/files/ReviewerBottomBar.css new file mode 100644 index 0000000..768270e --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/ReviewerBottomBar.css @@ -0,0 +1,60 @@ +body { + overflow: hidden; +} +body #outer { + border-top: 1px solid transparent; +} +body.nightMode #outer { + border-top-color: transparent; +} +body #outer table#innertable { + padding: 6px; + transform: translateY(8px); +} +body button { + margin: 0; +} +body .stat { + position: relative; + padding-top: 0px; + min-width: 120px; +} +body .stat2 { + padding-top: 0px; + font-weight: normal; +} +td[align="center"] { + position: relative; +} +body .stattxt, +td[align="center"] > span { + position: absolute; + display: block; + left: 50%; + transform: translate(-50%, -13px); + color: var(--text-fg, var(--legacy-text-fg)); +} +body .stattxt#time { + transform: translate(-50%, -6px); +} +body #outer button#ansbut, +body #outer table button { + transform: translateY(-4px); +} +/* ARBb addon fix */ +body #outer.arbb .stat { + min-width: auto; + padding-left: 2px; + padding-right: 2px; +} +body #outer.arbb table#innertable { + padding: initial; + width: calc(100% - 10px); +} +body #outer.arbb button { + /* color: var(--text-fg, var(--legacy-text-fg)); */ + letter-spacing: 0.02857em; + text-transform: uppercase; + margin-left: 2px; + margin-right: 2px; +} diff --git a/.local/share/Anki2/addons21/anki_reworked/files/TopToolbar.css b/.local/share/Anki2/addons21/anki_reworked/files/TopToolbar.css new file mode 100644 index 0000000..3b4b6ee --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/TopToolbar.css @@ -0,0 +1,25 @@ +body #outer { + display: flex; + justify-content: center; +} +body center #header { + width: auto; + border-bottom: none; + border-radius: 0 0 12px 12px; + background-color: var(--frame-bg, var(--legacy-frame-bg)); + height: 40px; + box-shadow: rgb(0 0 0 / 10%) 0px 0px 11px -2px, + rgb(0 0 0 / 14%) 0px 2px 2px 0px, rgb(0 0 0 / 12%) 0px 4px 5px 0px; +} +body.nightMode center #header { + background-color: var(--faint-border, var(--legacy-faint-border)); +} +body center #header .hitem { + padding-left: initial; + padding-right: initial; + padding: 0 15px; + color: var(--text-fg, var(--legacy-text-fg)) !important; +} +body center #header a#sync { + color: var(--link, var(--legacy-link)) !important; +} diff --git a/.local/share/Anki2/addons21/anki_reworked/files/global.css b/.local/share/Anki2/addons21/anki_reworked/files/global.css new file mode 100644 index 0000000..a145312 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/global.css @@ -0,0 +1,96 @@ +:root, +:root .isWin, +:root .isMac, +:root .isLin { + --focus-color: rgba(81, 135, 169, 0.7); +} +/* Force LIGHT MODE Background */ +:root body:not(.nightMode), +:root body.isWin:not(.nightMode), +:root body.isMac:not(.nightMode), +:root body.isLin:not(.nightMode) { + /* Force variable styling on legacy versions */ + --legacy-text-fg: black; + --legacy-frame-bg: white; + --legacy-border: #aaa; + --legacy-medium-border: #b6b6b6; + --legacy-faint-border: #e7e7e7; + --legacy-link: #00a; + --legacy-review-count: #0a0; + --legacy-new-count: #00a; + --legacy-learn-count: #c35617; + --legacy-zero-count: #ddd; + --legacy-slightly-grey-text: #333; + --legacy-highlight-bg: #77ccff; + --legacy-highlight-fg: black; + --legacy-disabled: #777; + --legacy-flag1-fg: #e25252; + --legacy-flag2-fg: #ffb347; + --legacy-flag3-fg: #54c414; + --legacy-flag4-fg: #578cff; + --legacy-flag5-fg: #ff82ee; + --legacy-flag6-fg: #00d1b5; + --legacy-flag7-fg: #9649dd; + --legacy-flag1-bg: #ff9b9b; + --legacy-flag2-bg: #ffb347; + --legacy-flag3-bg: #93e066; + --legacy-flag4-bg: #9dbcff; + --legacy-flag5-bg: #f5a8eb; + --legacy-flag6-bg: #7edbd7; + --legacy-flag7-bg: #cca3f1; + --legacy-buried-fg: #aaaa33; + --legacy-suspended-fg: #dd0; + --legacy-suspended-bg: #ffffb2; + --legacy-marked-bg: #cce; + --legacy-tooltip-bg: #fcfcfc; +} +/* Force DARK MODE Background */ +:root body.nightMode, +:root body.isWin.nightMode, +:root body.isMac.nightMode, +:root body.isLin.nightMode { + /* Force variable styling on legacy versions */ + --legacy-text-fg: white; + --legacy-frame-bg: #3a3a3a; + --legacy-border: #777; + --legacy-medium-border: #444; + --legacy-faint-border: #29292b; + --legacy-link: #77ccff; + --legacy-review-count: #5ccc00; + --legacy-new-count: #77ccff; + --legacy-learn-count: #ff935b; + --legacy-zero-count: #444; + --legacy-slightly-grey-text: #ccc; + --legacy-highlight-bg: #77ccff; + --legacy-highlight-fg: white; + --legacy-disabled: #777; + --legacy-flag1-fg: #ff7b7b; + --legacy-flag2-fg: #f5aa41; + --legacy-flag3-fg: #86ce5d; + --legacy-flag4-fg: #6f9dff; + --legacy-flag5-fg: #f097e4; + --legacy-flag6-fg: #5ccfca; + --legacy-flag7-fg: #9f63d3; + --legacy-flag1-bg: #aa5555; + --legacy-flag2-bg: #ac653a; + --legacy-flag3-bg: #559238; + --legacy-flag4-bg: #506aa3; + --legacy-flag5-bg: #975d8f; + --legacy-flag6-bg: #399185; + --legacy-flag7-bg: #624b77; + --legacy-buried-fg: #777733; + --legacy-suspended-fg: #ffffb2; + --legacy-suspended-bg: #aaaa33; + --legacy-marked-bg: #77c; + --legacy-tooltip-bg: #272727; +} + +body { + background-color: var(--window-bg) !important; +} +html { + font-size: 12px; +} +html body a { + color: var(--link, var(--legacy-link)) !important; +} diff --git a/.local/share/Anki2/addons21/anki_reworked/files/legacy.css b/.local/share/Anki2/addons21/anki_reworked/files/legacy.css new file mode 100644 index 0000000..2ce3692 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/files/legacy.css @@ -0,0 +1,18 @@ +button { + box-sizing: border-box; + color: var(--text-fg, var(--legacy-text-fg)); + border: none; + border-radius: 15px; + cursor: pointer; + padding: 6px 24px; + font-weight: 500; + font-size: 0.875rem; + line-height: 1.75; + letter-spacing: 0.02857em; + text-transform: uppercase; + background: initial; + background-color: var(--frame-bg, var(--legacy-frame-bg)); + transition: background 0.2s linear, color 0.3s ease-out; + box-shadow: rgb(0 0 0 / 20%) 0px 3px 7px -2px, + rgb(0 0 0 / 5%) 0px 5px 10px 0px, rgb(0 0 0 / 12%) 0px 1px 5px 0px; +}
\ No newline at end of file diff --git a/.local/share/Anki2/addons21/anki_reworked/manifest.json b/.local/share/Anki2/addons21/anki_reworked/manifest.json new file mode 100644 index 0000000..33ce43f --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/manifest.json @@ -0,0 +1,10 @@ +{ + "name": "Anki Redesign", + "package": "anki-redesign", + "ankiweb_id": "308574457", + "author": "Shirajuki", + "version": "0.1.3", + "homepage": "https://github.com/shirajuki/anki-redesign", + "conflicts": ["308574457", "688199788"], + "manifest_version": 2 +} diff --git a/.local/share/Anki2/addons21/anki_reworked/meta.json b/.local/share/Anki2/addons21/anki_reworked/meta.json new file mode 100644 index 0000000..17e78d2 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/meta.json @@ -0,0 +1 @@ +{"homepage": "https://github.com/shirajuki/anki-redesign", "name": "Anki-redesign", "conflicts": ["308574457", "688199788"], "mod": 1656801893, "min_point_version": 20, "max_point_version": 54, "branch_index": 0, "disabled": true, "config": {"addon_more_overview_stats": "True", "addon_advanced_review_bottom_bar": "True", "font": "3270Medium Nerd Font", "font_size": "12", "theme": "Catppuccin", "theme_reload": "True"}, "update_enabled": true}
\ No newline at end of file diff --git a/.local/share/Anki2/addons21/anki_reworked/themes/Anki.json b/.local/share/Anki2/addons21/anki_reworked/themes/Anki.json new file mode 100644 index 0000000..31a4818 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/themes/Anki.json @@ -0,0 +1,230 @@ +{
+ "colors": {
+ "BORDER": [
+ "Border",
+ "#aaa",
+ "#777",
+ "--border"
+ ],
+ "BURIED_FG": [
+ "Buried Foreground",
+ "#aaaa33",
+ "#777733",
+ "--buried-fg"
+ ],
+ "BUTTON_BG": [
+ "Button Background",
+ "#eff0f1",
+ "#454545",
+ ""
+ ],
+ "CURRENT_DECK": [
+ "Selected Deck",
+ "#e7e7e7",
+ "#29292b",
+ "--current-deck"
+ ],
+ "DISABLED": [
+ "Disabled",
+ "#777",
+ "#777",
+ "--disabled"
+ ],
+ "FAINT_BORDER": [
+ "Faint Border",
+ "#e7e7e7",
+ "#29292b",
+ "--faint-border"
+ ],
+ "FLAG1_BG": [
+ "Flag1 (Browse Cards List)",
+ "#ff9b9b",
+ "#aa5555",
+ "--flag1-bg"
+ ],
+ "FLAG1_FG": [
+ "Flag1 (Browse Sidebar)",
+ "#e25252",
+ "#ff7b7b",
+ "--flag1-fg"
+ ],
+ "FLAG2_BG": [
+ "Flag2 (Browse Cards List)",
+ "#ffb347",
+ "#ac653a",
+ "--flag2-bg"
+ ],
+ "FLAG2_FG": [
+ "Flag2 (Browse Sidebar)",
+ "#ffb347",
+ "#f5aa41",
+ "--flag2-fg"
+ ],
+ "FLAG3_BG": [
+ "Flag3 (Browse Cards List)",
+ "#93e066",
+ "#559238",
+ "--flag3-bg"
+ ],
+ "FLAG3_FG": [
+ "Flag3 (Browse Sidebar)",
+ "#54c414",
+ "#86ce5d",
+ "--flag3-fg"
+ ],
+ "FLAG4_BG": [
+ "Flag4 (Browse Cards List)",
+ "#9dbcff",
+ "#506aa3",
+ "--flag4-bg"
+ ],
+ "FLAG4_FG": [
+ "Flag4 (Browse Sidebar)",
+ "#578cff",
+ "#6f9dff",
+ "--flag4-fg"
+ ],
+ "FLAG5_BG": [
+ "Flag5 (Browse Cards List)",
+ "#f5a8eb",
+ "#975d8f",
+ "--flag5-bg"
+ ],
+ "FLAG5_FG": [
+ "Flag5 (Browse Sidebar)",
+ "#ff82ee",
+ "#f097e4",
+ "--flag5-fg"
+ ],
+ "FLAG6_BG": [
+ "Flag6 (Browse Cards List)",
+ "#7edbd7",
+ "#399185",
+ "--flag6-bg"
+ ],
+ "FLAG6_FG": [
+ "Flag6 (Browse Sidebar)",
+ "#00d1b5",
+ "#5ccfca",
+ "--flag6-fg"
+ ],
+ "FLAG7_BG": [
+ "Flag7 (Browse Cards List)",
+ "#cca3f1",
+ "#624b77",
+ "--flag7-bg"
+ ],
+ "FLAG7_FG": [
+ "Flag7 (Browse Sidebar)",
+ "#9649dd",
+ "#9f63d3",
+ "--flag7-fg"
+ ],
+ "FRAME_BG": [
+ "Frame Background",
+ "white",
+ "#3a3a3a",
+ "--frame-bg"
+ ],
+ "HIGHLIGHT_BG": [
+ "Highlighted Background",
+ "#77ccff",
+ "#77ccff",
+ "--highlight-bg"
+ ],
+ "HIGHLIGHT_FG": [
+ "Highlighted Text",
+ "black",
+ "white",
+ "--highlight-fg"
+ ],
+ "LEARN_COUNT": [
+ "Learn Count",
+ "#c35617",
+ "#ff935b",
+ "--learn-count"
+ ],
+ "LINK": [
+ "Hyperlink",
+ "#00a",
+ "#77ccff",
+ "--link"
+ ],
+ "MARKED_BG": [
+ "Marked Background",
+ "#cce",
+ "#77c",
+ "--marked-bg"
+ ],
+ "MEDIUM_BORDER": [
+ "Medium Border",
+ "#b6b6b6",
+ "#444",
+ "--medium-border"
+ ],
+ "NEW_COUNT": [
+ "New Count",
+ "#00a",
+ "#77ccff",
+ "--new-count"
+ ],
+ "PRIMARY_COLOR": [
+ "Primary Color",
+ "#0093d0",
+ "#0093d0",
+ "--primary-color"
+ ],
+ "REVIEW_COUNT": [
+ "Review Count",
+ "#0a0",
+ "#5ccc00",
+ "--review-count"
+ ],
+ "SLIGHTLY_GREY_TEXT": [
+ "Switch Text",
+ "#333",
+ "#ccc",
+ "--slightly-grey-text"
+ ],
+ "SUSPENDED_BG": [
+ "Suspended Background",
+ "#ffffb2",
+ "#aaaa33",
+ "--suspended-bg"
+ ],
+ "SUSPENDED_FG": [
+ "Suspended Foreground",
+ "#dd0",
+ "#ffffb2",
+ "--suspended-fg"
+ ],
+ "TEXT_FG": [
+ "Text Foreground",
+ "black",
+ "white",
+ "--text-fg"
+ ],
+ "TOOLTIP_BG": [
+ "Tooltip Background",
+ "#fcfcfc",
+ "#272727",
+ "--tooltip-bg"
+ ],
+ "WINDOW_BG": [
+ "Window Background",
+ "#fafafa",
+ "#2f2f31",
+ "--window-bg"
+ ],
+ "ZERO_COUNT": [
+ "Zero Count",
+ "#ddd",
+ "#444",
+ "--zero-count"
+ ]
+ },
+ "version": {
+ "major": -1,
+ "minor": -1
+ }
+}
\ No newline at end of file diff --git a/.local/share/Anki2/addons21/anki_reworked/themes/Catppuccin.json b/.local/share/Anki2/addons21/anki_reworked/themes/Catppuccin.json new file mode 100644 index 0000000..39684d2 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/themes/Catppuccin.json @@ -0,0 +1,230 @@ +{
+ "colors": {
+ "BORDER": [
+ "Border",
+ "#aaa",
+ "#434c5e",
+ "--border"
+ ],
+ "BURIED_FG": [
+ "Buried Foreground",
+ "#aaaa33",
+ "#777733",
+ "--buried-fg"
+ ],
+ "BUTTON_BG": [
+ "Button Background",
+ "#e7e7e7",
+ "#1A1826",
+ "--button-bg"
+ ],
+ "CURRENT_DECK": [
+ "Selected Deck",
+ "#e7e7e7",
+ "#1A1826",
+ "--current-deck"
+ ],
+ "DISABLED": [
+ "Disabled",
+ "#777",
+ "#C3BAC6",
+ "--disabled"
+ ],
+ "FAINT_BORDER": [
+ "Faint Border",
+ "#e7e7e7",
+ "#1A1826",
+ "--faint-border"
+ ],
+ "FLAG1_BG": [
+ "Flag1 (Browse Cards List)",
+ "#BF616A",
+ "#BF616A",
+ "--flag1-bg"
+ ],
+ "FLAG1_FG": [
+ "Flag1 (BrowseSidebar)",
+ "#BF616A",
+ "#BF616A",
+ "--flag1-fg"
+ ],
+ "FLAG2_BG": [
+ "Flag2 (Browse Cards List)",
+ "#D08770",
+ "#D08770",
+ "--flag2-bg"
+ ],
+ "FLAG2_FG": [
+ "Flag2 (Browse Sidebar)",
+ "#D08770",
+ "#D08770",
+ "--flag2-fg"
+ ],
+ "FLAG3_BG": [
+ "Flag3 (Browse Cards List)",
+ "#A3BE8C",
+ "#A3BE8C",
+ "--flag3-bg"
+ ],
+ "FLAG3_FG": [
+ "Flag3 (Browse Sidebar)",
+ "#A3BE8C",
+ "#A3BE8C",
+ "--flag3-fg"
+ ],
+ "FLAG4_BG": [
+ "Flag4 (Browse Cards List)",
+ "#5E81AC",
+ "#5E81AC",
+ "--flag4-bg"
+ ],
+ "FLAG4_FG": [
+ "Flag4 (Browse Sidebar)",
+ "#5E81AC",
+ "#5E81AC",
+ "--flag4-fg"
+ ],
+ "FLAG5_BG": [
+ "Flag5 (Browse Cards List)",
+ "#B48EAD",
+ "#B48EAD",
+ "--flag5-bg"
+ ],
+ "FLAG5_FG": [
+ "Flag5 (Browse Sidebar)",
+ "#B48EAD",
+ "#B48EAD",
+ "--flag5-fg"
+ ],
+ "FLAG6_BG": [
+ "Flag6 (Browse Cards List)",
+ "#7edbd7",
+ "#399185",
+ "--flag6-bg"
+ ],
+ "FLAG6_FG": [
+ "Flag6 (Browse Sidebar)",
+ "#00d1b5",
+ "#5ccfca",
+ "--flag6-fg"
+ ],
+ "FLAG7_BG": [
+ "Flag7 (Browse Cards List)",
+ "#cca3f1",
+ "#624b77",
+ "--flag7-bg"
+ ],
+ "FLAG7_FG": [
+ "Flag7 (Browse Sidebar)",
+ "#9649dd",
+ "#9f63d3",
+ "--flag7-fg"
+ ],
+ "FRAME_BG": [
+ "Frame Background",
+ "white",
+ "#1A1826",
+ "--frame-bg"
+ ],
+ "HIGHLIGHT_BG": [
+ "Highlighted Background",
+ "#77ccff",
+ "#81A1C1",
+ "--highlight-bg"
+ ],
+ "HIGHLIGHT_FG": [
+ "Highlighted Text",
+ "black",
+ "#ECEFF4",
+ "--highlight-fg"
+ ],
+ "LEARN_COUNT": [
+ "Learn Count",
+ "#c35617",
+ "#D08770",
+ "--learn-count"
+ ],
+ "LINK": [
+ "Hyperlink",
+ "#6e9fda",
+ "#89DCEB",
+ "--link"
+ ],
+ "MARKED_BG": [
+ "Marked Background",
+ "#cce",
+ "#ebcb8b",
+ "--marked-bg"
+ ],
+ "MEDIUM_BORDER": [
+ "Medium Border",
+ "#b6b6b6",
+ "#434C5E",
+ "--medium-border"
+ ],
+ "NEW_COUNT": [
+ "New Count",
+ "#00a",
+ "#5E81AC",
+ "--new-count"
+ ],
+ "PRIMARY_COLOR": [
+ "Primary Color",
+ "#0093d0",
+ "#0093d0",
+ "--primary-color"
+ ],
+ "REVIEW_COUNT": [
+ "Review Count",
+ "#0a0",
+ "#A3BE8C",
+ "--review-count"
+ ],
+ "SLIGHTLY_GREY_TEXT": [
+ "Switch Text",
+ "#333",
+ "#D8DEE9",
+ "--slightly-grey-text"
+ ],
+ "SUSPENDED_BG": [
+ "Suspended Background",
+ "#ffffb2",
+ "#161320",
+ "--suspended-bg"
+ ],
+ "SUSPENDED_FG": [
+ "Suspended Foreground",
+ "#dd0",
+ "#ECEFF4",
+ "--suspended-fg"
+ ],
+ "TEXT_FG": [
+ "Text Foreground",
+ "black",
+ "#d9e0ee",
+ "--text-fg"
+ ],
+ "TOOLTIP_BG": [
+ "Tooltip Background",
+ "#fcfcfc",
+ "#4C566A",
+ "--tooltip-bg"
+ ],
+ "WINDOW_BG": [
+ "Window Background",
+ "#fafafa",
+ "#1E1E2E",
+ "--window-bg"
+ ],
+ "ZERO_COUNT": [
+ "Zero Count",
+ "#ddd",
+ "#434C5E",
+ "--zero-count"
+ ]
+ },
+ "version": {
+ "major": 1,
+ "minor": 5
+ }
+}
\ No newline at end of file diff --git a/.local/share/Anki2/addons21/anki_reworked/themes/Nord.json b/.local/share/Anki2/addons21/anki_reworked/themes/Nord.json new file mode 100644 index 0000000..25c507b --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/themes/Nord.json @@ -0,0 +1,230 @@ +{
+ "colors": {
+ "BORDER": [
+ "Border",
+ "#D8DEE9",
+ "#434C5E",
+ "--border"
+ ],
+ "BURIED_FG": [
+ "Buried Foreground",
+ "#aaaa33",
+ "#777733",
+ "--buried-fg"
+ ],
+ "BUTTON_BG": [
+ "Button Background",
+ "#D8DEE9",
+ "#3B4252",
+ ""
+ ],
+ "CURRENT_DECK": [
+ "Selected Deck",
+ "#E5E9F0",
+ "#3B4252",
+ "--current-deck"
+ ],
+ "DISABLED": [
+ "Disabled",
+ "#D8DEE9",
+ "#D8DEE9",
+ "--disabled"
+ ],
+ "FAINT_BORDER": [
+ "Faint Border",
+ "#ECEFF4",
+ "#3B4252",
+ "--faint-border"
+ ],
+ "FLAG1_BG": [
+ "Flag1 (Browse Cards List)",
+ "#BF616A",
+ "#BF616A",
+ "--flag1-bg"
+ ],
+ "FLAG1_FG": [
+ "Flag1 (BrowseSidebar)",
+ "#BF616A",
+ "#BF616A",
+ "--flag1-fg"
+ ],
+ "FLAG2_BG": [
+ "Flag2 (Browse Cards List)",
+ "#D08770",
+ "#D08770",
+ "--flag2-bg"
+ ],
+ "FLAG2_FG": [
+ "Flag2 (Browse Sidebar)",
+ "#D08770",
+ "#D08770",
+ "--flag2-fg"
+ ],
+ "FLAG3_BG": [
+ "Flag3 (Browse Cards List)",
+ "#A3BE8C",
+ "#A3BE8C",
+ "--flag3-bg"
+ ],
+ "FLAG3_FG": [
+ "Flag3 (Browse Sidebar)",
+ "#A3BE8C",
+ "#A3BE8C",
+ "--flag3-fg"
+ ],
+ "FLAG4_BG": [
+ "Flag4 (Browse Cards List)",
+ "#5E81AC",
+ "#5E81AC",
+ "--flag4-bg"
+ ],
+ "FLAG4_FG": [
+ "Flag4 (Browse Sidebar)",
+ "#5E81AC",
+ "#5E81AC",
+ "--flag4-fg"
+ ],
+ "FLAG5_BG": [
+ "Flag5 (Browse Cards List)",
+ "#B48EAD",
+ "#B48EAD",
+ "--flag5-bg"
+ ],
+ "FLAG5_FG": [
+ "Flag5 (Browse Sidebar)",
+ "#B48EAD",
+ "#B48EAD",
+ "--flag5-fg"
+ ],
+ "FLAG6_BG": [
+ "Flag6 (Browse Cards List)",
+ "#7edbd7",
+ "#399185",
+ "--flag6-bg"
+ ],
+ "FLAG6_FG": [
+ "Flag6 (Browse Sidebar)",
+ "#00d1b5",
+ "#5ccfca",
+ "--flag6-fg"
+ ],
+ "FLAG7_BG": [
+ "Flag7 (Browse Cards List)",
+ "#cca3f1",
+ "#624b77",
+ "--flag7-bg"
+ ],
+ "FLAG7_FG": [
+ "Flag7 (Browse Sidebar)",
+ "#9649dd",
+ "#9f63d3",
+ "--flag7-fg"
+ ],
+ "FRAME_BG": [
+ "Frame Background",
+ "#E5E9F0",
+ "#3B4252",
+ "--frame-bg"
+ ],
+ "HIGHLIGHT_BG": [
+ "Highlighted Background",
+ "#81A1C1",
+ "#81A1C1",
+ "--highlight-bg"
+ ],
+ "HIGHLIGHT_FG": [
+ "Highlighted Text",
+ "white",
+ "#ECEFF4",
+ "--highlight-fg"
+ ],
+ "LEARN_COUNT": [
+ "Learn Count",
+ "#D08770",
+ "#D08770",
+ "--learn-count"
+ ],
+ "LINK": [
+ "Hyperlink",
+ "#8FBCBB",
+ "#8FBCBB",
+ "--link"
+ ],
+ "MARKED_BG": [
+ "Marked Background",
+ "#EBCB8B",
+ "#EBCB8B",
+ "--marked-bg"
+ ],
+ "MEDIUM_BORDER": [
+ "Medium Border",
+ "#E5E9F0",
+ "#434C5E",
+ "--medium-border"
+ ],
+ "NEW_COUNT": [
+ "New Count",
+ "#5E81AC",
+ "#5E81AC",
+ "--new-count"
+ ],
+ "PRIMARY_COLOR": [
+ "Primary Color",
+ "#0093d0",
+ "#0093d0",
+ "--primary-color"
+ ],
+ "REVIEW_COUNT": [
+ "Review Count",
+ "#A3BE8C",
+ "#A3BE8C",
+ "--review-count"
+ ],
+ "SLIGHTLY_GREY_TEXT": [
+ "Switch Text",
+ "#3B4252",
+ "#D8DEE9",
+ "--slightly-grey-text"
+ ],
+ "SUSPENDED_BG": [
+ "Suspended Background",
+ "#88C0D0",
+ "#88C0D0",
+ "--suspended-bg"
+ ],
+ "SUSPENDED_FG": [
+ "Suspended Foreground",
+ "#3B4252",
+ "#ECEFF4",
+ "--suspended-fg"
+ ],
+ "TEXT_FG": [
+ "Text Foreground",
+ "#2E3440",
+ "#E5E9F0",
+ "--text-fg"
+ ],
+ "TOOLTIP_BG": [
+ "Tooltip Background",
+ "#D8DEE9",
+ "#4C566A",
+ "--tooltip-bg"
+ ],
+ "WINDOW_BG": [
+ "Window Background",
+ "white",
+ "#2E3440",
+ "--window-bg"
+ ],
+ "ZERO_COUNT": [
+ "Zero Count",
+ "#D8DEE9",
+ "#434C5E",
+ "--zero-count"
+ ]
+ },
+ "version": {
+ "major": 1,
+ "minor": 5
+ }
+}
\ No newline at end of file diff --git a/.local/share/Anki2/addons21/anki_reworked/themes/readme.txt b/.local/share/Anki2/addons21/anki_reworked/themes/readme.txt new file mode 100644 index 0000000..43f5cc1 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/themes/readme.txt @@ -0,0 +1,8 @@ +To create your own customized themes
+make a copy of Anki.json, name and edit it according
+to your wishes.
+
+This addon is also compatible with the themes of ReColor,
+which means that the uploaded community themes can also
+be downloaded and used:
+- https://github.com/AnKingMed/AnkiRecolor/wiki/Themes
diff --git a/.local/share/Anki2/addons21/anki_reworked/user_files/readme.txt b/.local/share/Anki2/addons21/anki_reworked/user_files/readme.txt new file mode 100644 index 0000000..f612d51 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/user_files/readme.txt @@ -0,0 +1,11 @@ +To create your own customized style design, +copy over the css files from ./files to ./user_files +you would like to edit. + +CSS files starting with "Q" indicates that the syntax is of +Qt CSS, which is in it's core quite similar to the usual CSS. +Documentation here: +- https://doc.qt.io/qt-5/stylesheet-syntax.html + +User edited themes should that is also customized will be saved +in this folder. diff --git a/.local/share/Anki2/addons21/anki_reworked/utils/css_files.py b/.local/share/Anki2/addons21/anki_reworked/utils/css_files.py new file mode 100644 index 0000000..0b88564 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/utils/css_files.py @@ -0,0 +1,37 @@ +import os +from aqt import mw + +mw.addonManager.setWebExports(__name__, r"files/.*\.(css|svg|gif|png)|user_files/.*\.(css|svg|gif|png)") +addon_package = mw.addonManager.addonFromModule(__name__) + +this_script_dir = os.path.join(os.path.dirname(__file__), "..") +files_dir = os.path.join(this_script_dir, 'files') +user_files_dir = os.path.join(this_script_dir, 'user_files') +css_files_dir = { + 'BottomBar': f"/_addons/{addon_package}/files/BottomBar.css", + 'CardLayout': f"/_addons/{addon_package}/files/CardLayout.css", + 'DeckBrowser': f"/_addons/{addon_package}/files/DeckBrowser.css", + 'Editor': f"/_addons/{addon_package}/files/Editor.css", + 'global': f"/_addons/{addon_package}/files/global.css", + 'legacy': f"/_addons/{addon_package}/files/legacy.css", + 'Overview': f"/_addons/{addon_package}/files/Overview.css", + 'QAbout': os.path.join(files_dir, 'QAbout.css'), + 'QAddCards': os.path.join(files_dir, 'QAddCards.css'), + 'QAddonsDialog': os.path.join(files_dir, 'QAddonsDialog.css'), + 'QBrowser': os.path.join(files_dir, 'QBrowser.css'), + 'QFilteredDeckConfigDialog': os.path.join(files_dir, 'QFilteredDeckConfigDialog.css'), + 'QEditCurrent': os.path.join(files_dir, 'QEditCurrent.css'), + 'QNewDeckStats': os.path.join(files_dir, 'QNewDeckStats.css'), + 'QPreferences': os.path.join(files_dir, 'QPreferences.css'), + 'Reviewer': f"/_addons/{addon_package}/files/Reviewer.css", + 'ReviewerBottomBar': f"/_addons/{addon_package}/files/ReviewerBottomBar.css", + 'TopToolbar': f"/_addons/{addon_package}/files/TopToolbar.css", +} +# Replace pathing for user customised styled files +for file in os.listdir(user_files_dir): + file = file.replace(".css", "") + if css_files_dir.get(file, "") != "": + if file.startswith("Q"): + css_files_dir[file] = os.path.join(user_files_dir, file+'.css') + else: + css_files_dir[file] = f"/_addons/{addon_package}/user_files/{file}.css" diff --git a/.local/share/Anki2/addons21/anki_reworked/utils/logger.py b/.local/share/Anki2/addons21/anki_reworked/utils/logger.py new file mode 100644 index 0000000..3c67988 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/utils/logger.py @@ -0,0 +1,17 @@ +import os +import logging +# declare an empty logger class +class EmptyLogger(): + def debug(self, *_): + return None +logger = EmptyLogger() +# init logger +if 'ANKI_REDESIGN_DEBUG_LOGGING' in os.environ: + filename = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "user_files", "test.log") + logging.basicConfig(format='%(asctime)s %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s', + datefmt='%Y%m%d-%H:%M:%S', + filename=filename, + level=logging.DEBUG) + logger = logging.getLogger('anki-redesign') + logger.setLevel(logging.DEBUG) + logger.debug("Initialized anki") diff --git a/.local/share/Anki2/addons21/anki_reworked/utils/modules.py b/.local/share/Anki2/addons21/anki_reworked/utils/modules.py new file mode 100644 index 0000000..fc55a12 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/utils/modules.py @@ -0,0 +1,18 @@ +def module_exists(module_name): + try: + __import__(module_name) + except ImportError: + return False + else: + return True + +def module_has_attribute(module_name, attribute): + if module_exists(module_name): + return hasattr(__import__(module_name), attribute) + return False + +def attribute_exists(object, attribute): + return attribute in object.__dict__ + +def context_name_includes(context, classname): + return classname in str(context.__class__)
\ No newline at end of file diff --git a/.local/share/Anki2/addons21/anki_reworked/utils/themes.py b/.local/share/Anki2/addons21/anki_reworked/utils/themes.py new file mode 100644 index 0000000..36af2d9 --- /dev/null +++ b/.local/share/Anki2/addons21/anki_reworked/utils/themes.py @@ -0,0 +1,34 @@ +import os +import json +from aqt import mw +from .logger import logger + +this_script_dir = os.path.join(os.path.dirname(__file__), "..") +themes_dir = os.path.join(this_script_dir, 'themes') + +def get_themes_dict() -> dict: + # Replace pathing for theme files (ReColor compatible) + themes = {} + for file in os.listdir(themes_dir): + if "json" in file: + file = file.replace(".json", "") + if themes.get(file, "") == "": + themes[file] = os.path.join(themes_dir, file+'.json') + return themes + +def get_theme(theme: str) -> dict: + themes_parsed = json.loads(open(themes[theme], encoding='utf-8').read()) + theme_colors = themes_parsed.get("colors") + # Add extra color_keys on theme files if not exist (ReColor compatible) + if not theme_colors.get("PRIMARY_COLOR", False): + theme_colors["PRIMARY_COLOR"] = ["Primary Color", "#0093d0", "#0093d0", "--primary-color"] + if not theme_colors.get("FOCUS_SHADOW", False): + theme_colors["FOCUS_SHADOW"] = ["Focus Shadow", "#ff93d0", "#0093d0", "--focus-shadow-color"] + themes_parsed["colors"] = theme_colors + return themes_parsed + +def write_theme(file, theme_content): + with open(file, "w") as f: + json.dump(theme_content, f, indent=2, sort_keys=True) + +themes = get_themes_dict() |