diff --git a/CONTRIBUTORS b/CONTRIBUTORS index a77c6d46d..9e710163c 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -247,6 +247,11 @@ jariji Hanna Nilsén Elias Johansson Lara Toby Penner +Danilo Spillebeen +Matbe766 +Amanda Sternberg +arold0 + ******************** diff --git a/ftl/core/deck-config.ftl b/ftl/core/deck-config.ftl index fae113d8e..aed1db49d 100644 --- a/ftl/core/deck-config.ftl +++ b/ftl/core/deck-config.ftl @@ -385,7 +385,7 @@ deck-config-which-deck = Which deck would you like to display options for? ## Messages related to the FSRS scheduler deck-config-updating-cards = Updating cards: { $current_cards_count }/{ $total_cards_count }... -deck-config-invalid-parameters = The provided FSRS parameters are invalid. Leave them blank to use the default parameters. +deck-config-invalid-parameters = The provided FSRS parameters are invalid. Leave them blank to use the default values. deck-config-not-enough-history = Insufficient review history to perform this operation. deck-config-must-have-400-reviews = { $count -> diff --git a/ftl/core/launcher.ftl b/ftl/core/launcher.ftl index 13d419a0c..ee3aa6320 100644 --- a/ftl/core/launcher.ftl +++ b/ftl/core/launcher.ftl @@ -1,9 +1,10 @@ launcher-title = Anki Launcher +launcher-press-enter-to-install = Press the Enter/Return key on your keyboard to install or update Anki. launcher-press-enter-to-start = Press enter to start Anki. launcher-anki-will-start-shortly = Anki will start shortly. launcher-you-can-close-this-window = You can close this window. launcher-updating-anki = Updating Anki... -launcher-latest-anki = Latest Anki (just press Enter) +launcher-latest-anki = Install Latest Anki (default) launcher-choose-a-version = Choose a version launcher-sync-project-changes = Sync project changes launcher-keep-existing-version = Keep existing version ({ $current }) @@ -13,7 +14,7 @@ launcher-on = on launcher-off = off launcher-cache-downloads = Cache downloads: { $state } launcher-download-mirror = Download mirror: { $state } -launcher-uninstall = Uninstall +launcher-uninstall = Uninstall Anki launcher-invalid-input = Invalid input. Please try again. launcher-latest-releases = Latest releases: { $releases } launcher-enter-the-version-you-want = Enter the version you want to install: diff --git a/qt/aqt/addcards.py b/qt/aqt/addcards.py index a27d86234..01d7423d8 100644 --- a/qt/aqt/addcards.py +++ b/qt/aqt/addcards.py @@ -289,6 +289,10 @@ class AddCards(QMainWindow): def _add_current_note(self) -> None: note = self.editor.note + # Prevent adding a note that has already been added (e.g., from double-clicking) + if note.id != 0: + return + if not self._note_can_be_added(note): return diff --git a/qt/aqt/sync.py b/qt/aqt/sync.py index 9b29ada20..75bdeca89 100644 --- a/qt/aqt/sync.py +++ b/qt/aqt/sync.py @@ -209,11 +209,20 @@ def on_full_sync_timer(mw: aqt.main.AnkiQt, label: str) -> None: return sync_progress = progress.full_sync + # If we've reached total, show the "checking" label if sync_progress.transferred == sync_progress.total: label = tr.sync_checking() + + total = sync_progress.total + transferred = sync_progress.transferred + + # Scale both to kilobytes with floor division + max_for_bar = total // 1024 + value_for_bar = transferred // 1024 + mw.progress.update( - value=sync_progress.transferred, - max=sync_progress.total, + value=value_for_bar, + max=max_for_bar, process=False, label=label, ) diff --git a/qt/launcher/src/main.rs b/qt/launcher/src/main.rs index cdfc54d8c..26fbe86a7 100644 --- a/qt/launcher/src/main.rs +++ b/qt/launcher/src/main.rs @@ -173,6 +173,8 @@ fn run() -> Result<()> { ensure_os_supported()?; + println!("{}\n", state.tr.launcher_press_enter_to_install()); + check_versions(&mut state); main_menu_loop(&state)?; diff --git a/rslib/src/notetype/stock.rs b/rslib/src/notetype/stock.rs index 9b5df66d5..b27881809 100644 --- a/rslib/src/notetype/stock.rs +++ b/rslib/src/notetype/stock.rs @@ -122,7 +122,7 @@ pub(crate) fn basic(tr: &I18n) -> Notetype { pub(crate) fn basic_typing(tr: &I18n) -> Notetype { let mut nt = basic(tr); - nt.config.original_stock_kind = StockKind::BasicTyping as i32; + nt.config.original_stock_kind = OriginalStockKind::BasicTyping as i32; nt.name = tr.notetypes_basic_type_answer_name().into(); let front = tr.notetypes_front_field(); let back = tr.notetypes_back_field(); @@ -138,7 +138,7 @@ pub(crate) fn basic_typing(tr: &I18n) -> Notetype { pub(crate) fn basic_forward_reverse(tr: &I18n) -> Notetype { let mut nt = basic(tr); - nt.config.original_stock_kind = StockKind::BasicAndReversed as i32; + nt.config.original_stock_kind = OriginalStockKind::BasicAndReversed as i32; nt.name = tr.notetypes_basic_reversed_name().into(); let front = tr.notetypes_front_field(); let back = tr.notetypes_back_field(); @@ -156,7 +156,7 @@ pub(crate) fn basic_forward_reverse(tr: &I18n) -> Notetype { pub(crate) fn basic_optional_reverse(tr: &I18n) -> Notetype { let mut nt = basic_forward_reverse(tr); - nt.config.original_stock_kind = StockKind::BasicOptionalReversed as i32; + nt.config.original_stock_kind = OriginalStockKind::BasicOptionalReversed as i32; nt.name = tr.notetypes_basic_optional_reversed_name().into(); let addrev = tr.notetypes_add_reverse_field(); nt.add_field(addrev.as_ref()); diff --git a/rslib/src/scheduler/fsrs/error.rs b/rslib/src/scheduler/fsrs/error.rs index d5b596a36..404ee3605 100644 --- a/rslib/src/scheduler/fsrs/error.rs +++ b/rslib/src/scheduler/fsrs/error.rs @@ -13,13 +13,7 @@ impl From for AnkiError { FSRSError::OptimalNotFound => AnkiError::FsrsUnableToDetermineDesiredRetention, FSRSError::Interrupted => AnkiError::Interrupted, FSRSError::InvalidParameters => AnkiError::FsrsParamsInvalid, - FSRSError::InvalidInput => AnkiError::InvalidInput { - source: InvalidInputError { - message: "invalid params provided".to_string(), - source: None, - backtrace: None, - }, - }, + FSRSError::InvalidInput => AnkiError::FsrsParamsInvalid, FSRSError::InvalidDeckSize => AnkiError::InvalidInput { source: InvalidInputError { message: "no cards to simulate".to_string(), diff --git a/ts/routes/image-occlusion/Toolbar.svelte b/ts/routes/image-occlusion/Toolbar.svelte index 5b627ffdf..b00e42087 100644 --- a/ts/routes/image-occlusion/Toolbar.svelte +++ b/ts/routes/image-occlusion/Toolbar.svelte @@ -32,6 +32,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html saveNeededStore, opacityStateStore, } from "./store"; + import { get } from "svelte/store"; import { drawEllipse, drawPolygon, drawRectangle, drawText } from "./tools/index"; import { makeMaskTransparent, SHAPE_MASK_COLOR } from "./tools/lib"; import { enableSelectable, stopDraw } from "./tools/lib"; @@ -233,7 +234,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html } onMount(() => { - opacityStateStore.set(maskOpacity); + maskOpacity = get(opacityStateStore); removeHandlers = singleCallback( on(document, "click", onClick), on(window, "mousemove", onMousemove), diff --git a/ts/routes/image-occlusion/mask-editor.ts b/ts/routes/image-occlusion/mask-editor.ts index 6d4d0d284..41adbe423 100644 --- a/ts/routes/image-occlusion/mask-editor.ts +++ b/ts/routes/image-occlusion/mask-editor.ts @@ -8,10 +8,22 @@ import { fabric } from "fabric"; import { get } from "svelte/store"; import { optimumCssSizeForCanvas } from "./canvas-scale"; -import { hideAllGuessOne, notesDataStore, saveNeededStore, tagsWritable, textEditingState } from "./store"; +import { + hideAllGuessOne, + notesDataStore, + opacityStateStore, + saveNeededStore, + tagsWritable, + textEditingState, +} from "./store"; import Toast from "./Toast.svelte"; import { addShapesToCanvasFromCloze } from "./tools/add-from-cloze"; -import { enableSelectable, makeShapesRemainInCanvas, moveShapeToCanvasBoundaries } from "./tools/lib"; +import { + enableSelectable, + makeMaskTransparent, + makeShapesRemainInCanvas, + moveShapeToCanvasBoundaries, +} from "./tools/lib"; import { modifiedPolygon } from "./tools/tool-polygon"; import { undoStack } from "./tools/tool-undo-redo"; import { enablePinchZoom, onResize, setCanvasSize } from "./tools/tool-zoom"; @@ -83,6 +95,7 @@ export const setupMaskEditorForEdit = async ( window.requestAnimationFrame(() => { onImageLoaded({ noteId: BigInt(noteId) }); }); + if (get(opacityStateStore)) { makeMaskTransparent(canvas, true); } }; return canvas;