diff --git a/rslib/src/browser_table.rs b/rslib/src/browser_table.rs index 9c55f6267..927dea6b7 100644 --- a/rslib/src/browser_table.rs +++ b/rslib/src/browser_table.rs @@ -94,55 +94,9 @@ pub struct Font { pub size: u32, } -trait RowContext { - fn get_cell_text(&mut self, column: Column) -> Result; - fn get_row_color(&self) -> Color; - fn get_row_font(&self) -> Result; - fn note(&self) -> &Note; - fn notetype(&self) -> &Notetype; - - fn get_cell(&mut self, column: Column) -> Result { - 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 { - Ok(Row { - cells: columns - .iter() - .map(|&column| self.get_cell(column)) - .collect::>()?, - color: self.get_row_color(), - font: self.get_row_font()?, - }) - } -} - -struct CardRowContext { - card: Card, +struct RowContext { + notes_mode: bool, + cards: Vec, note: Note, notetype: Arc, deck: Arc, @@ -159,14 +113,6 @@ struct RenderContext { answer_nodes: Vec, } -struct NoteRowContext { - note: Note, - notetype: Arc, - cards: Vec, - 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 { - 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 { @@ -275,20 +218,32 @@ impl RenderContext { } } -impl CardRowContext { - fn new(col: &mut Collection, id: i64, with_card_render: bool) -> Result { - let card = col - .storage - .get_card(CardId(id))? - .ok_or(AnkiError::NotFound)?; - let note = col.get_note_maybe_with_fields(card.note_id, with_card_render)?; +impl RowContext { + fn new( + col: &mut Collection, + id: i64, + notes_mode: bool, + with_card_render: bool, + ) -> Result { + 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 .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, ¬e, ¬etype)?) + Some(RenderContext::new(col, &cards[0], ¬e, ¬etype)?) } 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 { + Ok(Row { + cells: columns + .iter() + .map(|&column| self.get_cell(column)) + .collect::>()?, + color: self.get_row_color(), + font: self.get_row_font()?, + }) + } + + fn get_cell(&mut self, column: Column) -> Result { + Ok(Cell { + text: self.get_cell_text(column)?, + is_rtl: self.get_is_rtl(column), + }) + } + + fn get_cell_text(&mut self, column: Column) -> Result { + 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::().to_string(), + Column::NoteReps => self.cards.iter().map(|c| c.reps).sum::().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 { - 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 { - 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 { - 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 { - 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::().to_string(), - Column::NoteMod => self.note.mtime.date_string(), - Column::NoteReps => self.cards.iter().map(|c| c.reps).sum::().to_string(), - Column::NoteTags => self.note.tags.join(" "), - Column::Notetype => self.notetype.name.to_owned(), - _ => "".to_string(), + fn get_row_font(&self) -> Result { + 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.note.is_marked() { - Color::Marked + if self.notes_mode { + if self.note.is_marked() { + Color::Marked + } else { + Color::Default + } } 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 { - Ok(Font { - name: "".to_owned(), - size: 0, - }) - } - - fn note(&self) -> &Note { - &self.note - } - - fn notetype(&self) -> &Notetype { - &self.notetype - } }