mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 14:32:22 -04:00
embed deck config and expose to frontend
This commit is contained in:
parent
037df9522b
commit
42a4d11416
6 changed files with 103 additions and 74 deletions
|
@ -39,7 +39,7 @@ from anki.cards import Card, CardId
|
||||||
from anki.config import Config, ConfigManager
|
from anki.config import Config, ConfigManager
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.dbproxy import DBProxy
|
from anki.dbproxy import DBProxy
|
||||||
from anki.decks import Deck, DeckId, DeckManager
|
from anki.decks import Deck, DeckConfig, DeckConfigId, DeckId, DeckManager
|
||||||
from anki.errors import AbortSchemaModification, DBError
|
from anki.errors import AbortSchemaModification, DBError
|
||||||
from anki.lang import FormatTimeSpan
|
from anki.lang import FormatTimeSpan
|
||||||
from anki.media import MediaManager, media_paths_from_col_path
|
from anki.media import MediaManager, media_paths_from_col_path
|
||||||
|
@ -335,6 +335,10 @@ class Collection:
|
||||||
"Get a new-style deck object. Currently read-only."
|
"Get a new-style deck object. Currently read-only."
|
||||||
return self._backend.get_deck(id)
|
return self._backend.get_deck(id)
|
||||||
|
|
||||||
|
def get_deck_config(self, id: DeckConfigId) -> DeckConfig:
|
||||||
|
"Get a new-style deck config object. Currently read-only."
|
||||||
|
return self._backend.get_deck_config(id)
|
||||||
|
|
||||||
def get_notetype(self, id: NotetypeId) -> Notetype:
|
def get_notetype(self, id: NotetypeId) -> Notetype:
|
||||||
"""Get a new-style notetype object. This is not cached; avoid calling frequently."""
|
"""Get a new-style notetype object. This is not cached; avoid calling frequently."""
|
||||||
return self._backend.get_notetype(id)
|
return self._backend.get_notetype(id)
|
||||||
|
|
|
@ -32,12 +32,13 @@ DeckConfigDict = Dict[str, Any]
|
||||||
|
|
||||||
# currently only supports read-only access
|
# currently only supports read-only access
|
||||||
Deck = _pb.Deck
|
Deck = _pb.Deck
|
||||||
|
DeckConfig = _pb.DeckConfig
|
||||||
|
|
||||||
DeckId = NewType("DeckId", int)
|
DeckId = NewType("DeckId", int)
|
||||||
DeckConfId = NewType("DeckConfId", int)
|
DeckConfigId = NewType("DeckConfigId", int)
|
||||||
|
|
||||||
DEFAULT_DECK_ID = DeckId(1)
|
DEFAULT_DECK_ID = DeckId(1)
|
||||||
DEFAULT_DECK_CONF_ID = DeckConfId(1)
|
DEFAULT_DECK_CONF_ID = DeckConfigId(1)
|
||||||
|
|
||||||
|
|
||||||
class DecksDictProxy:
|
class DecksDictProxy:
|
||||||
|
@ -128,7 +129,7 @@ class DeckManager:
|
||||||
self,
|
self,
|
||||||
name: str,
|
name: str,
|
||||||
create: bool = True,
|
create: bool = True,
|
||||||
type: DeckConfId = DeckConfId(0),
|
type: DeckConfigId = DeckConfigId(0),
|
||||||
) -> Optional[DeckId]:
|
) -> Optional[DeckId]:
|
||||||
"Add a deck with NAME. Reuse deck if already exists. Return id as int."
|
"Add a deck with NAME. Reuse deck if already exists. Return id as int."
|
||||||
id = self.id_for_name(name)
|
id = self.id_for_name(name)
|
||||||
|
@ -323,7 +324,7 @@ class DeckManager:
|
||||||
deck = self.get(did, default=False)
|
deck = self.get(did, default=False)
|
||||||
assert deck
|
assert deck
|
||||||
if "conf" in deck:
|
if "conf" in deck:
|
||||||
dcid = DeckConfId(int(deck["conf"])) # may be a string
|
dcid = DeckConfigId(int(deck["conf"])) # may be a string
|
||||||
conf = self.get_config(dcid)
|
conf = self.get_config(dcid)
|
||||||
if not conf:
|
if not conf:
|
||||||
# fall back on default
|
# fall back on default
|
||||||
|
@ -333,7 +334,7 @@ class DeckManager:
|
||||||
# dynamic decks have embedded conf
|
# dynamic decks have embedded conf
|
||||||
return deck
|
return deck
|
||||||
|
|
||||||
def get_config(self, conf_id: DeckConfId) -> Optional[DeckConfigDict]:
|
def get_config(self, conf_id: DeckConfigId) -> Optional[DeckConfigDict]:
|
||||||
try:
|
try:
|
||||||
return from_json_bytes(self.col._backend.get_deck_config_legacy(conf_id))
|
return from_json_bytes(self.col._backend.get_deck_config_legacy(conf_id))
|
||||||
except NotFoundError:
|
except NotFoundError:
|
||||||
|
@ -358,10 +359,10 @@ class DeckManager:
|
||||||
|
|
||||||
def add_config_returning_id(
|
def add_config_returning_id(
|
||||||
self, name: str, clone_from: Optional[DeckConfigDict] = None
|
self, name: str, clone_from: Optional[DeckConfigDict] = None
|
||||||
) -> DeckConfId:
|
) -> DeckConfigId:
|
||||||
return self.add_config(name, clone_from)["id"]
|
return self.add_config(name, clone_from)["id"]
|
||||||
|
|
||||||
def remove_config(self, id: DeckConfId) -> None:
|
def remove_config(self, id: DeckConfigId) -> None:
|
||||||
"Remove a configuration and update all decks using it."
|
"Remove a configuration and update all decks using it."
|
||||||
self.col.modSchema(check=True)
|
self.col.modSchema(check=True)
|
||||||
for g in self.all():
|
for g in self.all():
|
||||||
|
@ -373,7 +374,7 @@ class DeckManager:
|
||||||
self.save(g)
|
self.save(g)
|
||||||
self.col._backend.remove_deck_config(id)
|
self.col._backend.remove_deck_config(id)
|
||||||
|
|
||||||
def setConf(self, grp: DeckConfigDict, id: DeckConfId) -> None:
|
def setConf(self, grp: DeckConfigDict, id: DeckConfigId) -> None:
|
||||||
grp["conf"] = id
|
grp["conf"] = id
|
||||||
self.save(grp)
|
self.save(grp)
|
||||||
|
|
||||||
|
|
|
@ -219,6 +219,7 @@ service CardRenderingService {
|
||||||
service DeckConfigService {
|
service DeckConfigService {
|
||||||
rpc AddOrUpdateDeckConfigLegacy(AddOrUpdateDeckConfigLegacyIn)
|
rpc AddOrUpdateDeckConfigLegacy(AddOrUpdateDeckConfigLegacyIn)
|
||||||
returns (DeckConfigId);
|
returns (DeckConfigId);
|
||||||
|
rpc GetDeckConfig(DeckConfigId) returns (DeckConfig);
|
||||||
rpc AllDeckConfigLegacy(Empty) returns (Json);
|
rpc AllDeckConfigLegacy(Empty) returns (Json);
|
||||||
rpc GetDeckConfigLegacy(DeckConfigId) returns (Json);
|
rpc GetDeckConfigLegacy(DeckConfigId) returns (Json);
|
||||||
rpc NewDeckConfigLegacy(Empty) returns (Json);
|
rpc NewDeckConfigLegacy(Empty) returns (Json);
|
||||||
|
@ -294,71 +295,76 @@ service CardsService {
|
||||||
// These should be moved to a separate file in the future
|
// These should be moved to a separate file in the future
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
|
|
||||||
message DeckConfigInner {
|
message DeckConfig {
|
||||||
enum NewCardOrder {
|
message Config {
|
||||||
NEW_CARD_ORDER_DUE = 0;
|
enum NewCardOrder {
|
||||||
NEW_CARD_ORDER_RANDOM = 1;
|
NEW_CARD_ORDER_DUE = 0;
|
||||||
}
|
NEW_CARD_ORDER_RANDOM = 1;
|
||||||
enum ReviewCardOrder {
|
}
|
||||||
REVIEW_CARD_ORDER_SHUFFLED_BY_DAY = 0;
|
enum ReviewCardOrder {
|
||||||
REVIEW_CARD_ORDER_SHUFFLED = 1;
|
REVIEW_CARD_ORDER_SHUFFLED_BY_DAY = 0;
|
||||||
REVIEW_CARD_ORDER_INTERVALS_ASCENDING = 2;
|
REVIEW_CARD_ORDER_SHUFFLED = 1;
|
||||||
REVIEW_CARD_ORDER_INTERVALS_DESCENDING = 3;
|
REVIEW_CARD_ORDER_INTERVALS_ASCENDING = 2;
|
||||||
}
|
REVIEW_CARD_ORDER_INTERVALS_DESCENDING = 3;
|
||||||
enum ReviewMix {
|
}
|
||||||
REVIEW_MIX_MIX_WITH_REVIEWS = 0;
|
enum ReviewMix {
|
||||||
REVIEW_MIX_AFTER_REVIEWS = 1;
|
REVIEW_MIX_MIX_WITH_REVIEWS = 0;
|
||||||
REVIEW_MIX_BEFORE_REVIEWS = 2;
|
REVIEW_MIX_AFTER_REVIEWS = 1;
|
||||||
}
|
REVIEW_MIX_BEFORE_REVIEWS = 2;
|
||||||
enum LeechAction {
|
}
|
||||||
LEECH_ACTION_SUSPEND = 0;
|
enum LeechAction {
|
||||||
LEECH_ACTION_TAG_ONLY = 1;
|
LEECH_ACTION_SUSPEND = 0;
|
||||||
|
LEECH_ACTION_TAG_ONLY = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated float learn_steps = 1;
|
||||||
|
repeated float relearn_steps = 2;
|
||||||
|
|
||||||
|
reserved 3 to 8;
|
||||||
|
|
||||||
|
uint32 new_per_day = 9;
|
||||||
|
uint32 reviews_per_day = 10;
|
||||||
|
uint32 new_per_day_minimum = 29;
|
||||||
|
|
||||||
|
float initial_ease = 11;
|
||||||
|
float easy_multiplier = 12;
|
||||||
|
float hard_multiplier = 13;
|
||||||
|
float lapse_multiplier = 14;
|
||||||
|
float interval_multiplier = 15;
|
||||||
|
|
||||||
|
uint32 maximum_review_interval = 16;
|
||||||
|
uint32 minimum_lapse_interval = 17;
|
||||||
|
|
||||||
|
uint32 graduating_interval_good = 18;
|
||||||
|
uint32 graduating_interval_easy = 19;
|
||||||
|
|
||||||
|
NewCardOrder new_card_order = 20;
|
||||||
|
ReviewCardOrder review_order = 32;
|
||||||
|
|
||||||
|
ReviewMix new_mix = 30;
|
||||||
|
ReviewMix interday_learning_mix = 31;
|
||||||
|
|
||||||
|
LeechAction leech_action = 21;
|
||||||
|
uint32 leech_threshold = 22;
|
||||||
|
|
||||||
|
bool disable_autoplay = 23;
|
||||||
|
uint32 cap_answer_time_to_secs = 24;
|
||||||
|
uint32 visible_timer_secs = 25;
|
||||||
|
bool skip_question_when_replaying_answer = 26;
|
||||||
|
|
||||||
|
bool bury_new = 27;
|
||||||
|
bool bury_reviews = 28;
|
||||||
|
|
||||||
|
bytes other = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
repeated float learn_steps = 1;
|
int64 id = 1;
|
||||||
repeated float relearn_steps = 2;
|
string name = 2;
|
||||||
|
int64 mtime_secs = 3;
|
||||||
reserved 3 to 8;
|
int32 usn = 4;
|
||||||
|
Config config = 5;
|
||||||
uint32 new_per_day = 9;
|
|
||||||
uint32 reviews_per_day = 10;
|
|
||||||
uint32 new_per_day_minimum = 29;
|
|
||||||
|
|
||||||
float initial_ease = 11;
|
|
||||||
float easy_multiplier = 12;
|
|
||||||
float hard_multiplier = 13;
|
|
||||||
float lapse_multiplier = 14;
|
|
||||||
float interval_multiplier = 15;
|
|
||||||
|
|
||||||
uint32 maximum_review_interval = 16;
|
|
||||||
uint32 minimum_lapse_interval = 17;
|
|
||||||
|
|
||||||
uint32 graduating_interval_good = 18;
|
|
||||||
uint32 graduating_interval_easy = 19;
|
|
||||||
|
|
||||||
NewCardOrder new_card_order = 20;
|
|
||||||
ReviewCardOrder review_order = 32;
|
|
||||||
|
|
||||||
ReviewMix new_mix = 30;
|
|
||||||
ReviewMix interday_learning_mix = 31;
|
|
||||||
|
|
||||||
LeechAction leech_action = 21;
|
|
||||||
uint32 leech_threshold = 22;
|
|
||||||
|
|
||||||
bool disable_autoplay = 23;
|
|
||||||
uint32 cap_answer_time_to_secs = 24;
|
|
||||||
uint32 visible_timer_secs = 25;
|
|
||||||
bool skip_question_when_replaying_answer = 26;
|
|
||||||
|
|
||||||
bool bury_new = 27;
|
|
||||||
bool bury_reviews = 28;
|
|
||||||
|
|
||||||
bytes other = 255;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Containers for passing around database objects
|
|
||||||
///////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
message Deck {
|
message Deck {
|
||||||
message Common {
|
message Common {
|
||||||
bool study_collapsed = 1;
|
bool study_collapsed = 1;
|
||||||
|
@ -504,6 +510,9 @@ message Notetype {
|
||||||
repeated Template templates = 9;
|
repeated Template templates = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Database objects
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
|
||||||
message Note {
|
message Note {
|
||||||
int64 id = 1;
|
int64 id = 1;
|
||||||
string guid = 2;
|
string guid = 2;
|
||||||
|
|
|
@ -38,6 +38,10 @@ impl DeckConfigService for Backend {
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_deck_config(&self, input: pb::DeckConfigId) -> Result<pb::DeckConfig> {
|
||||||
|
self.with_col(|col| Ok(col.get_deck_config(input.into(), true)?.unwrap().into()))
|
||||||
|
}
|
||||||
|
|
||||||
fn get_deck_config_legacy(&self, input: pb::DeckConfigId) -> Result<pb::Json> {
|
fn get_deck_config_legacy(&self, input: pb::DeckConfigId) -> Result<pb::Json> {
|
||||||
self.with_col(|col| {
|
self.with_col(|col| {
|
||||||
let conf = col.get_deck_config(input.into(), true)?.unwrap();
|
let conf = col.get_deck_config(input.into(), true)?.unwrap();
|
||||||
|
@ -58,3 +62,15 @@ impl DeckConfigService for Backend {
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<DeckConf> for pb::DeckConfig {
|
||||||
|
fn from(c: DeckConf) -> Self {
|
||||||
|
pb::DeckConfig {
|
||||||
|
id: c.id.0,
|
||||||
|
name: c.name,
|
||||||
|
mtime_secs: c.mtime_secs.0,
|
||||||
|
usn: c.usn.0,
|
||||||
|
config: Some(c.inner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::backend_proto::{
|
pub use crate::backend_proto::{
|
||||||
deck_config_inner::{LeechAction, NewCardOrder, ReviewCardOrder, ReviewMix},
|
deck_config::config::{LeechAction, NewCardOrder, ReviewCardOrder, ReviewMix},
|
||||||
DeckConfigInner,
|
deck_config::Config as DeckConfigInner,
|
||||||
};
|
};
|
||||||
pub use schema11::{DeckConfSchema11, NewCardOrderSchema11};
|
pub use schema11::{DeckConfSchema11, NewCardOrderSchema11};
|
||||||
/// Old deck config and cards table store 250% as 2500.
|
/// Old deck config and cards table store 250% as 2500.
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use super::{DeckConf, DeckConfId, INITIAL_EASE_FACTOR_THOUSANDS};
|
use super::{DeckConf, DeckConfId, INITIAL_EASE_FACTOR_THOUSANDS};
|
||||||
use crate::backend_proto::deck_config_inner::NewCardOrder;
|
use super::{DeckConfigInner, NewCardOrder};
|
||||||
use crate::backend_proto::DeckConfigInner;
|
|
||||||
use crate::{serde::default_on_invalid, timestamp::TimestampSecs, types::Usn};
|
use crate::{serde::default_on_invalid, timestamp::TimestampSecs, types::Usn};
|
||||||
use serde_aux::field_attributes::deserialize_number_from_string;
|
use serde_aux::field_attributes::deserialize_number_from_string;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
Loading…
Reference in a new issue