Commit Graph

106 Commits

Author SHA1 Message Date
Matthias Metelka
f169ee0933
Revamp Preferences, implement Minimalist Mode and Qt widget gallery to test GUI changes (#2289)
* 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
2023-01-18 21:24:16 +10:00
Damien Elmes
cf45cbf429
Rework syncing code, and replace local sync server (#2329)
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.
2023-01-18 12:43:46 +10:00
Matthias Metelka
9f8667fb47
Auto-hide toolbar in Reviewer (#2262)
* Give webviews a slide-in animation

if reduced motion isn't set.

* Auto-hide toolbar in review mode

moving the mouse above the main webview expands the toolbar. When the mouse leaves the toolbar, it will collapse after a delay of 2s.

* Save some space on bottom toolbars

* Use props for all hard-coded transition durations

and decrease most commonly used duration (200ms) to 150ms.

* Move auto-hide logic into ToolbarWebView

and handle auto-hide specific events in the respective webview subclasses.

* Fix typing issues

* Fix flickering issue

* Add auto_hide_toolbar opt-in to preferences

* Rename hide_toolbar to collapse_toolbar

to better describe the dock-like behaviour.

* Rename setting to minimize_distractions

* Reduce calls to pm in eventFilter

* Run formatter

* Revert setting title to something more specific

* Increase default animation time to 180ms

* Inset toolbar in review mode

when auto-hide is not enabled.

* Use card background on toolbar and add glass effect

* Use flatten/elevate over inset/outset

* Use flatten/elevate over inset/outset

* Update toolbar.py

* Fix toolbar background delay

* Tweak styles

* Use "collapse" instead of "auto-hide"

* Fix background misalignment in collapse mode

* Do not collapse toolbar when pointer is outside MainWebView

* Reduce hide_timer interval to 1000ms

* Use CSS to hide toolbar instead of setting webview height

* Add guard to prevent backdrop-filter: blur on Qt 5.14

* Apply transition to body instead of toolbar

to not complicate things for #2301.

* Fix Qt 5.14 and apply guard globally

* Fix background image scaling difference

* Tweak preference wording (dae)
2023-01-09 14:39:31 +10:00
Damien Elmes
0570cfdf48 Migrate from slog to tracing
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.
2022-12-24 10:44:40 +10:00
Damien Elmes
1ed2cce648 Use 6 digit hex codes for default colors
The color selector prints a warning otherwise.
2022-12-13 11:35:21 +10:00
Matthias Metelka
627313666e
Add profile manager setting to force custom qt stylesheets (#2233) 2022-12-04 12:54:39 +10:00
Matthias Metelka
f72570c604
Make tags editor resizable using Henrik's components (#2046)
* Make tags editor resizable using Henrik's components

All credit for the components goes to Henrik. I just tweaked the design a bit and implemented them in NoteEditor.

Co-Authored-By: Henrik Giesel <hengiesel@gmail.com>

* Remove PaneContent padding

Co-Authored-By: Henrik Giesel <hengiesel@gmail.com>

* Add responsive box-shadows on scroll/resize

only shown when content overflows in the respective direction.

* Remove comment

* Fix overflow calculations and shadow mix-up

This happened when I switched from using scrolledToX to overflowX booleans.

* Simplify overflow calculations

* Make drag handles 0 height/width

The remaining height requirement comes from a margin set on NoteEditor.

* Run eslint on components

* Split editor into three panes: Toolbar, Fields, Tags

* Remove upper split for now

to unblock 2.1.55 beta

* Move panes.scss to sass folder

* Use single type for resizable panes

* Implement collapsed state toggled with click on resizer

* Add button to uncollapse tags pane and focus input

* Add indicator for # of tags

* Use dbclick to prevent interference with resize state

* Add utility functions for expand/collapse

* Meddle around with types and formatting

* Fix collapsed state being forgotten on second browser open (dae)

* Fix typecheck (dae)

Our tooling generates .d.ts files from the Svelte files, but it doesn't
expect variables to be exported. By changing them into functions, they
get included in .bazel/bin/ts/components/Pane.svelte.d.ts

* Remove an unnecessary bridgeCommand (dae)

* Fix the bottom of tags getting cut off (dae)

Not sure why offsetHeight is inaccurate in this case.

* Add missing header (dae)

Co-authored-by: Henrik Giesel <hengiesel@gmail.com>
2022-09-28 14:02:32 +10:00
Abdo
73035819a9
Fix pm.night_mode() (#2091)
* Fix pm.night_mode()

* Add deprecation notice (dae)
2022-09-26 11:06:21 +10:00
Matthias Metelka
52f52724fa
Add orientation toggle to browser view menu (#2074)
* Use horizontal orientation on browser splitter by default

* Add View menu action to toggle browser orientation

* Add shortcut for toggleOrientation action

based on the most popular add-on.

* Try to fix typing issue

* Make orientation respond to aspect ratio

aspect ratio < 1 means vertical orientation, >= 1 horizontal

* Implement three-way switch for browser orientation

* Fix typing

* Add separator before QWidgetAction

* Use submenu instead of widget and adjust enum

* Add accelerators; move non-accelerator strings into separate .ftl (dae)

* Move BrowserLayout to its own file (dae)
2022-09-20 12:56:59 +10:00
Matthias Metelka
414ff5db1c
Redesign Qt widgets with stylesheets (#2050)
* 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 ff36297456b693a0d4b4b69f5f487ac1a01c1861, reversing
changes made to 6bb45355d143aa081d2d643933bd02ddc43206de.

* 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
2022-09-08 20:44:38 +10:00
Matthias Metelka
e2193950a9
Add animation toggle to preferences (#2041)
* Add animation toggle to preferences

and move settings affecting appearance together.

* Add class to body if animations unchecked

* Fix formatting in preferences.ftl

* Update duration(height) function for Collapsible transition

and add explanation.

* Fix formatting

* Increase duration baseline to 10 and decrease factor to 20

* Restore initial layout and rename option to "Reduce motion"

* Move checkboxes together and fix tab order (dae)

+ Remove separation of UI size
2022-09-03 12:14:47 +10:00
Sam Penny
e0368a3858
modify type hint in aqt/qt/profiles (#1972) 2022-07-19 17:29:46 +10:00
Aristotelis
704ff7ab99
Fix legacy import switch (#1970) 2022-07-19 04:23:21 +10:00
Damien Elmes
d482e90c6b Turn new import/export code on by default
Closes #1966
2022-07-18 13:31:24 +10:00
Sam Penny
662586765b
Load previously loaded profile (#1960)
* added option to load the last loaded profile

* add formatting changes for tests

* fix comments - integrate as new functionality rather than as an option, fix type hinting and remove bug if profile is deleted
2022-07-18 13:01:36 +10:00
RumovZ
5f9451f547
Add apkg import/export on backend (#1743)
* Add apkg export on backend

* Filter out missing media-paths at write time

* Make TagMatcher::new() infallible

* Gather export data instead of copying directly

* Revert changes to rslib/src/tags/

* Reuse filename_is_safe/check_filename_safe()

* Accept func to produce MediaIter in export_apkg()

* Only store file folder once in MediaIter

* Use temporary tables for gathering

export_apkg() now accepts a search instead of a deck id. Decks are
gathered according to the matched notes' cards.

* Use schedule_as_new() to reset cards

* ExportData → ExchangeData

* Ignore ascii case when filtering system tags

* search_notes_cards_into_table →

search_cards_of_notes_into_table

* Start on apkg importing on backend

* Fix due dates in days for apkg export

* Refactor import-export/package

- Move media and meta code into appropriate modules.
- Normalize/check for normalization when deserializing media entries.

* Add SafeMediaEntry for deserialized MediaEntries

* Prepare media based on checksums

- Ensure all existing media files are hashed.
- Hash incoming files during preparation to detect conflicts.
- Uniquify names of conflicting files with hash (not notetype id).
- Mark media files as used while importing notes.
- Finally copy used media.

* Handle encoding in `replace_media_refs()`

* Add trait to keep down cow boilerplate

* Add notetypes immediately instaed of preparing

* Move target_col into Context

* Add notes immediately instaed of preparing

* Note id, not guid of conflicting notes

* Add import_decks()

* decks_configs → deck_configs

* Add import_deck_configs()

* Add import_cards(), import_revlog()

* Use dyn instead of generic for media_fn

Otherwise, would have to pass None with type annotation in the default
case.

* Fix signature of import_apkg()

* Fix search_cards_of_notes_into_table()

* Test new functions in text.rs

* Add roundtrip test for apkg (stub)

* Keep source id of imported cards (or skip)

* Keep source ids of imported revlog (or skip)

* Try to keep source ids of imported notes

* Make adding notetype with id undoable

* Wrap apkg import in transaction

* Keep source ids of imported deck configs (or skip)

* Handle card due dates and original due/did

* Fix importing cards/revlog

Card ids are manually uniquified.

* Factor out card importing

* Refactor card and revlog importing

* Factor out card importing

Also handle missing parents .

* Factor out note importing

* Factor out media importing

* Maybe upgrade scheduler of apkg

* Fix parent deck gathering

* Unconditionally import static media

* Fix deck importing edge cases

Test those edge cases, and add some global test helpers.

* Test note importing

* Let import_apkg() take a progress func

* Expand roundtrip apkg test

* Use fat pointer to avoid propogating generics

* Fix progress_fn type

* Expose apkg export/import on backend

* Return note log when importing apkg

* Fix archived collection name on apkg import

* Add CollectionOpWithBackendProgress

* Fix wrong Interrupted Exception being checked

* Add ClosedCollectionOp

* Add note ids to log and strip HTML

* Update progress when checking incoming media too

* Conditionally enable new importing in GUI

* Fix all_checksums() for media import

Entries of deleted files are nulled, not removed.

* Make apkg exporting on backend abortable

* Return number of notes imported from apkg

* Fix exception printing for QueryOp as well

* Add QueryOpWithBackendProgress

Also support backend exporting progress.

* Expose new apkg and colpkg exporting

* Open transaction in insert_data()

Was slowing down exporting by several orders of magnitude.

* Handle zstd-compressed apkg

* Add legacy arg to ExportAnkiPackage

Currently not exposed on the frontend

* Remove unused import in proto file

* Add symlink for typechecking of import_export_pb2

* Avoid kwargs in pb message creation, so typechecking is not lost

Protobuf's behaviour is rather subtle and I had to dig through the docs
to figure it out: set a field on a submessage to automatically assign 
the submessage to the parent, or call SetInParent() to persist a default
version of the field you specified.

* Avoid re-exporting protobuf msgs we only use internally

* Stop after one test failure

mypy often fails much faster than pylint

* Avoid an extra allocation when extracting media checksums

* Update progress after prepare_media() finishes

Otherwise the bulk of the import ends up being shown as "Checked: 0"
in the progress window.

* Show progress of note imports

Note import is the slowest part, so showing progress here makes the UI
feel more responsive.

* Reset filtered decks at import time

Before this change, filtered decks exported with scheduling remained
filtered on import, and maybe_remove_from_filtered_deck() moved cards
into them as their home deck, leading to errors during review.

We may still want to provide a way to preserve filtered decks on import,
but to do that we'll need to ensure we don't rewrite the home decks of
cards, and we'll need to ensure the home decks are included as part of
the import (or give an error if they're not).

https://github.com/ankitects/anki/pull/1743/files#r839346423

* Fix a corner-case where due dates were shifted by a day

This issue existed in the old Python code as well. We need to include
the user's UTC offset in the exported file, or days_elapsed falls back
on the v1 cutoff calculation, which may be a day earlier or later than
the v2 calculation.

* Log conflicting note in remapped nt case

* take_fields() → into_fields()

* Alias `[u8; 20]` with `Sha1Hash`

* Truncate logged fields

* Rework apkg note import tests

- Use macros for more helpful errors.
- Split monolith into unit tests.
- Fix some unknown error with the previous test along the way.
(Was failing after 969484de4388d225c9f17d94534b3ba0094c3568.)

* Fix sorting of imported decks

Also adjust the test, so it fails without the patch. It was only passing
before, because the parent deck happened to come before the
inconsistently capitalised child alphabetically. But we want all parent
decks to be imported before their child decks, so their children can
adopt their capitalisation.

* target[_id]s → existing_card[_id]s

* export_collection_extracting_media() → ...

export_into_collection_file()

* target_already_exists→card_ordinal_already_exists

* Add search_cards_of_notes_into_table.sql

* Imrove type of apkg export selector/limit

* Remove redundant call to mod_schema()

* Parent tooltips to mw

* Fix a crash when truncating note text

String::truncate() is a bit of a footgun, and I've hit this before
too :-)

* Remove ExportLimit in favour of separate classes

* Remove OpWithBackendProgress and ClosedCollectionOp

Backend progress logic is now in ProgressManager. QueryOp can be used
for running on closed collection.

Also fix aborting of colpkg exports, which slipped through in #1817.

* Tidy up import log

* Avoid QDialog.exec()

* Default to excluding scheuling for deck list deck

* Use IncrementalProgress in whole import_export code

* Compare checksums when importing colpkgs

* Avoid registering changes if hashes are not needed

* ImportProgress::Collection → ImportProgress::File

* Make downgrading apkgs depend on meta version

* Generalise IncrementableProgress

And use it in entire import_export code instead.

* Fix type complexity lint

* Take count_map for IncrementableProgress::get_inner

* Replace import/export env with Shift click

* Accept all args from update() for backend progress

* Pass fields of ProgressUpdate explicitly

* Move update_interval into IncrementableProgress

* Outsource incrementing into Incrementor

* Mutate ProgressUpdate in progress_update callback

* Switch import/export legacy toggle to profile setting

Shift would have been nice, but the existing shortcuts complicate things.
If the user triggers an import with ctrl+shift+i, shift is unlikely to
have been released by the time our code runs, meaning the user accidentally
triggers the new code. We could potentially wait a while before bringing
up the dialog, but then we're forced to guess at how long it will take the
user to release the key.

One alternative would be to use alt instead of shift, but then we need to
trigger our shortcut when that key is pressed as well, and it could
potentially cause a conflict with an add-on that already uses that
combination.

* Show extension in export dialog

* Continue to provide separate options for schema 11+18 colpkg export

* Default to colpkg export when using File>Export

* Improve appearance of combo boxes when switching between apkg/colpkg

+ Deal with long deck names

* Convert newlines to spaces when showing fields from import

Ensures each imported note appears on a separate line

* Don't separate total note count from the other summary lines

This may come down to personal preference, but I feel the other counts
are equally as important, and separating them feels like it makes it
a bit easier to ignore them.

* Fix 'deck not normal' error when importing a filtered deck for the 2nd time

* Fix [Identical] being shown on first import

* Revert "Continue to provide separate options for schema 11+18 colpkg export"

This reverts commit 8f0b2c175f4794d642823b60414d142a12768441.

Will use a different approach

* Move legacy support into a separate exporter option; add to apkg export

* Adjust 'too new' message to also apply to .apkg import case

* Show a better message when attempting to import new apkg into old code

Previously the user could end seeing a message like:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb5 in position 1: invalid start byte

Unfortunately we can't retroactively fix this for older clients.

* Hide legacy support option in older exporting screen

* Reflect change from paths to fnames in type & name

* Make imported decks normal at once

Then skip special casing in update_deck(). Also skip updating
description if new one is empty.

Co-authored-by: Damien Elmes <gpg@ankiweb.net>
2022-05-02 21:12:46 +10:00
Damien Elmes
f2bffaa185 Tweaks to video driver handling
- 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.
2022-04-06 11:35:49 +10:00
Damien Elmes
e4f46463f2 Expose video driver settings on Qt6, sans ANGLE 2022-04-03 19:57:58 +10:00
Damien Elmes
7506d5f06c Fall back on regular deletion when trash folder unavailable
aa0cac1ed3 (commitcomment-69668166)
2022-03-28 14:40:31 +10:00
Damien Elmes
1165939271 Update Python deps, including stable Black
Black 22.1 made some changes that required some minor reformatting.
2022-02-25 15:26:16 +10:00
RumovZ
f6546c9f35
Add last version check for add-on updates (#1608)
* Add last version check for add-on updates

* Remove second add-on update check

* Show tooltip after toggling/deleting add-on
2022-01-21 21:43:54 +10:00
Damien Elmes
9ed13eee80 convert invariant assertions to if statements
The packaged builds of 2.1.50 use python -OO, which means our assertion
statements won't be run. This is not an issue for unit tests (as we
don't run them from a packaged build), or for type assertions (which are
added for mypy's benefit), but we do need to ensure that invariant checks
are still run.
2021-11-25 17:47:50 +10:00
Damien Elmes
ebad6ad379 update platform checks (eg isWin -> is_win) + devMode 2021-11-25 09:06:16 +10:00
RumovZ
f2173fddb0
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 <gpg@ankiweb.net>
2021-11-25 07:17:41 +10:00
Damien Elmes
5a9a03e65a fix profile with older keys being reported as corrupt
Older Anki versions like 2.1.35 used sip 5.2, which appears to
(presumably incorrectly) serialize QByteArrays as Unicode:

    0: (    MARK
    1: d        DICT       (MARK at 0)
    2: p    PUT        0
    5: V    UNICODE    'mainWindowGeom'
   21: p    PUT        1
   24: c    GLOBAL     'sip _unpickle_type'
   44: p    PUT        2
   47: (    MARK
   48: V        UNICODE    'PyQt5.QtCore'
   62: p        PUT        3
   65: V        UNICODE    'QByteArray'
   77: p        PUT        4
   80: (        MARK
   81: c            GLOBAL     '_codecs encode'
   97: p            PUT        5
  100: (            MARK
  101: V                UNICODE    "[...]"
  354: p                PUT        6
  357: V                UNICODE    'latin1'
  365: p                PUT        7
  368: t                TUPLE      (MARK at 100)

Our unpickle_type() was incorrectly ignoring any non-PyQt class when
unpickling, so it was choking on the reference to _codecs.
2021-11-06 09:44:00 +10:00
RumovZ
9dc3cf216a
PEP8 for rest of pylib (#1451)
* PEP8 dbproxy.py

* PEP8 errors.py

* PEP8 httpclient.py

* PEP8 lang.py

* PEP8 latex.py

* Add decorator to deprectate key words

* Make replacement for deprecated attribute optional

* Use new helper `_print_replacement_warning()`

* PEP8 media.py

* PEP8 rsbackend.py

* PEP8 sound.py

* PEP8 stdmodels.py

* PEP8 storage.py

* PEP8 sync.py

* PEP8 tags.py

* PEP8 template.py

* PEP8 types.py

* Fix DeprecatedNamesMixinForModule

The class methods need to be overridden with instance methods, so every
module has its own dicts.

* Use `# pylint: disable=invalid-name` instead of id

* PEP8 utils.py

* Only decorate `__getattr__` with `@no_type_check`

* Fix mypy issue with snakecase

Importing it from `anki._vendor` raises attribute errors.

* Format

* Remove inheritance of DeprecatedNamesMixin

There's almost no shared code now and overriding classmethods with
instance methods raises mypy issues.

* Fix traceback frames of deprecation warnings

* remove fn/TimedLog (dae)

Neither Anki nor add-ons appear to have been using it

* fix some issues with stringcase use (dae)

- the wheel was depending on the PyPI version instead of our vendored
version
- _vendor:stringcase should not have been listed in the anki py_library.
We already include the sources in py_srcs, and need to refer to them
directly. By listing _vendor:stringcase as well, we were making a
top-level stringcase library available, which would have only worked for
distributing because the wheel definition was also incorrect.
- mypy errors are what caused me to mistakenly add the above - they
were because the type: ignore at the top of stringcase.py was causing
mypy to completely ignore the file, so it was not aware of any attributes
it contained.
2021-10-25 14:50:13 +10:00
Damien Elmes
52642d693b drop PyAudio support
I do not recall anyone reporting that it worked better than the Qt
implementation for them, and the lack of recent wheels on PyPI is a pain.
We can always add it back in the future if enough people come out of
the woodwork to report they were using it.
2021-10-15 13:15:16 +10:00
Damien Elmes
a7812dedc0 switch to new-style PyQt scoped enums and Qt6
The enum changes should work on PyQt 5.x, and are required in PyQt 6.x.
They are not supported by the PyQt5 typings however, so we need to run
our tests with PyQt6.
2021-10-15 12:57:19 +10:00
Damien Elmes
dfcefaebe3 miscellaneous pyqt6 compat fixes
- add a few gates for qt5-specific behaviour
- prepare for some changes to the typings in qt6
- map pickled Qt5 ByteArrays to Qt6 when running Qt6
2021-10-15 12:57:19 +10:00
Damien Elmes
b85ee30c70 stop migrating from old folder locations
Closes #1390
2021-10-12 16:18:31 +10:00
Damien Elmes
c39a5e17e8 Revert "Merge pull request #610 from evandroforks/ask_confirmation_before_moving_anki_collection"
This reverts commit a53aac40f8, reversing
changes made to e323a8f902.

Migration is about to be dropped (#1390), and the references to modules
like QtGui complicate a PyQt5/6 shim.
2021-10-12 16:18:24 +10:00
Damien Elmes
69c196b409 .exec_() -> .exec()
The former is not supported in PyQt6
2021-10-12 16:17:37 +10:00
Damien Elmes
e357dbf6b3 use Qt search path instead of resource system
Means URLs like :/icons/foo.jpg should become icons:foo.jpg

This is part of the prep work for a PyQt6 update. PyQt6 has dropped
pyrcc, so we can longer generate the icons_qrc.py file we did previously.

Qt Designer expects us to use the resource system, so we continue to
generate the icons.qrc file to make editing the UI files easier. But at
runtime, we no longer use that file.
2021-10-12 16:17:08 +10:00
Damien Elmes
3814385e41 add trailing newline to profiles readme
closes #1407
2021-10-07 13:31:44 +10:00
Damien Elmes
b9251290ca run pyupgrade over codebase [python upgrade required]
This adds Python 3.9 and 3.10 typing syntax to files that import
attributions from __future___. Python 3.9 should be able to cope with
the 3.10 syntax, but Python 3.8 will no longer work.

On Windows/Mac, install the latest Python 3.9 version from python.org.
There are currently no orjson wheels for Python 3.10 on Windows/Mac,
which will break the build unless you have Rust installed separately.

On Linux, modern distros should have Python 3.9 available already. If
you're on an older distro, you'll need to build Python from source first.
2021-10-04 15:05:48 +10:00
Damien Elmes
daf2e0a78f fix profile save not working on Python 3.10 2021-10-03 12:23:37 +10:00
Damien Elmes
553ce808e5 add missing encoding argument to open calls 2021-10-02 23:51:50 +10:00
Damien Elmes
1ceb9965ad add hidden option to disable tooltips in browse screen
https://forums.ankiweb.net/t/browser-text-pop-up-when-hovering-over-card-poll/13254
2021-09-21 15:03:37 +10:00
Henrik Giesel
4db7cebf62 Remember last text and highlight color again 2021-08-02 23:12:00 +02:00
Damien Elmes
7ac1fa17e6 move proto files into separate py_library in same namespace
Will allow importing the Protobuf without pulling in the rest of
the library. This is not a full PEP420 namespace, and the wheel still
bundles everything - it just makes things easier in a Bazel workspace.
I originally tried with PEP420, but it required more invasive changes,
and I ran into issues with mypy.
2021-07-11 14:51:25 +10:00
cherryblossom
92fe68abfe
fix documentation links 2021-06-03 16:51:03 +10:00
Damien Elmes
e687552aeb update TR references that crossed multiple lines 2021-03-26 14:38:15 +10:00
Damien Elmes
b7587cb8d2 update TR references that contain arguments 2021-03-26 14:21:04 +10:00
Damien Elmes
0c338bfd53 update no-arg tr references in qt/ 2021-03-26 13:48:26 +10:00
Damien Elmes
9aece2a7b8 rework translation handling
Instead of generating a fluent.proto file with a giant enum, create
a .json file representing the translations that downstream consumers
can use for code generation.

This enables the generation of a separate method for each translation,
with a docstring that shows the actual text, and any required arguments
listed in the function signature.

The codebase is still using the old enum for now; updating it will need
to come in future commits, and the old enum will need to be kept
around, as add-ons are referencing it.

Other changes:

- move translation code into a separate crate
- store the translations on a per-file/module basis, which will allow
us to avoid sending 1000+ strings on each JS page load in the future
- drop the undocumented support for external .ftl files, that we weren't
using
- duplicate strings in translation files are now checked for at build
time
- fix i18n test failing when run outside Bazel
- drop slog dependency in i18n module
2021-03-26 09:41:32 +10:00
Damien Elmes
6b1dd9ee19 expand backend Preferences and make undoable
- moved 'default to current deck when adding' into prefs
- move some profile options into the collection config, so they're
undoable and will sync. There is (currently) no automatic migration
from the old profile settings, meaning users will need to set the
options again if they've customized them.
- tidy up preferences.py
- drop the deleteMedia option that was not exposed in the UI
2021-03-10 18:51:03 +10:00
Damien Elmes
2a585c5e5a Revert "add escape hatch for new clicking behaviour, in case it causes problems"
This reverts commit 678756c3e9.
2021-02-11 10:10:45 +10:00
Damien Elmes
88c002f4eb convert qt strings to f-strings with flynt
Also revealed an incorrect type def in editor.py that mypy wasn't
noticing before :-(
2021-02-11 10:09:06 +10:00
Damien Elmes
678756c3e9 add escape hatch for new clicking behaviour, in case it causes problems 2021-02-09 19:29:59 +10:00
Damien Elmes
4a5ef69068 add remaining types and disable missing types on (almost) all aqt 2021-02-03 00:00:29 +10:00