mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 06:22:22 -04:00
support undo for (renamed) unbury_deck() action
This commit is contained in:
parent
d0f3007fad
commit
abab4826bb
16 changed files with 92 additions and 83 deletions
|
@ -8,7 +8,7 @@ ignored-classes=
|
|||
BrowserRow,
|
||||
FormatTimespanIn,
|
||||
AnswerCardIn,
|
||||
UnburyCardsInCurrentDeckIn,
|
||||
UnburyDeckIn,
|
||||
BuryOrSuspendCardsIn,
|
||||
NoteIsDuplicateOrEmptyOut,
|
||||
BackendError,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@ ignored-classes=
|
|||
BrowserRow,
|
||||
SearchNode,
|
||||
Config,
|
||||
OpChanges
|
||||
OpChanges,
|
||||
UnburyDeckIn,
|
||||
|
||||
[REPORTS]
|
||||
output-format=colorized
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
|
|
|
@ -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
|
||||
############################################################
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<pb::Empty> {
|
||||
fn unbury_deck(&self, input: pb::UnburyDeckIn) -> Result<pb::OpChanges> {
|
||||
self.with_col(|col| {
|
||||
col.unbury_cards_in_current_deck(input.mode())
|
||||
col.unbury_deck(input.deck_id.into(), input.mode())
|
||||
.map(Into::into)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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},
|
||||
};
|
||||
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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<OpOutput<()>> {
|
||||
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()
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()),+])
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue