mirror of
https://github.com/ankitects/anki.git
synced 2025-09-22 16:02:23 -04:00

The existing code was really difficult to reason about: - The default notetype depended on the selected deck, and vice versa, and this logic was buried in the deck and notetype choosing screens, and models.py. - Changes to the notetype were not passed back directly, but were fired via a hook, which changed any screen in the app that had a notetype selector. It also wasn't great for performance, as the most recent deck and tags were embedded in the notetype, which can be expensive to save and sync for large notetypes. To address these points: - The current deck for a notetype, and notetype for a deck, are now stored in separate config variables, instead of directly in the deck or notetype. These are cheap to read and write, and we'll be able to sync them individually in the future once config syncing is updated in the future. I seem to recall some users not wanting the tag saving behaviour, so I've dropped that for now, but if people end up missing it, it would be simple to add as an extra auxiliary config variable. - The logic for getting the starting deck and notetype has been moved into the backend. It should be the same as the older Python code, with one exception: when "change deck depending on notetype" is enabled in the preferences, it will start with the current notetype ("curModel"), instead of first trying to get a deck-specific notetype. - ModelChooser has been duplicated into notetypechooser.py, and it has been updated to solely be concerned with keeping track of a selected notetype - it no longer alters global state.
113 lines
4.1 KiB
Rust
113 lines
4.1 KiB
Rust
// Copyright: Ankitects Pty Ltd and contributors
|
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
use std::sync::Arc;
|
|
|
|
use crate::prelude::*;
|
|
|
|
pub struct DeckAndNotetype {
|
|
pub deck_id: DeckID,
|
|
pub notetype_id: NoteTypeID,
|
|
}
|
|
|
|
impl Collection {
|
|
/// An option in the preferences screen governs the behaviour here.
|
|
///
|
|
/// - When 'default to the current deck' is enabled, we use the current deck
|
|
/// if it's normal, the provided reviewer card's deck as a fallback, and
|
|
/// Default as a final fallback. We then fetch the last used notetype stored
|
|
/// in the deck, falling back to the global notetype, or the first available one.
|
|
///
|
|
/// - Otherwise, each note type remembers the last deck cards were added to,
|
|
/// and we use that, defaulting to the current deck if missing, and
|
|
/// Default otherwise.
|
|
pub fn defaults_for_adding(
|
|
&mut self,
|
|
home_deck_of_reviewer_card: DeckID,
|
|
) -> Result<DeckAndNotetype> {
|
|
let deck_id;
|
|
let notetype_id;
|
|
if self.get_bool(BoolKey::AddingDefaultsToCurrentDeck) {
|
|
deck_id = self
|
|
.get_current_deck_for_adding(home_deck_of_reviewer_card)?
|
|
.id;
|
|
notetype_id = self.default_notetype_for_deck(deck_id)?.id;
|
|
} else {
|
|
notetype_id = self.get_current_notetype_for_adding()?.id;
|
|
deck_id = if let Some(deck_id) = self.default_deck_for_notetype(notetype_id)? {
|
|
deck_id
|
|
} else {
|
|
// default not set in notetype; fall back to current deck
|
|
self.get_current_deck_for_adding(home_deck_of_reviewer_card)?
|
|
.id
|
|
};
|
|
}
|
|
|
|
Ok(DeckAndNotetype {
|
|
deck_id,
|
|
notetype_id,
|
|
})
|
|
}
|
|
|
|
/// The currently selected deck, the home deck of the provided card, or the default deck.
|
|
fn get_current_deck_for_adding(
|
|
&mut self,
|
|
home_deck_of_reviewer_card: DeckID,
|
|
) -> Result<Arc<Deck>> {
|
|
// current deck, if not filtered
|
|
if let Some(current) = self.get_deck(self.get_current_deck_id())? {
|
|
if !current.is_filtered() {
|
|
return Ok(current);
|
|
}
|
|
}
|
|
// provided reviewer card's home deck
|
|
if let Some(home_deck) = self.get_deck(home_deck_of_reviewer_card)? {
|
|
return Ok(home_deck);
|
|
}
|
|
// default deck
|
|
self.get_deck(DeckID(1))?.ok_or(AnkiError::NotFound)
|
|
}
|
|
|
|
fn get_current_notetype_for_adding(&mut self) -> Result<Arc<NoteType>> {
|
|
// try global 'current' notetype
|
|
if let Some(ntid) = self.get_current_notetype_id() {
|
|
if let Some(nt) = self.get_notetype(ntid)? {
|
|
return Ok(nt);
|
|
}
|
|
}
|
|
// try first available notetype
|
|
if let Some((ntid, _)) = self.storage.get_all_notetype_names()?.first() {
|
|
Ok(self.get_notetype(*ntid)?.unwrap())
|
|
} else {
|
|
Err(AnkiError::NotFound)
|
|
}
|
|
}
|
|
|
|
fn default_notetype_for_deck(&mut self, deck: DeckID) -> Result<Arc<NoteType>> {
|
|
// try last notetype used by deck
|
|
if let Some(ntid) = self.get_last_notetype_for_deck(deck) {
|
|
if let Some(nt) = self.get_notetype(ntid)? {
|
|
return Ok(nt);
|
|
}
|
|
}
|
|
|
|
// fall back
|
|
self.get_current_notetype_for_adding()
|
|
}
|
|
|
|
/// Returns the last deck added to with this notetype, provided it is valid.
|
|
/// This is optional due to the inconsistent handling, where changes in notetype
|
|
/// may need to update the current deck, but not vice versa. If a previous deck is
|
|
/// not set, we want to keep the current selection, instead of resetting it.
|
|
pub(crate) fn default_deck_for_notetype(&mut self, ntid: NoteTypeID) -> Result<Option<DeckID>> {
|
|
if let Some(last_deck_id) = self.get_last_deck_added_to_for_notetype(ntid) {
|
|
if let Some(deck) = self.get_deck(last_deck_id)? {
|
|
if !deck.is_filtered() {
|
|
return Ok(Some(deck.id));
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(None)
|
|
}
|
|
}
|