mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 06:22:22 -04:00
add getter/setter for boolean config values
This commit is contained in:
parent
a9be60c8b4
commit
5ff7944a26
8 changed files with 80 additions and 10 deletions
|
@ -12,6 +12,7 @@ import traceback
|
||||||
import weakref
|
import weakref
|
||||||
from typing import TYPE_CHECKING, Any, List, Optional, Sequence, Tuple, Union
|
from typing import TYPE_CHECKING, Any, List, Optional, Sequence, Tuple, Union
|
||||||
|
|
||||||
|
import anki.backend_pb2 as pb
|
||||||
import anki.find
|
import anki.find
|
||||||
import anki.latex # sets up hook
|
import anki.latex # sets up hook
|
||||||
import anki.template
|
import anki.template
|
||||||
|
@ -32,16 +33,19 @@ from anki.rsbackend import (
|
||||||
Progress,
|
Progress,
|
||||||
RustBackend,
|
RustBackend,
|
||||||
from_json_bytes,
|
from_json_bytes,
|
||||||
pb,
|
|
||||||
)
|
)
|
||||||
from anki.sched import Scheduler as V1Scheduler
|
from anki.sched import Scheduler as V1Scheduler
|
||||||
from anki.schedv2 import Scheduler as V2Scheduler
|
from anki.schedv2 import Scheduler as V2Scheduler
|
||||||
from anki.tags import TagManager
|
from anki.tags import TagManager
|
||||||
from anki.utils import devMode, ids2str, intTime
|
from anki.utils import devMode, ids2str, intTime
|
||||||
|
|
||||||
|
ConfigBoolKey = pb.ConfigBool.Key # pylint: disable=no-member
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from anki.rsbackend import FormatTimeSpanContextValue, TRValue
|
from anki.rsbackend import FormatTimeSpanContextValue, TRValue
|
||||||
|
|
||||||
|
ConfigBoolKeyValue = pb.ConfigBool.KeyValue # pylint: disable=no-member
|
||||||
|
|
||||||
|
|
||||||
class Collection:
|
class Collection:
|
||||||
sched: Union[V1Scheduler, V2Scheduler]
|
sched: Union[V1Scheduler, V2Scheduler]
|
||||||
|
@ -496,6 +500,13 @@ class Collection:
|
||||||
"This is a debugging aid. Prefer .get_config() when you know the key you need."
|
"This is a debugging aid. Prefer .get_config() when you know the key you need."
|
||||||
return from_json_bytes(self.backend.get_all_config())
|
return from_json_bytes(self.backend.get_all_config())
|
||||||
|
|
||||||
|
def get_config_bool(self, key: ConfigBoolKeyValue) -> bool:
|
||||||
|
return self.backend.get_config_bool(key)
|
||||||
|
|
||||||
|
def set_config_bool(self, key: ConfigBoolKeyValue, value: bool) -> None:
|
||||||
|
self.setMod()
|
||||||
|
self.backend.set_config_bool(key=key, value=value)
|
||||||
|
|
||||||
# Stats
|
# Stats
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,9 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
assert anki._rsbridge.buildhash() == anki.buildinfo.buildhash
|
assert anki._rsbridge.buildhash() == anki.buildinfo.buildhash
|
||||||
|
|
||||||
|
# FIXME: rather than adding new items here, items intended to be consumed
|
||||||
|
# by external libraries (eg aqt) should be exported in the module that
|
||||||
|
# refers to them, eg collection.py
|
||||||
SchedTimingToday = pb.SchedTimingTodayOut
|
SchedTimingToday = pb.SchedTimingTodayOut
|
||||||
BuiltinSortKind = pb.BuiltinSearchOrder.BuiltinSortKind
|
BuiltinSortKind = pb.BuiltinSearchOrder.BuiltinSortKind
|
||||||
BackendCard = pb.Card
|
BackendCard = pb.Card
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from anki.collection import ConfigBoolKey
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.rsbackend import BuiltinSortKind
|
from anki.rsbackend import BuiltinSortKind
|
||||||
from tests.shared import getEmptyCol, isNearCutoff
|
from tests.shared import getEmptyCol, isNearCutoff
|
||||||
|
@ -121,7 +122,7 @@ def test_findCards():
|
||||||
col.flush()
|
col.flush()
|
||||||
assert col.findCards("", order=True)[-1] in latestCardIds
|
assert col.findCards("", order=True)[-1] in latestCardIds
|
||||||
assert col.findCards("", order=True)[0] == firstCardId
|
assert col.findCards("", order=True)[0] == firstCardId
|
||||||
col.conf["sortBackwards"] = True
|
col.set_config_bool(ConfigBoolKey.BROWSER_SORT_BACKWARDS, True)
|
||||||
col.flush()
|
col.flush()
|
||||||
assert col.findCards("", order=True)[0] in latestCardIds
|
assert col.findCards("", order=True)[0] in latestCardIds
|
||||||
assert (
|
assert (
|
||||||
|
|
|
@ -13,7 +13,7 @@ from typing import List, Optional, Sequence, Tuple, cast
|
||||||
import aqt
|
import aqt
|
||||||
import aqt.forms
|
import aqt.forms
|
||||||
from anki.cards import Card
|
from anki.cards import Card
|
||||||
from anki.collection import Collection
|
from anki.collection import Collection, ConfigBoolKey
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.lang import without_unicode_isolation
|
from anki.lang import without_unicode_isolation
|
||||||
from anki.models import NoteType
|
from anki.models import NoteType
|
||||||
|
@ -827,13 +827,13 @@ QTableView {{ gridline-color: {grid} }}
|
||||||
# default to descending for non-text fields
|
# default to descending for non-text fields
|
||||||
if type == "noteFld":
|
if type == "noteFld":
|
||||||
ord = not ord
|
ord = not ord
|
||||||
self.col.conf["sortBackwards"] = ord
|
self.col.set_config_bool(ConfigBoolKey.BROWSER_SORT_BACKWARDS, ord)
|
||||||
self.col.setMod()
|
self.col.setMod()
|
||||||
self.col.save()
|
self.col.save()
|
||||||
self.search()
|
self.search()
|
||||||
else:
|
else:
|
||||||
if self.col.conf["sortBackwards"] != ord:
|
if self.col.get_config_bool(ConfigBoolKey.BROWSER_SORT_BACKWARDS) != ord:
|
||||||
self.col.conf["sortBackwards"] = ord
|
self.col.set_config_bool(ConfigBoolKey.BROWSER_SORT_BACKWARDS, ord)
|
||||||
self.col.setMod()
|
self.col.setMod()
|
||||||
self.col.save()
|
self.col.save()
|
||||||
self.model.reverse()
|
self.model.reverse()
|
||||||
|
@ -846,7 +846,7 @@ QTableView {{ gridline-color: {grid} }}
|
||||||
hh.setSortIndicatorShown(False)
|
hh.setSortIndicatorShown(False)
|
||||||
return
|
return
|
||||||
idx = self.model.activeCols.index(type)
|
idx = self.model.activeCols.index(type)
|
||||||
if self.col.conf["sortBackwards"]:
|
if self.col.get_config_bool(ConfigBoolKey.BROWSER_SORT_BACKWARDS):
|
||||||
ord = Qt.DescendingOrder
|
ord = Qt.DescendingOrder
|
||||||
else:
|
else:
|
||||||
ord = Qt.AscendingOrder
|
ord = Qt.AscendingOrder
|
||||||
|
|
|
@ -7,6 +7,7 @@ import time
|
||||||
from typing import Any, Callable, Optional, Union
|
from typing import Any, Callable, Optional, Union
|
||||||
|
|
||||||
from anki.cards import Card
|
from anki.cards import Card
|
||||||
|
from anki.collection import ConfigBoolKey
|
||||||
from aqt import AnkiQt, gui_hooks
|
from aqt import AnkiQt, gui_hooks
|
||||||
from aqt.qt import (
|
from aqt.qt import (
|
||||||
QAbstractItemView,
|
QAbstractItemView,
|
||||||
|
@ -87,7 +88,9 @@ class Previewer(QDialog):
|
||||||
both_sides_button.setShortcut(QKeySequence("B"))
|
both_sides_button.setShortcut(QKeySequence("B"))
|
||||||
both_sides_button.setToolTip(tr(TR.ACTIONS_SHORTCUT_KEY, val="B"))
|
both_sides_button.setToolTip(tr(TR.ACTIONS_SHORTCUT_KEY, val="B"))
|
||||||
self.bbox.addButton(both_sides_button, QDialogButtonBox.ActionRole)
|
self.bbox.addButton(both_sides_button, QDialogButtonBox.ActionRole)
|
||||||
self._show_both_sides = self.mw.col.conf.get("previewBothSides", False)
|
self._show_both_sides = self.mw.col.get_config_bool(
|
||||||
|
ConfigBoolKey.PREVIEW_BOTH_SIDES
|
||||||
|
)
|
||||||
both_sides_button.setChecked(self._show_both_sides)
|
both_sides_button.setChecked(self._show_both_sides)
|
||||||
qconnect(both_sides_button.toggled, self._on_show_both_sides)
|
qconnect(both_sides_button.toggled, self._on_show_both_sides)
|
||||||
|
|
||||||
|
@ -213,7 +216,7 @@ class Previewer(QDialog):
|
||||||
|
|
||||||
def _on_show_both_sides(self, toggle):
|
def _on_show_both_sides(self, toggle):
|
||||||
self._show_both_sides = toggle
|
self._show_both_sides = toggle
|
||||||
self.mw.col.conf["previewBothSides"] = toggle
|
self.mw.col.set_config_bool(ConfigBoolKey.PREVIEW_BOTH_SIDES, toggle)
|
||||||
self.mw.col.setMod()
|
self.mw.col.setMod()
|
||||||
if self._state == "answer" and not toggle:
|
if self._state == "answer" and not toggle:
|
||||||
self._state = "question"
|
self._state = "question"
|
||||||
|
|
|
@ -220,6 +220,8 @@ service BackendService {
|
||||||
rpc SetConfigJson(SetConfigJsonIn) returns (Empty);
|
rpc SetConfigJson(SetConfigJsonIn) returns (Empty);
|
||||||
rpc RemoveConfig(String) returns (Empty);
|
rpc RemoveConfig(String) returns (Empty);
|
||||||
rpc GetAllConfig(Empty) returns (Json);
|
rpc GetAllConfig(Empty) returns (Json);
|
||||||
|
rpc GetConfigBool(ConfigBool) returns (Bool);
|
||||||
|
rpc SetConfigBool(SetConfigBoolIn) returns (Empty);
|
||||||
|
|
||||||
// preferences
|
// preferences
|
||||||
|
|
||||||
|
@ -1186,3 +1188,16 @@ message SetDeckIn {
|
||||||
repeated int64 card_ids = 1;
|
repeated int64 card_ids = 1;
|
||||||
int64 deck_id = 2;
|
int64 deck_id = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ConfigBool {
|
||||||
|
enum Key {
|
||||||
|
BROWSER_SORT_BACKWARDS = 0;
|
||||||
|
PREVIEW_BOTH_SIDES = 1;
|
||||||
|
}
|
||||||
|
Key key = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SetConfigBoolIn {
|
||||||
|
ConfigBool.Key key = 1;
|
||||||
|
bool value = 2;
|
||||||
|
}
|
||||||
|
|
|
@ -1429,6 +1429,19 @@ impl BackendService for Backend {
|
||||||
self.with_col(|col| col.transact(None, |col| col.set_preferences(input)))
|
self.with_col(|col| col.transact(None, |col| col.set_preferences(input)))
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_config_bool(&self, input: pb::ConfigBool) -> BackendResult<pb::Bool> {
|
||||||
|
self.with_col(|col| {
|
||||||
|
Ok(pb::Bool {
|
||||||
|
val: col.get_bool(input),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_config_bool(&self, input: pb::SetConfigBoolIn) -> BackendResult<pb::Empty> {
|
||||||
|
self.with_col(|col| col.transact(None, |col| col.set_bool(input)))
|
||||||
|
.map(Into::into)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
collection::Collection, decks::DeckID, err::Result, notetype::NoteTypeID,
|
backend_proto as pb, collection::Collection, decks::DeckID, err::Result, notetype::NoteTypeID,
|
||||||
timestamp::TimestampSecs,
|
timestamp::TimestampSecs,
|
||||||
};
|
};
|
||||||
|
use pb::config_bool::Key as BoolKey;
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
use serde_aux::field_attributes::deserialize_bool_from_anything;
|
use serde_aux::field_attributes::deserialize_bool_from_anything;
|
||||||
use serde_derive::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
|
@ -52,6 +53,7 @@ pub(crate) enum ConfigKey {
|
||||||
NewReviewMix,
|
NewReviewMix,
|
||||||
NextNewCardPosition,
|
NextNewCardPosition,
|
||||||
NormalizeNoteText,
|
NormalizeNoteText,
|
||||||
|
PreviewBothSides,
|
||||||
Rollover,
|
Rollover,
|
||||||
SchedulerVersion,
|
SchedulerVersion,
|
||||||
ShowDayLearningCardsFirst,
|
ShowDayLearningCardsFirst,
|
||||||
|
@ -83,6 +85,7 @@ impl From<ConfigKey> for &'static str {
|
||||||
ConfigKey::NewReviewMix => "newSpread",
|
ConfigKey::NewReviewMix => "newSpread",
|
||||||
ConfigKey::NextNewCardPosition => "nextPos",
|
ConfigKey::NextNewCardPosition => "nextPos",
|
||||||
ConfigKey::NormalizeNoteText => "normalize_note_text",
|
ConfigKey::NormalizeNoteText => "normalize_note_text",
|
||||||
|
ConfigKey::PreviewBothSides => "previewBothSides",
|
||||||
ConfigKey::Rollover => "rollover",
|
ConfigKey::Rollover => "rollover",
|
||||||
ConfigKey::SchedulerVersion => "schedVer",
|
ConfigKey::SchedulerVersion => "schedVer",
|
||||||
ConfigKey::ShowDayLearningCardsFirst => "dayLearnFirst",
|
ConfigKey::ShowDayLearningCardsFirst => "dayLearnFirst",
|
||||||
|
@ -92,6 +95,15 @@ impl From<ConfigKey> for &'static str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<BoolKey> for ConfigKey {
|
||||||
|
fn from(key: BoolKey) -> Self {
|
||||||
|
match key {
|
||||||
|
BoolKey::BrowserSortBackwards => ConfigKey::BrowserSortReverse,
|
||||||
|
BoolKey::PreviewBothSides => ConfigKey::PreviewBothSides,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This is a workaround for old clients that used ints to represent boolean
|
/// This is a workaround for old clients that used ints to represent boolean
|
||||||
/// values. For new config items, prefer using a bool directly.
|
/// values. For new config items, prefer using a bool directly.
|
||||||
#[derive(Deserialize, Default)]
|
#[derive(Deserialize, Default)]
|
||||||
|
@ -310,6 +322,18 @@ impl Collection {
|
||||||
pub(crate) fn set_last_unburied_day(&self, day: u32) -> Result<()> {
|
pub(crate) fn set_last_unburied_day(&self, day: u32) -> Result<()> {
|
||||||
self.set_config(ConfigKey::LastUnburiedDay, &day)
|
self.set_config(ConfigKey::LastUnburiedDay, &day)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::match_single_binding)]
|
||||||
|
pub(crate) fn get_bool(&self, config: pb::ConfigBool) -> bool {
|
||||||
|
match config.key() {
|
||||||
|
// all options default to false at the moment
|
||||||
|
other => self.get_config_default(ConfigKey::from(other)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_bool(&self, input: pb::SetConfigBoolIn) -> Result<()> {
|
||||||
|
self.set_config(ConfigKey::from(input.key()), &input.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, PartialEq, Debug, Clone, Copy)]
|
#[derive(Deserialize, PartialEq, Debug, Clone, Copy)]
|
||||||
|
|
Loading…
Reference in a new issue