mirror of
https://github.com/ankitects/anki.git
synced 2025-09-22 16:02:23 -04:00
Revamp preferences, add minimalist mode
Also: - create additional and missing widget styles and tweak existing ones - use single profile entry to set widget styles and reduce choices to Anki and Native
This commit is contained in:
parent
0e559bff8b
commit
9f6db2c208
21 changed files with 1649 additions and 1142 deletions
|
@ -4,13 +4,13 @@ preferences-basic = Basic
|
||||||
preferences-change-deck-depending-on-note-type = Change deck depending on note type
|
preferences-change-deck-depending-on-note-type = Change deck depending on note type
|
||||||
preferences-changes-will-take-effect-when-you = Changes will take effect when you restart Anki.
|
preferences-changes-will-take-effect-when-you = Changes will take effect when you restart Anki.
|
||||||
preferences-hours-past-midnight = hours past midnight
|
preferences-hours-past-midnight = hours past midnight
|
||||||
preferences-interface-language = Interface language:
|
preferences-language = Language
|
||||||
preferences-interrupt-current-audio-when-answering = Interrupt current audio when answering
|
preferences-interrupt-current-audio-when-answering = Interrupt current audio when answering
|
||||||
preferences-learn-ahead-limit = Learn ahead limit
|
preferences-learn-ahead-limit = Learn ahead limit
|
||||||
preferences-mins = mins
|
preferences-mins = mins
|
||||||
preferences-network = Network
|
preferences-network = Network
|
||||||
preferences-next-day-starts-at = Next day starts at
|
preferences-next-day-starts-at = Next day starts at
|
||||||
preferences-note-media-is-not-backed-up = Note: Media is not backed up. Please create a periodic backup of your Anki folder to be safe.
|
preferences-note-media-is-not-backed-up = Media is not backed up. Please create a periodic backup of your Anki folder to be safe.
|
||||||
preferences-on-next-sync-force-changes-in = On next sync, force changes in one direction
|
preferences-on-next-sync-force-changes-in = On next sync, force changes in one direction
|
||||||
preferences-paste-clipboard-images-as-png = Paste clipboard images as PNG
|
preferences-paste-clipboard-images-as-png = Paste clipboard images as PNG
|
||||||
preferences-paste-without-shift-key-strips-formatting = Paste without shift key strips formatting
|
preferences-paste-without-shift-key-strips-formatting = Paste without shift key strips formatting
|
||||||
|
@ -21,19 +21,19 @@ preferences-scheduling = Scheduling
|
||||||
preferences-show-learning-cards-with-larger-steps = Show learning cards with larger steps before reviews
|
preferences-show-learning-cards-with-larger-steps = Show learning cards with larger steps before reviews
|
||||||
preferences-show-next-review-time-above-answer = Show next review time above answer buttons
|
preferences-show-next-review-time-above-answer = Show next review time above answer buttons
|
||||||
preferences-show-play-buttons-on-cards-with = Show play buttons on cards with audio
|
preferences-show-play-buttons-on-cards-with = Show play buttons on cards with audio
|
||||||
preferences-show-remaining-card-count-during-review = Show remaining card count during review
|
preferences-show-remaining-card-count-during-review = Show remaining card count
|
||||||
preferences-some-settings-will-take-effect-after = Some settings will take effect after you restart Anki.
|
preferences-some-settings-will-take-effect-after = Some settings will take effect after you restart Anki.
|
||||||
preferences-synchronisation = <b>Synchronisation</b>
|
preferences-synchronisation = Synchronisation
|
||||||
preferences-synchronizationnot-currently-enabled-click-the-sync = <b>Synchronization</b><br> Not currently enabled; click the sync button in the main window to enable.
|
preferences-synchronizationnot-currently-enabled-click-the-sync = <b>Synchronization</b><br> Not currently enabled; click the sync button in the main window to enable.
|
||||||
preferences-synchronize-audio-and-images-too = Synchronize audio and images too
|
preferences-synchronize-audio-and-images-too = Synchronize audio and images too
|
||||||
preferences-timebox-time-limit = Timebox time limit
|
preferences-timebox-time-limit = Timebox time limit
|
||||||
preferences-user-interface-size = User interface size
|
preferences-user-interface-size = User interface size
|
||||||
preferences-when-adding-default-to-current-deck = When adding, default to current deck
|
preferences-when-adding-default-to-current-deck = When adding, default to current deck
|
||||||
preferences-you-can-restore-backups-via-fileswitch = You can restore backups via File>Switch Profile.
|
preferences-you-can-restore-backups-via-fileswitch = You can restore backups via File > Switch Profile.
|
||||||
preferences-legacy-timezone-handling = Legacy timezone handling (buggy, but required for AnkiDroid <= 2.14)
|
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 = Default search text
|
||||||
preferences-default-search-text-example = eg. 'deck:current '
|
preferences-default-search-text-example = eg. 'deck:current '
|
||||||
preferences-theme-label = Theme: { $theme }
|
preferences-theme = Theme
|
||||||
preferences-theme-follow-system = Follow System
|
preferences-theme-follow-system = Follow System
|
||||||
preferences-theme-light = Light
|
preferences-theme-light = Light
|
||||||
preferences-theme-dark = Dark
|
preferences-theme-dark = Dark
|
||||||
|
@ -48,4 +48,21 @@ preferences-monthly-backups = Monthly backups to keep:
|
||||||
preferences-minutes-between-backups = Minutes between automatic backups:
|
preferences-minutes-between-backups = Minutes between automatic backups:
|
||||||
preferences-reduce-motion = Reduce motion
|
preferences-reduce-motion = Reduce motion
|
||||||
preferences-reduce-motion-tooltip = Disable various animations and transitions of the user interface
|
preferences-reduce-motion-tooltip = Disable various animations and transitions of the user interface
|
||||||
preferences-collapse-toolbar = Hide top bar during review
|
preferences-collapse-toolbar = Hide top bar
|
||||||
|
preferences-appearance = Appearance
|
||||||
|
preferences-general = General
|
||||||
|
preferences-style = Style
|
||||||
|
preferences-review = Review
|
||||||
|
preferences-reviewer = Reviewer
|
||||||
|
preferences-distractions = Distractions
|
||||||
|
preferences-minimalist-mode = Minimalist mode
|
||||||
|
preferences-editing = Editing
|
||||||
|
preferences-browsing = Browsing
|
||||||
|
preferences-default-deck = Default deck
|
||||||
|
preferences-account = AnkiWeb Account
|
||||||
|
preferences-media = Media
|
||||||
|
preferences-note = Note
|
||||||
|
preferences-limits = Limits
|
||||||
|
preferences-scheduler = Scheduler
|
||||||
|
preferences-user-interface = User Interface
|
||||||
|
preferences-import-export = Import/Export
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
## Video drivers/hardware acceleration. Please avoid translating 'OpenGL' and 'ANGLE'.
|
## Video drivers/hardware acceleration. Please avoid translating 'OpenGL' and 'ANGLE'.
|
||||||
|
|
||||||
preferences-video-driver = Video driver: { $driver }
|
preferences-video-driver = Video driver
|
||||||
preferences-video-driver-opengl-mac = OpenGL (recommended on Macs)
|
preferences-video-driver-opengl-mac = OpenGL (recommended on Macs)
|
||||||
preferences-video-driver-software-mac = Software (not recommended)
|
preferences-video-driver-software-mac = Software (not recommended)
|
||||||
preferences-video-driver-opengl-other = OpenGL (faster, may cause issues)
|
preferences-video-driver-opengl-other = OpenGL (faster, may cause issues)
|
||||||
|
|
|
@ -351,6 +351,7 @@ class AnkiApp(QApplication):
|
||||||
QCheckBox,
|
QCheckBox,
|
||||||
QRadioButton,
|
QRadioButton,
|
||||||
QMenu,
|
QMenu,
|
||||||
|
QSlider,
|
||||||
# classes with PyQt5 compatibility proxy
|
# classes with PyQt5 compatibility proxy
|
||||||
without_qt5_compat_wrapper(QToolButton),
|
without_qt5_compat_wrapper(QToolButton),
|
||||||
without_qt5_compat_wrapper(QTabBar),
|
without_qt5_compat_wrapper(QTabBar),
|
||||||
|
|
|
@ -7,17 +7,19 @@
|
||||||
|
|
||||||
table {
|
table {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background: var(--canvas-elevated);
|
|
||||||
border: 1px solid var(--border-subtle);
|
|
||||||
border-radius: var(--border-radius-large);
|
|
||||||
|
|
||||||
@include elevation(1, $opacity-boost: -0.08);
|
.fancy & {
|
||||||
&:hover {
|
border: 1px solid var(--border-subtle);
|
||||||
@include elevation(2);
|
border-radius: var(--border-radius-medium);
|
||||||
|
|
||||||
|
@include elevation(1, $opacity-boost: -0.08);
|
||||||
|
&:hover {
|
||||||
|
@include elevation(2);
|
||||||
|
}
|
||||||
|
transition: box-shadow var(--transition) ease-in-out;
|
||||||
|
background: var(--canvas-glass);
|
||||||
|
backdrop-filter: blur(var(--blur));
|
||||||
}
|
}
|
||||||
transition: box-shadow var(--transition) ease-in-out;
|
|
||||||
background: var(--canvas-glass);
|
|
||||||
backdrop-filter: blur(var(--blur));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a.deck {
|
a.deck {
|
||||||
|
@ -37,7 +39,11 @@ th {
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.deck td {
|
tr.deck td {
|
||||||
padding: 4px 12px;
|
padding: 2px 12px;
|
||||||
|
|
||||||
|
.fancy & {
|
||||||
|
padding: 4px 12px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.top-level-drag-row td {
|
tr.top-level-drag-row td {
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
@use "sass/button-mixins" as button;
|
@use "sass/button-mixins" as button;
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
height: 41px;
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, 1fr);
|
grid-template-columns: repeat(3, 1fr);
|
||||||
align-items: start;
|
align-items: start;
|
||||||
|
@ -31,65 +30,88 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
height: 31px;
|
|
||||||
justify-self: center;
|
justify-self: center;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
|
||||||
border-bottom-left-radius: prop(border-radius-large);
|
|
||||||
border-bottom-right-radius: prop(border-radius-large);
|
|
||||||
@include elevation(1, $opacity-boost: -0.1);
|
|
||||||
|
|
||||||
// elevated state (deck browser, overview)
|
|
||||||
body:not(.flat) & {
|
|
||||||
background: var(--canvas-elevated);
|
|
||||||
@include elevation(1);
|
|
||||||
&:hover {
|
|
||||||
@include elevation(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// glass effect
|
|
||||||
background: var(--canvas-glass);backdrop-filter: unset;
|
|
||||||
backdrop-filter: blur(var(--blur));
|
|
||||||
|
|
||||||
transition: all var(--transition) ease-in-out;
|
transition: all var(--transition) ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hitem {
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 5px 12px;
|
||||||
|
color: color(fg);
|
||||||
|
display: inline-block;
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&.collapsed {
|
&:not(.fancy).collapsed {
|
||||||
transform: translateY(-100vh);
|
opacity: 0;
|
||||||
|
}
|
||||||
|
transition: opacity var(--transition) ease-in-out;
|
||||||
|
|
||||||
|
&.fancy {
|
||||||
|
&.collapsed {
|
||||||
|
transform: translateY(-100vh);
|
||||||
|
}
|
||||||
|
transition: transform var(--transition) ease-in-out;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
height: 41px;
|
||||||
|
}
|
||||||
|
.toolbar {
|
||||||
|
height: 31px;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
border-bottom-left-radius: prop(border-radius-medium);
|
||||||
|
border-bottom-right-radius: prop(border-radius-medium);
|
||||||
|
@include elevation(1, $opacity-boost: -0.1);
|
||||||
|
|
||||||
|
// elevated state (deck browser, overview)
|
||||||
|
body:not(.flat) & {
|
||||||
|
background: var(--canvas-elevated);
|
||||||
|
@include elevation(1);
|
||||||
|
&:hover {
|
||||||
|
@include elevation(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// glass effect
|
||||||
|
background: var(--canvas-glass);
|
||||||
|
backdrop-filter: blur(var(--blur));
|
||||||
|
}
|
||||||
|
|
||||||
|
.hitem {
|
||||||
|
&:hover {
|
||||||
|
background: var(--canvas-inset);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
@include button.base($border: false);
|
||||||
|
background: var(--canvas-elevated);
|
||||||
|
}
|
||||||
|
&:first-child {
|
||||||
|
padding-left: 18px;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
padding-right: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:not(.fancy) {
|
||||||
|
border-bottom: 1px solid var(--border-subtle);
|
||||||
}
|
}
|
||||||
transition: transform var(--transition) ease-in-out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
-webkit-user-drag: none;
|
-webkit-user-drag: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hitem {
|
|
||||||
font-weight: bold;
|
|
||||||
padding: 5px 12px;
|
|
||||||
text-decoration: none;
|
|
||||||
color: color(fg);
|
|
||||||
display: inline-block;
|
|
||||||
|
|
||||||
body:not(.flat) &,
|
|
||||||
&:hover {
|
|
||||||
@include button.base($border: false);
|
|
||||||
background: var(--canvas-elevated);
|
|
||||||
}
|
|
||||||
&:first-child {
|
|
||||||
padding-left: 18px;
|
|
||||||
}
|
|
||||||
&:last-child {
|
|
||||||
padding-right: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.hitem:focus {
|
.hitem:focus {
|
||||||
outline: 0;
|
outline: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,11 @@ body {
|
||||||
&.no-blur * {
|
&.no-blur * {
|
||||||
backdrop-filter: none !important;
|
backdrop-filter: none !important;
|
||||||
}
|
}
|
||||||
|
&:not(.fancy),
|
||||||
|
&:not(.fancy) * {
|
||||||
|
box-shadow: none !important;
|
||||||
|
backdrop-filter: none !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,7 +17,7 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>preferences_interface_language</string>
|
<string>preferences_language</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -33,13 +33,6 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="forceCheckBox">
|
|
||||||
<property name="text">
|
|
||||||
<string notr="true">Force Style</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|
|
@ -1068,9 +1068,9 @@ title="{}" {}>{}</button>""".format(
|
||||||
if is_lin:
|
if is_lin:
|
||||||
# On Linux, the check requires invoking an external binary,
|
# On Linux, the check requires invoking an external binary,
|
||||||
# which we don't want to be doing frequently
|
# which we don't want to be doing frequently
|
||||||
interval_secs = 300
|
interval_secs = 10
|
||||||
else:
|
else:
|
||||||
interval_secs = 5
|
interval_secs = 2
|
||||||
self.progress.timer(
|
self.progress.timer(
|
||||||
interval_secs * 1000,
|
interval_secs * 1000,
|
||||||
theme_manager.apply_style_if_system_style_changed,
|
theme_manager.apply_style_if_system_style_changed,
|
||||||
|
|
|
@ -13,7 +13,7 @@ from aqt import AnkiQt
|
||||||
from aqt.operations.collection import set_preferences
|
from aqt.operations.collection import set_preferences
|
||||||
from aqt.profiles import VideoDriver
|
from aqt.profiles import VideoDriver
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.theme import Theme
|
from aqt.theme import AnkiStyles, Theme
|
||||||
from aqt.utils import HelpPage, disable_help_button, openHelp, showInfo, showWarning, tr
|
from aqt.utils import HelpPage, disable_help_button, openHelp, showInfo, showWarning, tr
|
||||||
|
|
||||||
|
|
||||||
|
@ -207,20 +207,35 @@ class Preferences(QDialog):
|
||||||
|
|
||||||
def setup_global(self) -> None:
|
def setup_global(self) -> None:
|
||||||
"Setup options global to all profiles."
|
"Setup options global to all profiles."
|
||||||
self.form.reduce_motion.setChecked(self.mw.pm.reduced_motion())
|
self.form.reduce_motion.setChecked(self.mw.pm.reduce_motion())
|
||||||
|
qconnect(self.form.reduce_motion.stateChanged, self.mw.pm.set_reduce_motion)
|
||||||
|
|
||||||
|
self.form.minimalist_mode.setChecked(self.mw.pm.minimalist_mode())
|
||||||
|
qconnect(self.form.minimalist_mode.stateChanged, self.mw.pm.set_minimalist_mode)
|
||||||
|
|
||||||
self.form.collapse_toolbar.setChecked(self.mw.pm.collapse_toolbar())
|
self.form.collapse_toolbar.setChecked(self.mw.pm.collapse_toolbar())
|
||||||
|
qconnect(
|
||||||
|
self.form.collapse_toolbar.stateChanged, self.mw.pm.set_collapse_toolbar
|
||||||
|
)
|
||||||
|
|
||||||
self.form.uiScale.setValue(int(self.mw.pm.uiScale() * 100))
|
self.form.uiScale.setValue(int(self.mw.pm.uiScale() * 100))
|
||||||
themes = [
|
themes = [
|
||||||
tr.preferences_theme_label(theme=theme)
|
tr.preferences_theme_follow_system(),
|
||||||
for theme in (
|
tr.preferences_theme_light(),
|
||||||
tr.preferences_theme_follow_system(),
|
tr.preferences_theme_dark(),
|
||||||
tr.preferences_theme_light(),
|
|
||||||
tr.preferences_theme_dark(),
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
self.form.theme.addItems(themes)
|
self.form.theme.addItems(themes)
|
||||||
self.form.theme.setCurrentIndex(self.mw.pm.theme().value)
|
self.form.theme.setCurrentIndex(self.mw.pm.theme().value)
|
||||||
qconnect(self.form.theme.currentIndexChanged, self.on_theme_changed)
|
qconnect(self.form.theme.currentIndexChanged, self.on_theme_changed)
|
||||||
|
|
||||||
|
self.form.styleComboBox.addItems(
|
||||||
|
[member.name.lower().capitalize() for member in AnkiStyles]
|
||||||
|
)
|
||||||
|
self.form.styleComboBox.setCurrentIndex(self.mw.pm.get_widget_style())
|
||||||
|
qconnect(
|
||||||
|
self.form.styleComboBox.currentIndexChanged,
|
||||||
|
self.mw.pm.set_widget_style,
|
||||||
|
)
|
||||||
self.form.legacy_import_export.setChecked(self.mw.pm.legacy_import_export())
|
self.form.legacy_import_export.setChecked(self.mw.pm.legacy_import_export())
|
||||||
|
|
||||||
self.setup_language()
|
self.setup_language()
|
||||||
|
@ -238,8 +253,6 @@ class Preferences(QDialog):
|
||||||
self.mw.pm.setUiScale(newScale)
|
self.mw.pm.setUiScale(newScale)
|
||||||
restart_required = True
|
restart_required = True
|
||||||
|
|
||||||
self.mw.pm.set_reduced_motion(self.form.reduce_motion.isChecked())
|
|
||||||
self.mw.pm.set_collapse_toolbar(self.form.collapse_toolbar.isChecked())
|
|
||||||
self.mw.pm.set_legacy_import_export(self.form.legacy_import_export.isChecked())
|
self.mw.pm.set_legacy_import_export(self.form.legacy_import_export.isChecked())
|
||||||
|
|
||||||
if restart_required:
|
if restart_required:
|
||||||
|
@ -289,14 +302,12 @@ class Preferences(QDialog):
|
||||||
|
|
||||||
def setup_video_driver(self) -> None:
|
def setup_video_driver(self) -> None:
|
||||||
self.video_drivers = VideoDriver.all_for_platform()
|
self.video_drivers = VideoDriver.all_for_platform()
|
||||||
names = [
|
names = [video_driver_name_for_platform(d) for d in self.video_drivers]
|
||||||
tr.preferences_video_driver(driver=video_driver_name_for_platform(d))
|
|
||||||
for d in self.video_drivers
|
|
||||||
]
|
|
||||||
self.form.video_driver.addItems(names)
|
self.form.video_driver.addItems(names)
|
||||||
self.form.video_driver.setCurrentIndex(
|
self.form.video_driver.setCurrentIndex(
|
||||||
self.video_drivers.index(self.mw.pm.video_driver())
|
self.video_drivers.index(self.mw.pm.video_driver())
|
||||||
)
|
)
|
||||||
|
self.form.video_driver_label.setVisible(qtmajor == 5)
|
||||||
self.form.video_driver.setVisible(qtmajor == 5)
|
self.form.video_driver.setVisible(qtmajor == 5)
|
||||||
|
|
||||||
def update_video_driver(self) -> None:
|
def update_video_driver(self) -> None:
|
||||||
|
|
|
@ -21,7 +21,7 @@ from anki.db import DB
|
||||||
from anki.lang import without_unicode_isolation
|
from anki.lang import without_unicode_isolation
|
||||||
from anki.sync import SyncAuth
|
from anki.sync import SyncAuth
|
||||||
from anki.utils import int_time, is_mac, is_win, point_version
|
from anki.utils import int_time, is_mac, is_win, point_version
|
||||||
from aqt import appHelpSite
|
from aqt import appHelpSite, gui_hooks
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.theme import AnkiStyles, Theme, theme_manager
|
from aqt.theme import AnkiStyles, Theme, theme_manager
|
||||||
from aqt.utils import disable_help_button, send_to_trash, showWarning, tr
|
from aqt.utils import disable_help_button, send_to_trash, showWarning, tr
|
||||||
|
@ -523,12 +523,21 @@ create table if not exists profiles
|
||||||
|
|
||||||
def set_reduce_motion(self, on: bool) -> None:
|
def set_reduce_motion(self, on: bool) -> None:
|
||||||
self.meta["reduce_motion"] = on
|
self.meta["reduce_motion"] = on
|
||||||
|
gui_hooks.body_classes_need_update()
|
||||||
|
|
||||||
|
def minimalist_mode(self) -> bool:
|
||||||
|
return self.meta.get("tatsumoto_mode", False)
|
||||||
|
|
||||||
|
def set_minimalist_mode(self, on: bool) -> None:
|
||||||
|
self.meta["tatsumoto_mode"] = on
|
||||||
|
gui_hooks.body_classes_need_update()
|
||||||
|
|
||||||
def collapse_toolbar(self) -> bool:
|
def collapse_toolbar(self) -> bool:
|
||||||
return self.meta.get("collapse_toolbar", False)
|
return self.meta.get("collapse_toolbar", False)
|
||||||
|
|
||||||
def set_collapse_toolbar(self, on: bool) -> None:
|
def set_collapse_toolbar(self, on: bool) -> None:
|
||||||
self.meta["collapse_toolbar"] = on
|
self.meta["collapse_toolbar"] = on
|
||||||
|
gui_hooks.body_classes_need_update()
|
||||||
|
|
||||||
def last_addon_update_check(self) -> int:
|
def last_addon_update_check(self) -> int:
|
||||||
return self.meta.get("last_addon_update_check", 0)
|
return self.meta.get("last_addon_update_check", 0)
|
||||||
|
@ -546,34 +555,14 @@ create table if not exists profiles
|
||||||
def set_theme(self, theme: Theme) -> None:
|
def set_theme(self, theme: Theme) -> None:
|
||||||
self.meta["theme"] = theme.value
|
self.meta["theme"] = theme.value
|
||||||
|
|
||||||
def set_forced_style(self, style: AnkiStyles | None) -> None:
|
def set_widget_style(self, style: AnkiStyles) -> None:
|
||||||
if style:
|
self.meta["widget_style"] = style
|
||||||
self.meta[f"force_{AnkiStyles(style).name.lower()}_styles"] = True
|
|
||||||
|
|
||||||
for member in AnkiStyles:
|
|
||||||
if member != style:
|
|
||||||
self.meta[f"force_{AnkiStyles(member).name.lower()}_styles"] = False
|
|
||||||
|
|
||||||
theme_manager.apply_style()
|
theme_manager.apply_style()
|
||||||
|
|
||||||
def has_forced_style(self) -> bool:
|
def get_widget_style(self) -> AnkiStyles:
|
||||||
for member in AnkiStyles:
|
return self.meta.get(
|
||||||
if self.meta[f"force_{AnkiStyles(member).name.lower()}_styles"]:
|
"widget_style", AnkiStyles.NATIVE if is_mac else AnkiStyles.ANKI
|
||||||
return True
|
)
|
||||||
return False
|
|
||||||
|
|
||||||
# These getters are used by ThemeManager
|
|
||||||
def unset_forced_styles(self) -> None:
|
|
||||||
self.set_forced_style(None)
|
|
||||||
|
|
||||||
def force_anki_styles(self) -> bool:
|
|
||||||
return self.meta.get("force_anki_styles", False)
|
|
||||||
|
|
||||||
def force_fusion_styles(self) -> bool:
|
|
||||||
return self.meta.get("force_fusion_styles", False)
|
|
||||||
|
|
||||||
def force_native_styles(self) -> bool:
|
|
||||||
return self.meta.get("force_native_styles", False)
|
|
||||||
|
|
||||||
def browser_layout(self) -> BrowserLayout:
|
def browser_layout(self) -> BrowserLayout:
|
||||||
from aqt.browser.layout import BrowserLayout
|
from aqt.browser.layout import BrowserLayout
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -46,8 +46,7 @@ class ColoredIcon:
|
||||||
|
|
||||||
class AnkiStyles(enum.IntEnum):
|
class AnkiStyles(enum.IntEnum):
|
||||||
ANKI = 0
|
ANKI = 0
|
||||||
FUSION = 1
|
NATIVE = 1
|
||||||
NATIVE = 2
|
|
||||||
|
|
||||||
|
|
||||||
class Theme(enum.IntEnum):
|
class Theme(enum.IntEnum):
|
||||||
|
@ -176,6 +175,8 @@ class ThemeManager:
|
||||||
classes.append("macos-dark-mode")
|
classes.append("macos-dark-mode")
|
||||||
if aqt.mw.pm.reduce_motion():
|
if aqt.mw.pm.reduce_motion():
|
||||||
classes.append("reduce-motion")
|
classes.append("reduce-motion")
|
||||||
|
if not aqt.mw.pm.minimalist_mode():
|
||||||
|
classes.append("fancy")
|
||||||
if qtmajor == 5 and qtminor < 15:
|
if qtmajor == 5 and qtminor < 15:
|
||||||
classes.append("no-blur")
|
classes.append("no-blur")
|
||||||
return " ".join(classes)
|
return " ".join(classes)
|
||||||
|
@ -237,36 +238,24 @@ class ThemeManager:
|
||||||
gui_hooks.theme_did_change()
|
gui_hooks.theme_did_change()
|
||||||
|
|
||||||
def _apply_style(self, app: QApplication) -> None:
|
def _apply_style(self, app: QApplication) -> None:
|
||||||
from aqt.stylesheets import splitter_styles
|
buf = ""
|
||||||
|
|
||||||
buf = splitter_styles(self) if not aqt.mw.pm.force_native_styles() else ""
|
if aqt.mw.pm.get_widget_style() == AnkiStyles.ANKI:
|
||||||
|
from aqt.stylesheets import custom_styles
|
||||||
if aqt.mw.pm.force_anki_styles() or not (
|
|
||||||
aqt.mw.pm.force_native_styles() or aqt.mw.pm.force_fusion_styles() or is_mac
|
|
||||||
):
|
|
||||||
from aqt.stylesheets import (
|
|
||||||
button_styles,
|
|
||||||
checkbox_styles,
|
|
||||||
combobox_styles,
|
|
||||||
general_styles,
|
|
||||||
menu_styles,
|
|
||||||
scrollbar_styles,
|
|
||||||
spinbox_styles,
|
|
||||||
table_styles,
|
|
||||||
tabwidget_styles,
|
|
||||||
)
|
|
||||||
|
|
||||||
buf += "".join(
|
buf += "".join(
|
||||||
[
|
[
|
||||||
general_styles(self),
|
custom_styles.general(self),
|
||||||
button_styles(self),
|
custom_styles.button(self),
|
||||||
checkbox_styles(self),
|
custom_styles.checkbox(self),
|
||||||
menu_styles(self),
|
custom_styles.menu(self),
|
||||||
combobox_styles(self),
|
custom_styles.combobox(self),
|
||||||
tabwidget_styles(self),
|
custom_styles.tabwidget(self),
|
||||||
table_styles(self),
|
custom_styles.table(self),
|
||||||
spinbox_styles(self),
|
custom_styles.spinbox(self),
|
||||||
scrollbar_styles(self),
|
custom_styles.scrollbar(self),
|
||||||
|
custom_styles.slider(self),
|
||||||
|
custom_styles.splitter(self),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -278,19 +267,6 @@ class ThemeManager:
|
||||||
def _apply_palette(self, app: QApplication) -> None:
|
def _apply_palette(self, app: QApplication) -> None:
|
||||||
set_macos_dark_mode(self.night_mode)
|
set_macos_dark_mode(self.night_mode)
|
||||||
|
|
||||||
if aqt.mw.pm.force_native_styles() or (
|
|
||||||
is_mac and not (qtmajor == 5 or aqt.mw.pm.force_anki_styles())
|
|
||||||
):
|
|
||||||
app.setStyle(QStyleFactory.create(self._default_style)) # type: ignore
|
|
||||||
self.default_palette.setColor(
|
|
||||||
QPalette.ColorRole.Window, self.qcolor(colors.CANVAS)
|
|
||||||
)
|
|
||||||
self.default_palette.setColor(
|
|
||||||
QPalette.ColorRole.AlternateBase, self.qcolor(colors.CANVAS)
|
|
||||||
)
|
|
||||||
app.setPalette(self.default_palette)
|
|
||||||
return
|
|
||||||
|
|
||||||
app.setStyle(QStyleFactory.create("fusion")) # type: ignore
|
app.setStyle(QStyleFactory.create("fusion")) # type: ignore
|
||||||
|
|
||||||
palette = QPalette()
|
palette = QPalette()
|
||||||
|
|
|
@ -52,6 +52,11 @@ class ToolbarWebView(AnkiWebView):
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def on_body_classes_need_update(self) -> None:
|
||||||
|
super().on_body_classes_need_update()
|
||||||
|
super().adjustHeightToFit()
|
||||||
|
self.expand()
|
||||||
|
|
||||||
def _onHeight(self, qvar: Optional[int]) -> None:
|
def _onHeight(self, qvar: Optional[int]) -> None:
|
||||||
super()._onHeight(qvar)
|
super()._onHeight(qvar)
|
||||||
self.web_height = int(qvar)
|
self.web_height = int(qvar)
|
||||||
|
|
|
@ -248,6 +248,7 @@ class AnkiWebView(QWebEngineView):
|
||||||
self.resetHandlers()
|
self.resetHandlers()
|
||||||
self._filterSet = False
|
self._filterSet = False
|
||||||
gui_hooks.theme_did_change.append(self.on_theme_did_change)
|
gui_hooks.theme_did_change.append(self.on_theme_did_change)
|
||||||
|
gui_hooks.body_classes_need_update.append(self.on_body_classes_need_update)
|
||||||
|
|
||||||
qconnect(self.loadFinished, self._on_load_finished)
|
qconnect(self.loadFinished, self._on_load_finished)
|
||||||
|
|
||||||
|
@ -706,6 +707,7 @@ html {{ {font} }}
|
||||||
return
|
return
|
||||||
|
|
||||||
gui_hooks.theme_did_change.remove(self.on_theme_did_change)
|
gui_hooks.theme_did_change.remove(self.on_theme_did_change)
|
||||||
|
gui_hooks.body_classes_need_update.remove(self.on_body_classes_need_update)
|
||||||
mw.mediaServer.clear_page_html(id(self))
|
mw.mediaServer.clear_page_html(id(self))
|
||||||
self._page.deleteLater()
|
self._page.deleteLater()
|
||||||
|
|
||||||
|
@ -733,6 +735,16 @@ html {{ {font} }}
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def on_body_classes_need_update(self) -> None:
|
||||||
|
from aqt import mw
|
||||||
|
|
||||||
|
self.eval(
|
||||||
|
f"""document.body.classList.toggle("fancy", {json.dumps(not mw.pm.minimalist_mode())}); """
|
||||||
|
)
|
||||||
|
self.eval(
|
||||||
|
f"""document.body.classList.toggle("reduce-motion", {json.dumps(mw.pm.minimalist_mode())}); """
|
||||||
|
)
|
||||||
|
|
||||||
@deprecated(info="use theme_manager.qcolor() instead")
|
@deprecated(info="use theme_manager.qcolor() instead")
|
||||||
def get_window_bg_color(self, night_mode: Optional[bool] = None) -> QColor:
|
def get_window_bg_color(self, night_mode: Optional[bool] = None) -> QColor:
|
||||||
return theme_manager.qcolor(colors.CANVAS)
|
return theme_manager.qcolor(colors.CANVAS)
|
||||||
|
|
|
@ -5,7 +5,7 @@ import aqt
|
||||||
import aqt.main
|
import aqt.main
|
||||||
from aqt.qt import QDialog, qconnect
|
from aqt.qt import QDialog, qconnect
|
||||||
from aqt.theme import AnkiStyles
|
from aqt.theme import AnkiStyles
|
||||||
from aqt.utils import is_mac, restoreGeom, saveGeom
|
from aqt.utils import restoreGeom, saveGeom
|
||||||
|
|
||||||
|
|
||||||
class WidgetGallery(QDialog):
|
class WidgetGallery(QDialog):
|
||||||
|
@ -29,23 +29,12 @@ class WidgetGallery(QDialog):
|
||||||
self.form.styleComboBox.addItems(
|
self.form.styleComboBox.addItems(
|
||||||
[member.name.lower().capitalize() for member in AnkiStyles]
|
[member.name.lower().capitalize() for member in AnkiStyles]
|
||||||
)
|
)
|
||||||
self.form.styleComboBox.setCurrentIndex(
|
self.form.styleComboBox.setCurrentIndex(self.mw.pm.get_widget_style())
|
||||||
AnkiStyles.FUSION
|
|
||||||
if self.mw.pm.force_fusion_styles()
|
|
||||||
else AnkiStyles.NATIVE
|
|
||||||
if self.mw.pm.force_native_styles() or is_mac
|
|
||||||
else AnkiStyles.ANKI
|
|
||||||
)
|
|
||||||
self.form.forceCheckBox.setChecked(self.mw.pm.has_forced_style())
|
|
||||||
|
|
||||||
qconnect(
|
qconnect(
|
||||||
self.form.styleComboBox.currentIndexChanged,
|
self.form.styleComboBox.currentIndexChanged,
|
||||||
self.mw.pm.set_forced_style,
|
self.mw.pm.set_widget_style,
|
||||||
)
|
)
|
||||||
|
|
||||||
def reject(self) -> None:
|
def reject(self) -> None:
|
||||||
super().reject()
|
super().reject()
|
||||||
if not self.form.forceCheckBox.isChecked():
|
|
||||||
self.mw.pm.unset_forced_styles()
|
|
||||||
|
|
||||||
saveGeom(self, "WidgetGallery")
|
saveGeom(self, "WidgetGallery")
|
||||||
|
|
|
@ -613,6 +613,10 @@ hooks = [
|
||||||
name="theme_did_change",
|
name="theme_did_change",
|
||||||
doc="Called after night mode is toggled.",
|
doc="Called after night mode is toggled.",
|
||||||
),
|
),
|
||||||
|
Hook(
|
||||||
|
name="body_classes_need_update",
|
||||||
|
doc="Called when a setting involving a webview body class is toggled.",
|
||||||
|
),
|
||||||
# Webview
|
# Webview
|
||||||
###################
|
###################
|
||||||
Hook(
|
Hook(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
@use "vars" as *;
|
@use "vars" as *;
|
||||||
@use "root-vars";
|
@use "root-vars";
|
||||||
@use "button-mixins" as button;
|
@use "button-mixins" as button;
|
||||||
|
@use "sass/scrollbar";
|
||||||
|
|
||||||
$body-color: color(fg);
|
$body-color: color(fg);
|
||||||
$body-bg: color(canvas);
|
$body-bg: color(canvas);
|
||||||
|
@ -43,6 +44,26 @@ html {
|
||||||
overscroll-behavior: none;
|
overscroll-behavior: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
&:not(.isMac),
|
||||||
|
&:not(.isMac) * {
|
||||||
|
@include scrollbar.custom;
|
||||||
|
}
|
||||||
|
&.reduce-motion,
|
||||||
|
&.reduce-motion * {
|
||||||
|
transition: none !important;
|
||||||
|
animation: none !important;
|
||||||
|
}
|
||||||
|
&.no-blur * {
|
||||||
|
backdrop-filter: none !important;
|
||||||
|
}
|
||||||
|
&:not(.fancy),
|
||||||
|
&:not(.fancy) * {
|
||||||
|
box-shadow: none !important;
|
||||||
|
backdrop-filter: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
/* override transition for instant hover response */
|
/* override transition for instant hover response */
|
||||||
transition: color var(--transition) ease-in-out, box-shadow var(--transition) ease-in-out !important;
|
transition: color var(--transition) ease-in-out, box-shadow var(--transition) ease-in-out !important;
|
||||||
|
|
|
@ -24,15 +24,22 @@
|
||||||
|
|
||||||
button {
|
button {
|
||||||
outline: none !important;
|
outline: none !important;
|
||||||
@include button.base;
|
border: none;
|
||||||
border-radius: var(--border-radius-large);
|
background: none;
|
||||||
padding: 8px 10px;
|
&:hover {
|
||||||
|
background: var(--button-bg);
|
||||||
|
}
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
padding: 8px 10px;
|
||||||
margin: 0 4px;
|
margin: 0 4px;
|
||||||
|
|
||||||
@include elevation(1, $opacity-boost: -0.08);
|
.fancy & {
|
||||||
&:hover {
|
@include button.base;
|
||||||
@include elevation(2);
|
border-radius: var(--border-radius-large);
|
||||||
transition: box-shadow var(--transition) linear;
|
@include elevation(1, $opacity-boost: -0.08);
|
||||||
|
&:hover {
|
||||||
|
@include elevation(2);
|
||||||
|
transition: box-shadow var(--transition) linear;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,9 +36,26 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
@use "sass/elevation" as *;
|
@use "sass/elevation" as *;
|
||||||
.container {
|
.container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: var(--canvas-elevated);
|
:global(.fancy) & {
|
||||||
border: 1px solid var(--border-subtle);
|
background: var(--canvas-elevated);
|
||||||
border-radius: var(--border-radius-large, 10px);
|
border: 1px solid var(--border-subtle);
|
||||||
|
border-radius: var(--border-radius-medium, 10px);
|
||||||
|
|
||||||
|
&.light {
|
||||||
|
@include elevation(2, $opacity-boost: -0.08);
|
||||||
|
&:hover,
|
||||||
|
&:focus-within {
|
||||||
|
@include elevation(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.dark {
|
||||||
|
@include elevation(3, $opacity-boost: -0.08);
|
||||||
|
&:hover,
|
||||||
|
&:focus-within {
|
||||||
|
@include elevation(4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
padding: 1rem 1.75rem 0.75rem 1.25rem;
|
padding: 1rem 1.75rem 0.75rem 1.25rem;
|
||||||
&.rtl {
|
&.rtl {
|
||||||
padding: 1rem 1.25rem 0.75rem 1.75rem;
|
padding: 1rem 1.25rem 0.75rem 1.75rem;
|
||||||
|
@ -49,20 +66,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
color: var(--fg-subtle);
|
color: var(--fg-subtle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.light {
|
|
||||||
@include elevation(2, $opacity-boost: -0.08);
|
|
||||||
&:hover,
|
|
||||||
&:focus-within {
|
|
||||||
@include elevation(3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.dark {
|
|
||||||
@include elevation(3, $opacity-boost: -0.08);
|
|
||||||
&:hover,
|
|
||||||
&:focus-within {
|
|
||||||
@include elevation(4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
transition: box-shadow var(--transition) ease-in-out;
|
transition: box-shadow var(--transition) ease-in-out;
|
||||||
page-break-inside: avoid;
|
page-break-inside: avoid;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue