mirror of
https://github.com/ankitects/anki.git
synced 2025-09-23 08:22:24 -04:00
remember last input for 'set due'; add string config; nest config types
This commit is contained in:
parent
b56580a8c0
commit
f434cff36f
12 changed files with 124 additions and 48 deletions
|
@ -8,7 +8,8 @@ license = "AGPL-3.0-or-later"
|
||||||
members = ["rslib", "pylib/rsbridge"]
|
members = ["rslib", "pylib/rsbridge"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "dummy"
|
# dummy top level for tooling
|
||||||
|
name = "anki"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[package.metadata.raze]
|
[package.metadata.raze]
|
||||||
|
|
|
@ -50,7 +50,7 @@ MediaSyncProgress = _pb.MediaSyncProgress
|
||||||
FullSyncProgress = _pb.FullSyncProgress
|
FullSyncProgress = _pb.FullSyncProgress
|
||||||
NormalSyncProgress = _pb.NormalSyncProgress
|
NormalSyncProgress = _pb.NormalSyncProgress
|
||||||
DatabaseCheckProgress = _pb.DatabaseCheckProgress
|
DatabaseCheckProgress = _pb.DatabaseCheckProgress
|
||||||
ConfigBool = _pb.ConfigBool
|
Config = _pb.Config
|
||||||
EmptyCardsReport = _pb.EmptyCardsReport
|
EmptyCardsReport = _pb.EmptyCardsReport
|
||||||
NoteWithEmptyCards = _pb.NoteWithEmptyCards
|
NoteWithEmptyCards = _pb.NoteWithEmptyCards
|
||||||
GraphPreferences = _pb.GraphPreferences
|
GraphPreferences = _pb.GraphPreferences
|
||||||
|
@ -586,13 +586,20 @@ 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: ConfigBool.Key.V) -> bool:
|
def get_config_bool(self, key: Config.Bool.Key.V) -> bool:
|
||||||
return self._backend.get_config_bool(key)
|
return self._backend.get_config_bool(key)
|
||||||
|
|
||||||
def set_config_bool(self, key: ConfigBool.Key.V, value: bool) -> None:
|
def set_config_bool(self, key: Config.Bool.Key.V, value: bool) -> None:
|
||||||
self.setMod()
|
self.setMod()
|
||||||
self._backend.set_config_bool(key=key, value=value)
|
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.setMod()
|
||||||
|
self._backend.set_config_string(key=key, value=value)
|
||||||
|
|
||||||
# Stats
|
# Stats
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from anki.collection import BuiltinSort, ConfigBool
|
from anki.collection import BuiltinSort, Config
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from tests.shared import getEmptyCol, isNearCutoff
|
from tests.shared import getEmptyCol, isNearCutoff
|
||||||
|
|
||||||
|
@ -121,7 +121,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.set_config_bool(ConfigBool.BROWSER_SORT_BACKWARDS, True)
|
col.set_config_bool(Config.Bool.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 (
|
||||||
|
|
|
@ -5,7 +5,9 @@ ignore = forms,hooks_gen.py
|
||||||
|
|
||||||
[TYPECHECK]
|
[TYPECHECK]
|
||||||
ignored-modules=win32file,pywintypes,socket,win32pipe,winrt,pyaudio
|
ignored-modules=win32file,pywintypes,socket,win32pipe,winrt,pyaudio
|
||||||
ignored-classes=SearchTerm,ConfigBool
|
ignored-classes=
|
||||||
|
SearchTerm,
|
||||||
|
Config,
|
||||||
|
|
||||||
[REPORTS]
|
[REPORTS]
|
||||||
output-format=colorized
|
output-format=colorized
|
||||||
|
|
|
@ -13,7 +13,7 @@ from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union,
|
||||||
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, ConfigBool, SearchTerm
|
from anki.collection import Collection, Config, SearchTerm
|
||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.errors import InvalidInput
|
from anki.errors import InvalidInput
|
||||||
from anki.lang import without_unicode_isolation
|
from anki.lang import without_unicode_isolation
|
||||||
|
@ -852,13 +852,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.set_config_bool(ConfigBool.BROWSER_SORT_BACKWARDS, ord)
|
self.col.set_config_bool(Config.Bool.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.get_config_bool(ConfigBool.BROWSER_SORT_BACKWARDS) != ord:
|
if self.col.get_config_bool(Config.Bool.BROWSER_SORT_BACKWARDS) != ord:
|
||||||
self.col.set_config_bool(ConfigBool.BROWSER_SORT_BACKWARDS, ord)
|
self.col.set_config_bool(Config.Bool.BROWSER_SORT_BACKWARDS, ord)
|
||||||
self.col.setMod()
|
self.col.setMod()
|
||||||
self.col.save()
|
self.col.save()
|
||||||
self.model.reverse()
|
self.model.reverse()
|
||||||
|
@ -871,7 +871,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.get_config_bool(ConfigBool.BROWSER_SORT_BACKWARDS):
|
if self.col.get_config_bool(Config.Bool.BROWSER_SORT_BACKWARDS):
|
||||||
ord = Qt.DescendingOrder
|
ord = Qt.DescendingOrder
|
||||||
else:
|
else:
|
||||||
ord = Qt.AscendingOrder
|
ord = Qt.AscendingOrder
|
||||||
|
@ -1399,7 +1399,7 @@ where id in %s"""
|
||||||
mw=self.mw,
|
mw=self.mw,
|
||||||
parent=self,
|
parent=self,
|
||||||
card_ids=self.selectedCards(),
|
card_ids=self.selectedCards(),
|
||||||
default="0",
|
default_key=Config.String.SET_DUE_BROWSER,
|
||||||
on_done=self._after_schedule,
|
on_done=self._after_schedule,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,7 +7,7 @@ import time
|
||||||
from typing import Any, Callable, Optional, Tuple, Union
|
from typing import Any, Callable, Optional, Tuple, Union
|
||||||
|
|
||||||
from anki.cards import Card
|
from anki.cards import Card
|
||||||
from anki.collection import ConfigBool
|
from anki.collection import Config
|
||||||
from aqt import AnkiQt, gui_hooks
|
from aqt import AnkiQt, gui_hooks
|
||||||
from aqt.qt import (
|
from aqt.qt import (
|
||||||
QAbstractItemView,
|
QAbstractItemView,
|
||||||
|
@ -94,7 +94,7 @@ class Previewer(QDialog):
|
||||||
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.get_config_bool(
|
self._show_both_sides = self.mw.col.get_config_bool(
|
||||||
ConfigBool.PREVIEW_BOTH_SIDES
|
Config.Bool.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)
|
||||||
|
@ -221,7 +221,7 @@ class Previewer(QDialog):
|
||||||
|
|
||||||
def _on_show_both_sides(self, toggle: bool) -> None:
|
def _on_show_both_sides(self, toggle: bool) -> None:
|
||||||
self._show_both_sides = toggle
|
self._show_both_sides = toggle
|
||||||
self.mw.col.set_config_bool(ConfigBool.PREVIEW_BOTH_SIDES, toggle)
|
self.mw.col.set_config_bool(Config.Bool.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"
|
||||||
|
|
|
@ -14,6 +14,7 @@ from PyQt5.QtCore import Qt
|
||||||
|
|
||||||
from anki import hooks
|
from anki import hooks
|
||||||
from anki.cards import Card
|
from anki.cards import Card
|
||||||
|
from anki.collection import Config
|
||||||
from anki.utils import stripHTML
|
from anki.utils import stripHTML
|
||||||
from aqt import AnkiQt, gui_hooks
|
from aqt import AnkiQt, gui_hooks
|
||||||
from aqt.profiles import VideoDriver
|
from aqt.profiles import VideoDriver
|
||||||
|
@ -809,7 +810,7 @@ time = %(time)d;
|
||||||
mw=self.mw,
|
mw=self.mw,
|
||||||
parent=self.mw,
|
parent=self.mw,
|
||||||
card_ids=[self.card.id],
|
card_ids=[self.card.id],
|
||||||
default="1",
|
default_key=Config.String.SET_DUE_REVIEWER,
|
||||||
on_done=self.mw.reset,
|
on_done=self.mw.reset,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ from concurrent.futures import Future
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
|
from anki.collection import Config
|
||||||
from anki.errors import InvalidInput
|
from anki.errors import InvalidInput
|
||||||
from anki.lang import TR
|
from anki.lang import TR
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
|
@ -18,12 +19,14 @@ def set_due_date_dialog(
|
||||||
mw: aqt.AnkiQt,
|
mw: aqt.AnkiQt,
|
||||||
parent: QDialog,
|
parent: QDialog,
|
||||||
card_ids: List[int],
|
card_ids: List[int],
|
||||||
default: str,
|
default_key: Config.String.Key.V,
|
||||||
on_done: Callable[[], None],
|
on_done: Callable[[], None],
|
||||||
) -> None:
|
) -> None:
|
||||||
if not card_ids:
|
if not card_ids:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
default = mw.col.get_config_string(default_key)
|
||||||
|
|
||||||
(days, success) = getText(
|
(days, success) = getText(
|
||||||
prompt=tr(TR.SCHEDULING_SET_DUE_DATE_PROMPT, cards=len(card_ids)),
|
prompt=tr(TR.SCHEDULING_SET_DUE_DATE_PROMPT, cards=len(card_ids)),
|
||||||
parent=parent,
|
parent=parent,
|
||||||
|
@ -33,7 +36,12 @@ def set_due_date_dialog(
|
||||||
if not success or not days.strip():
|
if not success or not days.strip():
|
||||||
return
|
return
|
||||||
|
|
||||||
def on_done_wrapper(fut: Future) -> None:
|
def set_due() -> None:
|
||||||
|
mw.col.sched.set_due_date(card_ids, days)
|
||||||
|
if days != default:
|
||||||
|
mw.col.set_config_string(default_key, days)
|
||||||
|
|
||||||
|
def after_set(fut: Future) -> None:
|
||||||
try:
|
try:
|
||||||
fut.result()
|
fut.result()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -53,9 +61,7 @@ def set_due_date_dialog(
|
||||||
on_done()
|
on_done()
|
||||||
|
|
||||||
mw.checkpoint(tr(TR.ACTIONS_SET_DUE_DATE))
|
mw.checkpoint(tr(TR.ACTIONS_SET_DUE_DATE))
|
||||||
mw.taskman.with_progress(
|
mw.taskman.with_progress(set_due, after_set)
|
||||||
lambda: mw.col.sched.set_due_date(card_ids, days), on_done_wrapper
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def forget_cards(
|
def forget_cards(
|
||||||
|
|
|
@ -9,7 +9,7 @@ from enum import Enum, auto
|
||||||
from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, cast
|
from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, cast
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.collection import ConfigBool, SearchTerm
|
from anki.collection import Config, SearchTerm
|
||||||
from anki.decks import DeckTreeNode
|
from anki.decks import DeckTreeNode
|
||||||
from anki.errors import DeckRenameError, InvalidInput
|
from anki.errors import DeckRenameError, InvalidInput
|
||||||
from anki.tags import TagTreeNode
|
from anki.tags import TagTreeNode
|
||||||
|
@ -526,7 +526,7 @@ class SidebarTreeView(QTreeView):
|
||||||
root: SidebarItem,
|
root: SidebarItem,
|
||||||
name: TR.V,
|
name: TR.V,
|
||||||
icon: Union[str, ColoredIcon],
|
icon: Union[str, ColoredIcon],
|
||||||
collapse_key: ConfigBool.Key.V,
|
collapse_key: Config.Bool.Key.V,
|
||||||
type: Optional[SidebarItemType] = None,
|
type: Optional[SidebarItemType] = None,
|
||||||
) -> SidebarItem:
|
) -> SidebarItem:
|
||||||
def update(expanded: bool) -> None:
|
def update(expanded: bool) -> None:
|
||||||
|
@ -557,7 +557,7 @@ class SidebarTreeView(QTreeView):
|
||||||
root=root,
|
root=root,
|
||||||
name=TR.BROWSING_SIDEBAR_SAVED_SEARCHES,
|
name=TR.BROWSING_SIDEBAR_SAVED_SEARCHES,
|
||||||
icon=icon,
|
icon=icon,
|
||||||
collapse_key=ConfigBool.COLLAPSE_SAVED_SEARCHES,
|
collapse_key=Config.Bool.COLLAPSE_SAVED_SEARCHES,
|
||||||
type=SidebarItemType.SAVED_SEARCH_ROOT,
|
type=SidebarItemType.SAVED_SEARCH_ROOT,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -584,7 +584,7 @@ class SidebarTreeView(QTreeView):
|
||||||
root=root,
|
root=root,
|
||||||
name=TR.BROWSING_SIDEBAR_RECENT,
|
name=TR.BROWSING_SIDEBAR_RECENT,
|
||||||
icon=icon,
|
icon=icon,
|
||||||
collapse_key=ConfigBool.COLLAPSE_RECENT,
|
collapse_key=Config.Bool.COLLAPSE_RECENT,
|
||||||
type=SidebarItemType.FLAG_ROOT,
|
type=SidebarItemType.FLAG_ROOT,
|
||||||
)
|
)
|
||||||
type = SidebarItemType.FLAG
|
type = SidebarItemType.FLAG
|
||||||
|
@ -646,7 +646,7 @@ class SidebarTreeView(QTreeView):
|
||||||
root=root,
|
root=root,
|
||||||
name=TR.BROWSING_SIDEBAR_CARD_STATE,
|
name=TR.BROWSING_SIDEBAR_CARD_STATE,
|
||||||
icon=icon,
|
icon=icon,
|
||||||
collapse_key=ConfigBool.COLLAPSE_CARD_STATE,
|
collapse_key=Config.Bool.COLLAPSE_CARD_STATE,
|
||||||
type=SidebarItemType.CARD_STATE_ROOT,
|
type=SidebarItemType.CARD_STATE_ROOT,
|
||||||
)
|
)
|
||||||
type = SidebarItemType.CARD_STATE
|
type = SidebarItemType.CARD_STATE
|
||||||
|
@ -693,7 +693,7 @@ class SidebarTreeView(QTreeView):
|
||||||
root=root,
|
root=root,
|
||||||
name=TR.BROWSING_SIDEBAR_FLAGS,
|
name=TR.BROWSING_SIDEBAR_FLAGS,
|
||||||
icon=icon,
|
icon=icon,
|
||||||
collapse_key=ConfigBool.COLLAPSE_FLAGS,
|
collapse_key=Config.Bool.COLLAPSE_FLAGS,
|
||||||
type=SidebarItemType.FLAG_ROOT,
|
type=SidebarItemType.FLAG_ROOT,
|
||||||
)
|
)
|
||||||
type = SidebarItemType.FLAG
|
type = SidebarItemType.FLAG
|
||||||
|
@ -771,7 +771,7 @@ class SidebarTreeView(QTreeView):
|
||||||
root=root,
|
root=root,
|
||||||
name=TR.BROWSING_SIDEBAR_TAGS,
|
name=TR.BROWSING_SIDEBAR_TAGS,
|
||||||
icon=icon,
|
icon=icon,
|
||||||
collapse_key=ConfigBool.COLLAPSE_TAGS,
|
collapse_key=Config.Bool.COLLAPSE_TAGS,
|
||||||
type=SidebarItemType.TAG_ROOT,
|
type=SidebarItemType.TAG_ROOT,
|
||||||
)
|
)
|
||||||
render(root, tree.children)
|
render(root, tree.children)
|
||||||
|
@ -810,7 +810,7 @@ class SidebarTreeView(QTreeView):
|
||||||
root=root,
|
root=root,
|
||||||
name=TR.BROWSING_SIDEBAR_DECKS,
|
name=TR.BROWSING_SIDEBAR_DECKS,
|
||||||
icon=icon,
|
icon=icon,
|
||||||
collapse_key=ConfigBool.COLLAPSE_DECKS,
|
collapse_key=Config.Bool.COLLAPSE_DECKS,
|
||||||
type=SidebarItemType.DECK_ROOT,
|
type=SidebarItemType.DECK_ROOT,
|
||||||
)
|
)
|
||||||
render(root, tree.children)
|
render(root, tree.children)
|
||||||
|
@ -824,7 +824,7 @@ class SidebarTreeView(QTreeView):
|
||||||
root=root,
|
root=root,
|
||||||
name=TR.BROWSING_SIDEBAR_NOTETYPES,
|
name=TR.BROWSING_SIDEBAR_NOTETYPES,
|
||||||
icon=icon,
|
icon=icon,
|
||||||
collapse_key=ConfigBool.COLLAPSE_NOTETYPES,
|
collapse_key=Config.Bool.COLLAPSE_NOTETYPES,
|
||||||
type=SidebarItemType.NOTETYPE_ROOT,
|
type=SidebarItemType.NOTETYPE_ROOT,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -228,8 +228,10 @@ 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 GetConfigBool(Config.Bool) returns (Bool);
|
||||||
rpc SetConfigBool(SetConfigBoolIn) returns (Empty);
|
rpc SetConfigBool(SetConfigBoolIn) returns (Empty);
|
||||||
|
rpc GetConfigString(Config.String) returns (String);
|
||||||
|
rpc SetConfigString(SetConfigStringIn) returns (Empty);
|
||||||
|
|
||||||
// preferences
|
// preferences
|
||||||
|
|
||||||
|
@ -1216,7 +1218,8 @@ message SetDeckIn {
|
||||||
int64 deck_id = 2;
|
int64 deck_id = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ConfigBool {
|
message Config {
|
||||||
|
message Bool {
|
||||||
enum Key {
|
enum Key {
|
||||||
BROWSER_SORT_BACKWARDS = 0;
|
BROWSER_SORT_BACKWARDS = 0;
|
||||||
PREVIEW_BOTH_SIDES = 1;
|
PREVIEW_BOTH_SIDES = 1;
|
||||||
|
@ -1229,9 +1232,23 @@ message ConfigBool {
|
||||||
COLLAPSE_FLAGS = 8;
|
COLLAPSE_FLAGS = 8;
|
||||||
}
|
}
|
||||||
Key key = 1;
|
Key key = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message String {
|
||||||
|
enum Key {
|
||||||
|
SET_DUE_BROWSER = 0;
|
||||||
|
SET_DUE_REVIEWER = 1;
|
||||||
|
}
|
||||||
|
Key key = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetConfigBoolIn {
|
message SetConfigBoolIn {
|
||||||
ConfigBool.Key key = 1;
|
Config.Bool.Key key = 1;
|
||||||
bool value = 2;
|
bool value = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message SetConfigStringIn {
|
||||||
|
Config.String.Key key = 1;
|
||||||
|
string value = 2;
|
||||||
|
}
|
||||||
|
|
|
@ -1493,7 +1493,7 @@ impl BackendService for Backend {
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_config_bool(&self, input: pb::ConfigBool) -> BackendResult<pb::Bool> {
|
fn get_config_bool(&self, input: pb::config::Bool) -> BackendResult<pb::Bool> {
|
||||||
self.with_col(|col| {
|
self.with_col(|col| {
|
||||||
Ok(pb::Bool {
|
Ok(pb::Bool {
|
||||||
val: col.get_bool(input),
|
val: col.get_bool(input),
|
||||||
|
@ -1505,6 +1505,19 @@ impl BackendService for Backend {
|
||||||
self.with_col(|col| col.transact(None, |col| col.set_bool(input)))
|
self.with_col(|col| col.transact(None, |col| col.set_bool(input)))
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_config_string(&self, input: pb::config::String) -> BackendResult<pb::String> {
|
||||||
|
self.with_col(|col| {
|
||||||
|
Ok(pb::String {
|
||||||
|
val: col.get_string(input),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_config_string(&self, input: pb::SetConfigStringIn) -> BackendResult<pb::Empty> {
|
||||||
|
self.with_col(|col| col.transact(None, |col| col.set_string(input)))
|
||||||
|
.map(Into::into)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
|
|
|
@ -5,7 +5,8 @@ use crate::{
|
||||||
backend_proto as pb, 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 pb::config::bool::Key as BoolKey;
|
||||||
|
use pb::config::string::Key as StringKey;
|
||||||
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;
|
||||||
|
@ -63,6 +64,8 @@ pub(crate) enum ConfigKey {
|
||||||
PreviewBothSides,
|
PreviewBothSides,
|
||||||
Rollover,
|
Rollover,
|
||||||
SchedulerVersion,
|
SchedulerVersion,
|
||||||
|
SetDueBrowser,
|
||||||
|
SetDueReviewer,
|
||||||
ShowDayLearningCardsFirst,
|
ShowDayLearningCardsFirst,
|
||||||
ShowIntervalsAboveAnswerButtons,
|
ShowIntervalsAboveAnswerButtons,
|
||||||
ShowRemainingDueCountsInStudy,
|
ShowRemainingDueCountsInStudy,
|
||||||
|
@ -102,6 +105,8 @@ impl From<ConfigKey> for &'static str {
|
||||||
ConfigKey::PreviewBothSides => "previewBothSides",
|
ConfigKey::PreviewBothSides => "previewBothSides",
|
||||||
ConfigKey::Rollover => "rollover",
|
ConfigKey::Rollover => "rollover",
|
||||||
ConfigKey::SchedulerVersion => "schedVer",
|
ConfigKey::SchedulerVersion => "schedVer",
|
||||||
|
ConfigKey::SetDueBrowser => "setDueBrowser",
|
||||||
|
ConfigKey::SetDueReviewer => "setDueReviewer",
|
||||||
ConfigKey::ShowDayLearningCardsFirst => "dayLearnFirst",
|
ConfigKey::ShowDayLearningCardsFirst => "dayLearnFirst",
|
||||||
ConfigKey::ShowIntervalsAboveAnswerButtons => "estTimes",
|
ConfigKey::ShowIntervalsAboveAnswerButtons => "estTimes",
|
||||||
ConfigKey::ShowRemainingDueCountsInStudy => "dueCounts",
|
ConfigKey::ShowRemainingDueCountsInStudy => "dueCounts",
|
||||||
|
@ -125,6 +130,15 @@ impl From<BoolKey> for ConfigKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<StringKey> for ConfigKey {
|
||||||
|
fn from(key: StringKey) -> Self {
|
||||||
|
match key {
|
||||||
|
StringKey::SetDueBrowser => ConfigKey::SetDueBrowser,
|
||||||
|
StringKey::SetDueReviewer => ConfigKey::SetDueReviewer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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)]
|
||||||
|
@ -345,7 +359,7 @@ impl Collection {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::match_single_binding)]
|
#[allow(clippy::match_single_binding)]
|
||||||
pub(crate) fn get_bool(&self, config: pb::ConfigBool) -> bool {
|
pub(crate) fn get_bool(&self, config: pb::config::Bool) -> bool {
|
||||||
match config.key() {
|
match config.key() {
|
||||||
// all options default to false at the moment
|
// all options default to false at the moment
|
||||||
other => self.get_config_default(ConfigKey::from(other)),
|
other => self.get_config_default(ConfigKey::from(other)),
|
||||||
|
@ -355,6 +369,21 @@ impl Collection {
|
||||||
pub(crate) fn set_bool(&self, input: pb::SetConfigBoolIn) -> Result<()> {
|
pub(crate) fn set_bool(&self, input: pb::SetConfigBoolIn) -> Result<()> {
|
||||||
self.set_config(ConfigKey::from(input.key()), &input.value)
|
self.set_config(ConfigKey::from(input.key()), &input.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_string(&self, config: pb::config::String) -> String {
|
||||||
|
let key = config.key();
|
||||||
|
let default = match key {
|
||||||
|
StringKey::SetDueBrowser => "0",
|
||||||
|
StringKey::SetDueReviewer => "1",
|
||||||
|
// other => "",
|
||||||
|
};
|
||||||
|
self.get_config_optional(ConfigKey::from(key))
|
||||||
|
.unwrap_or_else(|| default.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_string(&self, input: pb::SetConfigStringIn) -> 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