From f2173fddb04a95a3eff17494c9845736997131e4 Mon Sep 17 00:00:00 2001 From: RumovZ Date: Wed, 24 Nov 2021 22:17:41 +0100 Subject: [PATCH] Live theme changes (#1497) * Allow theme change at runtime and add hook * Save or restore default palette on theme change * Update aqt widget styles on theme change * styling fixes - drop _light_palette, as default_palette serves the same purpose - save default platform theme, and restore it when switching away from nightmode - update macOS light/dark mode on theme switch - fix unreadable menus on Windows * update night-mode classes on theme change This is the easy part - CSS styling that uses standard_css or our css variables should update automatically. The main remaining issue is JS code that sets colors based on the theme at the time it's run - eg the graph code, and the editor. * switch night mode value on toggle * expose current theme via a store; switch graphs to use it https://github.com/ankitects/anki/issues/1471#issuecomment-972402492 * start using currentTheme in editor/components This fixes basic editing - there are still components that need updating. * add simple xcodeproj for code completion * add helper to get currently-active system theme on macOS * fix setCurrentTheme not being immediately available * live update tag color * style().name() doesn't work on Qt5 * automatic theme switching on Windows/Mac * currentTheme -> pageTheme * Replace `nightModeKey` with `pageTheme` Co-authored-by: Damien Elmes --- ftl/core/preferences.ftl | 4 + qt/aqt/browser/sidebar/searchbar.py | 14 +- qt/aqt/browser/sidebar/toolbar.py | 8 + qt/aqt/browser/sidebar/tree.py | 19 +- qt/aqt/browser/table/table.py | 25 +- qt/aqt/clayout.py | 2 +- qt/aqt/forms/preferences.ui | 12 +- qt/aqt/main.py | 14 +- qt/aqt/platform.py | 49 ++- qt/aqt/preferences.py | 20 +- qt/aqt/profiles.py | 7 + qt/aqt/theme.py | 72 ++++- qt/aqt/webview.py | 30 +- qt/mac/AnkiHelper.m | 18 ++ qt/mac/ankihelper.xcodeproj/project.pbxproj | 280 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../UserInterfaceState.xcuserstate | Bin 0 -> 16238 bytes .../xcschemes/xcschememanagement.plist | 14 + qt/tools/genhooks_gui.py | 4 + ts/change-notetype/index.ts | 6 +- ts/components/ButtonToolbar.svelte | 9 +- ts/components/DropdownItem.svelte | 10 +- ts/components/IconButton.svelte | 8 +- ts/components/LabelButton.svelte | 8 +- ts/components/SelectButton.svelte | 12 +- ts/components/context-keys.ts | 1 - ts/deck-options/EnumSelector.svelte | 9 +- ts/deck-options/SpinBox.svelte | 7 +- ts/deck-options/SpinBoxFloat.svelte | 7 +- ts/deck-options/StepsInput.svelte | 7 +- ts/deck-options/Switch.svelte | 7 +- ts/deck-options/TextInputModal.svelte | 11 +- ts/deck-options/index.ts | 6 +- ts/editable/Mathjax.svelte | 7 +- ts/editable/mathjax-element.ts | 8 - ts/editor/AutocompleteItem.svelte | 10 +- ts/editor/HandleControl.svelte | 19 +- ts/editor/RichTextInput.svelte | 8 +- ts/editor/Tag.svelte | 10 +- ts/editor/TagWithTooltip.svelte | 8 +- ts/editor/index.ts | 9 - ts/graphs/GraphsPage.svelte | 4 +- ts/graphs/index.ts | 4 +- ts/lib/nightmode.ts | 4 +- ts/sveltelib/theme.ts | 35 +++ 46 files changed, 659 insertions(+), 182 deletions(-) create mode 100644 qt/mac/ankihelper.xcodeproj/project.pbxproj create mode 100644 qt/mac/ankihelper.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 qt/mac/ankihelper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 qt/mac/ankihelper.xcodeproj/project.xcworkspace/xcuserdata/dae.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 qt/mac/ankihelper.xcodeproj/xcuserdata/dae.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 ts/sveltelib/theme.ts diff --git a/ftl/core/preferences.ftl b/ftl/core/preferences.ftl index 6e3bf0730..facd16271 100644 --- a/ftl/core/preferences.ftl +++ b/ftl/core/preferences.ftl @@ -37,4 +37,8 @@ preferences-you-can-restore-backups-via-fileswitch = You can restore backups via preferences-legacy-timezone-handling = Legacy timezone handling (buggy, but required for AnkiDroid <= 2.14) preferences-default-search-text = Default search text preferences-default-search-text-example = eg. 'deck:current ' +preferences-theme-label = Theme: { $theme } +preferences-theme-follow-system = Follow System +preferences-theme-light = Light +preferences-theme-dark = Dark preferences-v3-scheduler = V3 scheduler diff --git a/qt/aqt/browser/sidebar/searchbar.py b/qt/aqt/browser/sidebar/searchbar.py index ae08f22fb..9d12e3fae 100644 --- a/qt/aqt/browser/sidebar/searchbar.py +++ b/qt/aqt/browser/sidebar/searchbar.py @@ -19,6 +19,14 @@ class SidebarSearchBar(QLineEdit): self.timer.setInterval(600) self.timer.setSingleShot(True) self.setFrame(False) + self.setup_style() + + qconnect(self.timer.timeout, self.onSearch) + qconnect(self.textChanged, self.onTextChanged) + + aqt.gui_hooks.theme_did_change.append(self.setup_style) + + def setup_style(self) -> None: border = theme_manager.color(colors.MEDIUM_BORDER) styles = [ "padding: 1px", @@ -32,9 +40,6 @@ class SidebarSearchBar(QLineEdit): self.setStyleSheet("QLineEdit { %s }" % ";".join(styles)) - qconnect(self.timer.timeout, self.onSearch) - qconnect(self.textChanged, self.onTextChanged) - def onTextChanged(self, text: str) -> None: if not self.timer.isActive(): self.timer.start() @@ -49,3 +54,6 @@ class SidebarSearchBar(QLineEdit): self.onSearch() else: QLineEdit.keyPressEvent(self, evt) + + def cleanup(self) -> None: + aqt.gui_hooks.theme_did_change.remove(self.setup_style) diff --git a/qt/aqt/browser/sidebar/toolbar.py b/qt/aqt/browser/sidebar/toolbar.py index 3f544682d..030b47041 100644 --- a/qt/aqt/browser/sidebar/toolbar.py +++ b/qt/aqt/browser/sidebar/toolbar.py @@ -31,6 +31,7 @@ class SidebarToolbar(QToolBar): self.setIconSize(QSize(16, 16)) self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) self.setStyle(QStyleFactory.create("fusion")) + aqt.gui_hooks.theme_did_change.append(self._update_icons) def _setup_tools(self) -> None: for row, tool in enumerate(self._tools): @@ -48,3 +49,10 @@ class SidebarToolbar(QToolBar): def _on_action_group_triggered(self, action: QAction) -> None: index = self._action_group.actions().index(action) self.sidebar.tool = self._tools[index][0] + + def cleanup(self) -> None: + aqt.gui_hooks.theme_did_change.remove(self._update_icons) + + def _update_icons(self) -> None: + for idx, action in enumerate(self._action_group.actions()): + action.setIcon(theme_manager.icon_from_resources(self._tools[idx][1])) diff --git a/qt/aqt/browser/sidebar/tree.py b/qt/aqt/browser/sidebar/tree.py index b7b88d01f..06f138994 100644 --- a/qt/aqt/browser/sidebar/tree.py +++ b/qt/aqt/browser/sidebar/tree.py @@ -91,6 +91,16 @@ class SidebarTreeView(QTreeView): qconnect(self.expanded, self._on_expansion) qconnect(self.collapsed, self._on_collapse) + self._setup_style() + + # these do not really belong here, they should be in a higher-level class + self.toolbar = SidebarToolbar(self) + self.searchBar = SidebarSearchBar(self) + + gui_hooks.flag_label_did_change.append(self.refresh) + gui_hooks.theme_did_change.append(self._setup_style) + + def _setup_style(self) -> None: # match window background color and tweak style bgcolor = QPalette().window().color().name() border = theme_manager.color(colors.MEDIUM_BORDER) @@ -105,14 +115,11 @@ class SidebarTreeView(QTreeView): self.setStyleSheet("QTreeView { %s }" % ";".join(styles)) - # these do not really belong here, they should be in a higher-level class - self.toolbar = SidebarToolbar(self) - self.searchBar = SidebarSearchBar(self) - - gui_hooks.flag_label_did_change.append(self.refresh) - def cleanup(self) -> None: + self.toolbar.cleanup() + self.searchBar.cleanup() gui_hooks.flag_label_did_change.remove(self.refresh) + gui_hooks.theme_did_change.remove(self._setup_style) @property def tool(self) -> SidebarTool: diff --git a/qt/aqt/browser/table/table.py b/qt/aqt/browser/table/table.py index c11a518da..7ddc68b57 100644 --- a/qt/aqt/browser/table/table.py +++ b/qt/aqt/browser/table/table.py @@ -59,6 +59,7 @@ class Table: def cleanup(self) -> None: self._save_header() + gui_hooks.theme_did_change.remove(self._setup_style) # Public Methods ###################################################################### @@ -342,17 +343,10 @@ class Table: self._view.setHorizontalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel) self._view.horizontalScrollBar().setSingleStep(10) self._update_font() - if not theme_manager.night_mode: - self._view.setStyleSheet( - "QTableView{ selection-background-color: rgba(150, 150, 150, 50); " - "selection-color: black; }" - ) - elif theme_manager.macos_dark_mode(): - self._view.setStyleSheet( - f"QTableView {{ gridline-color: {colors.FRAME_BG} }}" - ) + self._setup_style() self._view.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) qconnect(self._view.customContextMenuRequested, self._on_context_menu) + gui_hooks.theme_did_change.append(self._setup_style) def _update_font(self) -> None: # we can't choose different line heights efficiently, so we need @@ -365,6 +359,19 @@ class Table: curmax = bsize self._view.verticalHeader().setDefaultSectionSize(curmax + 6) + def _setup_style(self) -> None: + if not theme_manager.night_mode: + self._view.setStyleSheet( + "QTableView{ selection-background-color: rgba(150, 150, 150, 50); " + "selection-color: black; }" + ) + elif theme_manager.macos_dark_mode(): + self._view.setStyleSheet( + f"QTableView {{ gridline-color: {colors.FRAME_BG} }}" + ) + else: + self._view.setStyleSheet("") + def _setup_headers(self) -> None: vh = self._view.verticalHeader() hh = self._view.horizontalHeader() diff --git a/qt/aqt/clayout.py b/qt/aqt/clayout.py index ca081af87..5771278f9 100644 --- a/qt/aqt/clayout.py +++ b/qt/aqt/clayout.py @@ -55,7 +55,7 @@ class CardLayout(QDialog): self.model = note.note_type() self.templates = self.model["tmpls"] self.fill_empty_action_toggled = fill_empty - self.night_mode_is_enabled = self.mw.pm.night_mode() + self.night_mode_is_enabled = theme_manager.night_mode self.mobile_emulation_enabled = False self.have_autoplayed = False self.mm._remove_from_cache(self.model["id"]) diff --git a/qt/aqt/forms/preferences.ui b/qt/aqt/forms/preferences.ui index 6ab365da3..9bff83670 100644 --- a/qt/aqt/forms/preferences.ui +++ b/qt/aqt/forms/preferences.ui @@ -55,6 +55,9 @@ + + + @@ -86,13 +89,6 @@ - - - - preferences_night_mode - - - @@ -602,12 +598,12 @@ lang + theme video_driver showPlayButtons interrupt_audio pastePNG paste_strips_formatting - nightMode useCurrent default_search_text uiScale diff --git a/qt/aqt/main.py b/qt/aqt/main.py index d40fcd935..47378c0e0 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -47,7 +47,7 @@ from aqt.qt import * from aqt.qt import sip from aqt.sync import sync_collection, sync_login from aqt.taskman import TaskManager -from aqt.theme import theme_manager +from aqt.theme import Theme, theme_manager from aqt.undo import UndoActionsInfo from aqt.utils import ( HelpPage, @@ -145,11 +145,11 @@ class AnkiQt(QMainWindow): self.setupMediaServer() self.setupSound() self.setupSpellCheck() + self.setupProgress() self.setupStyle() self.setupMainWindow() self.setupSystemSpecific() self.setupMenus() - self.setupProgress() self.setupErrorHandler() self.setupSignals() self.setupAutoUpdate() @@ -1004,8 +1004,14 @@ title="{}" {}>{}""".format( return True def setupStyle(self) -> None: - theme_manager.night_mode = self.pm.night_mode() - theme_manager.apply_style(self.app) + theme_manager.apply_style() + self.progress.timer( + 5 * 1000, theme_manager.apply_style_if_system_style_changed, True, False + ) + + def set_theme(self, theme: Theme) -> None: + self.pm.set_theme(theme) + self.setupStyle() # Key handling ########################################################################## diff --git a/qt/aqt/platform.py b/qt/aqt/platform.py index fdf038e1b..ace59fd44 100644 --- a/qt/aqt/platform.py +++ b/qt/aqt/platform.py @@ -3,20 +3,40 @@ """Platform-specific functionality.""" +from __future__ import annotations + import os import sys from ctypes import CDLL import aqt.utils -from anki.utils import isMac +from anki.utils import isMac, isWin -def set_dark_mode(enabled: bool) -> bool: +def get_windows_dark_mode() -> bool: + "True if Windows system is currently in dark mode." + if not isWin: + return False + + from winreg import ( # pylint: disable=import-error + HKEY_CURRENT_USER, + OpenKey, + QueryValueEx, + ) + + key = OpenKey( + HKEY_CURRENT_USER, + r"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", + ) + return not QueryValueEx(key, "AppsUseLightTheme")[0] + + +def set_macos_dark_mode(enabled: bool) -> bool: "True if setting successful." if not isMac: return False try: - _set_dark_mode(enabled) + _ankihelper().set_darkmode_enabled(enabled) return True except Exception as e: # swallow exceptions, as library will fail on macOS 10.13 @@ -24,9 +44,28 @@ def set_dark_mode(enabled: bool) -> bool: return False -def _set_dark_mode(enabled: bool) -> None: +def get_macos_dark_mode() -> bool: + "True if macOS system is currently in dark mode." + if not isMac: + return False + try: + return _ankihelper().system_is_dark() + except Exception as e: + # swallow exceptions, as library will fail on macOS 10.13 + print(e) + return False + + +_ankihelper_dll: CDLL | None = None + + +def _ankihelper() -> CDLL: + global _ankihelper_dll + if _ankihelper_dll: + return _ankihelper_dll if getattr(sys, "frozen", False): path = os.path.join(sys.prefix, "libankihelper.dylib") else: path = os.path.join(aqt.utils.aqt_data_folder(), "lib", "libankihelper.dylib") - CDLL(path).set_darkmode_enabled(enabled) + _ankihelper_dll = CDLL(path) + return _ankihelper_dll diff --git a/qt/aqt/preferences.py b/qt/aqt/preferences.py index 134507865..e677728e1 100644 --- a/qt/aqt/preferences.py +++ b/qt/aqt/preferences.py @@ -11,6 +11,7 @@ from aqt import AnkiQt from aqt.operations.collection import set_preferences from aqt.profiles import VideoDriver from aqt.qt import * +from aqt.theme import Theme from aqt.utils import HelpPage, disable_help_button, openHelp, showInfo, showWarning, tr @@ -199,7 +200,17 @@ class Preferences(QDialog): def setup_global(self) -> None: "Setup options global to all profiles." self.form.uiScale.setValue(int(self.mw.pm.uiScale() * 100)) - self.form.nightMode.setChecked(self.mw.pm.night_mode()) + themes = [ + tr.preferences_theme_label(theme=theme) + for theme in ( + tr.preferences_theme_follow_system(), + tr.preferences_theme_light(), + tr.preferences_theme_dark(), + ) + ] + self.form.theme.addItems(themes) + self.form.theme.setCurrentIndex(self.mw.pm.theme().value) + qconnect(self.form.theme.currentIndexChanged, self.on_theme_changed) self.setup_language() self.setup_video_driver() @@ -216,15 +227,14 @@ class Preferences(QDialog): self.mw.pm.setUiScale(newScale) restart_required = True - if self.mw.pm.night_mode() != self.form.nightMode.isChecked(): - self.mw.pm.set_night_mode(not self.mw.pm.night_mode()) - restart_required = True - if restart_required: showInfo(tr.preferences_changes_will_take_effect_when_you()) self.updateOptions() + def on_theme_changed(self, index: int) -> None: + self.mw.set_theme(Theme(index)) + # legacy - one of Henrik's add-ons is currently wrapping them def setupOptions(self) -> None: diff --git a/qt/aqt/profiles.py b/qt/aqt/profiles.py index 976ca37e7..da37dc53c 100644 --- a/qt/aqt/profiles.py +++ b/qt/aqt/profiles.py @@ -23,6 +23,7 @@ from anki.sync import SyncAuth from anki.utils import int_time, isMac, isWin from aqt import appHelpSite from aqt.qt import * +from aqt.theme import Theme from aqt.utils import disable_help_button, showWarning, tr # Profile handling @@ -515,6 +516,12 @@ create table if not exists profiles def set_night_mode(self, on: bool) -> None: self.meta["night_mode"] = on + def theme(self) -> Theme: + return Theme(self.meta.get("theme", 0)) + + def set_theme(self, theme: Theme) -> None: + self.meta["theme"] = theme.value + def dark_mode_widgets(self) -> bool: return self.meta.get("dark_mode_widgets", False) diff --git a/qt/aqt/theme.py b/qt/aqt/theme.py index 7fde423aa..b28860234 100644 --- a/qt/aqt/theme.py +++ b/qt/aqt/theme.py @@ -3,12 +3,14 @@ from __future__ import annotations +import enum import platform from dataclasses import dataclass +import aqt from anki.utils import isMac from aqt import QApplication, colors, gui_hooks, isWin -from aqt.platform import set_dark_mode +from aqt.platform import get_macos_dark_mode, get_windows_dark_mode, set_macos_dark_mode from aqt.qt import ( QColor, QGuiApplication, @@ -37,6 +39,12 @@ class ColoredIcon: return ColoredIcon(path=self.path, color=color) +class Theme(enum.IntEnum): + FOLLOW_SYSTEM = 0 + LIGHT = 1 + DARK = 2 + + class ThemeManager: _night_mode_preference = False _icon_cache_light: dict[str, QIcon] = {} @@ -44,6 +52,7 @@ class ThemeManager: _icon_size = 128 _dark_mode_available: bool | None = None default_palette: QPalette | None = None + _default_style: str | None = None # Qt applies a gradient to the buttons in dark mode # from about #505050 to #606060. @@ -58,7 +67,7 @@ class ThemeManager: return False if self._dark_mode_available is None: - self._dark_mode_available = set_dark_mode(True) + self._dark_mode_available = set_macos_dark_mode(True) from aqt import mw @@ -143,28 +152,57 @@ class ThemeManager: def qcolor(self, colors: tuple[str, str]) -> QColor: return QColor(self.color(colors)) - def apply_style(self, app: QApplication) -> None: - self.default_palette = QGuiApplication.palette() + def _determine_night_mode(self) -> bool: + theme = aqt.mw.pm.theme() + if theme == Theme.LIGHT: + return False + elif theme == Theme.DARK: + return True + else: + if isWin: + return get_windows_dark_mode() + elif isMac: + return get_macos_dark_mode() + else: + # not supported on Linux + return False + + def apply_style_if_system_style_changed(self) -> None: + theme = aqt.mw.pm.theme() + if theme != Theme.FOLLOW_SYSTEM: + return + if self._determine_night_mode() != self.night_mode: + self.apply_style() + + def apply_style(self) -> None: + "Apply currently configured style." + app = aqt.mw.app + self.night_mode = self._determine_night_mode() + if not self.default_palette: + self.default_palette = QGuiApplication.palette() + self._default_style = app.style().objectName() self._apply_palette(app) self._apply_style(app) + gui_hooks.theme_did_change() def _apply_style(self, app: QApplication) -> None: buf = "" - if isWin and platform.release() == "10" and not self.night_mode: - # add missing bottom border to menubar - buf += """ -QMenuBar { - border-bottom: 1px solid #aaa; - background: white; -} + if isWin and platform.release() == "10": + # day mode is missing a bottom border; background must be + # also set for border to apply + buf += f""" +QMenuBar {{ + border-bottom: 1px solid {self.color(colors.BORDER)}; + background: {self.color(colors.WINDOW_BG)}; +}} """ # qt bug? setting the above changes the browser sidebar # to white as well, so set it back - buf += """ -QTreeWidget { - background: #eee; -} + buf += f""" +QTreeWidget {{ + background: {self.color(colors.WINDOW_BG)}; +}} """ if self.night_mode: @@ -209,7 +247,11 @@ QTabWidget {{ background-color: {}; }} app.setStyleSheet(buf) def _apply_palette(self, app: QApplication) -> None: + set_macos_dark_mode(self.night_mode) + if not self.night_mode: + app.setStyle(QStyleFactory.create(self._default_style)) # type: ignore + app.setPalette(self.default_palette) return if not self.macos_dark_mode(): diff --git a/qt/aqt/webview.py b/qt/aqt/webview.py index 21e1e79df..dd3a7f8f9 100644 --- a/qt/aqt/webview.py +++ b/qt/aqt/webview.py @@ -252,6 +252,7 @@ class AnkiWebView(QWebEngineView): context=Qt.ShortcutContext.WidgetWithChildrenShortcut, activated=self.onEsc, ) + gui_hooks.theme_did_change.append(self.on_theme_did_change) def set_title(self, title: str) -> None: self.title = title # type: ignore[assignment] @@ -445,7 +446,7 @@ div[contenteditable="true"]:focus {{ lang_dir = "ltr" return f""" -body {{ zoom: {zoom}; background-color: {body_bg}; direction: {lang_dir}; }} +body {{ zoom: {zoom}; background-color: --window-bg; direction: {lang_dir}; }} html {{ {font} }} {button_style} :root {{ --window-bg: {window_bg_day} }} @@ -551,6 +552,8 @@ html {{ {font} }} self._maybeRunActions() def _maybeRunActions(self) -> None: + if sip.isdeleted(self): + return while self._pendingActions and self._domDone: name, args = self._pendingActions.pop(0) @@ -675,4 +678,29 @@ document.head.appendChild(style); # this will fail when __del__ is called during app shutdown return + gui_hooks.theme_did_change.remove(self.on_theme_did_change) mw.mediaServer.clear_page_html(id(self)) + + def on_theme_did_change(self) -> None: + # avoid flashes if page reloaded + self._page.setBackgroundColor( + self.get_window_bg_color(theme_manager.night_mode) + ) + # update night-mode class, and legacy nightMode/night-mode body classes + self.eval( + f""" +(function() {{ + const doc = document.documentElement.classList; + const body = document.body.classList; + if ({1 if theme_manager.night_mode else 0}) {{ + doc.add("night-mode"); + body.add("night-mode"); + body.add("nightMode"); + }} else {{ + doc.remove("night-mode"); + body.remove("night-mode"); + body.remove("nightMode"); + }} +}})(); +""" + ) diff --git a/qt/mac/AnkiHelper.m b/qt/mac/AnkiHelper.m index b0bda45e1..2b461ee82 100644 --- a/qt/mac/AnkiHelper.m +++ b/qt/mac/AnkiHelper.m @@ -4,6 +4,7 @@ @import Foundation; @import AppKit; +/// Force our app to be either light or dark mode. void set_darkmode_enabled(BOOL enabled) { NSAppearance *appearance; if (enabled) { @@ -14,3 +15,20 @@ void set_darkmode_enabled(BOOL enabled) { [NSApplication sharedApplication].appearance = appearance; } + +/// True if the system is set to dark mode. +BOOL system_is_dark(void) { + BOOL styleSet = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleInterfaceStyle"] != nil; + return styleSet; + // FIXME: confirm whether this is required on 10.15/16 (it + // does not appear to be on 11) + + // BOOL autoSwitch = [[NSUserDefaults standardUserDefaults] boolForKey:@"AppleInterfaceStyleSwitchesAutomatically"]; + // + // if (@available(macOS 10.15, *)) { + // return autoSwitch ? !styleSet : styleSet; + // } else { + // return styleSet; + // } + +} diff --git a/qt/mac/ankihelper.xcodeproj/project.pbxproj b/qt/mac/ankihelper.xcodeproj/project.pbxproj new file mode 100644 index 000000000..d03fb4567 --- /dev/null +++ b/qt/mac/ankihelper.xcodeproj/project.pbxproj @@ -0,0 +1,280 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + 1327600A274613D9001D63D7 /* AnkiHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 13276009274613D8001D63D7 /* AnkiHelper.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 13276009274613D8001D63D7 /* AnkiHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AnkiHelper.m; sourceTree = ""; }; + 138B770F2746137F003A3E4F /* libankihelper.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libankihelper.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 138B770D2746137F003A3E4F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 138B77062746137F003A3E4F = { + isa = PBXGroup; + children = ( + 13276009274613D8001D63D7 /* AnkiHelper.m */, + 138B77102746137F003A3E4F /* Products */, + ); + sourceTree = ""; + }; + 138B77102746137F003A3E4F /* Products */ = { + isa = PBXGroup; + children = ( + 138B770F2746137F003A3E4F /* libankihelper.dylib */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 138B770B2746137F003A3E4F /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 138B770E2746137F003A3E4F /* ankihelper */ = { + isa = PBXNativeTarget; + buildConfigurationList = 138B77182746137F003A3E4F /* Build configuration list for PBXNativeTarget "ankihelper" */; + buildPhases = ( + 138B770B2746137F003A3E4F /* Headers */, + 138B770C2746137F003A3E4F /* Sources */, + 138B770D2746137F003A3E4F /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ankihelper; + productName = ankihelper; + productReference = 138B770F2746137F003A3E4F /* libankihelper.dylib */; + productType = "com.apple.product-type.library.dynamic"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 138B77072746137F003A3E4F /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastUpgradeCheck = 1310; + TargetAttributes = { + 138B770E2746137F003A3E4F = { + CreatedOnToolsVersion = 13.1; + }; + }; + }; + buildConfigurationList = 138B770A2746137F003A3E4F /* Build configuration list for PBXProject "ankihelper" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 138B77062746137F003A3E4F; + productRefGroup = 138B77102746137F003A3E4F /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 138B770E2746137F003A3E4F /* ankihelper */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 138B770C2746137F003A3E4F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1327600A274613D9001D63D7 /* AnkiHelper.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 138B77162746137F003A3E4F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 11.6; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 138B77172746137F003A3E4F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 11.6; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + }; + name = Release; + }; + 138B77192746137F003A3E4F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7ZM8SLJM4P; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 138B771A2746137F003A3E4F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7ZM8SLJM4P; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 138B770A2746137F003A3E4F /* Build configuration list for PBXProject "ankihelper" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 138B77162746137F003A3E4F /* Debug */, + 138B77172746137F003A3E4F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 138B77182746137F003A3E4F /* Build configuration list for PBXNativeTarget "ankihelper" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 138B77192746137F003A3E4F /* Debug */, + 138B771A2746137F003A3E4F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 138B77072746137F003A3E4F /* Project object */; +} diff --git a/qt/mac/ankihelper.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/qt/mac/ankihelper.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/qt/mac/ankihelper.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/qt/mac/ankihelper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/qt/mac/ankihelper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/qt/mac/ankihelper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/qt/mac/ankihelper.xcodeproj/project.xcworkspace/xcuserdata/dae.xcuserdatad/UserInterfaceState.xcuserstate b/qt/mac/ankihelper.xcodeproj/project.xcworkspace/xcuserdata/dae.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..255052f657c793b78e3639d5588108e23711424a GIT binary patch literal 16238 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 b&d;33onJb?37e2a`sUV$ZO8Ce(d7RFP$W&3 literal 0 HcmV?d00001 diff --git a/qt/mac/ankihelper.xcodeproj/xcuserdata/dae.xcuserdatad/xcschemes/xcschememanagement.plist b/qt/mac/ankihelper.xcodeproj/xcuserdata/dae.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 000000000..7b914bfe3 --- /dev/null +++ b/qt/mac/ankihelper.xcodeproj/xcuserdata/dae.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + ankihelper.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/qt/tools/genhooks_gui.py b/qt/tools/genhooks_gui.py index 8910a1c17..3c2938a0d 100644 --- a/qt/tools/genhooks_gui.py +++ b/qt/tools/genhooks_gui.py @@ -540,6 +540,10 @@ hooks = [ there are no outstanding ops. """, ), + Hook( + name="theme_did_change", + doc="Called after night mode is toggled.", + ), # Webview ################### Hook( diff --git a/ts/change-notetype/index.ts b/ts/change-notetype/index.ts index b57572b9f..eaa5aa639 100644 --- a/ts/change-notetype/index.ts +++ b/ts/change-notetype/index.ts @@ -9,7 +9,6 @@ import { ChangeNotetypeState, getChangeNotetypeInfo, getNotetypeNames } from "./ import { setupI18n, ModuleName } from "../lib/i18n"; import { checkNightMode } from "../lib/nightmode"; import ChangeNotetypePage from "./ChangeNotetypePage.svelte"; -import { nightModeKey } from "../components/context-keys"; export async function changeNotetypePage( target: HTMLDivElement, @@ -28,14 +27,11 @@ export async function changeNotetypePage( }), ]); - const nightMode = checkNightMode(); - const context = new Map(); - context.set(nightModeKey, nightMode); + checkNightMode(); const state = new ChangeNotetypeState(names, info); return new ChangeNotetypePage({ target, props: { state }, - context, } as any); } diff --git a/ts/components/ButtonToolbar.svelte b/ts/components/ButtonToolbar.svelte index baa79fd7a..b6b29b78e 100644 --- a/ts/components/ButtonToolbar.svelte +++ b/ts/components/ButtonToolbar.svelte @@ -16,13 +16,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html