* Migrate build system to uv
Closes#3787, and is a step towards #3081 and #4022
This change breaks our PyOxidizer bundling process. While we probably
could update it to work with the new venvs & lockfile, my intention
is to use this as a base to try out a uv-based packager/installer.
Some notes about the changes:
- Use uv for python download + venv installation
- Drop python/requirements* in favour of pyproject files / uv.lock
- Bumped to latest Python 3.9 version. The move to 3.13 should be
a fairly trivial change when we're ready.
- Dropped the old write_wheel.py in favour of uv/hatchling. This has
the unfortunate side-effect of dropping leading zeros in our wheels,
which we could try hack around in the future.
- Switch to Qt 6.7 for the dev repo, as it's the first PyQt version
with a Linux/ARM WebEngine wheel.
- Unified our macOS deployment target with minimum required for ARM.
- Dropped unused fluent python files
- Dropped unused python license generation
- Dropped helpers to run under Qt 5, as our wheels were already
requiring Qt 6 to install.
* Build action to create universal uv binary
* Drop some PyOxidizer-related files
* Use Windows ARM64 cargo/node binaries during build
We can't provide ARM64 wheels to users yet due to #4079, but we can
at least speed up the build.
The rustls -> native-tls change on Windows is because ring requires
clang to compile for ARM64, and I figured it's best to keep our Windows
deps consistent. We already built the wheels with native-tls.
* Make libankihelper a universal library
We were shipping a single arch library in a purelib, leading to
breakages when running on a different platform.
* Use Python wheel for mpv/lame on Windows/Mac
This is convenient, but suboptimal on a Mac at the moment. The first
run of mpv will take a number of seconds for security checks to run,
and our mpv code ends up timing out, repeating the process each time.
Our installer stub will need to invoke mpv once first to get it validated.
We could address this by distributing the audio with the installer/stub,
or perhaps by putting the binaries in a .pkg file that's notarized+stapled
and then included in the wheel.
* Add some helper scripts to build a fully-locked wheel
* Initial macOS launcher prototype
* Add a hidden env var to preload our libs and audio helpers on macOS
* qt/bundle -> qt/launcher
- remove more of the old bundling code
- handle app icon
* Fat binary, notarization & dmg
* Publish wheels on testpypi for testing
* Use our Python pin for the launcher too
* Python cleanups
* Extend launcher to other platforms + more
- Switch to Qt 6.8 for repo default, as 6.7 depends on an older
libwebp/tiff which is unavailable on newer installs
- Drop tools/mac-x86, as we no longer need to test against Qt 5
- Add flags to cross compile wheels on Mac and Linux
- Bump glibc target to 2_36, building on Debian Stable
- Increase mpv timeout on macOS to allow for initial gatekeeper checks
- Ship both arm64 and amd64 uv on Linux, with a bash stub to pick
the appropriate arch.
* Fix pylint on Linux
* Fix failure to run from /usr/local/bin
* Remove remaining pyoxidizer refs, and clean up duplicate release folder
* Rust dep updates
- Rust 1.87 for now (1.88 due out in around a week)
- Nom looks involved, so I left it for now
- prost-reflect depends on a new prost version that got yanked
* Python 3.13 + dep updates
Updated protoc binaries + add helper in order to try fix build breakage.
Ended up being due to an AI-generated update to pip-system-certs that
was not reviewed carefully enough:
https://gitlab.com/alelec/pip-system-certs/-/issues/36
The updated mypy/black needed some tweaks to our files.
* Windows compilation fixes
* Automatically run Anki after installing on Windows
* Touch pyproject.toml upon install, so we check for updates
* Update Python deps
- urllib3 for CVE
- pip-system-certs got fixed
- markdown/pytest also updated
* fix: except only non-system-exiting exceptions
see https://youtu.be/zrVfY9SuO64
* chore: add myself to CONTRIBUTORS file
* refactor: explicitly specify possible exceptions
If an exception is not an Exception, there are only three options left.
see https://docs.python.org/3/library/exceptions.html#exception-hierarchy
* refactor: use BaseException for fallback
Co-authored-by: Damien Elmes <dae@users.noreply.github.com>
* chore: add myself to contributors
* chore: add myself to CONTRIBUTORS file
* refactor: use newer type hints for Union/Optional
* refactor: fix deprecated type annotations
use collections.abc rather than typing
* refactor: use lower letter type annotations
* style: reformat with black
* refactor: remove unused imports
* refactor: add missing imports for type hints
* fixup! refactor: use newer type hints for Union/Optional
* fix: add missing imports for type annotations
* fixup! refactor: use newer type hints for Union/Optional
* fixup! style: reformat with black
* refactor: fix remaining imports re: type hints
This dependency usually doesn't benefit Linux distros with requests library configured to use system certificate already. And is not packaged by most distros. Making it optional will make most Linux users' installation much easier.
* qt/aqt/__init__.py: Skip GL library workaround for FreeBSD
The workaround to load explicitly "libGL.so.1" isn't required for
FreeBSD and leads to segmentation faults if used in environments that
have nVidia drivers loaded.
See also FreeBSD bug 270778 for further details. [1]
[1] https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=270778
* Update CONTRIBUTORS
* adds log module
* enable logging in the app
* adds a getLogger method to AddonManager
* change log level depending on ANKIDEV
* fix undefined module variable
* - fix addons log file path
- remove a breakpoint leftover
set the addons log files under pm.addonFolder()/NNNNNN/user_files/logs/NNNNNN.log
* fix path bug
* move log closing handling into AddonManager deleteAddon/backupUserFiles methods
* logging module level import
fix undefined variable in backupUserFiles
* pretty format log records
* move MediaServer log into logging
* update CONTRIBUTORS
* documentation cleanup
* capture warnings into log messages
fix waitress verbosity
* remove record_factory function
* add get_logger method alias to getLogger in AddonManager
switch to TimedRotatingFileHandler handler
fix minor typo
* set main log level to DEBUG if ANKIDEV is not 0 (or unset)
added two new methods to AddonManager addon_get_logger/addon_toggle_log_level
* add new find_logger_output to AddonManager
* move logs under pm.base
* change log output
* update addonmanager getlogger
* Format imports
* Refactor logging set-up slightly and tweak docstring
* Remove obsolete log closing statements
As logs are no longer stored in user_files, we do not need to close their handlers
* Refactor and try to simplify log module
* Remove demo code
* Refactor and update add-on manager logging API
* Simplify writing unit tests for add-ons that use logging
Loggers are likely to be also employed in non UI code, so it seems like a good idea to decouple them from requiring a running Anki instance to work (thus freeing add-on authors from the need to mock Anki APIs in their tests).
* Fix arguments and drop obsolete inline instructions
Lets add a section on logging to the add-on docs instead
* Drop unnecessary import
* Supply logging basicConfig force option by default
Until we change the module import order and thus ensure that `log` is always evaluated before third-party dependencies have a chance to initialize the root logger, `force` is non-optional.
* Fix formatting and type errors
* Restore mediasrv type ignore comments
* Add note on prefix API stability
* Consistently use addon_from_module in new code
* Use logFolder rather than profileFolder
* Adjust method name for PEP8
* Change loggerDict access path, satisfying pylint
* Drop unused import and use lazy % formatting
* lint fix
* refactor .log_folder -> .addon_logs
store anki.log under logdir
* Fix method name (dae)
* Disable file-based logging in the backend (dae)
I have never found this useful, and it logs nothing by default, so
creating/opening the file is a waste. Removing it also ensures that
addon_logs() is solely used for add-ons.
---------
Co-authored-by: Glutanimate <5459332+glutanimate@users.noreply.github.com>
* Expose video driver options for Qt6
* Default to d3d11/metal/vulkan on Qt6
* Remove `pass`
* Add missing word to existing translation
* Default to OpenGL on Linux
* Exclude Vulkan from macOS
* Label default drivers
* Create widget gallery dialog
* Add WidgetGallery to debug dialog
* Use enum for its intended purpose
* Rename "reduced-motion" to "reduce-motion"
* Add another border-radius value
and make former large radius a bit smaller.
* 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
* Indent QTabBar style definitions
* Add missing styles for QPushButton states
* Fix QTableView background
* Remove unused layout from Preferences
* Fix QTabView focused tab style
* Highlight QCheckBox and QRadioButton when focused
* Fix toolbar styles
* Reorder preferences
* Add setting to hide bottom toolbar
* Move toolbar settings above minimalist modes
* Remove unused lines
* Implement proper full-screen mode
* Sort imports
* Tweak deck overview appearance in minimalist mode
* Undo TitledContainer changes
since nobody asked for that
* Remove dynamic toolbar background from minimalist mode
* Tweak buttons in minimalist mode
* Fix some issues
* Reduce theme check interval to 5s on Linux
* Increase hide timer interval to 2s
* Collapse toolbars with slight delay when moving to review state
This should ensure the bottom toolbar collapses too.
* Allow users to make hiding exclusive to full screen
* Rename full screen option
* Fix hide mode dropdown ignoring checkbox state on startup
* Fix typing issue
* Refine background image handling
Giving the toolbar body the main webview height ensures background-size: cover behaves exactly the same.
To prevent an override of other background properties, users are advised to only set background-images via the background-image property, not the background shorthand.
* Fix top toolbar getting huge when switching modes
The issue was caused by the min-height hack to align the background images. A call to web.adjustHeightToFit would set the toolbar to the same height as the main webview, as the function makes use of document.offsetHeight.
* Prevent scrollbar from appearing on bottom toolbar resize
* Cleanup
* Put review tab before editing; fix some tab orders
* Rename 'network' to 'syncing'
* Fix bottom toolbar disappearing on UI > 100
* Improve Preferences layout by adding vertical spacers to the bottom
also make the hiding of video_driver and its label more obvious in preferences.py.
* Fix bottom toolbar animating on startup
Also fix bottom toolbar not appearing when unchecking hide mode in reviewer.
* Hide/Show menubar in fullscreen mode along with toolbar
* Attempt to fix broken native theme on macOS
* Format
* Improve native theme on other systems by not forcing palette
with the caveat that theme switching can get weird.
* Fix theme switching in native style
* Remove redundant condition
* Add back check for Qt5 to prevent theme issues
* Add check for macOS before setting fusion theme
* Do not force scrollbar styles on macOS
* Remove all of that crazy theme logic
* Use canvas instead of button-bg for ColorRole.Button
* Make sure Anki style is always based on Fusion
otherwise we can't guarantee the same look on all systems.
* Explicitly apply default style when Anki style is not selected
This should fix the style not switching back after it was selected.
* Remove reduncant default_palette
* Revert 8af4c1cc2
On Mac with native theme, both Qt5 and Qt6 look correct already. On
the Anki theme, without this change, we get the fusion-style scrollbars
instead of the rounded ones.
* Rename AnkiStyles enum to WidgetStyle
* Fix theme switching shades on same theme
* Format
* Remove unused placeholderText
that caused an error when opening the widget gallery on Qt5.
* Check for full screen windowState using bitwise operator
to prevent error in Qt5.
Credit: https://stackoverflow.com/a/65425151
* Hide style option on Windows
also exclude native option from dropdown just in case.
* Format
* Minor naming tweak
This PR replaces the existing Python-driven sync server with a new one in Rust.
The new server supports both collection and media syncing, and is compatible
with both the new protocol mentioned below, and older clients. A setting has
been added to the preferences screen to point Anki to a local server, and a
similar setting is likely to come to AnkiMobile soon.
Documentation is available here: <https://docs.ankiweb.net/sync-server.html>
In addition to the new server and refactoring, this PR also makes changes to the
sync protocol. The existing sync protocol places payloads and metadata inside a
multipart POST body, which causes a few headaches:
- Legacy clients build the request in a non-deterministic order, meaning the
entire request needs to be scanned to extract the metadata.
- Reqwest's multipart API directly writes the multipart body, without exposing
the resulting stream to us, making it harder to track the progress of the
transfer. We've been relying on a patched version of reqwest for timeouts,
which is a pain to keep up to date.
To address these issues, the metadata is now sent in a HTTP header, with the
data payload sent directly in the body. Instead of the slower gzip, we now
use zstd. The old timeout handling code has been replaced with a new implementation
that wraps the request and response body streams to track progress, allowing us
to drop the git dependencies for reqwest, hyper-timeout and tokio-io-timeout.
The main other change to the protocol is that one-way syncs no longer need to
downgrade the collection to schema 11 prior to sending.
The Rust community appear to have converged on tracing - it's used by
the Rust compiler, and receives close to 10x the number of downloads
that slog does. Its API is more ergonomic, and it does a much nicer
job with async rust.
To make this change, we no longer pass around explicit loggers, and rely
on a globally-registered one. The log file location has been changed
from one in each profile folder to a single one in the base folder. This
will remain empty for most users, since only errors are logged by default,
but may be useful for debugging future changes.
This reverts commit 5dc79e22cd.
I appear to have been confused in my earlier testing, as reverting
this change seems to make no difference the top bar on first startup,
and fixes a bunch of other regressions that the original change introduced.
https://github.com/ankitects/anki/issues/2269
* Give QMenu cursor: pointer
* Darken border colors in dark theme
* Refactor cursor: pointer event filter
* Add QMenu stylesheet
* Remove min-width for QMenu item
* Add QMenuBar styles
with increased height for touchscreen users and more visible highlight color.
* Fix type
* Revert "Add QMenuBar styles"
This reverts commit 6ae405a073.
* Remove strong border from QMenu checkbox style
* Keep highlight color consistent
* Adjust highlight-bg
* Increase horizontal padding and adjust checkbox margin
* Introduce border-faint var and make default border brighter in dark mode
* Fix 1px move on hover and make highlight color more subtle
* Remove win10 styles
because the properties are set in the other stylesheets anyway.
* Fix bottom border of QMenuBar not showing underneath entries
* Remove unused import
* Make border-faint one shade darker in light theme
* Create _input-mixins.scss
* Use button-mixins on more elements
* Replace <select> tag with custom Select component
* Fix RevertButton causing cursor: pointer when hidden
* Increase SaveButton chevron width
* Hide floating component box-shadow when inactive
* Rework SpinBox and move it into components
* Run eslint and prettier
* Remove leftover options prop
* Pass disabled array to EnumSelector again
* Update MapperRow.svelte
* Darken QHeaderView border color
Slipping this in without an extra PR.
* Adjust disabled color, border and cursor
* Remove redundant icon definition from stylesheets
* Fix deck options initial config
* Fix z-index issues in change notetype screen
It might be best to handle z-index locally in each user component instead of hard-coded component values.
* Give web SpinBox a horizontal design
* Give QRadioButton the same treatment as QCheckBox in #2079
* Fix unused CSS selector warning with base button-mixin
* Remove redundant import
* Fix deck options save button
* Delete input-mixins and remove unused down-arrow
* Run eslint on change-notetype
* Run eslint on components
* Use cursor: pointer on QCheckBoxes too and exclude disabled widgets
* Left-align all QCheckBoxes to make hover-area and clickable area the same
Altough the clickable area has always been restricted to the label, the widget itself stretched all the way. This became a problem with the new cursor-pointer for checkboxes.
* Remove Switch duplicate from deck-options
* Add cursor: pointer to Switch and RevertButton
* Add cursor: pointer to bottom toolbar buttons
* Add cursor: pointer to gears
* Add cursor: pointer to radio and checkbox inputs of graphs page
* Improve button appearance in stats screen
* Add cursor: pointer to QTabBar and QToolButton
* Add cursor: pointer to non-editable QComboBox
* Center settings-will-take-effect-after notice in preferences screen
* Use public without_qt5_compat_wrapper() function
* Run prettier
* Remove --medium-border variable
* Implement color palette using Sass maps
I hand-picked the gray tones, the other colors are from the Tailwind CSS v3 palette.
Significant changes:
- light theme is brighter
- dark theme is darker
- borders are softer
I also deleted some platform- and night-mode-specific code.
* Use custom colors for note view switch
* Use same placeholder color for all inputs
* Skew color palette for more dark values
by removing gray[3], which wasn't used anywhere. Slight adjustments were made to the darker tones.
* Adjust frame- window- and border colors
* Give deck browser entries --frame-bg as background color
* Define styling for QComboBox and QLineEdit globally
* Experiment with CSS filter for inline-colors
Inside darker inputs, some colors like dark blue will be hard to read, so we could try to improve text-color contrast with global adjustments depending on the theme.
* Use different map structure for _vars.scss
after @hgiesel's idea: https://github.com/ankitects/anki/pull/2016#discussion_r947087871
* Move custom QLineEdit styles out of searchbar.py
* Merge branch 'main' into color-palette
* Revert QComboBox stylesheet override
* Align gray color palette more with macOS
* Adjust light theme
* Add custom styling for Qt controls
* Use --slightly-grey-text for options tab color
* Replace gray tones with more neutral values
* Improve categorization of global colors
by renaming almost all of them and sorting them into separate maps.
* Saturate highlight-bg in light theme
* Tweak gray tones
* Adjust box-shadow of EditingArea to make fields look inset
* Add Sass functions to access color palette and semantic variables
in response to https://github.com/ankitects/anki/pull/2016#issuecomment-1220571076
* Showcase use of access functions in several locations
@hgiesel in buttons.scss I access the color palette directly. Is this what you meant by "... keep it local to the component, and possibly make it global at a later time ..."?
* Fix focus box shadow transition and remove default shadow for a cleaner look
I couldn't quite get the inset look the way I wanted, because inset box-shadows do not respect the border radius, therefore causing aliasing.
* Tweak light theme border and shadow colors
* Add functions and colors to base_lib
* Add vars_lib as dependency to base_lib and button_mixins_lib
* Improve uses of default-themed variables
* Use old --frame-bg color and use darker tone for canvas-default
* Return CSS var by default and add palette-of function for raw value
* Showcase use of palette-of function
The #{...} syntax is required only because the use cases are CSS var definitions. In other cases a simple palette-of(keyword, theme) would suffice.
* Light theme: decrease brightness of canvas-default and adjust fg-default
* Use canvas-inset variable for switch knob
* Adjust light theme
* Add back box-shadow to EditingArea
* Light theme: darken background and flatten transition
also set hue and saturation of gray-8 to 0 (like all the other grays).
* Reduce flag colors to single default value
* Tweak card/note accent colors
* Experiment with inset look for fields again
Is this too dark in night mode? It's the same color used for all other text inputs.
* Dark theme: make border-default one shade darker
* Tweak inset shadow color
* Dark theme: make border-faint darker than canvas-default
meaning two shades darker than it currently was.
* Fix PlainTextInput not expanding
* Dark theme: use less saturated flag colors
* Adjust gray tones
* Create stylesheet overrides for various Qt widgets
Including QPushButton, QComboBox, QSpinBox, QLineEdit, QListWidget, QTabWidget, QTreeWidget, QToolTip, QTableView, QScrollBar and sub-widgets.
* Make webview scrollbar look identical to Qt one
* Add blue colors for primary buttons
* Tweak disabled state of SpinBox button
* Apply styles to all platforms
mainly so people like @hgiesel can easily test the widget style overrides, but maybe you actually prefer them over the native ones, who knows :)
* Tweak webview button borders
* Add type annotations to eventFilter
* Adjust padding of QComboBox and its drop-down arrow
* Use isinstance for comparison
* Remove reimport of Any
* Revert "Merge branch 'redesign-test' into custom-qt-controls"
This reverts commit ff36297456, reversing
changes made to 6bb45355d1.
* Add missing copyright header
* Left-align QTabWidget headers
* Exclude macOS from stylesheet overrides
* Fix failure to start on macOS (dae)
* Use standard macOS theme in dark mode (dae)
I believe this was originally behind a feature flag because the user
had to use a hack to get it to work
(https://forums.ankiweb.net/t/title-bar-dark-mode-fix-broken/1189),
and it did not work correctly when the system theme was changed.
Since the introduction of libankihelper and the app automatically
updating as the system theme changes, these issues no longer seem to
exist, and switching between light and dark appears to work consistently.
Pushed into this PR because it addresses the background color issue
mentioned in code review.
Closes#2054
- Use a separate `gldriver6` file for configuring Qt6 so we don't
pick up old settings, or cause problems when switching back and forth.
- Default to OpenGL/auto instead of software, as that was what we
were using throughout the beta period.
- Try to detect driver failure on startup. Untested.
- Hide the selector in the preferences again, as if Anki is unable
to automatically switch drivers, the user could change the setting
and then not be able to get back into Anki.
* Set QT_QPA_PLATFORM for Win on recent Qt versions
Erroneously dropped for Qt 5.15.1+.
* Enable original shortcut to create copy
* minor tweaks to comment to make it clearer (dae)