Merge row contexts

This commit is contained in:
RumovZ 2021-04-08 13:29:32 +02:00
parent 8a131da9a2
commit c6ebb9b441

View File

@ -94,55 +94,9 @@ pub struct Font {
pub size: u32,
}
trait RowContext {
fn get_cell_text(&mut self, column: Column) -> Result<String>;
fn get_row_color(&self) -> Color;
fn get_row_font(&self) -> Result<Font>;
fn note(&self) -> &Note;
fn notetype(&self) -> &Notetype;
fn get_cell(&mut self, column: Column) -> Result<Cell> {
Ok(Cell {
text: self.get_cell_text(column)?,
is_rtl: self.get_is_rtl(column),
})
}
fn note_creation_str(&self) -> String {
TimestampMillis(self.note().id.into())
.as_secs()
.date_string()
}
fn note_field_str(&self) -> String {
let index = self.notetype().config.sort_field_idx as usize;
html_to_text_line(&self.note().fields()[index]).into()
}
fn get_is_rtl(&self, column: Column) -> bool {
match column {
Column::NoteField => {
let index = self.notetype().config.sort_field_idx as usize;
self.notetype().fields[index].config.rtl
}
_ => false,
}
}
fn browser_row_for_id(&mut self, columns: &[Column]) -> Result<Row> {
Ok(Row {
cells: columns
.iter()
.map(|&column| self.get_cell(column))
.collect::<Result<_>>()?,
color: self.get_row_color(),
font: self.get_row_font()?,
})
}
}
struct CardRowContext {
card: Card,
struct RowContext {
notes_mode: bool,
cards: Vec<Card>,
note: Note,
notetype: Arc<Notetype>,
deck: Arc<Deck>,
@ -159,14 +113,6 @@ struct RenderContext {
answer_nodes: Vec<RenderedNode>,
}
struct NoteRowContext {
note: Note,
notetype: Arc<Notetype>,
cards: Vec<Card>,
tr: I18n,
timing: SchedTimingToday,
}
fn card_render_required(columns: &[Column]) -> bool {
columns
.iter()
@ -218,18 +164,15 @@ impl Note {
impl Collection {
pub fn browser_row_for_id(&mut self, id: i64) -> Result<Row> {
if self.get_bool(BoolKey::BrowserTableShowNotesMode) {
let columns = self
.get_desktop_browser_note_columns()
.ok_or_else(|| AnkiError::invalid_input("Note columns not set."))?;
NoteRowContext::new(self, id)?.browser_row_for_id(&columns)
let notes_mode = self.get_bool(BoolKey::BrowserTableShowNotesMode);
let columns = if notes_mode {
self.get_desktop_browser_note_columns()
.ok_or_else(|| AnkiError::invalid_input("Note columns not set."))?
} else {
let columns = self
.get_desktop_browser_card_columns()
.ok_or_else(|| AnkiError::invalid_input("Card columns not set."))?;
CardRowContext::new(self, id, card_render_required(&columns))?
.browser_row_for_id(&columns)
}
self.get_desktop_browser_card_columns()
.ok_or_else(|| AnkiError::invalid_input("Card columns not set."))?
};
RowContext::new(self, id, notes_mode, card_render_required(&columns))?.browser_row(&columns)
}
fn get_note_maybe_with_fields(&self, id: NoteId, _with_fields: bool) -> Result<Note> {
@ -275,20 +218,32 @@ impl RenderContext {
}
}
impl CardRowContext {
fn new(col: &mut Collection, id: i64, with_card_render: bool) -> Result<Self> {
let card = col
impl RowContext {
fn new(
col: &mut Collection,
id: i64,
notes_mode: bool,
with_card_render: bool,
) -> Result<Self> {
let cards;
let note;
if notes_mode {
note = col.get_note_maybe_with_fields(NoteId(id), with_card_render)?;
cards = col.storage.all_cards_of_note(note.id)?;
} else {
cards = vec![col
.storage
.get_card(CardId(id))?
.ok_or(AnkiError::NotFound)?;
let note = col.get_note_maybe_with_fields(card.note_id, with_card_render)?;
.ok_or(AnkiError::NotFound)?];
note = col.get_note_maybe_with_fields(cards[0].note_id, with_card_render)?;
}
let notetype = col
.get_notetype(note.notetype_id)?
.ok_or(AnkiError::NotFound)?;
let deck = col.get_deck(card.deck_id)?.ok_or(AnkiError::NotFound)?;
let original_deck = if card.original_deck_id.0 != 0 {
let deck = col.get_deck(cards[0].deck_id)?.ok_or(AnkiError::NotFound)?;
let original_deck = if cards[0].original_deck_id.0 != 0 {
Some(
col.get_deck(card.original_deck_id)?
col.get_deck(cards[0].original_deck_id)?
.ok_or(AnkiError::NotFound)?,
)
} else {
@ -296,13 +251,14 @@ impl CardRowContext {
};
let timing = col.timing_today()?;
let render_context = if with_card_render {
Some(RenderContext::new(col, &card, &note, &notetype)?)
Some(RenderContext::new(col, &cards[0], &note, &notetype)?)
} else {
None
};
Ok(CardRowContext {
card,
Ok(RowContext {
notes_mode,
cards,
note,
notetype,
deck,
@ -313,8 +269,72 @@ impl CardRowContext {
})
}
fn browser_row(&mut self, columns: &[Column]) -> Result<Row> {
Ok(Row {
cells: columns
.iter()
.map(|&column| self.get_cell(column))
.collect::<Result<_>>()?,
color: self.get_row_color(),
font: self.get_row_font()?,
})
}
fn get_cell(&mut self, column: Column) -> Result<Cell> {
Ok(Cell {
text: self.get_cell_text(column)?,
is_rtl: self.get_is_rtl(column),
})
}
fn get_cell_text(&mut self, column: Column) -> Result<String> {
Ok(match column {
Column::Question => self.question_str(),
Column::Answer => self.answer_str(),
Column::CardDeck => self.deck_str(),
Column::CardDue => self.card_due_str(),
Column::CardEase => self.card_ease_str(),
Column::CardInterval => self.card_interval_str(),
Column::CardLapses => self.cards[0].lapses.to_string(),
Column::CardMod => self.cards[0].mtime.date_string(),
Column::CardReps => self.cards[0].reps.to_string(),
Column::CardTemplate => self.template_str()?,
Column::NoteCreation => self.note_creation_str(),
Column::NoteField => self.note_field_str(),
Column::NoteMod => self.note.mtime.date_string(),
Column::NoteTags => self.note.tags.join(" "),
Column::Notetype => self.notetype.name.to_owned(),
Column::NoteCards => self.cards.len().to_string(),
Column::NoteDue => self.note_due_str(),
Column::NoteEase => self.note_ease_str(),
Column::NoteInterval => self.note_interval_str(),
Column::NoteLapses => self.cards.iter().map(|c| c.lapses).sum::<u32>().to_string(),
Column::NoteReps => self.cards.iter().map(|c| c.reps).sum::<u32>().to_string(),
Column::Custom => "".to_string(),
})
}
fn note_creation_str(&self) -> String {
TimestampMillis(self.note.id.into()).as_secs().date_string()
}
fn note_field_str(&self) -> String {
let index = self.notetype.config.sort_field_idx as usize;
html_to_text_line(&self.note.fields()[index]).into()
}
fn get_is_rtl(&self, column: Column) -> bool {
match column {
Column::NoteField => {
let index = self.notetype.config.sort_field_idx as usize;
self.notetype.fields[index].config.rtl
}
_ => false,
}
}
fn template(&self) -> Result<&CardTemplate> {
self.notetype.get_template(self.card.template_idx)
self.notetype.get_template(self.cards[0].template_idx)
}
fn answer_str(&self) -> String {
@ -343,16 +363,16 @@ impl CardRowContext {
}
fn card_due_str(&mut self) -> String {
let due = if self.card.is_filtered_deck() {
let due = if self.cards[0].is_filtered_deck() {
self.tr.browsing_filtered()
} else if self.card.is_new_type_or_queue() {
self.tr.statistics_due_for_new_card(self.card.due)
} else if let Some(time) = self.card.due_time(&self.timing) {
} else if self.cards[0].is_new_type_or_queue() {
self.tr.statistics_due_for_new_card(self.cards[0].due)
} else if let Some(time) = self.cards[0].due_time(&self.timing) {
time.date_string().into()
} else {
return "".into();
};
if self.card.is_undue_queue() {
if self.cards[0].is_undue_queue() {
format!("({})", due)
} else {
due.into()
@ -360,17 +380,17 @@ impl CardRowContext {
}
fn card_ease_str(&self) -> String {
match self.card.ctype {
match self.cards[0].ctype {
CardType::New => self.tr.browsing_new().into(),
_ => format!("{}%", self.card.ease_factor / 10),
_ => format!("{}%", self.cards[0].ease_factor / 10),
}
}
fn card_interval_str(&self) -> String {
match self.card.ctype {
match self.cards[0].ctype {
CardType::New => self.tr.browsing_new().into(),
CardType::Learn => self.tr.browsing_learning().into(),
_ => time_span((self.card.interval * 86400) as f32, &self.tr, false),
_ => time_span((self.cards[0].interval * 86400) as f32, &self.tr, false),
}
}
@ -387,88 +407,13 @@ impl CardRowContext {
let name = &self.template()?.name;
Ok(match self.notetype.config.kind() {
NotetypeKind::Normal => name.to_owned(),
NotetypeKind::Cloze => format!("{} {}", name, self.card.template_idx + 1),
NotetypeKind::Cloze => format!("{} {}", name, self.cards[0].template_idx + 1),
})
}
fn question_str(&self) -> String {
html_to_text_line(&self.render_context.as_ref().unwrap().question).to_string()
}
}
impl RowContext for CardRowContext {
fn get_cell_text(&mut self, column: Column) -> Result<String> {
Ok(match column {
Column::Question => self.question_str(),
Column::Answer => self.answer_str(),
Column::CardDeck => self.deck_str(),
Column::CardDue => self.card_due_str(),
Column::CardEase => self.card_ease_str(),
Column::CardInterval => self.card_interval_str(),
Column::CardLapses => self.card.lapses.to_string(),
Column::CardMod => self.card.mtime.date_string(),
Column::CardReps => self.card.reps.to_string(),
Column::CardTemplate => self.template_str()?,
Column::NoteCreation => self.note_creation_str(),
Column::NoteField => self.note_field_str(),
Column::NoteMod => self.note.mtime.date_string(),
Column::NoteTags => self.note.tags.join(" "),
Column::Notetype => self.notetype.name.to_owned(),
_ => "".to_string(),
})
}
fn get_row_color(&self) -> Color {
match self.card.flags {
1 => Color::FlagRed,
2 => Color::FlagOrange,
3 => Color::FlagGreen,
4 => Color::FlagBlue,
_ => {
if self.note.is_marked() {
Color::Marked
} else if self.card.queue == CardQueue::Suspended {
Color::Suspended
} else {
Color::Default
}
}
}
}
fn get_row_font(&self) -> Result<Font> {
Ok(Font {
name: self.template()?.config.browser_font_name.to_owned(),
size: self.template()?.config.browser_font_size,
})
}
fn note(&self) -> &Note {
&self.note
}
fn notetype(&self) -> &Notetype {
&self.notetype
}
}
impl NoteRowContext {
fn new(col: &mut Collection, id: i64) -> Result<Self> {
let note = col.get_note_maybe_with_fields(NoteId(id), false)?;
let notetype = col
.get_notetype(note.notetype_id)?
.ok_or(AnkiError::NotFound)?;
let cards = col.storage.all_cards_of_note(note.id)?;
let timing = col.timing_today()?;
Ok(NoteRowContext {
note,
notetype,
cards,
tr: col.tr.clone(),
timing,
})
}
/// Returns the average ease of the non-new cards or a hint if there aren't any.
fn note_ease_str(&self) -> String {
@ -516,46 +461,37 @@ impl NoteRowContext {
)
}
}
}
impl RowContext for NoteRowContext {
fn get_cell_text(&mut self, column: Column) -> Result<String> {
Ok(match column {
Column::NoteCards => self.cards.len().to_string(),
Column::NoteCreation => self.note_creation_str(),
Column::NoteDue => self.note_due_str(),
Column::NoteEase => self.note_ease_str(),
Column::NoteField => self.note_field_str(),
Column::NoteInterval => self.note_interval_str(),
Column::NoteLapses => self.cards.iter().map(|c| c.lapses).sum::<u32>().to_string(),
Column::NoteMod => self.note.mtime.date_string(),
Column::NoteReps => self.cards.iter().map(|c| c.reps).sum::<u32>().to_string(),
Column::NoteTags => self.note.tags.join(" "),
Column::Notetype => self.notetype.name.to_owned(),
_ => "".to_string(),
fn get_row_font(&self) -> Result<Font> {
Ok(Font {
name: self.template()?.config.browser_font_name.to_owned(),
size: self.template()?.config.browser_font_size,
})
}
fn get_row_color(&self) -> Color {
if self.notes_mode {
if self.note.is_marked() {
Color::Marked
} else {
Color::Default
}
}
fn get_row_font(&self) -> Result<Font> {
Ok(Font {
name: "".to_owned(),
size: 0,
})
}
fn note(&self) -> &Note {
&self.note
}
fn notetype(&self) -> &Notetype {
&self.notetype
} else {
match self.cards[0].flags {
1 => Color::FlagRed,
2 => Color::FlagOrange,
3 => Color::FlagGreen,
4 => Color::FlagBlue,
_ => {
if self.note.is_marked() {
Color::Marked
} else if self.cards[0].queue == CardQueue::Suspended {
Color::Suspended
} else {
Color::Default
}
}
}
}
}
}