2021-01-31 21:50:21 +01:00
|
|
|
// Copyright: Ankitects Pty Ltd and contributors
|
|
|
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
2019-12-24 04:33:44 +01:00
|
|
|
syntax = "proto3";
|
|
|
|
|
2020-06-17 07:27:08 +02:00
|
|
|
package BackendProto;
|
2019-12-24 04:33:44 +01:00
|
|
|
|
2020-05-22 13:25:25 +02:00
|
|
|
// Generic containers
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
2019-12-24 04:33:44 +01:00
|
|
|
message Empty {}
|
|
|
|
|
2020-03-22 05:15:02 +01:00
|
|
|
message OptionalInt32 {
|
2021-01-09 06:50:24 +01:00
|
|
|
sint32 val = 1;
|
2020-03-22 05:15:02 +01:00
|
|
|
}
|
|
|
|
|
2020-04-14 01:32:28 +02:00
|
|
|
message OptionalUInt32 {
|
2021-01-09 06:50:24 +01:00
|
|
|
uint32 val = 1;
|
2020-04-14 01:32:28 +02:00
|
|
|
}
|
|
|
|
|
2020-05-22 13:25:25 +02:00
|
|
|
message Int32 {
|
2021-01-09 06:50:24 +01:00
|
|
|
sint32 val = 1;
|
2020-05-22 13:25:25 +02:00
|
|
|
}
|
|
|
|
|
2020-05-23 08:19:48 +02:00
|
|
|
message UInt32 {
|
2021-01-09 06:50:24 +01:00
|
|
|
uint32 val = 1;
|
2020-05-23 08:19:48 +02:00
|
|
|
}
|
|
|
|
|
2020-05-22 13:25:25 +02:00
|
|
|
message Int64 {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 val = 1;
|
2020-05-22 13:25:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
message String {
|
2021-01-09 06:50:24 +01:00
|
|
|
string val = 1;
|
2020-05-22 13:25:25 +02:00
|
|
|
}
|
|
|
|
|
2020-05-23 08:56:05 +02:00
|
|
|
message Json {
|
2021-01-09 06:50:24 +01:00
|
|
|
bytes json = 1;
|
2020-05-23 04:58:13 +02:00
|
|
|
}
|
|
|
|
|
2020-05-23 07:09:16 +02:00
|
|
|
message Bool {
|
2021-01-09 06:50:24 +01:00
|
|
|
bool val = 1;
|
2020-05-23 07:09:16 +02:00
|
|
|
}
|
|
|
|
|
2021-02-02 09:32:07 +01:00
|
|
|
message StringList {
|
|
|
|
repeated string vals = 1;
|
|
|
|
}
|
|
|
|
|
undoable ops now return changes directly; add new *_ops.py files
- Introduced a new transact() method that wraps the return value
in a separate struct that describes the changes that were made.
- Changes are now gathered from the undo log, so we don't need to
guess at what was changed - eg if update_note() is called with identical
note contents, no changes are returned. Card changes will only be set
if cards were actually generated by the update_note() call, and tag
will only be set if a new tag was added.
- mw.perform_op() has been updated to expect the op to return the changes,
or a structure with the changes in it, and it will use them to fire the
change hook, instead of fetching the changes from undo_status(), so there
is no risk of race conditions.
- the various calls to mw.perform_op() have been split into separate
files like card_ops.py. Aside from making the code cleaner, this works
around a rather annoying issue with mypy. Because we run it with
no_strict_optional, mypy is happy to accept an operation that returns None,
despite the type signature saying it requires changes to be returned.
Turning no_strict_optional on for the whole codebase is not practical
at the moment, but we can enable it for individual files.
Still todo:
- The cursor keeps moving back to the start of a field when typing -
we need to ignore the refresh hook when we are the initiator.
- The busy cursor icon should probably be delayed a few hundreds ms.
- Still need to think about a nicer way of handling saveNow()
- op_made_changes(), op_affects_study_queue() might be better embedded
as properties in the object instead
2021-03-16 05:26:42 +01:00
|
|
|
message OpChangesWithCount {
|
|
|
|
uint32 count = 1;
|
|
|
|
OpChanges changes = 2;
|
|
|
|
}
|
|
|
|
|
2021-03-27 12:38:20 +01:00
|
|
|
message OpChangesWithId {
|
2021-03-22 14:17:07 +01:00
|
|
|
int64 id = 1;
|
|
|
|
OpChanges changes = 2;
|
|
|
|
}
|
|
|
|
|
2020-05-23 08:56:05 +02:00
|
|
|
// IDs used in RPC calls
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
2021-03-27 13:03:19 +01:00
|
|
|
message NotetypeId {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 ntid = 1;
|
2020-05-23 08:19:48 +02:00
|
|
|
}
|
|
|
|
|
2021-03-27 12:38:20 +01:00
|
|
|
message NoteId {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 nid = 1;
|
2020-05-23 08:19:48 +02:00
|
|
|
}
|
|
|
|
|
2021-03-27 12:38:20 +01:00
|
|
|
message CardId {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 cid = 1;
|
2020-05-23 08:19:48 +02:00
|
|
|
}
|
|
|
|
|
2021-03-27 12:38:20 +01:00
|
|
|
message CardIds {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated int64 cids = 1;
|
2020-08-29 14:02:22 +02:00
|
|
|
}
|
|
|
|
|
2021-03-27 12:38:20 +01:00
|
|
|
message DeckId {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 did = 1;
|
2020-05-23 08:56:05 +02:00
|
|
|
}
|
|
|
|
|
2021-03-27 12:38:20 +01:00
|
|
|
message DeckIds {
|
2021-02-26 19:52:02 +01:00
|
|
|
repeated int64 dids = 1;
|
|
|
|
}
|
|
|
|
|
2021-03-27 12:38:20 +01:00
|
|
|
message DeckConfigId {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 dcid = 1;
|
2020-05-23 08:56:05 +02:00
|
|
|
}
|
2020-05-23 08:19:48 +02:00
|
|
|
|
2021-03-11 05:33:57 +01:00
|
|
|
// Backend methods
|
2020-05-22 13:25:25 +02:00
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
2021-03-11 05:33:57 +01:00
|
|
|
/// while the protobuf descriptors expose the order services are defined in,
|
|
|
|
/// that information is not available in prost, so we define an enum to make
|
2021-03-11 07:53:36 +01:00
|
|
|
/// sure all clients agree on the service index
|
2021-03-11 05:33:57 +01:00
|
|
|
enum ServiceIndex {
|
|
|
|
SERVICE_INDEX_SCHEDULING = 0;
|
2021-03-11 06:47:31 +01:00
|
|
|
SERVICE_INDEX_DECKS = 1;
|
|
|
|
SERVICE_INDEX_NOTES = 2;
|
|
|
|
SERVICE_INDEX_SYNC = 3;
|
2021-03-27 13:03:19 +01:00
|
|
|
SERVICE_INDEX_NOTETYPES = 4;
|
2021-03-11 06:47:31 +01:00
|
|
|
SERVICE_INDEX_CONFIG = 5;
|
2021-03-11 07:05:06 +01:00
|
|
|
SERVICE_INDEX_CARD_RENDERING = 6;
|
|
|
|
SERVICE_INDEX_DECK_CONFIG = 7;
|
|
|
|
SERVICE_INDEX_TAGS = 8;
|
2021-03-11 07:16:40 +01:00
|
|
|
SERVICE_INDEX_SEARCH = 9;
|
|
|
|
SERVICE_INDEX_STATS = 10;
|
|
|
|
SERVICE_INDEX_MEDIA = 11;
|
2021-03-11 07:53:36 +01:00
|
|
|
SERVICE_INDEX_I18N = 12;
|
|
|
|
SERVICE_INDEX_COLLECTION = 13;
|
|
|
|
SERVICE_INDEX_CARDS = 14;
|
2021-03-11 05:33:57 +01:00
|
|
|
}
|
2021-01-09 15:48:34 +01:00
|
|
|
|
2021-03-11 05:33:57 +01:00
|
|
|
service SchedulingService {
|
2021-01-09 15:48:34 +01:00
|
|
|
rpc SchedTimingToday(Empty) returns (SchedTimingTodayOut);
|
|
|
|
rpc StudiedToday(Empty) returns (String);
|
|
|
|
rpc StudiedTodayMessage(StudiedTodayMessageIn) returns (String);
|
|
|
|
rpc UpdateStats(UpdateStatsIn) returns (Empty);
|
|
|
|
rpc ExtendLimits(ExtendLimitsIn) returns (Empty);
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc CountsForDeckToday(DeckId) returns (CountsForDeckTodayOut);
|
2021-01-09 15:48:34 +01:00
|
|
|
rpc CongratsInfo(Empty) returns (CongratsInfoOut);
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc RestoreBuriedAndSuspendedCards(CardIds) returns (OpChanges);
|
2021-04-30 12:03:20 +02:00
|
|
|
rpc UnburyDeck(UnburyDeckIn) returns (OpChanges);
|
2021-04-06 08:38:42 +02:00
|
|
|
rpc BuryOrSuspendCards(BuryOrSuspendCardsIn) returns (OpChangesWithCount);
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc EmptyFilteredDeck(DeckId) returns (OpChanges);
|
|
|
|
rpc RebuildFilteredDeck(DeckId) returns (OpChangesWithCount);
|
undoable ops now return changes directly; add new *_ops.py files
- Introduced a new transact() method that wraps the return value
in a separate struct that describes the changes that were made.
- Changes are now gathered from the undo log, so we don't need to
guess at what was changed - eg if update_note() is called with identical
note contents, no changes are returned. Card changes will only be set
if cards were actually generated by the update_note() call, and tag
will only be set if a new tag was added.
- mw.perform_op() has been updated to expect the op to return the changes,
or a structure with the changes in it, and it will use them to fire the
change hook, instead of fetching the changes from undo_status(), so there
is no risk of race conditions.
- the various calls to mw.perform_op() have been split into separate
files like card_ops.py. Aside from making the code cleaner, this works
around a rather annoying issue with mypy. Because we run it with
no_strict_optional, mypy is happy to accept an operation that returns None,
despite the type signature saying it requires changes to be returned.
Turning no_strict_optional on for the whole codebase is not practical
at the moment, but we can enable it for individual files.
Still todo:
- The cursor keeps moving back to the start of a field when typing -
we need to ignore the refresh hook when we are the initiator.
- The busy cursor icon should probably be delayed a few hundreds ms.
- Still need to think about a nicer way of handling saveNow()
- op_made_changes(), op_affects_study_queue() might be better embedded
as properties in the object instead
2021-03-16 05:26:42 +01:00
|
|
|
rpc ScheduleCardsAsNew(ScheduleCardsAsNewIn) returns (OpChanges);
|
|
|
|
rpc SetDueDate(SetDueDateIn) returns (OpChanges);
|
2021-03-18 02:46:11 +01:00
|
|
|
rpc SortCards(SortCardsIn) returns (OpChangesWithCount);
|
|
|
|
rpc SortDeck(SortDeckIn) returns (OpChangesWithCount);
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc GetNextCardStates(CardId) returns (NextCardStates);
|
2021-02-20 05:13:03 +01:00
|
|
|
rpc DescribeNextStates(NextCardStates) returns (StringList);
|
2021-02-23 03:44:26 +01:00
|
|
|
rpc StateIsLeech(SchedulingState) returns (Bool);
|
2021-05-11 03:37:08 +02:00
|
|
|
rpc AnswerCard(CardAnswer) returns (OpChanges);
|
2021-02-21 06:50:41 +01:00
|
|
|
rpc UpgradeScheduler(Empty) returns (Empty);
|
2021-05-26 04:59:45 +02:00
|
|
|
rpc GetQueuedCards(GetQueuedCardsIn) returns (QueuedCards);
|
2021-03-11 05:33:57 +01:00
|
|
|
}
|
2021-01-09 15:48:34 +01:00
|
|
|
|
2021-03-11 06:47:31 +01:00
|
|
|
service DecksService {
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc AddDeckLegacy(Json) returns (OpChangesWithId);
|
|
|
|
rpc AddOrUpdateDeckLegacy(AddOrUpdateDeckLegacyIn) returns (DeckId);
|
2021-01-09 15:48:34 +01:00
|
|
|
rpc DeckTree(DeckTreeIn) returns (DeckTreeNode);
|
|
|
|
rpc DeckTreeLegacy(Empty) returns (Json);
|
|
|
|
rpc GetAllDecksLegacy(Empty) returns (Json);
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc GetDeckIdByName(String) returns (DeckId);
|
2021-04-03 16:15:25 +02:00
|
|
|
rpc GetDeck(DeckId) returns (Deck);
|
2021-04-05 02:21:50 +02:00
|
|
|
rpc UpdateDeck(Deck) returns (OpChanges);
|
|
|
|
rpc SetDeckCollapsed(SetDeckCollapsedIn) returns (OpChanges);
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc GetDeckLegacy(DeckId) returns (Json);
|
2021-01-09 15:48:34 +01:00
|
|
|
rpc GetDeckNames(GetDeckNamesIn) returns (DeckNames);
|
|
|
|
rpc NewDeckLegacy(Bool) returns (Json);
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc RemoveDecks(DeckIds) returns (OpChangesWithCount);
|
2021-03-22 09:23:56 +01:00
|
|
|
rpc ReparentDecks(ReparentDecksIn) returns (OpChangesWithCount);
|
undoable ops now return changes directly; add new *_ops.py files
- Introduced a new transact() method that wraps the return value
in a separate struct that describes the changes that were made.
- Changes are now gathered from the undo log, so we don't need to
guess at what was changed - eg if update_note() is called with identical
note contents, no changes are returned. Card changes will only be set
if cards were actually generated by the update_note() call, and tag
will only be set if a new tag was added.
- mw.perform_op() has been updated to expect the op to return the changes,
or a structure with the changes in it, and it will use them to fire the
change hook, instead of fetching the changes from undo_status(), so there
is no risk of race conditions.
- the various calls to mw.perform_op() have been split into separate
files like card_ops.py. Aside from making the code cleaner, this works
around a rather annoying issue with mypy. Because we run it with
no_strict_optional, mypy is happy to accept an operation that returns None,
despite the type signature saying it requires changes to be returned.
Turning no_strict_optional on for the whole codebase is not practical
at the moment, but we can enable it for individual files.
Still todo:
- The cursor keeps moving back to the start of a field when typing -
we need to ignore the refresh hook when we are the initiator.
- The busy cursor icon should probably be delayed a few hundreds ms.
- Still need to think about a nicer way of handling saveNow()
- op_made_changes(), op_affects_study_queue() might be better embedded
as properties in the object instead
2021-03-16 05:26:42 +01:00
|
|
|
rpc RenameDeck(RenameDeckIn) returns (OpChanges);
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc GetOrCreateFilteredDeck(DeckId) returns (FilteredDeckForUpdate);
|
|
|
|
rpc AddOrUpdateFilteredDeck(FilteredDeckForUpdate) returns (OpChangesWithId);
|
2021-04-01 15:50:16 +02:00
|
|
|
rpc FilteredDeckOrderLabels(Empty) returns (StringList);
|
2021-04-06 13:37:31 +02:00
|
|
|
rpc SetCurrentDeck(DeckId) returns (OpChanges);
|
|
|
|
rpc GetCurrentDeck(Empty) returns (Deck);
|
2021-03-11 06:47:31 +01:00
|
|
|
}
|
2021-01-09 15:48:34 +01:00
|
|
|
|
2021-03-11 06:47:31 +01:00
|
|
|
service NotesService {
|
2021-03-27 13:03:19 +01:00
|
|
|
rpc NewNote(NotetypeId) returns (Note);
|
undoable ops now return changes directly; add new *_ops.py files
- Introduced a new transact() method that wraps the return value
in a separate struct that describes the changes that were made.
- Changes are now gathered from the undo log, so we don't need to
guess at what was changed - eg if update_note() is called with identical
note contents, no changes are returned. Card changes will only be set
if cards were actually generated by the update_note() call, and tag
will only be set if a new tag was added.
- mw.perform_op() has been updated to expect the op to return the changes,
or a structure with the changes in it, and it will use them to fire the
change hook, instead of fetching the changes from undo_status(), so there
is no risk of race conditions.
- the various calls to mw.perform_op() have been split into separate
files like card_ops.py. Aside from making the code cleaner, this works
around a rather annoying issue with mypy. Because we run it with
no_strict_optional, mypy is happy to accept an operation that returns None,
despite the type signature saying it requires changes to be returned.
Turning no_strict_optional on for the whole codebase is not practical
at the moment, but we can enable it for individual files.
Still todo:
- The cursor keeps moving back to the start of a field when typing -
we need to ignore the refresh hook when we are the initiator.
- The busy cursor icon should probably be delayed a few hundreds ms.
- Still need to think about a nicer way of handling saveNow()
- op_made_changes(), op_affects_study_queue() might be better embedded
as properties in the object instead
2021-03-16 05:26:42 +01:00
|
|
|
rpc AddNote(AddNoteIn) returns (AddNoteOut);
|
Simplify note adding and the deck/notetype choosers
The existing code was really difficult to reason about:
- The default notetype depended on the selected deck, and vice versa,
and this logic was buried in the deck and notetype choosing screens,
and models.py.
- Changes to the notetype were not passed back directly, but were fired
via a hook, which changed any screen in the app that had a notetype
selector.
It also wasn't great for performance, as the most recent deck and tags
were embedded in the notetype, which can be expensive to save and sync
for large notetypes.
To address these points:
- The current deck for a notetype, and notetype for a deck, are now
stored in separate config variables, instead of directly in the deck
or notetype. These are cheap to read and write, and we'll be able to
sync them individually in the future once config syncing is updated in
the future. I seem to recall some users not wanting the tag saving
behaviour, so I've dropped that for now, but if people end up missing
it, it would be simple to add as an extra auxiliary config variable.
- The logic for getting the starting deck and notetype has been moved
into the backend. It should be the same as the older Python code, with
one exception: when "change deck depending on notetype" is enabled in
the preferences, it will start with the current notetype ("curModel"),
instead of first trying to get a deck-specific notetype.
- ModelChooser has been duplicated into notetypechooser.py, and it
has been updated to solely be concerned with keeping track of a selected
notetype - it no longer alters global state.
2021-03-08 14:23:24 +01:00
|
|
|
rpc DefaultsForAdding(DefaultsForAddingIn) returns (DeckAndNotetype);
|
2021-03-27 13:03:19 +01:00
|
|
|
rpc DefaultDeckForNotetype(NotetypeId) returns (DeckId);
|
undoable ops now return changes directly; add new *_ops.py files
- Introduced a new transact() method that wraps the return value
in a separate struct that describes the changes that were made.
- Changes are now gathered from the undo log, so we don't need to
guess at what was changed - eg if update_note() is called with identical
note contents, no changes are returned. Card changes will only be set
if cards were actually generated by the update_note() call, and tag
will only be set if a new tag was added.
- mw.perform_op() has been updated to expect the op to return the changes,
or a structure with the changes in it, and it will use them to fire the
change hook, instead of fetching the changes from undo_status(), so there
is no risk of race conditions.
- the various calls to mw.perform_op() have been split into separate
files like card_ops.py. Aside from making the code cleaner, this works
around a rather annoying issue with mypy. Because we run it with
no_strict_optional, mypy is happy to accept an operation that returns None,
despite the type signature saying it requires changes to be returned.
Turning no_strict_optional on for the whole codebase is not practical
at the moment, but we can enable it for individual files.
Still todo:
- The cursor keeps moving back to the start of a field when typing -
we need to ignore the refresh hook when we are the initiator.
- The busy cursor icon should probably be delayed a few hundreds ms.
- Still need to think about a nicer way of handling saveNow()
- op_made_changes(), op_affects_study_queue() might be better embedded
as properties in the object instead
2021-03-16 05:26:42 +01:00
|
|
|
rpc UpdateNote(UpdateNoteIn) returns (OpChanges);
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc GetNote(NoteId) returns (Note);
|
2021-04-06 06:56:36 +02:00
|
|
|
rpc RemoveNotes(RemoveNotesIn) returns (OpChangesWithCount);
|
2021-01-09 15:48:34 +01:00
|
|
|
rpc ClozeNumbersInNote(Note) returns (ClozeNumbersInNoteOut);
|
2021-04-29 06:07:16 +02:00
|
|
|
rpc AfterNoteUpdates(AfterNoteUpdatesIn) returns (OpChangesWithCount);
|
2021-01-09 15:48:34 +01:00
|
|
|
rpc FieldNamesForNotes(FieldNamesForNotesIn) returns (FieldNamesForNotesOut);
|
|
|
|
rpc NoteIsDuplicateOrEmpty(Note) returns (NoteIsDuplicateOrEmptyOut);
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc CardsOfNote(NoteId) returns (CardIds);
|
2021-03-11 06:47:31 +01:00
|
|
|
}
|
2021-01-09 15:48:34 +01:00
|
|
|
|
2021-03-11 06:47:31 +01:00
|
|
|
service SyncService {
|
2021-01-09 15:48:34 +01:00
|
|
|
rpc SyncMedia(SyncAuth) returns (Empty);
|
|
|
|
rpc AbortSync(Empty) returns (Empty);
|
|
|
|
rpc AbortMediaSync(Empty) returns (Empty);
|
|
|
|
rpc BeforeUpload(Empty) returns (Empty);
|
|
|
|
rpc SyncLogin(SyncLoginIn) returns (SyncAuth);
|
|
|
|
rpc SyncStatus(SyncAuth) returns (SyncStatusOut);
|
|
|
|
rpc SyncCollection(SyncAuth) returns (SyncCollectionOut);
|
|
|
|
rpc FullUpload(SyncAuth) returns (Empty);
|
|
|
|
rpc FullDownload(SyncAuth) returns (Empty);
|
2021-01-11 05:11:18 +01:00
|
|
|
rpc SyncServerMethod(SyncServerMethodIn) returns (Json);
|
2021-03-11 06:47:31 +01:00
|
|
|
}
|
2021-01-09 15:48:34 +01:00
|
|
|
|
2021-03-11 06:47:31 +01:00
|
|
|
service ConfigService {
|
|
|
|
rpc GetConfigJson(String) returns (Json);
|
2021-05-21 09:50:41 +02:00
|
|
|
rpc SetConfigJson(SetConfigJsonIn) returns (OpChanges);
|
|
|
|
rpc SetConfigJsonNoUndo(SetConfigJsonIn) returns (Empty);
|
|
|
|
rpc RemoveConfig(String) returns (OpChanges);
|
2021-03-11 06:47:31 +01:00
|
|
|
rpc GetAllConfig(Empty) returns (Json);
|
|
|
|
rpc GetConfigBool(Config.Bool) returns (Bool);
|
2021-05-21 09:50:41 +02:00
|
|
|
rpc SetConfigBool(SetConfigBoolIn) returns (OpChanges);
|
2021-03-11 06:47:31 +01:00
|
|
|
rpc GetConfigString(Config.String) returns (String);
|
2021-05-21 09:50:41 +02:00
|
|
|
rpc SetConfigString(SetConfigStringIn) returns (OpChanges);
|
2021-03-11 06:47:31 +01:00
|
|
|
rpc GetPreferences(Empty) returns (Preferences);
|
undoable ops now return changes directly; add new *_ops.py files
- Introduced a new transact() method that wraps the return value
in a separate struct that describes the changes that were made.
- Changes are now gathered from the undo log, so we don't need to
guess at what was changed - eg if update_note() is called with identical
note contents, no changes are returned. Card changes will only be set
if cards were actually generated by the update_note() call, and tag
will only be set if a new tag was added.
- mw.perform_op() has been updated to expect the op to return the changes,
or a structure with the changes in it, and it will use them to fire the
change hook, instead of fetching the changes from undo_status(), so there
is no risk of race conditions.
- the various calls to mw.perform_op() have been split into separate
files like card_ops.py. Aside from making the code cleaner, this works
around a rather annoying issue with mypy. Because we run it with
no_strict_optional, mypy is happy to accept an operation that returns None,
despite the type signature saying it requires changes to be returned.
Turning no_strict_optional on for the whole codebase is not practical
at the moment, but we can enable it for individual files.
Still todo:
- The cursor keeps moving back to the start of a field when typing -
we need to ignore the refresh hook when we are the initiator.
- The busy cursor icon should probably be delayed a few hundreds ms.
- Still need to think about a nicer way of handling saveNow()
- op_made_changes(), op_affects_study_queue() might be better embedded
as properties in the object instead
2021-03-16 05:26:42 +01:00
|
|
|
rpc SetPreferences(Preferences) returns (OpChanges);
|
2021-03-11 06:47:31 +01:00
|
|
|
}
|
2021-01-09 15:48:34 +01:00
|
|
|
|
2021-03-27 13:03:19 +01:00
|
|
|
service NotetypesService {
|
2021-04-29 15:28:42 +02:00
|
|
|
rpc AddNotetype(Notetype) returns (OpChangesWithId);
|
|
|
|
rpc UpdateNotetype(Notetype) returns (OpChanges);
|
2021-04-30 07:16:44 +02:00
|
|
|
rpc AddNotetypeLegacy(Json) returns (OpChangesWithId);
|
|
|
|
rpc UpdateNotetypeLegacy(Json) returns (OpChanges);
|
2021-03-27 13:03:19 +01:00
|
|
|
rpc AddOrUpdateNotetype(AddOrUpdateNotetypeIn) returns (NotetypeId);
|
|
|
|
rpc GetStockNotetypeLegacy(StockNotetype) returns (Json);
|
2021-04-04 12:45:37 +02:00
|
|
|
rpc GetNotetype(NotetypeId) returns (Notetype);
|
2021-03-27 13:03:19 +01:00
|
|
|
rpc GetNotetypeLegacy(NotetypeId) returns (Json);
|
|
|
|
rpc GetNotetypeNames(Empty) returns (NotetypeNames);
|
|
|
|
rpc GetNotetypeNamesAndCounts(Empty) returns (NotetypeUseCounts);
|
|
|
|
rpc GetNotetypeIdByName(String) returns (NotetypeId);
|
2021-04-29 15:28:42 +02:00
|
|
|
rpc RemoveNotetype(NotetypeId) returns (OpChanges);
|
2021-05-25 12:29:21 +02:00
|
|
|
rpc GetAuxNotetypeConfigKey(GetAuxConfigKeyIn) returns (String);
|
|
|
|
rpc GetAuxTemplateConfigKey(GetAuxTemplateConfigKeyIn) returns (String);
|
2021-03-11 06:47:31 +01:00
|
|
|
}
|
|
|
|
|
2021-03-11 07:05:06 +01:00
|
|
|
service CardRenderingService {
|
2021-03-11 05:33:57 +01:00
|
|
|
rpc ExtractAVTags(ExtractAVTagsIn) returns (ExtractAVTagsOut);
|
|
|
|
rpc ExtractLatex(ExtractLatexIn) returns (ExtractLatexOut);
|
|
|
|
rpc GetEmptyCards(Empty) returns (EmptyCardsReport);
|
|
|
|
rpc RenderExistingCard(RenderExistingCardIn) returns (RenderCardOut);
|
|
|
|
rpc RenderUncommittedCard(RenderUncommittedCardIn) returns (RenderCardOut);
|
2021-05-25 08:58:06 +02:00
|
|
|
rpc RenderUncommittedCardLegacy(RenderUncommittedCardLegacyIn)
|
|
|
|
returns (RenderCardOut);
|
2021-03-11 05:33:57 +01:00
|
|
|
rpc StripAVTags(String) returns (String);
|
2021-02-09 09:46:48 +01:00
|
|
|
rpc RenderMarkdown(RenderMarkdownIn) returns (String);
|
2021-03-11 07:05:06 +01:00
|
|
|
}
|
2021-01-09 15:48:34 +01:00
|
|
|
|
2021-03-11 07:05:06 +01:00
|
|
|
service DeckConfigService {
|
|
|
|
rpc AddOrUpdateDeckConfigLegacy(AddOrUpdateDeckConfigLegacyIn)
|
2021-03-27 12:38:20 +01:00
|
|
|
returns (DeckConfigId);
|
2021-04-04 14:24:35 +02:00
|
|
|
rpc GetDeckConfig(DeckConfigId) returns (DeckConfig);
|
2021-03-11 07:05:06 +01:00
|
|
|
rpc AllDeckConfigLegacy(Empty) returns (Json);
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc GetDeckConfigLegacy(DeckConfigId) returns (Json);
|
2021-03-11 07:05:06 +01:00
|
|
|
rpc NewDeckConfigLegacy(Empty) returns (Json);
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc RemoveDeckConfig(DeckConfigId) returns (Empty);
|
2021-04-18 03:56:41 +02:00
|
|
|
rpc GetDeckConfigsForUpdate(DeckId) returns (DeckConfigsForUpdate);
|
|
|
|
rpc UpdateDeckConfigs(UpdateDeckConfigsIn) returns (OpChanges);
|
2021-03-11 07:05:06 +01:00
|
|
|
}
|
2021-01-09 15:48:34 +01:00
|
|
|
|
2021-03-11 07:05:06 +01:00
|
|
|
service TagsService {
|
clear_unused_tags and browser redraw improvements
- clear_unused_tags() is now undoable, and returns the number of removed
notes
- add a new mw.query_op() helper for immutable queries
- decouple "freeze/unfreeze ui state" hooks from the "interface update
required" hook, so that the former is fired even on error, and can be
made re-entrant
- use a 'block_updates' flag in Python, instead of setUpdatesEnabled(),
as the latter has the side-effect of preventing child windows like
tooltips from appearing, and forces a full redrawn when updates are
enabled again. The new behaviour leads to the card list blanking out
when a long-running op is running, but in the future if we cache the
cell values we can just display them from the cache instead.
- we were indiscriminately saving the note with saveNow(), due to the
call to saveTags(). Changed so that it only saves when the tags field
is focused.
- drain the "on_done" queue on main before launching a new background
task, to lower the chances of something in on_done making a small query
to the DB and hanging until a long op finishes
- the duplicate check in the editor was executed after the webview loads,
leading to it hanging until the sidebar finishes loading. Run it at
set_note() time instead, so that the editor loads first.
- don't throw an error when a long-running op started with with_progress()
finishes after the window it was launched from has closed
- don't throw an error when the browser is closed before the sidebar
has finished loading
2021-03-17 12:27:42 +01:00
|
|
|
rpc ClearUnusedTags(Empty) returns (OpChangesWithCount);
|
2021-02-02 09:32:07 +01:00
|
|
|
rpc AllTags(Empty) returns (StringList);
|
2021-03-18 12:35:32 +01:00
|
|
|
rpc RemoveTags(String) returns (OpChangesWithCount);
|
2021-04-05 03:41:53 +02:00
|
|
|
rpc SetTagCollapsed(SetTagCollapsedIn) returns (OpChanges);
|
2021-01-09 15:48:34 +01:00
|
|
|
rpc TagTree(Empty) returns (TagTreeNode);
|
2021-03-19 10:15:17 +01:00
|
|
|
rpc ReparentTags(ReparentTagsIn) returns (OpChangesWithCount);
|
2021-03-18 11:43:04 +01:00
|
|
|
rpc RenameTags(RenameTagsIn) returns (OpChangesWithCount);
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc AddNoteTags(NoteIdsAndTagsIn) returns (OpChangesWithCount);
|
|
|
|
rpc RemoveNoteTags(NoteIdsAndTagsIn) returns (OpChangesWithCount);
|
2021-03-19 07:55:10 +01:00
|
|
|
rpc FindAndReplaceTag(FindAndReplaceTagIn) returns (OpChangesWithCount);
|
2021-03-11 07:05:06 +01:00
|
|
|
}
|
2021-01-09 15:48:34 +01:00
|
|
|
|
2021-03-11 07:16:40 +01:00
|
|
|
service SearchService {
|
2021-03-11 05:33:57 +01:00
|
|
|
rpc BuildSearchString(SearchNode) returns (String);
|
2021-03-29 08:12:26 +02:00
|
|
|
rpc SearchCards(SearchIn) returns (SearchOut);
|
|
|
|
rpc SearchNotes(SearchIn) returns (SearchOut);
|
2021-03-11 05:33:57 +01:00
|
|
|
rpc JoinSearchNodes(JoinSearchNodesIn) returns (String);
|
|
|
|
rpc ReplaceSearchNode(ReplaceSearchNodeIn) returns (String);
|
undoable ops now return changes directly; add new *_ops.py files
- Introduced a new transact() method that wraps the return value
in a separate struct that describes the changes that were made.
- Changes are now gathered from the undo log, so we don't need to
guess at what was changed - eg if update_note() is called with identical
note contents, no changes are returned. Card changes will only be set
if cards were actually generated by the update_note() call, and tag
will only be set if a new tag was added.
- mw.perform_op() has been updated to expect the op to return the changes,
or a structure with the changes in it, and it will use them to fire the
change hook, instead of fetching the changes from undo_status(), so there
is no risk of race conditions.
- the various calls to mw.perform_op() have been split into separate
files like card_ops.py. Aside from making the code cleaner, this works
around a rather annoying issue with mypy. Because we run it with
no_strict_optional, mypy is happy to accept an operation that returns None,
despite the type signature saying it requires changes to be returned.
Turning no_strict_optional on for the whole codebase is not practical
at the moment, but we can enable it for individual files.
Still todo:
- The cursor keeps moving back to the start of a field when typing -
we need to ignore the refresh hook when we are the initiator.
- The busy cursor icon should probably be delayed a few hundreds ms.
- Still need to think about a nicer way of handling saveNow()
- op_made_changes(), op_affects_study_queue() might be better embedded
as properties in the object instead
2021-03-16 05:26:42 +01:00
|
|
|
rpc FindAndReplace(FindAndReplaceIn) returns (OpChangesWithCount);
|
2021-04-08 23:48:24 +02:00
|
|
|
rpc AllBrowserColumns(Empty) returns (BrowserColumns);
|
2021-03-29 08:12:26 +02:00
|
|
|
rpc BrowserRowForId(Int64) returns (BrowserRow);
|
2021-04-09 22:53:02 +02:00
|
|
|
rpc SetActiveBrowserColumns(StringList) returns (Empty);
|
2021-03-11 07:16:40 +01:00
|
|
|
}
|
2021-01-09 15:48:34 +01:00
|
|
|
|
2021-03-11 07:16:40 +01:00
|
|
|
service StatsService {
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc CardStats(CardId) returns (String);
|
2021-01-09 15:48:34 +01:00
|
|
|
rpc Graphs(GraphsIn) returns (GraphsOut);
|
2021-01-23 11:47:45 +01:00
|
|
|
rpc GetGraphPreferences(Empty) returns (GraphPreferences);
|
|
|
|
rpc SetGraphPreferences(GraphPreferences) returns (Empty);
|
2021-03-11 07:16:40 +01:00
|
|
|
}
|
2021-01-29 07:30:42 +01:00
|
|
|
|
2021-03-11 07:16:40 +01:00
|
|
|
service MediaService {
|
2021-01-09 15:48:34 +01:00
|
|
|
rpc CheckMedia(Empty) returns (CheckMediaOut);
|
|
|
|
rpc TrashMediaFiles(TrashMediaFilesIn) returns (Empty);
|
|
|
|
rpc AddMediaFile(AddMediaFileIn) returns (String);
|
|
|
|
rpc EmptyTrash(Empty) returns (Empty);
|
|
|
|
rpc RestoreTrash(Empty) returns (Empty);
|
2021-03-11 07:16:40 +01:00
|
|
|
}
|
2021-01-29 07:30:42 +01:00
|
|
|
|
2021-03-11 07:53:36 +01:00
|
|
|
service I18nService {
|
|
|
|
rpc TranslateString(TranslateStringIn) returns (String);
|
|
|
|
rpc FormatTimespan(FormatTimespanIn) returns (String);
|
2021-03-26 12:22:37 +01:00
|
|
|
rpc I18nResources(I18nResourcesIn) returns (Json);
|
2021-03-11 07:53:36 +01:00
|
|
|
}
|
2021-01-09 15:48:34 +01:00
|
|
|
|
2021-03-11 07:53:36 +01:00
|
|
|
service CollectionService {
|
2021-01-09 15:48:34 +01:00
|
|
|
rpc OpenCollection(OpenCollectionIn) returns (Empty);
|
|
|
|
rpc CloseCollection(CloseCollectionIn) returns (Empty);
|
|
|
|
rpc CheckDatabase(Empty) returns (CheckDatabaseOut);
|
2021-03-04 10:17:19 +01:00
|
|
|
rpc GetUndoStatus(Empty) returns (UndoStatus);
|
2021-04-03 06:38:49 +02:00
|
|
|
rpc Undo(Empty) returns (OpChangesAfterUndo);
|
|
|
|
rpc Redo(Empty) returns (OpChangesAfterUndo);
|
2021-05-06 07:54:04 +02:00
|
|
|
rpc AddCustomUndoEntry(String) returns (UInt32);
|
|
|
|
rpc MergeUndoEntries(UInt32) returns (OpChanges);
|
2021-03-11 07:53:36 +01:00
|
|
|
rpc LatestProgress(Empty) returns (Progress);
|
|
|
|
rpc SetWantsAbort(Empty) returns (Empty);
|
|
|
|
}
|
2021-01-09 15:48:34 +01:00
|
|
|
|
2021-03-11 07:53:36 +01:00
|
|
|
service CardsService {
|
2021-03-27 12:38:20 +01:00
|
|
|
rpc GetCard(CardId) returns (Card);
|
undoable ops now return changes directly; add new *_ops.py files
- Introduced a new transact() method that wraps the return value
in a separate struct that describes the changes that were made.
- Changes are now gathered from the undo log, so we don't need to
guess at what was changed - eg if update_note() is called with identical
note contents, no changes are returned. Card changes will only be set
if cards were actually generated by the update_note() call, and tag
will only be set if a new tag was added.
- mw.perform_op() has been updated to expect the op to return the changes,
or a structure with the changes in it, and it will use them to fire the
change hook, instead of fetching the changes from undo_status(), so there
is no risk of race conditions.
- the various calls to mw.perform_op() have been split into separate
files like card_ops.py. Aside from making the code cleaner, this works
around a rather annoying issue with mypy. Because we run it with
no_strict_optional, mypy is happy to accept an operation that returns None,
despite the type signature saying it requires changes to be returned.
Turning no_strict_optional on for the whole codebase is not practical
at the moment, but we can enable it for individual files.
Still todo:
- The cursor keeps moving back to the start of a field when typing -
we need to ignore the refresh hook when we are the initiator.
- The busy cursor icon should probably be delayed a few hundreds ms.
- Still need to think about a nicer way of handling saveNow()
- op_made_changes(), op_affects_study_queue() might be better embedded
as properties in the object instead
2021-03-16 05:26:42 +01:00
|
|
|
rpc UpdateCard(UpdateCardIn) returns (OpChanges);
|
2021-03-11 07:53:36 +01:00
|
|
|
rpc RemoveCards(RemoveCardsIn) returns (Empty);
|
2021-05-21 08:03:05 +02:00
|
|
|
rpc SetDeck(SetDeckIn) returns (OpChangesWithCount);
|
|
|
|
rpc SetFlag(SetFlagIn) returns (OpChangesWithCount);
|
2020-05-22 12:02:10 +02:00
|
|
|
}
|
|
|
|
|
2020-05-18 00:57:30 +02:00
|
|
|
// Protobuf stored in .anki2 files
|
|
|
|
// These should be moved to a separate file in the future
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
2021-04-04 14:24:35 +02:00
|
|
|
message DeckConfig {
|
|
|
|
message Config {
|
2021-05-15 12:09:50 +02:00
|
|
|
enum NewCardInsertOrder {
|
|
|
|
NEW_CARD_INSERT_ORDER_DUE = 0;
|
|
|
|
NEW_CARD_INSERT_ORDER_RANDOM = 1;
|
|
|
|
}
|
|
|
|
enum NewCardGatherPriority {
|
|
|
|
NEW_CARD_GATHER_PRIORITY_DECK = 0;
|
|
|
|
NEW_CARD_GATHER_PRIORITY_POSITION = 1;
|
2021-05-12 08:33:18 +02:00
|
|
|
}
|
|
|
|
enum NewCardSortOrder {
|
|
|
|
NEW_CARD_SORT_ORDER_TEMPLATE_THEN_DUE = 0;
|
|
|
|
NEW_CARD_SORT_ORDER_TEMPLATE_THEN_RANDOM = 1;
|
|
|
|
NEW_CARD_SORT_ORDER_DUE = 2;
|
|
|
|
NEW_CARD_SORT_ORDER_RANDOM = 3;
|
2021-04-04 14:24:35 +02:00
|
|
|
}
|
|
|
|
enum ReviewCardOrder {
|
2021-05-12 08:33:18 +02:00
|
|
|
REVIEW_CARD_ORDER_DAY_THEN_RANDOM = 0;
|
|
|
|
REVIEW_CARD_ORDER_INTERVALS_ASCENDING = 1;
|
|
|
|
REVIEW_CARD_ORDER_INTERVALS_DESCENDING = 2;
|
|
|
|
// REVIEW_CARD_ORDER_RELATIVE_OVERDUE = 3;
|
2021-04-04 14:24:35 +02:00
|
|
|
}
|
|
|
|
enum ReviewMix {
|
|
|
|
REVIEW_MIX_MIX_WITH_REVIEWS = 0;
|
|
|
|
REVIEW_MIX_AFTER_REVIEWS = 1;
|
|
|
|
REVIEW_MIX_BEFORE_REVIEWS = 2;
|
|
|
|
}
|
|
|
|
enum LeechAction {
|
|
|
|
LEECH_ACTION_SUSPEND = 0;
|
|
|
|
LEECH_ACTION_TAG_ONLY = 1;
|
|
|
|
}
|
2020-05-18 00:57:30 +02:00
|
|
|
|
2021-04-04 14:24:35 +02:00
|
|
|
repeated float learn_steps = 1;
|
|
|
|
repeated float relearn_steps = 2;
|
2020-05-18 00:57:30 +02:00
|
|
|
|
2021-04-04 14:24:35 +02:00
|
|
|
reserved 3 to 8;
|
2020-05-18 00:57:30 +02:00
|
|
|
|
2021-04-04 14:24:35 +02:00
|
|
|
uint32 new_per_day = 9;
|
|
|
|
uint32 reviews_per_day = 10;
|
|
|
|
uint32 new_per_day_minimum = 29;
|
2020-05-18 00:57:30 +02:00
|
|
|
|
2021-04-04 14:24:35 +02:00
|
|
|
float initial_ease = 11;
|
|
|
|
float easy_multiplier = 12;
|
|
|
|
float hard_multiplier = 13;
|
|
|
|
float lapse_multiplier = 14;
|
|
|
|
float interval_multiplier = 15;
|
2020-05-18 00:57:30 +02:00
|
|
|
|
2021-04-04 14:24:35 +02:00
|
|
|
uint32 maximum_review_interval = 16;
|
|
|
|
uint32 minimum_lapse_interval = 17;
|
2020-05-18 00:57:30 +02:00
|
|
|
|
2021-04-04 14:24:35 +02:00
|
|
|
uint32 graduating_interval_good = 18;
|
|
|
|
uint32 graduating_interval_easy = 19;
|
2020-05-18 00:57:30 +02:00
|
|
|
|
2021-05-15 12:09:50 +02:00
|
|
|
NewCardInsertOrder new_card_insert_order = 20;
|
|
|
|
NewCardGatherPriority new_card_gather_priority = 34;
|
2021-05-12 08:33:18 +02:00
|
|
|
NewCardSortOrder new_card_sort_order = 32;
|
2021-05-15 12:09:50 +02:00
|
|
|
ReviewMix new_mix = 30;
|
|
|
|
|
2021-05-12 08:33:18 +02:00
|
|
|
ReviewCardOrder review_order = 33;
|
2021-03-01 01:34:04 +01:00
|
|
|
|
2021-04-04 14:24:35 +02:00
|
|
|
ReviewMix interday_learning_mix = 31;
|
2020-05-18 00:57:30 +02:00
|
|
|
|
2021-04-04 14:24:35 +02:00
|
|
|
LeechAction leech_action = 21;
|
|
|
|
uint32 leech_threshold = 22;
|
2020-05-18 00:57:30 +02:00
|
|
|
|
2021-04-04 14:24:35 +02:00
|
|
|
bool disable_autoplay = 23;
|
|
|
|
uint32 cap_answer_time_to_secs = 24;
|
2021-04-12 13:54:05 +02:00
|
|
|
bool show_timer = 25;
|
2021-04-04 14:24:35 +02:00
|
|
|
bool skip_question_when_replaying_answer = 26;
|
2020-05-18 00:57:30 +02:00
|
|
|
|
2021-04-04 14:24:35 +02:00
|
|
|
bool bury_new = 27;
|
|
|
|
bool bury_reviews = 28;
|
2020-05-18 00:57:30 +02:00
|
|
|
|
2021-04-04 14:24:35 +02:00
|
|
|
bytes other = 255;
|
|
|
|
}
|
2020-05-18 00:57:30 +02:00
|
|
|
|
2021-04-04 14:24:35 +02:00
|
|
|
int64 id = 1;
|
|
|
|
string name = 2;
|
|
|
|
int64 mtime_secs = 3;
|
|
|
|
int32 usn = 4;
|
|
|
|
Config config = 5;
|
|
|
|
}
|
2020-05-18 00:57:30 +02:00
|
|
|
|
|
|
|
message Deck {
|
2021-04-04 13:15:30 +02:00
|
|
|
message Common {
|
|
|
|
bool study_collapsed = 1;
|
|
|
|
bool browser_collapsed = 2;
|
|
|
|
|
|
|
|
uint32 last_day_studied = 3;
|
|
|
|
int32 new_studied = 4;
|
|
|
|
int32 review_studied = 5;
|
|
|
|
int32 milliseconds_studied = 7;
|
|
|
|
|
|
|
|
// previously set in the v1 scheduler,
|
|
|
|
// but not currently used for anything
|
|
|
|
int32 learning_studied = 6;
|
|
|
|
|
|
|
|
reserved 8 to 13;
|
|
|
|
|
|
|
|
bytes other = 255;
|
|
|
|
}
|
|
|
|
message Normal {
|
|
|
|
int64 config_id = 1;
|
|
|
|
uint32 extend_new = 2;
|
|
|
|
uint32 extend_review = 3;
|
|
|
|
string description = 4;
|
|
|
|
bool markdown_description = 5;
|
|
|
|
|
|
|
|
reserved 6 to 11;
|
|
|
|
}
|
|
|
|
message Filtered {
|
|
|
|
message SearchTerm {
|
|
|
|
enum Order {
|
|
|
|
OLDEST_REVIEWED_FIRST = 0;
|
|
|
|
RANDOM = 1;
|
|
|
|
INTERVALS_ASCENDING = 2;
|
|
|
|
INTERVALS_DESCENDING = 3;
|
|
|
|
LAPSES = 4;
|
|
|
|
ADDED = 5;
|
|
|
|
DUE = 6;
|
|
|
|
REVERSE_ADDED = 7;
|
|
|
|
DUE_PRIORITY = 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
string search = 1;
|
|
|
|
uint32 limit = 2;
|
|
|
|
Order order = 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool reschedule = 1;
|
|
|
|
repeated SearchTerm search_terms = 2;
|
|
|
|
// v1 scheduler only
|
|
|
|
repeated float delays = 3;
|
|
|
|
// v2 scheduler only
|
|
|
|
uint32 preview_delay = 4;
|
|
|
|
}
|
|
|
|
// a container to store the deck specifics in the DB
|
|
|
|
// as a tagged enum
|
|
|
|
message KindContainer {
|
|
|
|
oneof kind {
|
|
|
|
Normal normal = 1;
|
|
|
|
Filtered filtered = 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 id = 1;
|
|
|
|
string name = 2;
|
2021-03-22 14:17:07 +01:00
|
|
|
int64 mtime_secs = 3;
|
2021-01-09 06:50:24 +01:00
|
|
|
int32 usn = 4;
|
2021-04-04 13:15:30 +02:00
|
|
|
Common common = 5;
|
|
|
|
// the specifics are inlined here when sending data to clients,
|
|
|
|
// as otherwise an extra level of indirection would be required
|
2021-01-09 06:50:24 +01:00
|
|
|
oneof kind {
|
2021-04-04 13:15:30 +02:00
|
|
|
Normal normal = 6;
|
|
|
|
Filtered filtered = 7;
|
2021-01-09 06:50:24 +01:00
|
|
|
}
|
2020-05-18 00:57:30 +02:00
|
|
|
}
|
|
|
|
|
2021-03-27 13:03:19 +01:00
|
|
|
message Notetype {
|
2021-04-04 13:57:17 +02:00
|
|
|
message Config {
|
|
|
|
enum Kind {
|
|
|
|
KIND_NORMAL = 0;
|
|
|
|
KIND_CLOZE = 1;
|
|
|
|
}
|
|
|
|
message CardRequirement {
|
|
|
|
enum Kind {
|
|
|
|
KIND_NONE = 0;
|
|
|
|
KIND_ANY = 1;
|
|
|
|
KIND_ALL = 2;
|
|
|
|
}
|
|
|
|
uint32 card_ord = 1;
|
|
|
|
Kind kind = 2;
|
|
|
|
repeated uint32 field_ords = 3;
|
|
|
|
}
|
2020-05-18 00:57:30 +02:00
|
|
|
|
2021-04-04 13:57:17 +02:00
|
|
|
Kind kind = 1;
|
|
|
|
uint32 sort_field_idx = 2;
|
|
|
|
string css = 3;
|
2021-04-29 10:48:22 +02:00
|
|
|
/// This is now stored separately; retrieve with DefaultsForAdding()
|
|
|
|
int64 target_deck_id_unused = 4;
|
2021-04-04 13:57:17 +02:00
|
|
|
string latex_pre = 5;
|
|
|
|
string latex_post = 6;
|
|
|
|
bool latex_svg = 7;
|
|
|
|
repeated CardRequirement reqs = 8;
|
2020-05-18 00:57:30 +02:00
|
|
|
|
2021-04-04 13:57:17 +02:00
|
|
|
bytes other = 255;
|
|
|
|
}
|
|
|
|
message Field {
|
|
|
|
message Config {
|
|
|
|
bool sticky = 1;
|
|
|
|
bool rtl = 2;
|
|
|
|
string font_name = 3;
|
|
|
|
uint32 font_size = 4;
|
|
|
|
|
|
|
|
bytes other = 255;
|
|
|
|
}
|
|
|
|
OptionalUInt32 ord = 1;
|
|
|
|
string name = 2;
|
|
|
|
Config config = 5;
|
|
|
|
}
|
|
|
|
message Template {
|
|
|
|
message Config {
|
|
|
|
string q_format = 1;
|
|
|
|
string a_format = 2;
|
|
|
|
string q_format_browser = 3;
|
|
|
|
string a_format_browser = 4;
|
|
|
|
int64 target_deck_id = 5;
|
|
|
|
string browser_font_name = 6;
|
|
|
|
uint32 browser_font_size = 7;
|
|
|
|
|
|
|
|
bytes other = 255;
|
|
|
|
}
|
|
|
|
|
|
|
|
OptionalUInt32 ord = 1;
|
|
|
|
string name = 2;
|
2021-04-29 15:28:42 +02:00
|
|
|
int64 mtime_secs = 3;
|
2021-04-04 13:57:17 +02:00
|
|
|
sint32 usn = 4;
|
|
|
|
Config config = 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64 id = 1;
|
2021-01-09 06:50:24 +01:00
|
|
|
string name = 2;
|
2021-04-29 15:28:42 +02:00
|
|
|
int64 mtime_secs = 3;
|
2021-01-09 06:50:24 +01:00
|
|
|
sint32 usn = 4;
|
2021-04-04 13:57:17 +02:00
|
|
|
Config config = 7;
|
|
|
|
repeated Field fields = 8;
|
|
|
|
repeated Template templates = 9;
|
2020-05-18 00:57:30 +02:00
|
|
|
}
|
|
|
|
|
2021-04-04 14:24:35 +02:00
|
|
|
// Database objects
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
2020-05-18 00:57:30 +02:00
|
|
|
message Note {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 id = 1;
|
|
|
|
string guid = 2;
|
|
|
|
int64 notetype_id = 3;
|
|
|
|
uint32 mtime_secs = 4;
|
|
|
|
int32 usn = 5;
|
|
|
|
repeated string tags = 6;
|
|
|
|
repeated string fields = 7;
|
2020-05-18 00:57:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
message Card {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 id = 1;
|
|
|
|
int64 note_id = 2;
|
|
|
|
int64 deck_id = 3;
|
|
|
|
uint32 template_idx = 4;
|
|
|
|
int64 mtime_secs = 5;
|
|
|
|
sint32 usn = 6;
|
|
|
|
uint32 ctype = 7;
|
|
|
|
sint32 queue = 8;
|
|
|
|
sint32 due = 9;
|
|
|
|
uint32 interval = 10;
|
|
|
|
uint32 ease_factor = 11;
|
|
|
|
uint32 reps = 12;
|
|
|
|
uint32 lapses = 13;
|
|
|
|
uint32 remaining_steps = 14;
|
|
|
|
sint32 original_due = 15;
|
|
|
|
int64 original_deck_id = 16;
|
|
|
|
uint32 flags = 17;
|
|
|
|
string data = 18;
|
2020-05-18 00:57:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Backend
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
2020-01-30 02:22:34 +01:00
|
|
|
message BackendInit {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated string preferred_langs = 1;
|
|
|
|
string locale_folder_path = 2;
|
|
|
|
bool server = 3;
|
2020-01-30 02:22:34 +01:00
|
|
|
}
|
|
|
|
|
2020-02-23 05:57:02 +01:00
|
|
|
message I18nBackendInit {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated string preferred_langs = 4;
|
|
|
|
string locale_folder_path = 5;
|
2020-02-23 05:57:02 +01:00
|
|
|
}
|
|
|
|
|
2020-05-24 00:36:50 +02:00
|
|
|
// Errors
|
2020-05-22 13:25:25 +02:00
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
2019-12-24 23:59:33 +01:00
|
|
|
message BackendError {
|
2021-04-03 08:00:15 +02:00
|
|
|
enum Kind {
|
|
|
|
INVALID_INPUT = 0;
|
|
|
|
UNDO_EMPTY = 1;
|
|
|
|
INTERRUPTED = 2;
|
|
|
|
TEMPLATE_PARSE = 3;
|
|
|
|
IO_ERROR = 4;
|
|
|
|
DB_ERROR = 5;
|
|
|
|
NETWORK_ERROR = 6;
|
|
|
|
SYNC_AUTH_ERROR = 7;
|
|
|
|
SYNC_OTHER_ERROR = 8;
|
|
|
|
JSON_ERROR = 9;
|
|
|
|
PROTO_ERROR = 10;
|
|
|
|
NOT_FOUND_ERROR = 11;
|
|
|
|
EXISTS = 12;
|
|
|
|
FILTERED_DECK_ERROR = 13;
|
|
|
|
SEARCH_ERROR = 14;
|
2021-01-09 06:50:24 +01:00
|
|
|
}
|
2019-12-24 04:33:44 +01:00
|
|
|
|
2021-04-03 08:00:15 +02:00
|
|
|
// localized error description suitable for displaying to the user
|
|
|
|
string localized = 1;
|
|
|
|
// the error subtype
|
|
|
|
Kind kind = 2;
|
2020-02-04 10:39:31 +01:00
|
|
|
}
|
|
|
|
|
2020-05-29 11:59:50 +02:00
|
|
|
// Progress
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
message Progress {
|
2021-02-08 07:40:27 +01:00
|
|
|
message MediaSync {
|
|
|
|
string checked = 1;
|
|
|
|
string added = 2;
|
|
|
|
string removed = 3;
|
2021-01-09 06:50:24 +01:00
|
|
|
}
|
2020-05-29 11:59:50 +02:00
|
|
|
|
2021-02-08 07:40:27 +01:00
|
|
|
message FullSync {
|
|
|
|
uint32 transferred = 1;
|
|
|
|
uint32 total = 2;
|
|
|
|
}
|
2020-02-04 00:07:15 +01:00
|
|
|
|
2021-02-08 07:40:27 +01:00
|
|
|
message NormalSync {
|
|
|
|
string stage = 1;
|
|
|
|
string added = 2;
|
|
|
|
string removed = 3;
|
|
|
|
}
|
2020-05-31 06:43:27 +02:00
|
|
|
|
2021-02-08 07:40:27 +01:00
|
|
|
message DatabaseCheck {
|
|
|
|
string stage = 1;
|
|
|
|
uint32 stage_total = 2;
|
|
|
|
uint32 stage_current = 3;
|
|
|
|
}
|
|
|
|
oneof value {
|
|
|
|
Empty none = 1;
|
|
|
|
MediaSync media_sync = 2;
|
|
|
|
string media_check = 3;
|
|
|
|
FullSync full_sync = 4;
|
|
|
|
NormalSync normal_sync = 5;
|
|
|
|
DatabaseCheck database_check = 6;
|
|
|
|
}
|
2020-06-08 12:28:11 +02:00
|
|
|
}
|
|
|
|
|
2020-05-24 00:36:50 +02:00
|
|
|
// Messages
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
2019-12-27 09:14:19 +01:00
|
|
|
message SchedTimingTodayOut {
|
2021-01-09 06:50:24 +01:00
|
|
|
uint32 days_elapsed = 1;
|
|
|
|
int64 next_day_at = 2;
|
2019-12-27 09:14:19 +01:00
|
|
|
}
|
2020-01-06 03:18:20 +01:00
|
|
|
|
2020-05-03 00:43:22 +02:00
|
|
|
message DeckTreeIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
// if non-zero, counts for the provided timestamp will be included
|
|
|
|
int64 now = 1;
|
|
|
|
int64 top_deck_id = 2;
|
2020-01-06 03:18:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
message DeckTreeNode {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 deck_id = 1;
|
|
|
|
string name = 2;
|
|
|
|
uint32 level = 4;
|
|
|
|
bool collapsed = 5;
|
2020-05-03 00:43:22 +02:00
|
|
|
|
2021-01-09 06:50:24 +01:00
|
|
|
uint32 review_count = 6;
|
|
|
|
uint32 learn_count = 7;
|
|
|
|
uint32 new_count = 8;
|
2020-05-16 02:52:14 +02:00
|
|
|
|
2021-01-09 06:50:24 +01:00
|
|
|
bool filtered = 16;
|
2021-05-15 12:09:50 +02:00
|
|
|
|
|
|
|
// low index so key can be packed into a byte, but at bottom
|
|
|
|
// to make debug output easier to read
|
|
|
|
repeated DeckTreeNode children = 3;
|
2020-01-06 03:18:20 +01:00
|
|
|
}
|
|
|
|
|
2020-05-13 02:35:01 +02:00
|
|
|
message RenderExistingCardIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 card_id = 1;
|
|
|
|
bool browser = 2;
|
2020-01-08 11:28:04 +01:00
|
|
|
}
|
|
|
|
|
2020-05-13 09:24:49 +02:00
|
|
|
message RenderUncommittedCardIn {
|
2021-05-25 08:58:06 +02:00
|
|
|
Note note = 1;
|
|
|
|
uint32 card_ord = 2;
|
|
|
|
Notetype.Template template = 3;
|
|
|
|
bool fill_empty = 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
message RenderUncommittedCardLegacyIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
Note note = 1;
|
|
|
|
uint32 card_ord = 2;
|
|
|
|
bytes template = 3;
|
|
|
|
bool fill_empty = 4;
|
2020-05-13 09:24:49 +02:00
|
|
|
}
|
|
|
|
|
2020-01-12 06:15:46 +01:00
|
|
|
message RenderCardOut {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated RenderedTemplateNode question_nodes = 1;
|
|
|
|
repeated RenderedTemplateNode answer_nodes = 2;
|
2021-05-25 10:41:43 +02:00
|
|
|
string css = 3;
|
|
|
|
bool latex_svg = 4;
|
2020-01-08 11:28:04 +01:00
|
|
|
}
|
|
|
|
|
2020-01-10 05:59:29 +01:00
|
|
|
message RenderedTemplateNode {
|
2021-01-09 06:50:24 +01:00
|
|
|
oneof value {
|
|
|
|
string text = 1;
|
|
|
|
RenderedTemplateReplacement replacement = 2;
|
|
|
|
}
|
2020-01-08 11:28:04 +01:00
|
|
|
}
|
|
|
|
|
2020-01-10 05:59:29 +01:00
|
|
|
message RenderedTemplateReplacement {
|
2021-01-09 06:50:24 +01:00
|
|
|
string field_name = 1;
|
|
|
|
string current_text = 2;
|
|
|
|
repeated string filters = 3;
|
2020-01-08 11:28:04 +01:00
|
|
|
}
|
2020-01-20 10:12:34 +01:00
|
|
|
|
2020-01-24 02:06:11 +01:00
|
|
|
message ExtractAVTagsIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
string text = 1;
|
|
|
|
bool question_side = 2;
|
2020-01-24 02:06:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
message ExtractAVTagsOut {
|
2021-01-09 06:50:24 +01:00
|
|
|
string text = 1;
|
|
|
|
repeated AVTag av_tags = 2;
|
2020-01-20 10:12:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
message AVTag {
|
2021-01-09 06:50:24 +01:00
|
|
|
oneof value {
|
|
|
|
string sound_or_video = 1;
|
|
|
|
TTSTag tts = 2;
|
|
|
|
}
|
2020-01-20 10:12:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
message TTSTag {
|
2021-01-09 06:50:24 +01:00
|
|
|
string field_text = 1;
|
|
|
|
string lang = 2;
|
|
|
|
repeated string voices = 3;
|
|
|
|
float speed = 4;
|
|
|
|
repeated string other_args = 5;
|
2020-01-20 10:12:34 +01:00
|
|
|
}
|
2020-01-28 12:45:26 +01:00
|
|
|
|
2020-02-11 05:20:07 +01:00
|
|
|
message ExtractLatexIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
string text = 1;
|
|
|
|
bool svg = 2;
|
|
|
|
bool expand_clozes = 3;
|
2020-02-11 05:20:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
message ExtractLatexOut {
|
2021-01-09 06:50:24 +01:00
|
|
|
string text = 1;
|
|
|
|
repeated ExtractedLatex latex = 2;
|
2020-02-11 05:20:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
message ExtractedLatex {
|
2021-01-09 06:50:24 +01:00
|
|
|
string filename = 1;
|
|
|
|
string latex_body = 2;
|
2020-02-11 05:20:07 +01:00
|
|
|
}
|
|
|
|
|
2020-02-11 09:08:34 +01:00
|
|
|
message AddMediaFileIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
string desired_name = 1;
|
|
|
|
bytes data = 2;
|
2020-02-04 00:07:15 +01:00
|
|
|
}
|
|
|
|
|
2020-05-22 13:25:25 +02:00
|
|
|
message CheckMediaOut {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated string unused = 1;
|
|
|
|
repeated string missing = 2;
|
|
|
|
string report = 3;
|
|
|
|
bool have_trash = 4;
|
2020-02-11 08:30:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
message TrashMediaFilesIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated string fnames = 1;
|
2020-02-16 12:07:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
message TranslateStringIn {
|
2021-03-27 02:56:31 +01:00
|
|
|
uint32 module_index = 1;
|
|
|
|
uint32 message_index = 2;
|
2021-01-09 06:50:24 +01:00
|
|
|
map<string, TranslateArgValue> args = 3;
|
2020-02-16 12:07:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
message TranslateArgValue {
|
2021-01-09 06:50:24 +01:00
|
|
|
oneof value {
|
|
|
|
string str = 1;
|
|
|
|
double number = 2;
|
|
|
|
}
|
2020-02-16 12:07:40 +01:00
|
|
|
}
|
2020-02-20 05:16:33 +01:00
|
|
|
|
2020-05-24 00:36:50 +02:00
|
|
|
message FormatTimespanIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
enum Context {
|
|
|
|
PRECISE = 0;
|
|
|
|
ANSWER_BUTTONS = 1;
|
|
|
|
INTERVALS = 2;
|
|
|
|
}
|
2020-02-20 05:16:33 +01:00
|
|
|
|
2021-01-09 06:50:24 +01:00
|
|
|
float seconds = 1;
|
|
|
|
Context context = 2;
|
2020-02-20 05:16:33 +01:00
|
|
|
}
|
2020-02-21 09:01:15 +01:00
|
|
|
|
2021-03-26 12:22:37 +01:00
|
|
|
message I18nResourcesIn {
|
|
|
|
repeated string modules = 1;
|
|
|
|
}
|
|
|
|
|
2020-09-02 09:18:29 +02:00
|
|
|
message StudiedTodayMessageIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
uint32 cards = 1;
|
|
|
|
double seconds = 2;
|
2020-02-21 09:01:15 +01:00
|
|
|
}
|
2020-02-21 10:26:45 +01:00
|
|
|
|
2020-05-23 13:34:19 +02:00
|
|
|
message CongratsLearnMessageIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
float next_due = 1;
|
|
|
|
uint32 remaining = 2;
|
2020-03-09 09:58:49 +01:00
|
|
|
}
|
2020-03-14 00:08:02 +01:00
|
|
|
|
|
|
|
message OpenCollectionIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
string collection_path = 1;
|
|
|
|
string media_folder_path = 2;
|
|
|
|
string media_db_path = 3;
|
|
|
|
string log_path = 4;
|
2020-03-14 00:08:02 +01:00
|
|
|
}
|
2020-03-19 23:20:47 +01:00
|
|
|
|
2021-03-29 08:12:26 +02:00
|
|
|
message SearchIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
string search = 1;
|
|
|
|
SortOrder order = 2;
|
2020-03-19 23:20:47 +01:00
|
|
|
}
|
|
|
|
|
2021-03-29 08:12:26 +02:00
|
|
|
message SearchOut {
|
|
|
|
repeated int64 ids = 1;
|
2020-03-19 23:20:47 +01:00
|
|
|
}
|
2020-03-20 22:54:43 +01:00
|
|
|
|
|
|
|
message SortOrder {
|
2021-01-31 08:08:22 +01:00
|
|
|
message Builtin {
|
2021-04-09 18:50:30 +02:00
|
|
|
string column = 1;
|
2021-01-31 08:08:22 +01:00
|
|
|
bool reverse = 2;
|
|
|
|
}
|
2021-01-09 06:50:24 +01:00
|
|
|
oneof value {
|
2021-04-10 11:13:42 +02:00
|
|
|
Empty none = 1;
|
|
|
|
string custom = 2;
|
|
|
|
Builtin builtin = 3;
|
2021-01-09 06:50:24 +01:00
|
|
|
}
|
2020-03-20 22:54:43 +01:00
|
|
|
}
|
2020-03-21 00:00:05 +01:00
|
|
|
|
2021-02-11 10:57:19 +01:00
|
|
|
message SearchNode {
|
2021-01-30 02:10:26 +01:00
|
|
|
message Dupe {
|
|
|
|
int64 notetype_id = 1;
|
|
|
|
string first_field = 2;
|
2021-01-09 19:03:43 +01:00
|
|
|
}
|
2021-01-29 18:27:33 +01:00
|
|
|
enum Flag {
|
2021-01-30 17:56:29 +01:00
|
|
|
FLAG_NONE = 0;
|
|
|
|
FLAG_ANY = 1;
|
|
|
|
FLAG_RED = 2;
|
|
|
|
FLAG_ORANGE = 3;
|
|
|
|
FLAG_GREEN = 4;
|
|
|
|
FLAG_BLUE = 5;
|
2021-01-29 18:27:33 +01:00
|
|
|
}
|
2021-01-30 02:54:39 +01:00
|
|
|
enum Rating {
|
2021-01-30 17:56:29 +01:00
|
|
|
RATING_ANY = 0;
|
|
|
|
RATING_AGAIN = 1;
|
|
|
|
RATING_HARD = 2;
|
|
|
|
RATING_GOOD = 3;
|
|
|
|
RATING_EASY = 4;
|
|
|
|
RATING_BY_RESCHEDULE = 5;
|
2021-01-30 02:54:39 +01:00
|
|
|
}
|
2021-01-30 01:26:23 +01:00
|
|
|
message Rated {
|
|
|
|
uint32 days = 1;
|
|
|
|
Rating rating = 2;
|
|
|
|
}
|
2021-01-30 01:49:00 +01:00
|
|
|
enum CardState {
|
2021-01-30 17:56:29 +01:00
|
|
|
CARD_STATE_NEW = 0;
|
|
|
|
CARD_STATE_LEARN = 1;
|
|
|
|
CARD_STATE_REVIEW = 2;
|
|
|
|
CARD_STATE_DUE = 3;
|
|
|
|
CARD_STATE_SUSPENDED = 4;
|
|
|
|
CARD_STATE_BURIED = 5;
|
2021-01-30 01:49:00 +01:00
|
|
|
}
|
2021-01-30 02:23:32 +01:00
|
|
|
message IdList {
|
|
|
|
repeated int64 ids = 1;
|
2021-01-13 11:57:41 +01:00
|
|
|
}
|
2021-02-11 02:21:33 +01:00
|
|
|
message Group {
|
2021-02-11 10:57:19 +01:00
|
|
|
enum Joiner {
|
2021-02-11 02:21:33 +01:00
|
|
|
AND = 0;
|
|
|
|
OR = 1;
|
|
|
|
}
|
2021-02-11 10:57:19 +01:00
|
|
|
repeated SearchNode nodes = 1;
|
|
|
|
Joiner joiner = 2;
|
2021-02-11 02:21:33 +01:00
|
|
|
}
|
2021-01-09 19:03:43 +01:00
|
|
|
oneof filter {
|
2021-02-11 02:21:33 +01:00
|
|
|
Group group = 1;
|
2021-02-11 10:57:19 +01:00
|
|
|
SearchNode negated = 2;
|
|
|
|
string parsable_text = 3;
|
2021-01-29 18:27:33 +01:00
|
|
|
uint32 template = 4;
|
2021-01-30 02:23:32 +01:00
|
|
|
int64 nid = 5;
|
2021-01-30 02:10:26 +01:00
|
|
|
Dupe dupe = 6;
|
2021-01-29 18:27:33 +01:00
|
|
|
string field_name = 7;
|
2021-01-30 01:26:23 +01:00
|
|
|
Rated rated = 8;
|
2021-01-29 18:27:33 +01:00
|
|
|
uint32 added_in_days = 9;
|
|
|
|
int32 due_in_days = 10;
|
2021-01-31 11:12:49 +01:00
|
|
|
Flag flag = 11;
|
|
|
|
CardState card_state = 12;
|
|
|
|
IdList nids = 13;
|
2021-02-05 06:26:12 +01:00
|
|
|
uint32 edited_in_days = 14;
|
2021-02-11 02:21:33 +01:00
|
|
|
string deck = 15;
|
2021-02-11 01:41:19 +01:00
|
|
|
int32 due_on_day = 16;
|
2021-02-11 02:21:33 +01:00
|
|
|
string tag = 17;
|
2021-02-11 08:11:17 +01:00
|
|
|
string note = 18;
|
2021-04-18 13:27:10 +02:00
|
|
|
uint32 introduced_in_days = 19;
|
2021-01-09 19:03:43 +01:00
|
|
|
}
|
2021-01-09 10:50:08 +01:00
|
|
|
}
|
|
|
|
|
2021-02-11 10:57:19 +01:00
|
|
|
message JoinSearchNodesIn {
|
|
|
|
SearchNode.Group.Joiner joiner = 1;
|
|
|
|
SearchNode existing_node = 2;
|
|
|
|
SearchNode additional_node = 3;
|
2021-01-06 14:03:43 +01:00
|
|
|
}
|
|
|
|
|
2021-02-11 10:57:19 +01:00
|
|
|
message ReplaceSearchNodeIn {
|
|
|
|
SearchNode existing_node = 1;
|
|
|
|
SearchNode replacement_node = 2;
|
2021-01-06 14:03:43 +01:00
|
|
|
}
|
|
|
|
|
2020-03-30 12:01:16 +02:00
|
|
|
message CloseCollectionIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
bool downgrade_to_schema11 = 1;
|
2020-03-30 12:01:16 +02:00
|
|
|
}
|
2020-04-03 05:54:52 +02:00
|
|
|
|
2020-05-23 07:09:16 +02:00
|
|
|
message AddOrUpdateDeckConfigLegacyIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
bytes config = 1;
|
|
|
|
bool preserve_usn_and_mtime = 2;
|
2020-04-03 05:54:52 +02:00
|
|
|
}
|
2020-04-03 11:30:42 +02:00
|
|
|
|
2021-04-18 03:56:41 +02:00
|
|
|
message DeckConfigsForUpdate {
|
2021-04-12 06:18:30 +02:00
|
|
|
message ConfigWithExtra {
|
|
|
|
DeckConfig config = 1;
|
|
|
|
uint32 use_count = 2;
|
|
|
|
}
|
|
|
|
message CurrentDeck {
|
|
|
|
string name = 1;
|
|
|
|
int64 config_id = 2;
|
2021-04-17 04:53:59 +02:00
|
|
|
repeated int64 parent_config_ids = 3;
|
2021-04-12 06:18:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
repeated ConfigWithExtra all_config = 1;
|
|
|
|
CurrentDeck current_deck = 2;
|
|
|
|
DeckConfig defaults = 3;
|
2021-04-18 03:56:41 +02:00
|
|
|
bool schema_modified = 4;
|
2021-05-13 07:23:16 +02:00
|
|
|
bool v3_scheduler = 5;
|
2021-05-19 08:20:25 +02:00
|
|
|
bool have_addons = 6;
|
2021-04-12 06:18:30 +02:00
|
|
|
}
|
|
|
|
|
2021-04-18 03:56:41 +02:00
|
|
|
message UpdateDeckConfigsIn {
|
|
|
|
int64 target_deck_id = 1;
|
|
|
|
/// Unchanged, non-selected configs can be omitted. Deck will
|
|
|
|
/// be set to whichever entry comes last.
|
|
|
|
repeated DeckConfig configs = 2;
|
|
|
|
repeated int64 removed_config_ids = 3;
|
|
|
|
bool apply_to_children = 4;
|
2021-04-12 06:18:30 +02:00
|
|
|
}
|
|
|
|
|
2021-04-05 03:41:53 +02:00
|
|
|
message SetTagCollapsedIn {
|
2021-01-09 15:48:34 +01:00
|
|
|
string name = 1;
|
2021-04-05 03:41:53 +02:00
|
|
|
bool collapsed = 2;
|
2021-01-09 14:55:08 +01:00
|
|
|
}
|
|
|
|
|
2021-04-05 02:21:50 +02:00
|
|
|
message SetDeckCollapsedIn {
|
|
|
|
enum Scope {
|
|
|
|
REVIEWER = 0;
|
|
|
|
BROWSER = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64 deck_id = 1;
|
|
|
|
bool collapsed = 2;
|
|
|
|
Scope scope = 3;
|
|
|
|
}
|
|
|
|
|
2020-04-03 11:30:42 +02:00
|
|
|
message GetChangedTagsOut {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated string tags = 1;
|
2020-04-03 11:30:42 +02:00
|
|
|
}
|
|
|
|
|
2021-01-06 15:04:03 +01:00
|
|
|
message TagTreeNode {
|
2021-01-12 21:12:35 +01:00
|
|
|
string name = 1;
|
|
|
|
repeated TagTreeNode children = 2;
|
|
|
|
uint32 level = 3;
|
2021-04-05 03:41:53 +02:00
|
|
|
bool collapsed = 4;
|
2021-01-06 15:04:03 +01:00
|
|
|
}
|
|
|
|
|
2021-03-19 10:15:17 +01:00
|
|
|
message ReparentTagsIn {
|
|
|
|
repeated string tags = 1;
|
|
|
|
string new_parent = 2;
|
2021-02-02 11:14:04 +01:00
|
|
|
}
|
|
|
|
|
2021-03-18 11:43:04 +01:00
|
|
|
message RenameTagsIn {
|
|
|
|
string current_prefix = 1;
|
|
|
|
string new_prefix = 2;
|
|
|
|
}
|
|
|
|
|
2020-05-24 00:36:50 +02:00
|
|
|
message SetConfigJsonIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
string key = 1;
|
|
|
|
bytes value_json = 2;
|
2021-05-24 06:50:46 +02:00
|
|
|
bool undoable = 3;
|
2020-04-05 13:38:58 +02:00
|
|
|
}
|
2020-04-12 09:45:21 +02:00
|
|
|
|
2021-03-27 13:03:19 +01:00
|
|
|
message StockNotetype {
|
2021-01-31 07:56:19 +01:00
|
|
|
enum Kind {
|
|
|
|
BASIC = 0;
|
|
|
|
BASIC_AND_REVERSED = 1;
|
|
|
|
BASIC_OPTIONAL_REVERSED = 2;
|
|
|
|
BASIC_TYPING = 3;
|
|
|
|
CLOZE = 4;
|
|
|
|
}
|
2020-04-13 23:30:33 +02:00
|
|
|
|
2021-01-31 07:56:19 +01:00
|
|
|
Kind kind = 1;
|
2020-05-23 12:43:55 +02:00
|
|
|
}
|
|
|
|
|
2021-03-27 13:03:19 +01:00
|
|
|
message NotetypeNames {
|
|
|
|
repeated NotetypeNameId entries = 1;
|
2020-04-23 02:10:28 +02:00
|
|
|
}
|
|
|
|
|
2021-03-27 13:03:19 +01:00
|
|
|
message NotetypeUseCounts {
|
|
|
|
repeated NotetypeNameIdUseCount entries = 1;
|
2020-04-23 02:10:28 +02:00
|
|
|
}
|
|
|
|
|
2021-03-27 13:03:19 +01:00
|
|
|
message NotetypeNameId {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 id = 1;
|
|
|
|
string name = 2;
|
2020-04-23 02:10:28 +02:00
|
|
|
}
|
|
|
|
|
2021-03-27 13:03:19 +01:00
|
|
|
message NotetypeNameIdUseCount {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 id = 1;
|
|
|
|
string name = 2;
|
|
|
|
uint32 use_count = 3;
|
2020-04-23 02:10:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
message AddOrUpdateNotetypeIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
bytes json = 1;
|
|
|
|
bool preserve_usn_and_mtime = 2;
|
2020-04-23 02:10:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
message AddNoteIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
Note note = 1;
|
|
|
|
int64 deck_id = 2;
|
2020-04-23 02:10:28 +02:00
|
|
|
}
|
2020-04-25 10:25:56 +02:00
|
|
|
|
undoable ops now return changes directly; add new *_ops.py files
- Introduced a new transact() method that wraps the return value
in a separate struct that describes the changes that were made.
- Changes are now gathered from the undo log, so we don't need to
guess at what was changed - eg if update_note() is called with identical
note contents, no changes are returned. Card changes will only be set
if cards were actually generated by the update_note() call, and tag
will only be set if a new tag was added.
- mw.perform_op() has been updated to expect the op to return the changes,
or a structure with the changes in it, and it will use them to fire the
change hook, instead of fetching the changes from undo_status(), so there
is no risk of race conditions.
- the various calls to mw.perform_op() have been split into separate
files like card_ops.py. Aside from making the code cleaner, this works
around a rather annoying issue with mypy. Because we run it with
no_strict_optional, mypy is happy to accept an operation that returns None,
despite the type signature saying it requires changes to be returned.
Turning no_strict_optional on for the whole codebase is not practical
at the moment, but we can enable it for individual files.
Still todo:
- The cursor keeps moving back to the start of a field when typing -
we need to ignore the refresh hook when we are the initiator.
- The busy cursor icon should probably be delayed a few hundreds ms.
- Still need to think about a nicer way of handling saveNow()
- op_made_changes(), op_affects_study_queue() might be better embedded
as properties in the object instead
2021-03-16 05:26:42 +01:00
|
|
|
message AddNoteOut {
|
|
|
|
int64 note_id = 1;
|
|
|
|
OpChanges changes = 2;
|
|
|
|
}
|
|
|
|
|
2021-03-05 13:45:55 +01:00
|
|
|
message UpdateNoteIn {
|
|
|
|
Note note = 1;
|
|
|
|
bool skip_undo_entry = 2;
|
|
|
|
}
|
|
|
|
|
2021-03-06 15:17:17 +01:00
|
|
|
message UpdateCardIn {
|
|
|
|
Card card = 1;
|
|
|
|
bool skip_undo_entry = 2;
|
|
|
|
}
|
|
|
|
|
2020-04-25 10:25:56 +02:00
|
|
|
message EmptyCardsReport {
|
2021-02-08 10:11:16 +01:00
|
|
|
message NoteWithEmptyCards {
|
|
|
|
int64 note_id = 1;
|
|
|
|
repeated int64 card_ids = 2;
|
|
|
|
bool will_delete_note = 3;
|
|
|
|
}
|
2021-01-09 06:50:24 +01:00
|
|
|
string report = 1;
|
|
|
|
repeated NoteWithEmptyCards notes = 2;
|
2020-04-25 10:25:56 +02:00
|
|
|
}
|
|
|
|
|
2020-05-02 04:41:53 +02:00
|
|
|
message DeckNames {
|
2021-03-27 12:38:20 +01:00
|
|
|
repeated DeckNameId entries = 1;
|
2020-05-02 04:41:53 +02:00
|
|
|
}
|
|
|
|
|
2021-03-27 12:38:20 +01:00
|
|
|
message DeckNameId {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 id = 1;
|
|
|
|
string name = 2;
|
2020-05-02 04:41:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
message AddOrUpdateDeckLegacyIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
bytes deck = 1;
|
|
|
|
bool preserve_usn_and_mtime = 2;
|
2020-05-02 04:41:53 +02:00
|
|
|
}
|
2020-05-03 00:43:22 +02:00
|
|
|
|
2020-05-05 12:50:17 +02:00
|
|
|
message FieldNamesForNotesIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated int64 nids = 1;
|
2020-05-05 12:50:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
message FieldNamesForNotesOut {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated string fields = 1;
|
2020-05-05 12:50:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
message FindAndReplaceIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated int64 nids = 1;
|
|
|
|
string search = 2;
|
|
|
|
string replacement = 3;
|
|
|
|
bool regex = 4;
|
|
|
|
bool match_case = 5;
|
|
|
|
string field_name = 6;
|
2020-05-05 12:50:17 +02:00
|
|
|
}
|
2020-05-06 05:14:57 +02:00
|
|
|
|
2021-04-06 19:46:12 +02:00
|
|
|
message BrowserColumns {
|
2021-04-08 11:40:24 +02:00
|
|
|
enum Sorting {
|
|
|
|
SORTING_NONE = 0;
|
|
|
|
SORTING_NORMAL = 1;
|
|
|
|
SORTING_REVERSED = 2;
|
|
|
|
}
|
2021-04-08 11:28:29 +02:00
|
|
|
enum Alignment {
|
|
|
|
ALIGNMENT_START = 0;
|
|
|
|
ALIGNMENT_CENTER = 1;
|
|
|
|
}
|
2021-04-08 10:16:06 +02:00
|
|
|
message Column {
|
|
|
|
string key = 1;
|
2021-04-10 09:14:20 +02:00
|
|
|
string cards_mode_label = 2;
|
|
|
|
string notes_mode_label = 3;
|
2021-04-08 23:48:24 +02:00
|
|
|
Sorting sorting = 4;
|
2021-04-08 10:16:06 +02:00
|
|
|
bool uses_cell_font = 5;
|
2021-04-08 11:28:29 +02:00
|
|
|
Alignment alignment = 6;
|
2021-04-08 10:16:06 +02:00
|
|
|
}
|
|
|
|
repeated Column columns = 1;
|
2021-04-06 19:46:12 +02:00
|
|
|
}
|
|
|
|
|
2021-03-20 12:02:51 +01:00
|
|
|
message BrowserRow {
|
|
|
|
message Cell {
|
|
|
|
string text = 1;
|
|
|
|
bool is_rtl = 2;
|
|
|
|
}
|
|
|
|
enum Color {
|
|
|
|
COLOR_DEFAULT = 0;
|
|
|
|
COLOR_MARKED = 1;
|
|
|
|
COLOR_SUSPENDED = 2;
|
|
|
|
COLOR_FLAG_RED = 3;
|
|
|
|
COLOR_FLAG_ORANGE = 4;
|
|
|
|
COLOR_FLAG_GREEN = 5;
|
|
|
|
COLOR_FLAG_BLUE = 6;
|
|
|
|
}
|
|
|
|
repeated Cell cells = 1;
|
|
|
|
Color color = 2;
|
|
|
|
string font_name = 3;
|
|
|
|
uint32 font_size = 4;
|
|
|
|
}
|
|
|
|
|
2020-05-06 05:14:57 +02:00
|
|
|
message AfterNoteUpdatesIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated int64 nids = 1;
|
|
|
|
bool mark_notes_modified = 2;
|
|
|
|
bool generate_cards = 3;
|
2020-05-06 05:14:57 +02:00
|
|
|
}
|
2020-05-07 09:54:23 +02:00
|
|
|
|
2021-03-27 12:38:20 +01:00
|
|
|
message NoteIdsAndTagsIn {
|
2021-03-19 04:37:42 +01:00
|
|
|
repeated int64 note_ids = 1;
|
2021-01-09 06:50:24 +01:00
|
|
|
string tags = 2;
|
2020-05-07 09:54:23 +02:00
|
|
|
}
|
|
|
|
|
2021-03-19 07:55:10 +01:00
|
|
|
message FindAndReplaceTagIn {
|
|
|
|
repeated int64 note_ids = 1;
|
|
|
|
string search = 2;
|
2021-01-09 06:50:24 +01:00
|
|
|
string replacement = 3;
|
|
|
|
bool regex = 4;
|
2021-03-19 07:55:10 +01:00
|
|
|
bool match_case = 5;
|
2020-05-07 09:54:23 +02:00
|
|
|
}
|
2020-05-10 05:50:04 +02:00
|
|
|
|
|
|
|
message CheckDatabaseOut {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated string problems = 1;
|
2020-05-10 05:50:04 +02:00
|
|
|
}
|
2020-05-11 10:35:15 +02:00
|
|
|
|
2021-03-10 05:11:59 +01:00
|
|
|
message Preferences {
|
|
|
|
message Scheduling {
|
|
|
|
enum NewReviewMix {
|
|
|
|
DISTRIBUTE = 0;
|
|
|
|
REVIEWS_FIRST = 1;
|
|
|
|
NEW_FIRST = 2;
|
|
|
|
}
|
2020-05-11 10:35:15 +02:00
|
|
|
|
2021-05-13 07:23:16 +02:00
|
|
|
// read only; 1-3
|
2021-03-10 05:11:59 +01:00
|
|
|
uint32 scheduler_version = 1;
|
2021-02-21 06:50:41 +01:00
|
|
|
|
2021-03-10 05:11:59 +01:00
|
|
|
uint32 rollover = 2;
|
|
|
|
uint32 learn_ahead_secs = 3;
|
|
|
|
NewReviewMix new_review_mix = 4;
|
2020-05-11 10:35:15 +02:00
|
|
|
|
2021-03-10 05:11:59 +01:00
|
|
|
// v2 only
|
2021-03-10 09:20:37 +01:00
|
|
|
bool new_timezone = 5;
|
|
|
|
bool day_learn_first = 6;
|
|
|
|
}
|
|
|
|
message Reviewing {
|
|
|
|
bool hide_audio_play_buttons = 1;
|
|
|
|
bool interrupt_audio_when_answering = 2;
|
|
|
|
bool show_remaining_due_counts = 3;
|
|
|
|
bool show_intervals_on_buttons = 4;
|
|
|
|
uint32 time_limit_secs = 5;
|
|
|
|
}
|
|
|
|
message Editing {
|
|
|
|
bool adding_defaults_to_current_deck = 1;
|
|
|
|
bool paste_images_as_png = 2;
|
|
|
|
bool paste_strips_formatting = 3;
|
2021-03-10 05:11:59 +01:00
|
|
|
}
|
2020-05-11 10:35:15 +02:00
|
|
|
|
2021-03-10 05:11:59 +01:00
|
|
|
Scheduling scheduling = 1;
|
2021-03-10 09:20:37 +01:00
|
|
|
Reviewing reviewing = 2;
|
|
|
|
Editing editing = 3;
|
2020-05-11 10:35:15 +02:00
|
|
|
}
|
2020-05-14 04:14:00 +02:00
|
|
|
|
|
|
|
message ClozeNumbersInNoteOut {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated uint32 numbers = 1;
|
2020-05-14 04:14:00 +02:00
|
|
|
}
|
2020-05-15 13:21:10 +02:00
|
|
|
|
|
|
|
message GetDeckNamesIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
bool skip_empty_default = 1;
|
|
|
|
// if unset, implies skip_empty_default
|
|
|
|
bool include_filtered = 2;
|
2020-05-15 13:21:10 +02:00
|
|
|
}
|
2020-05-24 11:48:56 +02:00
|
|
|
|
2021-03-22 09:23:56 +01:00
|
|
|
message ReparentDecksIn {
|
|
|
|
repeated int64 deck_ids = 1;
|
|
|
|
int64 new_parent = 2;
|
2021-01-30 11:37:29 +01:00
|
|
|
}
|
|
|
|
|
2020-05-24 11:48:56 +02:00
|
|
|
message NoteIsDuplicateOrEmptyOut {
|
2021-01-09 06:50:24 +01:00
|
|
|
enum State {
|
|
|
|
NORMAL = 0;
|
|
|
|
EMPTY = 1;
|
|
|
|
DUPLICATE = 2;
|
|
|
|
}
|
|
|
|
State state = 1;
|
2020-05-24 11:48:56 +02:00
|
|
|
}
|
2020-05-28 11:49:44 +02:00
|
|
|
|
|
|
|
message SyncLoginIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
string username = 1;
|
|
|
|
string password = 2;
|
2020-05-28 11:49:44 +02:00
|
|
|
}
|
|
|
|
|
2020-06-02 05:23:01 +02:00
|
|
|
message SyncStatusOut {
|
2021-01-09 06:50:24 +01:00
|
|
|
enum Required {
|
|
|
|
NO_CHANGES = 0;
|
|
|
|
NORMAL_SYNC = 1;
|
|
|
|
FULL_SYNC = 2;
|
|
|
|
}
|
|
|
|
Required required = 1;
|
2020-06-02 05:23:01 +02:00
|
|
|
}
|
|
|
|
|
2020-05-28 11:49:44 +02:00
|
|
|
message SyncCollectionOut {
|
2021-01-09 06:50:24 +01:00
|
|
|
enum ChangesRequired {
|
|
|
|
NO_CHANGES = 0;
|
|
|
|
NORMAL_SYNC = 1;
|
|
|
|
FULL_SYNC = 2;
|
|
|
|
// local collection has no cards; upload not an option
|
|
|
|
FULL_DOWNLOAD = 3;
|
|
|
|
// remote collection has no cards; download not an option
|
|
|
|
FULL_UPLOAD = 4;
|
|
|
|
}
|
2020-05-28 11:49:44 +02:00
|
|
|
|
2021-01-09 06:50:24 +01:00
|
|
|
uint32 host_number = 1;
|
|
|
|
string server_message = 2;
|
|
|
|
ChangesRequired required = 3;
|
2020-05-28 11:49:44 +02:00
|
|
|
}
|
2020-05-29 08:45:27 +02:00
|
|
|
|
|
|
|
message SyncAuth {
|
2021-01-09 06:50:24 +01:00
|
|
|
string hkey = 1;
|
|
|
|
uint32 host_number = 2;
|
2020-05-29 08:45:27 +02:00
|
|
|
}
|
2020-06-04 10:21:04 +02:00
|
|
|
|
2021-01-11 05:11:18 +01:00
|
|
|
message SyncServerMethodIn {
|
|
|
|
enum Method {
|
|
|
|
HOST_KEY = 0;
|
|
|
|
META = 1;
|
|
|
|
START = 2;
|
|
|
|
APPLY_GRAVES = 3;
|
|
|
|
APPLY_CHANGES = 4;
|
|
|
|
CHUNK = 5;
|
|
|
|
APPLY_CHUNK = 6;
|
|
|
|
SANITY_CHECK = 7;
|
|
|
|
FINISH = 8;
|
|
|
|
ABORT = 9;
|
|
|
|
// caller must reopen after these two are called
|
|
|
|
FULL_UPLOAD = 10;
|
|
|
|
FULL_DOWNLOAD = 11;
|
|
|
|
}
|
|
|
|
Method method = 1;
|
|
|
|
bytes data = 2;
|
|
|
|
}
|
|
|
|
|
2020-06-04 10:21:04 +02:00
|
|
|
message RemoveNotesIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated int64 note_ids = 1;
|
|
|
|
repeated int64 card_ids = 2;
|
2020-06-04 10:21:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
message RemoveCardsIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated int64 card_ids = 1;
|
2020-06-04 10:21:04 +02:00
|
|
|
}
|
2020-06-05 11:49:53 +02:00
|
|
|
|
|
|
|
message UpdateStatsIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 deck_id = 1;
|
|
|
|
int32 new_delta = 2;
|
|
|
|
int32 review_delta = 4;
|
|
|
|
int32 millisecond_delta = 5;
|
2020-06-05 11:49:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
message ExtendLimitsIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 deck_id = 1;
|
|
|
|
int32 new_delta = 2;
|
|
|
|
int32 review_delta = 3;
|
2020-06-05 11:49:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
message CountsForDeckTodayOut {
|
2021-01-09 06:50:24 +01:00
|
|
|
int32 new = 1;
|
|
|
|
int32 review = 2;
|
2020-06-05 11:49:53 +02:00
|
|
|
}
|
2020-06-17 10:55:16 +02:00
|
|
|
|
|
|
|
message GraphsIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
string search = 1;
|
|
|
|
uint32 days = 2;
|
2020-06-17 10:55:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
message GraphsOut {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated Card cards = 1;
|
|
|
|
repeated RevlogEntry revlog = 2;
|
|
|
|
uint32 days_elapsed = 3;
|
|
|
|
// Based on rollover hour
|
|
|
|
uint32 next_day_at_secs = 4;
|
|
|
|
uint32 scheduler_version = 5;
|
|
|
|
/// Seconds to add to UTC timestamps to get local time.
|
|
|
|
int32 local_offset_secs = 7;
|
2020-06-17 10:55:16 +02:00
|
|
|
}
|
2020-06-22 05:33:53 +02:00
|
|
|
|
2021-01-23 11:47:45 +01:00
|
|
|
message GraphPreferences {
|
2021-01-21 03:25:14 +01:00
|
|
|
enum Weekday {
|
|
|
|
SUNDAY = 0;
|
|
|
|
MONDAY = 1;
|
|
|
|
FRIDAY = 5;
|
|
|
|
SATURDAY = 6;
|
|
|
|
}
|
|
|
|
Weekday calendar_first_day_of_week = 1;
|
|
|
|
bool card_counts_separate_inactive = 2;
|
2021-01-25 16:33:18 +01:00
|
|
|
bool browser_links_supported = 3;
|
2021-01-27 01:15:19 +01:00
|
|
|
bool future_due_show_backlog = 4;
|
2021-01-21 03:25:14 +01:00
|
|
|
}
|
|
|
|
|
2020-06-22 05:33:53 +02:00
|
|
|
message RevlogEntry {
|
2021-01-09 06:50:24 +01:00
|
|
|
enum ReviewKind {
|
|
|
|
LEARNING = 0;
|
|
|
|
REVIEW = 1;
|
|
|
|
RELEARNING = 2;
|
|
|
|
EARLY_REVIEW = 3;
|
|
|
|
MANUAL = 4;
|
|
|
|
}
|
|
|
|
int64 id = 1;
|
|
|
|
int64 cid = 2;
|
|
|
|
int32 usn = 3;
|
|
|
|
uint32 button_chosen = 4;
|
|
|
|
int32 interval = 5;
|
|
|
|
int32 last_interval = 6;
|
|
|
|
uint32 ease_factor = 7;
|
|
|
|
uint32 taken_millis = 8;
|
|
|
|
ReviewKind review_kind = 9;
|
2020-06-22 05:33:53 +02:00
|
|
|
}
|
2020-08-27 13:46:34 +02:00
|
|
|
|
|
|
|
message CongratsInfoOut {
|
2021-01-09 06:50:24 +01:00
|
|
|
uint32 learn_remaining = 1;
|
|
|
|
uint32 secs_until_next_learn = 2;
|
|
|
|
bool review_remaining = 3;
|
|
|
|
bool new_remaining = 4;
|
|
|
|
bool have_sched_buried = 5;
|
|
|
|
bool have_user_buried = 6;
|
|
|
|
bool is_filtered_deck = 7;
|
|
|
|
bool bridge_commands_supported = 8;
|
2021-02-06 04:20:06 +01:00
|
|
|
string deck_description = 9;
|
2020-08-27 13:46:34 +02:00
|
|
|
}
|
2020-08-29 14:02:22 +02:00
|
|
|
|
2021-04-30 12:03:20 +02:00
|
|
|
message UnburyDeckIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
enum Mode {
|
|
|
|
ALL = 0;
|
|
|
|
SCHED_ONLY = 1;
|
|
|
|
USER_ONLY = 2;
|
|
|
|
}
|
2021-04-30 12:03:20 +02:00
|
|
|
int64 deck_id = 1;
|
|
|
|
Mode mode = 2;
|
2020-08-29 14:02:22 +02:00
|
|
|
}
|
2020-08-31 08:14:04 +02:00
|
|
|
|
|
|
|
message BuryOrSuspendCardsIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
enum Mode {
|
|
|
|
SUSPEND = 0;
|
|
|
|
BURY_SCHED = 1;
|
|
|
|
BURY_USER = 2;
|
|
|
|
}
|
|
|
|
repeated int64 card_ids = 1;
|
2021-04-06 08:38:42 +02:00
|
|
|
repeated int64 note_ids = 2;
|
|
|
|
Mode mode = 3;
|
2020-08-31 08:14:04 +02:00
|
|
|
}
|
2020-09-02 06:41:46 +02:00
|
|
|
|
Rework reschedule tool
The old rescheduling dialog's two options have been split into two
separate menu items, "Forget", and "Set Due Date"
For cards that are not review cards, "Set Due Date" behaves like the
old reschedule option, changing the cards into a review card, and
and setting both the interval and due date to the provided number of
days.
When "Set Due Date" is applied to a review card, it no longer resets
the card's interval. Instead, it looks at how much the provided number
of days will change the original interval, and adjusts the interval by
that amount, so that cards that are answered earlier receive a smaller
next interval, and cards that are answered after a longer delay receive
a bonus.
For example, imagine a card was answered on day 5, and given an interval
of 10 days, so it has a due date of day 15.
- if on day 10 the due date is changed to day 12 (today+2), the card
is being scheduled 3 days earlier than it was supposed to be, so the
interval will be adjusted to 7 days.
- and if on day 10 the due date is changed to day 20, the interval will
be changed from 10 days to 15 days.
There is no separate option to reset the interval of a review card, but
it can be accomplished by forgetting the card(s), and then setting the
desired due date.
Other notes:
- Added the action to the review screen as well.
- Set the shortcut to Ctrl+Shift+D, and changed the existing Delete
Tags shortcut to Ctrl+Alt+Shift+A.
2021-02-07 11:58:16 +01:00
|
|
|
message ScheduleCardsAsNewIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated int64 card_ids = 1;
|
Rework reschedule tool
The old rescheduling dialog's two options have been split into two
separate menu items, "Forget", and "Set Due Date"
For cards that are not review cards, "Set Due Date" behaves like the
old reschedule option, changing the cards into a review card, and
and setting both the interval and due date to the provided number of
days.
When "Set Due Date" is applied to a review card, it no longer resets
the card's interval. Instead, it looks at how much the provided number
of days will change the original interval, and adjusts the interval by
that amount, so that cards that are answered earlier receive a smaller
next interval, and cards that are answered after a longer delay receive
a bonus.
For example, imagine a card was answered on day 5, and given an interval
of 10 days, so it has a due date of day 15.
- if on day 10 the due date is changed to day 12 (today+2), the card
is being scheduled 3 days earlier than it was supposed to be, so the
interval will be adjusted to 7 days.
- and if on day 10 the due date is changed to day 20, the interval will
be changed from 10 days to 15 days.
There is no separate option to reset the interval of a review card, but
it can be accomplished by forgetting the card(s), and then setting the
desired due date.
Other notes:
- Added the action to the review screen as well.
- Set the shortcut to Ctrl+Shift+D, and changed the existing Delete
Tags shortcut to Ctrl+Alt+Shift+A.
2021-02-07 11:58:16 +01:00
|
|
|
bool log = 2;
|
2020-09-02 06:41:46 +02:00
|
|
|
}
|
2020-09-03 07:44:14 +02:00
|
|
|
|
Rework reschedule tool
The old rescheduling dialog's two options have been split into two
separate menu items, "Forget", and "Set Due Date"
For cards that are not review cards, "Set Due Date" behaves like the
old reschedule option, changing the cards into a review card, and
and setting both the interval and due date to the provided number of
days.
When "Set Due Date" is applied to a review card, it no longer resets
the card's interval. Instead, it looks at how much the provided number
of days will change the original interval, and adjusts the interval by
that amount, so that cards that are answered earlier receive a smaller
next interval, and cards that are answered after a longer delay receive
a bonus.
For example, imagine a card was answered on day 5, and given an interval
of 10 days, so it has a due date of day 15.
- if on day 10 the due date is changed to day 12 (today+2), the card
is being scheduled 3 days earlier than it was supposed to be, so the
interval will be adjusted to 7 days.
- and if on day 10 the due date is changed to day 20, the interval will
be changed from 10 days to 15 days.
There is no separate option to reset the interval of a review card, but
it can be accomplished by forgetting the card(s), and then setting the
desired due date.
Other notes:
- Added the action to the review screen as well.
- Set the shortcut to Ctrl+Shift+D, and changed the existing Delete
Tags shortcut to Ctrl+Alt+Shift+A.
2021-02-07 11:58:16 +01:00
|
|
|
message SetDueDateIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated int64 card_ids = 1;
|
Rework reschedule tool
The old rescheduling dialog's two options have been split into two
separate menu items, "Forget", and "Set Due Date"
For cards that are not review cards, "Set Due Date" behaves like the
old reschedule option, changing the cards into a review card, and
and setting both the interval and due date to the provided number of
days.
When "Set Due Date" is applied to a review card, it no longer resets
the card's interval. Instead, it looks at how much the provided number
of days will change the original interval, and adjusts the interval by
that amount, so that cards that are answered earlier receive a smaller
next interval, and cards that are answered after a longer delay receive
a bonus.
For example, imagine a card was answered on day 5, and given an interval
of 10 days, so it has a due date of day 15.
- if on day 10 the due date is changed to day 12 (today+2), the card
is being scheduled 3 days earlier than it was supposed to be, so the
interval will be adjusted to 7 days.
- and if on day 10 the due date is changed to day 20, the interval will
be changed from 10 days to 15 days.
There is no separate option to reset the interval of a review card, but
it can be accomplished by forgetting the card(s), and then setting the
desired due date.
Other notes:
- Added the action to the review screen as well.
- Set the shortcut to Ctrl+Shift+D, and changed the existing Delete
Tags shortcut to Ctrl+Alt+Shift+A.
2021-02-07 11:58:16 +01:00
|
|
|
string days = 2;
|
2021-03-12 05:50:31 +01:00
|
|
|
Config.String config_key = 3;
|
2021-01-05 02:07:09 +01:00
|
|
|
}
|
|
|
|
|
2020-09-03 07:44:14 +02:00
|
|
|
message SortCardsIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated int64 card_ids = 1;
|
|
|
|
uint32 starting_from = 2;
|
|
|
|
uint32 step_size = 3;
|
|
|
|
bool randomize = 4;
|
|
|
|
bool shift_existing = 5;
|
2020-09-03 07:44:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
message SortDeckIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
int64 deck_id = 1;
|
|
|
|
bool randomize = 2;
|
2020-09-03 07:44:14 +02:00
|
|
|
}
|
2020-09-03 09:42:46 +02:00
|
|
|
|
|
|
|
message SetDeckIn {
|
2021-01-09 06:50:24 +01:00
|
|
|
repeated int64 card_ids = 1;
|
|
|
|
int64 deck_id = 2;
|
2020-09-03 09:42:46 +02:00
|
|
|
}
|
2021-01-29 12:03:19 +01:00
|
|
|
|
2021-02-08 05:10:05 +01:00
|
|
|
message Config {
|
|
|
|
message Bool {
|
|
|
|
enum Key {
|
2021-03-29 09:12:45 +02:00
|
|
|
BROWSER_TABLE_SHOW_NOTES_MODE = 0;
|
2021-03-29 08:12:26 +02:00
|
|
|
BROWSER_SORT_BACKWARDS = 1;
|
|
|
|
BROWSER_NOTE_SORT_BACKWARDS = 2;
|
|
|
|
PREVIEW_BOTH_SIDES = 3;
|
|
|
|
COLLAPSE_TAGS = 4;
|
|
|
|
COLLAPSE_NOTETYPES = 5;
|
|
|
|
COLLAPSE_DECKS = 6;
|
|
|
|
COLLAPSE_SAVED_SEARCHES = 7;
|
|
|
|
COLLAPSE_TODAY = 8;
|
|
|
|
COLLAPSE_CARD_STATE = 9;
|
|
|
|
COLLAPSE_FLAGS = 10;
|
|
|
|
SCHED_2021 = 11;
|
|
|
|
ADDING_DEFAULTS_TO_CURRENT_DECK = 12;
|
|
|
|
HIDE_AUDIO_PLAY_BUTTONS = 13;
|
|
|
|
INTERRUPT_AUDIO_WHEN_ANSWERING = 14;
|
|
|
|
PASTE_IMAGES_AS_PNG = 15;
|
|
|
|
PASTE_STRIPS_FORMATTING = 16;
|
|
|
|
NORMALIZE_NOTE_TEXT = 17;
|
2021-02-08 05:10:05 +01:00
|
|
|
}
|
|
|
|
Key key = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
message String {
|
|
|
|
enum Key {
|
|
|
|
SET_DUE_BROWSER = 0;
|
|
|
|
SET_DUE_REVIEWER = 1;
|
|
|
|
}
|
|
|
|
Key key = 1;
|
2021-01-29 12:03:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
message SetConfigBoolIn {
|
2021-02-08 05:10:05 +01:00
|
|
|
Config.Bool.Key key = 1;
|
2021-01-29 12:03:19 +01:00
|
|
|
bool value = 2;
|
2021-05-24 06:50:46 +02:00
|
|
|
bool undoable = 3;
|
2021-01-29 12:03:19 +01:00
|
|
|
}
|
2021-02-08 05:10:05 +01:00
|
|
|
|
|
|
|
message SetConfigStringIn {
|
|
|
|
Config.String.Key key = 1;
|
|
|
|
string value = 2;
|
2021-05-24 06:50:46 +02:00
|
|
|
bool undoable = 3;
|
2021-02-08 05:10:05 +01:00
|
|
|
}
|
2021-02-09 09:46:48 +01:00
|
|
|
|
|
|
|
message RenderMarkdownIn {
|
|
|
|
string markdown = 1;
|
|
|
|
bool sanitize = 2;
|
|
|
|
}
|
2021-02-20 05:13:03 +01:00
|
|
|
|
|
|
|
message SchedulingState {
|
|
|
|
message New {
|
|
|
|
uint32 position = 1;
|
|
|
|
}
|
|
|
|
message Learning {
|
|
|
|
uint32 remaining_steps = 1;
|
|
|
|
uint32 scheduled_secs = 2;
|
|
|
|
}
|
|
|
|
message Review {
|
|
|
|
uint32 scheduled_days = 1;
|
|
|
|
uint32 elapsed_days = 2;
|
|
|
|
float ease_factor = 3;
|
|
|
|
uint32 lapses = 4;
|
2021-02-23 03:44:26 +01:00
|
|
|
bool leeched = 5;
|
2021-02-20 05:13:03 +01:00
|
|
|
}
|
|
|
|
message Relearning {
|
|
|
|
Review review = 1;
|
|
|
|
Learning learning = 2;
|
|
|
|
}
|
|
|
|
message Normal {
|
|
|
|
oneof value {
|
|
|
|
New new = 1;
|
|
|
|
Learning learning = 2;
|
|
|
|
Review review = 3;
|
|
|
|
Relearning relearning = 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
message Preview {
|
|
|
|
uint32 scheduled_secs = 1;
|
2021-03-01 14:47:00 +01:00
|
|
|
bool finished = 2;
|
2021-02-20 05:13:03 +01:00
|
|
|
}
|
|
|
|
message ReschedulingFilter {
|
|
|
|
Normal original_state = 1;
|
|
|
|
}
|
|
|
|
message Filtered {
|
|
|
|
oneof value {
|
|
|
|
Preview preview = 1;
|
|
|
|
ReschedulingFilter rescheduling = 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
oneof value {
|
|
|
|
Normal normal = 1;
|
|
|
|
Filtered filtered = 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
message NextCardStates {
|
|
|
|
SchedulingState current = 1;
|
|
|
|
SchedulingState again = 2;
|
|
|
|
SchedulingState hard = 3;
|
|
|
|
SchedulingState good = 4;
|
|
|
|
SchedulingState easy = 5;
|
|
|
|
}
|
|
|
|
|
2021-05-11 03:37:08 +02:00
|
|
|
message CardAnswer {
|
2021-02-20 05:13:03 +01:00
|
|
|
enum Rating {
|
|
|
|
AGAIN = 0;
|
|
|
|
HARD = 1;
|
|
|
|
GOOD = 2;
|
|
|
|
EASY = 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64 card_id = 1;
|
|
|
|
SchedulingState current_state = 2;
|
|
|
|
SchedulingState new_state = 3;
|
|
|
|
Rating rating = 4;
|
2021-02-22 03:29:31 +01:00
|
|
|
int64 answered_at_millis = 5;
|
2021-02-20 05:13:03 +01:00
|
|
|
uint32 milliseconds_taken = 6;
|
|
|
|
}
|
2021-03-01 01:34:04 +01:00
|
|
|
|
|
|
|
message GetQueuedCardsIn {
|
|
|
|
uint32 fetch_limit = 1;
|
|
|
|
bool intraday_learning_only = 2;
|
|
|
|
}
|
|
|
|
|
2021-05-11 03:37:08 +02:00
|
|
|
message QueuedCards {
|
2021-03-01 01:34:04 +01:00
|
|
|
enum Queue {
|
2021-05-11 03:37:08 +02:00
|
|
|
NEW = 0;
|
|
|
|
LEARNING = 1;
|
|
|
|
REVIEW = 2;
|
2021-03-01 01:34:04 +01:00
|
|
|
}
|
|
|
|
message QueuedCard {
|
|
|
|
Card card = 1;
|
2021-03-02 06:48:25 +01:00
|
|
|
Queue queue = 2;
|
|
|
|
NextCardStates next_states = 3;
|
2021-03-01 01:34:04 +01:00
|
|
|
}
|
|
|
|
|
2021-05-11 03:37:08 +02:00
|
|
|
repeated QueuedCard cards = 1;
|
|
|
|
uint32 new_count = 2;
|
|
|
|
uint32 learning_count = 3;
|
|
|
|
uint32 review_count = 4;
|
|
|
|
}
|
2021-03-01 01:34:04 +01:00
|
|
|
|
undoable ops now return changes directly; add new *_ops.py files
- Introduced a new transact() method that wraps the return value
in a separate struct that describes the changes that were made.
- Changes are now gathered from the undo log, so we don't need to
guess at what was changed - eg if update_note() is called with identical
note contents, no changes are returned. Card changes will only be set
if cards were actually generated by the update_note() call, and tag
will only be set if a new tag was added.
- mw.perform_op() has been updated to expect the op to return the changes,
or a structure with the changes in it, and it will use them to fire the
change hook, instead of fetching the changes from undo_status(), so there
is no risk of race conditions.
- the various calls to mw.perform_op() have been split into separate
files like card_ops.py. Aside from making the code cleaner, this works
around a rather annoying issue with mypy. Because we run it with
no_strict_optional, mypy is happy to accept an operation that returns None,
despite the type signature saying it requires changes to be returned.
Turning no_strict_optional on for the whole codebase is not practical
at the moment, but we can enable it for individual files.
Still todo:
- The cursor keeps moving back to the start of a field when typing -
we need to ignore the refresh hook when we are the initiator.
- The busy cursor icon should probably be delayed a few hundreds ms.
- Still need to think about a nicer way of handling saveNow()
- op_made_changes(), op_affects_study_queue() might be better embedded
as properties in the object instead
2021-03-16 05:26:42 +01:00
|
|
|
message OpChanges {
|
2021-04-06 02:14:11 +02:00
|
|
|
bool card = 1;
|
|
|
|
bool note = 2;
|
|
|
|
bool deck = 3;
|
|
|
|
bool tag = 4;
|
|
|
|
bool notetype = 5;
|
2021-04-06 13:37:31 +02:00
|
|
|
bool config = 6;
|
2021-04-22 02:55:32 +02:00
|
|
|
bool deck_config = 11;
|
2021-05-28 03:09:16 +02:00
|
|
|
bool mtime = 12;
|
2021-04-06 02:14:11 +02:00
|
|
|
|
|
|
|
bool browser_table = 7;
|
|
|
|
bool browser_sidebar = 8;
|
|
|
|
bool editor = 9;
|
2021-05-11 03:37:08 +02:00
|
|
|
bool reviewer = 10;
|
2021-03-13 11:45:24 +01:00
|
|
|
}
|
|
|
|
|
2021-03-04 10:17:19 +01:00
|
|
|
message UndoStatus {
|
|
|
|
string undo = 1;
|
|
|
|
string redo = 2;
|
2021-05-06 07:54:04 +02:00
|
|
|
uint32 last_step = 3;
|
2021-03-04 10:17:19 +01:00
|
|
|
}
|
Simplify note adding and the deck/notetype choosers
The existing code was really difficult to reason about:
- The default notetype depended on the selected deck, and vice versa,
and this logic was buried in the deck and notetype choosing screens,
and models.py.
- Changes to the notetype were not passed back directly, but were fired
via a hook, which changed any screen in the app that had a notetype
selector.
It also wasn't great for performance, as the most recent deck and tags
were embedded in the notetype, which can be expensive to save and sync
for large notetypes.
To address these points:
- The current deck for a notetype, and notetype for a deck, are now
stored in separate config variables, instead of directly in the deck
or notetype. These are cheap to read and write, and we'll be able to
sync them individually in the future once config syncing is updated in
the future. I seem to recall some users not wanting the tag saving
behaviour, so I've dropped that for now, but if people end up missing
it, it would be simple to add as an extra auxiliary config variable.
- The logic for getting the starting deck and notetype has been moved
into the backend. It should be the same as the older Python code, with
one exception: when "change deck depending on notetype" is enabled in
the preferences, it will start with the current notetype ("curModel"),
instead of first trying to get a deck-specific notetype.
- ModelChooser has been duplicated into notetypechooser.py, and it
has been updated to solely be concerned with keeping track of a selected
notetype - it no longer alters global state.
2021-03-08 14:23:24 +01:00
|
|
|
|
2021-04-03 06:38:49 +02:00
|
|
|
message OpChangesAfterUndo {
|
|
|
|
OpChanges changes = 1;
|
|
|
|
string operation = 2;
|
|
|
|
int64 reverted_to_timestamp = 3;
|
|
|
|
UndoStatus new_status = 4;
|
2021-05-08 09:51:36 +02:00
|
|
|
uint32 counter = 5;
|
2021-04-03 06:38:49 +02:00
|
|
|
}
|
|
|
|
|
Simplify note adding and the deck/notetype choosers
The existing code was really difficult to reason about:
- The default notetype depended on the selected deck, and vice versa,
and this logic was buried in the deck and notetype choosing screens,
and models.py.
- Changes to the notetype were not passed back directly, but were fired
via a hook, which changed any screen in the app that had a notetype
selector.
It also wasn't great for performance, as the most recent deck and tags
were embedded in the notetype, which can be expensive to save and sync
for large notetypes.
To address these points:
- The current deck for a notetype, and notetype for a deck, are now
stored in separate config variables, instead of directly in the deck
or notetype. These are cheap to read and write, and we'll be able to
sync them individually in the future once config syncing is updated in
the future. I seem to recall some users not wanting the tag saving
behaviour, so I've dropped that for now, but if people end up missing
it, it would be simple to add as an extra auxiliary config variable.
- The logic for getting the starting deck and notetype has been moved
into the backend. It should be the same as the older Python code, with
one exception: when "change deck depending on notetype" is enabled in
the preferences, it will start with the current notetype ("curModel"),
instead of first trying to get a deck-specific notetype.
- ModelChooser has been duplicated into notetypechooser.py, and it
has been updated to solely be concerned with keeping track of a selected
notetype - it no longer alters global state.
2021-03-08 14:23:24 +01:00
|
|
|
message DefaultsForAddingIn {
|
|
|
|
int64 home_deck_of_current_review_card = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
message DeckAndNotetype {
|
|
|
|
int64 deck_id = 1;
|
|
|
|
int64 notetype_id = 2;
|
|
|
|
}
|
2021-03-11 09:54:30 +01:00
|
|
|
|
|
|
|
message RenameDeckIn {
|
|
|
|
int64 deck_id = 1;
|
|
|
|
string new_name = 2;
|
more reset refactoring
'card modified' covers the common case where we need to rebuild the
study queue, but is also set when changing the card flags. We want to
avoid a queue rebuild in that case, as it causes UI flicker, and may
result in a different card being shown. Note marking doesn't trigger
a queue build, but still causes flicker, and may return the user back
to the front side when they were looking at the answer.
I still think entity-based change tracking is the simplest in the
common case, but to solve the above, I've introduced an enum describing
the last operation that was taken. This currently is not trying to list
out all possible operations, and just describes the ones we want to
special-case.
Other changes:
- Fire the old 'state_did_reset' hook after an operation is performed,
so legacy code can refresh itself after an operation is performed.
- Fire the new `operation_did_execute` hook when mw.reset() is called,
so that as the UI is updated to the use the new hook, it will still
be able to refresh after legacy code calls mw.reset()
- Update the deck browser, overview and review screens to listen to
the new hook, instead of relying on the main window to call moveToState()
- Add a 'set flag' backend action, so we can distinguish it from a
normal card update.
- Drop the separate added/modified entries in the change list in
favour of a single entry per entity.
- Add typing to mw.state
- Tweak perform_op()
- Convert a few more actions to use perform_op()
2021-03-14 10:54:15 +01:00
|
|
|
}
|
|
|
|
|
2021-03-24 03:56:06 +01:00
|
|
|
message FilteredDeckForUpdate {
|
rework filtered deck screen & search errors
- Filtered deck creation now happens as an atomic operation, and is
undoable.
- The logic for initial search text, normalizing searches and so on
has been pushed into the backend.
- Use protobuf to pass the filtered deck to the updated dialog, so
we don't need to deal with untyped JSON.
- Change the "revise your search?" prompt to be a simple info box -
user has access to cancel and build buttons, and doesn't need a separate
prompt. Tweak the wording so the 'show excluded' button should be more
obvious.
- Filtered decks have a time appended to them instead of a number,
primarily because it's easier to implement. No objections going back to
the old behaviour if someone wants to contribute a clean patch.
The standard de-duplication will happen if two decks are created in the
same minute with the same name.
- Tweak the default sort order, and start with two searches. The UI
will still hide the second search by default, but by starting with two,
the frontend doesn't need logic for creating the starting text.
- Search errors now have their own error type, instead of using
InvalidInput, as that was intended mainly for bad API calls. The markdown
conversion is done when the error is converted from the backend, allowing
errors to printed as a string without any special handling by the calling
code.
TODO: when building a new filtered deck, update_active() is clobbering
the undo log when the overview is refreshed
2021-03-24 12:52:48 +01:00
|
|
|
int64 id = 1;
|
2021-03-24 03:56:06 +01:00
|
|
|
string name = 2;
|
2021-04-04 13:15:30 +02:00
|
|
|
Deck.Filtered config = 3;
|
2021-03-24 03:56:06 +01:00
|
|
|
}
|
|
|
|
|
more reset refactoring
'card modified' covers the common case where we need to rebuild the
study queue, but is also set when changing the card flags. We want to
avoid a queue rebuild in that case, as it causes UI flicker, and may
result in a different card being shown. Note marking doesn't trigger
a queue build, but still causes flicker, and may return the user back
to the front side when they were looking at the answer.
I still think entity-based change tracking is the simplest in the
common case, but to solve the above, I've introduced an enum describing
the last operation that was taken. This currently is not trying to list
out all possible operations, and just describes the ones we want to
special-case.
Other changes:
- Fire the old 'state_did_reset' hook after an operation is performed,
so legacy code can refresh itself after an operation is performed.
- Fire the new `operation_did_execute` hook when mw.reset() is called,
so that as the UI is updated to the use the new hook, it will still
be able to refresh after legacy code calls mw.reset()
- Update the deck browser, overview and review screens to listen to
the new hook, instead of relying on the main window to call moveToState()
- Add a 'set flag' backend action, so we can distinguish it from a
normal card update.
- Drop the separate added/modified entries in the change list in
favour of a single entry per entity.
- Add typing to mw.state
- Tweak perform_op()
- Convert a few more actions to use perform_op()
2021-03-14 10:54:15 +01:00
|
|
|
message SetFlagIn {
|
|
|
|
repeated int64 card_ids = 1;
|
|
|
|
uint32 flag = 2;
|
|
|
|
}
|
2021-05-25 12:29:21 +02:00
|
|
|
|
|
|
|
message GetAuxConfigKeyIn {
|
|
|
|
int64 id = 1;
|
|
|
|
string key = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
message GetAuxTemplateConfigKeyIn {
|
|
|
|
int64 notetype_id = 1;
|
|
|
|
uint32 card_ordinal = 2;
|
|
|
|
string key = 3;
|
|
|
|
}
|