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, pub size: u32,
} }
trait RowContext { struct RowContext {
fn get_cell_text(&mut self, column: Column) -> Result<String>; notes_mode: bool,
fn get_row_color(&self) -> Color; cards: Vec<Card>,
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,
note: Note, note: Note,
notetype: Arc<Notetype>, notetype: Arc<Notetype>,
deck: Arc<Deck>, deck: Arc<Deck>,
@ -159,14 +113,6 @@ struct RenderContext {
answer_nodes: Vec<RenderedNode>, 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 { fn card_render_required(columns: &[Column]) -> bool {
columns columns
.iter() .iter()
@ -218,18 +164,15 @@ impl Note {
impl Collection { impl Collection {
pub fn browser_row_for_id(&mut self, id: i64) -> Result<Row> { pub fn browser_row_for_id(&mut self, id: i64) -> Result<Row> {
if self.get_bool(BoolKey::BrowserTableShowNotesMode) { let notes_mode = self.get_bool(BoolKey::BrowserTableShowNotesMode);
let columns = self let columns = if notes_mode {
.get_desktop_browser_note_columns() self.get_desktop_browser_note_columns()
.ok_or_else(|| AnkiError::invalid_input("Note columns not set."))?; .ok_or_else(|| AnkiError::invalid_input("Note columns not set."))?
NoteRowContext::new(self, id)?.browser_row_for_id(&columns)
} else { } else {
let columns = self self.get_desktop_browser_card_columns()
.get_desktop_browser_card_columns() .ok_or_else(|| AnkiError::invalid_input("Card columns not set."))?
.ok_or_else(|| AnkiError::invalid_input("Card columns not set."))?; };
CardRowContext::new(self, id, card_render_required(&columns))? RowContext::new(self, id, notes_mode, card_render_required(&columns))?.browser_row(&columns)
.browser_row_for_id(&columns)
}
} }
fn get_note_maybe_with_fields(&self, id: NoteId, _with_fields: bool) -> Result<Note> { fn get_note_maybe_with_fields(&self, id: NoteId, _with_fields: bool) -> Result<Note> {
@ -275,20 +218,32 @@ impl RenderContext {
} }
} }
impl CardRowContext { impl RowContext {
fn new(col: &mut Collection, id: i64, with_card_render: bool) -> Result<Self> { fn new(
let card = col col: &mut Collection,
.storage id: i64,
.get_card(CardId(id))? notes_mode: bool,
.ok_or(AnkiError::NotFound)?; with_card_render: bool,
let note = col.get_note_maybe_with_fields(card.note_id, with_card_render)?; ) -> 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)?];
note = col.get_note_maybe_with_fields(cards[0].note_id, with_card_render)?;
}
let notetype = col let notetype = col
.get_notetype(note.notetype_id)? .get_notetype(note.notetype_id)?
.ok_or(AnkiError::NotFound)?; .ok_or(AnkiError::NotFound)?;
let deck = col.get_deck(card.deck_id)?.ok_or(AnkiError::NotFound)?; let deck = col.get_deck(cards[0].deck_id)?.ok_or(AnkiError::NotFound)?;
let original_deck = if card.original_deck_id.0 != 0 { let original_deck = if cards[0].original_deck_id.0 != 0 {
Some( Some(
col.get_deck(card.original_deck_id)? col.get_deck(cards[0].original_deck_id)?
.ok_or(AnkiError::NotFound)?, .ok_or(AnkiError::NotFound)?,
) )
} else { } else {
@ -296,13 +251,14 @@ impl CardRowContext {
}; };
let timing = col.timing_today()?; let timing = col.timing_today()?;
let render_context = if with_card_render { let render_context = if with_card_render {
Some(RenderContext::new(col, &card, &note, &notetype)?) Some(RenderContext::new(col, &cards[0], &note, &notetype)?)
} else { } else {
None None
}; };
Ok(CardRowContext { Ok(RowContext {
card, notes_mode,
cards,
note, note,
notetype, notetype,
deck, 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> { 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 { fn answer_str(&self) -> String {
@ -343,16 +363,16 @@ impl CardRowContext {
} }
fn card_due_str(&mut self) -> String { 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() self.tr.browsing_filtered()
} else if self.card.is_new_type_or_queue() { } else if self.cards[0].is_new_type_or_queue() {
self.tr.statistics_due_for_new_card(self.card.due) self.tr.statistics_due_for_new_card(self.cards[0].due)
} else if let Some(time) = self.card.due_time(&self.timing) { } else if let Some(time) = self.cards[0].due_time(&self.timing) {
time.date_string().into() time.date_string().into()
} else { } else {
return "".into(); return "".into();
}; };
if self.card.is_undue_queue() { if self.cards[0].is_undue_queue() {
format!("({})", due) format!("({})", due)
} else { } else {
due.into() due.into()
@ -360,17 +380,17 @@ impl CardRowContext {
} }
fn card_ease_str(&self) -> String { fn card_ease_str(&self) -> String {
match self.card.ctype { match self.cards[0].ctype {
CardType::New => self.tr.browsing_new().into(), 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 { fn card_interval_str(&self) -> String {
match self.card.ctype { match self.cards[0].ctype {
CardType::New => self.tr.browsing_new().into(), CardType::New => self.tr.browsing_new().into(),
CardType::Learn => self.tr.browsing_learning().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; let name = &self.template()?.name;
Ok(match self.notetype.config.kind() { Ok(match self.notetype.config.kind() {
NotetypeKind::Normal => name.to_owned(), 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 { fn question_str(&self) -> String {
html_to_text_line(&self.render_context.as_ref().unwrap().question).to_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. /// Returns the average ease of the non-new cards or a hint if there aren't any.
fn note_ease_str(&self) -> String { fn note_ease_str(&self) -> String {
@ -516,46 +461,37 @@ impl NoteRowContext {
) )
} }
} }
}
impl RowContext for NoteRowContext { fn get_row_font(&self) -> Result<Font> {
fn get_cell_text(&mut self, column: Column) -> Result<String> { Ok(Font {
Ok(match column { name: self.template()?.config.browser_font_name.to_owned(),
Column::NoteCards => self.cards.len().to_string(), size: self.template()?.config.browser_font_size,
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_color(&self) -> Color { fn get_row_color(&self) -> Color {
if self.note.is_marked() { if self.notes_mode {
Color::Marked if self.note.is_marked() {
Color::Marked
} else {
Color::Default
}
} else { } else {
Color::Default 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
}
}
}
} }
} }
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
}
} }