expose undoable config changes to frontend; refresh sidebar

The browser header handling still needs updating
This commit is contained in:
Damien Elmes 2021-05-21 17:50:41 +10:00
parent 99b7da49a9
commit 3d4cf26758
24 changed files with 140 additions and 94 deletions

View File

@ -52,3 +52,4 @@ actions-expand-collapse = Expand/Collapse
actions-add-notetype = Add Notetype
actions-remove-notetype = Remove Notetype
actions-update-notetype = Update Notetype
actions-update-config = Update Config

View File

@ -58,6 +58,7 @@ from anki.utils import (
intTime,
splitFields,
stripHTMLMedia,
to_json_bytes,
)
anki.latex.setup_hook()
@ -788,11 +789,11 @@ class Collection:
except KeyError:
return default
def set_config(self, key: str, val: Any) -> None:
self.conf.set(key, val)
def set_config(self, key: str, val: Any) -> OpChanges:
return self._backend.set_config_json(key=key, value_json=to_json_bytes(val))
def remove_config(self, key: str) -> None:
self.conf.remove(key)
def remove_config(self, key: str) -> OpChanges:
return self.conf.remove(key)
def all_config(self) -> Dict[str, Any]:
"This is a debugging aid. Prefer .get_config() when you know the key you need."
@ -801,14 +802,14 @@ class Collection:
def get_config_bool(self, key: Config.Bool.Key.V) -> bool:
return self._backend.get_config_bool(key)
def set_config_bool(self, key: Config.Bool.Key.V, value: bool) -> None:
self._backend.set_config_bool(key=key, value=value)
def set_config_bool(self, key: Config.Bool.Key.V, value: bool) -> OpChanges:
return self._backend.set_config_bool(key=key, value=value)
def get_config_string(self, key: Config.String.Key.V) -> str:
return self._backend.get_config_string(key)
def set_config_string(self, key: Config.String.Key.V, value: str) -> None:
self._backend.set_config_string(key=key, value=value)
def set_config_string(self, key: Config.String.Key.V, value: str) -> OpChanges:
return self._backend.set_config_string(key=key, value=value)
# Stats
##########################################################################

View File

@ -14,6 +14,7 @@ For legacy reasons, the config is also exposed as a dict interface
as col.conf. To support old code that was mutating inner values,
using col.conf["key"] needs to wrap lists and dicts when returning them.
As this is less efficient, please use the col.*_config() API in new code.
The legacy set also does not support the new undo handling.
"""
from __future__ import annotations
@ -25,6 +26,7 @@ from weakref import ref
import anki
from anki._backend import backend_pb2 as _pb
from anki.collection import OpChanges
from anki.errors import NotFoundError
from anki.utils import from_json_bytes, to_json_bytes
@ -42,10 +44,12 @@ class ConfigManager:
raise KeyError from exc
def set(self, key: str, val: Any) -> None:
self.col._backend.set_config_json(key=key, value_json=to_json_bytes(val))
self.col._backend.set_config_json_no_undo(
key=key, value_json=to_json_bytes(val)
)
def remove(self, key: str) -> None:
self.col._backend.remove_config(key)
def remove(self, key: str) -> OpChanges:
return self.col._backend.remove_config(key)
# Legacy dict interface
#########################

View File

@ -115,7 +115,7 @@ class Browser(QMainWindow):
focused = current_top_level_widget() == self
self.table.op_executed(changes, handler, focused)
self.sidebar.op_executed(changes, handler, focused)
if changes.note or changes.notetype:
if changes.editor:
if handler is not self.editor:
# fixme: this will leave the splitter shown, but with no current
# note being edited
@ -129,7 +129,8 @@ class Browser(QMainWindow):
self.editor.set_note(note)
self._renderPreview()
elif changes.card:
if changes.browser_table and changes.card:
self.card = self.table.get_current_card()
def on_focus_change(self, new: Optional[QWidget], old: Optional[QWidget]) -> None:

View File

@ -21,7 +21,7 @@ from aqt.browser.sidebar.toolbar import SidebarTool, SidebarToolbar
from aqt.clayout import CardLayout
from aqt.flags import load_flags
from aqt.models import Models
from aqt.operations import QueryOp
from aqt.operations import CollectionOp, QueryOp
from aqt.operations.deck import (
remove_decks,
rename_deck,
@ -444,7 +444,10 @@ class SidebarTreeView(QTreeView):
type: Optional[SidebarItemType] = None,
) -> SidebarItem:
def update(expanded: bool) -> None:
self.col.set_config_bool(collapse_key, not expanded)
CollectionOp(
self.browser,
lambda col: col.set_config_bool(collapse_key, not expanded),
).run_in_background(initiator=self)
top = SidebarItem(
name,

View File

@ -188,13 +188,14 @@ service SyncService {
service ConfigService {
rpc GetConfigJson(String) returns (Json);
rpc SetConfigJson(SetConfigJsonIn) returns (Empty);
rpc RemoveConfig(String) returns (Empty);
rpc SetConfigJson(SetConfigJsonIn) returns (OpChanges);
rpc SetConfigJsonNoUndo(SetConfigJsonIn) returns (Empty);
rpc RemoveConfig(String) returns (OpChanges);
rpc GetAllConfig(Empty) returns (Json);
rpc GetConfigBool(Config.Bool) returns (Bool);
rpc SetConfigBool(SetConfigBoolIn) returns (Empty);
rpc SetConfigBool(SetConfigBoolIn) returns (OpChanges);
rpc GetConfigString(Config.String) returns (String);
rpc SetConfigString(SetConfigStringIn) returns (Empty);
rpc SetConfigString(SetConfigStringIn) returns (OpChanges);
rpc GetPreferences(Empty) returns (Preferences);
rpc SetPreferences(Preferences) returns (OpChanges);
}

View File

@ -27,7 +27,7 @@ impl Collection {
) -> Result<DeckAndNotetype> {
let deck_id;
let notetype_id;
if self.get_bool(BoolKey::AddingDefaultsToCurrentDeck) {
if self.get_config_bool(BoolKey::AddingDefaultsToCurrentDeck) {
deck_id = self
.get_current_deck_for_adding(home_deck_of_reviewer_card)?
.id;

View File

@ -62,19 +62,24 @@ impl ConfigService for Backend {
})
}
fn set_config_json(&self, input: pb::SetConfigJsonIn) -> Result<pb::Empty> {
fn set_config_json(&self, input: pb::SetConfigJsonIn) -> Result<pb::OpChanges> {
self.with_col(|col| {
col.transact_no_undo(|col| {
// ensure it's a well-formed object
let val: Value = serde_json::from_slice(&input.value_json)?;
col.set_config(input.key.as_str(), &val).map(|_| ())
})
let val: Value = serde_json::from_slice(&input.value_json)?;
col.set_config_json(input.key.as_str(), &val)
})
.map(Into::into)
}
fn remove_config(&self, input: pb::String) -> Result<pb::Empty> {
self.with_col(|col| col.transact_no_undo(|col| col.remove_config(input.val.as_str())))
fn set_config_json_no_undo(&self, input: pb::SetConfigJsonIn) -> Result<pb::Empty> {
self.with_col(|col| {
let val: Value = serde_json::from_slice(&input.value_json)?;
col.transact_no_undo(|col| col.set_config(input.key.as_str(), &val).map(|_| ()))
})
.map(Into::into)
}
fn remove_config(&self, input: pb::String) -> Result<pb::OpChanges> {
self.with_col(|col| col.remove_config(input.val.as_str()))
.map(Into::into)
}
@ -89,31 +94,27 @@ impl ConfigService for Backend {
fn get_config_bool(&self, input: pb::config::Bool) -> Result<pb::Bool> {
self.with_col(|col| {
Ok(pb::Bool {
val: col.get_bool(input.key().into()),
val: col.get_config_bool(input.key().into()),
})
})
}
fn set_config_bool(&self, input: pb::SetConfigBoolIn) -> Result<pb::Empty> {
self.with_col(|col| {
col.transact_no_undo(|col| col.set_bool(input.key().into(), input.value))
})
.map(|_| ().into())
fn set_config_bool(&self, input: pb::SetConfigBoolIn) -> Result<pb::OpChanges> {
self.with_col(|col| col.set_config_bool(input.key().into(), input.value))
.map(Into::into)
}
fn get_config_string(&self, input: pb::config::String) -> Result<pb::String> {
self.with_col(|col| {
Ok(pb::String {
val: col.get_string(input.key().into()),
val: col.get_config_string(input.key().into()),
})
})
}
fn set_config_string(&self, input: pb::SetConfigStringIn) -> Result<pb::Empty> {
self.with_col(|col| {
col.transact_no_undo(|col| col.set_string(input.key().into(), &input.value))
})
.map(|_| ().into())
fn set_config_string(&self, input: pb::SetConfigStringIn) -> Result<pb::OpChanges> {
self.with_col(|col| col.set_config_string(input.key().into(), &input.value))
.map(Into::into)
}
fn get_preferences(&self, _input: pb::Empty) -> Result<pb::Preferences> {

View File

@ -196,7 +196,7 @@ impl Collection {
}
pub fn browser_row_for_id(&mut self, id: i64) -> Result<pb::BrowserRow> {
let notes_mode = self.get_bool(BoolKey::BrowserTableShowNotesMode);
let notes_mode = self.get_config_bool(BoolKey::BrowserTableShowNotesMode);
let columns = Arc::clone(
self.state
.active_browser_columns

View File

@ -48,7 +48,7 @@ pub enum BoolKey {
struct BoolLike(#[serde(deserialize_with = "deserialize_bool_from_anything")] bool);
impl Collection {
pub(crate) fn get_bool(&self, key: BoolKey) -> bool {
pub fn get_config_bool(&self, key: BoolKey) -> bool {
match key {
BoolKey::BrowserSortBackwards => {
// older clients were storing this as an int
@ -70,7 +70,15 @@ impl Collection {
}
}
pub(crate) fn set_bool(&mut self, key: BoolKey, value: bool) -> Result<bool> {
pub fn set_config_bool(&mut self, key: BoolKey, value: bool) -> Result<OpOutput<()>> {
self.transact(Op::UpdateConfig, |col| {
col.set_config(key, &value).map(|_| ())
})
}
}
impl Collection {
pub(crate) fn set_config_bool_inner(&mut self, key: BoolKey, value: bool) -> Result<bool> {
self.set_config(key, &value)
}
}

View File

@ -68,6 +68,17 @@ pub enum SchedulerVersion {
V1 = 1,
V2 = 2,
}
impl Collection {
pub fn set_config_json<T: Serialize>(&mut self, key: &str, val: &T) -> Result<OpOutput<()>> {
self.transact(Op::UpdateConfig, |col| col.set_config(key, val).map(|_| ()))
}
pub fn remove_config(&mut self, key: &str) -> Result<OpOutput<()>> {
self.transact(Op::UpdateConfig, |col| col.remove_config_inner(key))
}
}
impl Collection {
/// Get config item, returning None if missing/invalid.
pub(crate) fn get_config_optional<'a, T, K>(&self, key: K) -> Option<T>
@ -109,7 +120,7 @@ impl Collection {
self.set_config_undoable(entry)
}
pub(crate) fn remove_config<'a, K>(&mut self, key: K) -> Result<()>
pub(crate) fn remove_config_inner<'a, K>(&mut self, key: K) -> Result<()>
where
K: Into<&'a str>,
{
@ -119,7 +130,7 @@ impl Collection {
/// Remove all keys starting with provided prefix, which must end with '_'.
pub(crate) fn remove_config_prefix(&mut self, key: &str) -> Result<()> {
for (key, _val) in self.storage.get_config_prefix(key)? {
self.remove_config(key.as_str())?;
self.remove_config_inner(key.as_str())?;
}
Ok(())
}
@ -134,7 +145,7 @@ impl Collection {
self.set_config(ConfigKey::CreationOffset, &mins)
.map(|_| ())
} else {
self.remove_config(ConfigKey::CreationOffset)
self.remove_config_inner(ConfigKey::CreationOffset)
}
}

View File

@ -13,7 +13,7 @@ pub enum StringKey {
}
impl Collection {
pub(crate) fn get_string(&self, key: StringKey) -> String {
pub fn get_config_string(&self, key: StringKey) -> String {
let default = match key {
StringKey::SetDueBrowser => "0",
StringKey::SetDueReviewer => "1",
@ -23,7 +23,15 @@ impl Collection {
.unwrap_or_else(|| default.to_string())
}
pub(crate) fn set_string(&mut self, key: StringKey, val: &str) -> Result<bool> {
pub fn set_config_string(&mut self, key: StringKey, val: &str) -> Result<OpOutput<()>> {
self.transact(Op::UpdateConfig, |col| {
col.set_config_string_inner(key, val).map(|_| ())
})
}
}
impl Collection {
pub(crate) fn set_config_string_inner(&mut self, key: StringKey, val: &str) -> Result<bool> {
self.set_config(key, &val)
}
}

View File

@ -82,35 +82,35 @@ mod test {
let key = BoolKey::NormalizeNoteText;
// not set by default, but defaults to true
assert_eq!(col.get_bool(key), true);
assert_eq!(col.get_config_bool(key), true);
// first set adds the key
col.transact(op.clone(), |col| col.set_bool(key, false))?;
assert_eq!(col.get_bool(key), false);
col.transact(op.clone(), |col| col.set_config_bool_inner(key, false))?;
assert_eq!(col.get_config_bool(key), false);
// mutate it twice
col.transact(op.clone(), |col| col.set_bool(key, true))?;
assert_eq!(col.get_bool(key), true);
col.transact(op.clone(), |col| col.set_bool(key, false))?;
assert_eq!(col.get_bool(key), false);
col.transact(op.clone(), |col| col.set_config_bool_inner(key, true))?;
assert_eq!(col.get_config_bool(key), true);
col.transact(op.clone(), |col| col.set_config_bool_inner(key, false))?;
assert_eq!(col.get_config_bool(key), false);
// when we remove it, it goes back to its default
col.transact(op, |col| col.remove_config(key))?;
assert_eq!(col.get_bool(key), true);
col.transact(op, |col| col.remove_config_inner(key))?;
assert_eq!(col.get_config_bool(key), true);
// undo the removal
col.undo()?;
assert_eq!(col.get_bool(key), false);
assert_eq!(col.get_config_bool(key), false);
// undo the mutations
col.undo()?;
assert_eq!(col.get_bool(key), true);
assert_eq!(col.get_config_bool(key), true);
col.undo()?;
assert_eq!(col.get_bool(key), false);
assert_eq!(col.get_config_bool(key), false);
// and undo the initial add
col.undo()?;
assert_eq!(col.get_bool(key), true);
assert_eq!(col.get_config_bool(key), true);
Ok(())
}

View File

@ -204,7 +204,7 @@ impl Collection {
F: FnMut(DatabaseCheckProgress, bool),
{
let nids_by_notetype = self.storage.all_note_ids_by_notetype()?;
let norm = self.get_bool(BoolKey::NormalizeNoteText);
let norm = self.get_config_bool(BoolKey::NormalizeNoteText);
let usn = self.usn()?;
let stamp = TimestampMillis::now();

View File

@ -37,7 +37,7 @@ impl Collection {
.storage
.get_collection_timestamps()?
.schema_changed_since_sync(),
v3_scheduler: self.get_bool(BoolKey::Sched2021),
v3_scheduler: self.get_config_bool(BoolKey::Sched2021),
have_addons: false,
})
}

View File

@ -281,7 +281,7 @@ impl Collection {
let days_elapsed = self.timing_for_timestamp(now)?.days_elapsed;
let learn_cutoff = (now.0 as u32) + self.learn_ahead_secs();
let sched_ver = self.scheduler_version();
let v3 = self.get_bool(BoolKey::Sched2021);
let v3 = self.get_config_bool(BoolKey::Sched2021);
let counts = self.due_counts(days_elapsed, learn_cutoff, limit, v3)?;
let dconf = self.storage.get_deck_config_map()?;
add_counts(&mut tree, &counts);

View File

@ -49,7 +49,7 @@ impl Collection {
field_name: Option<String>,
) -> Result<OpOutput<usize>> {
self.transact(Op::FindAndReplace, |col| {
let norm = col.get_bool(BoolKey::NormalizeNoteText);
let norm = col.get_config_bool(BoolKey::NormalizeNoteText);
let search = if norm {
normalize_to_nfc(search_re)
} else {

View File

@ -77,7 +77,7 @@ impl Collection {
.ok_or_else(|| AnkiError::invalid_input("missing note type"))?;
let last_deck = col.get_last_deck_added_to_for_notetype(note.notetype_id);
let ctx = CardGenContext::new(&nt, last_deck, col.usn()?);
let norm = col.get_bool(BoolKey::NormalizeNoteText);
let norm = col.get_config_bool(BoolKey::NormalizeNoteText);
col.add_note_inner(&ctx, note, did, norm)
})
}
@ -387,7 +387,7 @@ impl Collection {
.ok_or_else(|| AnkiError::invalid_input("missing note type"))?;
let last_deck = self.get_last_deck_added_to_for_notetype(note.notetype_id);
let ctx = CardGenContext::new(&nt, last_deck, self.usn()?);
let norm = self.get_bool(BoolKey::NormalizeNoteText);
let norm = self.get_config_bool(BoolKey::NormalizeNoteText);
self.update_note_inner_generating_cards(&ctx, note, &existing_note, true, norm, true)?;
Ok(())
}
@ -475,7 +475,7 @@ impl Collection {
F: FnMut(&mut Note, &Notetype) -> Result<TransformNoteOutput>,
{
let nids_by_notetype = self.storage.note_ids_by_notetype(nids)?;
let norm = self.get_bool(BoolKey::NormalizeNoteText);
let norm = self.get_config_bool(BoolKey::NormalizeNoteText);
let mut changed_notes = 0;
let usn = self.usn()?;
@ -531,7 +531,7 @@ impl Collection {
pub(crate) fn note_is_duplicate_or_empty(&self, note: &Note) -> Result<DuplicateState> {
if let Some(field1) = note.fields.get(0) {
let field1 = if self.get_bool(BoolKey::NormalizeNoteText) {
let field1 = if self.get_config_bool(BoolKey::NormalizeNoteText) {
normalize_to_nfc(field1)
} else {
field1.into()

View File

@ -482,7 +482,7 @@ impl Collection {
original: Option<Notetype>,
usn: Usn,
) -> Result<()> {
let normalize = self.get_bool(BoolKey::NormalizeNoteText);
let normalize = self.get_config_bool(BoolKey::NormalizeNoteText);
notetype.prepare_for_update(original.as_ref())?;
self.ensure_notetype_name_unique(notetype, usn)?;

View File

@ -33,6 +33,7 @@ pub enum Op {
Suspend,
UnburyUnsuspend,
UpdateCard,
UpdateConfig,
UpdateDeck,
UpdateDeckConfig,
UpdateNote,
@ -79,6 +80,7 @@ impl Op {
Op::AddNotetype => tr.actions_add_notetype(),
Op::RemoveNotetype => tr.actions_remove_notetype(),
Op::UpdateNotetype => tr.actions_update_notetype(),
Op::UpdateConfig => tr.actions_update_config(),
Op::Custom(name) => name.into(),
}
.into()
@ -136,13 +138,14 @@ impl OpChanges {
let c = &self.changes;
c.card
|| c.notetype
|| c.config
|| (c.note && self.op != Op::AddNote)
|| (c.deck && self.op != Op::ExpandCollapse)
}
pub fn requires_browser_sidebar_redraw(&self) -> bool {
let c = &self.changes;
c.tag || c.deck || c.notetype
c.tag || c.deck || c.notetype || c.config
}
pub fn requires_editor_redraw(&self) -> bool {

View File

@ -46,7 +46,7 @@ impl Collection {
scheduler_version: match self.scheduler_version() {
crate::config::SchedulerVersion::V1 => 1,
crate::config::SchedulerVersion::V2 => {
if self.get_bool(BoolKey::Sched2021) {
if self.get_config_bool(BoolKey::Sched2021) {
3
} else {
2
@ -61,14 +61,14 @@ impl Collection {
crate::config::NewReviewMix::NewFirst => NewRevMixPB::NewFirst,
} as i32,
new_timezone: self.get_creation_utc_offset().is_some(),
day_learn_first: self.get_bool(BoolKey::ShowDayLearningCardsFirst),
day_learn_first: self.get_config_bool(BoolKey::ShowDayLearningCardsFirst),
})
}
pub(crate) fn set_scheduling_preferences(&mut self, settings: Scheduling) -> Result<()> {
let s = settings;
self.set_bool(BoolKey::ShowDayLearningCardsFirst, s.day_learn_first)?;
self.set_config_bool_inner(BoolKey::ShowDayLearningCardsFirst, s.day_learn_first)?;
self.set_learn_ahead_secs(s.learn_ahead_secs)?;
self.set_new_review_mix(match s.new_review_mix() {
@ -96,26 +96,28 @@ impl Collection {
pub fn get_reviewing_preferences(&self) -> Result<Reviewing> {
Ok(Reviewing {
hide_audio_play_buttons: self.get_bool(BoolKey::HideAudioPlayButtons),
interrupt_audio_when_answering: self.get_bool(BoolKey::InterruptAudioWhenAnswering),
show_remaining_due_counts: self.get_bool(BoolKey::ShowRemainingDueCountsInStudy),
show_intervals_on_buttons: self.get_bool(BoolKey::ShowIntervalsAboveAnswerButtons),
hide_audio_play_buttons: self.get_config_bool(BoolKey::HideAudioPlayButtons),
interrupt_audio_when_answering: self
.get_config_bool(BoolKey::InterruptAudioWhenAnswering),
show_remaining_due_counts: self.get_config_bool(BoolKey::ShowRemainingDueCountsInStudy),
show_intervals_on_buttons: self
.get_config_bool(BoolKey::ShowIntervalsAboveAnswerButtons),
time_limit_secs: self.get_answer_time_limit_secs(),
})
}
pub(crate) fn set_reviewing_preferences(&mut self, settings: Reviewing) -> Result<()> {
let s = settings;
self.set_bool(BoolKey::HideAudioPlayButtons, s.hide_audio_play_buttons)?;
self.set_bool(
self.set_config_bool_inner(BoolKey::HideAudioPlayButtons, s.hide_audio_play_buttons)?;
self.set_config_bool_inner(
BoolKey::InterruptAudioWhenAnswering,
s.interrupt_audio_when_answering,
)?;
self.set_bool(
self.set_config_bool_inner(
BoolKey::ShowRemainingDueCountsInStudy,
s.show_remaining_due_counts,
)?;
self.set_bool(
self.set_config_bool_inner(
BoolKey::ShowIntervalsAboveAnswerButtons,
s.show_intervals_on_buttons,
)?;
@ -125,20 +127,21 @@ impl Collection {
pub fn get_editing_preferences(&self) -> Result<Editing> {
Ok(Editing {
adding_defaults_to_current_deck: self.get_bool(BoolKey::AddingDefaultsToCurrentDeck),
paste_images_as_png: self.get_bool(BoolKey::PasteImagesAsPng),
paste_strips_formatting: self.get_bool(BoolKey::PasteStripsFormatting),
adding_defaults_to_current_deck: self
.get_config_bool(BoolKey::AddingDefaultsToCurrentDeck),
paste_images_as_png: self.get_config_bool(BoolKey::PasteImagesAsPng),
paste_strips_formatting: self.get_config_bool(BoolKey::PasteStripsFormatting),
})
}
pub(crate) fn set_editing_preferences(&mut self, settings: Editing) -> Result<()> {
let s = settings;
self.set_bool(
self.set_config_bool_inner(
BoolKey::AddingDefaultsToCurrentDeck,
s.adding_defaults_to_current_deck,
)?;
self.set_bool(BoolKey::PasteImagesAsPng, s.paste_images_as_png)?;
self.set_bool(BoolKey::PasteStripsFormatting, s.paste_strips_formatting)?;
self.set_config_bool_inner(BoolKey::PasteImagesAsPng, s.paste_images_as_png)?;
self.set_config_bool_inner(BoolKey::PasteStripsFormatting, s.paste_strips_formatting)?;
Ok(())
}
}

View File

@ -111,7 +111,7 @@ impl Collection {
}
col.storage.clear_searched_cards_table()?;
if let Some(key) = context {
col.set_string(key, days)?;
col.set_config_string_inner(key, days)?;
}
Ok(())
})

View File

@ -33,7 +33,7 @@ pub(crate) struct SqlWriter<'a> {
impl SqlWriter<'_> {
pub(crate) fn new(col: &mut Collection, item_type: ReturnItemType) -> SqlWriter<'_> {
let normalize_note_text = col.get_bool(BoolKey::NormalizeNoteText);
let normalize_note_text = col.get_config_bool(BoolKey::NormalizeNoteText);
let sql = String::new();
let args = vec![];
SqlWriter {

View File

@ -56,9 +56,10 @@ impl Collection {
pub(crate) fn get_graph_preferences(&self) -> pb::GraphPreferences {
pb::GraphPreferences {
calendar_first_day_of_week: self.get_first_day_of_week() as i32,
card_counts_separate_inactive: self.get_bool(BoolKey::CardCountsSeparateInactive),
card_counts_separate_inactive: self
.get_config_bool(BoolKey::CardCountsSeparateInactive),
browser_links_supported: true,
future_due_show_backlog: self.get_bool(BoolKey::FutureDueShowBacklog),
future_due_show_backlog: self.get_config_bool(BoolKey::FutureDueShowBacklog),
}
}
@ -69,11 +70,11 @@ impl Collection {
6 => Weekday::Saturday,
_ => Weekday::Sunday,
})?;
self.set_bool(
self.set_config_bool_inner(
BoolKey::CardCountsSeparateInactive,
prefs.card_counts_separate_inactive,
)?;
self.set_bool(BoolKey::FutureDueShowBacklog, prefs.future_due_show_backlog)?;
self.set_config_bool_inner(BoolKey::FutureDueShowBacklog, prefs.future_due_show_backlog)?;
Ok(())
}
}