Merge pull request #1104 from RumovZ/column-enum

Column enum for backend
This commit is contained in:
Damien Elmes 2021-03-30 20:32:25 +10:00 committed by GitHub
commit 42942a521e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 199 additions and 112 deletions

View File

@ -681,7 +681,7 @@ class Collection:
else:
return SearchNode.Group.Joiner.OR
# Browser rows
# Browser Table
##########################################################################
def browser_row_for_id(
@ -695,6 +695,30 @@ class Collection:
row.font_size,
)
def load_browser_card_columns(self) -> List[str]:
"""Return the stored card column names and ensure the backend columns are set and in sync."""
columns = self.get_config(
"activeCols", ["noteFld", "template", "cardDue", "deck"]
)
self._backend.set_desktop_browser_card_columns(columns)
return columns
def set_browser_card_columns(self, columns: List[str]) -> None:
self.set_config("activeCols", columns)
self._backend.set_desktop_browser_card_columns(columns)
def load_browser_note_columns(self) -> List[str]:
"""Return the stored note column names and ensure the backend columns are set and in sync."""
columns = self.get_config(
"activeNoteCols", ["noteFld", "note", "noteCards", "noteTags"]
)
self._backend.set_desktop_browser_note_columns(columns)
return columns
def set_browser_note_columns(self, columns: List[str]) -> None:
self.set_config("activeNoteCols", columns)
self._backend.set_desktop_browser_note_columns(columns)
# Config
##########################################################################

View File

@ -618,7 +618,7 @@ class CardState(ItemState):
def __init__(self, col: Collection) -> None:
super().__init__(col)
self._load_columns()
self._load_active_columns()
self._active_columns = self.col.load_browser_card_columns()
self._sort_column = self.col.get_config("sortType")
self._sort_backwards = self.col.get_config_bool(
Config.Bool.BROWSER_SORT_BACKWARDS
@ -644,11 +644,6 @@ class CardState(ItemState):
]
self._columns.sort(key=itemgetter(1))
def _load_active_columns(self) -> None:
self._active_columns = self.col.get_config(
"activeCols", ["noteFld", "template", "cardDue", "deck"]
)
@property
def columns(self) -> List[Tuple[str, str]]:
return self._columns
@ -662,7 +657,7 @@ class CardState(ItemState):
self._active_columns.remove(column)
else:
self._active_columns.append(column)
self.col.set_config("activeCols", self._active_columns)
self.col.set_browser_card_columns(self._active_columns)
@property
def sort_column(self) -> str:
@ -711,7 +706,7 @@ class NoteState(ItemState):
def __init__(self, col: Collection) -> None:
super().__init__(col)
self._load_columns()
self._load_active_columns()
self._active_columns = self.col.load_browser_note_columns()
self._sort_column = self.col.get_config("noteSortType")
self._sort_backwards = self.col.get_config_bool(
Config.Bool.BROWSER_NOTE_SORT_BACKWARDS
@ -731,11 +726,6 @@ class NoteState(ItemState):
]
self._columns.sort(key=itemgetter(1))
def _load_active_columns(self) -> None:
self._active_columns = self.col.get_config(
"activeNoteCols", ["noteFld", "note", "noteTags", "noteMod"]
)
@property
def columns(self) -> List[Tuple[str, str]]:
return self._columns
@ -749,7 +739,7 @@ class NoteState(ItemState):
self._active_columns.remove(column)
else:
self._active_columns.append(column)
self.col.set_config("activeNoteCols", self._active_columns)
self.col.set_browser_note_columns(self._active_columns)
@property
def sort_column(self) -> str:

View File

@ -243,6 +243,8 @@ service SearchService {
rpc ReplaceSearchNode(ReplaceSearchNodeIn) returns (String);
rpc FindAndReplace(FindAndReplaceIn) returns (OpChangesWithCount);
rpc BrowserRowForId(Int64) returns (BrowserRow);
rpc SetDesktopBrowserCardColumns(StringList) returns (Empty);
rpc SetDesktopBrowserNoteColumns(StringList) returns (Empty);
}
service StatsService {

View File

@ -1,38 +0,0 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use crate::{backend_proto as pb, browser_rows};
impl From<browser_rows::Row> for pb::BrowserRow {
fn from(row: browser_rows::Row) -> Self {
pb::BrowserRow {
cells: row.cells.into_iter().map(Into::into).collect(),
color: row.color.into(),
font_name: row.font.name,
font_size: row.font.size,
}
}
}
impl From<browser_rows::Cell> for pb::browser_row::Cell {
fn from(cell: browser_rows::Cell) -> Self {
pb::browser_row::Cell {
text: cell.text,
is_rtl: cell.is_rtl,
}
}
}
impl From<browser_rows::Color> for i32 {
fn from(color: browser_rows::Color) -> Self {
match color {
browser_rows::Color::Default => pb::browser_row::Color::Default as i32,
browser_rows::Color::Marked => pb::browser_row::Color::Marked as i32,
browser_rows::Color::Suspended => pb::browser_row::Color::Suspended as i32,
browser_rows::Color::FlagRed => pb::browser_row::Color::FlagRed as i32,
browser_rows::Color::FlagOrange => pb::browser_row::Color::FlagOrange as i32,
browser_rows::Color::FlagGreen => pb::browser_row::Color::FlagGreen as i32,
browser_rows::Color::FlagBlue => pb::browser_row::Color::FlagBlue as i32,
}
}
}

View File

@ -0,0 +1,71 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use crate::{backend_proto as pb, browser_table};
impl From<pb::StringList> for Vec<browser_table::Column> {
fn from(input: pb::StringList) -> Self {
input.vals.into_iter().map(Into::into).collect()
}
}
impl From<String> for browser_table::Column {
fn from(text: String) -> Self {
match text.as_str() {
"question" => browser_table::Column::Question,
"answer" => browser_table::Column::Answer,
"deck" => browser_table::Column::CardDeck,
"cardDue" => browser_table::Column::CardDue,
"cardEase" => browser_table::Column::CardEase,
"cardLapses" => browser_table::Column::CardLapses,
"cardIvl" => browser_table::Column::CardInterval,
"cardMod" => browser_table::Column::CardMod,
"cardReps" => browser_table::Column::CardReps,
"template" => browser_table::Column::CardTemplate,
"noteCards" => browser_table::Column::NoteCards,
"noteCrt" => browser_table::Column::NoteCreation,
"noteEase" => browser_table::Column::NoteEase,
"noteFld" => browser_table::Column::NoteField,
"noteLapses" => browser_table::Column::NoteLapses,
"noteMod" => browser_table::Column::NoteMod,
"noteReps" => browser_table::Column::NoteReps,
"noteTags" => browser_table::Column::NoteTags,
"note" => browser_table::Column::Notetype,
_ => browser_table::Column::Custom,
}
}
}
impl From<browser_table::Row> for pb::BrowserRow {
fn from(row: browser_table::Row) -> Self {
pb::BrowserRow {
cells: row.cells.into_iter().map(Into::into).collect(),
color: row.color.into(),
font_name: row.font.name,
font_size: row.font.size,
}
}
}
impl From<browser_table::Cell> for pb::browser_row::Cell {
fn from(cell: browser_table::Cell) -> Self {
pb::browser_row::Cell {
text: cell.text,
is_rtl: cell.is_rtl,
}
}
}
impl From<browser_table::Color> for i32 {
fn from(color: browser_table::Color) -> Self {
match color {
browser_table::Color::Default => pb::browser_row::Color::Default as i32,
browser_table::Color::Marked => pb::browser_row::Color::Marked as i32,
browser_table::Color::Suspended => pb::browser_row::Color::Suspended as i32,
browser_table::Color::FlagRed => pb::browser_row::Color::FlagRed as i32,
browser_table::Color::FlagOrange => pb::browser_row::Color::FlagOrange as i32,
browser_table::Color::FlagGreen => pb::browser_row::Color::FlagGreen as i32,
browser_table::Color::FlagBlue => pb::browser_row::Color::FlagBlue as i32,
}
}
}

View File

@ -1,7 +1,7 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
mod browser_row;
mod browser_table;
mod search_node;
use std::convert::TryInto;
@ -92,6 +92,16 @@ impl SearchService for Backend {
fn browser_row_for_id(&self, input: pb::Int64) -> Result<pb::BrowserRow> {
self.with_col(|col| col.browser_row_for_id(input.val).map(Into::into))
}
fn set_desktop_browser_card_columns(&self, input: pb::StringList) -> Result<pb::Empty> {
self.with_col(|col| col.set_desktop_browser_card_columns(input.into()))?;
Ok(().into())
}
fn set_desktop_browser_note_columns(&self, input: pb::StringList) -> Result<pb::Empty> {
self.with_col(|col| col.set_desktop_browser_note_columns(input.into()))?;
Ok(().into())
}
}
impl From<SortKindProto> for SortKind {

View File

@ -4,6 +4,7 @@
use std::sync::Arc;
use itertools::Itertools;
use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::err::{AnkiError, Result};
use crate::i18n::I18n;
@ -20,7 +21,30 @@ use crate::{
timestamp::{TimestampMillis, TimestampSecs},
};
const CARD_RENDER_COLUMNS: [&str; 2] = ["question", "answer"];
#[derive(Serialize_repr, Deserialize_repr, Debug, PartialEq, Clone, Copy)]
#[repr(u8)]
pub enum Column {
Custom = 0,
Question = 1,
Answer = 2,
CardDeck = 3,
CardDue = 4,
CardEase = 5,
CardLapses = 6,
CardInterval = 7,
CardMod = 8,
CardReps = 9,
CardTemplate = 10,
NoteCards = 11,
NoteCreation = 12,
NoteEase = 13,
NoteField = 14,
NoteLapses = 15,
NoteMod = 16,
NoteReps = 17,
NoteTags = 18,
Notetype = 19,
}
#[derive(Debug, PartialEq)]
pub struct Row {
@ -53,13 +77,13 @@ pub struct Font {
}
trait RowContext {
fn get_cell_text(&mut self, column: &str) -> Result<String>;
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: &str) -> Result<Cell> {
fn get_cell(&mut self, column: &Column) -> Result<Cell> {
Ok(Cell {
text: self.get_cell_text(column)?,
is_rtl: self.get_is_rtl(column),
@ -77,9 +101,9 @@ trait RowContext {
html_to_text_line(&self.note().fields()[index]).into()
}
fn get_is_rtl(&self, column: &str) -> bool {
fn get_is_rtl(&self, column: &Column) -> bool {
match column {
"noteFld" => {
Column::NoteField => {
let index = self.notetype().config.sort_field_idx as usize;
self.notetype().fields[index].config.rtl
}
@ -87,7 +111,7 @@ trait RowContext {
}
}
fn browser_row_for_id(&mut self, columns: &[String]) -> Result<Row> {
fn browser_row_for_id(&mut self, columns: &[Column]) -> Result<Row> {
Ok(Row {
cells: columns
.iter()
@ -125,20 +149,27 @@ struct NoteRowContext<'a> {
tr: &'a I18n,
}
fn card_render_required(columns: &[String]) -> bool {
fn card_render_required(columns: &[Column]) -> bool {
columns
.iter()
.any(|c| CARD_RENDER_COLUMNS.contains(&c.as_str()))
.any(|c| matches!(c, Column::Question | Column::Answer))
}
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();
let columns =
self.get_desktop_browser_note_columns()
.ok_or(AnkiError::InvalidInput {
info: "Note columns not set.".into(),
})?;
NoteRowContext::new(self, id)?.browser_row_for_id(&columns)
} else {
// this is inefficient; we may want to use an enum in the future
let columns = self.get_desktop_browser_card_columns();
let columns =
self.get_desktop_browser_card_columns()
.ok_or(AnkiError::InvalidInput {
info: "Card columns not set.".into(),
})?;
CardRowContext::new(self, id, card_render_required(&columns))?
.browser_row_for_id(&columns)
}
@ -329,23 +360,23 @@ impl<'a> CardRowContext<'a> {
}
impl RowContext for CardRowContext<'_> {
fn get_cell_text(&mut self, column: &str) -> Result<String> {
fn get_cell_text(&mut self, column: &Column) -> Result<String> {
Ok(match column {
"answer" => self.answer_str(),
"cardDue" => self.card_due_str(),
"cardEase" => self.card_ease_str(),
"cardIvl" => self.card_interval_str(),
"cardLapses" => self.card.lapses.to_string(),
"cardMod" => self.card.mtime.date_string(),
"cardReps" => self.card.reps.to_string(),
"deck" => self.deck_str()?,
"note" => self.notetype.name.to_owned(),
"noteCrt" => self.note_creation_str(),
"noteFld" => self.note_field_str(),
"noteMod" => self.note.mtime.date_string(),
"noteTags" => self.note.tags.join(" "),
"question" => self.question_str(),
"template" => self.template_str()?,
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(),
})
}
@ -421,17 +452,17 @@ impl<'a> NoteRowContext<'a> {
}
impl RowContext for NoteRowContext<'_> {
fn get_cell_text(&mut self, column: &str) -> Result<String> {
fn get_cell_text(&mut self, column: &Column) -> Result<String> {
Ok(match column {
"note" => self.notetype.name.to_owned(),
"noteCards" => self.cards.len().to_string(),
"noteCrt" => self.note_creation_str(),
"noteEase" => self.note_ease_str(),
"noteFld" => self.note_field_str(),
"noteLapses" => self.cards.iter().map(|c| c.lapses).sum::<u32>().to_string(),
"noteMod" => self.note.mtime.date_string(),
"noteReps" => self.cards.iter().map(|c| c.reps).sum::<u32>().to_string(),
"noteTags" => self.note.tags.join(" "),
Column::NoteCards => self.cards.len().to_string(),
Column::NoteCreation => self.note_creation_str(),
Column::NoteEase => self.note_ease_str(),
Column::NoteField => self.note_field_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(),
})
}

View File

@ -9,6 +9,7 @@ mod string;
pub(crate) mod undo;
pub use self::{bool::BoolKey, string::StringKey};
use crate::browser_table;
use crate::prelude::*;
use serde::{de::DeserializeOwned, Serialize};
use serde_derive::Deserialize;
@ -65,9 +66,7 @@ pub(crate) enum ConfigKey {
#[strum(to_string = "schedVer")]
SchedulerVersion,
#[strum(to_string = "activeCols")]
DesktopBrowserCardColumns,
#[strum(to_string = "activeNoteCols")]
DesktopBrowserNoteColumns,
}
@ -140,28 +139,26 @@ impl Collection {
self.get_config_default(ConfigKey::BrowserNoteSortKind)
}
pub(crate) fn get_desktop_browser_card_columns(&self) -> Vec<String> {
pub(crate) fn get_desktop_browser_card_columns(&self) -> Option<Vec<browser_table::Column>> {
self.get_config_optional(ConfigKey::DesktopBrowserCardColumns)
.unwrap_or_else(|| {
vec![
"noteFld".to_string(),
"template".to_string(),
"cardDue".to_string(),
"deck".to_string(),
]
})
}
pub(crate) fn get_desktop_browser_note_columns(&self) -> Vec<String> {
pub(crate) fn set_desktop_browser_card_columns(
&mut self,
columns: Vec<browser_table::Column>,
) -> Result<()> {
self.set_config(ConfigKey::DesktopBrowserCardColumns, &columns)
}
pub(crate) fn get_desktop_browser_note_columns(&self) -> Option<Vec<browser_table::Column>> {
self.get_config_optional(ConfigKey::DesktopBrowserNoteColumns)
.unwrap_or_else(|| {
vec![
"noteFld".to_string(),
"note".to_string(),
"noteTags".to_string(),
"noteMod".to_string(),
]
})
}
pub(crate) fn set_desktop_browser_note_columns(
&mut self,
columns: Vec<browser_table::Column>,
) -> Result<()> {
self.set_config(ConfigKey::DesktopBrowserNoteColumns, &columns)
}
pub(crate) fn get_creation_utc_offset(&self) -> Option<i32> {

View File

@ -6,7 +6,7 @@
pub mod adding;
pub mod backend;
mod backend_proto;
pub mod browser_rows;
pub mod browser_table;
pub mod card;
pub mod cloze;
pub mod collection;