diff --git a/ftl/core/preferences.ftl b/ftl/core/preferences.ftl index 76e3132a0..779dc4f70 100644 --- a/ftl/core/preferences.ftl +++ b/ftl/core/preferences.ftl @@ -46,3 +46,5 @@ preferences-daily-backups = Daily backups to keep: preferences-weekly-backups = Weekly backups to keep: preferences-monthly-backups = Monthly backups to keep: preferences-minutes-between-backups = Minutes between automatic backups: +preferences-reduce-motion = Reduce motion +preferences-reduce-motion-tooltip = Disable various animations and transitions of the user interface diff --git a/qt/aqt/forms/preferences.ui b/qt/aqt/forms/preferences.ui index eb4a4bd35..d1b7f4aac 100644 --- a/qt/aqt/forms/preferences.ui +++ b/qt/aqt/forms/preferences.ui @@ -7,7 +7,7 @@ 0 0 640 - 530 + 640 @@ -42,6 +42,9 @@ 12 + + + @@ -55,9 +58,6 @@ - - - @@ -103,6 +103,16 @@ + + + + preferences_reduce_motion_tooltip + + + preferences_reduce_motion + + + @@ -676,8 +686,8 @@ - lang theme + lang video_driver showPlayButtons interrupt_audio @@ -685,6 +695,7 @@ paste_strips_formatting ignore_accents_in_search legacy_import_export + reduce_motion useCurrent default_search_text uiScale @@ -703,11 +714,11 @@ fullSync syncDeauth media_log - tabWidget minutes_between_backups daily_backups weekly_backups monthly_backups + tabWidget diff --git a/qt/aqt/preferences.py b/qt/aqt/preferences.py index f3b1fee0f..9f485764b 100644 --- a/qt/aqt/preferences.py +++ b/qt/aqt/preferences.py @@ -207,6 +207,7 @@ class Preferences(QDialog): def setup_global(self) -> None: "Setup options global to all profiles." + self.form.reduce_motion.setChecked(self.mw.pm.reduced_motion()) self.form.uiScale.setValue(int(self.mw.pm.uiScale() * 100)) themes = [ tr.preferences_theme_label(theme=theme) @@ -236,6 +237,8 @@ class Preferences(QDialog): self.mw.pm.setUiScale(newScale) restart_required = True + self.mw.pm.set_reduced_motion(self.form.reduce_motion.isChecked()) + self.mw.pm.set_legacy_import_export(self.form.legacy_import_export.isChecked()) if restart_required: diff --git a/qt/aqt/profiles.py b/qt/aqt/profiles.py index f177950d5..75cc87cde 100644 --- a/qt/aqt/profiles.py +++ b/qt/aqt/profiles.py @@ -518,6 +518,12 @@ create table if not exists profiles def setUiScale(self, scale: float) -> None: self.meta["uiScale"] = scale + def reduced_motion(self) -> bool: + return self.meta.get("reduced_motion", False) + + def set_reduced_motion(self, on: bool) -> None: + self.meta["reduced_motion"] = on + def last_addon_update_check(self) -> int: return self.meta.get("last_addon_update_check", 0) diff --git a/qt/aqt/theme.py b/qt/aqt/theme.py index 6a943e042..36b536d59 100644 --- a/qt/aqt/theme.py +++ b/qt/aqt/theme.py @@ -122,7 +122,7 @@ class ThemeManager: return cache.setdefault(path, icon) def body_class(self, night_mode: bool | None = None) -> str: - "Returns space-separated class list for platform/theme." + "Returns space-separated class list for platform/theme/global settings." classes = [] if is_win: classes.append("isWin") @@ -137,6 +137,8 @@ class ThemeManager: classes.extend(["nightMode", "night_mode"]) if self.macos_dark_mode(): classes.append("macos-dark-mode") + if aqt.mw.pm.reduced_motion(): + classes.append("reduced-motion") return " ".join(classes) def body_classes_for_card_ord( diff --git a/sass/base.scss b/sass/base.scss index ab8054a6b..7b907140e 100644 --- a/sass/base.scss +++ b/sass/base.scss @@ -74,3 +74,8 @@ samp { .night-mode .form-select:disabled { background-color: var(--disabled); } + +.reduced-motion * { + transition: none !important; + animation: none !important; +} diff --git a/ts/components/Collapsible.svelte b/ts/components/Collapsible.svelte index 1b19f28c9..22396e11d 100644 --- a/ts/components/Collapsible.svelte +++ b/ts/components/Collapsible.svelte @@ -46,7 +46,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html isCollapsed = true; const height = collapse ? inner.clientHeight : getRequiredHeight(inner); - const duration = Math.sqrt(height * 80); + + /* This function practically caps the maximum time at around 200ms, + but still allows to differentiate between small and large contents */ + const duration = 10 + Math.pow(height, 1 / 4) * 20; setStyle(height, duration);