diff --git a/pylib/.pylintrc b/pylib/.pylintrc index b734d4c91..27c32f9d0 100644 --- a/pylib/.pylintrc +++ b/pylib/.pylintrc @@ -8,7 +8,7 @@ ignored-classes= BrowserRow, FormatTimespanIn, AnswerCardIn, - UnburyCardsInCurrentDeckIn, + UnburyDeckIn, BuryOrSuspendCardsIn, NoteIsDuplicateOrEmptyOut, BackendError, diff --git a/pylib/anki/scheduler/__init__.py b/pylib/anki/scheduler/__init__.py index 2fb735952..46ad82b02 100644 --- a/pylib/anki/scheduler/__init__.py +++ b/pylib/anki/scheduler/__init__.py @@ -7,7 +7,7 @@ import sys import anki.scheduler.base as _base -UnburyCurrentDeck = _base.UnburyCurrentDeck +UnburyDeck = _base.UnburyDeck CongratsInfo = _base.CongratsInfo BuryOrSuspend = _base.BuryOrSuspend FilteredDeckForUpdate = _base.FilteredDeckForUpdate diff --git a/pylib/anki/scheduler/base.py b/pylib/anki/scheduler/base.py index a9f8b9ea9..237ea3f62 100644 --- a/pylib/anki/scheduler/base.py +++ b/pylib/anki/scheduler/base.py @@ -20,7 +20,7 @@ from anki.notes import NoteId from anki.utils import ids2str, intTime CongratsInfo = _pb.CongratsInfoOut -UnburyCurrentDeck = _pb.UnburyCardsInCurrentDeckIn +UnburyDeck = _pb.UnburyDeckIn BuryOrSuspend = _pb.BuryOrSuspendCardsIn FilteredDeckForUpdate = _pb.FilteredDeckForUpdate @@ -118,11 +118,12 @@ select id from cards where did in %s and queue = {QUEUE_TYPE_REV} and due <= ? l def unbury_cards(self, ids: List[CardId]) -> OpChanges: return self.col._backend.restore_buried_and_suspended_cards(ids) - def unbury_cards_in_current_deck( + def unbury_deck( self, - mode: UnburyCurrentDeck.Mode.V = UnburyCurrentDeck.ALL, - ) -> None: - self.col._backend.unbury_cards_in_current_deck(mode) + deck_id: DeckId, + mode: UnburyDeck.Mode.V = UnburyDeck.ALL, + ) -> OpChanges: + return self.col._backend.unbury_deck(deck_id=deck_id, mode=mode) def suspend_cards(self, ids: Sequence[CardId]) -> OpChangesWithCount: return self.col._backend.bury_or_suspend_cards( diff --git a/pylib/anki/scheduler/legacy.py b/pylib/anki/scheduler/legacy.py index d4710583d..ac3a33533 100644 --- a/pylib/anki/scheduler/legacy.py +++ b/pylib/anki/scheduler/legacy.py @@ -7,7 +7,7 @@ from anki.cards import Card, CardId from anki.consts import CARD_TYPE_RELEARNING, QUEUE_TYPE_DAY_LEARN_RELEARN from anki.decks import DeckConfigDict, DeckId from anki.notes import NoteId -from anki.scheduler.base import SchedulerBase, UnburyCurrentDeck +from anki.scheduler.base import SchedulerBase, UnburyDeck from anki.utils import from_json_bytes, ids2str @@ -24,22 +24,18 @@ class SchedulerBaseWithLegacy(SchedulerBase): self.bury_cards(note.card_ids()) def unburyCards(self) -> None: - print( - "please use unbury_cards() or unbury_cards_in_current_deck instead of unburyCards()" - ) - self.unbury_cards_in_current_deck() + print("please use unbury_cards() or unbury_deck() instead of unburyCards()") + self.unbury_deck(self.col.decks.get_current_id()) def unburyCardsForDeck(self, type: str = "all") -> None: - print( - "please use unbury_cards_in_current_deck() instead of unburyCardsForDeck()" - ) + print("please use unbury_deck() instead of unburyCardsForDeck()") if type == "all": - mode = UnburyCurrentDeck.ALL + mode = UnburyDeck.ALL elif type == "manual": - mode = UnburyCurrentDeck.USER_ONLY + mode = UnburyDeck.USER_ONLY else: # elif type == "siblings": - mode = UnburyCurrentDeck.SCHED_ONLY - self.unbury_cards_in_current_deck(mode) + mode = UnburyDeck.SCHED_ONLY + self.unbury_deck(self.col.decks.get_current_id(), mode) def finishedMsg(self) -> str: print("finishedMsg() is obsolete") diff --git a/pylib/tests/test_schedv1.py b/pylib/tests/test_schedv1.py index 377ac7710..9ce6945ee 100644 --- a/pylib/tests/test_schedv1.py +++ b/pylib/tests/test_schedv1.py @@ -4,13 +4,14 @@ import copy import time +from anki import Collection from anki.consts import * from anki.lang import without_unicode_isolation from anki.utils import intTime from tests.shared import getEmptyCol as getEmptyColOrig -def getEmptyCol(): +def getEmptyCol() -> Collection: col = getEmptyColOrig() # only safe in test environment col.set_config("schedVer", 1) @@ -505,7 +506,7 @@ def test_misc(): col.sched.bury_notes([note.id]) col.reset() assert not col.sched.getCard() - col.sched.unbury_cards_in_current_deck() + col.sched.unbury_deck(deck_id=col.decks.get_current_id()) col.reset() assert col.sched.getCard() diff --git a/pylib/tests/test_schedv2.py b/pylib/tests/test_schedv2.py index cf56062fe..b862afa3c 100644 --- a/pylib/tests/test_schedv2.py +++ b/pylib/tests/test_schedv2.py @@ -11,7 +11,7 @@ import pytest from anki import hooks from anki.consts import * from anki.lang import without_unicode_isolation -from anki.scheduler import UnburyCurrentDeck +from anki.scheduler import UnburyDeck from anki.utils import intTime from tests.shared import getEmptyCol as getEmptyColOrig @@ -673,18 +673,20 @@ def test_bury(): col.reset() assert not col.sched.getCard() - col.sched.unbury_cards_in_current_deck(UnburyCurrentDeck.USER_ONLY) + col.sched.unbury_deck(deck_id=col.decks.get_current_id(), mode=UnburyDeck.USER_ONLY) c.load() assert c.queue == QUEUE_TYPE_NEW c2.load() assert c2.queue == QUEUE_TYPE_SIBLING_BURIED - col.sched.unbury_cards_in_current_deck(UnburyCurrentDeck.SCHED_ONLY) + col.sched.unbury_deck( + deck_id=col.decks.get_current_id(), mode=UnburyDeck.SCHED_ONLY + ) c2.load() assert c2.queue == QUEUE_TYPE_NEW col.sched.bury_cards([c.id, c2.id]) - col.sched.unbury_cards_in_current_deck() + col.sched.unbury_deck(deck_id=col.decks.get_current_id()) col.reset() diff --git a/qt/.pylintrc b/qt/.pylintrc index fb0800e47..8e8d07dc0 100644 --- a/qt/.pylintrc +++ b/qt/.pylintrc @@ -10,7 +10,8 @@ ignored-classes= BrowserRow, SearchNode, Config, - OpChanges + OpChanges, + UnburyDeckIn, [REPORTS] output-format=colorized diff --git a/qt/aqt/operations/scheduling.py b/qt/aqt/operations/scheduling.py index 384aa0602..ec5e27531 100644 --- a/qt/aqt/operations/scheduling.py +++ b/qt/aqt/operations/scheduling.py @@ -16,7 +16,7 @@ from anki.collection import ( ) from anki.decks import DeckId from anki.notes import NoteId -from anki.scheduler import FilteredDeckForUpdate +from anki.scheduler import FilteredDeckForUpdate, UnburyDeck from aqt.operations import CollectionOp from aqt.qt import * from aqt.utils import disable_help_button, getText, tooltip, tr @@ -196,3 +196,14 @@ def add_or_update_filtered_deck( deck: FilteredDeckForUpdate, ) -> CollectionOp[OpChangesWithId]: return CollectionOp(parent, lambda col: col.sched.add_or_update_filtered_deck(deck)) + + +def unbury_deck( + *, + parent: QWidget, + deck_id: DeckId, + mode: UnburyDeck.Mode.V = UnburyDeck.ALL, +) -> CollectionOp[OpChanges]: + return CollectionOp( + parent, lambda col: col.sched.unbury_deck(deck_id=deck_id, mode=mode) + ) diff --git a/qt/aqt/overview.py b/qt/aqt/overview.py index e87a267a8..d853f6de0 100644 --- a/qt/aqt/overview.py +++ b/qt/aqt/overview.py @@ -7,9 +7,14 @@ from typing import Any, Callable, Dict, List, Optional, Tuple import aqt from anki.collection import OpChanges +from anki.scheduler import UnburyDeck from aqt import gui_hooks from aqt.deckdescription import DeckDescriptionDialog -from aqt.operations.scheduling import empty_filtered_deck, rebuild_filtered_deck +from aqt.operations.scheduling import ( + empty_filtered_deck, + rebuild_filtered_deck, + unbury_deck, +) from aqt.sound import av_player from aqt.toolbar import BottomBar from aqt.utils import askUserDialog, openLink, shortcut, tooltip, tr @@ -102,7 +107,7 @@ class Overview: elif url == "studymore" or url == "customStudy": self.onStudyMore() elif url == "unbury": - self.onUnbury() + self.on_unbury() elif url == "description": self.edit_description() elif url.lower().startswith("http"): @@ -115,7 +120,7 @@ class Overview: ("r", self.rebuild_current_filtered_deck), ("e", self.empty_current_filtered_deck), ("c", self.onCustomStudyKey), - ("u", self.onUnbury), + ("u", self.on_unbury), ] def _current_deck_is_filtered(self) -> int: @@ -135,34 +140,33 @@ class Overview: if not self._current_deck_is_filtered(): self.onStudyMore() - def onUnbury(self) -> None: - if self.mw.col.schedVer() == 1: - self.mw.col.sched.unburyCardsForDeck() - self.mw.reset() - return + def on_unbury(self) -> None: + mode = UnburyDeck.Mode.ALL + if self.mw.col.schedVer() != 1: + info = self.mw.col.sched.congratulations_info() + if info.have_sched_buried and info.have_user_buried: + opts = [ + tr.studying_manually_buried_cards(), + tr.studying_buried_siblings(), + tr.studying_all_buried_cards(), + tr.actions_cancel(), + ] - info = self.mw.col.sched.congratulations_info() - if info.have_sched_buried and info.have_user_buried: - opts = [ - tr.studying_manually_buried_cards(), - tr.studying_buried_siblings(), - tr.studying_all_buried_cards(), - tr.actions_cancel(), - ] + diag = askUserDialog(tr.studying_what_would_you_like_to_unbury(), opts) + diag.setDefault(0) + ret = diag.run() + if ret == opts[0]: + mode = UnburyDeck.Mode.USER_ONLY + elif ret == opts[1]: + mode = UnburyDeck.Mode.SCHED_ONLY + elif ret == opts[3]: + return - diag = askUserDialog(tr.studying_what_would_you_like_to_unbury(), opts) - diag.setDefault(0) - ret = diag.run() - if ret == opts[0]: - self.mw.col.sched.unburyCardsForDeck(type="manual") - elif ret == opts[1]: - self.mw.col.sched.unburyCardsForDeck(type="siblings") - elif ret == opts[2]: - self.mw.col.sched.unburyCardsForDeck(type="all") - else: - self.mw.col.sched.unburyCardsForDeck(type="all") + unbury_deck( + parent=self.mw, deck_id=self.mw.col.decks.get_current_id(), mode=mode + ).run_in_background() - self.mw.reset() + onUnbury = on_unbury # HTML ############################################################ diff --git a/rslib/backend.proto b/rslib/backend.proto index df2a51293..1ae1b3092 100644 --- a/rslib/backend.proto +++ b/rslib/backend.proto @@ -119,7 +119,7 @@ service SchedulingService { rpc CountsForDeckToday(DeckId) returns (CountsForDeckTodayOut); rpc CongratsInfo(Empty) returns (CongratsInfoOut); rpc RestoreBuriedAndSuspendedCards(CardIds) returns (OpChanges); - rpc UnburyCardsInCurrentDeck(UnburyCardsInCurrentDeckIn) returns (Empty); + rpc UnburyDeck(UnburyDeckIn) returns (OpChanges); rpc BuryOrSuspendCards(BuryOrSuspendCardsIn) returns (OpChangesWithCount); rpc EmptyFilteredDeck(DeckId) returns (OpChanges); rpc RebuildFilteredDeck(DeckId) returns (OpChangesWithCount); @@ -1333,13 +1333,14 @@ message CongratsInfoOut { string deck_description = 9; } -message UnburyCardsInCurrentDeckIn { +message UnburyDeckIn { enum Mode { ALL = 0; SCHED_ONLY = 1; USER_ONLY = 2; } - Mode mode = 1; + int64 deck_id = 1; + Mode mode = 2; } message BuryOrSuspendCardsIn { diff --git a/rslib/src/backend/scheduler/mod.rs b/rslib/src/backend/scheduler/mod.rs index 1556f78fe..020597857 100644 --- a/rslib/src/backend/scheduler/mod.rs +++ b/rslib/src/backend/scheduler/mod.rs @@ -77,12 +77,9 @@ impl SchedulingService for Backend { self.with_col(|col| col.unbury_or_unsuspend_cards(&cids).map(Into::into)) } - fn unbury_cards_in_current_deck( - &self, - input: pb::UnburyCardsInCurrentDeckIn, - ) -> Result { + fn unbury_deck(&self, input: pb::UnburyDeckIn) -> Result { self.with_col(|col| { - col.unbury_cards_in_current_deck(input.mode()) + col.unbury_deck(input.deck_id.into(), input.mode()) .map(Into::into) }) } diff --git a/rslib/src/notetype/schemachange.rs b/rslib/src/notetype/schemachange.rs index 99cb254b9..51e260cd5 100644 --- a/rslib/src/notetype/schemachange.rs +++ b/rslib/src/notetype/schemachange.rs @@ -5,9 +5,7 @@ use std::collections::HashMap; use super::{CardGenContext, Notetype}; use crate::{ - collection::Collection, - error::Result, - match_all, + prelude::*, search::{Node, SortMode, TemplateKind}, }; diff --git a/rslib/src/prelude.rs b/rslib/src/prelude.rs index 3120b5b8b..f749d1fdc 100644 --- a/rslib/src/prelude.rs +++ b/rslib/src/prelude.rs @@ -12,6 +12,7 @@ pub use crate::{ decks::{Deck, DeckId, DeckKind, NativeDeckName}, error::{AnkiError, Result}, i18n::I18n, + match_all, match_any, notes::{Note, NoteId}, notetype::{Notetype, NotetypeId}, ops::{Op, OpChanges, OpOutput}, diff --git a/rslib/src/scheduler/bury_and_suspend.rs b/rslib/src/scheduler/bury_and_suspend.rs index a21270aa6..59523d045 100644 --- a/rslib/src/scheduler/bury_and_suspend.rs +++ b/rslib/src/scheduler/bury_and_suspend.rs @@ -4,15 +4,12 @@ use super::timing::SchedTimingToday; use crate::{ backend_proto::{ - bury_or_suspend_cards_in::Mode as BuryOrSuspendMode, - unbury_cards_in_current_deck_in::Mode as UnburyDeckMode, + bury_or_suspend_cards_in::Mode as BuryOrSuspendMode, unbury_deck_in::Mode as UnburyDeckMode, }, - card::{Card, CardId, CardQueue}, - collection::Collection, + card::CardQueue, config::SchedulerVersion, - error::Result, prelude::*, - search::SortMode, + search::{SortMode, StateKind}, }; impl Card { @@ -73,14 +70,14 @@ impl Collection { }) } - pub fn unbury_cards_in_current_deck(&mut self, mode: UnburyDeckMode) -> Result<()> { - let search = match mode { - UnburyDeckMode::All => "is:buried", - UnburyDeckMode::UserOnly => "is:buried-manually", - UnburyDeckMode::SchedOnly => "is:buried-sibling", + pub fn unbury_deck(&mut self, deck_id: DeckId, mode: UnburyDeckMode) -> Result> { + let state = match mode { + UnburyDeckMode::All => StateKind::Buried, + UnburyDeckMode::UserOnly => StateKind::UserBuried, + UnburyDeckMode::SchedOnly => StateKind::SchedBuried, }; - self.transact_no_undo(|col| { - col.search_cards_into_table(&format!("deck:current {}", search), SortMode::NoOrder)?; + self.transact(Op::UnburyUnsuspend, |col| { + col.search_cards_into_table(match_all![deck_id, state], SortMode::NoOrder)?; col.unsuspend_or_unbury_searched_cards() }) } diff --git a/rslib/src/scheduler/new.rs b/rslib/src/scheduler/new.rs index 1dce5cb83..c82e5fcb0 100644 --- a/rslib/src/scheduler/new.rs +++ b/rslib/src/scheduler/new.rs @@ -8,9 +8,8 @@ use rand::seq::SliceRandom; use crate::{ card::{CardQueue, CardType}, deckconfig::NewCardOrder, - match_all, prelude::*, - search::{Node, SortMode, StateKind}, + search::{SortMode, StateKind}, }; impl Card { diff --git a/rslib/src/search/parser.rs b/rslib/src/search/parser.rs index 722962eff..aa7571fb4 100644 --- a/rslib/src/search/parser.rs +++ b/rslib/src/search/parser.rs @@ -70,14 +70,14 @@ impl Node { #[macro_export] macro_rules! match_all { ($($param:expr),+ $(,)?) => { - Node::all(vec![$($param.into()),+]) + $crate::search::Node::all(vec![$($param.into()),+]) }; } #[macro_export] macro_rules! match_any { ($($param:expr),+ $(,)?) => { - Node::any(vec![$($param.into()),+]) + $crate::search::Node::any(vec![$($param.into()),+]) }; }