Merge branch 'main' into editor-3830

This commit is contained in:
Abdo 2025-10-13 13:38:14 +03:00
commit fbfd2784d8
13 changed files with 49 additions and 37 deletions

View file

@ -246,6 +246,11 @@ Aldlss <ayaldlss@gmail.com>
Hanna Nilsén <hanni614@student.liu.se> Hanna Nilsén <hanni614@student.liu.se>
Elias Johansson Lara <elias.johanssonlara@gmail.com> Elias Johansson Lara <elias.johanssonlara@gmail.com>
Toby Penner <tobypenner01@gmail.com> Toby Penner <tobypenner01@gmail.com>
Danilo Spillebeen <spillebeendanilo@gmail.com>
Matbe766 <matildabergstrom01@gmail.com>
Amanda Sternberg <mandis.sternberg@gmail.com>
arold0 <arold0@icloud.com>
nav1s <nav1s@proton.me>
******************** ********************

View file

@ -382,7 +382,7 @@ deck-config-which-deck = Which deck would you like to display options for?
## Messages related to the FSRS scheduler ## Messages related to the FSRS scheduler
deck-config-updating-cards = Updating cards: { $current_cards_count }/{ $total_cards_count }... 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-not-enough-history = Insufficient review history to perform this operation.
deck-config-must-have-400-reviews = deck-config-must-have-400-reviews =
{ $count -> { $count ->

View file

@ -1,9 +1,10 @@
launcher-title = Anki Launcher 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-press-enter-to-start = Press enter to start Anki.
launcher-anki-will-start-shortly = Anki will start shortly. launcher-anki-will-start-shortly = Anki will start shortly.
launcher-you-can-close-this-window = You can close this window. launcher-you-can-close-this-window = You can close this window.
launcher-updating-anki = Updating Anki... 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-choose-a-version = Choose a version
launcher-sync-project-changes = Sync project changes launcher-sync-project-changes = Sync project changes
launcher-keep-existing-version = Keep existing version ({ $current }) launcher-keep-existing-version = Keep existing version ({ $current })
@ -13,7 +14,7 @@ launcher-on = on
launcher-off = off launcher-off = off
launcher-cache-downloads = Cache downloads: { $state } launcher-cache-downloads = Cache downloads: { $state }
launcher-download-mirror = Download mirror: { $state } launcher-download-mirror = Download mirror: { $state }
launcher-uninstall = Uninstall launcher-uninstall = Uninstall Anki
launcher-invalid-input = Invalid input. Please try again. launcher-invalid-input = Invalid input. Please try again.
launcher-latest-releases = Latest releases: { $releases } launcher-latest-releases = Latest releases: { $releases }
launcher-enter-the-version-you-want = Enter the version you want to install: launcher-enter-the-version-you-want = Enter the version you want to install:

View file

@ -289,6 +289,10 @@ class AddCards(QMainWindow):
def _add_current_note(self) -> None: def _add_current_note(self) -> None:
note = self.editor.note 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): if not self._note_can_be_added(note):
return return

View file

@ -80,7 +80,7 @@ class SidebarItem:
self.search_node = search_node self.search_node = search_node
self.on_expanded = on_expanded self.on_expanded = on_expanded
self.children: list[SidebarItem] = [] self.children: list[SidebarItem] = []
self.tooltip: str | None = None self.tooltip: str = name
self._parent_item: SidebarItem | None = None self._parent_item: SidebarItem | None = None
self._expanded = expanded self._expanded = expanded
self._row_in_parent: int | None = None self._row_in_parent: int | None = None

View file

@ -209,11 +209,20 @@ def on_full_sync_timer(mw: aqt.main.AnkiQt, label: str) -> None:
return return
sync_progress = progress.full_sync sync_progress = progress.full_sync
# If we've reached total, show the "checking" label
if sync_progress.transferred == sync_progress.total: if sync_progress.transferred == sync_progress.total:
label = tr.sync_checking() 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( mw.progress.update(
value=sync_progress.transferred, value=value_for_bar,
max=sync_progress.total, max=max_for_bar,
process=False, process=False,
label=label, label=label,
) )

View file

@ -173,6 +173,8 @@ fn run() -> Result<()> {
ensure_os_supported()?; ensure_os_supported()?;
println!("{}\n", state.tr.launcher_press_enter_to_install());
check_versions(&mut state); check_versions(&mut state);
main_menu_loop(&state)?; main_menu_loop(&state)?;

View file

@ -122,7 +122,7 @@ pub(crate) fn basic(tr: &I18n) -> Notetype {
pub(crate) fn basic_typing(tr: &I18n) -> Notetype { pub(crate) fn basic_typing(tr: &I18n) -> Notetype {
let mut nt = basic(tr); 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(); nt.name = tr.notetypes_basic_type_answer_name().into();
let front = tr.notetypes_front_field(); let front = tr.notetypes_front_field();
let back = tr.notetypes_back_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 { pub(crate) fn basic_forward_reverse(tr: &I18n) -> Notetype {
let mut nt = basic(tr); 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(); nt.name = tr.notetypes_basic_reversed_name().into();
let front = tr.notetypes_front_field(); let front = tr.notetypes_front_field();
let back = tr.notetypes_back_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 { pub(crate) fn basic_optional_reverse(tr: &I18n) -> Notetype {
let mut nt = basic_forward_reverse(tr); 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(); nt.name = tr.notetypes_basic_optional_reversed_name().into();
let addrev = tr.notetypes_add_reverse_field(); let addrev = tr.notetypes_add_reverse_field();
nt.add_field(addrev.as_ref()); nt.add_field(addrev.as_ref());

View file

@ -13,13 +13,7 @@ impl From<FSRSError> for AnkiError {
FSRSError::OptimalNotFound => AnkiError::FsrsUnableToDetermineDesiredRetention, FSRSError::OptimalNotFound => AnkiError::FsrsUnableToDetermineDesiredRetention,
FSRSError::Interrupted => AnkiError::Interrupted, FSRSError::Interrupted => AnkiError::Interrupted,
FSRSError::InvalidParameters => AnkiError::FsrsParamsInvalid, FSRSError::InvalidParameters => AnkiError::FsrsParamsInvalid,
FSRSError::InvalidInput => AnkiError::InvalidInput { FSRSError::InvalidInput => AnkiError::FsrsParamsInvalid,
source: InvalidInputError {
message: "invalid params provided".to_string(),
source: None,
backtrace: None,
},
},
FSRSError::InvalidDeckSize => AnkiError::InvalidInput { FSRSError::InvalidDeckSize => AnkiError::InvalidInput {
source: InvalidInputError { source: InvalidInputError {
message: "no cards to simulate".to_string(), message: "no cards to simulate".to_string(),

View file

@ -31,7 +31,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
</script> </script>
<script lang="ts"> <script lang="ts">
import { randomUUID } from "@tslib/uuid";
import { onDestroy } from "svelte"; import { onDestroy } from "svelte";
import { writable } from "svelte/store"; import { writable } from "svelte/store";
@ -66,7 +65,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
$: empty = title === "MathJax"; $: empty = title === "MathJax";
$: encoded = encodeURIComponent(converted); $: encoded = encodeURIComponent(converted);
const uuid = randomUUID(); const uuid = crypto.randomUUID();
const imageHeight = writable(0); const imageHeight = writable(0);
imageToHeightMap.set(uuid, imageHeight); imageToHeightMap.set(uuid, imageHeight);

View file

@ -1,16 +0,0 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
/**
* TODO replace with crypto.randomUUID
*/
export function randomUUID(): string {
const value = `${1e7}-${1e3}-${4e3}-${8e3}-${1e11}`;
return value.replace(/[018]/g, (character: string): string =>
(
Number(character)
^ (crypto.getRandomValues(new Uint8Array(1))[0]
& (15 >> (Number(character) / 4)))
).toString(16));
}

View file

@ -32,6 +32,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
saveNeededStore, saveNeededStore,
opacityStateStore, opacityStateStore,
} from "./store"; } from "./store";
import { get } from "svelte/store";
import { drawEllipse, drawPolygon, drawRectangle, drawText } from "./tools/index"; import { drawEllipse, drawPolygon, drawRectangle, drawText } from "./tools/index";
import { makeMaskTransparent, SHAPE_MASK_COLOR } from "./tools/lib"; import { makeMaskTransparent, SHAPE_MASK_COLOR } from "./tools/lib";
import { enableSelectable, stopDraw } 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(() => { onMount(() => {
opacityStateStore.set(maskOpacity); maskOpacity = get(opacityStateStore);
removeHandlers = singleCallback( removeHandlers = singleCallback(
on(document, "click", onClick), on(document, "click", onClick),
on(window, "mousemove", onMousemove), on(window, "mousemove", onMousemove),

View file

@ -8,10 +8,22 @@ import { fabric } from "fabric";
import { get } from "svelte/store"; import { get } from "svelte/store";
import { optimumCssSizeForCanvas } from "./canvas-scale"; import { optimumCssSizeForCanvas } from "./canvas-scale";
import { hideAllGuessOne, notesDataStore, saveNeededStore, tagsWritable, textEditingState } from "./store"; import {
hideAllGuessOne,
notesDataStore,
opacityStateStore,
saveNeededStore,
tagsWritable,
textEditingState,
} from "./store";
import { showToast } from "./toast-utils.svelte"; import { showToast } from "./toast-utils.svelte";
import { addShapesToCanvasFromCloze } from "./tools/add-from-cloze"; 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 { modifiedPolygon } from "./tools/tool-polygon";
import { undoStack } from "./tools/tool-undo-redo"; import { undoStack } from "./tools/tool-undo-redo";
import { enablePinchZoom, onResize, setCanvasSize } from "./tools/tool-zoom"; import { enablePinchZoom, onResize, setCanvasSize } from "./tools/tool-zoom";
@ -77,6 +89,7 @@ export const setupMaskEditorForEdit = async (
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
onImageLoaded({ noteId: BigInt(noteId) }); onImageLoaded({ noteId: BigInt(noteId) });
}); });
if (get(opacityStateStore)) { makeMaskTransparent(canvas, true); }
}; };
return canvas; return canvas;